on e37ceaa help sign in
2785 lines 93 kB history raw
1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Reporting.Error.Syntax
4 ( Error(..)
5 --
6 , Module(..)
7 , Exposing(..)
8 --
9 , Decl(..)
10 , DeclType(..)
11 , TypeAlias(..)
12 , CustomType(..)
13 , DeclDef(..)
14 , Port(..)
15 --
16 , Expr(..)
17 , Record(..)
18 , Tuple(..)
19 , List(..)
20 , Func(..)
21 , Case(..)
22 , If(..)
23 , Let(..)
24 , Def(..)
25 , Destruct(..)
26 --
27 , Pattern(..)
28 , PRecord(..)
29 , PTuple(..)
30 , PList(..)
31 --
32 , Type(..)
33 , TRecord(..)
34 , TTuple(..)
35 --
36 , Char(..)
37 , String(..)
38 , Escape(..)
39 , Number(..)
40 --
41 , Space(..)
42 , toReport
43 )
44 where
47import Prelude hiding (Char, String)
48import qualified Data.Char as Char
49import qualified Data.Name as Name
50import Data.Word (Word16)
51import Numeric (showHex)
53import qualified Elm.ModuleName as ModuleName
54import Parse.Primitives (Row, Col)
55import Parse.Symbol (BadOperator(..))
56import qualified Reporting.Annotation as A
57import qualified Reporting.Doc as D
58import qualified Reporting.Report as Report
59import qualified Reporting.Render.Code as Code
63-- ALL SYNTAX ERRORS
66data Error
67 = ModuleNameUnspecified ModuleName.Raw
68 | ModuleNameMismatch ModuleName.Raw (A.Located ModuleName.Raw)
69 | UnexpectedPort A.Region
70 | NoPorts A.Region
71 | ParseError Module
75-- MODULE
78data Module
79 = ModuleSpace Space Row Col
80 | ModuleEndOfFile Row Col
81 --
82 | ModuleProblem Row Col
83 | ModuleName Row Col
84 | ModuleExposing Exposing Row Col
85 --
86 | PortModuleProblem Row Col
87 | PortModuleName Row Col
88 | PortModuleExposing Exposing Row Col
89 --
90 | Effect Row Col
91 --
92 | FreshLine Row Col
93 --
94 | ImportStart Row Col
95 | ImportName Row Col
96 | ImportAs Row Col
97 | ImportAlias Row Col
98 | ImportExposing Row Col
99 | ImportExposingList Exposing Row Col
100 | ImportEnd Row Col -- different based on col=1 or if greater
101 --
102 | ImportIndentName Row Col
103 | ImportIndentAlias Row Col
104 | ImportIndentExposingList Row Col
105 --
106 | Infix Row Col
107 --
108 | Declarations Decl Row Col
111data Exposing
112 = ExposingSpace Space Row Col
113 | ExposingStart Row Col
114 | ExposingValue Row Col
115 | ExposingOperator Row Col
116 | ExposingOperatorReserved BadOperator Row Col
117 | ExposingOperatorRightParen Row Col
118 | ExposingEnd Row Col
119 --
120 | ExposingTypePrivacy Row Col
121 | ExposingTypePrivacyDots Row Col
122 | ExposingTypePrivacyEnd Row Col
123 --
124 | ExposingIndentEnd Row Col
125 | ExposingIndentValue Row Col
126 | ExposingIndentValueEnd Row Col
127 | ExposingIndentTypePrivacy Row Col
128 | ExposingIndentTypePrivacyDots Row Col
129 | ExposingIndentTypePrivacyEnd Row Col
133-- DECLARATIONS
136data Decl
137 = DeclStart Row Col
138 | DeclSpace Space Row Col
139 --
140 | Port Port Row Col
141 | DeclType DeclType Row Col
142 | DeclDef Name.Name DeclDef Row Col
143 --
144 | DeclFreshLineStart Row Col
145 | DeclFreshLineAfterDocComment Row Col
148data DeclDef
149 = DeclDefSpace Space Row Col
150 | DeclDefEquals Row Col
151 | DeclDefType Type Row Col
152 | DeclDefArg Pattern Row Col
153 | DeclDefBody Expr Row Col
154 | DeclDefNameRepeat Row Col
155 | DeclDefNameMatch Name.Name Row Col
156 --
157 | DeclDefIndentType Row Col
158 | DeclDefIndentEquals Row Col
159 | DeclDefIndentBody Row Col
160 --
161 | DeclDefFreshLineAfterType Row Col
164data Port
165 = PortSpace Space Row Col
166 | PortName Row Col
167 | PortColon Row Col
168 | PortType Type Row Col
169 | PortIndentName Row Col
170 | PortIndentColon Row Col
171 | PortIndentType Row Col
175-- TYPE DECLARATIONS
178data DeclType
179 = DT_Space Space Row Col
180 | DT_Name Row Col
181 | DT_Alias TypeAlias Row Col
182 | DT_Union CustomType Row Col
183 --
184 | DT_IndentName Row Col
187data TypeAlias
188 = AliasSpace Space Row Col
189 | AliasName Row Col
190 | AliasEquals Row Col
191 | AliasBody Type Row Col
192 --
193 | AliasIndentEquals Row Col
194 | AliasIndentBody Row Col
197data CustomType
198 = CT_Space Space Row Col
199 | CT_Name Row Col
200 | CT_Equals Row Col
201 | CT_Bar Row Col
202 | CT_Variant Row Col
203 | CT_VariantArg Type Row Col
204 --
205 | CT_IndentEquals Row Col
206 | CT_IndentBar Row Col
207 | CT_IndentAfterBar Row Col
208 | CT_IndentAfterEquals Row Col
212-- EXPRESSIONS
215data Expr
216 = Let Let Row Col
217 | Case Case Row Col
218 | If If Row Col
219 | List List Row Col
220 | Record Record Row Col
221 | Tuple Tuple Row Col
222 | Func Func Row Col
223 --
224 | Dot Row Col
225 | Access Row Col
226 | OperatorRight Name.Name Row Col
227 | OperatorReserved BadOperator Row Col
228 --
229 | Start Row Col
230 | Char Char Row Col
231 | String String Row Col
232 | Number Number Row Col
233 | Space Space Row Col
234 | EndlessShader Row Col
235 | ShaderProblem [Char.Char] Row Col
236 | IndentOperatorRight Name.Name Row Col
237 | IndentMoreExpr Row Col
240data Record
241 = RecordOpen Row Col
242 | RecordEnd Row Col
243 | RecordField Row Col
244 | RecordEquals Row Col
245 | RecordExpr Expr Row Col
246 | RecordSpace Space Row Col
247 --
248 | RecordIndentOpen Row Col
249 | RecordIndentEnd Row Col
250 | RecordIndentField Row Col
251 | RecordIndentEquals Row Col
252 | RecordIndentExpr Row Col
255data Tuple
256 = TupleExpr Expr Row Col
257 | TupleSpace Space Row Col
258 | TupleEnd Row Col
259 | TupleOperatorClose Row Col
260 | TupleOperatorReserved BadOperator Row Col
261 --
262 | TupleIndentExpr1 Row Col
263 | TupleIndentExprN Row Col
264 | TupleIndentEnd Row Col
267data List
268 = ListSpace Space Row Col
269 | ListOpen Row Col
270 | ListExpr Expr Row Col
271 | ListEnd Row Col
272 --
273 | ListIndentOpen Row Col
274 | ListIndentEnd Row Col
275 | ListIndentExpr Row Col
278data Func
279 = FuncSpace Space Row Col
280 | FuncArg Pattern Row Col
281 | FuncBody Expr Row Col
282 | FuncArrow Row Col
283 --
284 | FuncIndentArg Row Col
285 | FuncIndentArrow Row Col
286 | FuncIndentBody Row Col
289data Case
290 = CaseSpace Space Row Col
291 | CaseOf Row Col
292 | CasePattern Pattern Row Col
293 | CaseArrow Row Col
294 | CaseExpr Expr Row Col
295 | CaseBranch Expr Row Col
296 --
297 | CaseIndentOf Row Col
298 | CaseIndentExpr Row Col
299 | CaseIndentPattern Row Col
300 | CaseIndentArrow Row Col
301 | CaseIndentBranch Row Col
302 | CasePatternAlignment Word16 Row Col
305data If
306 = IfSpace Space Row Col
307 | IfThen Row Col
308 | IfElse Row Col
309 | IfElseBranchStart Row Col
310 --
311 | IfCondition Expr Row Col
312 | IfThenBranch Expr Row Col
313 | IfElseBranch Expr Row Col
314 --
315 | IfIndentCondition Row Col
316 | IfIndentThen Row Col
317 | IfIndentThenBranch Row Col
318 | IfIndentElseBranch Row Col
319 | IfIndentElse Row Col
322data Let
323 = LetSpace Space Row Col
324 | LetIn Row Col
325 | LetDefAlignment Word16 Row Col
326 | LetDefName Row Col
327 | LetDef Name.Name Def Row Col
328 | LetDestruct Destruct Row Col
329 | LetBody Expr Row Col
330 | LetIndentDef Row Col
331 | LetIndentIn Row Col
332 | LetIndentBody Row Col
335data Def
336 = DefSpace Space Row Col
337 | DefType Type Row Col
338 | DefNameRepeat Name.Name Row Col
339 | DefNameMatch Name.Name Name.Name Row Col
340 | DefArg Pattern Row Col
341 | DefEquals Row Col
342 | DefBody Expr Row Col
343 | DefIndentEquals Row Col
344 | DefIndentType Row Col
345 | DefIndentBody Row Col
346 | DefAlignment Word16 Row Col
349data Destruct
350 = DestructSpace Space Row Col
351 | DestructPattern Pattern Row Col
352 | DestructEquals Row Col
353 | DestructBody Expr Row Col
354 | DestructIndentEquals Row Col
355 | DestructIndentBody Row Col
359-- PATTERNS
362data Pattern
363 = PRecord PRecord Row Col
364 | PTuple PTuple Row Col
365 | PList PList Row Col
366 --
367 | PStart Row Col
368 | PChar Char Row Col
369 | PString String Row Col
370 | PNumber Number Row Col
371 | PFloat Int Row Col
372 | PAlias Row Col
373 | PWildcardNotVar Int Row Col
374 | PSpace Space Row Col
375 --
376 | PIndentStart Row Col
377 | PIndentAlias Row Col
380data PRecord
381 = PRecordOpen Row Col
382 | PRecordEnd Row Col
383 | PRecordField Row Col
384 | PRecordSpace Space Row Col
385 --
386 | PRecordIndentOpen Row Col
387 | PRecordIndentEnd Row Col
388 | PRecordIndentField Row Col
391data PTuple
392 = PTupleOpen Row Col
393 | PTupleEnd Row Col
394 | PTupleExpr Pattern Row Col
395 | PTupleSpace Space Row Col
396 --
397 | PTupleIndentOpen Row Col
398 | PTupleIndentEnd Row Col
399 | PTupleIndentExpr Row Col
402data PList
403 = PListOpen Row Col
404 | PListEnd Row Col
405 | PListExpr Pattern Row Col
406 | PListSpace Space Row Col
407 --
408 | PListIndentOpen Row Col
409 | PListIndentEnd Row Col
410 | PListIndentExpr Row Col
414-- TYPES
417data Type
418 = TRecord TRecord Row Col
419 | TTuple TTuple Row Col
420 | TVariant Row Col
421 | TArrow Row Col
422 --
423 | TStart Row Col
424 | TSpace Space Row Col
425 --
426 | TIndentStart Row Col
429data TRecord
430 = TRecordOpen Row Col
431 | TRecordEnd Row Col
432 --
433 | TRecordField Row Col
434 | TRecordColon Row Col
435 | TRecordType Type Row Col
436 --
437 | TRecordSpace Space Row Col
438 --
439 | TRecordIndentOpen Row Col
440 | TRecordIndentField Row Col
441 | TRecordIndentColon Row Col
442 | TRecordIndentType Row Col
443 | TRecordIndentEnd Row Col
446data TTuple
447 = TTupleOpen Row Col
448 | TTupleEnd Row Col
449 | TTupleType Type Row Col
450 | TTupleSpace Space Row Col
451 --
452 | TTupleIndentOpen Row Col
453 | TTupleIndentType Row Col
454 | TTupleIndentEnd Row Col
458-- LITERALS
461data Char
462 = CharEndless
463 | CharEscape Escape
464 | CharNotString Word16
467data String
468 = StringEndless_Single
469 | StringEndless_Multi
470 | StringEscape Escape
473data Escape
474 = EscapeUnknown
475 | BadUnicodeFormat Word16
476 | BadUnicodeCode Word16
477 | BadUnicodeLength Word16 Int Int
480data Number
481 = NumberEnd
482 | NumberDot Int
483 | NumberHexDigit
484 | NumberNoLeadingZero
488-- MISC
491data Space
492 = HasTab
493 | EndlessMultiComment
497-- TO REPORT
500toReport :: Code.Source -> Error -> Report.Report
501toReport source err =
502 case err of
503 ModuleNameUnspecified name ->
504 let
505 region = toRegion 1 1
506 in
507 Report.Report "MODULE NAME MISSING" region [] $
508 D.stack
509 [ D.reflow $
510 "I need the module name to be declared at the top of this file, like this:"
511 , D.indent 4 $ D.green $ D.fromChars $
512 "module " ++ ModuleName.toChars name ++ " exposing (..)"
513 , D.reflow $
514 "Try adding that as the first line of your file!"
515 , D.toSimpleNote $
516 "It is best to replace (..) with an explicit list of types and\
517 \ functions you want to expose. When you know a value is only used\
518 \ within this module, you can refactor without worrying about uses\
519 \ elsewhere. Limiting exposed values can also speed up compilation\
520 \ because I can skip a bunch of work if I see that the exposed API\
521 \ has not changed."
522 ]
524 ModuleNameMismatch expectedName (A.At region actualName) ->
525 Report.Report "MODULE NAME MISMATCH" region [ModuleName.toChars expectedName] $
526 Code.toSnippet source region Nothing
527 (
528 "It looks like this module name is out of sync:"
529 ,
530 D.stack
531 [ D.reflow $
532 "I need it to match the file path, so I was expecting it to see `"
533 ++ ModuleName.toChars expectedName
534 ++ "` here. Make the following change, and you should be all set!"
535 , D.indent 4 $
536 D.dullyellow (D.fromName actualName) <> " -> " <> D.green (D.fromName expectedName)
537 , D.toSimpleNote $
538 "I require that module names correspond to file paths. This makes it much\
539 \ easier to explore unfamiliar codebases! So if you want to keep the current\
540 \ module name, try renaming the file instead."
541 ]
542 )
544 UnexpectedPort region ->
545 Report.Report "UNEXPECTED PORTS" region [] $
546 Code.toSnippet source region Nothing
547 (
548 D.reflow $
549 "You are declaring ports in a normal module."
550 ,
551 D.stack
552 [ D.fillSep
553 ["Switch","this","to","say",D.green "port module","instead,"
554 ,"marking","that","this","module","contains","port","declarations."
555 ]
556 , D.link "Note"
557 "Ports are not a traditional FFI for calling JS functions directly. They need a different mindset! Read"
558 "ports"
559 "to learn the syntax and how to use it effectively."
560 ]
561 )
563 NoPorts region ->
564 Report.Report "NO PORTS" region [] $
565 Code.toSnippet source region Nothing
566 (
567 D.reflow $
568 "This module does not declare any ports, but it says it will:"
569 ,
570 D.fillSep
571 ["Switch","this","to",D.green "module"
572 ,"and","you","should","be","all","set!"
573 ]
574 )
576 ParseError modul ->
577 toParseErrorReport source modul
580toParseErrorReport :: Code.Source -> Module -> Report.Report
581toParseErrorReport source modul =
582 case modul of
583 ModuleSpace space row col ->
584 toSpaceReport source space row col
586 ModuleEndOfFile row col ->
587 let
588 region = toRegion row col
589 in
590 Report.Report "EXPECTING END OF FILE" region [] $
591 Code.toSnippet source region Nothing
592 (
593 D.reflow $
594 "I was not expecting to see anything more here:"
595 ,
596 D.reflow $
597 "I think I have read all the declarations in the file and that there is nothing\
598 \ left to see, so whatever I am running into is confusing me a lot!"
599 )
601 ModuleProblem row col ->
602 let
603 region = toRegion row col
604 in
605 Report.Report "UNFINISHED MODULE DECLARATION" region [] $
606 Code.toSnippet source region Nothing
607 (
608 D.reflow $
609 "I am parsing an `module` declaration, but I got stuck here:"
610 ,
611 D.stack
612 [ D.reflow $
613 "Here are some examples of valid `module` declarations:"
614 , D.indent 4 $ D.vcat $
615 [ D.fillSep [D.cyan "module","Main",D.cyan "exposing","(..)"]
616 , D.fillSep [D.cyan "module","Dict",D.cyan "exposing","(Dict, empty, get)"]
617 ]
618 , D.reflow $
619 "I generally recommend using an explicit exposing list. I can skip compiling a bunch\
620 \ of files when the public interface of a module stays the same, so exposing fewer\
621 \ values can help improve compile times!"
622 ]
623 )
625 ModuleName row col ->
626 let
627 region = toRegion row col
628 in
629 Report.Report "EXPECTING MODULE NAME" region [] $
630 Code.toSnippet source region Nothing
631 (
632 D.reflow $
633 "I was parsing an `module` declaration until I got stuck here:"
634 ,
635 D.stack
636 [ D.reflow $
637 "I was expecting to see the module name next, like in these examples:"
638 , D.indent 4 $ D.vcat $
639 [ D.fillSep [D.cyan "module","Dict",D.cyan "exposing","(..)"]
640 , D.fillSep [D.cyan "module","Maybe",D.cyan "exposing","(..)"]
641 , D.fillSep [D.cyan "module","Html.Attributes",D.cyan "exposing","(..)"]
642 , D.fillSep [D.cyan "module","Json.Decode",D.cyan "exposing","(..)"]
643 ]
644 , D.reflow $
645 "Notice that the module names all start with capital letters. That is required!"
646 ]
647 )
649 ModuleExposing exposing row col ->
650 error "TODO ModuleExposing" exposing row col
652 PortModuleProblem row col ->
653 let
654 region = toRegion row col
655 in
656 Report.Report "UNFINISHED PORT MODULE DECLARATION" region [] $
657 Code.toSnippet source region Nothing
658 (
659 D.reflow $
660 "I am parsing an `port module` declaration, but I got stuck here:"
661 ,
662 D.stack
663 [ D.reflow $
664 "Here are some examples of valid `port module` declarations:"
665 , D.indent 4 $ D.vcat $
666 [ D.fillSep [D.cyan "port",D.cyan "module","WebSockets",D.cyan "exposing","(send, listen, keepAlive)"]
667 , D.fillSep [D.cyan "port",D.cyan "module","Maps",D.cyan "exposing","(Location, goto)"]
668 ]
669 , D.link "Note" "Read" "ports" "for more help."
670 ]
671 )
673 PortModuleName row col ->
674 let
675 region = toRegion row col
676 in
677 Report.Report "EXPECTING MODULE NAME" region [] $
678 Code.toSnippet source region Nothing
679 (
680 D.reflow $
681 "I was parsing an `module` declaration until I got stuck here:"
682 ,
683 D.stack
684 [ D.reflow $
685 "I was expecting to see the module name next, like in these examples:"
686 , D.indent 4 $ D.vcat $
687 [ D.fillSep [D.cyan "port",D.cyan "module","WebSockets",D.cyan "exposing","(send, listen, keepAlive)"]
688 , D.fillSep [D.cyan "port",D.cyan "module","Maps",D.cyan "exposing","(Location, goto)"]
689 ]
690 , D.reflow $
691 "Notice that the module names start with capital letters. That is required!"
692 ]
693 )
695 PortModuleExposing exposing row col ->
696 error "TODO PortModuleExposing" exposing row col
698 Effect row col ->
699 let
700 region = toRegion row col
701 in
702 Report.Report "BAD MODULE DECLARATION" region [] $
703 Code.toSnippet source region Nothing
704 (
705 D.reflow $
706 "I cannot parse this module declaration:"
707 ,
708 D.reflow $
709 "This type of module is reserved for the @elm organization. It is used to\
710 \ define certain effects, avoiding building them into the compiler."
711 )
713 FreshLine row col ->
714 let
715 region = toRegion row col
717 toBadFirstLineReport keyword =
718 Report.Report "TOO MUCH INDENTATION" region [] $
719 Code.toSnippet source region Nothing
720 (
721 D.reflow $
722 "This `" ++ keyword ++ "` should not have any spaces before it:"
723 ,
724 D.reflow $
725 "Delete the spaces before `" ++ keyword ++ "` until there are none left!"
726 )
728 in
729 case Code.whatIsNext source row col of
730 Code.Keyword "module" -> toBadFirstLineReport "module"
731 Code.Keyword "import" -> toBadFirstLineReport "import"
732 Code.Keyword "type" -> toBadFirstLineReport "type"
733 Code.Keyword "port" -> toBadFirstLineReport "port"
734 _ ->
735 Report.Report "SYNTAX PROBLEM" region [] $
736 Code.toSnippet source region Nothing
737 (
738 D.reflow $
739 "I got stuck here:"
740 ,
741 D.stack
742 [ D.reflow $
743 "I am not sure what is going on, but I recommend starting an Elm\
744 \ file with the following lines:"
745 , D.vcat
746 [ D.fillSep [D.cyan "import","Html"]
747 , ""
748 , D.fillSep [D.green "main","="]
749 , D.indent 2 $ D.fillSep [D.cyan "Html" <> ".text",D.dullyellow "\"Hello!\""]
750 ]
751 , D.reflow $
752 "You should be able to copy those lines directly into your file. Check out\
753 \ some of the examples on https://elm-lang.org for more help getting started!"
754 , D.toSimpleNote $
755 "This can also happen when something is indented too much!"
756 ]
757 )
759 ImportStart row col ->
760 toImportReport source row col
762 ImportName row col ->
763 let
764 region = toRegion row col
765 in
766 Report.Report "EXPECTING IMPORT NAME" region [] $
767 Code.toSnippet source region Nothing
768 (
769 D.reflow $
770 "I was parsing an `import` until I got stuck here:"
771 ,
772 D.stack
773 [ D.reflow $
774 "I was expecting to see a module name next, like in these examples:"
775 , D.indent 4 $ D.vcat $
776 [ D.fillSep [D.cyan "import","Dict"]
777 , D.fillSep [D.cyan "import","Maybe"]
778 , D.fillSep [D.cyan "import","Html.Attributes"]
779 , D.fillSep [D.cyan "import","Json.Decode"]
780 ]
781 , D.reflow $
782 "Notice that the module names all start with capital letters. That is required!"
783 ]
784 )
786 ImportAs row col ->
787 toImportReport source row col
789 ImportAlias row col ->
790 let
791 region = toRegion row col
792 in
793 Report.Report "EXECTING IMPORT ALIAS" region [] $
794 Code.toSnippet source region Nothing
795 (
796 D.reflow $
797 "I was parsing an `import` until I got stuck here:"
798 ,
799 D.stack
800 [ D.reflow $
801 "I was expecting to see an alias next, like in these examples:"
802 , D.indent 4 $ D.vcat $
803 [ D.fillSep [D.cyan "import","Html.Attributes",D.cyan "as","Attr"]
804 , D.fillSep [D.cyan "import","WebGL.Texture",D.cyan "as","Texture"]
805 , D.fillSep [D.cyan "import","Json.Decode",D.cyan "as","D"]
806 ]
807 , D.reflow $
808 "Notice that the alias always starts with a capital letter. That is required!"
809 ]
810 )
812 ImportExposing row col ->
813 toImportReport source row col
815 ImportExposingList exposing row col ->
816 error "TODO ImportExposingList" exposing row col
818 ImportEnd row col ->
819 toImportReport source row col
821 ImportIndentName row col ->
822 toImportReport source row col
824 ImportIndentAlias row col ->
825 toImportReport source row col
827 ImportIndentExposingList row col ->
828 let
829 region = toRegion row col
830 in
831 Report.Report "UNFINISHED IMPORT" region [] $
832 Code.toSnippet source region Nothing
833 (
834 D.reflow $
835 "I was parsing an `import` until I got stuck here:"
836 ,
837 D.stack
838 [ D.reflow $
839 "I was expecting to see the list of exposed values next. For example, here\
840 \ are two ways to expose values from the `Html` module:"
841 , D.indent 4 $ D.vcat $
842 [ D.fillSep [D.cyan "import","Html",D.cyan "exposing","(..)"]
843 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
844 ]
845 , D.reflow $
846 "I generally recommend the second style. It is more explicit, making it\
847 \ much easier to figure out where values are coming from in large projects!"
848 ]
849 )
851 Infix row col ->
852 let
853 region = toRegion row col
854 in
855 Report.Report "BAD INFIX" region [] $
856 Code.toSnippet source region Nothing
857 (
858 D.reflow $
859 "Something went wrong in this infix operator declaration:"
860 ,
861 D.reflow $
862 "This feature is used by the @elm organization to define the\
863 \ languages built-in operators."
864 )
866 Declarations decl _ _ ->
867 toDeclarationsReport source decl
871-- IMPORTS
874toImportReport :: Code.Source -> Row -> Col -> Report.Report
875toImportReport source row col =
876 let
877 region = toRegion row col
878 in
879 Report.Report "UNFINISHED IMPORT" region [] $
880 Code.toSnippet source region Nothing
881 (
882 D.reflow $
883 "I am partway through parsing an import, but I got stuck here:"
884 ,
885 D.stack
886 [ D.reflow $
887 "Here are some examples of valid `import` declarations:"
888 , D.indent 4 $ D.vcat $
889 [ D.fillSep [D.cyan "import","Html"]
890 , D.fillSep [D.cyan "import","Html",D.cyan "as","H"]
891 , D.fillSep [D.cyan "import","Html",D.cyan "as","H",D.cyan "exposing","(..)"]
892 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
893 ]
894 , D.reflow $
895 "You are probably trying to import a different module, but try to make it look like one of these examples!"
896 ]
897 )
901-- SPACES
904toSpaceReport :: Code.Source -> Space -> Row -> Col -> Report.Report
905toSpaceReport source space row col =
906 case space of
907 HasTab ->
908 let
909 region = toRegion row col
910 in
911 Report.Report "NO TABS" region [] $
912 Code.toSnippet source region Nothing
913 (
914 D.reflow $
915 "I ran into a tab, but tabs are not allowed in Elm files."
916 ,
917 D.reflow $
918 "Replace the tab with spaces."
919 )
921 EndlessMultiComment ->
922 let
923 region = toWiderRegion row col 2
924 in
925 Report.Report "ENDLESS COMMENT" region [] $
926 Code.toSnippet source region Nothing
927 (
928 D.reflow $
929 "I cannot find the end of this multi-line comment:"
930 ,
931 D.stack -- "{-"
932 [ D.reflow "Add a -} somewhere after this to end the comment."
933 , D.toSimpleHint
934 "Multi-line comments can be nested in Elm, so {- {- -} -} is a comment\
935 \ that happens to contain another comment. Like parentheses and curly braces,\
936 \ the start and end markers must always be balanced. Maybe that is the problem?"
937 ]
938 )
942-- DECLARATIONS
945toRegion :: Row -> Col -> A.Region
946toRegion row col =
947 let
948 pos = A.Position row col
949 in
950 A.Region pos pos
953toWiderRegion :: Row -> Col -> Word16 -> A.Region
954toWiderRegion row col extra =
955 A.Region
956 (A.Position row col)
957 (A.Position row (col + extra))
960toDeclarationsReport :: Code.Source -> Decl -> Report.Report
961toDeclarationsReport source decl =
962 case decl of
963 DeclStart row col ->
964 error "TODO DeclStart" row col
966 DeclSpace space row col ->
967 toSpaceReport source space row col
969 Port port row col ->
970 error "TODO Port" port row col
972 DeclType declType row col ->
973 error "TODO DeclType" declType row col
975 DeclDef name declDef row col ->
976 toDeclDefReport source name declDef row col
978 DeclFreshLineStart row col ->
979 error "TODO DeclFreshLineStart" row col
981 DeclFreshLineAfterDocComment row col ->
982 error "TODO DeclFreshLineAfterDocComment" row col
985toDeclDefReport :: Code.Source -> Name.Name -> DeclDef -> Row -> Col -> Report.Report
986toDeclDefReport source name declDef startRow startCol =
987 case declDef of
988 DeclDefSpace space row col ->
989 toSpaceReport source space row col
991 DeclDefEquals row col ->
992 error "TODO DeclDefEquals" row col
994 DeclDefType tipe row col ->
995 error "TODO DeclDefType" tipe row col
997 DeclDefArg pattern row col ->
998 error "TODO DeclDefArg" pattern row col
1000 DeclDefBody expr row col ->
1001 toExprReport source (InDef name startRow startCol) expr row col
1003 DeclDefNameRepeat row col ->
1004 let
1005 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1006 region = toRegion row col
1007 in
1008 Report.Report "EXPECTING DEFINITION" region [] $
1009 Code.toSnippet source surroundings (Just region)
1011 D.reflow $
1012 "I just saw the type annotation for `" ++ Name.toChars name
1013 ++ "` so I was expecting to see its definition here:"
1015 D.reflow $
1016 "Type annotations always appear directly above the relevant\
1017 \ definition, without anything else (even doc comments) in between."
1020 DeclDefNameMatch defName row col ->
1021 let
1022 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1023 region = toRegion row col
1024 in
1025 Report.Report "NAME MISMATCH" region [] $
1026 Code.toSnippet source surroundings (Just region)
1028 D.reflow $
1029 "I just saw a type annotation for `" ++ Name.toChars name ++ "`, but it is followed by a definition for `" ++ Name.toChars defName ++ "`:"
1031 D.stack
1032 [ D.reflow $
1033 "These names do not match! Is there a typo?"
1034 , D.indent 4 $ D.fillSep $
1035 [D.dullyellow (D.fromName defName),"->",D.green (D.fromName name)]
1039 DeclDefIndentType row col ->
1040 error "TODO DeclDefIndentType" row col
1042 DeclDefIndentEquals row col ->
1043 error "TODO DeclDefIndentEquals" row col
1045 DeclDefIndentBody row col ->
1046 error "TODO DeclDefIndentBody" row col
1048 DeclDefFreshLineAfterType row col ->
1049 error "TODO DeclDefFreshLineAfterType" row col
1053-- CONTEXT
1056data Context
1057 = InNode Node Row Col Context
1058 | InDef Name.Name Row Col
1061data Node
1062 = NRecord
1063 | NParens
1064 | NList
1065 | NFunc
1066 | NCond
1067 | NThen
1068 | NElse
1069 | NCase
1070 | NBranch
1071 deriving (Eq)
1074getDefName :: Context -> Name.Name
1075getDefName context =
1076 case context of
1077 InDef name _ _ -> name
1078 InNode _ _ _ c -> getDefName c
1081isWithin :: Node -> Context -> Bool
1082isWithin desiredNode context =
1083 case context of
1084 InDef _ _ _ -> False
1085 InNode actualNode _ _ _ -> desiredNode == actualNode
1089-- EXPR REPORTS
1092toExprReport :: Code.Source -> Context -> Expr -> Row -> Col -> Report.Report
1093toExprReport source context expr startRow startCol =
1094 case expr of
1095 Let _ _ _ ->
1096 error "TODO Let"
1098 Case case_ row col ->
1099 toCaseReport source context case_ row col
1101 If if_ row col ->
1102 toIfReport source context if_ row col
1104 List list row col ->
1105 toListReport source context list row col
1107 Record record row col ->
1108 toRecordReport source context record row col
1110 Tuple tuple row col ->
1111 toTupleReport source context tuple row col
1113 Func func row col ->
1114 toFuncReport source context func row col
1116 Dot row col ->
1117 let region = toRegion row col in
1118 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
1119 Code.toSnippet source region Nothing
1121 D.reflow $
1122 "I was expecting to see a record accessor here:"
1124 D.fillSep
1125 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
1126 ,"that","accesses","a","value","from","a","record."
1130 Access row col ->
1131 let region = toRegion row col in
1132 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
1133 Code.toSnippet source region Nothing
1135 D.reflow $
1136 "I am trying to parse a record accessor here:"
1138 D.stack
1140 D.fillSep
1141 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
1142 ,"that","accesses","a","value","from","a","record."
1145 D.toSimpleNote $
1146 "Record field names must start with a lower case letter!"
1150 OperatorRight op row col ->
1151 let region = toRegion row col in
1152 Report.Report "MISSING EXPRESSION" region [] $
1153 Code.toSnippet source region Nothing
1155 D.reflow $
1156 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
1158 D.stack
1159 [ D.fillSep $
1160 ["You","can","just","put","anything","for","now,","like"
1161 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1162 ,"Once","there","is","something","there,","I","can","probably"
1163 ,"give","a","more","specific","hint!"
1165 , D.toSimpleNote $
1166 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
1167 \ Or if I run into operators in unexpected spots. Point is, there are a\
1168 \ couple ways I can get confused and give sort of weird advice!"
1172 OperatorReserved operator row col ->
1173 toOperatorReport source context operator row col
1175 Start row col ->
1176 let
1177 (contextRow, contextCol, aThing) =
1178 case context of
1179 InDef name r c -> (r, c, "the `" ++ Name.toChars name ++ "` definition")
1180 InNode NRecord r c _ -> (r, c, "a record")
1181 InNode NParens r c _ -> (r, c, "some parentheses")
1182 InNode NList r c _ -> (r, c, "a list")
1183 InNode NFunc r c _ -> (r, c, "an anonymous function")
1184 InNode NCond r c _ -> (r, c, "an `if` expression")
1185 InNode NThen r c _ -> (r, c, "an `if` expression")
1186 InNode NElse r c _ -> (r, c, "an `if` expression")
1187 InNode NCase r c _ -> (r, c, "a `case` expression")
1188 InNode NBranch r c _ -> (r, c, "a `case` expression")
1189 -- TODO check if this is actually the best way to get error messages here
1191 surroundings = A.Region (A.Position contextRow contextCol) (A.Position row col)
1192 region = toRegion row col
1193 in
1194 Report.Report "MISSING EXPRESSION" region [] $
1195 Code.toSnippet source surroundings (Just region)
1197 D.reflow $
1198 "I am partway through parsing " ++ aThing ++ ", but I got stuck here:"
1200 D.stack
1201 [ D.fillSep $
1202 ["I","was","expecting","to","see","an","expression","like"
1203 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1204 ,"Once","there","is","something","there,","I","can","probably"
1205 ,"give","a","more","specific","hint!"
1207 , D.toSimpleNote $
1208 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
1209 \ Or if I run into operators in unexpected spots. Point is, there are a\
1210 \ couple ways I can get confused and give sort of weird advice!"
1214 Char char row col ->
1215 toCharReport source char row col
1217 String string row col ->
1218 toStringReport source string row col
1220 Number number row col ->
1221 toNumberReport source number row col
1223 Space space row col ->
1224 toSpaceReport source space row col
1226 EndlessShader row col ->
1227 let
1228 region = toWiderRegion row col 6
1229 in
1230 Report.Report "ENDLESS SHADER" region [] $
1231 Code.toSnippet source region Nothing
1233 D.reflow "I cannot find the end of this shader:"
1235 D.reflow "Add a |] somewhere after this to end the shader."
1238 ShaderProblem problem row col ->
1239 let
1240 region = toRegion row col
1241 in
1242 Report.Report "SHADER PROBLEM" region [] $
1243 Code.toSnippet source region Nothing
1245 D.reflow $
1246 "I ran into a problem while parsing this GLSL block."
1248 D.stack
1249 [ D.reflow $
1250 "I use a 3rd party GLSL parser for now, and I did my best to extract their error message:"
1251 , D.indent 4 $ D.vcat $
1252 map D.fromChars (filter (/="") (lines problem))
1256 IndentOperatorRight op row col ->
1257 let
1258 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1259 region = toRegion row col
1260 in
1261 Report.Report "MISSING EXPRESSION" region [] $
1262 Code.toSnippet source surroundings (Just region)
1264 D.reflow $
1265 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
1267 D.stack
1269 D.fillSep $
1270 ["You","can","just","put","anything","for","now,","like"
1271 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1272 ,"Once","there","is","something","there,","I","can","probably"
1273 ,"give","a","more","specific","hint!"
1276 D.toSimpleNote $
1277 "I may be getting confused by your indentation? The easiest way to make sure\
1278 \ this is not an indentation problem is to put the expression on the right of\
1279 \ the " ++ Name.toChars op ++ " operator on the same line."
1283 IndentMoreExpr _ _ ->
1284 error "TODO IndentMoreExpr"
1288-- CHAR
1291toCharReport :: Code.Source -> Char -> Row -> Col -> Report.Report
1292toCharReport source char row col =
1293 case char of
1294 CharEndless ->
1295 let
1296 region = toRegion row col
1297 in
1298 Report.Report "MISSING SINGLE QUOTE" region [] $
1299 Code.toSnippet source region Nothing
1301 D.reflow $
1302 "I thought I was parsing a character, but I got to the end of\
1303 \ the line without seeing the closing single quote:"
1305 D.reflow $
1306 "Add a closing single quote here!"
1309 CharEscape escape ->
1310 toEscapeReport source escape row col
1312 CharNotString width ->
1313 let
1314 region = toWiderRegion row col width
1315 in
1316 Report.Report "NEEDS DOUBLE QUOTES" region [] $
1317 Code.toSnippet source region Nothing
1319 "The following string uses single quotes:"
1321 D.stack
1322 [ "Please switch to double quotes instead:"
1323 , D.indent 4 $
1324 D.dullyellow "'this'" <> " => " <> D.green "\"this\""
1325 , D.toSimpleNote $
1326 "Elm uses double quotes for strings like \"hello\", whereas it uses single\
1327 \ quotes for individual characters like 'a' and 'ø'. This distinction helps with\
1328 \ code like (String.any (\\c -> c == 'X') \"90210\") where you are inspecting\
1329 \ individual characters."
1335-- STRING
1338toStringReport :: Code.Source -> String -> Row -> Col -> Report.Report
1339toStringReport source string row col =
1340 case string of
1341 StringEndless_Single ->
1342 let
1343 region = toRegion row col
1344 in
1345 Report.Report "ENDLESS STRING" region [] $
1346 Code.toSnippet source region Nothing
1348 D.reflow $
1349 "I got to the end of the line without seeing the closing double quote:"
1351 D.stack
1352 [ D.fillSep $
1353 ["Strings","look","like",D.green "\"this\"","with","double"
1354 ,"quotes","on","each","end.","Is","the","closing","double"
1355 ,"quote","missing","in","your","code?"
1357 , D.link "Note" "Read" "TODO" "if you want a string that spans multiple lines."
1361 StringEndless_Multi ->
1362 let
1363 region = toWiderRegion row col 3
1364 in
1365 Report.Report "ENDLESS STRING" region [] $
1366 Code.toSnippet source region Nothing
1368 D.reflow $
1369 "I cannot find the end of this multi-line string:"
1371 D.stack
1372 [ D.reflow "Add a \"\"\" somewhere after this to end the string."
1373 , D.link "Hint" "Read" "TODO" "for more information on strings and multi-line strings."
1377 StringEscape escape ->
1378 toEscapeReport source escape row col
1382-- ESCAPES
1385toEscapeReport :: Code.Source -> Escape -> Row -> Col -> Report.Report
1386toEscapeReport source escape row col =
1387 case escape of
1388 EscapeUnknown ->
1389 let
1390 region = toWiderRegion row col 2
1391 in
1392 Report.Report "UNKNOWN ESCAPE" region [] $
1393 Code.toSnippet source region Nothing
1395 D.reflow $
1396 "Backslashes always start escaped characters, but I do not recognize this one:"
1398 D.stack
1399 [ D.reflow $
1400 "Valid escape characters include:"
1401 , D.dullyellow $ D.indent 4 $ D.vcat $
1402 [ "\\n"
1403 , "\\r"
1404 , "\\t"
1405 , "\\\""
1406 , "\\\'"
1407 , "\\\\"
1408 , "\\u{003D}"
1410 , D.reflow $
1411 "Do you want one of those instead? Maybe you need \\\\ to escape a backslash?"
1412 , D.toSimpleNote $
1413 "The last style lets encode ANY character by its Unicode code\
1414 \ point. That means \\u{0009} and \\t are the same. You can use\
1415 \ that style for anything not covered by the other six escapes!"
1419 BadUnicodeFormat width ->
1420 let
1421 region = toWiderRegion row col width
1422 in
1423 Report.Report "BAD UNICODE ESCAPE" region [] $
1424 Code.toSnippet source region Nothing
1426 D.reflow $
1427 "I ran into an invalid Unicode escape:"
1429 D.stack
1430 [ D.reflow $
1431 "Here are some examples of valid Unicode escapes:"
1432 , D.dullyellow $ D.indent 4 $ D.vcat $
1433 [ "\\u{0041}"
1434 , "\\u{03BB}"
1435 , "\\u{6728}"
1436 , "\\u{1F60A}"
1438 , D.reflow $
1439 "Notice that the code point is always surrounded by curly braces.\
1440 \ Maybe you are missing the opening or closing curly brace?"
1443 BadUnicodeCode width ->
1444 let
1445 region = toWiderRegion row col width
1446 in
1447 Report.Report "BAD UNICODE ESCAPE" region [] $
1448 Code.toSnippet source region Nothing
1450 D.reflow $
1451 "This is not a valid code point:"
1453 D.reflow $
1454 "The valid code points are between 0 and 10FFFF inclusive."
1457 BadUnicodeLength width numDigits badCode ->
1458 let
1459 region = toWiderRegion row col width
1460 in
1461 Report.Report "BAD UNICODE ESCAPE" region [] $
1462 Code.toSnippet source region Nothing $
1463 if numDigits < 4 then
1465 D.reflow $
1466 "Every code point needs at least four digits:"
1468 let
1469 goodCode = replicate (4 - numDigits) '0' ++ map Char.toUpper (showHex badCode "")
1470 suggestion = "\\u{" <> D.fromChars goodCode <> "}"
1471 in
1472 D.fillSep ["Try",D.green suggestion,"instead?"]
1475 else
1477 D.reflow $
1478 "This code point has too many digits:"
1480 D.fillSep $
1481 ["Valid","code","points","are","between"
1482 ,D.green "\\u{0000}","and",D.green "\\u{10FFFF}" <> ","
1483 ,"so","try","trimming","any","leading","zeros","until"
1484 ,"you","have","between","four","and","six","digits."
1490-- NUMBERS
1493toNumberReport :: Code.Source -> Number -> Row -> Col -> Report.Report
1494toNumberReport source number row col =
1495 let
1496 region = toRegion row col
1497 in
1498 case number of
1499 NumberEnd ->
1500 Report.Report "WEIRD NUMBER" region [] $
1501 Code.toSnippet source region Nothing
1503 D.reflow $
1504 "I thought I was reading a number, but I ran into some weird stuff here:"
1506 D.stack
1507 [ D.reflow $
1508 "I recognize numbers in the following formats:"
1509 , D.indent 4 $ D.vcat [ "42", "3.14", "6.022e23", "0x002B" ]
1510 , D.reflow $
1511 "So is there a way to write it like one of those?"
1515 NumberDot int ->
1516 Report.Report "WEIRD NUMBER" region [] $
1517 Code.toSnippet source region Nothing
1519 D.reflow $
1520 "Numbers cannot end with a dot like this:"
1522 D.fillSep
1523 ["Switching","to",D.green (D.fromChars (show int))
1524 ,"or",D.green (D.fromChars (show int ++ ".0"))
1525 ,"will","work","though!"
1529 NumberHexDigit ->
1530 Report.Report "WEIRD HEXIDECIMAL" region [] $
1531 Code.toSnippet source region Nothing
1533 D.reflow $
1534 "I thought I was reading a hexidecimal number until I got here:"
1536 D.stack
1537 [ D.reflow $
1538 "Valid hexidecimal digits include 0123456789abcdefABCDEF, so I can\
1539 \ only recognize things like this:"
1540 , D.indent 4 $ D.vcat [ "0x2B", "0x002B", "0x00ffb3" ]
1544 NumberNoLeadingZero ->
1545 Report.Report "LEADING ZEROS" region [] $
1546 Code.toSnippet source region Nothing
1548 D.reflow $
1549 "I do not accept numbers with leading zeros:"
1551 D.stack
1552 [ D.reflow $
1553 "Just delete the leading zeros and it should work!"
1554 , D.toSimpleNote $
1555 "Some languages let you to specify octal numbers by adding a leading zero.\
1556 \ So in C, writing 0111 is the same as writing 73. Some people are used to\
1557 \ that, but others probably want it to equal 111. Either path is going to\
1558 \ surprise people from certain backgrounds, so Elm tries to avoid this whole\
1559 \ situation."
1565-- OPERATORS
1568toOperatorReport :: Code.Source -> Context -> BadOperator -> Row -> Col -> Report.Report
1569toOperatorReport source context operator row col =
1570 case operator of
1571 BadDot ->
1572 let
1573 region = toRegion row col
1574 in
1575 Report.Report "UNEXPECTED SYMBOL" region [] $
1576 Code.toSnippet source region Nothing
1578 "I was not expecting this dot:"
1580 D.reflow $
1581 "Dots are for record access and decimal points, so\
1582 \ they cannot float around on their own. Maybe\
1583 \ there is some extra whitespace?"
1586 BadPipe ->
1587 let
1588 region = toRegion row col
1589 in
1590 Report.Report "UNEXPECTED SYMBOL" region [] $
1591 Code.toSnippet source region Nothing
1593 D.reflow $
1594 "I was not expecting this vertical bar:"
1596 D.reflow $
1597 "Vertical bars should only appear in custom type declarations. Maybe you want || instead?"
1600 BadArrow ->
1601 let
1602 region = toWiderRegion row col 2
1603 in
1604 Report.Report "UNEXPECTED ARROW" region [] $
1605 Code.toSnippet source region Nothing $
1606 if isWithin NBranch context then
1608 D.reflow $
1609 "I was not expecting to see an arrow here:"
1611 D.stack
1613 D.reflow $
1614 "I think I am parsing a `case` expression right now, so it makes sense to\
1615 \ see arrows around here. This one is confusing me though!"
1617 D.toSimpleHint $
1618 "I may be getting confused by the indentation. Every pattern in a `case` must be\
1619 \ exactly aligned (with exactly the same amount of indentation) so maybe this arrow\
1620 \ appears after the next `case` pattern (correctly!) but the pattern itself is\
1621 \ indented too far?"
1625 else
1627 D.reflow $
1628 "I was not expecting an arrow here:"
1630 D.reflow $
1631 "Arrows should only appear in `case` expressions and anonymous functions. Maybe\
1632 \ you want > or >= instead?"
1635 BadEquals ->
1636 let
1637 region = toRegion row col
1638 name = getDefName context
1639 in
1640 Report.Report "UNEXPECTED EQUALS" region [] $
1641 Code.toSnippet source region Nothing
1643 D.reflow $
1644 "I was not expecting to see this equals sign:"
1646 D.stack
1648 D.reflow "Maybe you want == instead? To check if two values are equal?"
1650 D.toSimpleNote $
1651 if isWithin NRecord context then
1652 "Records look like { x = 3, y = 4 } with the equals sign right\
1653 \ after the field name. So maybe you forgot a comma?"
1654 else
1655 "I may be getting confused by your indentation. Is this supposed to be part of\
1656 \ a definition AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
1657 \ the problem may be a bit before the equals sign. I need all definitions to\
1658 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
1659 \ this new definition is indented a bit too much."
1663 BadHasType ->
1664 let
1665 region = toRegion row col
1666 name = getDefName context
1667 in
1668 Report.Report "UNEXPECTED SYMBOL" region [] $
1669 Code.toSnippet source region Nothing $
1671 D.reflow $
1672 "I was not expecting to run into the \"has type\" symbol here:"
1674 D.stack
1676 D.fillSep
1677 ["Maybe","you","want",D.green "::","instead?"
1678 ,"To","put","something","on","the","front","of","a","list?"
1680 , D.toSimpleNote $
1681 "The single colon is reserved for type annotations and record types, but I think\
1682 \ I am parsing the definition of `" ++ Name.toChars name ++ "` right now."
1684 D.toSimpleNote $
1685 "I may be getting confused by your indentation. Is this supposed to be part of\
1686 \ a type annotation AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
1687 \ the problem may be a bit before the \"has type\" symbol. I need all definitions to\
1688 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
1689 \ this new definition is indented a bit too much."
1695-- CASE
1698toCaseReport :: Code.Source -> Context -> Case -> Row -> Col -> Report.Report
1699toCaseReport source context case_ startRow startCol =
1700 case case_ of
1701 CaseSpace space row col ->
1702 toSpaceReport source space row col
1704 CaseOf row col ->
1705 toUnfinishCaseReport source row col startRow startCol $
1706 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
1708 CasePattern pattern row col ->
1709 error "TODO CasePattern" pattern row col
1711 CaseArrow row col ->
1712 let
1713 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1714 region = toRegion row col
1715 in
1716 case Code.whatIsNext source row col of
1717 Code.Keyword keyword ->
1718 Report.Report "RESERVED WORD" region [] $
1719 Code.toSnippet source surroundings (Just region)
1721 D.reflow $
1722 "I am partway through parsing a `case` expression, but I got stuck here:"
1724 D.reflow $
1725 "It looks like you are trying to use `" ++ keyword ++ "` in one of your\
1726 \ patterns, but it is a reserved word. Try using a different name?"
1729 Code.Operator ":" ->
1730 Report.Report "UNEXPECTED OPERATOR" region [] $
1731 Code.toSnippet source surroundings (Just region)
1733 D.reflow $
1734 "I am partway through parsing a `case` expression, but I got stuck here:"
1736 D.fillSep $
1737 ["I","am","seeing",D.dullyellow ":","but","maybe","you","want",D.green "::","instead?"
1738 ,"For","pattern","matching","on","lists?"
1742 Code.Operator "=" ->
1743 Report.Report "UNEXPECTED OPERATOR" region [] $
1744 Code.toSnippet source surroundings (Just region)
1746 D.reflow $
1747 "I am partway through parsing a `case` expression, but I got stuck here:"
1749 D.fillSep $
1750 ["I","am","seeing",D.dullyellow "=","but","maybe","you","want",D.green "->","instead?"
1754 _ ->
1755 Report.Report "MISSING ARROW" region [] $
1756 Code.toSnippet source surroundings (Just region)
1758 D.reflow $
1759 "I am partway through parsing a `case` expression, but I got stuck here:"
1761 addNoteForCaseIndentError $
1762 D.reflow $
1763 "I was expecting to see an arrow next."
1766 CaseExpr expr row col ->
1767 toExprReport source (InNode NCase startRow startCol context) expr row col
1769 CaseBranch expr row col ->
1770 toExprReport source (InNode NBranch startRow startCol context) expr row col
1772 CaseIndentOf row col ->
1773 toUnfinishCaseReport source row col startRow startCol $
1774 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
1776 CaseIndentExpr row col ->
1777 toUnfinishCaseReport source row col startRow startCol $
1778 D.reflow "I was expecting to see a expression next."
1780 CaseIndentPattern row col ->
1781 toUnfinishCaseReport source row col startRow startCol $
1782 D.reflow "I was expecting to see a pattern next."
1784 CaseIndentArrow row col ->
1785 toUnfinishCaseReport source row col startRow startCol $
1786 D.fillSep
1787 ["I","just","saw","a","pattern,","so","I","was","expecting"
1788 ,"to","see","a",D.dullyellow "->","next."
1791 CaseIndentBranch row col ->
1792 toUnfinishCaseReport source row col startRow startCol $
1793 D.reflow $
1794 "I was expecting to see an expression next. What should I do when\
1795 \ I run into this particular pattern?"
1797 CasePatternAlignment indent row col ->
1798 toUnfinishCaseReport source row col startRow startCol $
1799 D.reflow $
1800 "I suspect this is a pattern that is not indented far enough? (" ++ show indent ++ " spaces)"
1803toUnfinishCaseReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
1804toUnfinishCaseReport source row col startRow startCol message =
1805 let
1806 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1807 region = toRegion row col
1808 in
1809 Report.Report "UNFINISHED CASE" region [] $
1810 Code.toSnippet source surroundings (Just region)
1812 D.reflow $
1813 "I was partway through parsing a `case` expression, but I got stuck here:"
1815 D.stack
1816 [ message
1817 , D.toSimpleNote $
1818 "Here is an example of a valid `case` expression for reference."
1819 , D.vcat $
1820 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
1821 , D.indent 6 $ D.fillSep [D.green "Just","width","->"]
1822 , D.indent 8 $ D.fillSep ["width","+",D.yellow "200"]
1823 , ""
1824 , D.indent 6 $ D.fillSep [D.green "Nothing","->"]
1825 , D.indent 8 $ D.fillSep [D.yellow "400"]
1827 , D.reflow $
1828 "Notice the indentation. Each pattern is aligned, and each branch is indented\
1829 \ a bit more than the corresponding pattern. That is important!"
1834addNoteForCaseIndentError :: D.Doc -> D.Doc
1835addNoteForCaseIndentError message =
1836 D.stack $
1837 message
1839 [ D.toSimpleNote $
1840 "Sometimes I get confused by indentation, so try to make your `case` look\
1841 \ something like this:"
1842 , D.vcat $
1843 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
1844 , D.indent 6 $ D.fillSep [D.green "Just","width","->"]
1845 , D.indent 8 $ D.fillSep ["width","+",D.yellow "200"]
1846 , ""
1847 , D.indent 6 $ D.fillSep [D.green "Nothing","->"]
1848 , D.indent 8 $ D.fillSep [D.yellow "400"]
1850 , D.reflow $
1851 "Notice the indentation! Each pattern is aligned, and each branch is indented\
1852 \ a bit more than the corresponding pattern. That is important!"
1857-- IF
1860toIfReport :: Code.Source -> Context -> If -> Row -> Col -> Report.Report
1861toIfReport source context if_ startRow startCol =
1862 case if_ of
1863 IfSpace space row col ->
1864 toSpaceReport source space row col
1866 IfThen row col ->
1867 let
1868 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1869 region = toRegion row col
1870 in
1871 Report.Report "UNFINISHED IF" region [] $
1872 Code.toSnippet source surroundings (Just region)
1874 D.reflow $
1875 "I was expecting to see more of this `if` expression, but I got stuck here:"
1877 D.fillSep $
1878 ["I","was","expecting","to","see","the",D.green "then","keyword","next."
1882 IfElse row col ->
1883 let
1884 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1885 region = toRegion row col
1886 in
1887 Report.Report "UNFINISHED IF" region [] $
1888 Code.toSnippet source surroundings (Just region)
1890 D.reflow $
1891 "I was expecting to see more of this `if` expression, but I got stuck here:"
1893 D.fillSep $
1894 ["I","was","expecting","to","see","the",D.green "else","keyword","next."
1898 IfElseBranchStart row col ->
1899 let
1900 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1901 region = toRegion row col
1902 in
1903 Report.Report "UNFINISHED IF" region [] $
1904 Code.toSnippet source surroundings (Just region)
1906 D.reflow $
1907 "I just saw the start of an `else` branch, but then I got stuck here:"
1909 D.reflow $
1910 "I was expecting to see an expression next. Maybe it is not filled in yet?"
1913 IfCondition expr row col ->
1914 toExprReport source (InNode NCond startRow startCol context) expr row col
1916 IfThenBranch expr row col ->
1917 toExprReport source (InNode NThen startRow startCol context) expr row col
1919 IfElseBranch expr row col ->
1920 toExprReport source (InNode NElse startRow startCol context) expr row col
1922 IfIndentCondition row col ->
1923 let
1924 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1925 region = toRegion row col
1926 in
1927 Report.Report "UNFINISHED IF" region [] $
1928 Code.toSnippet source surroundings (Just region)
1930 D.reflow $
1931 "I was expecting to see more of this `if` expression, but I got stuck here:"
1933 D.stack
1934 [ D.fillSep $
1935 ["I","was","expecting","to","see","an","expression","like",D.dullyellow "x < 0"
1936 ,"that","evaluates","to","True","or","False."
1938 , D.toSimpleNote $
1939 "I can be confused by indentation. Maybe something is not indented enough?"
1943 IfIndentThen row col ->
1944 let
1945 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1946 region = toRegion row col
1947 in
1948 Report.Report "UNFINISHED IF" region [] $
1949 Code.toSnippet source surroundings (Just region)
1951 D.reflow $
1952 "I was expecting to see more of this `if` expression, but I got stuck here:"
1954 D.stack
1955 [ D.fillSep $
1956 ["I","was","expecting","to","see","the",D.green "then","keyword","next."
1958 , D.toSimpleNote $
1959 "I can be confused by indentation. Maybe something is not indented enough?"
1963 IfIndentThenBranch row col ->
1964 let
1965 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1966 region = toRegion row col
1967 in
1968 Report.Report "UNFINISHED IF" region [] $
1969 Code.toSnippet source surroundings (Just region)
1971 D.reflow $
1972 "I got stuck after the start of this `then` branch:"
1974 D.stack
1975 [ D.reflow $
1976 "I was expecting to see an expression next. Maybe it is not filled in yet?"
1977 , D.toSimpleNote $
1978 "I can be confused by indentation, so if the `then` branch is already\
1979 \ present, it may not be indented enough for me to recognize it."
1983 IfIndentElseBranch row col ->
1984 let
1985 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1986 region = toRegion row col
1987 in
1988 Report.Report "UNFINISHED IF" region [] $
1989 Code.toSnippet source surroundings (Just region)
1991 D.reflow $
1992 "I got stuck after the start of this `else` branch:"
1994 D.stack
1995 [ D.reflow $
1996 "I was expecting to see an expression next. Maybe it is not filled in yet?"
1997 , D.toSimpleNote $
1998 "I can be confused by indentation, so if the `else` branch is already\
1999 \ present, it may not be indented enough for me to recognize it."
2003 IfIndentElse row col ->
2004 let
2005 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2006 region = toRegion row col
2007 in
2008 Report.Report "UNFINISHED IF" region [] $
2009 Code.toSnippet source surroundings (Just region)
2011 D.reflow $
2012 "I was expecting to see an `else` branch after this:"
2014 D.stack
2015 [ D.reflow $
2016 "I know what to do when the condition is `True`, but not when it is `False`."
2017 , D.fillSep
2018 ["Add","an",D.green "else","branch","to","handle","that","scenario!"]
2024-- RECORD
2027toRecordReport :: Code.Source -> Context -> Record -> Row -> Col -> Report.Report
2028toRecordReport source context record startRow startCol =
2029 case record of
2030 RecordOpen row col ->
2031 let
2032 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2033 region = toRegion row col
2034 in
2035 case Code.whatIsNext source row col of
2036 Code.Keyword keyword ->
2037 Report.Report "RESERVED WORD" region [] $
2038 Code.toSnippet source surroundings (Just region)
2040 D.reflow $
2041 "I just started parsing a record, but I got stuck on this field name:"
2043 D.reflow $
2044 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
2045 \ that is a reserved word. Try using a different name!"
2048 _ ->
2049 Report.Report "UNFINISHED RECORD" region [] $
2050 Code.toSnippet source surroundings (Just region)
2052 D.reflow $
2053 "I just started parsing a record, but I got stuck here:"
2055 D.fillSep
2056 ["Records","look","like",D.dullyellow "{ x = 3, y = 4 },"
2057 ,"so","I","was","expecting","to","see","a","field","name","next."
2061 RecordEnd row col ->
2062 let
2063 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2064 region = toRegion row col
2065 in
2066 Report.Report "UNFINISHED RECORD" region [] $
2067 Code.toSnippet source surroundings (Just region)
2069 D.reflow $
2070 "I am partway through parsing a record, but I got stuck here:"
2072 D.stack
2073 [ D.fillSep
2074 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
2075 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
2077 , D.toSimpleNote $
2078 "When I get stuck like this, it usually means that there is a missing parenthesis\
2079 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
2083 RecordField row col ->
2084 let
2085 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2086 region = toRegion row col
2087 in
2088 case Code.whatIsNext source row col of
2089 Code.Keyword keyword ->
2090 Report.Report "RESERVED WORD" region [] $
2091 Code.toSnippet source surroundings (Just region)
2093 D.reflow $
2094 "I am partway through parsing a record, but I got stuck on this field name:"
2096 D.reflow $
2097 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
2098 \ that is a reserved word. Try using a different name!"
2101 _ ->
2102 Report.Report "UNFINISHED RECORD" region [] $
2103 Code.toSnippet source surroundings (Just region)
2105 D.reflow $
2106 "I am partway through parsing a record, but I got stuck after that last comma:"
2108 addNoteForRecordError $
2109 D.reflow $
2110 "Trailing commas are not allowed in records, so I was expecting to see another\
2111 \ record field defined next. If you are done defining the record, the fix may\
2112 \ be to delete that last comma?"
2115 RecordEquals row col ->
2116 let
2117 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2118 region = toRegion row col
2119 in
2120 Report.Report "UNFINISHED RECORD" region [] $
2121 Code.toSnippet source surroundings (Just region)
2123 D.reflow $
2124 "I am partway through parsing a record, but I got stuck here:"
2126 addNoteForRecordError $
2127 D.fillSep $
2128 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
2129 ,"an","equals","sign","next.","So","try","putting","an",D.green "=","sign","here?"
2133 RecordExpr expr row col ->
2134 toExprReport source (InNode NRecord startRow startCol context) expr row col
2136 RecordSpace space row col ->
2137 toSpaceReport source space row col
2139 RecordIndentOpen row col ->
2140 let
2141 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2142 region = toRegion row col
2143 in
2144 Report.Report "UNFINISHED RECORD" region [] $
2145 Code.toSnippet source surroundings (Just region)
2147 D.reflow $
2148 "I just saw the opening curly brace of a record, but then I got stuck here:"
2150 addNoteForRecordIndentError $
2151 D.fillSep $
2152 ["I","am","expecting","a","record","like",D.dullyellow "{ x = 3, y = 4 }","here."
2153 ,"Try","defining","some","fields","of","your","own?"
2157 RecordIndentEnd row col ->
2158 let
2159 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2160 region = toRegion row col
2161 in
2162 Report.Report "UNFINISHED RECORD" region [] $
2163 Code.toSnippet source surroundings (Just region)
2165 D.reflow $
2166 "I was expecting to see a closing curly brace next:"
2168 addNoteForRecordIndentError $
2169 D.fillSep $
2170 ["Try","putting","an",D.green "}","and","see","if","that","helps?"
2174 RecordIndentField row col ->
2175 let
2176 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2177 region = toRegion row col
2178 in
2179 Report.Report "UNFINISHED RECORD" region [] $
2180 Code.toSnippet source surroundings (Just region)
2182 D.reflow $
2183 "I am partway through parsing a record, but I got stuck after that last comma:"
2185 addNoteForRecordError $
2186 D.reflow $
2187 "Trailing commas are not allowed in records, so the fix may be to\
2188 \ delete that last comma? Or maybe you were in the middle of defining\
2189 \ an additional field?"
2192 RecordIndentEquals row col ->
2193 let
2194 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2195 region = toRegion row col
2196 in
2197 Report.Report "UNFINISHED RECORD" region [] $
2198 Code.toSnippet source surroundings (Just region)
2200 D.reflow $
2201 "I am partway through parsing a record. I just saw a record\
2202 \ field, so I was expecting to see an equals sign next:"
2204 addNoteForRecordIndentError $
2205 D.fillSep $
2206 ["Try","putting","an",D.green "=","followed","by","an","expression?"
2210 RecordIndentExpr row col ->
2211 let
2212 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2213 region = toRegion row col
2214 in
2215 Report.Report "UNFINISHED RECORD" region [] $
2216 Code.toSnippet source surroundings (Just region)
2218 D.reflow $
2219 "I am partway through parsing a record, and I was expecting to run into an expression next:"
2221 addNoteForRecordIndentError $
2222 D.fillSep $
2223 ["Try","putting","something,","like"
2224 ,D.dullyellow "42","or",D.dullyellow"\"hello\"","for","now?"
2229addNoteForRecordError :: D.Doc -> D.Doc
2230addNoteForRecordError normalRecommendation =
2231 D.stack $
2232 normalRecommendation
2234 [ D.toSimpleNote
2235 "If you are trying to define a record across multiple lines, I recommend using this format:"
2236 , D.indent 4 $ D.vcat $
2237 [ "{ name = \"Alice\""
2238 , ", age = 42"
2239 , ", height = 1.75"
2240 , "}"
2242 , D.reflow $
2243 "Notice that nothing comes directly after a newline. Each line starts with some spaces. I\
2244 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
2245 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2249addNoteForRecordIndentError :: D.Doc -> D.Doc
2250addNoteForRecordIndentError normalRecommendation =
2251 D.stack $
2252 normalRecommendation
2254 [ D.toSimpleNote
2255 "I may be confused by indentation. For example, if you are trying to define\
2256 \ a record across multiple lines, I recommend using this format:"
2257 , D.indent 4 $ D.vcat $
2258 [ "[ \"Alice\""
2259 , ", \"Bob\""
2260 , ", \"Chuck\""
2261 , "]"
2263 , D.reflow $
2264 "Notice that nothing comes directly after a newline. Each line starts with some spaces. I\
2265 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
2266 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2271-- TUPLE
2274toTupleReport :: Code.Source -> Context -> Tuple -> Row -> Col -> Report.Report
2275toTupleReport source context tuple startRow startCol =
2276 case tuple of
2277 TupleExpr expr row col ->
2278 toExprReport source (InNode NParens startRow startCol context) expr row col
2280 TupleSpace space row col ->
2281 toSpaceReport source space row col
2283 TupleEnd row col ->
2284 let
2285 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2286 region = toRegion row col
2287 in
2288 Report.Report "UNFINISHED PARENTHESES" region [] $
2289 Code.toSnippet source surroundings (Just region)
2291 D.reflow $
2292 "I was expecting to see a closing parentheses next, but I got stuck here:"
2294 D.stack
2295 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
2296 , D.toSimpleNote $
2297 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
2298 \ unexpectedly. So there may be some earlier syntax trouble (like extra parenthesis\
2299 \ or missing brackets) that is confusing me."
2303 TupleOperatorClose row col ->
2304 let
2305 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2306 region = toRegion row col
2307 in
2308 Report.Report "UNFINISHED OPERATOR FUNCTION" region [] $
2309 Code.toSnippet source surroundings (Just region)
2311 D.reflow "I was expecting a closing parenthesis here:"
2313 D.stack
2314 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
2315 , D.toSimpleNote $
2316 "I think I am parsing an operator function right now, so I am expecting to see\
2317 \ something like (+) or (&&) where an operator is surrounded by parentheses with\
2318 \ no extra spaces."
2322 TupleOperatorReserved operator row col ->
2323 let
2324 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2325 region = toRegion row col
2326 in
2327 Report.Report "UNEXPECTED SYMBOL" region [] $
2328 Code.toSnippet source surroundings (Just region)
2330 D.reflow $
2331 "I ran into an unexpected symbol here:"
2333 D.fillSep $
2334 case operator of
2335 BadDot -> ["Maybe","you","wanted","a","record","accessor","like",D.dullyellow ".x","or",D.dullyellow ".name","instead?"]
2336 BadPipe -> ["Try",D.dullyellow "(||)","instead?","To","turn","boolean","OR","into","a","function?"]
2337 BadArrow -> ["Maybe","you","wanted",D.dullyellow "(>)","or",D.dullyellow "(>=)","instead?"]
2338 BadEquals -> ["Try",D.dullyellow "(==)","instead?","To","make","a","function","that","checks","equality?"]
2339 BadHasType -> ["Try",D.dullyellow "(::)","instead?","To","add","values","to","the","front","of","lists?"]
2342 TupleIndentExpr1 row col ->
2343 let
2344 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2345 region = toRegion row col
2346 in
2347 Report.Report "UNFINISHED PARENTHESES" region [] $
2348 Code.toSnippet source surroundings (Just region)
2350 D.reflow $
2351 "I just saw an open parenthesis, so I was expecting to see an expression next."
2353 D.stack
2354 [ D.fillSep $
2355 ["Something","like",D.dullyellow "(4 + 5)","or"
2356 ,D.dullyellow "(String.reverse \"desserts\")" <> "."
2357 ,"Anything","where","you","are","putting","parentheses","around","normal","expressions."
2359 , D.toSimpleNote $
2360 "I can get confused by indentation in cases like this, so\
2361 \ maybe you have an expression but it is not indented enough?"
2365 TupleIndentExprN row col ->
2366 let
2367 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2368 region = toRegion row col
2369 in
2370 Report.Report "UNFINISHED TUPLE" region [] $
2371 Code.toSnippet source surroundings (Just region)
2373 D.reflow $
2374 "I think I am in the middle of parsing a tuple. I just saw a comma, so I was expecting to see expression next."
2376 D.stack
2377 [ D.fillSep $
2378 ["A","tuple","looks","like",D.dullyellow "(3,4)","or"
2379 ,D.dullyellow "(\"Tom\",42)" <> ","
2380 ,"so","I","think","there","is","an","expression","missing","here?"
2382 , D.toSimpleNote $
2383 "I can get confused by indentation in cases like this, so\
2384 \ maybe you have an expression but it is not indented enough?"
2388 TupleIndentEnd row col ->
2389 let
2390 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2391 region = toRegion row col
2392 in
2393 Report.Report "UNFINISHED PARENTHESES" region [] $
2394 Code.toSnippet source surroundings (Just region)
2396 D.reflow $
2397 "I was expecting to see a closing parenthesis next:"
2399 D.stack
2400 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
2401 , D.toSimpleNote $
2402 "I can get confused by indentation in cases like this, so\
2403 \ maybe you have a closing parenthesis but it is not indented enough?"
2408toListReport :: Code.Source -> Context -> List -> Row -> Col -> Report.Report
2409toListReport source context list startRow startCol =
2410 case list of
2411 ListSpace space row col ->
2412 toSpaceReport source space row col
2414 ListOpen row col ->
2415 let
2416 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2417 region = toRegion row col
2418 in
2419 Report.Report "UNFINISHED LIST" region [] $
2420 Code.toSnippet source surroundings (Just region)
2422 D.reflow $
2423 "I am partway through parsing a list, but I got stuck here:"
2425 D.stack
2426 [ D.fillSep
2427 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
2428 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
2430 , D.toSimpleNote $
2431 "When I get stuck like this, it usually means that there is a missing parenthesis\
2432 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
2436 ListExpr expr row col ->
2437 case expr of
2438 Start r c ->
2439 let
2440 surroundings = A.Region (A.Position startRow startCol) (A.Position r c)
2441 region = toRegion r c
2442 in
2443 Report.Report "UNFINISHED LIST" region [] $
2444 Code.toSnippet source surroundings (Just region)
2446 D.reflow $
2447 "I was expecting to see another list entry after that last comma:"
2449 D.stack
2450 [ D.reflow $
2451 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
2452 , D.toSimpleNote
2453 "I recommend using the following format for lists that span multiple lines:"
2454 , D.indent 4 $ D.vcat $
2455 [ "[ \"Alice\""
2456 , ", \"Bob\""
2457 , ", \"Chuck\""
2458 , "]"
2460 , D.reflow $
2461 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2462 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2463 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2467 _ ->
2468 toExprReport source (InNode NList startRow startCol context) expr row col
2470 ListEnd row col ->
2471 let
2472 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2473 region = toRegion row col
2474 in
2475 Report.Report "UNFINISHED LIST" region [] $
2476 Code.toSnippet source surroundings (Just region)
2478 D.reflow $
2479 "I am partway through parsing a list, but I got stuck here:"
2481 D.stack
2482 [ D.fillSep
2483 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
2484 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
2486 , D.toSimpleNote $
2487 "When I get stuck like this, it usually means that there is a missing parenthesis\
2488 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
2492 ListIndentOpen row col ->
2493 let
2494 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2495 region = toRegion row col
2496 in
2497 Report.Report "UNFINISHED LIST" region [] $
2498 Code.toSnippet source surroundings (Just region)
2500 D.reflow $
2501 "I cannot find the end of this list:"
2503 D.stack
2504 [ D.fillSep $
2505 ["You","could","change","it","to","something","like"
2506 ,D.dullyellow "[3,4,5]"
2507 ,"or","even","just"
2508 ,D.dullyellow "[]" <> "."
2509 ,"Anything","where","there","is","an","open","and","close","square","brace,"
2510 ,"and","where","the","elements","of","the","list","are","separated","by","commas."
2512 , D.toSimpleNote
2513 "I may be confused by indentation. For example, if you are trying to define\
2514 \ a list across multiple lines, I recommend using this format:"
2515 , D.indent 4 $ D.vcat $
2516 [ "[ \"Alice\""
2517 , ", \"Bob\""
2518 , ", \"Chuck\""
2519 , "]"
2521 , D.reflow $
2522 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2523 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2524 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2528 ListIndentEnd row col ->
2529 let
2530 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2531 region = toRegion row col
2532 in
2533 Report.Report "UNFINISHED LIST" region [] $
2534 Code.toSnippet source surroundings (Just region)
2536 D.reflow $
2537 "I cannot find the end of this list:"
2539 D.stack
2540 [ D.fillSep $
2541 ["You","can","just","add","a","closing",D.dullyellow "]"
2542 ,"right","here,","and","I","will","be","all","set!"
2544 , D.toSimpleNote
2545 "I may be confused by indentation. For example, if you are trying to define\
2546 \ a list across multiple lines, I recommend using this format:"
2547 , D.indent 4 $ D.vcat $
2548 [ "[ \"Alice\""
2549 , ", \"Bob\""
2550 , ", \"Chuck\""
2551 , "]"
2553 , D.reflow $
2554 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2555 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2556 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2560 ListIndentExpr row col ->
2561 let
2562 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2563 region = toRegion row col
2564 in
2565 Report.Report "UNFINISHED LIST" region [] $
2566 Code.toSnippet source surroundings (Just region)
2568 D.reflow $
2569 "I was expecting to see another list entry after this comma:"
2571 D.stack
2572 [ D.reflow $
2573 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
2574 , D.toSimpleNote
2575 "I recommend using the following format for lists that span multiple lines:"
2576 , D.indent 4 $ D.vcat $
2577 [ "[ \"Alice\""
2578 , ", \"Bob\""
2579 , ", \"Chuck\""
2580 , "]"
2582 , D.reflow $
2583 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2584 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2585 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2590toFuncReport :: Code.Source -> Context -> Func -> Row -> Col -> Report.Report
2591toFuncReport source context func startRow startCol =
2592 case func of
2593 FuncSpace space row col ->
2594 toSpaceReport source space row col
2596 FuncArg pattern row col ->
2597 error "TODO FuncArg" pattern row col
2599 FuncBody expr row col ->
2600 toExprReport source (InNode NFunc startRow startCol context) expr row col
2602 FuncArrow row col ->
2603 let
2604 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2605 region = toRegion row col
2606 in
2607 case Code.whatIsNext source row col of
2608 Code.Keyword keyword ->
2609 Report.Report "RESERVED WORD" region [] $
2610 Code.toSnippet source surroundings (Just region)
2612 D.reflow $
2613 "I was parsing an anonymous function, but I got stuck here:"
2615 D.reflow $
2616 "It looks like you are trying to use `" ++ keyword ++ "` as an argument, but\
2617 \ it is a reserved word in this language. Try using a different argument name!"
2620 _ ->
2621 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
2622 Code.toSnippet source surroundings (Just region)
2624 D.reflow $
2625 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
2627 D.fillSep $
2628 ["The","syntax","for","anonymous","functions","is"
2629 ,D.dullyellow "(\\x -> x + 1)"
2630 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
2634 FuncIndentArg row col ->
2635 let
2636 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2637 region = toRegion row col
2638 in
2639 Report.Report "MISSING ARGUMENT" region [] $
2640 Code.toSnippet source surroundings (Just region)
2642 D.reflow $
2643 "I just saw the beginning of an anonymous function, so I was expecting to see an argument next:"
2645 D.stack
2646 [ D.fillSep
2647 ["Something","like",D.dullyellow"x","or",D.dullyellow "name" <> "."
2648 ,"Anything","that","starts","with","a","lower","case","letter!"
2650 , D.toSimpleNote $
2651 "The syntax for anonymous functions is (\\x -> x + 1) where the backslash\
2652 \ is meant to look a bit like a lambda if you squint. This visual pun seemed\
2653 \ like a better idea at the time!"
2657 FuncIndentArrow row col ->
2658 let
2659 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2660 region = toRegion row col
2661 in
2662 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
2663 Code.toSnippet source surroundings (Just region)
2665 D.reflow $
2666 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
2668 D.stack
2669 [ D.fillSep $
2670 ["The","syntax","for","anonymous","functions","is"
2671 ,D.dullyellow "(\\x -> x + 1)"
2672 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
2674 , D.toSimpleNote $
2675 "It is possible that I am confused about indetation! I generally recommend\
2676 \ switching to named functions if the definition cannot fit inline nicely, so\
2677 \ either (1) try to fit the whole anonymous function on one line or (2) break\
2678 \ the whole thing out into a named function. Things tend to be clearer that way!"
2682 FuncIndentBody row col ->
2683 let
2684 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2685 region = toRegion row col
2686 in
2687 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
2688 Code.toSnippet source surroundings (Just region)
2690 D.reflow $
2691 "I was expecting to see the body of your anonymous function next:"
2693 D.stack
2694 [ D.fillSep $
2695 ["The","syntax","for","anonymous","functions","is"
2696 ,D.dullyellow "(\\x -> x + 1)"
2697 ,"so","I","am","missing","all","the","stuff","after","the","arrow!"
2699 , D.toSimpleNote $
2700 "It is possible that I am confused about indetation! I generally recommend\
2701 \ switching to named functions if the definition cannot fit inline nicely, so\
2702 \ either (1) try to fit the whole anonymous function on one line or (2) break\
2703 \ the whole thing out into a named function. Things tend to be clearer that way!"
2711 case err of
2712 CommentOnNothing region ->
2713 Report.Report "STRAY COMMENT" region [] $
2714 Code.toSnippet source region Nothing
2716 "This documentation comment is not followed by anything."
2718 D.reflow $
2719 "All documentation comments need to be right above the declaration they\
2720 \ describe. Maybe some code got deleted or commented out by accident? Or\
2721 \ maybe this comment is here by accident?"
2724 ParseError row col context expectation ->
2725 let
2726 pos = A.Position row col
2727 region = A.Region pos pos
2728 in
2729 case expectation of
2731 DocComment ->
2732 Report.Report "EXPECTING DOC COMMENT" region [] $
2733 Code.toSnippet source region Nothing
2735 D.reflow $
2736 "I was expecting a doc comment here:"
2738 D.reflowLink
2739 "Check out" "TODO" "for examples of doc comments."
2742 -- Parse.Number
2744 Wildcard ->
2745 Report.Report "EXPECTING A WILDCARD" region [] $
2746 Code.toSnippet source region Nothing
2748 D.reflow $
2749 "I was expecting a _ here:"
2751 D.reflow $
2752 "An underscore indicates that “I do not care about this value” and is\
2753 \ called a wildcard pattern because it will match with any type of values."
2756 WildcardNotVar startCol endCol ->
2757 let
2758 badRegion =
2759 A.Region (A.Position row startCol) (A.Position row endCol)
2760 in
2761 Report.Report "INVALID PATTERN" badRegion [] $
2762 Code.toSnippet source badRegion Nothing
2764 D.reflow $
2765 "I was expecting to see an underscore without any additional characters:"
2767 D.reflow $
2768 "There are two options. Either (1) remove the extra characters and ignore the\
2769 \ value or (2) remove the starting underscore to give the value a normal name."
2772 -- Parse.Pattern
2774 FloatInPattern ->
2775 Report.Report "INVALID PATTERN" region [] $
2776 Code.toSnippet source region Nothing
2778 D.reflow $
2779 "I cannot pattern match with floating point numbers:"
2781 D.reflow $
2782 "Equality on floats can be unreliable, so you usually want to check that they\
2783 \ are nearby with some sort of (abs (actual - expected) < 0.001) check."