on 36fbd4b help sign in
5300 lines 190 kB history raw
1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Reporting.Error.Syntax
4 ( Error(..)
5 , toReport
6 --
7 , Module(..)
8 , Exposing(..)
9 --
10 , Decl(..)
11 , DeclType(..)
12 , TypeAlias(..)
13 , CustomType(..)
14 , DeclDef(..)
15 , Port(..)
16 --
17 , Expr(..)
18 , Record(..)
19 , Tuple(..)
20 , List(..)
21 , Func(..)
22 , Case(..)
23 , If(..)
24 , Let(..)
25 , Def(..)
26 , Destruct(..)
27 --
28 , Pattern(..)
29 , PRecord(..)
30 , PTuple(..)
31 , PList(..)
32 --
33 , Type(..)
34 , TRecord(..)
35 , TTuple(..)
36 --
37 , Char(..)
38 , String(..)
39 , Escape(..)
40 , Number(..)
41 --
42 , Space(..)
43 , toSpaceReport
44 )
45 where
48import Prelude hiding (Char, String)
49import qualified Data.Char as Char
50import qualified Data.Name as Name
51import Data.Word (Word16)
52import Numeric (showHex)
54import qualified Elm.ModuleName as ModuleName
55import Parse.Primitives (Row, Col)
56import Parse.Symbol (BadOperator(..))
57import qualified Reporting.Annotation as A
58import qualified Reporting.Doc as D
59import qualified Reporting.Report as Report
60import qualified Reporting.Render.Code as Code
64-- ALL SYNTAX ERRORS
67data Error
68 = ModuleNameUnspecified ModuleName.Raw
69 | ModuleNameMismatch ModuleName.Raw (A.Located ModuleName.Raw)
70 | UnexpectedPort A.Region
71 | NoPorts A.Region
72 | ParseError Module
76-- MODULE
79data Module
80 = ModuleSpace Space Row Col
81 | ModuleBadEnd Row Col
82 --
83 | ModuleProblem Row Col
84 | ModuleName Row Col
85 | ModuleExposing Exposing Row Col
86 --
87 | PortModuleProblem Row Col
88 | PortModuleName Row Col
89 | PortModuleExposing Exposing Row Col
90 --
91 | Effect Row Col
92 --
93 | FreshLine Row Col
94 --
95 | ImportStart Row Col
96 | ImportName Row Col
97 | ImportAs Row Col
98 | ImportAlias Row Col
99 | ImportExposing Row Col
100 | ImportExposingList Exposing Row Col
101 | ImportEnd Row Col -- different based on col=1 or if greater
102 --
103 | ImportIndentName Row Col
104 | ImportIndentAlias Row Col
105 | ImportIndentExposingList Row Col
106 --
107 | Infix Row Col
108 --
109 | Declarations Decl Row Col
112data Exposing
113 = ExposingSpace Space Row Col
114 | ExposingStart Row Col
115 | ExposingValue Row Col
116 | ExposingOperator Row Col
117 | ExposingOperatorReserved BadOperator Row Col
118 | ExposingOperatorRightParen Row Col
119 | ExposingTypePrivacy Row Col
120 | ExposingEnd Row Col
121 --
122 | ExposingIndentEnd Row Col
123 | ExposingIndentValue Row Col
127-- DECLARATIONS
130data Decl
131 = DeclStart Row Col
132 | DeclSpace Space Row Col
133 --
134 | Port Port Row Col
135 | DeclType DeclType Row Col
136 | DeclDef Name.Name DeclDef Row Col
137 --
138 | DeclFreshLineAfterDocComment Row Col
141data DeclDef
142 = DeclDefSpace Space Row Col
143 | DeclDefEquals Row Col
144 | DeclDefType Type Row Col
145 | DeclDefArg Pattern Row Col
146 | DeclDefBody Expr Row Col
147 | DeclDefNameRepeat Row Col
148 | DeclDefNameMatch Name.Name Row Col
149 --
150 | DeclDefIndentType Row Col
151 | DeclDefIndentEquals Row Col
152 | DeclDefIndentBody Row Col
155data Port
156 = PortSpace Space Row Col
157 | PortName Row Col
158 | PortColon Row Col
159 | PortType Type Row Col
160 | PortIndentName Row Col
161 | PortIndentColon Row Col
162 | PortIndentType Row Col
166-- TYPE DECLARATIONS
169data DeclType
170 = DT_Space Space Row Col
171 | DT_Name Row Col
172 | DT_Alias TypeAlias Row Col
173 | DT_Union CustomType Row Col
174 --
175 | DT_IndentName Row Col
178data TypeAlias
179 = AliasSpace Space Row Col
180 | AliasName Row Col
181 | AliasEquals Row Col
182 | AliasBody Type Row Col
183 --
184 | AliasIndentEquals Row Col
185 | AliasIndentBody Row Col
188data CustomType
189 = CT_Space Space Row Col
190 | CT_Name Row Col
191 | CT_Equals Row Col
192 | CT_Bar Row Col
193 | CT_Variant Row Col
194 | CT_VariantArg Type Row Col
195 --
196 | CT_IndentEquals Row Col
197 | CT_IndentBar Row Col
198 | CT_IndentAfterBar Row Col
199 | CT_IndentAfterEquals Row Col
203-- EXPRESSIONS
206data Expr
207 = Let Let Row Col
208 | Case Case Row Col
209 | If If Row Col
210 | List List Row Col
211 | Record Record Row Col
212 | Tuple Tuple Row Col
213 | Func Func Row Col
214 --
215 | Dot Row Col
216 | Access Row Col
217 | OperatorRight Name.Name Row Col
218 | OperatorReserved BadOperator Row Col
219 --
220 | Start Row Col
221 | Char Char Row Col
222 | String String Row Col
223 | Number Number Row Col
224 | Space Space Row Col
225 | EndlessShader Row Col
226 | ShaderProblem [Char.Char] Row Col
227 | IndentOperatorRight Name.Name Row Col
230data Record
231 = RecordOpen Row Col
232 | RecordEnd Row Col
233 | RecordField Row Col
234 | RecordEquals Row Col
235 | RecordExpr Expr Row Col
236 | RecordSpace Space Row Col
237 --
238 | RecordIndentOpen Row Col
239 | RecordIndentEnd Row Col
240 | RecordIndentField Row Col
241 | RecordIndentEquals Row Col
242 | RecordIndentExpr Row Col
245data Tuple
246 = TupleExpr Expr Row Col
247 | TupleSpace Space Row Col
248 | TupleEnd Row Col
249 | TupleOperatorClose Row Col
250 | TupleOperatorReserved BadOperator Row Col
251 --
252 | TupleIndentExpr1 Row Col
253 | TupleIndentExprN Row Col
254 | TupleIndentEnd Row Col
257data List
258 = ListSpace Space Row Col
259 | ListOpen Row Col
260 | ListExpr Expr Row Col
261 | ListEnd Row Col
262 --
263 | ListIndentOpen Row Col
264 | ListIndentEnd Row Col
265 | ListIndentExpr Row Col
268data Func
269 = FuncSpace Space Row Col
270 | FuncArg Pattern Row Col
271 | FuncBody Expr Row Col
272 | FuncArrow Row Col
273 --
274 | FuncIndentArg Row Col
275 | FuncIndentArrow Row Col
276 | FuncIndentBody Row Col
279data Case
280 = CaseSpace Space Row Col
281 | CaseOf Row Col
282 | CasePattern Pattern Row Col
283 | CaseArrow Row Col
284 | CaseExpr Expr Row Col
285 | CaseBranch Expr Row Col
286 --
287 | CaseIndentOf Row Col
288 | CaseIndentExpr Row Col
289 | CaseIndentPattern Row Col
290 | CaseIndentArrow Row Col
291 | CaseIndentBranch Row Col
292 | CasePatternAlignment Word16 Row Col
295data If
296 = IfSpace Space Row Col
297 | IfThen Row Col
298 | IfElse Row Col
299 | IfElseBranchStart Row Col
300 --
301 | IfCondition Expr Row Col
302 | IfThenBranch Expr Row Col
303 | IfElseBranch Expr Row Col
304 --
305 | IfIndentCondition Row Col
306 | IfIndentThen Row Col
307 | IfIndentThenBranch Row Col
308 | IfIndentElseBranch Row Col
309 | IfIndentElse Row Col
312data Let
313 = LetSpace Space Row Col
314 | LetIn Row Col
315 | LetDefAlignment Word16 Row Col
316 | LetDefName Row Col
317 | LetDef Name.Name Def Row Col
318 | LetDestruct Destruct Row Col
319 | LetBody Expr Row Col
320 | LetIndentDef Row Col
321 | LetIndentIn Row Col
322 | LetIndentBody Row Col
325data Def
326 = DefSpace Space Row Col
327 | DefType Type Row Col
328 | DefNameRepeat Row Col
329 | DefNameMatch Name.Name Row Col
330 | DefArg Pattern Row Col
331 | DefEquals Row Col
332 | DefBody Expr Row Col
333 | DefIndentEquals Row Col
334 | DefIndentType Row Col
335 | DefIndentBody Row Col
336 | DefAlignment Word16 Row Col
339data Destruct
340 = DestructSpace Space Row Col
341 | DestructPattern Pattern Row Col
342 | DestructEquals Row Col
343 | DestructBody Expr Row Col
344 | DestructIndentEquals Row Col
345 | DestructIndentBody Row Col
349-- PATTERNS
352data Pattern
353 = PRecord PRecord Row Col
354 | PTuple PTuple Row Col
355 | PList PList Row Col
356 --
357 | PStart Row Col
358 | PChar Char Row Col
359 | PString String Row Col
360 | PNumber Number Row Col
361 | PFloat Word16 Row Col
362 | PAlias Row Col
363 | PWildcardNotVar Name.Name Int Row Col
364 | PSpace Space Row Col
365 --
366 | PIndentStart Row Col
367 | PIndentAlias Row Col
370data PRecord
371 = PRecordOpen Row Col
372 | PRecordEnd Row Col
373 | PRecordField Row Col
374 | PRecordSpace Space Row Col
375 --
376 | PRecordIndentOpen Row Col
377 | PRecordIndentEnd Row Col
378 | PRecordIndentField Row Col
381data PTuple
382 = PTupleOpen Row Col
383 | PTupleEnd Row Col
384 | PTupleExpr Pattern Row Col
385 | PTupleSpace Space Row Col
386 --
387 | PTupleIndentEnd Row Col
388 | PTupleIndentExpr1 Row Col
389 | PTupleIndentExprN Row Col
392data PList
393 = PListOpen Row Col
394 | PListEnd Row Col
395 | PListExpr Pattern Row Col
396 | PListSpace Space Row Col
397 --
398 | PListIndentOpen Row Col
399 | PListIndentEnd Row Col
400 | PListIndentExpr Row Col
404-- TYPES
407data Type
408 = TRecord TRecord Row Col
409 | TTuple TTuple Row Col
410 --
411 | TStart Row Col
412 | TSpace Space Row Col
413 --
414 | TIndentStart Row Col
417data TRecord
418 = TRecordOpen Row Col
419 | TRecordEnd Row Col
420 --
421 | TRecordField Row Col
422 | TRecordColon Row Col
423 | TRecordType Type Row Col
424 --
425 | TRecordSpace Space Row Col
426 --
427 | TRecordIndentOpen Row Col
428 | TRecordIndentField Row Col
429 | TRecordIndentColon Row Col
430 | TRecordIndentType Row Col
431 | TRecordIndentEnd Row Col
434data TTuple
435 = TTupleOpen Row Col
436 | TTupleEnd Row Col
437 | TTupleType Type Row Col
438 | TTupleSpace Space Row Col
439 --
440 | TTupleIndentType1 Row Col
441 | TTupleIndentTypeN Row Col
442 | TTupleIndentEnd Row Col
446-- LITERALS
449data Char
450 = CharEndless
451 | CharEscape Escape
452 | CharNotString Word16
455data String
456 = StringEndless_Single
457 | StringEndless_Multi
458 | StringEscape Escape
461data Escape
462 = EscapeUnknown
463 | BadUnicodeFormat Word16
464 | BadUnicodeCode Word16
465 | BadUnicodeLength Word16 Int Int
468data Number
469 = NumberEnd
470 | NumberDot Int
471 | NumberHexDigit
472 | NumberNoLeadingZero
476-- MISC
479data Space
480 = HasTab
481 | EndlessMultiComment
485-- TO REPORT
488toReport :: Code.Source -> Error -> Report.Report
489toReport source err =
490 case err of
491 ModuleNameUnspecified name ->
492 let
493 region = toRegion 1 1
494 in
495 Report.Report "MODULE NAME MISSING" region [] $
496 D.stack
497 [ D.reflow $
498 "I need the module name to be declared at the top of this file, like this:"
499 , D.indent 4 $ D.fillSep $
500 [ D.cyan "module", D.fromName name, D.cyan "exposing", "(..)" ]
501 , D.reflow $
502 "Try adding that as the first line of your file!"
503 , D.toSimpleNote $
504 "It is best to replace (..) with an explicit list of types and\
505 \ functions you want to expose. When you know a value is only used\
506 \ within this module, you can refactor without worrying about uses\
507 \ elsewhere. Limiting exposed values can also speed up compilation\
508 \ because I can skip a bunch of work if I see that the exposed API\
509 \ has not changed."
510 ]
512 ModuleNameMismatch expectedName (A.At region actualName) ->
513 Report.Report "MODULE NAME MISMATCH" region [ModuleName.toChars expectedName] $
514 Code.toSnippet source region Nothing
515 (
516 "It looks like this module name is out of sync:"
517 ,
518 D.stack
519 [ D.reflow $
520 "I need it to match the file path, so I was expecting it to see `"
521 ++ ModuleName.toChars expectedName
522 ++ "` here. Make the following change, and you should be all set!"
523 , D.indent 4 $
524 D.dullyellow (D.fromName actualName) <> " -> " <> D.green (D.fromName expectedName)
525 , D.toSimpleNote $
526 "I require that module names correspond to file paths. This makes it much\
527 \ easier to explore unfamiliar codebases! So if you want to keep the current\
528 \ module name, try renaming the file instead."
529 ]
530 )
532 UnexpectedPort region ->
533 Report.Report "UNEXPECTED PORTS" region [] $
534 Code.toSnippet source region Nothing
535 (
536 D.reflow $
537 "You are declaring ports in a normal module."
538 ,
539 D.stack
540 [ D.fillSep
541 ["Switch","this","to","say",D.cyan "port module","instead,"
542 ,"marking","that","this","module","contains","port","declarations."
543 ]
544 , D.link "Note"
545 "Ports are not a traditional FFI for calling JS functions directly. They need a different mindset! Read"
546 "ports"
547 "to learn the syntax and how to use it effectively."
548 ]
549 )
551 NoPorts region ->
552 Report.Report "NO PORTS" region [] $
553 Code.toSnippet source region Nothing
554 (
555 D.reflow $
556 "This module does not declare any ports, but it says it will:"
557 ,
558 D.fillSep
559 ["Switch","this","to",D.cyan "module"
560 ,"and","you","should","be","all","set!"
561 ]
562 )
564 ParseError modul ->
565 toParseErrorReport source modul
568toParseErrorReport :: Code.Source -> Module -> Report.Report
569toParseErrorReport source modul =
570 case modul of
571 ModuleSpace space row col ->
572 toSpaceReport source space row col
574 ModuleBadEnd row col ->
575 case Code.whatIsNext source row col of
576 Code.Keyword keyword ->
577 let
578 region = toKeywordRegion row col keyword
579 in
580 Report.Report "RESERVED WORD" region [] $
581 Code.toSnippet source region Nothing
582 (
583 D.reflow $
584 "I got stuck on this reserved word:"
585 ,
586 D.reflow $
587 "The name `" ++ keyword ++ "` is reserved, so try using a different name?"
588 )
590 Code.Operator op ->
591 let
592 region = toKeywordRegion row col op
593 in
594 Report.Report "UNEXPECTED SYMBOL" region [] $
595 Code.toSnippet source region Nothing
596 (
597 D.reflow $
598 "I ran into an unexpected symbol:"
599 ,
600 D.reflow $
601 "I was not expecting to see a " ++ op ++ " here. Try deleting it? Maybe\
602 \ I can give a better hint from there?"
603 )
605 Code.Close term bracket ->
606 let
607 region = toRegion row col
608 in
609 Report.Report ("UNEXPECTED " ++ map Char.toUpper term) region [] $
610 Code.toSnippet source region Nothing
611 (
612 D.reflow $
613 "I ran into an unexpected " ++ term ++ ":"
614 ,
615 D.reflow $
616 "This " ++ bracket : " does not match up with an earlier open " ++ term ++ ". Try deleting it?"
617 )
619 Code.Other ->
620 let
621 region = toRegion row col
622 in
623 Report.Report "SYNTAX PROBLEM" region [] $
624 Code.toSnippet source region Nothing
625 (
626 D.reflow $
627 "I got stuck here:"
628 ,
629 D.reflow $
630 "Whatever I am running into is confusing me a lot! Normally I can give fairly\
631 \ specific hints, but something is really tripping me up this time."
632 )
634 ModuleProblem row col ->
635 let
636 region = toRegion row col
637 in
638 Report.Report "UNFINISHED MODULE DECLARATION" region [] $
639 Code.toSnippet source region Nothing
640 (
641 D.reflow $
642 "I am parsing an `module` declaration, but I got stuck here:"
643 ,
644 D.stack
645 [ D.reflow $
646 "Here are some examples of valid `module` declarations:"
647 , D.indent 4 $ D.vcat $
648 [ D.fillSep [D.cyan "module","Main",D.cyan "exposing","(..)"]
649 , D.fillSep [D.cyan "module","Dict",D.cyan "exposing","(Dict, empty, get)"]
650 ]
651 , D.reflow $
652 "I generally recommend using an explicit exposing list. I can skip compiling a bunch\
653 \ of files when the public interface of a module stays the same, so exposing fewer\
654 \ values can help improve compile times!"
655 ]
656 )
658 ModuleName row col ->
659 let
660 region = toRegion row col
661 in
662 Report.Report "EXPECTING MODULE NAME" region [] $
663 Code.toSnippet source region Nothing
664 (
665 D.reflow $
666 "I was parsing an `module` declaration until I got stuck here:"
667 ,
668 D.stack
669 [ D.reflow $
670 "I was expecting to see the module name next, like in these examples:"
671 , D.indent 4 $ D.vcat $
672 [ D.fillSep [D.cyan "module","Dict",D.cyan "exposing","(..)"]
673 , D.fillSep [D.cyan "module","Maybe",D.cyan "exposing","(..)"]
674 , D.fillSep [D.cyan "module","Html.Attributes",D.cyan "exposing","(..)"]
675 , D.fillSep [D.cyan "module","Json.Decode",D.cyan "exposing","(..)"]
676 ]
677 , D.reflow $
678 "Notice that the module names all start with capital letters. That is required!"
679 ]
680 )
682 ModuleExposing exposing row col ->
683 toExposingReport source exposing row col
685 PortModuleProblem row col ->
686 let
687 region = toRegion row col
688 in
689 Report.Report "UNFINISHED PORT MODULE DECLARATION" region [] $
690 Code.toSnippet source region Nothing
691 (
692 D.reflow $
693 "I am parsing an `port module` declaration, but I got stuck here:"
694 ,
695 D.stack
696 [ D.reflow $
697 "Here are some examples of valid `port module` declarations:"
698 , D.indent 4 $ D.vcat $
699 [ D.fillSep [D.cyan "port",D.cyan "module","WebSockets",D.cyan "exposing","(send, listen, keepAlive)"]
700 , D.fillSep [D.cyan "port",D.cyan "module","Maps",D.cyan "exposing","(Location, goto)"]
701 ]
702 , D.link "Note" "Read" "ports" "for more help."
703 ]
704 )
706 PortModuleName row col ->
707 let
708 region = toRegion row col
709 in
710 Report.Report "EXPECTING MODULE NAME" region [] $
711 Code.toSnippet source region Nothing
712 (
713 D.reflow $
714 "I was parsing an `module` declaration until I got stuck here:"
715 ,
716 D.stack
717 [ D.reflow $
718 "I was expecting to see the module name next, like in these examples:"
719 , D.indent 4 $ D.vcat $
720 [ D.fillSep [D.cyan "port",D.cyan "module","WebSockets",D.cyan "exposing","(send, listen, keepAlive)"]
721 , D.fillSep [D.cyan "port",D.cyan "module","Maps",D.cyan "exposing","(Location, goto)"]
722 ]
723 , D.reflow $
724 "Notice that the module names start with capital letters. That is required!"
725 ]
726 )
728 PortModuleExposing exposing row col ->
729 toExposingReport source exposing row col
731 Effect row col ->
732 let
733 region = toRegion row col
734 in
735 Report.Report "BAD MODULE DECLARATION" region [] $
736 Code.toSnippet source region Nothing
737 (
738 D.reflow $
739 "I cannot parse this module declaration:"
740 ,
741 D.reflow $
742 "This type of module is reserved for the @elm organization. It is used to\
743 \ define certain effects, avoiding building them into the compiler."
744 )
746 FreshLine row col ->
747 let
748 region = toRegion row col
750 toBadFirstLineReport keyword =
751 Report.Report "TOO MUCH INDENTATION" region [] $
752 Code.toSnippet source region Nothing
753 (
754 D.reflow $
755 "This `" ++ keyword ++ "` should not have any spaces before it:"
756 ,
757 D.reflow $
758 "Delete the spaces before `" ++ keyword ++ "` until there are none left!"
759 )
761 in
762 case Code.whatIsNext source row col of
763 Code.Keyword "module" -> toBadFirstLineReport "module"
764 Code.Keyword "import" -> toBadFirstLineReport "import"
765 Code.Keyword "type" -> toBadFirstLineReport "type"
766 Code.Keyword "port" -> toBadFirstLineReport "port"
767 _ ->
768 Report.Report "SYNTAX PROBLEM" region [] $
769 Code.toSnippet source region Nothing
770 (
771 D.reflow $
772 "I got stuck here:"
773 ,
774 D.stack
775 [ D.reflow $
776 "I am not sure what is going on, but I recommend starting an Elm\
777 \ file with the following lines:"
778 , D.vcat
779 [ D.fillSep [D.cyan "import","Html"]
780 , ""
781 , D.fillSep [D.green "main","="]
782 , D.indent 2 $ D.fillSep [D.cyan "Html" <> ".text",D.dullyellow "\"Hello!\""]
783 ]
784 , D.reflow $
785 "You should be able to copy those lines directly into your file. Check out\
786 \ some of the examples on https://elm-lang.org for more help getting started!"
787 , D.toSimpleNote $
788 "This can also happen when something is indented too much!"
789 ]
790 )
792 ImportStart row col ->
793 toImportReport source row col
795 ImportName row col ->
796 let
797 region = toRegion row col
798 in
799 Report.Report "EXPECTING IMPORT NAME" region [] $
800 Code.toSnippet source region Nothing
801 (
802 D.reflow $
803 "I was parsing an `import` until I got stuck here:"
804 ,
805 D.stack
806 [ D.reflow $
807 "I was expecting to see a module name next, like in these examples:"
808 , D.indent 4 $ D.vcat $
809 [ D.fillSep [D.cyan "import","Dict"]
810 , D.fillSep [D.cyan "import","Maybe"]
811 , D.fillSep [D.cyan "import","Html.Attributes"]
812 , D.fillSep [D.cyan "import","Json.Decode"]
813 ]
814 , D.reflow $
815 "Notice that the module names all start with capital letters. That is required!"
816 ]
817 )
819 ImportAs row col ->
820 toImportReport source row col
822 ImportAlias row col ->
823 let
824 region = toRegion row col
825 in
826 Report.Report "EXECTING IMPORT ALIAS" region [] $
827 Code.toSnippet source region Nothing
828 (
829 D.reflow $
830 "I was parsing an `import` until I got stuck here:"
831 ,
832 D.stack
833 [ D.reflow $
834 "I was expecting to see an alias next, like in these examples:"
835 , D.indent 4 $ D.vcat $
836 [ D.fillSep [D.cyan "import","Html.Attributes",D.cyan "as","Attr"]
837 , D.fillSep [D.cyan "import","WebGL.Texture",D.cyan "as","Texture"]
838 , D.fillSep [D.cyan "import","Json.Decode",D.cyan "as","D"]
839 ]
840 , D.reflow $
841 "Notice that the alias always starts with a capital letter. That is required!"
842 ]
843 )
845 ImportExposing row col ->
846 toImportReport source row col
848 ImportExposingList exposing row col ->
849 toExposingReport source exposing row col
851 ImportEnd row col ->
852 toImportReport source row col
854 ImportIndentName row col ->
855 toImportReport source row col
857 ImportIndentAlias row col ->
858 toImportReport source row col
860 ImportIndentExposingList row col ->
861 let
862 region = toRegion row col
863 in
864 Report.Report "UNFINISHED IMPORT" region [] $
865 Code.toSnippet source region Nothing
866 (
867 D.reflow $
868 "I was parsing an `import` until I got stuck here:"
869 ,
870 D.stack
871 [ D.reflow $
872 "I was expecting to see the list of exposed values next. For example, here\
873 \ are two ways to expose values from the `Html` module:"
874 , D.indent 4 $ D.vcat $
875 [ D.fillSep [D.cyan "import","Html",D.cyan "exposing","(..)"]
876 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
877 ]
878 , D.reflow $
879 "I generally recommend the second style. It is more explicit, making it\
880 \ much easier to figure out where values are coming from in large projects!"
881 ]
882 )
884 Infix row col ->
885 let
886 region = toRegion row col
887 in
888 Report.Report "BAD INFIX" region [] $
889 Code.toSnippet source region Nothing
890 (
891 D.reflow $
892 "Something went wrong in this infix operator declaration:"
893 ,
894 D.reflow $
895 "This feature is used by the @elm organization to define the\
896 \ languages built-in operators."
897 )
899 Declarations decl _ _ ->
900 toDeclarationsReport source decl
904-- IMPORTS
907toImportReport :: Code.Source -> Row -> Col -> Report.Report
908toImportReport source row col =
909 let
910 region = toRegion row col
911 in
912 Report.Report "UNFINISHED IMPORT" region [] $
913 Code.toSnippet source region Nothing
914 (
915 D.reflow $
916 "I am partway through parsing an import, but I got stuck here:"
917 ,
918 D.stack
919 [ D.reflow $
920 "Here are some examples of valid `import` declarations:"
921 , D.indent 4 $ D.vcat $
922 [ D.fillSep [D.cyan "import","Html"]
923 , D.fillSep [D.cyan "import","Html",D.cyan "as","H"]
924 , D.fillSep [D.cyan "import","Html",D.cyan "as","H",D.cyan "exposing","(..)"]
925 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
926 ]
927 , D.reflow $
928 "You are probably trying to import a different module, but try to make it look like one of these examples!"
929 ]
930 )
934-- EXPOSING
937toExposingReport :: Code.Source -> Exposing -> Row -> Col -> Report.Report
938toExposingReport source exposing startRow startCol =
939 case exposing of
940 ExposingSpace space row col ->
941 toSpaceReport source space row col
943 ExposingStart row col ->
944 let
945 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
946 region = toRegion row col
947 in
948 Report.Report "PROBLEM IN EXPOSING" region [] $
949 Code.toSnippet source surroundings (Just region)
950 (
951 D.reflow $
952 "I want to parse exposed values, but I am getting stuck here:"
953 ,
954 D.stack
955 [ D.fillSep $
956 ["Exposed","values","are","always","surrounded","by","parentheses."
957 ,"So","try","adding","a",D.green "(","here?"
958 ]
959 , D.toSimpleNote "Here are some valid examples of `exposing` for reference:"
960 , D.indent 4 $ D.vcat $
961 [ D.fillSep [D.cyan "import","Html",D.cyan "exposing","(..)"]
962 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
963 ]
964 , D.reflow $
965 "If you are getting tripped up, you can just expose everything for now. It should\
966 \ get easier to make an explicit exposing list as you see more examples in the wild."
967 ]
968 )
970 ExposingValue row col ->
971 case Code.whatIsNext source row col of
972 Code.Keyword keyword ->
973 let
974 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
975 region = toKeywordRegion row col keyword
976 in
977 Report.Report "RESERVED WORD" region [] $
978 Code.toSnippet source surroundings (Just region)
979 (
980 D.reflow $
981 "I got stuck on this reserved word:"
982 ,
983 D.reflow $
984 "It looks like you are trying to expose `" ++ keyword ++ "` but that is a reserved word. Is there a typo?"
985 )
987 Code.Operator op ->
988 let
989 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
990 region = toKeywordRegion row col op
991 in
992 Report.Report "UNEXPECTED SYMBOL" region [] $
993 Code.toSnippet source surroundings (Just region)
994 (
995 D.reflow $
996 "I got stuck on this symbol:"
997 ,
998 D.stack
999 [ D.reflow $
1000 "If you are trying to expose an operator, add parentheses around it like this:"
1001 , D.indent 4 $ D.dullyellow (D.fromChars op) <> " -> " <> D.green ("(" <> D.fromChars op <> ")")
1005 _ ->
1006 let
1007 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1008 region = toRegion row col
1009 in
1010 Report.Report "PROBLEM IN EXPOSING" region [] $
1011 Code.toSnippet source surroundings (Just region)
1013 D.reflow $
1014 "I got stuck while parsing these exposed values:"
1016 D.stack
1017 [ D.reflow $
1018 "I do not have an exact recommendation, so here are some valid examples\
1019 \ of `exposing` for reference:"
1020 , D.indent 4 $ D.vcat $
1021 [ D.fillSep [D.cyan "import","Html",D.cyan "exposing","(..)"]
1022 , D.fillSep [D.cyan "import","Basics",D.cyan "exposing","(Int, Float, Bool(..), (+), not, sqrt)"]
1024 , D.reflow $
1025 "These examples show how to expose types, variants, operators, and functions. Everything\
1026 \ should be some permutation of these examples, just with different names."
1030 ExposingOperator row col ->
1031 let
1032 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1033 region = toRegion row col
1034 in
1035 Report.Report "PROBLEM IN EXPOSING" region [] $
1036 Code.toSnippet source surroundings (Just region)
1038 D.reflow $
1039 "I just saw an open parenthesis, so I was expecting an operator next:"
1041 D.fillSep $
1042 ["It","is","possible","to","expose","operators,","so","I","was","expecting"
1043 ,"to","see","something","like",D.dullyellow "(+)","or",D.dullyellow "(|=)"
1044 ,"or",D.dullyellow "(||)","after","I","saw","that","open","parenthesis."
1048 ExposingOperatorReserved op row col ->
1049 let
1050 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1051 region = toRegion row col
1052 in
1053 Report.Report "RESERVED SYMBOL" region [] $
1054 Code.toSnippet source surroundings (Just region)
1056 D.reflow $
1057 "I cannot expose this as an operator:"
1059 case op of
1060 BadDot -> D.reflow "Try getting rid of this entry? Maybe I can give you a better hint after that?"
1061 BadPipe -> D.fillSep ["Maybe","you","want",D.dullyellow "(||)","instead?"]
1062 BadArrow -> D.reflow "Try getting rid of this entry? Maybe I can give you a better hint after that?"
1063 BadEquals -> D.fillSep ["Maybe","you","want",D.dullyellow "(==)","instead?"]
1064 BadHasType -> D.fillSep ["Maybe","you","want",D.dullyellow "(::)","instead?"]
1067 ExposingOperatorRightParen row col ->
1068 let
1069 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1070 region = toRegion row col
1071 in
1072 Report.Report "PROBLEM IN EXPOSING" region [] $
1073 Code.toSnippet source surroundings (Just region)
1075 D.reflow $
1076 "It looks like you are exposing an operator, but I got stuck here:"
1078 D.fillSep $
1079 ["I","was","expecting","to","see","the","closing","parenthesis","immediately"
1080 ,"after","the","operator.","Try","adding","a",D.green ")","right","here?"
1084 ExposingEnd row col ->
1085 let
1086 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1087 region = toRegion row col
1088 in
1089 Report.Report "UNFINISHED EXPOSING" region [] $
1090 Code.toSnippet source surroundings (Just region)
1092 D.reflow $
1093 "I was partway through parsing exposed values, but I got stuck here:"
1095 D.reflow $
1096 "Maybe there is a comma missing before this?"
1099 ExposingTypePrivacy row col ->
1100 let
1101 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1102 region = toRegion row col
1103 in
1104 Report.Report "PROBLEM EXPOSING CUSTOM TYPE VARIANTS" region [] $
1105 Code.toSnippet source surroundings (Just region)
1107 D.reflow $
1108 "It looks like you are trying to expose the variants of a custom type:"
1110 D.stack
1111 [ D.fillSep $
1112 ["You","need","to","write","something","like"
1113 ,D.dullyellow "Status(..)","or",D.dullyellow "Entity(..)"
1114 ,"though.","It","is","all","or","nothing,","otherwise","`case`"
1115 ,"expressions","could","miss","a","variant","and","crash!"
1117 , D.toSimpleNote $
1118 "It is often best to keep the variants hidden! If someone pattern matches on\
1119 \ the variants, it is a MAJOR change if any new variants are added. Suddenly\
1120 \ their `case` expressions do not cover all variants! So if you do not need\
1121 \ people to pattern match, keep the variants hidden and expose functions to\
1122 \ construct values of this type. This way you can add new variants as a MINOR change!"
1126 ExposingIndentEnd row col ->
1127 let
1128 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1129 region = toRegion row col
1130 in
1131 Report.Report "UNFINISHED EXPOSING" region [] $
1132 Code.toSnippet source surroundings (Just region)
1134 D.reflow $
1135 "I was partway through parsing exposed values, but I got stuck here:"
1137 D.stack
1138 [ D.fillSep $
1139 ["I","was","expecting","a","closing","parenthesis."
1140 ,"Try","adding","a",D.green ")","right","here?"
1142 , D.toSimpleNote $
1143 "I can get confused when there is not enough indentation, so if you already\
1144 \ have a closing parenthesis, it probably just needs some spaces in front of it."
1148 ExposingIndentValue row col ->
1149 let
1150 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1151 region = toRegion row col
1152 in
1153 Report.Report "UNFINISHED EXPOSING" region [] $
1154 Code.toSnippet source surroundings (Just region)
1156 D.reflow $
1157 "I was partway through parsing exposed values, but I got stuck here:"
1159 D.reflow $
1160 "I was expecting another value to expose."
1165-- SPACES
1168toSpaceReport :: Code.Source -> Space -> Row -> Col -> Report.Report
1169toSpaceReport source space row col =
1170 case space of
1171 HasTab ->
1172 let
1173 region = toRegion row col
1174 in
1175 Report.Report "NO TABS" region [] $
1176 Code.toSnippet source region Nothing
1178 D.reflow $
1179 "I ran into a tab, but tabs are not allowed in Elm files."
1181 D.reflow $
1182 "Replace the tab with spaces."
1185 EndlessMultiComment ->
1186 let
1187 region = toWiderRegion row col 2
1188 in
1189 Report.Report "ENDLESS COMMENT" region [] $
1190 Code.toSnippet source region Nothing
1192 D.reflow $
1193 "I cannot find the end of this multi-line comment:"
1195 D.stack -- "{-"
1196 [ D.reflow "Add a -} somewhere after this to end the comment."
1197 , D.toSimpleHint
1198 "Multi-line comments can be nested in Elm, so {- {- -} -} is a comment\
1199 \ that happens to contain another comment. Like parentheses and curly braces,\
1200 \ the start and end markers must always be balanced. Maybe that is the problem?"
1206-- DECLARATIONS
1209toRegion :: Row -> Col -> A.Region
1210toRegion row col =
1211 let
1212 pos = A.Position row col
1213 in
1214 A.Region pos pos
1217toWiderRegion :: Row -> Col -> Word16 -> A.Region
1218toWiderRegion row col extra =
1219 A.Region
1220 (A.Position row col)
1221 (A.Position row (col + extra))
1224toKeywordRegion :: Row -> Col -> [Char.Char] -> A.Region
1225toKeywordRegion row col keyword =
1226 A.Region
1227 (A.Position row col)
1228 (A.Position row (col + fromIntegral (length keyword)))
1231toDeclarationsReport :: Code.Source -> Decl -> Report.Report
1232toDeclarationsReport source decl =
1233 case decl of
1234 DeclStart row col ->
1235 case Code.whatIsNext source row col of
1236 Code.Close term bracket ->
1237 let
1238 region = toRegion row col
1239 in
1240 Report.Report ("STRAY " ++ map Char.toUpper term) region [] $
1241 Code.toSnippet source region Nothing
1243 D.reflow $
1244 "I was not expecting to see a " ++ term ++ " here:"
1245 , D.reflow $
1246 "This " ++ bracket : " does not match up with an earlier open " ++ term ++ ". Try deleting it?"
1249 Code.Keyword keyword ->
1250 let
1251 region = toKeywordRegion row col keyword
1252 in
1253 Report.Report "RESERVED WORD" region [] $
1254 Code.toSnippet source region Nothing
1256 D.reflow $
1257 "I was not expecting to run into the `" ++ keyword ++ "` keyword here:"
1259 case keyword of
1260 "import" ->
1261 D.reflow $
1262 "It is reserved for declaring imports at the top of your module. If you want\
1263 \ another import, try moving it up top with the other imports. If you want to\
1264 \ define a value or function, try changing the name to something else!"
1266 "case" ->
1267 D.stack
1268 [ D.reflow $
1269 "It is reserved for writing `case` expressions. Try using a different name?"
1270 , D.toSimpleNote $
1271 "If you are trying to write a `case` expression, it needs to be part of a\
1272 \ definition. So you could write something like this instead:"
1273 , D.vcat $
1274 [ D.indent 0 $ D.fillSep [D.green "getWidth","maybeWidth","="]
1275 , D.indent 2 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
1276 , D.indent 4 $ D.fillSep [D.blue "Just","width","->"]
1277 , D.indent 6 $ D.fillSep ["width","+",D.dullyellow "200"]
1278 , ""
1279 , D.indent 4 $ D.fillSep [D.blue "Nothing","->"]
1280 , D.indent 6 $ D.fillSep [D.dullyellow "400"]
1282 , D.reflow $
1283 "This defines a `getWidth` function that we can use elsewhere in our program."
1286 "if" ->
1287 D.stack
1288 [ D.reflow $
1289 "It is reserved for writing `if` expressions. Try using a different name?"
1290 , D.toSimpleNote $
1291 "If you are trying to write an `if` expression, it needs to be part of a\
1292 \ definition. So you could write something like this instead:"
1293 , D.vcat $
1294 [ D.indent 0 $ D.fillSep [D.green "reviewPowerLevel","powerLevel","="]
1295 , D.indent 2 $ D.fillSep $
1296 [D.cyan "if","powerLevel",">",D.dullyellow "9000"
1297 ,D.cyan "then",D.dullyellow "\"OVER 9000!!!\""
1298 ,D.cyan "else",D.dullyellow "\"not bad\""
1301 , D.reflow $
1302 "This defines a `reviewPowerLevel` function that we can use elsewhere in our program."
1305 _ ->
1306 D.reflow $
1307 "It is a reserved word. Try changing the name to something else?"
1310 _ ->
1311 let
1312 region = toRegion row col
1313 in
1314 Report.Report "SYNTAX PROBLEM" region [] $
1315 Code.toSnippet source region Nothing
1317 D.reflow $
1318 "I was expecting to see a new declaration here:"
1320 D.stack
1321 [ D.reflow $
1322 "I am not sure what is going wrong exactly, but here are a couple valid\
1323 \ declarations for reference:"
1324 , D.vcat
1325 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
1326 , D.fillSep [D.green "add","x","y","="]
1327 , D.fillSep [" ","x","+","y"]
1329 , D.fillSep [D.cyan "type",D.green "User","=","Anonymous","|","LoggedIn String"]
1330 , D.reflow $
1331 "Note that all declarations start with lower-case letters in Elm. Capitalization\
1332 \ makes a difference, so be consious of that if you are working from examples!"
1336 DeclSpace space row col ->
1337 toSpaceReport source space row col
1339 Port port_ row col ->
1340 toPortReport source port_ row col
1342 DeclType declType row col ->
1343 toDeclTypeReport source declType row col
1345 DeclDef name declDef row col ->
1346 toDeclDefReport source name declDef row col
1348 DeclFreshLineAfterDocComment row col ->
1349 let
1350 region = toRegion row col
1351 in
1352 Report.Report "EXPECTING DECLARATION" region [] $
1353 Code.toSnippet source region Nothing
1355 D.reflow $
1356 "I just saw a doc comment, but then I got stuck here:"
1358 D.reflow $
1359 "I was expecting to see the corresponding declaration next, starting on a fresh\
1360 \ line with no indentation."
1365-- PORT
1368toPortReport :: Code.Source -> Port -> Row -> Col -> Report.Report
1369toPortReport source port_ startRow startCol =
1370 case port_ of
1371 PortSpace space row col ->
1372 toSpaceReport source space row col
1374 PortName row col ->
1375 case Code.whatIsNext source row col of
1376 Code.Keyword keyword ->
1377 let
1378 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1379 region = toKeywordRegion row col keyword
1380 in
1381 Report.Report "RESERVED WORD" region [] $
1382 Code.toSnippet source surroundings (Just region)
1384 D.reflow $
1385 "I cannot handle ports with names like this:"
1387 D.reflow $
1388 "You are trying to make a port named `" ++ keyword
1389 ++ "` but that is a reserved word. Try using some other name?"
1392 _ ->
1393 let
1394 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1395 region = toRegion row col
1396 in
1397 Report.Report "PORT PROBLEM" region [] $
1398 Code.toSnippet source surroundings (Just region)
1400 D.reflow $
1401 "I just saw the start of a `port` declaration, but then I got stuck here:"
1403 D.stack
1404 [ D.fillSep
1405 ["I","was","expecting","to","see","a","name","like"
1406 ,D.dullyellow "send","or",D.dullyellow "receive","next."
1407 ,"Something","that","starts","with","a","lower-case","letter."
1409 , portNote
1413 PortColon row col ->
1414 let
1415 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1416 region = toRegion row col
1417 in
1418 Report.Report "PORT PROBLEM" region [] $
1419 Code.toSnippet source surroundings (Just region)
1421 D.reflow $
1422 "I just saw the start of a `port` declaration, but then I got stuck here:"
1424 D.stack
1425 [ D.reflow $
1426 "I was expecting to see a colon next. And then a type that tells me\
1427 \ what type of values are going to flow through."
1428 , portNote
1432 PortType tipe row col ->
1433 toTypeReport source TC_Port tipe row col
1435 PortIndentName row col ->
1436 let
1437 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1438 region = toRegion row col
1439 in
1440 Report.Report "UNFINISHED PORT" region [] $
1441 Code.toSnippet source surroundings (Just region)
1443 D.reflow $
1444 "I just saw the start of a `port` declaration, but then I got stuck here:"
1446 D.stack
1447 [ D.fillSep
1448 ["I","was","expecting","to","see","a","name","like"
1449 ,D.dullyellow "send","or",D.dullyellow "receive","next."
1450 ,"Something","that","starts","with","a","lower-case","letter."
1452 , portNote
1456 PortIndentColon row col ->
1457 let
1458 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1459 region = toRegion row col
1460 in
1461 Report.Report "UNFINISHED PORT" region [] $
1462 Code.toSnippet source surroundings (Just region)
1464 D.reflow $
1465 "I just saw the start of a `port` declaration, but then I got stuck here:"
1467 D.stack
1468 [ D.reflow $
1469 "I was expecting to see a colon next. And then a type that tells me\
1470 \ what type of values are going to flow through."
1471 , portNote
1475 PortIndentType row col ->
1476 let
1477 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1478 region = toRegion row col
1479 in
1480 Report.Report "UNFINISHED PORT" region [] $
1481 Code.toSnippet source surroundings (Just region)
1483 D.reflow $
1484 "I just saw the start of a `port` declaration, but then I got stuck here:"
1486 D.stack
1487 [ D.reflow $
1488 "I was expecting to see a type next. Here are examples of outgoing and\
1489 \ incoming ports for reference:"
1490 , D.vcat
1491 [ D.fillSep [D.cyan "port","send",":","String -> Cmd msg"]
1492 , D.fillSep [D.cyan "port","receive",":","(String -> msg) -> Sub msg"]
1494 , D.reflow $
1495 "The first line defines a `send` port so you can send strings out to JavaScript.\
1496 \ Maybe you send them on a WebSocket or put them into IndexedDB. The second line\
1497 \ defines a `receive` port so you can receive strings from JavaScript. Maybe you\
1498 \ get receive messages when new WebSocket messages come in or when an entry in\
1499 \ IndexedDB changes for some external reason."
1504portNote :: D.Doc
1505portNote =
1506 D.stack
1507 [ D.toSimpleNote $
1508 "Here are some example `port` declarations for reference:"
1509 , D.vcat
1510 [ D.fillSep [D.cyan "port","send",":","String -> Cmd msg"]
1511 , D.fillSep [D.cyan "port","receive",":","(String -> msg) -> Sub msg"]
1513 , D.reflow $
1514 "The first line defines a `send` port so you can send strings out to JavaScript.\
1515 \ Maybe you send them on a WebSocket or put them into IndexedDB. The second line\
1516 \ defines a `receive` port so you can receive strings from JavaScript. Maybe you\
1517 \ get receive messages when new WebSocket messages come in or when the IndexedDB\
1518 \ is changed for some external reason."
1523-- DECL TYPE
1526toDeclTypeReport :: Code.Source -> DeclType -> Row -> Col -> Report.Report
1527toDeclTypeReport source declType startRow startCol =
1528 case declType of
1529 DT_Space space row col ->
1530 toSpaceReport source space row col
1532 DT_Name row col ->
1533 let
1534 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1535 region = toRegion row col
1536 in
1537 Report.Report "EXPECTING TYPE NAME" region [] $
1538 Code.toSnippet source surroundings (Just region)
1540 D.reflow $
1541 "I think I am parsing a type declaration, but I got stuck here:"
1543 D.stack
1544 [ D.fillSep $
1545 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1546 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1548 , customTypeNote
1552 DT_Alias typeAlias row col ->
1553 toTypeAliasReport source typeAlias row col
1555 DT_Union customType row col ->
1556 toCustomTypeReport source customType row col
1558 DT_IndentName row col ->
1559 let
1560 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1561 region = toRegion row col
1562 in
1563 Report.Report "EXPECTING TYPE NAME" region [] $
1564 Code.toSnippet source surroundings (Just region)
1566 D.reflow $
1567 "I think I am parsing a type declaration, but I got stuck here:"
1569 D.stack
1570 [ D.fillSep $
1571 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1572 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1574 , customTypeNote
1579toTypeAliasReport :: Code.Source -> TypeAlias -> Row -> Col -> Report.Report
1580toTypeAliasReport source typeAlias startRow startCol =
1581 case typeAlias of
1582 AliasSpace space row col ->
1583 toSpaceReport source space row col
1585 AliasName row col ->
1586 let
1587 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1588 region = toRegion row col
1589 in
1590 Report.Report "EXPECTING TYPE ALIAS NAME" region [] $
1591 Code.toSnippet source surroundings (Just region)
1593 D.reflow $
1594 "I am partway through parsing a type alias, but I got stuck here:"
1596 D.stack
1597 [ D.fillSep $
1598 ["I","was","expecting","a","name","like",D.dullyellow "Person","or",D.dullyellow "Point"
1599 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1601 , typeAliasNote
1605 AliasEquals row col ->
1606 case Code.whatIsNext source row col of
1607 Code.Keyword keyword ->
1608 let
1609 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1610 region = toKeywordRegion row col keyword
1611 in
1612 Report.Report "RESERVED WORD" region [] $
1613 Code.toSnippet source surroundings (Just region)
1615 D.reflow $
1616 "I ran into a reserved word unexpectedly while parsing this type alias:"
1618 D.stack
1619 [ D.reflow $
1620 "It looks like you are trying use `" ++ keyword
1621 ++ "` as a type variable, but it is a reserved word. Try using a different name?"
1622 , typeAliasNote
1626 _ ->
1627 let
1628 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1629 region = toRegion row col
1630 in
1631 Report.Report "PROBLEM IN TYPE ALIAS" region [] $
1632 Code.toSnippet source surroundings (Just region)
1634 D.reflow $
1635 "I am partway through parsing a type alias, but I got stuck here:"
1637 D.stack
1638 [ D.reflow $
1639 "I was expecting to see a type variable or an an equals sign next."
1640 , typeAliasNote
1644 AliasBody tipe row col ->
1645 toTypeReport source TC_TypeAlias tipe row col
1647 AliasIndentEquals row col ->
1648 let
1649 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1650 region = toRegion row col
1651 in
1652 Report.Report "UNFINISHED TYPE ALIAS" region [] $
1653 Code.toSnippet source surroundings (Just region)
1655 D.reflow $
1656 "I am partway through parsing a type alias, but I got stuck here:"
1658 D.stack
1659 [ D.reflow $
1660 "I was expecting to see a type variable or an an equals sign next."
1661 , typeAliasNote
1665 AliasIndentBody row col ->
1666 let
1667 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1668 region = toRegion row col
1669 in
1670 Report.Report "UNFINISHED TYPE ALIAS" region [] $
1671 Code.toSnippet source surroundings (Just region)
1673 D.reflow $
1674 "I am partway through parsing a type alias, but I got stuck here:"
1676 D.stack
1677 [ D.fillSep $
1678 ["I","was","expecting","to","see","a","type","next.","Something","as","simple"
1679 ,"as",D.dullyellow "Int","or",D.dullyellow "Float","would","work!"
1681 , typeAliasNote
1686typeAliasNote :: D.Doc
1687typeAliasNote =
1688 D.stack
1689 [ D.toSimpleNote $
1690 "Here is an example of a valid `type alias` for reference:"
1691 , D.vcat $
1692 [ D.indent 0 $ D.fillSep [D.cyan "type",D.cyan "alias",D.green "Person","="]
1693 , D.indent 2 $ D.vcat $
1694 ["{ name : String"
1695 ,", age : Int"
1696 ,", height : Float"
1697 ,"}"
1700 , D.reflow $
1701 "This would let us use `Person` as a shorthand for that record type. Using this\
1702 \ shorthand makes type annotations much easier to read, and makes changing code\
1703 \ easier if you decide later that there is more to a person than age and height!"
1707toCustomTypeReport :: Code.Source -> CustomType -> Row -> Col -> Report.Report
1708toCustomTypeReport source customType startRow startCol =
1709 case customType of
1710 CT_Space space row col ->
1711 toSpaceReport source space row col
1713 CT_Name row col ->
1714 let
1715 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1716 region = toRegion row col
1717 in
1718 Report.Report "EXPECTING TYPE NAME" region [] $
1719 Code.toSnippet source surroundings (Just region)
1721 D.reflow $
1722 "I think I am parsing a type declaration, but I got stuck here:"
1724 D.stack
1725 [ D.fillSep $
1726 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1727 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1729 , customTypeNote
1733 CT_Equals row col ->
1734 case Code.whatIsNext source row col of
1735 Code.Keyword keyword ->
1736 let
1737 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1738 region = toKeywordRegion row col keyword
1739 in
1740 Report.Report "RESERVED WORD" region [] $
1741 Code.toSnippet source surroundings (Just region)
1743 D.reflow $
1744 "I ran into a reserved word unexpectedly while parsing this custom type:"
1746 D.stack
1747 [ D.reflow $
1748 "It looks like you are trying use `" ++ keyword
1749 ++ "` as a type variable, but it is a reserved word. Try using a different name?"
1750 , customTypeNote
1754 _ ->
1755 let
1756 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1757 region = toRegion row col
1758 in
1759 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
1760 Code.toSnippet source surroundings (Just region)
1762 D.reflow $
1763 "I am partway through parsing a custom type, but I got stuck here:"
1765 D.stack
1766 [ D.reflow $
1767 "I was expecting to see a type variable or an an equals sign next."
1768 , customTypeNote
1772 CT_Bar row col ->
1773 let
1774 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1775 region = toRegion row col
1776 in
1777 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
1778 Code.toSnippet source surroundings (Just region)
1780 D.reflow $
1781 "I am partway through parsing a custom type, but I got stuck here:"
1783 D.stack
1784 [ D.reflow $
1785 "I was expecting to see a vertical bar like | next."
1786 , customTypeNote
1790 CT_Variant row col ->
1791 let
1792 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1793 region = toRegion row col
1794 in
1795 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
1796 Code.toSnippet source surroundings (Just region)
1798 D.reflow $
1799 "I am partway through parsing a custom type, but I got stuck here:"
1801 D.stack
1802 [ D.fillSep $
1803 ["I","was","expecting","to","see","a","variant","name","next."
1804 ,"Something","like",D.dullyellow "Success","or",D.dullyellow "Sandwich" <> "."
1805 ,"Any","name","that","starts","with","a","capital","letter","really!"
1807 , customTypeNote
1811 CT_VariantArg tipe row col ->
1812 toTypeReport source TC_CustomType tipe row col
1814 CT_IndentEquals row col ->
1815 let
1816 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1817 region = toRegion row col
1818 in
1819 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1820 Code.toSnippet source surroundings (Just region)
1822 D.reflow $
1823 "I am partway through parsing a custom type, but I got stuck here:"
1825 D.stack
1826 [ D.reflow $
1827 "I was expecting to see a type variable or an an equals sign next."
1828 , customTypeNote
1832 CT_IndentBar row col ->
1833 let
1834 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1835 region = toRegion row col
1836 in
1837 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1838 Code.toSnippet source surroundings (Just region)
1840 D.reflow $
1841 "I am partway through parsing a custom type, but I got stuck here:"
1843 D.stack
1844 [ D.reflow $
1845 "I was expecting to see a vertical bar like | next."
1846 , customTypeNote
1850 CT_IndentAfterBar row col ->
1851 let
1852 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1853 region = toRegion row col
1854 in
1855 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1856 Code.toSnippet source surroundings (Just region)
1858 D.reflow $
1859 "I am partway through parsing a custom type, but I got stuck here:"
1861 D.stack
1862 [ D.reflow $
1863 "I just saw a vertical bar, so I was expecting to see another variant defined next."
1864 , customTypeNote
1868 CT_IndentAfterEquals row col ->
1869 let
1870 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1871 region = toRegion row col
1872 in
1873 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1874 Code.toSnippet source surroundings (Just region)
1876 D.reflow $
1877 "I am partway through parsing a custom type, but I got stuck here:"
1879 D.stack
1880 [ D.reflow $
1881 "I just saw an equals sign, so I was expecting to see the first variant defined next."
1882 , customTypeNote
1887customTypeNote :: D.Doc
1888customTypeNote =
1889 D.stack
1890 [ D.toSimpleNote $
1891 "Here is an example of a valid `type` declaration for reference:"
1892 , D.vcat $
1893 [ D.indent 0 $ D.fillSep [D.cyan "type",D.green "Status"]
1894 , D.indent 2 $ D.fillSep ["=","Failure"]
1895 , D.indent 2 $ D.fillSep ["|","Waiting"]
1896 , D.indent 2 $ D.fillSep ["|","Success","String"]
1898 , D.reflow $
1899 "This defines a new `Status` type with three variants. This could be useful if\
1900 \ we are waiting for an HTTP request. Maybe we start with `Waiting` and then\
1901 \ switch to `Failure` or `Success \"message from server\"` depending on how\
1902 \ things go. Notice that the Success variant has some associated data, allowing\
1903 \ us to store a String if the request goes well!"
1908-- DECL DEF
1911toDeclDefReport :: Code.Source -> Name.Name -> DeclDef -> Row -> Col -> Report.Report
1912toDeclDefReport source name declDef startRow startCol =
1913 case declDef of
1914 DeclDefSpace space row col ->
1915 toSpaceReport source space row col
1917 DeclDefEquals row col ->
1918 case Code.whatIsNext source row col of
1919 Code.Keyword keyword ->
1920 let
1921 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1922 region = toKeywordRegion row col keyword
1923 in
1924 Report.Report "RESERVED WORD" region [] $
1925 Code.toSnippet source surroundings (Just region)
1927 D.reflow $
1928 "It looks like you are trying to use `" ++ keyword ++ "` as an argument:"
1930 D.reflow $
1931 "This is a reserved word! Try using some other name?"
1934 Code.Operator op ->
1935 let
1936 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1937 region = toKeywordRegion row col op
1938 in
1939 Report.Report "UNEXPECTED SYMBOL" region [] $
1940 Code.toSnippet source surroundings (Just region)
1942 D.reflow $
1943 "I was not expecting to see this symbol here:"
1945 D.stack
1946 [ D.reflow $
1947 "I am not sure what is going wrong exactly, so here is a valid\
1948 \ definition (with an optional type annotation) for reference:"
1949 , D.vcat
1950 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
1951 , D.fillSep [D.green "add","x","y","="]
1952 , D.fillSep [" ","x","+","y"]
1954 , D.reflow $
1955 "Try to use that format with your `" ++ Name.toChars name ++ "` definition!"
1959 _ ->
1960 let
1961 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1962 region = toRegion row col
1963 in
1964 Report.Report "PROBLEM IN DEFINITION" region [] $
1965 Code.toSnippet source surroundings (Just region)
1967 D.reflow $
1968 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
1970 D.stack
1971 [ D.reflow $
1972 "I am not sure what is going wrong exactly, so here is a valid\
1973 \ definition (with an optional type annotation) for reference:"
1974 , D.vcat
1975 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
1976 , D.fillSep [D.green "add","x","y","="]
1977 , D.fillSep [" ","x","+","y"]
1979 , D.reflow $
1980 "Try to use that format!"
1984 DeclDefType tipe row col ->
1985 toTypeReport source (TC_Annotation name) tipe row col
1987 DeclDefArg pattern row col ->
1988 toPatternReport source PArg pattern row col
1990 DeclDefBody expr row col ->
1991 toExprReport source (InDef name startRow startCol) expr row col
1993 DeclDefNameRepeat row col ->
1994 let
1995 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1996 region = toRegion row col
1997 in
1998 Report.Report "EXPECTING DEFINITION" region [] $
1999 Code.toSnippet source surroundings (Just region)
2001 D.reflow $
2002 "I just saw the type annotation for `" ++ Name.toChars name
2003 ++ "` so I was expecting to see its definition here:"
2005 D.stack
2006 [ D.reflow $
2007 "Type annotations always appear directly above the relevant\
2008 \ definition, without anything else in between. (Not even doc comments!)"
2009 , declDefNote
2013 DeclDefNameMatch defName row col ->
2014 let
2015 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2016 region = toRegion row col
2017 in
2018 Report.Report "NAME MISMATCH" region [] $
2019 Code.toSnippet source surroundings (Just region)
2021 D.reflow $
2022 "I just saw a type annotation for `" ++ Name.toChars name ++ "`, but it is followed by a definition for `" ++ Name.toChars defName ++ "`:"
2024 D.stack
2025 [ D.reflow $
2026 "These names do not match! Is there a typo?"
2027 , D.indent 4 $ D.fillSep $
2028 [D.dullyellow (D.fromName defName),"->",D.green (D.fromName name)]
2032 DeclDefIndentType row col ->
2033 let
2034 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2035 region = toRegion row col
2036 in
2037 Report.Report "UNFINISHED DEFINITION" region [] $
2038 Code.toSnippet source surroundings (Just region)
2040 D.reflow $
2041 "I got stuck while parsing the `" ++ Name.toChars name ++ "` type annotation:"
2043 D.stack
2044 [ D.reflow $
2045 "I just saw a colon, so I am expecting to see a type next."
2046 , declDefNote
2050 DeclDefIndentEquals row col ->
2051 let
2052 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2053 region = toRegion row col
2054 in
2055 Report.Report "UNFINISHED DEFINITION" region [] $
2056 Code.toSnippet source surroundings (Just region)
2058 D.reflow $
2059 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
2061 D.stack
2062 [ D.reflow $
2063 "I was expecting to see an argument or an equals sign next."
2064 , declDefNote
2068 DeclDefIndentBody row col ->
2069 let
2070 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2071 region = toRegion row col
2072 in
2073 Report.Report "UNFINISHED DEFINITION" region [] $
2074 Code.toSnippet source surroundings (Just region)
2076 D.reflow $
2077 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
2079 D.stack
2080 [ D.reflow $
2081 "I was expecting to see an expression next. What is it equal to?"
2082 , declDefNote
2087declDefNote :: D.Doc
2088declDefNote =
2089 D.stack
2090 [ D.reflow $
2091 "Here is a valid definition (with a type annotation) for reference:"
2092 , D.vcat
2093 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
2094 , D.fillSep [D.green "add","x","y","="]
2095 , D.fillSep [" ","x","+","y"]
2097 , D.reflow $
2098 "The top line (called a \"type annotation\") is optional. You can leave it off\
2099 \ if you want. As you get more comfortable with Elm and as your project grows,\
2100 \ it becomes more and more valuable to add them though! They work great as\
2101 \ compiler-verified documentation, and they often improve error messages!"
2106-- CONTEXT
2109data Context
2110 = InNode Node Row Col Context
2111 | InDef Name.Name Row Col
2112 | InDestruct Row Col
2115data Node
2116 = NRecord
2117 | NParens
2118 | NList
2119 | NFunc
2120 | NCond
2121 | NThen
2122 | NElse
2123 | NCase
2124 | NBranch
2125 deriving (Eq)
2128getDefName :: Context -> Maybe Name.Name
2129getDefName context =
2130 case context of
2131 InDestruct _ _ -> Nothing
2132 InDef name _ _ -> Just name
2133 InNode _ _ _ c -> getDefName c
2136isWithin :: Node -> Context -> Bool
2137isWithin desiredNode context =
2138 case context of
2139 InDestruct _ _ -> False
2140 InDef _ _ _ -> False
2141 InNode actualNode _ _ _ -> desiredNode == actualNode
2145-- EXPR REPORTS
2148toExprReport :: Code.Source -> Context -> Expr -> Row -> Col -> Report.Report
2149toExprReport source context expr startRow startCol =
2150 case expr of
2151 Let let_ row col ->
2152 toLetReport source context let_ row col
2154 Case case_ row col ->
2155 toCaseReport source context case_ row col
2157 If if_ row col ->
2158 toIfReport source context if_ row col
2160 List list row col ->
2161 toListReport source context list row col
2163 Record record row col ->
2164 toRecordReport source context record row col
2166 Tuple tuple row col ->
2167 toTupleReport source context tuple row col
2169 Func func row col ->
2170 toFuncReport source context func row col
2172 Dot row col ->
2173 let region = toRegion row col in
2174 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
2175 Code.toSnippet source region Nothing
2177 D.reflow $
2178 "I was expecting to see a record accessor here:"
2180 D.fillSep
2181 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
2182 ,"that","accesses","a","value","from","a","record."
2186 Access row col ->
2187 let region = toRegion row col in
2188 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
2189 Code.toSnippet source region Nothing
2191 D.reflow $
2192 "I am trying to parse a record accessor here:"
2194 D.stack
2196 D.fillSep
2197 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
2198 ,"that","accesses","a","value","from","a","record."
2201 D.toSimpleNote $
2202 "Record field names must start with a lower case letter!"
2206 OperatorRight op row col ->
2207 let region = toRegion row col in
2208 Report.Report "MISSING EXPRESSION" region [] $
2209 Code.toSnippet source region Nothing
2211 D.reflow $
2212 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
2214 D.stack
2215 [ D.fillSep $
2216 ["You","can","just","put","anything","for","now,","like"
2217 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
2218 ,"Once","there","is","something","there,","I","can","probably"
2219 ,"give","a","more","specific","hint!"
2221 , D.toSimpleNote $
2222 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
2223 \ Or if I run into operators in unexpected spots. Point is, there are a\
2224 \ couple ways I can get confused and give sort of weird advice!"
2228 OperatorReserved operator row col ->
2229 toOperatorReport source context operator row col
2231 Start row col ->
2232 let
2233 (contextRow, contextCol, aThing) =
2234 case context of
2235 InDestruct r c -> (r, c, "a definition")
2236 InDef name r c -> (r, c, "the `" ++ Name.toChars name ++ "` definition")
2237 InNode NRecord r c _ -> (r, c, "a record")
2238 InNode NParens r c _ -> (r, c, "some parentheses")
2239 InNode NList r c _ -> (r, c, "a list")
2240 InNode NFunc r c _ -> (r, c, "an anonymous function")
2241 InNode NCond r c _ -> (r, c, "an `if` expression")
2242 InNode NThen r c _ -> (r, c, "an `if` expression")
2243 InNode NElse r c _ -> (r, c, "an `if` expression")
2244 InNode NCase r c _ -> (r, c, "a `case` expression")
2245 InNode NBranch r c _ -> (r, c, "a `case` expression")
2246 -- TODO check if this is actually the best way to get error messages here
2248 surroundings = A.Region (A.Position contextRow contextCol) (A.Position row col)
2249 region = toRegion row col
2250 in
2251 Report.Report "MISSING EXPRESSION" region [] $
2252 Code.toSnippet source surroundings (Just region)
2254 D.reflow $
2255 "I am partway through parsing " ++ aThing ++ ", but I got stuck here:"
2257 D.stack
2258 [ D.fillSep $
2259 ["I","was","expecting","to","see","an","expression","like"
2260 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
2261 ,"Once","there","is","something","there,","I","can","probably"
2262 ,"give","a","more","specific","hint!"
2264 , D.toSimpleNote $
2265 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
2266 \ Or if I run into operators in unexpected spots. Point is, there are a\
2267 \ couple ways I can get confused and give sort of weird advice!"
2271 Char char row col ->
2272 toCharReport source char row col
2274 String string row col ->
2275 toStringReport source string row col
2277 Number number row col ->
2278 toNumberReport source number row col
2280 Space space row col ->
2281 toSpaceReport source space row col
2283 EndlessShader row col ->
2284 let
2285 region = toWiderRegion row col 6
2286 in
2287 Report.Report "ENDLESS SHADER" region [] $
2288 Code.toSnippet source region Nothing
2290 D.reflow "I cannot find the end of this shader:"
2292 D.reflow "Add a |] somewhere after this to end the shader."
2295 ShaderProblem problem row col ->
2296 let
2297 region = toRegion row col
2298 in
2299 Report.Report "SHADER PROBLEM" region [] $
2300 Code.toSnippet source region Nothing
2302 D.reflow $
2303 "I ran into a problem while parsing this GLSL block."
2305 D.stack
2306 [ D.reflow $
2307 "I use a 3rd party GLSL parser for now, and I did my best to extract their error message:"
2308 , D.indent 4 $ D.vcat $
2309 map D.fromChars (filter (/="") (lines problem))
2313 IndentOperatorRight op row col ->
2314 let
2315 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2316 region = toRegion row col
2317 in
2318 Report.Report "MISSING EXPRESSION" region [] $
2319 Code.toSnippet source surroundings (Just region)
2321 D.reflow $
2322 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
2324 D.stack
2326 D.fillSep $
2327 ["You","can","just","put","anything","for","now,","like"
2328 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
2329 ,"Once","there","is","something","there,","I","can","probably"
2330 ,"give","a","more","specific","hint!"
2333 D.toSimpleNote $
2334 "I may be getting confused by your indentation? The easiest way to make sure\
2335 \ this is not an indentation problem is to put the expression on the right of\
2336 \ the " ++ Name.toChars op ++ " operator on the same line."
2342-- CHAR
2345toCharReport :: Code.Source -> Char -> Row -> Col -> Report.Report
2346toCharReport source char row col =
2347 case char of
2348 CharEndless ->
2349 let
2350 region = toRegion row col
2351 in
2352 Report.Report "MISSING SINGLE QUOTE" region [] $
2353 Code.toSnippet source region Nothing
2355 D.reflow $
2356 "I thought I was parsing a character, but I got to the end of\
2357 \ the line without seeing the closing single quote:"
2359 D.reflow $
2360 "Add a closing single quote here!"
2363 CharEscape escape ->
2364 toEscapeReport source escape row col
2366 CharNotString width ->
2367 let
2368 region = toWiderRegion row col width
2369 in
2370 Report.Report "NEEDS DOUBLE QUOTES" region [] $
2371 Code.toSnippet source region Nothing
2373 "The following string uses single quotes:"
2375 D.stack
2376 [ "Please switch to double quotes instead:"
2377 , D.indent 4 $
2378 D.dullyellow "'this'" <> " => " <> D.green "\"this\""
2379 , D.toSimpleNote $
2380 "Elm uses double quotes for strings like \"hello\", whereas it uses single\
2381 \ quotes for individual characters like 'a' and 'ø'. This distinction helps with\
2382 \ code like (String.any (\\c -> c == 'X') \"90210\") where you are inspecting\
2383 \ individual characters."
2389-- STRING
2392toStringReport :: Code.Source -> String -> Row -> Col -> Report.Report
2393toStringReport source string row col =
2394 case string of
2395 StringEndless_Single ->
2396 let
2397 region = toRegion row col
2398 in
2399 Report.Report "ENDLESS STRING" region [] $
2400 Code.toSnippet source region Nothing
2402 D.reflow $
2403 "I got to the end of the line without seeing the closing double quote:"
2405 D.stack
2406 [ D.fillSep $
2407 ["Strings","look","like",D.green "\"this\"","with","double"
2408 ,"quotes","on","each","end.","Is","the","closing","double"
2409 ,"quote","missing","in","your","code?"
2411 , D.toSimpleNote $
2412 "For a string that spans multiple lines, you can use the multi-line string\
2413 \ syntax like this:"
2414 , D.vcat
2415 [ D.fillSep [D.green "markdown","=",D.dullyellow "\"\"\""]
2416 , mempty
2417 , D.dullyellow "# Multi-line Strings"
2418 , mempty
2419 , D.dullyellow "- start with triple double quotes"
2420 , D.dullyellow "- write whatever you want"
2421 , D.dullyellow "- no need to escape newlines or double quotes"
2422 , D.dullyellow "- end with triple double quotes"
2423 , mempty
2424 , D.dullyellow "\"\"\""
2429 StringEndless_Multi ->
2430 let
2431 region = toWiderRegion row col 3
2432 in
2433 Report.Report "ENDLESS STRING" region [] $
2434 Code.toSnippet source region Nothing
2436 D.reflow $
2437 "I cannot find the end of this multi-line string:"
2439 D.stack
2440 [ D.reflow "Add a \"\"\" somewhere after this to end the string."
2441 , D.toSimpleNote $
2442 "Here is a valid multi-line string for reference:"
2443 , D.vcat
2444 [ D.fillSep [D.green "markdown","=",D.dullyellow "\"\"\""]
2445 , mempty
2446 , D.dullyellow "# Multi-line Strings"
2447 , mempty
2448 , D.dullyellow "- start with triple double quotes"
2449 , D.dullyellow "- write whatever you want"
2450 , D.dullyellow "- no need to escape newlines or double quotes"
2451 , D.dullyellow "- end with triple double quotes"
2452 , mempty
2453 , D.dullyellow "\"\"\""
2458 StringEscape escape ->
2459 toEscapeReport source escape row col
2463-- ESCAPES
2466toEscapeReport :: Code.Source -> Escape -> Row -> Col -> Report.Report
2467toEscapeReport source escape row col =
2468 case escape of
2469 EscapeUnknown ->
2470 let
2471 region = toWiderRegion row col 2
2472 in
2473 Report.Report "UNKNOWN ESCAPE" region [] $
2474 Code.toSnippet source region Nothing
2476 D.reflow $
2477 "Backslashes always start escaped characters, but I do not recognize this one:"
2479 D.stack
2480 [ D.reflow $
2481 "Valid escape characters include:"
2482 , D.dullyellow $ D.indent 4 $ D.vcat $
2483 [ "\\n"
2484 , "\\r"
2485 , "\\t"
2486 , "\\\""
2487 , "\\\'"
2488 , "\\\\"
2489 , "\\u{003D}"
2491 , D.reflow $
2492 "Do you want one of those instead? Maybe you need \\\\ to escape a backslash?"
2493 , D.toSimpleNote $
2494 "The last style lets encode ANY character by its Unicode code\
2495 \ point. That means \\u{0009} and \\t are the same. You can use\
2496 \ that style for anything not covered by the other six escapes!"
2500 BadUnicodeFormat width ->
2501 let
2502 region = toWiderRegion row col width
2503 in
2504 Report.Report "BAD UNICODE ESCAPE" region [] $
2505 Code.toSnippet source region Nothing
2507 D.reflow $
2508 "I ran into an invalid Unicode escape:"
2510 D.stack
2511 [ D.reflow $
2512 "Here are some examples of valid Unicode escapes:"
2513 , D.dullyellow $ D.indent 4 $ D.vcat $
2514 [ "\\u{0041}"
2515 , "\\u{03BB}"
2516 , "\\u{6728}"
2517 , "\\u{1F60A}"
2519 , D.reflow $
2520 "Notice that the code point is always surrounded by curly braces.\
2521 \ Maybe you are missing the opening or closing curly brace?"
2524 BadUnicodeCode width ->
2525 let
2526 region = toWiderRegion row col width
2527 in
2528 Report.Report "BAD UNICODE ESCAPE" region [] $
2529 Code.toSnippet source region Nothing
2531 D.reflow $
2532 "This is not a valid code point:"
2534 D.reflow $
2535 "The valid code points are between 0 and 10FFFF inclusive."
2538 BadUnicodeLength width numDigits badCode ->
2539 let
2540 region = toWiderRegion row col width
2541 in
2542 Report.Report "BAD UNICODE ESCAPE" region [] $
2543 Code.toSnippet source region Nothing $
2544 if numDigits < 4 then
2546 D.reflow $
2547 "Every code point needs at least four digits:"
2549 let
2550 goodCode = replicate (4 - numDigits) '0' ++ map Char.toUpper (showHex badCode "")
2551 suggestion = "\\u{" <> D.fromChars goodCode <> "}"
2552 in
2553 D.fillSep ["Try",D.green suggestion,"instead?"]
2556 else
2558 D.reflow $
2559 "This code point has too many digits:"
2561 D.fillSep $
2562 ["Valid","code","points","are","between"
2563 ,D.green "\\u{0000}","and",D.green "\\u{10FFFF}" <> ","
2564 ,"so","try","trimming","any","leading","zeros","until"
2565 ,"you","have","between","four","and","six","digits."
2571-- NUMBERS
2574toNumberReport :: Code.Source -> Number -> Row -> Col -> Report.Report
2575toNumberReport source number row col =
2576 let
2577 region = toRegion row col
2578 in
2579 case number of
2580 NumberEnd ->
2581 Report.Report "WEIRD NUMBER" region [] $
2582 Code.toSnippet source region Nothing
2584 D.reflow $
2585 "I thought I was reading a number, but I ran into some weird stuff here:"
2587 D.stack
2588 [ D.reflow $
2589 "I recognize numbers in the following formats:"
2590 , D.indent 4 $ D.vcat [ "42", "3.14", "6.022e23", "0x002B" ]
2591 , D.reflow $
2592 "So is there a way to write it like one of those?"
2596 NumberDot int ->
2597 Report.Report "WEIRD NUMBER" region [] $
2598 Code.toSnippet source region Nothing
2600 D.reflow $
2601 "Numbers cannot end with a dot like this:"
2603 D.fillSep
2604 ["Switching","to",D.green (D.fromChars (show int))
2605 ,"or",D.green (D.fromChars (show int ++ ".0"))
2606 ,"will","work","though!"
2610 NumberHexDigit ->
2611 Report.Report "WEIRD HEXIDECIMAL" region [] $
2612 Code.toSnippet source region Nothing
2614 D.reflow $
2615 "I thought I was reading a hexidecimal number until I got here:"
2617 D.stack
2618 [ D.reflow $
2619 "Valid hexidecimal digits include 0123456789abcdefABCDEF, so I can\
2620 \ only recognize things like this:"
2621 , D.indent 4 $ D.vcat [ "0x2B", "0x002B", "0x00ffb3" ]
2625 NumberNoLeadingZero ->
2626 Report.Report "LEADING ZEROS" region [] $
2627 Code.toSnippet source region Nothing
2629 D.reflow $
2630 "I do not accept numbers with leading zeros:"
2632 D.stack
2633 [ D.reflow $
2634 "Just delete the leading zeros and it should work!"
2635 , D.toSimpleNote $
2636 "Some languages let you to specify octal numbers by adding a leading zero.\
2637 \ So in C, writing 0111 is the same as writing 73. Some people are used to\
2638 \ that, but others probably want it to equal 111. Either path is going to\
2639 \ surprise people from certain backgrounds, so Elm tries to avoid this whole\
2640 \ situation."
2646-- OPERATORS
2649toOperatorReport :: Code.Source -> Context -> BadOperator -> Row -> Col -> Report.Report
2650toOperatorReport source context operator row col =
2651 case operator of
2652 BadDot ->
2653 let
2654 region = toRegion row col
2655 in
2656 Report.Report "UNEXPECTED SYMBOL" region [] $
2657 Code.toSnippet source region Nothing
2659 "I was not expecting this dot:"
2661 D.reflow $
2662 "Dots are for record access and decimal points, so\
2663 \ they cannot float around on their own. Maybe\
2664 \ there is some extra whitespace?"
2667 BadPipe ->
2668 let
2669 region = toRegion row col
2670 in
2671 Report.Report "UNEXPECTED SYMBOL" region [] $
2672 Code.toSnippet source region Nothing
2674 D.reflow $
2675 "I was not expecting this vertical bar:"
2677 D.reflow $
2678 "Vertical bars should only appear in custom type declarations. Maybe you want || instead?"
2681 BadArrow ->
2682 let
2683 region = toWiderRegion row col 2
2684 in
2685 Report.Report "UNEXPECTED ARROW" region [] $
2686 Code.toSnippet source region Nothing $
2687 if isWithin NBranch context then
2689 D.reflow $
2690 "I was not expecting to see an arrow here:"
2692 D.stack
2694 D.reflow $
2695 "I think I am parsing a `case` expression right now, so it makes sense to\
2696 \ see arrows around here. This one is confusing me though!"
2698 D.toSimpleHint $
2699 "I may be getting confused by the indentation. Every pattern in a `case` must be\
2700 \ exactly aligned (with exactly the same amount of indentation) so maybe this arrow\
2701 \ appears after the next `case` pattern (correctly!) but the pattern itself is\
2702 \ indented too far?"
2706 else
2708 D.reflow $
2709 "I was not expecting an arrow here:"
2711 D.reflow $
2712 "Arrows should only appear in `case` expressions and anonymous functions. Maybe\
2713 \ you want > or >= instead?"
2716 BadEquals ->
2717 let
2718 region = toRegion row col
2719 in
2720 Report.Report "UNEXPECTED EQUALS" region [] $
2721 Code.toSnippet source region Nothing
2723 D.reflow $
2724 "I was not expecting to see this equals sign:"
2726 D.stack
2728 D.reflow "Maybe you want == instead? To check if two values are equal?"
2730 D.toSimpleNote $
2731 if isWithin NRecord context then
2732 "Records look like { x = 3, y = 4 } with the equals sign right\
2733 \ after the field name. So maybe you forgot a comma?"
2734 else
2735 case getDefName context of
2736 Nothing ->
2737 "I may be getting confused by your indentation. I need all definitions to be indented\
2738 \ exactly the same amount, so if this is meant to be a new definition, it may have too\
2739 \ many spaces in front of it."
2741 Just name ->
2742 "I may be getting confused by your indentation. I think I am still parsing the `"
2743 ++ Name.toChars name ++ "` definition. Is this supposed to be part of a definition\
2744 \ after that? If so, the problem may be a bit before the equals sign. I need all\
2745 \ definitions to be indented exactly the same amount, so the problem may be that\
2746 \ this new definition has too many spaces in front of it."
2750 BadHasType ->
2751 let
2752 region = toRegion row col
2753 in
2754 Report.Report "UNEXPECTED SYMBOL" region [] $
2755 Code.toSnippet source region Nothing $
2757 D.reflow $
2758 "I was not expecting to run into the \"has type\" symbol here:"
2760 case getDefName context of
2761 Nothing ->
2762 D.fillSep
2763 ["Maybe","you","want",D.green "::","instead?"
2764 ,"To","put","something","on","the","front","of","a","list?"
2767 Just name ->
2768 D.stack
2770 D.fillSep
2771 ["Maybe","you","want",D.green "::","instead?"
2772 ,"To","put","something","on","the","front","of","a","list?"
2774 , D.toSimpleNote $
2775 "The single colon is reserved for type annotations and record types, but I think\
2776 \ I am parsing the definition of `" ++ Name.toChars name ++ "` right now."
2778 D.toSimpleNote $
2779 "I may be getting confused by your indentation. Is this supposed to be part of\
2780 \ a type annotation AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
2781 \ the problem may be a bit before the \"has type\" symbol. I need all definitions to\
2782 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
2783 \ this new definition is indented a bit too much."
2789-- CASE
2792toLetReport :: Code.Source -> Context -> Let -> Row -> Col -> Report.Report
2793toLetReport source context let_ startRow startCol =
2794 case let_ of
2795 LetSpace space row col ->
2796 toSpaceReport source space row col
2798 LetIn row col ->
2799 let
2800 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2801 region = toRegion row col
2802 in
2803 Report.Report "LET PROBLEM" region [] $
2804 Code.toSnippet source surroundings (Just region)
2806 D.reflow $
2807 "I was partway through parsing a `let` expression, but I got stuck here:"
2809 D.stack
2810 [ D.fillSep $
2811 ["Based","on","the","indentation,","I","was","expecting","to","see","the",D.cyan "in"
2812 ,"keyword","next.","Is","there","a","typo?"
2814 , D.toSimpleNote $
2815 "This can also happen if you are trying to define another value within the `let` but\
2816 \ it is not indented enough. Make sure each definition has exactly the same amount of\
2817 \ spaces before it. They should line up exactly!"
2821 LetDefAlignment _ row col ->
2822 let
2823 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2824 region = toRegion row col
2825 in
2826 Report.Report "LET PROBLEM" region [] $
2827 Code.toSnippet source surroundings (Just region)
2829 D.reflow $
2830 "I was partway through parsing a `let` expression, but I got stuck here:"
2832 D.stack
2833 [ D.fillSep $
2834 ["Based","on","the","indentation,","I","was","expecting","to","see","the",D.cyan "in"
2835 ,"keyword","next.","Is","there","a","typo?"
2837 , D.toSimpleNote $
2838 "This can also happen if you are trying to define another value within the `let` but\
2839 \ it is not indented enough. Make sure each definition has exactly the same amount of\
2840 \ spaces before it. The should line up exactly!"
2844 LetDefName row col ->
2845 case Code.whatIsNext source row col of
2846 Code.Keyword keyword ->
2847 let
2848 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2849 region = toKeywordRegion row col keyword
2850 in
2851 Report.Report "RESERVED WORD" region [] $
2852 Code.toSnippet source surroundings (Just region)
2854 D.reflow $
2855 "I was partway through parsing a `let` expression, but I got stuck here:"
2857 D.reflow $
2858 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name, but\
2859 \ it is a reserved word! Try using a different name instead."
2862 _ ->
2863 toUnfinishLetReport source row col startRow startCol $
2864 D.reflow $
2865 "I was expecting the name of a definition next."
2867 LetDef name def row col ->
2868 toLetDefReport source name def row col
2870 LetDestruct destruct row col ->
2871 toLetDestructReport source destruct row col
2873 LetBody expr row col ->
2874 toExprReport source context expr row col
2876 LetIndentDef row col ->
2877 toUnfinishLetReport source row col startRow startCol $
2878 D.reflow $
2879 "I was expecting a value to be defined here."
2881 LetIndentIn row col ->
2882 toUnfinishLetReport source row col startRow startCol $
2883 D.fillSep $
2884 ["I","was","expecting","to","see","the",D.cyan "in","keyword","next."
2885 ,"Or","maybe","more","of","that","expression?"
2888 LetIndentBody row col ->
2889 toUnfinishLetReport source row col startRow startCol $
2890 D.reflow $
2891 "I was expecting an expression next. Tell me what should happen with the value you just defined!"
2894toUnfinishLetReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
2895toUnfinishLetReport source row col startRow startCol message =
2896 let
2897 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2898 region = toRegion row col
2899 in
2900 Report.Report "UNFINISHED LET" region [] $
2901 Code.toSnippet source surroundings (Just region)
2903 D.reflow $
2904 "I was partway through parsing a `let` expression, but I got stuck here:"
2906 D.stack
2907 [ message
2908 , D.toSimpleNote $
2909 "Here is an example with a valid `let` expression for reference:"
2910 , D.vcat $
2911 [ D.indent 0 $ D.fillSep [D.green "viewPerson","person","="]
2912 , D.indent 2 $ D.fillSep [D.cyan "let"]
2913 , D.indent 4 $ D.fillSep ["fullName","="]
2914 , D.indent 6 $ D.fillSep ["person.firstName","++",D.dullyellow "\" \"","++","person.lastName"]
2915 , D.indent 2 $ D.fillSep [D.cyan "in"]
2916 , D.indent 2 $ D.fillSep ["div","[]","[","text","fullName","]"]
2918 , D.reflow $
2919 "Here we defined a `viewPerson` function that turns a person into some HTML. We use\
2920 \ a `let` expression to define the `fullName` we want to show. Notice the indentation! The\
2921 \ `fullName` is indented more than the `let` keyword, and the actual value of `fullName` is\
2922 \ indented a bit more than that. That is important!"
2927toLetDefReport :: Code.Source -> Name.Name -> Def -> Row -> Col -> Report.Report
2928toLetDefReport source name def startRow startCol =
2929 case def of
2930 DefSpace space row col ->
2931 toSpaceReport source space row col
2933 DefType tipe row col ->
2934 toTypeReport source (TC_Annotation name) tipe row col
2936 DefNameRepeat row col ->
2937 let
2938 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2939 region = toRegion row col
2940 in
2941 Report.Report "EXPECTING DEFINITION" region [] $
2942 Code.toSnippet source surroundings (Just region)
2944 D.reflow $
2945 "I just saw the type annotation for `" ++ Name.toChars name
2946 ++ "` so I was expecting to see its definition here:"
2948 D.stack
2949 [ D.reflow $
2950 "Type annotations always appear directly above the relevant\
2951 \ definition, without anything else in between."
2952 , defNote
2956 DefNameMatch defName row col ->
2957 let
2958 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2959 region = toRegion row col
2960 in
2961 Report.Report "NAME MISMATCH" region [] $
2962 Code.toSnippet source surroundings (Just region)
2964 D.reflow $
2965 "I just saw a type annotation for `" ++ Name.toChars name ++ "`, but it is followed by a definition for `" ++ Name.toChars defName ++ "`:"
2967 D.stack
2968 [ D.reflow $
2969 "These names do not match! Is there a typo?"
2970 , D.indent 4 $ D.fillSep $
2971 [D.dullyellow (D.fromName defName),"->",D.green (D.fromName name)]
2975 DefArg pattern row col ->
2976 toPatternReport source PArg pattern row col
2978 DefEquals row col ->
2979 case Code.whatIsNext source row col of
2980 Code.Keyword keyword ->
2981 let
2982 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2983 region = toKeywordRegion row col keyword
2984 in
2985 Report.Report "RESERVED WORD" region [] $
2986 Code.toSnippet source surroundings (Just region)
2988 D.reflow $
2989 "It looks like you are trying to use `" ++ keyword ++ "` as an argument:"
2991 D.reflow $
2992 "This is a reserved word! Try using some other name?"
2995 Code.Operator op ->
2996 let
2997 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2998 region = toKeywordRegion row col op
2999 in
3000 Report.Report "UNEXPECTED SYMBOL" region [] $
3001 Code.toSnippet source surroundings (Just region)
3003 D.reflow $
3004 "I was not expecting to see this symbol here:"
3006 D.stack
3007 [ D.reflow $
3008 "I am not sure what is going wrong exactly, so here is a valid\
3009 \ definition (with an optional type annotation) for reference:"
3010 , D.vcat
3011 [ D.indent 4 $ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
3012 , D.indent 4 $ D.fillSep [D.green "add","x","y","="]
3013 , D.indent 6 $ D.fillSep ["x","+","y"]
3015 , D.reflow $
3016 "Try to use that format with your `" ++ Name.toChars name ++ "` definition!"
3020 _ ->
3021 let
3022 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3023 region = toRegion row col
3024 in
3025 Report.Report "PROBLEM IN DEFINITION" region [] $
3026 Code.toSnippet source surroundings (Just region)
3028 D.reflow $
3029 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
3031 D.stack
3032 [ D.reflow $
3033 "I am not sure what is going wrong exactly, so here is a valid\
3034 \ definition (with an optional type annotation) for reference:"
3035 , D.vcat
3036 [ D.indent 4 $ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
3037 , D.indent 4 $ D.fillSep [D.green "add","x","y","="]
3038 , D.indent 4 $ D.fillSep ["x","+","y"]
3040 , D.reflow $
3041 "Try to use that format!"
3045 DefBody expr row col ->
3046 toExprReport source (InDef name startRow startCol) expr row col
3048 DefIndentEquals row col ->
3049 let
3050 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3051 region = toRegion row col
3052 in
3053 Report.Report "UNFINISHED DEFINITION" region [] $
3054 Code.toSnippet source surroundings (Just region)
3056 D.reflow $
3057 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
3059 D.stack
3060 [ D.reflow $
3061 "I was expecting to see an argument or an equals sign next."
3062 , defNote
3066 DefIndentType row col ->
3067 let
3068 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3069 region = toRegion row col
3070 in
3071 Report.Report "UNFINISHED DEFINITION" region [] $
3072 Code.toSnippet source surroundings (Just region)
3074 D.reflow $
3075 "I got stuck while parsing the `" ++ Name.toChars name ++ "` type annotation:"
3077 D.stack
3078 [ D.reflow $
3079 "I just saw a colon, so I am expecting to see a type next."
3080 , defNote
3084 DefIndentBody row col ->
3085 let
3086 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3087 region = toRegion row col
3088 in
3089 Report.Report "UNFINISHED DEFINITION" region [] $
3090 Code.toSnippet source surroundings (Just region)
3092 D.reflow $
3093 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
3095 D.stack
3096 [ D.reflow $
3097 "I was expecting to see an expression next. What is it equal to?"
3098 , declDefNote
3102 DefAlignment indent row col ->
3103 let
3104 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3105 region = toRegion row col
3106 offset = indent - col
3107 in
3108 Report.Report "PROBLEM IN DEFINITION" region [] $
3109 Code.toSnippet source surroundings (Just region)
3111 D.reflow $
3112 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
3114 D.reflow $
3115 "I just saw a type annotation indented " ++ show indent ++ " spaces, so I was\
3116 \ expecting to see the corresponding definition next with the exact same amount\
3117 \ of indentation. It looks like this line needs "
3118 ++ show offset ++ " more " ++ (if offset == 1 then "space" else "spaces") ++ "?"
3123defNote :: D.Doc
3124defNote =
3125 D.stack
3126 [ D.reflow $
3127 "Here is a valid definition (with a type annotation) for reference:"
3128 , D.vcat
3129 [ D.indent 4 $ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
3130 , D.indent 4 $ D.fillSep [D.green "add","x","y","="]
3131 , D.indent 6 $ D.fillSep ["x","+","y"]
3133 , D.reflow $
3134 "The top line (called a \"type annotation\") is optional. You can leave it off\
3135 \ if you want. As you get more comfortable with Elm and as your project grows,\
3136 \ it becomes more and more valuable to add them though! They work great as\
3137 \ compiler-verified documentation, and they often improve error messages!"
3141toLetDestructReport :: Code.Source -> Destruct -> Row -> Col -> Report.Report
3142toLetDestructReport source destruct startRow startCol =
3143 case destruct of
3144 DestructSpace space row col ->
3145 toSpaceReport source space row col
3147 DestructPattern pattern row col ->
3148 toPatternReport source PLet pattern row col
3150 DestructEquals row col ->
3151 let
3152 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3153 region = toRegion row col
3154 in
3155 Report.Report "PROBLEM IN DEFINITION" region [] $
3156 Code.toSnippet source surroundings (Just region)
3158 D.reflow $
3159 "I got stuck trying to parse this definition:"
3161 case Code.whatIsNext source row col of
3162 Code.Operator ":" ->
3163 D.stack
3164 [ D.reflow $
3165 "I was expecting to see an equals sign next, followed by an expression\
3166 \ telling me what to compute."
3167 , D.toSimpleNote $
3168 "It looks like you may be trying to write a type annotation? It is not\
3169 \ possible to add type annotations on destructuring definitions like this.\
3170 \ You can assign a name to the overall structure, put a type annotation on\
3171 \ that, and then destructure separately though."
3174 _ ->
3175 D.reflow $
3176 "I was expecting to see an equals sign next, followed by an expression\
3177 \ telling me what to compute."
3180 DestructBody expr row col ->
3181 toExprReport source (InDestruct startRow startCol) expr row col
3183 DestructIndentEquals row col ->
3184 let
3185 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3186 region = toRegion row col
3187 in
3188 Report.Report "UNFINISHED DEFINITION" region [] $
3189 Code.toSnippet source surroundings (Just region)
3191 D.reflow $
3192 "I got stuck trying to parse this definition:"
3194 D.reflow $
3195 "I was expecting to see an equals sign next, followed by an expression\
3196 \ telling me what to compute."
3199 DestructIndentBody row col ->
3200 let
3201 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3202 region = toRegion row col
3203 in
3204 Report.Report "UNFINISHED DEFINITION" region [] $
3205 Code.toSnippet source surroundings (Just region)
3207 D.reflow $
3208 "I got stuck while parsing this definition:"
3210 D.reflow $
3211 "I was expecting to see an expression next. What is it equal to?"
3216-- CASE
3219toCaseReport :: Code.Source -> Context -> Case -> Row -> Col -> Report.Report
3220toCaseReport source context case_ startRow startCol =
3221 case case_ of
3222 CaseSpace space row col ->
3223 toSpaceReport source space row col
3225 CaseOf row col ->
3226 toUnfinishCaseReport source row col startRow startCol $
3227 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
3229 CasePattern pattern row col ->
3230 toPatternReport source PCase pattern row col
3232 CaseArrow row col ->
3233 case Code.whatIsNext source row col of
3234 Code.Keyword keyword ->
3235 let
3236 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3237 region = toKeywordRegion row col keyword
3238 in
3239 Report.Report "RESERVED WORD" region [] $
3240 Code.toSnippet source surroundings (Just region)
3242 D.reflow $
3243 "I am partway through parsing a `case` expression, but I got stuck here:"
3245 D.reflow $
3246 "It looks like you are trying to use `" ++ keyword ++ "` in one of your\
3247 \ patterns, but it is a reserved word. Try using a different name?"
3250 Code.Operator ":" ->
3251 let
3252 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3253 region = toRegion row col
3254 in
3255 Report.Report "UNEXPECTED OPERATOR" region [] $
3256 Code.toSnippet source surroundings (Just region)
3258 D.reflow $
3259 "I am partway through parsing a `case` expression, but I got stuck here:"
3261 D.fillSep $
3262 ["I","am","seeing",D.dullyellow ":","but","maybe","you","want",D.green "::","instead?"
3263 ,"For","pattern","matching","on","lists?"
3267 Code.Operator "=" ->
3268 let
3269 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3270 region = toRegion row col
3271 in
3272 Report.Report "UNEXPECTED OPERATOR" region [] $
3273 Code.toSnippet source surroundings (Just region)
3275 D.reflow $
3276 "I am partway through parsing a `case` expression, but I got stuck here:"
3278 D.fillSep $
3279 ["I","am","seeing",D.dullyellow "=","but","maybe","you","want",D.green "->","instead?"
3283 _ ->
3284 let
3285 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3286 region = toRegion row col
3287 in
3288 Report.Report "MISSING ARROW" region [] $
3289 Code.toSnippet source surroundings (Just region)
3291 D.reflow $
3292 "I am partway through parsing a `case` expression, but I got stuck here:"
3294 addNoteForCaseIndentError $
3295 D.reflow $
3296 "I was expecting to see an arrow next."
3299 CaseExpr expr row col ->
3300 toExprReport source (InNode NCase startRow startCol context) expr row col
3302 CaseBranch expr row col ->
3303 toExprReport source (InNode NBranch startRow startCol context) expr row col
3305 CaseIndentOf row col ->
3306 toUnfinishCaseReport source row col startRow startCol $
3307 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
3309 CaseIndentExpr row col ->
3310 toUnfinishCaseReport source row col startRow startCol $
3311 D.reflow "I was expecting to see a expression next."
3313 CaseIndentPattern row col ->
3314 toUnfinishCaseReport source row col startRow startCol $
3315 D.reflow "I was expecting to see a pattern next."
3317 CaseIndentArrow row col ->
3318 toUnfinishCaseReport source row col startRow startCol $
3319 D.fillSep
3320 ["I","just","saw","a","pattern,","so","I","was","expecting"
3321 ,"to","see","a",D.dullyellow "->","next."
3324 CaseIndentBranch row col ->
3325 toUnfinishCaseReport source row col startRow startCol $
3326 D.reflow $
3327 "I was expecting to see an expression next. What should I do when\
3328 \ I run into this particular pattern?"
3330 CasePatternAlignment indent row col ->
3331 toUnfinishCaseReport source row col startRow startCol $
3332 D.reflow $
3333 "I suspect this is a pattern that is not indented far enough? (" ++ show indent ++ " spaces)"
3336toUnfinishCaseReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
3337toUnfinishCaseReport source row col startRow startCol message =
3338 let
3339 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3340 region = toRegion row col
3341 in
3342 Report.Report "UNFINISHED CASE" region [] $
3343 Code.toSnippet source surroundings (Just region)
3345 D.reflow $
3346 "I was partway through parsing a `case` expression, but I got stuck here:"
3348 D.stack
3349 [ message
3350 , D.toSimpleNote $
3351 "Here is an example of a valid `case` expression for reference."
3352 , D.vcat $
3353 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
3354 , D.indent 6 $ D.fillSep [D.blue "Just","width","->"]
3355 , D.indent 8 $ D.fillSep ["width","+",D.dullyellow "200"]
3356 , ""
3357 , D.indent 6 $ D.fillSep [D.blue "Nothing","->"]
3358 , D.indent 8 $ D.fillSep [D.dullyellow "400"]
3360 , D.reflow $
3361 "Notice the indentation. Each pattern is aligned, and each branch is indented\
3362 \ a bit more than the corresponding pattern. That is important!"
3367addNoteForCaseIndentError :: D.Doc -> D.Doc
3368addNoteForCaseIndentError message =
3369 D.stack $
3370 message
3372 [ D.toSimpleNote $
3373 "Sometimes I get confused by indentation, so try to make your `case` look\
3374 \ something like this:"
3375 , D.vcat $
3376 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
3377 , D.indent 6 $ D.fillSep [D.blue "Just","width","->"]
3378 , D.indent 8 $ D.fillSep ["width","+",D.dullyellow "200"]
3379 , ""
3380 , D.indent 6 $ D.fillSep [D.blue "Nothing","->"]
3381 , D.indent 8 $ D.fillSep [D.dullyellow "400"]
3383 , D.reflow $
3384 "Notice the indentation! Each pattern is aligned, and each branch is indented\
3385 \ a bit more than the corresponding pattern. That is important!"
3390-- IF
3393toIfReport :: Code.Source -> Context -> If -> Row -> Col -> Report.Report
3394toIfReport source context if_ startRow startCol =
3395 case if_ of
3396 IfSpace space row col ->
3397 toSpaceReport source space row col
3399 IfThen row col ->
3400 let
3401 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3402 region = toRegion row col
3403 in
3404 Report.Report "UNFINISHED IF" region [] $
3405 Code.toSnippet source surroundings (Just region)
3407 D.reflow $
3408 "I was expecting to see more of this `if` expression, but I got stuck here:"
3410 D.fillSep $
3411 ["I","was","expecting","to","see","the",D.cyan "then","keyword","next."
3415 IfElse row col ->
3416 let
3417 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3418 region = toRegion row col
3419 in
3420 Report.Report "UNFINISHED IF" region [] $
3421 Code.toSnippet source surroundings (Just region)
3423 D.reflow $
3424 "I was expecting to see more of this `if` expression, but I got stuck here:"
3426 D.fillSep $
3427 ["I","was","expecting","to","see","the",D.cyan "else","keyword","next."
3431 IfElseBranchStart row col ->
3432 let
3433 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3434 region = toRegion row col
3435 in
3436 Report.Report "UNFINISHED IF" region [] $
3437 Code.toSnippet source surroundings (Just region)
3439 D.reflow $
3440 "I just saw the start of an `else` branch, but then I got stuck here:"
3442 D.reflow $
3443 "I was expecting to see an expression next. Maybe it is not filled in yet?"
3446 IfCondition expr row col ->
3447 toExprReport source (InNode NCond startRow startCol context) expr row col
3449 IfThenBranch expr row col ->
3450 toExprReport source (InNode NThen startRow startCol context) expr row col
3452 IfElseBranch expr row col ->
3453 toExprReport source (InNode NElse startRow startCol context) expr row col
3455 IfIndentCondition row col ->
3456 let
3457 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3458 region = toRegion row col
3459 in
3460 Report.Report "UNFINISHED IF" region [] $
3461 Code.toSnippet source surroundings (Just region)
3463 D.reflow $
3464 "I was expecting to see more of this `if` expression, but I got stuck here:"
3466 D.stack
3467 [ D.fillSep $
3468 ["I","was","expecting","to","see","an","expression","like",D.dullyellow "x < 0"
3469 ,"that","evaluates","to","True","or","False."
3471 , D.toSimpleNote $
3472 "I can be confused by indentation. Maybe something is not indented enough?"
3476 IfIndentThen row col ->
3477 let
3478 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3479 region = toRegion row col
3480 in
3481 Report.Report "UNFINISHED IF" region [] $
3482 Code.toSnippet source surroundings (Just region)
3484 D.reflow $
3485 "I was expecting to see more of this `if` expression, but I got stuck here:"
3487 D.stack
3488 [ D.fillSep $
3489 ["I","was","expecting","to","see","the",D.cyan "then","keyword","next."
3491 , D.toSimpleNote $
3492 "I can be confused by indentation. Maybe something is not indented enough?"
3496 IfIndentThenBranch row col ->
3497 let
3498 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3499 region = toRegion row col
3500 in
3501 Report.Report "UNFINISHED IF" region [] $
3502 Code.toSnippet source surroundings (Just region)
3504 D.reflow $
3505 "I got stuck after the start of this `then` branch:"
3507 D.stack
3508 [ D.reflow $
3509 "I was expecting to see an expression next. Maybe it is not filled in yet?"
3510 , D.toSimpleNote $
3511 "I can be confused by indentation, so if the `then` branch is already\
3512 \ present, it may not be indented enough for me to recognize it."
3516 IfIndentElseBranch row col ->
3517 let
3518 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3519 region = toRegion row col
3520 in
3521 Report.Report "UNFINISHED IF" region [] $
3522 Code.toSnippet source surroundings (Just region)
3524 D.reflow $
3525 "I got stuck after the start of this `else` branch:"
3527 D.stack
3528 [ D.reflow $
3529 "I was expecting to see an expression next. Maybe it is not filled in yet?"
3530 , D.toSimpleNote $
3531 "I can be confused by indentation, so if the `else` branch is already\
3532 \ present, it may not be indented enough for me to recognize it."
3536 IfIndentElse row col ->
3537 let
3538 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3539 region = toRegion row col
3540 in
3541 Report.Report "UNFINISHED IF" region [] $
3542 Code.toSnippet source surroundings (Just region)
3544 D.reflow $
3545 "I was expecting to see an `else` branch after this:"
3547 D.stack
3548 [ D.reflow $
3549 "I know what to do when the condition is `True`, but not when it is `False`."
3550 , D.fillSep
3551 ["Add","an",D.cyan "else","branch","to","handle","that","scenario!"]
3557-- RECORD
3560toRecordReport :: Code.Source -> Context -> Record -> Row -> Col -> Report.Report
3561toRecordReport source context record startRow startCol =
3562 case record of
3563 RecordOpen row col ->
3564 case Code.whatIsNext source row col of
3565 Code.Keyword keyword ->
3566 let
3567 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3568 region = toKeywordRegion row col keyword
3569 in
3570 Report.Report "RESERVED WORD" region [] $
3571 Code.toSnippet source surroundings (Just region)
3573 D.reflow $
3574 "I just started parsing a record, but I got stuck on this field name:"
3576 D.reflow $
3577 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
3578 \ that is a reserved word. Try using a different name!"
3581 _ ->
3582 let
3583 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3584 region = toRegion row col
3585 in
3586 Report.Report "UNFINISHED RECORD" region [] $
3587 Code.toSnippet source surroundings (Just region)
3589 D.reflow $
3590 "I just started parsing a record, but I got stuck here:"
3592 D.fillSep
3593 ["Records","look","like",D.dullyellow "{ x = 3, y = 4 },"
3594 ,"so","I","was","expecting","to","see","a","field","name","next."
3598 RecordEnd row col ->
3599 let
3600 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3601 region = toRegion row col
3602 in
3603 Report.Report "UNFINISHED RECORD" region [] $
3604 Code.toSnippet source surroundings (Just region)
3606 D.reflow $
3607 "I am partway through parsing a record, but I got stuck here:"
3609 D.stack
3610 [ D.fillSep
3611 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
3612 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
3614 , D.toSimpleNote $
3615 "When I get stuck like this, it usually means that there is a missing parenthesis\
3616 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
3620 RecordField row col ->
3621 case Code.whatIsNext source row col of
3622 Code.Keyword keyword ->
3623 let
3624 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3625 region = toKeywordRegion row col keyword
3626 in
3627 Report.Report "RESERVED WORD" region [] $
3628 Code.toSnippet source surroundings (Just region)
3630 D.reflow $
3631 "I am partway through parsing a record, but I got stuck on this field name:"
3633 D.reflow $
3634 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
3635 \ that is a reserved word. Try using a different name!"
3638 _ ->
3639 let
3640 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3641 region = toRegion row col
3642 in
3643 Report.Report "UNFINISHED RECORD" region [] $
3644 Code.toSnippet source surroundings (Just region)
3646 D.reflow $
3647 "I am partway through parsing a record, but I got stuck after that last comma:"
3649 addNoteForRecordError $
3650 D.reflow $
3651 "Trailing commas are not allowed in records, so I was expecting to see another\
3652 \ record field defined next. If you are done defining the record, the fix may\
3653 \ be to delete that last comma?"
3656 RecordEquals row col ->
3657 let
3658 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3659 region = toRegion row col
3660 in
3661 Report.Report "UNFINISHED RECORD" region [] $
3662 Code.toSnippet source surroundings (Just region)
3664 D.reflow $
3665 "I am partway through parsing a record, but I got stuck here:"
3667 addNoteForRecordError $
3668 D.fillSep $
3669 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
3670 ,"an","equals","sign","next.","So","try","putting","an",D.green "=","sign","here?"
3674 RecordExpr expr row col ->
3675 toExprReport source (InNode NRecord startRow startCol context) expr row col
3677 RecordSpace space row col ->
3678 toSpaceReport source space row col
3680 RecordIndentOpen row col ->
3681 let
3682 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3683 region = toRegion row col
3684 in
3685 Report.Report "UNFINISHED RECORD" region [] $
3686 Code.toSnippet source surroundings (Just region)
3688 D.reflow $
3689 "I just saw the opening curly brace of a record, but then I got stuck here:"
3691 addNoteForRecordIndentError $
3692 D.fillSep $
3693 ["I","am","expecting","a","record","like",D.dullyellow "{ x = 3, y = 4 }","here."
3694 ,"Try","defining","some","fields","of","your","own?"
3698 RecordIndentEnd row col ->
3699 let
3700 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3701 region = toRegion row col
3702 in
3703 Report.Report "UNFINISHED RECORD" region [] $
3704 Code.toSnippet source surroundings (Just region)
3706 D.reflow $
3707 "I was expecting to see a closing curly brace next:"
3709 addNoteForRecordIndentError $
3710 D.fillSep $
3711 ["Try","putting","an",D.green "}","and","see","if","that","helps?"
3715 RecordIndentField row col ->
3716 let
3717 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3718 region = toRegion row col
3719 in
3720 Report.Report "UNFINISHED RECORD" region [] $
3721 Code.toSnippet source surroundings (Just region)
3723 D.reflow $
3724 "I am partway through parsing a record, but I got stuck after that last comma:"
3726 addNoteForRecordError $
3727 D.reflow $
3728 "Trailing commas are not allowed in records, so the fix may be to\
3729 \ delete that last comma? Or maybe you were in the middle of defining\
3730 \ an additional field?"
3733 RecordIndentEquals row col ->
3734 let
3735 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3736 region = toRegion row col
3737 in
3738 Report.Report "UNFINISHED RECORD" region [] $
3739 Code.toSnippet source surroundings (Just region)
3741 D.reflow $
3742 "I am partway through parsing a record. I just saw a record\
3743 \ field, so I was expecting to see an equals sign next:"
3745 addNoteForRecordIndentError $
3746 D.fillSep $
3747 ["Try","putting","an",D.green "=","followed","by","an","expression?"
3751 RecordIndentExpr row col ->
3752 let
3753 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3754 region = toRegion row col
3755 in
3756 Report.Report "UNFINISHED RECORD" region [] $
3757 Code.toSnippet source surroundings (Just region)
3759 D.reflow $
3760 "I am partway through parsing a record, and I was expecting to run into an expression next:"
3762 addNoteForRecordIndentError $
3763 D.fillSep $
3764 ["Try","putting","something","like"
3765 ,D.dullyellow "42","or",D.dullyellow"\"hello\"","for","now?"
3770addNoteForRecordError :: D.Doc -> D.Doc
3771addNoteForRecordError normalRecommendation =
3772 D.stack $
3773 normalRecommendation
3775 [ D.toSimpleNote
3776 "If you are trying to define a record across multiple lines, I recommend using this format:"
3777 , D.indent 4 $ D.vcat $
3778 [ "{ name = \"Alice\""
3779 , ", age = 42"
3780 , ", height = 1.75"
3781 , "}"
3783 , D.reflow $
3784 "Notice that each line starts with some indentation. Usually two or four spaces. I\
3785 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
3786 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3790addNoteForRecordIndentError :: D.Doc -> D.Doc
3791addNoteForRecordIndentError normalRecommendation =
3792 D.stack $
3793 normalRecommendation
3795 [ D.toSimpleNote
3796 "I may be confused by indentation. For example, if you are trying to define\
3797 \ a record across multiple lines, I recommend using this format:"
3798 , D.indent 4 $ D.vcat $
3799 [ "{ name = \"Alice\""
3800 , ", age = 42"
3801 , ", height = 1.75"
3802 , "}"
3804 , D.reflow $
3805 "Notice that each line starts with some indentation. Usually two or four spaces. I\
3806 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
3807 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3812-- TUPLE
3815toTupleReport :: Code.Source -> Context -> Tuple -> Row -> Col -> Report.Report
3816toTupleReport source context tuple startRow startCol =
3817 case tuple of
3818 TupleExpr expr row col ->
3819 toExprReport source (InNode NParens startRow startCol context) expr row col
3821 TupleSpace space row col ->
3822 toSpaceReport source space row col
3824 TupleEnd row col ->
3825 let
3826 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3827 region = toRegion row col
3828 in
3829 Report.Report "UNFINISHED PARENTHESES" region [] $
3830 Code.toSnippet source surroundings (Just region)
3832 D.reflow $
3833 "I was expecting to see a closing parentheses next, but I got stuck here:"
3835 D.stack
3836 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
3837 , D.toSimpleNote $
3838 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
3839 \ unexpectedly. So there may be some earlier syntax trouble (like extra parenthesis\
3840 \ or missing brackets) that is confusing me."
3844 TupleOperatorClose row col ->
3845 let
3846 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3847 region = toRegion row col
3848 in
3849 Report.Report "UNFINISHED OPERATOR FUNCTION" region [] $
3850 Code.toSnippet source surroundings (Just region)
3852 D.reflow "I was expecting a closing parenthesis here:"
3854 D.stack
3855 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
3856 , D.toSimpleNote $
3857 "I think I am parsing an operator function right now, so I am expecting to see\
3858 \ something like (+) or (&&) where an operator is surrounded by parentheses with\
3859 \ no extra spaces."
3863 TupleOperatorReserved operator row col ->
3864 let
3865 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3866 region = toRegion row col
3867 in
3868 Report.Report "UNEXPECTED SYMBOL" region [] $
3869 Code.toSnippet source surroundings (Just region)
3871 D.reflow $
3872 "I ran into an unexpected symbol here:"
3874 D.fillSep $
3875 case operator of
3876 BadDot -> ["Maybe","you","wanted","a","record","accessor","like",D.dullyellow ".x","or",D.dullyellow ".name","instead?"]
3877 BadPipe -> ["Try",D.dullyellow "(||)","instead?","To","turn","boolean","OR","into","a","function?"]
3878 BadArrow -> ["Maybe","you","wanted",D.dullyellow "(>)","or",D.dullyellow "(>=)","instead?"]
3879 BadEquals -> ["Try",D.dullyellow "(==)","instead?","To","make","a","function","that","checks","equality?"]
3880 BadHasType -> ["Try",D.dullyellow "(::)","instead?","To","add","values","to","the","front","of","lists?"]
3883 TupleIndentExpr1 row col ->
3884 let
3885 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3886 region = toRegion row col
3887 in
3888 Report.Report "UNFINISHED PARENTHESES" region [] $
3889 Code.toSnippet source surroundings (Just region)
3891 D.reflow $
3892 "I just saw an open parenthesis, so I was expecting to see an expression next."
3894 D.stack
3895 [ D.fillSep $
3896 ["Something","like",D.dullyellow "(4 + 5)","or"
3897 ,D.dullyellow "(String.reverse \"desserts\")" <> "."
3898 ,"Anything","where","you","are","putting","parentheses","around","normal","expressions."
3900 , D.toSimpleNote $
3901 "I can get confused by indentation in cases like this, so\
3902 \ maybe you have an expression but it is not indented enough?"
3906 TupleIndentExprN row col ->
3907 let
3908 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3909 region = toRegion row col
3910 in
3911 Report.Report "UNFINISHED TUPLE" region [] $
3912 Code.toSnippet source surroundings (Just region)
3914 D.reflow $
3915 "I think I am in the middle of parsing a tuple. I just saw a comma, so I was expecting to see an expression next."
3917 D.stack
3918 [ D.fillSep $
3919 ["A","tuple","looks","like",D.dullyellow "(3,4)","or"
3920 ,D.dullyellow "(\"Tom\",42)" <> ","
3921 ,"so","I","think","there","is","an","expression","missing","here?"
3923 , D.toSimpleNote $
3924 "I can get confused by indentation in cases like this, so\
3925 \ maybe you have an expression but it is not indented enough?"
3929 TupleIndentEnd row col ->
3930 let
3931 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3932 region = toRegion row col
3933 in
3934 Report.Report "UNFINISHED PARENTHESES" region [] $
3935 Code.toSnippet source surroundings (Just region)
3937 D.reflow $
3938 "I was expecting to see a closing parenthesis next:"
3940 D.stack
3941 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
3942 , D.toSimpleNote $
3943 "I can get confused by indentation in cases like this, so\
3944 \ maybe you have a closing parenthesis but it is not indented enough?"
3949toListReport :: Code.Source -> Context -> List -> Row -> Col -> Report.Report
3950toListReport source context list startRow startCol =
3951 case list of
3952 ListSpace space row col ->
3953 toSpaceReport source space row col
3955 ListOpen row col ->
3956 let
3957 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3958 region = toRegion row col
3959 in
3960 Report.Report "UNFINISHED LIST" region [] $
3961 Code.toSnippet source surroundings (Just region)
3963 D.reflow $
3964 "I am partway through parsing a list, but I got stuck here:"
3966 D.stack
3967 [ D.fillSep
3968 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
3969 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
3971 , D.toSimpleNote $
3972 "When I get stuck like this, it usually means that there is a missing parenthesis\
3973 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
3977 ListExpr expr row col ->
3978 case expr of
3979 Start r c ->
3980 let
3981 surroundings = A.Region (A.Position startRow startCol) (A.Position r c)
3982 region = toRegion r c
3983 in
3984 Report.Report "UNFINISHED LIST" region [] $
3985 Code.toSnippet source surroundings (Just region)
3987 D.reflow $
3988 "I was expecting to see another list entry after that last comma:"
3990 D.stack
3991 [ D.reflow $
3992 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
3993 , D.toSimpleNote
3994 "I recommend using the following format for lists that span multiple lines:"
3995 , D.indent 4 $ D.vcat $
3996 [ "[ \"Alice\""
3997 , ", \"Bob\""
3998 , ", \"Chuck\""
3999 , "]"
4001 , D.reflow $
4002 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
4003 \ This style can be jarring for people coming from C-like syntax, but folks generally\
4004 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
4008 _ ->
4009 toExprReport source (InNode NList startRow startCol context) expr row col
4011 ListEnd row col ->
4012 let
4013 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4014 region = toRegion row col
4015 in
4016 Report.Report "UNFINISHED LIST" region [] $
4017 Code.toSnippet source surroundings (Just region)
4019 D.reflow $
4020 "I am partway through parsing a list, but I got stuck here:"
4022 D.stack
4023 [ D.fillSep
4024 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
4025 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
4027 , D.toSimpleNote $
4028 "When I get stuck like this, it usually means that there is a missing parenthesis\
4029 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
4033 ListIndentOpen row col ->
4034 let
4035 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4036 region = toRegion row col
4037 in
4038 Report.Report "UNFINISHED LIST" region [] $
4039 Code.toSnippet source surroundings (Just region)
4041 D.reflow $
4042 "I cannot find the end of this list:"
4044 D.stack
4045 [ D.fillSep $
4046 ["You","could","change","it","to","something","like"
4047 ,D.dullyellow "[3,4,5]"
4048 ,"or","even","just"
4049 ,D.dullyellow "[]" <> "."
4050 ,"Anything","where","there","is","an","open","and","close","square","brace,"
4051 ,"and","where","the","elements","of","the","list","are","separated","by","commas."
4053 , D.toSimpleNote
4054 "I may be confused by indentation. For example, if you are trying to define\
4055 \ a list across multiple lines, I recommend using this format:"
4056 , D.indent 4 $ D.vcat $
4057 [ "[ \"Alice\""
4058 , ", \"Bob\""
4059 , ", \"Chuck\""
4060 , "]"
4062 , D.reflow $
4063 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
4064 \ This style can be jarring for people coming from C-like syntax, but folks generally\
4065 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
4069 ListIndentEnd row col ->
4070 let
4071 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4072 region = toRegion row col
4073 in
4074 Report.Report "UNFINISHED LIST" region [] $
4075 Code.toSnippet source surroundings (Just region)
4077 D.reflow $
4078 "I cannot find the end of this list:"
4080 D.stack
4081 [ D.fillSep $
4082 ["You","can","just","add","a","closing",D.dullyellow "]"
4083 ,"right","here,","and","I","will","be","all","set!"
4085 , D.toSimpleNote
4086 "I may be confused by indentation. For example, if you are trying to define\
4087 \ a list across multiple lines, I recommend using this format:"
4088 , D.indent 4 $ D.vcat $
4089 [ "[ \"Alice\""
4090 , ", \"Bob\""
4091 , ", \"Chuck\""
4092 , "]"
4094 , D.reflow $
4095 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
4096 \ This style can be jarring for people coming from C-like syntax, but folks generally\
4097 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
4101 ListIndentExpr row col ->
4102 let
4103 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4104 region = toRegion row col
4105 in
4106 Report.Report "UNFINISHED LIST" region [] $
4107 Code.toSnippet source surroundings (Just region)
4109 D.reflow $
4110 "I was expecting to see another list entry after this comma:"
4112 D.stack
4113 [ D.reflow $
4114 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
4115 , D.toSimpleNote
4116 "I recommend using the following format for lists that span multiple lines:"
4117 , D.indent 4 $ D.vcat $
4118 [ "[ \"Alice\""
4119 , ", \"Bob\""
4120 , ", \"Chuck\""
4121 , "]"
4123 , D.reflow $
4124 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
4125 \ This style can be jarring for people coming from C-like syntax, but folks generally\
4126 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
4131toFuncReport :: Code.Source -> Context -> Func -> Row -> Col -> Report.Report
4132toFuncReport source context func startRow startCol =
4133 case func of
4134 FuncSpace space row col ->
4135 toSpaceReport source space row col
4137 FuncArg pattern row col ->
4138 toPatternReport source PArg pattern row col
4140 FuncBody expr row col ->
4141 toExprReport source (InNode NFunc startRow startCol context) expr row col
4143 FuncArrow row col ->
4144 case Code.whatIsNext source row col of
4145 Code.Keyword keyword ->
4146 let
4147 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4148 region = toKeywordRegion row col keyword
4149 in
4150 Report.Report "RESERVED WORD" region [] $
4151 Code.toSnippet source surroundings (Just region)
4153 D.reflow $
4154 "I was parsing an anonymous function, but I got stuck here:"
4156 D.reflow $
4157 "It looks like you are trying to use `" ++ keyword ++ "` as an argument, but\
4158 \ it is a reserved word in this language. Try using a different argument name!"
4161 _ ->
4162 let
4163 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4164 region = toRegion row col
4165 in
4166 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
4167 Code.toSnippet source surroundings (Just region)
4169 D.reflow $
4170 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
4172 D.fillSep $
4173 ["The","syntax","for","anonymous","functions","is"
4174 ,D.dullyellow "(\\x -> x + 1)"
4175 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
4179 FuncIndentArg row col ->
4180 let
4181 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4182 region = toRegion row col
4183 in
4184 Report.Report "MISSING ARGUMENT" region [] $
4185 Code.toSnippet source surroundings (Just region)
4187 D.reflow $
4188 "I just saw the beginning of an anonymous function, so I was expecting to see an argument next:"
4190 D.stack
4191 [ D.fillSep
4192 ["Something","like",D.dullyellow"x","or",D.dullyellow "name" <> "."
4193 ,"Anything","that","starts","with","a","lower","case","letter!"
4195 , D.toSimpleNote $
4196 "The syntax for anonymous functions is (\\x -> x + 1) where the backslash\
4197 \ is meant to look a bit like a lambda if you squint. This visual pun seemed\
4198 \ like a better idea at the time!"
4202 FuncIndentArrow row col ->
4203 let
4204 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4205 region = toRegion row col
4206 in
4207 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
4208 Code.toSnippet source surroundings (Just region)
4210 D.reflow $
4211 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
4213 D.stack
4214 [ D.fillSep $
4215 ["The","syntax","for","anonymous","functions","is"
4216 ,D.dullyellow "(\\x -> x + 1)"
4217 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
4219 , D.toSimpleNote $
4220 "It is possible that I am confused about indetation! I generally recommend\
4221 \ switching to named functions if the definition cannot fit inline nicely, so\
4222 \ either (1) try to fit the whole anonymous function on one line or (2) break\
4223 \ the whole thing out into a named function. Things tend to be clearer that way!"
4227 FuncIndentBody row col ->
4228 let
4229 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4230 region = toRegion row col
4231 in
4232 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
4233 Code.toSnippet source surroundings (Just region)
4235 D.reflow $
4236 "I was expecting to see the body of your anonymous function next:"
4238 D.stack
4239 [ D.fillSep $
4240 ["The","syntax","for","anonymous","functions","is"
4241 ,D.dullyellow "(\\x -> x + 1)"
4242 ,"so","I","am","missing","all","the","stuff","after","the","arrow!"
4244 , D.toSimpleNote $
4245 "It is possible that I am confused about indetation! I generally recommend\
4246 \ switching to named functions if the definition cannot fit inline nicely, so\
4247 \ either (1) try to fit the whole anonymous function on one line or (2) break\
4248 \ the whole thing out into a named function. Things tend to be clearer that way!"
4254-- PATTERN
4257data PContext
4258 = PCase
4259 | PArg
4260 | PLet
4263toPatternReport :: Code.Source -> PContext -> Pattern -> Row -> Col -> Report.Report
4264toPatternReport source context pattern startRow startCol =
4265 case pattern of
4266 PRecord record row col ->
4267 toPRecordReport source record row col
4269 PTuple tuple row col ->
4270 toPTupleReport source context tuple row col
4272 PList list row col ->
4273 toPListReport source context list row col
4275 PStart row col ->
4276 case Code.whatIsNext source row col of
4277 Code.Keyword keyword ->
4278 let
4279 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4280 region = toKeywordRegion row col keyword
4281 inThisThing =
4282 case context of
4283 PArg -> "as an argument"
4284 PCase -> "in this pattern"
4285 PLet -> "in this pattern"
4286 in
4287 Report.Report "RESERVED WORD" region [] $
4288 Code.toSnippet source surroundings (Just region)
4290 D.reflow $
4291 "It looks like you are trying to use `" ++ keyword ++ "` " ++ inThisThing ++ ":"
4293 D.reflow $
4294 "This is a reserved word! Try using some other name?"
4297 Code.Operator "-" ->
4298 let
4299 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4300 region = toRegion row col
4301 in
4302 Report.Report "UNEXPECTED SYMBOL" region [] $
4303 Code.toSnippet source surroundings (Just region)
4305 D.reflow $
4306 "I ran into a minus sign unexpectedly in this pattern:"
4308 D.reflow $
4309 "It is not possible to pattern match on negative numbers at this\
4310 \ time. Try using an `if` expression for that sort of thing for now."
4313 _ ->
4314 let
4315 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4316 region = toRegion row col
4317 in
4318 Report.Report "PROBLEM IN PATTERN" region [] $
4319 Code.toSnippet source surroundings (Just region)
4321 D.reflow $
4322 "I wanted to parse a pattern next, but I got stuck here:"
4324 D.fillSep $
4325 ["I","am","not","sure","why","I","am","getting","stuck","exactly."
4326 ,"I","just","know","that","I","want","a","pattern","next."
4327 ,"Something","as","simple","as"
4328 ,D.dullyellow "maybeHeight","or",D.dullyellow "result"
4329 ,"would","work!"
4333 PChar char row col ->
4334 toCharReport source char row col
4336 PString string row col ->
4337 toStringReport source string row col
4339 PNumber number row col ->
4340 toNumberReport source number row col
4342 PFloat width row col ->
4343 let
4344 region = toWiderRegion row col width
4345 in
4346 Report.Report "UNEXPECTED PATTERN" region [] $
4347 Code.toSnippet source region Nothing
4349 D.reflow $
4350 "I cannot pattern match with floating point numbers:"
4352 D.fillSep $
4353 ["Equality","on","floats","can","be","unreliable,","so","you","usually","want"
4354 ,"to","check","that","they","are","nearby","with","some","sort","of"
4355 ,D.dullyellow "(abs (actual - expected) < 0.001)","check."
4359 PAlias row col ->
4360 let
4361 region = toRegion row col
4362 in
4363 Report.Report "UNFINISHED PATTERN" region [] $
4364 Code.toSnippet source region Nothing $
4366 D.reflow $
4367 "I was expecting to see a variable name after the `as` keyword:"
4369 D.stack
4370 [ D.fillSep $
4371 ["The","`as`","keyword","lets","you","write","patterns","like"
4372 ,"((" <> D.dullyellow "x" <> "," <> D.dullyellow "y" <> ") " <> D.cyan "as" <> D.dullyellow " point" <> ")"
4373 ,"so","you","can","refer","to","individual","parts","of","the","tuple","with"
4374 ,D.dullyellow "x","and",D.dullyellow "y","or","you","refer","to","the","whole"
4375 ,"thing","with",D.dullyellow "point."
4377 , D.reflow $
4378 "So I was expecting to see a variable name after the `as` keyword here. Sometimes\
4379 \ people just want to use `as` as a variable name though. Try using a different name\
4380 \ in that case!"
4384 PWildcardNotVar name width row col ->
4385 let
4386 region = toWiderRegion row col (fromIntegral width)
4387 examples =
4388 case dropWhile (=='_') (Name.toChars name) of
4389 [] -> [D.dullyellow "x","or",D.dullyellow "age"]
4390 c:cs -> [D.dullyellow (D.fromChars (Char.toLower c : cs))]
4391 in
4392 Report.Report "UNEXPECTED NAME" region [] $
4393 Code.toSnippet source region Nothing $
4395 D.reflow $
4396 "Variable names cannot start with underscores like this:"
4398 D.fillSep $
4399 ["You","can","either","have","an","underscore","like",D.dullyellow "_","to"
4400 ,"ignore","the","value,","or","you","can","have","a","name","like"
4401 ] ++ examples ++ ["to","use","the","matched","value." ]
4404 PSpace space row col ->
4405 toSpaceReport source space row col
4407 PIndentStart row col ->
4408 let
4409 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4410 region = toRegion row col
4411 in
4412 Report.Report "UNFINISHED PATTERN" region [] $
4413 Code.toSnippet source surroundings (Just region)
4415 D.reflow $
4416 "I wanted to parse a pattern next, but I got stuck here:"
4418 D.stack
4419 [ D.fillSep $
4420 ["I","am","not","sure","why","I","am","getting","stuck","exactly."
4421 ,"I","just","know","that","I","want","a","pattern","next."
4422 ,"Something","as","simple","as"
4423 ,D.dullyellow "maybeHeight","or",D.dullyellow "result"
4424 ,"would","work!"
4426 , D.toSimpleNote $
4427 "I can get confused by indentation. If you think there is a pattern next, maybe\
4428 \ it needs to be indented a bit more?"
4432 PIndentAlias row col ->
4433 let
4434 region = toRegion row col
4435 in
4436 Report.Report "UNFINISHED PATTERN" region [] $
4437 Code.toSnippet source region Nothing $
4439 D.reflow $
4440 "I was expecting to see a variable name after the `as` keyword:"
4442 D.stack
4443 [ D.fillSep $
4444 ["The","`as`","keyword","lets","you","write","patterns","like"
4445 ,"((" <> D.dullyellow "x" <> "," <> D.dullyellow "y" <> ") " <> D.cyan "as" <> D.dullyellow " point" <> ")"
4446 ,"so","you","can","refer","to","individual","parts","of","the","tuple","with"
4447 ,D.dullyellow "x","and",D.dullyellow "y","or","you","refer","to","the","whole"
4448 ,"thing","with",D.dullyellow "point."
4450 , D.reflow $
4451 "So I was expecting to see a variable name after the `as` keyword here. Sometimes\
4452 \ people just want to use `as` as a variable name though. Try using a different name\
4453 \ in that case!"
4458toPRecordReport :: Code.Source -> PRecord -> Row -> Col -> Report.Report
4459toPRecordReport source record startRow startCol =
4460 case record of
4461 PRecordOpen row col ->
4462 toUnfinishRecordPatternReport source row col startRow startCol $
4463 D.reflow "I was expecting to see a field name next."
4465 PRecordEnd row col ->
4466 toUnfinishRecordPatternReport source row col startRow startCol $
4467 D.fillSep
4468 ["I","was","expecting","to","see","a","closing","curly","brace","next."
4469 ,"Try","adding","a",D.dullyellow "}","here?"
4472 PRecordField row col ->
4473 case Code.whatIsNext source row col of
4474 Code.Keyword keyword ->
4475 let
4476 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4477 region = toKeywordRegion row col keyword
4478 in
4479 Report.Report "RESERVED WORD" region [] $
4480 Code.toSnippet source surroundings (Just region)
4482 D.reflow $
4483 "I was not expecting to see `" ++ keyword ++ "` as a record field name:"
4485 D.reflow $
4486 "This is a reserved word, not available for variable names. Try another name!"
4489 _ ->
4490 toUnfinishRecordPatternReport source row col startRow startCol $
4491 D.reflow "I was expecting to see a field name next."
4493 PRecordSpace space row col ->
4494 toSpaceReport source space row col
4496 PRecordIndentOpen row col ->
4497 toUnfinishRecordPatternReport source row col startRow startCol $
4498 D.reflow "I was expecting to see a field name next."
4500 PRecordIndentEnd row col ->
4501 toUnfinishRecordPatternReport source row col startRow startCol $
4502 D.fillSep
4503 ["I","was","expecting","to","see","a","closing","curly","brace","next."
4504 ,"Try","adding","a",D.dullyellow "}","here?"
4507 PRecordIndentField row col ->
4508 toUnfinishRecordPatternReport source row col startRow startCol $
4509 D.reflow "I was expecting to see a field name next."
4512toUnfinishRecordPatternReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
4513toUnfinishRecordPatternReport source row col startRow startCol message =
4514 let
4515 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4516 region = toRegion row col
4517 in
4518 Report.Report "UNFINISHED RECORD PATTERN" region [] $
4519 Code.toSnippet source surroundings (Just region)
4521 D.reflow $
4522 "I was partway through parsing a record pattern, but I got stuck here:"
4524 D.stack
4525 [ message
4526 , D.toFancyHint $
4527 ["A","record","pattern","looks","like",D.dullyellow "{x,y}","or",D.dullyellow "{name,age}"
4528 ,"where","you","list","the","field","names","you","want","to","access."
4535toPTupleReport :: Code.Source -> PContext -> PTuple -> Row -> Col -> Report.Report
4536toPTupleReport source context tuple startRow startCol =
4537 case tuple of
4538 PTupleOpen row col ->
4539 case Code.whatIsNext source row col of
4540 Code.Keyword keyword ->
4541 let
4542 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4543 region = toKeywordRegion row col keyword
4544 in
4545 Report.Report "RESERVED WORD" region [] $
4546 Code.toSnippet source surroundings (Just region)
4548 D.reflow $
4549 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name:"
4551 D.reflow $
4552 "This is a reserved word! Try using some other name?"
4555 _ ->
4556 let
4557 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4558 region = toRegion row col
4559 in
4560 Report.Report "UNFINISHED PARENTHESES" region [] $
4561 Code.toSnippet source surroundings (Just region)
4563 D.reflow $
4564 "I just saw an open parenthesis, but I got stuck here:"
4566 D.fillSep
4567 ["I","was","expecting","so","see","a","pattern","next."
4568 ,"Maybe","it","will","end","up","being","something"
4569 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "?"
4573 PTupleEnd row col ->
4574 case Code.whatIsNext source row col of
4575 Code.Keyword keyword ->
4576 let
4577 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4578 region = toKeywordRegion row col keyword
4579 in
4580 Report.Report "RESERVED WORD" region [] $
4581 Code.toSnippet source surroundings (Just region) $
4583 D.reflow $
4584 "I ran into a reserved word in this pattern:"
4586 D.reflow $
4587 "The `" ++ keyword ++ "` keyword is reserved. Try using a different name instead!"
4590 Code.Operator op ->
4591 let
4592 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4593 region = toKeywordRegion row col op
4594 in
4595 Report.Report "UNEXPECTED SYMBOL" region [] $
4596 Code.toSnippet source surroundings (Just region) $
4598 D.reflow $
4599 "I ran into the " ++ op ++ " symbol unexpectedly in this pattern:"
4601 D.reflow $
4602 "Only the :: symbol that works in patterns. It is useful if you\
4603 \ are pattern matching on lists, trying to get the first element\
4604 \ off the front. Did you want that instead?"
4607 Code.Close term bracket ->
4608 let
4609 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4610 region = toRegion row col
4611 in
4612 Report.Report ("STRAY " ++ map Char.toUpper term) region [] $
4613 Code.toSnippet source surroundings (Just region) $
4615 D.reflow $
4616 "I ran into a an unexpected " ++ term ++ " in this pattern:"
4618 D.reflow $
4619 "This " ++ bracket : " does not match up with an earlier open " ++ term ++ ". Try deleting it?"
4622 _ ->
4623 let
4624 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4625 region = toRegion row col
4626 in
4627 Report.Report "UNFINISHED PARENTHESES" region [] $
4628 Code.toSnippet source surroundings (Just region) $
4630 D.reflow $
4631 "I was partway through parsing a pattern, but I got stuck here:"
4633 D.fillSep
4634 ["I","was","expecting","a","closing","parenthesis","next,","so"
4635 ,"try","adding","a",D.dullyellow ")","to","see","if","that","helps?"
4639 PTupleExpr pattern row col ->
4640 toPatternReport source context pattern row col
4642 PTupleSpace space row col ->
4643 toSpaceReport source space row col
4645 PTupleIndentEnd row col ->
4646 let
4647 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4648 region = toRegion row col
4649 in
4650 Report.Report "UNFINISHED PARENTHESES" region [] $
4651 Code.toSnippet source surroundings (Just region) $
4653 D.reflow $
4654 "I was expecting a closing parenthesis next:"
4656 D.stack
4657 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
4658 , D.toSimpleNote $
4659 "I can get confused by indentation in cases like this, so\
4660 \ maybe you have a closing parenthesis but it is not indented enough?"
4664 PTupleIndentExpr1 row col ->
4665 let
4666 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4667 region = toRegion row col
4668 in
4669 Report.Report "UNFINISHED PARENTHESES" region [] $
4670 Code.toSnippet source surroundings (Just region) $
4672 D.reflow $
4673 "I just saw an open parenthesis, but then I got stuck here:"
4675 D.fillSep
4676 ["I","was","expecting","so","see","a","pattern","next."
4677 ,"Maybe","it","will","end","up","being","something"
4678 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "?"
4682 PTupleIndentExprN row col ->
4683 let
4684 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4685 region = toRegion row col
4686 in
4687 Report.Report "UNFINISHED TUPLE PATTERN" region [] $
4688 Code.toSnippet source surroundings (Just region) $
4690 D.reflow $
4691 "I am partway through parsing a tuple pattern, but I got stuck here:"
4693 D.stack
4694 [ D.fillSep
4695 ["I","was","expecting","so","see","a","pattern","next."
4696 ,"I","am","expecting","the","final","result","to","be","something"
4697 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "."
4699 , D.toSimpleNote $
4700 "I can get confused by indentation in cases like this, so the problem\
4701 \ may be that the next part is not indented enough?"
4706toPListReport :: Code.Source -> PContext -> PList -> Row -> Col -> Report.Report
4707toPListReport source context list startRow startCol =
4708 case list of
4709 PListOpen row col ->
4710 case Code.whatIsNext source row col of
4711 Code.Keyword keyword ->
4712 let
4713 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4714 region = toKeywordRegion row col keyword
4715 in
4716 Report.Report "RESERVED WORD" region [] $
4717 Code.toSnippet source surroundings (Just region)
4719 D.reflow $
4720 "It looks like you are trying to use `" ++ keyword ++ "` to name an element of a list:"
4722 D.reflow $
4723 "This is a reserved word though! Try using some other name?"
4726 _ ->
4727 let
4728 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4729 region = toRegion row col
4730 in
4731 Report.Report "UNFINISHED LIST PATTERN" region [] $
4732 Code.toSnippet source surroundings (Just region) $
4734 D.reflow $
4735 "I just saw an open square bracket, but then I got stuck here:"
4737 D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
4740 PListEnd row col ->
4741 let
4742 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4743 region = toRegion row col
4744 in
4745 Report.Report "UNFINISHED LIST PATTERN" region [] $
4746 Code.toSnippet source surroundings (Just region) $
4748 D.reflow $
4749 "I was expecting a closing square bracket to end this list pattern:"
4751 D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
4754 PListExpr pattern row col ->
4755 toPatternReport source context pattern row col
4757 PListSpace space row col ->
4758 toSpaceReport source space row col
4760 PListIndentOpen row col ->
4761 let
4762 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4763 region = toRegion row col
4764 in
4765 Report.Report "UNFINISHED LIST PATTERN" region [] $
4766 Code.toSnippet source surroundings (Just region) $
4768 D.reflow $
4769 "I just saw an open square bracket, but then I got stuck here:"
4771 D.stack
4772 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
4773 , D.toSimpleNote $
4774 "I can get confused by indentation in cases like this, so\
4775 \ maybe there is something next, but it is not indented enough?"
4779 PListIndentEnd row col ->
4780 let
4781 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4782 region = toRegion row col
4783 in
4784 Report.Report "UNFINISHED LIST PATTERN" region [] $
4785 Code.toSnippet source surroundings (Just region) $
4787 D.reflow $
4788 "I was expecting a closing square bracket to end this list pattern:"
4790 D.stack
4791 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
4792 , D.toSimpleNote $
4793 "I can get confused by indentation in cases like this, so\
4794 \ maybe you have a closing square bracket but it is not indented enough?"
4798 PListIndentExpr row col ->
4799 let
4800 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4801 region = toRegion row col
4802 in
4803 Report.Report "UNFINISHED LIST PATTERN" region [] $
4804 Code.toSnippet source surroundings (Just region) $
4806 D.reflow $
4807 "I am partway through parsing a list pattern, but I got stuck here:"
4809 D.stack
4810 [ D.reflow $
4811 "I was expecting to see another pattern next. Maybe a variable name."
4812 , D.toSimpleNote $
4813 "I can get confused by indentation in cases like this, so\
4814 \ maybe there is more to this pattern but it is not indented enough?"
4820-- TYPES
4823data TContext
4824 = TC_Annotation Name.Name
4825 | TC_CustomType
4826 | TC_TypeAlias
4827 | TC_Port
4830toTypeReport :: Code.Source -> TContext -> Type -> Row -> Col -> Report.Report
4831toTypeReport source context tipe startRow startCol =
4832 case tipe of
4833 TRecord record row col ->
4834 toTRecordReport source context record row col
4836 TTuple tuple row col ->
4837 toTTupleReport source context tuple row col
4839 TStart row col ->
4840 case Code.whatIsNext source row col of
4841 Code.Keyword keyword ->
4842 let
4843 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4844 region = toKeywordRegion row col keyword
4845 in
4846 Report.Report "RESERVED WORD" region [] $
4847 Code.toSnippet source surroundings (Just region)
4849 D.reflow $
4850 "I was expecting to see a type next, but I got stuck on this reserved word:"
4852 D.reflow $
4853 "It looks like you are trying to use `" ++ keyword ++ "` as a type variable, but \
4854 \ it is a reserved word. Try using a different name!"
4857 _ ->
4858 let
4859 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4860 region = toRegion row col
4862 thing =
4863 case context of
4864 TC_Annotation _ -> "type annotation"
4865 TC_CustomType -> "custom type"
4866 TC_TypeAlias -> "type alias"
4867 TC_Port -> "port"
4869 something =
4870 case context of
4871 TC_Annotation name -> "the `" ++ Name.toChars name ++ "` type annotation"
4872 TC_CustomType -> "a custom type"
4873 TC_TypeAlias -> "a type alias"
4874 TC_Port -> "a port"
4875 in
4876 Report.Report ("PROBLEM IN " ++ map Char.toUpper thing) region [] $
4877 Code.toSnippet source surroundings (Just region)
4879 D.reflow $
4880 "I was partway through parsing " ++ something ++ ", but I got stuck here:"
4882 D.fillSep $
4883 ["I","was","expecting","to","see","a","type","next."
4884 ,"Try","putting",D.dullyellow "Int","or",D.dullyellow "String","for","now?"
4888 TSpace space row col ->
4889 toSpaceReport source space row col
4891 TIndentStart row col ->
4892 let
4893 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4894 region = toRegion row col
4896 thing =
4897 case context of
4898 TC_Annotation _ -> "type annotation"
4899 TC_CustomType -> "custom type"
4900 TC_TypeAlias -> "type alias"
4901 TC_Port -> "port"
4902 in
4903 Report.Report ("UNFINISHED " ++ map Char.toUpper thing) region [] $
4904 Code.toSnippet source surroundings (Just region)
4906 D.reflow $
4907 "I was partway through parsing a " ++ thing ++ ", but I got stuck here:"
4909 D.stack
4910 [ D.fillSep $
4911 ["I","was","expecting","to","see","a","type","next."
4912 ,"Try","putting",D.dullyellow "Int","or",D.dullyellow "String","for","now?"
4914 , D.toSimpleNote $
4915 "I can get confused by indentation. If you think there is already a type\
4916 \ next, maybe it is not indented enough?"
4921toTRecordReport :: Code.Source -> TContext -> TRecord -> Row -> Col -> Report.Report
4922toTRecordReport source context record startRow startCol =
4923 case record of
4924 TRecordOpen row col ->
4925 case Code.whatIsNext source row col of
4926 Code.Keyword keyword ->
4927 let
4928 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4929 region = toKeywordRegion row col keyword
4930 in
4931 Report.Report "RESERVED WORD" region [] $
4932 Code.toSnippet source surroundings (Just region)
4934 D.reflow $
4935 "I just started parsing a record type, but I got stuck on this field name:"
4937 D.reflow $
4938 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
4939 \ that is a reserved word. Try using a different name!"
4942 _ ->
4943 let
4944 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4945 region = toRegion row col
4946 in
4947 Report.Report "UNFINISHED RECORD TYPE" region [] $
4948 Code.toSnippet source surroundings (Just region)
4950 D.reflow $
4951 "I just started parsing a record type, but I got stuck here:"
4953 D.fillSep
4954 ["Record","types","look","like",D.dullyellow "{ name : String, age : Int },"
4955 ,"so","I","was","expecting","to","see","a","field","name","next."
4959 TRecordEnd row col ->
4960 let
4961 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4962 region = toRegion row col
4963 in
4964 Report.Report "UNFINISHED RECORD TYPE" region [] $
4965 Code.toSnippet source surroundings (Just region)
4967 D.reflow $
4968 "I am partway through parsing a record type, but I got stuck here:"
4970 D.stack
4971 [ D.fillSep
4972 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
4973 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
4975 , D.toSimpleNote $
4976 "When I get stuck like this, it usually means that there is a missing parenthesis\
4977 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
4981 TRecordField row col ->
4982 case Code.whatIsNext source row col of
4983 Code.Keyword keyword ->
4984 let
4985 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4986 region = toKeywordRegion row col keyword
4987 in
4988 Report.Report "RESERVED WORD" region [] $
4989 Code.toSnippet source surroundings (Just region)
4991 D.reflow $
4992 "I am partway through parsing a record type, but I got stuck on this field name:"
4994 D.reflow $
4995 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
4996 \ that is a reserved word. Try using a different name!"
4999 _ ->
5000 let
5001 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5002 region = toRegion row col
5003 in
5004 Report.Report "UNFINISHED RECORD TYPE" region [] $
5005 Code.toSnippet source surroundings (Just region)
5007 D.reflow $
5008 "I am partway through parsing a record type, but I got stuck after that last comma:"
5010 addNoteForRecordTypeError $
5011 D.reflow $
5012 "Trailing commas are not allowed in records, so I was expecting to see another\
5013 \ record field defined next. If you are done defining the record, the fix may\
5014 \ be to delete that last comma?"
5017 TRecordColon row col ->
5018 let
5019 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5020 region = toRegion row col
5021 in
5022 Report.Report "UNFINISHED RECORD TYPE" region [] $
5023 Code.toSnippet source surroundings (Just region)
5025 D.reflow $
5026 "I am partway through parsing a record type, but I got stuck here:"
5028 addNoteForRecordTypeError $
5029 D.fillSep $
5030 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
5031 ,"a","colon","next.","So","try","putting","an",D.green ":","sign","here?"
5035 TRecordType tipe row col ->
5036 toTypeReport source context tipe row col
5038 TRecordSpace space row col ->
5039 toSpaceReport source space row col
5041 TRecordIndentOpen row col ->
5042 let
5043 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5044 region = toRegion row col
5045 in
5046 Report.Report "UNFINISHED RECORD TYPE" region [] $
5047 Code.toSnippet source surroundings (Just region)
5049 D.reflow $
5050 "I just saw the opening curly brace of a record type, but then I got stuck here:"
5052 addNoteForRecordTypeIndentError $
5053 D.fillSep $
5054 ["I","am","expecting","a","record","like",D.dullyellow "{ name : String, age : Int }","here."
5055 ,"Try","defining","some","fields","of","your","own?"
5059 TRecordIndentEnd row col ->
5060 let
5061 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5062 region = toRegion row col
5063 in
5064 Report.Report "UNFINISHED RECORD TYPE" region [] $
5065 Code.toSnippet source surroundings (Just region)
5067 D.reflow $
5068 "I was expecting to see a closing curly brace next:"
5070 addNoteForRecordTypeIndentError $
5071 D.fillSep $
5072 ["Try","putting","an",D.green "}","and","see","if","that","helps?"
5076 TRecordIndentField row col ->
5077 let
5078 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5079 region = toRegion row col
5080 in
5081 Report.Report "UNFINISHED RECORD TYPE" region [] $
5082 Code.toSnippet source surroundings (Just region)
5084 D.reflow $
5085 "I am partway through parsing a record type, but I got stuck after that last comma:"
5087 addNoteForRecordTypeIndentError $
5088 D.reflow $
5089 "Trailing commas are not allowed in record types, so the fix may be to\
5090 \ delete that last comma? Or maybe you were in the middle of defining\
5091 \ an additional field?"
5094 TRecordIndentColon row col ->
5095 let
5096 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5097 region = toRegion row col
5098 in
5099 Report.Report "UNFINISHED RECORD TYPE" region [] $
5100 Code.toSnippet source surroundings (Just region)
5102 D.reflow $
5103 "I am partway through parsing a record type. I just saw a record\
5104 \ field, so I was expecting to see a colon next:"
5106 addNoteForRecordTypeIndentError $
5107 D.fillSep $
5108 ["Try","putting","an",D.green ":","followed","by","a","type?"
5112 TRecordIndentType row col ->
5113 let
5114 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5115 region = toRegion row col
5116 in
5117 Report.Report "UNFINISHED RECORD TYPE" region [] $
5118 Code.toSnippet source surroundings (Just region)
5120 D.reflow $
5121 "I am partway through parsing a record type, and I was expecting to run into a type next:"
5123 addNoteForRecordTypeIndentError $
5124 D.fillSep $
5125 ["Try","putting","something","like"
5126 ,D.dullyellow "Int","or",D.dullyellow "String","for","now?"
5131addNoteForRecordTypeError :: D.Doc -> D.Doc
5132addNoteForRecordTypeError normalRecommendation =
5133 D.stack $
5134 normalRecommendation
5136 [ D.toSimpleNote
5137 "If you are trying to define a record type across multiple lines, I recommend using this format:"
5138 , D.indent 4 $ D.vcat $
5139 [ "{ name : String"
5140 , ", age : Int"
5141 , ", height : Float"
5142 , "}"
5144 , D.reflow $
5145 "Notice that each line starts with some indentation. Usually two or four spaces. I\
5146 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
5147 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
5151addNoteForRecordTypeIndentError :: D.Doc -> D.Doc
5152addNoteForRecordTypeIndentError normalRecommendation =
5153 D.stack $
5154 normalRecommendation
5156 [ D.toSimpleNote
5157 "I may be confused by indentation. For example, if you are trying to define\
5158 \ a record type across multiple lines, I recommend using this format:"
5159 , D.indent 4 $ D.vcat $
5160 [ "{ name : String"
5161 , ", age : Int"
5162 , ", height : Float"
5163 , "}"
5165 , D.reflow $
5166 "Notice that each line starts with some indentation. Usually two or four spaces. I\
5167 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
5168 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
5172toTTupleReport :: Code.Source -> TContext -> TTuple -> Row -> Col -> Report.Report
5173toTTupleReport source context tuple startRow startCol =
5174 case tuple of
5175 TTupleOpen row col ->
5176 case Code.whatIsNext source row col of
5177 Code.Keyword keyword ->
5178 let
5179 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5180 region = toKeywordRegion row col keyword
5181 in
5182 Report.Report "RESERVED WORD" region [] $
5183 Code.toSnippet source surroundings (Just region)
5185 D.reflow $
5186 "I ran into a reserved word unexpectedly:"
5188 D.reflow $
5189 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name, but \
5190 \ it is a reserved word. Try using a different name!"
5193 _ ->
5194 let
5195 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5196 region = toRegion row col
5197 in
5198 Report.Report "UNFINISHED PARENTHESES" region [] $
5199 Code.toSnippet source surroundings (Just region)
5201 D.reflow $
5202 "I just saw an open parenthesis, so I was expecting to see a type next."
5204 D.fillSep $
5205 ["Something","like",D.dullyellow "(Maybe Int)","or"
5206 ,D.dullyellow "(List Person)" <> "."
5207 ,"Anything","where","you","are","putting","parentheses","around","normal","types."
5211 TTupleEnd row col ->
5212 let
5213 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5214 region = toRegion row col
5215 in
5216 Report.Report "UNFINISHED PARENTHESES" region [] $
5217 Code.toSnippet source surroundings (Just region)
5219 D.reflow $
5220 "I was expecting to see a closing parentheses next, but I got stuck here:"
5222 D.stack
5223 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
5224 , D.toSimpleNote $
5225 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
5226 \ unexpectedly. So there may be some earlier syntax trouble (like extra parenthesis\
5227 \ or missing brackets) that is confusing me."
5231 TTupleType tipe row col ->
5232 toTypeReport source context tipe row col
5234 TTupleSpace space row col ->
5235 toSpaceReport source space row col
5237 TTupleIndentType1 row col ->
5238 let
5239 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5240 region = toRegion row col
5241 in
5242 Report.Report "UNFINISHED PARENTHESES" region [] $
5243 Code.toSnippet source surroundings (Just region)
5245 D.reflow $
5246 "I just saw an open parenthesis, so I was expecting to see a type next."
5248 D.stack
5249 [ D.fillSep $
5250 ["Something","like",D.dullyellow "(Maybe Int)","or"
5251 ,D.dullyellow "(List Person)" <> "."
5252 ,"Anything","where","you","are","putting","parentheses","around","normal","types."
5254 , D.toSimpleNote $
5255 "I can get confused by indentation in cases like this, so\
5256 \ maybe you have a type but it is not indented enough?"
5260 TTupleIndentTypeN row col ->
5261 let
5262 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5263 region = toRegion row col
5264 in
5265 Report.Report "UNFINISHED TUPLE TYPE" region [] $
5266 Code.toSnippet source surroundings (Just region)
5268 D.reflow $
5269 "I think I am in the middle of parsing a tuple type. I just saw a comma, so I was expecting to see a type next."
5271 D.stack
5272 [ D.fillSep $
5273 ["A","tuple","type","looks","like",D.dullyellow "(Float,Float)","or"
5274 ,D.dullyellow "(String,Int)" <> ","
5275 ,"so","I","think","there","is","a","type","missing","here?"
5277 , D.toSimpleNote $
5278 "I can get confused by indentation in cases like this, so\
5279 \ maybe you have an expression but it is not indented enough?"
5283 TTupleIndentEnd row col ->
5284 let
5285 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5286 region = toRegion row col
5287 in
5288 Report.Report "UNFINISHED PARENTHESES" region [] $
5289 Code.toSnippet source surroundings (Just region)
5291 D.reflow $
5292 "I was expecting to see a closing parenthesis next:"
5294 D.stack
5295 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
5296 , D.toSimpleNote $
5297 "I can get confused by indentation in cases like this, so\
5298 \ maybe you have a closing parenthesis but it is not indented enough?"