on 4520afe help sign in
3808 lines 132 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 Word16 Row Col
372 | PAlias Row Col
373 | PWildcardNotVar Name.Name 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 | PTupleIndentEnd Row Col
398 | PTupleIndentExpr1 Row Col
399 | PTupleIndentExprN 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 | TTupleIndentType1 Row Col
453 | TTupleIndentTypeN 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.fillSep $
512 [ D.cyan "module", D.fromName name, D.cyan "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.cyan "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.cyan "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))
960toKeywordRegion :: Row -> Col -> [Char.Char] -> A.Region
961toKeywordRegion row col keyword =
962 A.Region
963 (A.Position row col)
964 (A.Position row (col + fromIntegral (length keyword)))
967toDeclarationsReport :: Code.Source -> Decl -> Report.Report
968toDeclarationsReport source decl =
969 case decl of
970 DeclStart row col ->
971 error "TODO DeclStart" row col
973 DeclSpace space row col ->
974 toSpaceReport source space row col
976 Port port row col ->
977 error "TODO Port" port row col
979 DeclType declType row col ->
980 error "TODO DeclType" declType row col
982 DeclDef name declDef row col ->
983 toDeclDefReport source name declDef row col
985 DeclFreshLineStart row col ->
986 error "TODO DeclFreshLineStart" row col
988 DeclFreshLineAfterDocComment row col ->
989 error "TODO DeclFreshLineAfterDocComment" row col
992toDeclDefReport :: Code.Source -> Name.Name -> DeclDef -> Row -> Col -> Report.Report
993toDeclDefReport source name declDef startRow startCol =
994 case declDef of
995 DeclDefSpace space row col ->
996 toSpaceReport source space row col
998 DeclDefEquals row col ->
999 case Code.whatIsNext source row col of
1000 Code.Keyword keyword ->
1001 let
1002 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1003 region = toKeywordRegion row col keyword
1004 in
1005 Report.Report "RESERVED WORD" region [] $
1006 Code.toSnippet source surroundings (Just region)
1008 D.reflow $
1009 "It looks like you are trying to use `" ++ keyword ++ "` as an argument:"
1011 D.reflow $
1012 "This is a reserved word! Try using some other name?"
1015 Code.Operator op ->
1016 let
1017 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1018 region = toKeywordRegion row col op
1019 in
1020 Report.Report "UNEXPECTED SYMBOL" region [] $
1021 Code.toSnippet source surroundings (Just region)
1023 D.reflow $
1024 "I was not expecting to see this symbol here:"
1026 D.stack
1027 [ D.reflow $
1028 "I am not sure what is going wrong exactly, so here is a valid\
1029 \ definition (with an optional type annotation) for reference:"
1030 , D.vcat
1031 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
1032 , D.fillSep [D.green "add","x","y","="]
1033 , D.fillSep [" ","x","+","y"]
1035 , D.reflow $
1036 "Try to use that format with your `" ++ Name.toChars name ++ "` definition!"
1040 _ ->
1041 let
1042 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1043 region = toRegion row col
1044 in
1045 Report.Report "PROBLEM IN DEFINITION" region [] $
1046 Code.toSnippet source surroundings (Just region)
1048 D.reflow $
1049 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
1051 D.stack
1052 [ D.reflow $
1053 "I am not sure what is going wrong exactly, so here is a valid\
1054 \ definition (with an optional type annotation) for reference:"
1055 , D.vcat
1056 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
1057 , D.fillSep [D.green "add","x","y","="]
1058 , D.fillSep [" ","x","+","y"]
1060 , D.reflow $
1061 "Try to use that format!"
1065 DeclDefType tipe row col ->
1066 error "TODO DeclDefType" toTypeReport tipe row col
1068 DeclDefArg pattern row col ->
1069 toPatternReport source PArg pattern row col
1071 DeclDefBody expr row col ->
1072 toExprReport source (InDef name startRow startCol) expr row col
1074 DeclDefNameRepeat row col ->
1075 let
1076 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1077 region = toRegion row col
1078 in
1079 Report.Report "EXPECTING DEFINITION" region [] $
1080 Code.toSnippet source surroundings (Just region)
1082 D.reflow $
1083 "I just saw the type annotation for `" ++ Name.toChars name
1084 ++ "` so I was expecting to see its definition here:"
1086 D.reflow $
1087 "Type annotations always appear directly above the relevant\
1088 \ definition, without anything else (even doc comments) in between."
1091 DeclDefNameMatch defName row col ->
1092 let
1093 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1094 region = toRegion row col
1095 in
1096 Report.Report "NAME MISMATCH" region [] $
1097 Code.toSnippet source surroundings (Just region)
1099 D.reflow $
1100 "I just saw a type annotation for `" ++ Name.toChars name ++ "`, but it is followed by a definition for `" ++ Name.toChars defName ++ "`:"
1102 D.stack
1103 [ D.reflow $
1104 "These names do not match! Is there a typo?"
1105 , D.indent 4 $ D.fillSep $
1106 [D.dullyellow (D.fromName defName),"->",D.green (D.fromName name)]
1110 DeclDefIndentType row col ->
1111 error "TODO DeclDefIndentType" row col
1113 DeclDefIndentEquals row col ->
1114 error "TODO DeclDefIndentEquals" row col
1116 DeclDefIndentBody row col ->
1117 error "TODO DeclDefIndentBody" row col
1119 DeclDefFreshLineAfterType row col ->
1120 error "TODO DeclDefFreshLineAfterType" row col
1124-- CONTEXT
1127data Context
1128 = InNode Node Row Col Context
1129 | InDef Name.Name Row Col
1132data Node
1133 = NRecord
1134 | NParens
1135 | NList
1136 | NFunc
1137 | NCond
1138 | NThen
1139 | NElse
1140 | NCase
1141 | NBranch
1142 deriving (Eq)
1145getDefName :: Context -> Name.Name
1146getDefName context =
1147 case context of
1148 InDef name _ _ -> name
1149 InNode _ _ _ c -> getDefName c
1152isWithin :: Node -> Context -> Bool
1153isWithin desiredNode context =
1154 case context of
1155 InDef _ _ _ -> False
1156 InNode actualNode _ _ _ -> desiredNode == actualNode
1160-- EXPR REPORTS
1163toExprReport :: Code.Source -> Context -> Expr -> Row -> Col -> Report.Report
1164toExprReport source context expr startRow startCol =
1165 case expr of
1166 Let let_ row col ->
1167 toLetReport source context let_ row col
1169 Case case_ row col ->
1170 toCaseReport source context case_ row col
1172 If if_ row col ->
1173 toIfReport source context if_ row col
1175 List list row col ->
1176 toListReport source context list row col
1178 Record record row col ->
1179 toRecordReport source context record row col
1181 Tuple tuple row col ->
1182 toTupleReport source context tuple row col
1184 Func func row col ->
1185 toFuncReport source context func row col
1187 Dot row col ->
1188 let region = toRegion row col in
1189 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
1190 Code.toSnippet source region Nothing
1192 D.reflow $
1193 "I was expecting to see a record accessor here:"
1195 D.fillSep
1196 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
1197 ,"that","accesses","a","value","from","a","record."
1201 Access row col ->
1202 let region = toRegion row col in
1203 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
1204 Code.toSnippet source region Nothing
1206 D.reflow $
1207 "I am trying to parse a record accessor here:"
1209 D.stack
1211 D.fillSep
1212 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
1213 ,"that","accesses","a","value","from","a","record."
1216 D.toSimpleNote $
1217 "Record field names must start with a lower case letter!"
1221 OperatorRight op row col ->
1222 let region = toRegion row col in
1223 Report.Report "MISSING EXPRESSION" region [] $
1224 Code.toSnippet source region Nothing
1226 D.reflow $
1227 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
1229 D.stack
1230 [ D.fillSep $
1231 ["You","can","just","put","anything","for","now,","like"
1232 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1233 ,"Once","there","is","something","there,","I","can","probably"
1234 ,"give","a","more","specific","hint!"
1236 , D.toSimpleNote $
1237 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
1238 \ Or if I run into operators in unexpected spots. Point is, there are a\
1239 \ couple ways I can get confused and give sort of weird advice!"
1243 OperatorReserved operator row col ->
1244 toOperatorReport source context operator row col
1246 Start row col ->
1247 let
1248 (contextRow, contextCol, aThing) =
1249 case context of
1250 InDef name r c -> (r, c, "the `" ++ Name.toChars name ++ "` definition")
1251 InNode NRecord r c _ -> (r, c, "a record")
1252 InNode NParens r c _ -> (r, c, "some parentheses")
1253 InNode NList r c _ -> (r, c, "a list")
1254 InNode NFunc r c _ -> (r, c, "an anonymous function")
1255 InNode NCond r c _ -> (r, c, "an `if` expression")
1256 InNode NThen r c _ -> (r, c, "an `if` expression")
1257 InNode NElse r c _ -> (r, c, "an `if` expression")
1258 InNode NCase r c _ -> (r, c, "a `case` expression")
1259 InNode NBranch r c _ -> (r, c, "a `case` expression")
1260 -- TODO check if this is actually the best way to get error messages here
1262 surroundings = A.Region (A.Position contextRow contextCol) (A.Position row col)
1263 region = toRegion row col
1264 in
1265 Report.Report "MISSING EXPRESSION" region [] $
1266 Code.toSnippet source surroundings (Just region)
1268 D.reflow $
1269 "I am partway through parsing " ++ aThing ++ ", but I got stuck here:"
1271 D.stack
1272 [ D.fillSep $
1273 ["I","was","expecting","to","see","an","expression","like"
1274 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1275 ,"Once","there","is","something","there,","I","can","probably"
1276 ,"give","a","more","specific","hint!"
1278 , D.toSimpleNote $
1279 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
1280 \ Or if I run into operators in unexpected spots. Point is, there are a\
1281 \ couple ways I can get confused and give sort of weird advice!"
1285 Char char row col ->
1286 toCharReport source char row col
1288 String string row col ->
1289 toStringReport source string row col
1291 Number number row col ->
1292 toNumberReport source number row col
1294 Space space row col ->
1295 toSpaceReport source space row col
1297 EndlessShader row col ->
1298 let
1299 region = toWiderRegion row col 6
1300 in
1301 Report.Report "ENDLESS SHADER" region [] $
1302 Code.toSnippet source region Nothing
1304 D.reflow "I cannot find the end of this shader:"
1306 D.reflow "Add a |] somewhere after this to end the shader."
1309 ShaderProblem problem row col ->
1310 let
1311 region = toRegion row col
1312 in
1313 Report.Report "SHADER PROBLEM" region [] $
1314 Code.toSnippet source region Nothing
1316 D.reflow $
1317 "I ran into a problem while parsing this GLSL block."
1319 D.stack
1320 [ D.reflow $
1321 "I use a 3rd party GLSL parser for now, and I did my best to extract their error message:"
1322 , D.indent 4 $ D.vcat $
1323 map D.fromChars (filter (/="") (lines problem))
1327 IndentOperatorRight op row col ->
1328 let
1329 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1330 region = toRegion row col
1331 in
1332 Report.Report "MISSING EXPRESSION" region [] $
1333 Code.toSnippet source surroundings (Just region)
1335 D.reflow $
1336 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
1338 D.stack
1340 D.fillSep $
1341 ["You","can","just","put","anything","for","now,","like"
1342 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1343 ,"Once","there","is","something","there,","I","can","probably"
1344 ,"give","a","more","specific","hint!"
1347 D.toSimpleNote $
1348 "I may be getting confused by your indentation? The easiest way to make sure\
1349 \ this is not an indentation problem is to put the expression on the right of\
1350 \ the " ++ Name.toChars op ++ " operator on the same line."
1354 IndentMoreExpr _ _ ->
1355 error "TODO IndentMoreExpr"
1359-- CHAR
1362toCharReport :: Code.Source -> Char -> Row -> Col -> Report.Report
1363toCharReport source char row col =
1364 case char of
1365 CharEndless ->
1366 let
1367 region = toRegion row col
1368 in
1369 Report.Report "MISSING SINGLE QUOTE" region [] $
1370 Code.toSnippet source region Nothing
1372 D.reflow $
1373 "I thought I was parsing a character, but I got to the end of\
1374 \ the line without seeing the closing single quote:"
1376 D.reflow $
1377 "Add a closing single quote here!"
1380 CharEscape escape ->
1381 toEscapeReport source escape row col
1383 CharNotString width ->
1384 let
1385 region = toWiderRegion row col width
1386 in
1387 Report.Report "NEEDS DOUBLE QUOTES" region [] $
1388 Code.toSnippet source region Nothing
1390 "The following string uses single quotes:"
1392 D.stack
1393 [ "Please switch to double quotes instead:"
1394 , D.indent 4 $
1395 D.dullyellow "'this'" <> " => " <> D.green "\"this\""
1396 , D.toSimpleNote $
1397 "Elm uses double quotes for strings like \"hello\", whereas it uses single\
1398 \ quotes for individual characters like 'a' and 'ø'. This distinction helps with\
1399 \ code like (String.any (\\c -> c == 'X') \"90210\") where you are inspecting\
1400 \ individual characters."
1406-- STRING
1409toStringReport :: Code.Source -> String -> Row -> Col -> Report.Report
1410toStringReport source string row col =
1411 case string of
1412 StringEndless_Single ->
1413 let
1414 region = toRegion row col
1415 in
1416 Report.Report "ENDLESS STRING" region [] $
1417 Code.toSnippet source region Nothing
1419 D.reflow $
1420 "I got to the end of the line without seeing the closing double quote:"
1422 D.stack
1423 [ D.fillSep $
1424 ["Strings","look","like",D.green "\"this\"","with","double"
1425 ,"quotes","on","each","end.","Is","the","closing","double"
1426 ,"quote","missing","in","your","code?"
1428 , D.link "Note" "Read" "TODO" "if you want a string that spans multiple lines."
1432 StringEndless_Multi ->
1433 let
1434 region = toWiderRegion row col 3
1435 in
1436 Report.Report "ENDLESS STRING" region [] $
1437 Code.toSnippet source region Nothing
1439 D.reflow $
1440 "I cannot find the end of this multi-line string:"
1442 D.stack
1443 [ D.reflow "Add a \"\"\" somewhere after this to end the string."
1444 , D.link "Hint" "Read" "TODO" "for more information on strings and multi-line strings."
1448 StringEscape escape ->
1449 toEscapeReport source escape row col
1453-- ESCAPES
1456toEscapeReport :: Code.Source -> Escape -> Row -> Col -> Report.Report
1457toEscapeReport source escape row col =
1458 case escape of
1459 EscapeUnknown ->
1460 let
1461 region = toWiderRegion row col 2
1462 in
1463 Report.Report "UNKNOWN ESCAPE" region [] $
1464 Code.toSnippet source region Nothing
1466 D.reflow $
1467 "Backslashes always start escaped characters, but I do not recognize this one:"
1469 D.stack
1470 [ D.reflow $
1471 "Valid escape characters include:"
1472 , D.dullyellow $ D.indent 4 $ D.vcat $
1473 [ "\\n"
1474 , "\\r"
1475 , "\\t"
1476 , "\\\""
1477 , "\\\'"
1478 , "\\\\"
1479 , "\\u{003D}"
1481 , D.reflow $
1482 "Do you want one of those instead? Maybe you need \\\\ to escape a backslash?"
1483 , D.toSimpleNote $
1484 "The last style lets encode ANY character by its Unicode code\
1485 \ point. That means \\u{0009} and \\t are the same. You can use\
1486 \ that style for anything not covered by the other six escapes!"
1490 BadUnicodeFormat width ->
1491 let
1492 region = toWiderRegion row col width
1493 in
1494 Report.Report "BAD UNICODE ESCAPE" region [] $
1495 Code.toSnippet source region Nothing
1497 D.reflow $
1498 "I ran into an invalid Unicode escape:"
1500 D.stack
1501 [ D.reflow $
1502 "Here are some examples of valid Unicode escapes:"
1503 , D.dullyellow $ D.indent 4 $ D.vcat $
1504 [ "\\u{0041}"
1505 , "\\u{03BB}"
1506 , "\\u{6728}"
1507 , "\\u{1F60A}"
1509 , D.reflow $
1510 "Notice that the code point is always surrounded by curly braces.\
1511 \ Maybe you are missing the opening or closing curly brace?"
1514 BadUnicodeCode width ->
1515 let
1516 region = toWiderRegion row col width
1517 in
1518 Report.Report "BAD UNICODE ESCAPE" region [] $
1519 Code.toSnippet source region Nothing
1521 D.reflow $
1522 "This is not a valid code point:"
1524 D.reflow $
1525 "The valid code points are between 0 and 10FFFF inclusive."
1528 BadUnicodeLength width numDigits badCode ->
1529 let
1530 region = toWiderRegion row col width
1531 in
1532 Report.Report "BAD UNICODE ESCAPE" region [] $
1533 Code.toSnippet source region Nothing $
1534 if numDigits < 4 then
1536 D.reflow $
1537 "Every code point needs at least four digits:"
1539 let
1540 goodCode = replicate (4 - numDigits) '0' ++ map Char.toUpper (showHex badCode "")
1541 suggestion = "\\u{" <> D.fromChars goodCode <> "}"
1542 in
1543 D.fillSep ["Try",D.green suggestion,"instead?"]
1546 else
1548 D.reflow $
1549 "This code point has too many digits:"
1551 D.fillSep $
1552 ["Valid","code","points","are","between"
1553 ,D.green "\\u{0000}","and",D.green "\\u{10FFFF}" <> ","
1554 ,"so","try","trimming","any","leading","zeros","until"
1555 ,"you","have","between","four","and","six","digits."
1561-- NUMBERS
1564toNumberReport :: Code.Source -> Number -> Row -> Col -> Report.Report
1565toNumberReport source number row col =
1566 let
1567 region = toRegion row col
1568 in
1569 case number of
1570 NumberEnd ->
1571 Report.Report "WEIRD NUMBER" region [] $
1572 Code.toSnippet source region Nothing
1574 D.reflow $
1575 "I thought I was reading a number, but I ran into some weird stuff here:"
1577 D.stack
1578 [ D.reflow $
1579 "I recognize numbers in the following formats:"
1580 , D.indent 4 $ D.vcat [ "42", "3.14", "6.022e23", "0x002B" ]
1581 , D.reflow $
1582 "So is there a way to write it like one of those?"
1586 NumberDot int ->
1587 Report.Report "WEIRD NUMBER" region [] $
1588 Code.toSnippet source region Nothing
1590 D.reflow $
1591 "Numbers cannot end with a dot like this:"
1593 D.fillSep
1594 ["Switching","to",D.green (D.fromChars (show int))
1595 ,"or",D.green (D.fromChars (show int ++ ".0"))
1596 ,"will","work","though!"
1600 NumberHexDigit ->
1601 Report.Report "WEIRD HEXIDECIMAL" region [] $
1602 Code.toSnippet source region Nothing
1604 D.reflow $
1605 "I thought I was reading a hexidecimal number until I got here:"
1607 D.stack
1608 [ D.reflow $
1609 "Valid hexidecimal digits include 0123456789abcdefABCDEF, so I can\
1610 \ only recognize things like this:"
1611 , D.indent 4 $ D.vcat [ "0x2B", "0x002B", "0x00ffb3" ]
1615 NumberNoLeadingZero ->
1616 Report.Report "LEADING ZEROS" region [] $
1617 Code.toSnippet source region Nothing
1619 D.reflow $
1620 "I do not accept numbers with leading zeros:"
1622 D.stack
1623 [ D.reflow $
1624 "Just delete the leading zeros and it should work!"
1625 , D.toSimpleNote $
1626 "Some languages let you to specify octal numbers by adding a leading zero.\
1627 \ So in C, writing 0111 is the same as writing 73. Some people are used to\
1628 \ that, but others probably want it to equal 111. Either path is going to\
1629 \ surprise people from certain backgrounds, so Elm tries to avoid this whole\
1630 \ situation."
1636-- OPERATORS
1639toOperatorReport :: Code.Source -> Context -> BadOperator -> Row -> Col -> Report.Report
1640toOperatorReport source context operator row col =
1641 case operator of
1642 BadDot ->
1643 let
1644 region = toRegion row col
1645 in
1646 Report.Report "UNEXPECTED SYMBOL" region [] $
1647 Code.toSnippet source region Nothing
1649 "I was not expecting this dot:"
1651 D.reflow $
1652 "Dots are for record access and decimal points, so\
1653 \ they cannot float around on their own. Maybe\
1654 \ there is some extra whitespace?"
1657 BadPipe ->
1658 let
1659 region = toRegion row col
1660 in
1661 Report.Report "UNEXPECTED SYMBOL" region [] $
1662 Code.toSnippet source region Nothing
1664 D.reflow $
1665 "I was not expecting this vertical bar:"
1667 D.reflow $
1668 "Vertical bars should only appear in custom type declarations. Maybe you want || instead?"
1671 BadArrow ->
1672 let
1673 region = toWiderRegion row col 2
1674 in
1675 Report.Report "UNEXPECTED ARROW" region [] $
1676 Code.toSnippet source region Nothing $
1677 if isWithin NBranch context then
1679 D.reflow $
1680 "I was not expecting to see an arrow here:"
1682 D.stack
1684 D.reflow $
1685 "I think I am parsing a `case` expression right now, so it makes sense to\
1686 \ see arrows around here. This one is confusing me though!"
1688 D.toSimpleHint $
1689 "I may be getting confused by the indentation. Every pattern in a `case` must be\
1690 \ exactly aligned (with exactly the same amount of indentation) so maybe this arrow\
1691 \ appears after the next `case` pattern (correctly!) but the pattern itself is\
1692 \ indented too far?"
1696 else
1698 D.reflow $
1699 "I was not expecting an arrow here:"
1701 D.reflow $
1702 "Arrows should only appear in `case` expressions and anonymous functions. Maybe\
1703 \ you want > or >= instead?"
1706 BadEquals ->
1707 let
1708 region = toRegion row col
1709 name = getDefName context
1710 in
1711 Report.Report "UNEXPECTED EQUALS" region [] $
1712 Code.toSnippet source region Nothing
1714 D.reflow $
1715 "I was not expecting to see this equals sign:"
1717 D.stack
1719 D.reflow "Maybe you want == instead? To check if two values are equal?"
1721 D.toSimpleNote $
1722 if isWithin NRecord context then
1723 "Records look like { x = 3, y = 4 } with the equals sign right\
1724 \ after the field name. So maybe you forgot a comma?"
1725 else
1726 "I may be getting confused by your indentation. Is this supposed to be part of\
1727 \ a definition AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
1728 \ the problem may be a bit before the equals sign. I need all definitions to\
1729 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
1730 \ this new definition is indented a bit too much."
1734 BadHasType ->
1735 let
1736 region = toRegion row col
1737 name = getDefName context
1738 in
1739 Report.Report "UNEXPECTED SYMBOL" region [] $
1740 Code.toSnippet source region Nothing $
1742 D.reflow $
1743 "I was not expecting to run into the \"has type\" symbol here:"
1745 D.stack
1747 D.fillSep
1748 ["Maybe","you","want",D.green "::","instead?"
1749 ,"To","put","something","on","the","front","of","a","list?"
1751 , D.toSimpleNote $
1752 "The single colon is reserved for type annotations and record types, but I think\
1753 \ I am parsing the definition of `" ++ Name.toChars name ++ "` right now."
1755 D.toSimpleNote $
1756 "I may be getting confused by your indentation. Is this supposed to be part of\
1757 \ a type annotation AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
1758 \ the problem may be a bit before the \"has type\" symbol. I need all definitions to\
1759 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
1760 \ this new definition is indented a bit too much."
1766-- CASE
1769toLetReport :: Code.Source -> Context -> Let -> Row -> Col -> Report.Report
1770toLetReport source context let_ startRow startCol =
1771 case let_ of
1772 LetSpace space row col ->
1773 toSpaceReport source space row col
1775 LetIn row col ->
1776 let
1777 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1778 region = toRegion row col
1779 in
1780 Report.Report "LET PROBLEM" region [] $
1781 Code.toSnippet source surroundings (Just region)
1783 D.reflow $
1784 "I was partway through parsing a `let` expression, but I got stuck here:"
1786 D.stack
1787 [ D.fillSep $
1788 ["Based","on","the","indentation,","I","was","expecting","to","see","the",D.cyan "in"
1789 ,"keyword","next.","Is","there","a","typo?"
1791 , D.toSimpleNote $
1792 "This can also happen if you are trying to define another value within the `let` but\
1793 \ it is not indented enough. Make sure each definition has exactly the same amount of\
1794 \ spaces before it. They should line up exactly!"
1798 LetDefAlignment _ row col ->
1799 let
1800 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1801 region = toRegion row col
1802 in
1803 Report.Report "LET PROBLEM" region [] $
1804 Code.toSnippet source surroundings (Just region)
1806 D.reflow $
1807 "I was partway through parsing a `let` expression, but I got stuck here:"
1809 D.stack
1810 [ D.fillSep $
1811 ["Based","on","the","indentation,","I","was","expecting","to","see","the",D.cyan "in"
1812 ,"keyword","next.","Is","there","a","typo?"
1814 , D.toSimpleNote $
1815 "This can also happen if you are trying to define another value within the `let` but\
1816 \ it is not indented enough. Make sure each definition has exactly the same amount of\
1817 \ spaces before it. The should line up exactly!"
1821 LetDefName row col ->
1822 case Code.whatIsNext source row col of
1823 Code.Keyword keyword ->
1824 let
1825 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1826 region = toKeywordRegion row col keyword
1827 in
1828 Report.Report "RESERVED WORD" region [] $
1829 Code.toSnippet source surroundings (Just region)
1831 D.reflow $
1832 "I was partway through parsing a `let` expression, but I got stuck here:"
1834 D.reflow $
1835 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name, but\
1836 \ it is a reserved word! Try using a different name instead."
1839 _ ->
1840 toUnfinishLetReport source row col startRow startCol $
1841 D.reflow $
1842 "I was expecting the name of a definition next."
1844 LetDef name def row col ->
1845 error "TODO LetDef" name def row col
1847 LetDestruct destruct row col ->
1848 error "TODO LetDestruct" destruct row col
1850 LetBody expr row col ->
1851 toExprReport source context expr row col
1853 LetIndentDef row col ->
1854 toUnfinishLetReport source row col startRow startCol $
1855 D.reflow $
1856 "I was expecting a value to be defined here."
1858 LetIndentIn row col ->
1859 toUnfinishLetReport source row col startRow startCol $
1860 D.fillSep $
1861 ["I","was","expecting","to","see","the",D.cyan "in","keyword","next."
1862 ,"Or","maybe","more","of","that","expression?"
1865 LetIndentBody row col ->
1866 toUnfinishLetReport source row col startRow startCol $
1867 D.reflow $
1868 "I was expecting an expression next. Tell me what should happen with the value you just defined!"
1871toUnfinishLetReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
1872toUnfinishLetReport source row col startRow startCol message =
1873 let
1874 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1875 region = toRegion row col
1876 in
1877 Report.Report "UNFINISHED LET" region [] $
1878 Code.toSnippet source surroundings (Just region)
1880 D.reflow $
1881 "I was partway through parsing a `let` expression, but I got stuck here:"
1883 D.stack
1884 [ message
1885 , D.toSimpleNote $
1886 "Here is an example with a valid `let` expression for reference:"
1887 , D.vcat $
1888 [ D.indent 0 $ D.fillSep [D.green "viewPerson","person","="]
1889 , D.indent 2 $ D.fillSep [D.cyan "let"]
1890 , D.indent 4 $ D.fillSep ["fullName","="]
1891 , D.indent 6 $ D.fillSep ["person.firstName","++",D.dullyellow "\" \"","++","person.lastName"]
1892 , D.indent 2 $ D.fillSep [D.cyan "in"]
1893 , D.indent 2 $ D.fillSep ["div","[]","[","text","fullName","]"]
1895 , D.reflow $
1896 "Here we defined a `viewPerson` function that turns a person into some HTML. We use\
1897 \ a `let` expression to define the `fullName` we want to show. Notice the indentation! The\
1898 \ `fullName` is indented more than the `let` keyword, and the actual value of `fullName` is\
1899 \ indented a bit more than that. That is important!"
1905-- CASE
1908toCaseReport :: Code.Source -> Context -> Case -> Row -> Col -> Report.Report
1909toCaseReport source context case_ startRow startCol =
1910 case case_ of
1911 CaseSpace space row col ->
1912 toSpaceReport source space row col
1914 CaseOf row col ->
1915 toUnfinishCaseReport source row col startRow startCol $
1916 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
1918 CasePattern pattern row col ->
1919 toPatternReport source PCase pattern row col
1921 CaseArrow row col ->
1922 case Code.whatIsNext source row col of
1923 Code.Keyword keyword ->
1924 let
1925 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1926 region = toKeywordRegion row col keyword
1927 in
1928 Report.Report "RESERVED WORD" region [] $
1929 Code.toSnippet source surroundings (Just region)
1931 D.reflow $
1932 "I am partway through parsing a `case` expression, but I got stuck here:"
1934 D.reflow $
1935 "It looks like you are trying to use `" ++ keyword ++ "` in one of your\
1936 \ patterns, but it is a reserved word. Try using a different name?"
1939 Code.Operator ":" ->
1940 let
1941 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1942 region = toRegion row col
1943 in
1944 Report.Report "UNEXPECTED OPERATOR" region [] $
1945 Code.toSnippet source surroundings (Just region)
1947 D.reflow $
1948 "I am partway through parsing a `case` expression, but I got stuck here:"
1950 D.fillSep $
1951 ["I","am","seeing",D.dullyellow ":","but","maybe","you","want",D.green "::","instead?"
1952 ,"For","pattern","matching","on","lists?"
1956 Code.Operator "=" ->
1957 let
1958 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1959 region = toRegion row col
1960 in
1961 Report.Report "UNEXPECTED OPERATOR" region [] $
1962 Code.toSnippet source surroundings (Just region)
1964 D.reflow $
1965 "I am partway through parsing a `case` expression, but I got stuck here:"
1967 D.fillSep $
1968 ["I","am","seeing",D.dullyellow "=","but","maybe","you","want",D.green "->","instead?"
1972 _ ->
1973 let
1974 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1975 region = toRegion row col
1976 in
1977 Report.Report "MISSING ARROW" region [] $
1978 Code.toSnippet source surroundings (Just region)
1980 D.reflow $
1981 "I am partway through parsing a `case` expression, but I got stuck here:"
1983 addNoteForCaseIndentError $
1984 D.reflow $
1985 "I was expecting to see an arrow next."
1988 CaseExpr expr row col ->
1989 toExprReport source (InNode NCase startRow startCol context) expr row col
1991 CaseBranch expr row col ->
1992 toExprReport source (InNode NBranch startRow startCol context) expr row col
1994 CaseIndentOf row col ->
1995 toUnfinishCaseReport source row col startRow startCol $
1996 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
1998 CaseIndentExpr row col ->
1999 toUnfinishCaseReport source row col startRow startCol $
2000 D.reflow "I was expecting to see a expression next."
2002 CaseIndentPattern row col ->
2003 toUnfinishCaseReport source row col startRow startCol $
2004 D.reflow "I was expecting to see a pattern next."
2006 CaseIndentArrow row col ->
2007 toUnfinishCaseReport source row col startRow startCol $
2008 D.fillSep
2009 ["I","just","saw","a","pattern,","so","I","was","expecting"
2010 ,"to","see","a",D.dullyellow "->","next."
2013 CaseIndentBranch row col ->
2014 toUnfinishCaseReport source row col startRow startCol $
2015 D.reflow $
2016 "I was expecting to see an expression next. What should I do when\
2017 \ I run into this particular pattern?"
2019 CasePatternAlignment indent row col ->
2020 toUnfinishCaseReport source row col startRow startCol $
2021 D.reflow $
2022 "I suspect this is a pattern that is not indented far enough? (" ++ show indent ++ " spaces)"
2025toUnfinishCaseReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
2026toUnfinishCaseReport source row col startRow startCol message =
2027 let
2028 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2029 region = toRegion row col
2030 in
2031 Report.Report "UNFINISHED CASE" region [] $
2032 Code.toSnippet source surroundings (Just region)
2034 D.reflow $
2035 "I was partway through parsing a `case` expression, but I got stuck here:"
2037 D.stack
2038 [ message
2039 , D.toSimpleNote $
2040 "Here is an example of a valid `case` expression for reference."
2041 , D.vcat $
2042 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
2043 , D.indent 6 $ D.fillSep [D.green "Just","width","->"]
2044 , D.indent 8 $ D.fillSep ["width","+",D.dullyellow "200"]
2045 , ""
2046 , D.indent 6 $ D.fillSep [D.green "Nothing","->"]
2047 , D.indent 8 $ D.fillSep [D.dullyellow "400"]
2049 , D.reflow $
2050 "Notice the indentation. Each pattern is aligned, and each branch is indented\
2051 \ a bit more than the corresponding pattern. That is important!"
2056addNoteForCaseIndentError :: D.Doc -> D.Doc
2057addNoteForCaseIndentError message =
2058 D.stack $
2059 message
2061 [ D.toSimpleNote $
2062 "Sometimes I get confused by indentation, so try to make your `case` look\
2063 \ something like this:"
2064 , D.vcat $
2065 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
2066 , D.indent 6 $ D.fillSep [D.green "Just","width","->"]
2067 , D.indent 8 $ D.fillSep ["width","+",D.dullyellow "200"]
2068 , ""
2069 , D.indent 6 $ D.fillSep [D.green "Nothing","->"]
2070 , D.indent 8 $ D.fillSep [D.dullyellow "400"]
2072 , D.reflow $
2073 "Notice the indentation! Each pattern is aligned, and each branch is indented\
2074 \ a bit more than the corresponding pattern. That is important!"
2079-- IF
2082toIfReport :: Code.Source -> Context -> If -> Row -> Col -> Report.Report
2083toIfReport source context if_ startRow startCol =
2084 case if_ of
2085 IfSpace space row col ->
2086 toSpaceReport source space row col
2088 IfThen row col ->
2089 let
2090 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2091 region = toRegion row col
2092 in
2093 Report.Report "UNFINISHED IF" region [] $
2094 Code.toSnippet source surroundings (Just region)
2096 D.reflow $
2097 "I was expecting to see more of this `if` expression, but I got stuck here:"
2099 D.fillSep $
2100 ["I","was","expecting","to","see","the",D.cyan "then","keyword","next."
2104 IfElse row col ->
2105 let
2106 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2107 region = toRegion row col
2108 in
2109 Report.Report "UNFINISHED IF" region [] $
2110 Code.toSnippet source surroundings (Just region)
2112 D.reflow $
2113 "I was expecting to see more of this `if` expression, but I got stuck here:"
2115 D.fillSep $
2116 ["I","was","expecting","to","see","the",D.cyan "else","keyword","next."
2120 IfElseBranchStart row col ->
2121 let
2122 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2123 region = toRegion row col
2124 in
2125 Report.Report "UNFINISHED IF" region [] $
2126 Code.toSnippet source surroundings (Just region)
2128 D.reflow $
2129 "I just saw the start of an `else` branch, but then I got stuck here:"
2131 D.reflow $
2132 "I was expecting to see an expression next. Maybe it is not filled in yet?"
2135 IfCondition expr row col ->
2136 toExprReport source (InNode NCond startRow startCol context) expr row col
2138 IfThenBranch expr row col ->
2139 toExprReport source (InNode NThen startRow startCol context) expr row col
2141 IfElseBranch expr row col ->
2142 toExprReport source (InNode NElse startRow startCol context) expr row col
2144 IfIndentCondition row col ->
2145 let
2146 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2147 region = toRegion row col
2148 in
2149 Report.Report "UNFINISHED IF" region [] $
2150 Code.toSnippet source surroundings (Just region)
2152 D.reflow $
2153 "I was expecting to see more of this `if` expression, but I got stuck here:"
2155 D.stack
2156 [ D.fillSep $
2157 ["I","was","expecting","to","see","an","expression","like",D.dullyellow "x < 0"
2158 ,"that","evaluates","to","True","or","False."
2160 , D.toSimpleNote $
2161 "I can be confused by indentation. Maybe something is not indented enough?"
2165 IfIndentThen row col ->
2166 let
2167 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2168 region = toRegion row col
2169 in
2170 Report.Report "UNFINISHED IF" region [] $
2171 Code.toSnippet source surroundings (Just region)
2173 D.reflow $
2174 "I was expecting to see more of this `if` expression, but I got stuck here:"
2176 D.stack
2177 [ D.fillSep $
2178 ["I","was","expecting","to","see","the",D.cyan "then","keyword","next."
2180 , D.toSimpleNote $
2181 "I can be confused by indentation. Maybe something is not indented enough?"
2185 IfIndentThenBranch row col ->
2186 let
2187 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2188 region = toRegion row col
2189 in
2190 Report.Report "UNFINISHED IF" region [] $
2191 Code.toSnippet source surroundings (Just region)
2193 D.reflow $
2194 "I got stuck after the start of this `then` branch:"
2196 D.stack
2197 [ D.reflow $
2198 "I was expecting to see an expression next. Maybe it is not filled in yet?"
2199 , D.toSimpleNote $
2200 "I can be confused by indentation, so if the `then` branch is already\
2201 \ present, it may not be indented enough for me to recognize it."
2205 IfIndentElseBranch row col ->
2206 let
2207 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2208 region = toRegion row col
2209 in
2210 Report.Report "UNFINISHED IF" region [] $
2211 Code.toSnippet source surroundings (Just region)
2213 D.reflow $
2214 "I got stuck after the start of this `else` branch:"
2216 D.stack
2217 [ D.reflow $
2218 "I was expecting to see an expression next. Maybe it is not filled in yet?"
2219 , D.toSimpleNote $
2220 "I can be confused by indentation, so if the `else` branch is already\
2221 \ present, it may not be indented enough for me to recognize it."
2225 IfIndentElse row col ->
2226 let
2227 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2228 region = toRegion row col
2229 in
2230 Report.Report "UNFINISHED IF" region [] $
2231 Code.toSnippet source surroundings (Just region)
2233 D.reflow $
2234 "I was expecting to see an `else` branch after this:"
2236 D.stack
2237 [ D.reflow $
2238 "I know what to do when the condition is `True`, but not when it is `False`."
2239 , D.fillSep
2240 ["Add","an",D.cyan "else","branch","to","handle","that","scenario!"]
2246-- RECORD
2249toRecordReport :: Code.Source -> Context -> Record -> Row -> Col -> Report.Report
2250toRecordReport source context record startRow startCol =
2251 case record of
2252 RecordOpen row col ->
2253 case Code.whatIsNext source row col of
2254 Code.Keyword keyword ->
2255 let
2256 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2257 region = toKeywordRegion row col keyword
2258 in
2259 Report.Report "RESERVED WORD" region [] $
2260 Code.toSnippet source surroundings (Just region)
2262 D.reflow $
2263 "I just started parsing a record, but I got stuck on this field name:"
2265 D.reflow $
2266 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
2267 \ that is a reserved word. Try using a different name!"
2270 _ ->
2271 let
2272 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2273 region = toRegion row col
2274 in
2275 Report.Report "UNFINISHED RECORD" region [] $
2276 Code.toSnippet source surroundings (Just region)
2278 D.reflow $
2279 "I just started parsing a record, but I got stuck here:"
2281 D.fillSep
2282 ["Records","look","like",D.dullyellow "{ x = 3, y = 4 },"
2283 ,"so","I","was","expecting","to","see","a","field","name","next."
2287 RecordEnd row col ->
2288 let
2289 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2290 region = toRegion row col
2291 in
2292 Report.Report "UNFINISHED RECORD" region [] $
2293 Code.toSnippet source surroundings (Just region)
2295 D.reflow $
2296 "I am partway through parsing a record, but I got stuck here:"
2298 D.stack
2299 [ D.fillSep
2300 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
2301 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
2303 , D.toSimpleNote $
2304 "When I get stuck like this, it usually means that there is a missing parenthesis\
2305 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
2309 RecordField row col ->
2310 case Code.whatIsNext source row col of
2311 Code.Keyword keyword ->
2312 let
2313 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2314 region = toKeywordRegion row col keyword
2315 in
2316 Report.Report "RESERVED WORD" region [] $
2317 Code.toSnippet source surroundings (Just region)
2319 D.reflow $
2320 "I am partway through parsing a record, but I got stuck on this field name:"
2322 D.reflow $
2323 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
2324 \ that is a reserved word. Try using a different name!"
2327 _ ->
2328 let
2329 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2330 region = toRegion row col
2331 in
2332 Report.Report "UNFINISHED RECORD" region [] $
2333 Code.toSnippet source surroundings (Just region)
2335 D.reflow $
2336 "I am partway through parsing a record, but I got stuck after that last comma:"
2338 addNoteForRecordError $
2339 D.reflow $
2340 "Trailing commas are not allowed in records, so I was expecting to see another\
2341 \ record field defined next. If you are done defining the record, the fix may\
2342 \ be to delete that last comma?"
2345 RecordEquals row col ->
2346 let
2347 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2348 region = toRegion row col
2349 in
2350 Report.Report "UNFINISHED RECORD" region [] $
2351 Code.toSnippet source surroundings (Just region)
2353 D.reflow $
2354 "I am partway through parsing a record, but I got stuck here:"
2356 addNoteForRecordError $
2357 D.fillSep $
2358 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
2359 ,"an","equals","sign","next.","So","try","putting","an",D.green "=","sign","here?"
2363 RecordExpr expr row col ->
2364 toExprReport source (InNode NRecord startRow startCol context) expr row col
2366 RecordSpace space row col ->
2367 toSpaceReport source space row col
2369 RecordIndentOpen row col ->
2370 let
2371 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2372 region = toRegion row col
2373 in
2374 Report.Report "UNFINISHED RECORD" region [] $
2375 Code.toSnippet source surroundings (Just region)
2377 D.reflow $
2378 "I just saw the opening curly brace of a record, but then I got stuck here:"
2380 addNoteForRecordIndentError $
2381 D.fillSep $
2382 ["I","am","expecting","a","record","like",D.dullyellow "{ x = 3, y = 4 }","here."
2383 ,"Try","defining","some","fields","of","your","own?"
2387 RecordIndentEnd row col ->
2388 let
2389 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2390 region = toRegion row col
2391 in
2392 Report.Report "UNFINISHED RECORD" region [] $
2393 Code.toSnippet source surroundings (Just region)
2395 D.reflow $
2396 "I was expecting to see a closing curly brace next:"
2398 addNoteForRecordIndentError $
2399 D.fillSep $
2400 ["Try","putting","an",D.green "}","and","see","if","that","helps?"
2404 RecordIndentField row col ->
2405 let
2406 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2407 region = toRegion row col
2408 in
2409 Report.Report "UNFINISHED RECORD" region [] $
2410 Code.toSnippet source surroundings (Just region)
2412 D.reflow $
2413 "I am partway through parsing a record, but I got stuck after that last comma:"
2415 addNoteForRecordError $
2416 D.reflow $
2417 "Trailing commas are not allowed in records, so the fix may be to\
2418 \ delete that last comma? Or maybe you were in the middle of defining\
2419 \ an additional field?"
2422 RecordIndentEquals row col ->
2423 let
2424 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2425 region = toRegion row col
2426 in
2427 Report.Report "UNFINISHED RECORD" region [] $
2428 Code.toSnippet source surroundings (Just region)
2430 D.reflow $
2431 "I am partway through parsing a record. I just saw a record\
2432 \ field, so I was expecting to see an equals sign next:"
2434 addNoteForRecordIndentError $
2435 D.fillSep $
2436 ["Try","putting","an",D.green "=","followed","by","an","expression?"
2440 RecordIndentExpr row col ->
2441 let
2442 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2443 region = toRegion row col
2444 in
2445 Report.Report "UNFINISHED RECORD" region [] $
2446 Code.toSnippet source surroundings (Just region)
2448 D.reflow $
2449 "I am partway through parsing a record, and I was expecting to run into an expression next:"
2451 addNoteForRecordIndentError $
2452 D.fillSep $
2453 ["Try","putting","something,","like"
2454 ,D.dullyellow "42","or",D.dullyellow"\"hello\"","for","now?"
2459addNoteForRecordError :: D.Doc -> D.Doc
2460addNoteForRecordError normalRecommendation =
2461 D.stack $
2462 normalRecommendation
2464 [ D.toSimpleNote
2465 "If you are trying to define a record across multiple lines, I recommend using this format:"
2466 , D.indent 4 $ D.vcat $
2467 [ "{ name = \"Alice\""
2468 , ", age = 42"
2469 , ", height = 1.75"
2470 , "}"
2472 , D.reflow $
2473 "Notice that each line starts with some indentation. Usually two or four spaces. I\
2474 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
2475 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2479addNoteForRecordIndentError :: D.Doc -> D.Doc
2480addNoteForRecordIndentError normalRecommendation =
2481 D.stack $
2482 normalRecommendation
2484 [ D.toSimpleNote
2485 "I may be confused by indentation. For example, if you are trying to define\
2486 \ a record across multiple lines, I recommend using this format:"
2487 , D.indent 4 $ D.vcat $
2488 [ "{ name = \"Alice\""
2489 , ", age = 42"
2490 , ", height = 1.75"
2491 , "}"
2493 , D.reflow $
2494 "Notice that each line starts with some indentation. Usually two or four spaces. I\
2495 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
2496 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2501-- TUPLE
2504toTupleReport :: Code.Source -> Context -> Tuple -> Row -> Col -> Report.Report
2505toTupleReport source context tuple startRow startCol =
2506 case tuple of
2507 TupleExpr expr row col ->
2508 toExprReport source (InNode NParens startRow startCol context) expr row col
2510 TupleSpace space row col ->
2511 toSpaceReport source space row col
2513 TupleEnd row col ->
2514 let
2515 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2516 region = toRegion row col
2517 in
2518 Report.Report "UNFINISHED PARENTHESES" region [] $
2519 Code.toSnippet source surroundings (Just region)
2521 D.reflow $
2522 "I was expecting to see a closing parentheses next, but I got stuck here:"
2524 D.stack
2525 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
2526 , D.toSimpleNote $
2527 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
2528 \ unexpectedly. So there may be some earlier syntax trouble (like extra parenthesis\
2529 \ or missing brackets) that is confusing me."
2533 TupleOperatorClose row col ->
2534 let
2535 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2536 region = toRegion row col
2537 in
2538 Report.Report "UNFINISHED OPERATOR FUNCTION" region [] $
2539 Code.toSnippet source surroundings (Just region)
2541 D.reflow "I was expecting a closing parenthesis here:"
2543 D.stack
2544 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
2545 , D.toSimpleNote $
2546 "I think I am parsing an operator function right now, so I am expecting to see\
2547 \ something like (+) or (&&) where an operator is surrounded by parentheses with\
2548 \ no extra spaces."
2552 TupleOperatorReserved operator row col ->
2553 let
2554 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2555 region = toRegion row col
2556 in
2557 Report.Report "UNEXPECTED SYMBOL" region [] $
2558 Code.toSnippet source surroundings (Just region)
2560 D.reflow $
2561 "I ran into an unexpected symbol here:"
2563 D.fillSep $
2564 case operator of
2565 BadDot -> ["Maybe","you","wanted","a","record","accessor","like",D.dullyellow ".x","or",D.dullyellow ".name","instead?"]
2566 BadPipe -> ["Try",D.dullyellow "(||)","instead?","To","turn","boolean","OR","into","a","function?"]
2567 BadArrow -> ["Maybe","you","wanted",D.dullyellow "(>)","or",D.dullyellow "(>=)","instead?"]
2568 BadEquals -> ["Try",D.dullyellow "(==)","instead?","To","make","a","function","that","checks","equality?"]
2569 BadHasType -> ["Try",D.dullyellow "(::)","instead?","To","add","values","to","the","front","of","lists?"]
2572 TupleIndentExpr1 row col ->
2573 let
2574 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2575 region = toRegion row col
2576 in
2577 Report.Report "UNFINISHED PARENTHESES" region [] $
2578 Code.toSnippet source surroundings (Just region)
2580 D.reflow $
2581 "I just saw an open parenthesis, so I was expecting to see an expression next."
2583 D.stack
2584 [ D.fillSep $
2585 ["Something","like",D.dullyellow "(4 + 5)","or"
2586 ,D.dullyellow "(String.reverse \"desserts\")" <> "."
2587 ,"Anything","where","you","are","putting","parentheses","around","normal","expressions."
2589 , D.toSimpleNote $
2590 "I can get confused by indentation in cases like this, so\
2591 \ maybe you have an expression but it is not indented enough?"
2595 TupleIndentExprN row col ->
2596 let
2597 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2598 region = toRegion row col
2599 in
2600 Report.Report "UNFINISHED TUPLE" region [] $
2601 Code.toSnippet source surroundings (Just region)
2603 D.reflow $
2604 "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."
2606 D.stack
2607 [ D.fillSep $
2608 ["A","tuple","looks","like",D.dullyellow "(3,4)","or"
2609 ,D.dullyellow "(\"Tom\",42)" <> ","
2610 ,"so","I","think","there","is","an","expression","missing","here?"
2612 , D.toSimpleNote $
2613 "I can get confused by indentation in cases like this, so\
2614 \ maybe you have an expression but it is not indented enough?"
2618 TupleIndentEnd row col ->
2619 let
2620 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2621 region = toRegion row col
2622 in
2623 Report.Report "UNFINISHED PARENTHESES" region [] $
2624 Code.toSnippet source surroundings (Just region)
2626 D.reflow $
2627 "I was expecting to see a closing parenthesis next:"
2629 D.stack
2630 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
2631 , D.toSimpleNote $
2632 "I can get confused by indentation in cases like this, so\
2633 \ maybe you have a closing parenthesis but it is not indented enough?"
2638toListReport :: Code.Source -> Context -> List -> Row -> Col -> Report.Report
2639toListReport source context list startRow startCol =
2640 case list of
2641 ListSpace space row col ->
2642 toSpaceReport source space row col
2644 ListOpen row col ->
2645 let
2646 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2647 region = toRegion row col
2648 in
2649 Report.Report "UNFINISHED LIST" region [] $
2650 Code.toSnippet source surroundings (Just region)
2652 D.reflow $
2653 "I am partway through parsing a list, but I got stuck here:"
2655 D.stack
2656 [ D.fillSep
2657 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
2658 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
2660 , D.toSimpleNote $
2661 "When I get stuck like this, it usually means that there is a missing parenthesis\
2662 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
2666 ListExpr expr row col ->
2667 case expr of
2668 Start r c ->
2669 let
2670 surroundings = A.Region (A.Position startRow startCol) (A.Position r c)
2671 region = toRegion r c
2672 in
2673 Report.Report "UNFINISHED LIST" region [] $
2674 Code.toSnippet source surroundings (Just region)
2676 D.reflow $
2677 "I was expecting to see another list entry after that last comma:"
2679 D.stack
2680 [ D.reflow $
2681 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
2682 , D.toSimpleNote
2683 "I recommend using the following format for lists that span multiple lines:"
2684 , D.indent 4 $ D.vcat $
2685 [ "[ \"Alice\""
2686 , ", \"Bob\""
2687 , ", \"Chuck\""
2688 , "]"
2690 , D.reflow $
2691 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2692 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2693 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2697 _ ->
2698 toExprReport source (InNode NList startRow startCol context) expr row col
2700 ListEnd row col ->
2701 let
2702 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2703 region = toRegion row col
2704 in
2705 Report.Report "UNFINISHED LIST" region [] $
2706 Code.toSnippet source surroundings (Just region)
2708 D.reflow $
2709 "I am partway through parsing a list, but I got stuck here:"
2711 D.stack
2712 [ D.fillSep
2713 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
2714 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
2716 , D.toSimpleNote $
2717 "When I get stuck like this, it usually means that there is a missing parenthesis\
2718 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
2722 ListIndentOpen row col ->
2723 let
2724 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2725 region = toRegion row col
2726 in
2727 Report.Report "UNFINISHED LIST" region [] $
2728 Code.toSnippet source surroundings (Just region)
2730 D.reflow $
2731 "I cannot find the end of this list:"
2733 D.stack
2734 [ D.fillSep $
2735 ["You","could","change","it","to","something","like"
2736 ,D.dullyellow "[3,4,5]"
2737 ,"or","even","just"
2738 ,D.dullyellow "[]" <> "."
2739 ,"Anything","where","there","is","an","open","and","close","square","brace,"
2740 ,"and","where","the","elements","of","the","list","are","separated","by","commas."
2742 , D.toSimpleNote
2743 "I may be confused by indentation. For example, if you are trying to define\
2744 \ a list across multiple lines, I recommend using this format:"
2745 , D.indent 4 $ D.vcat $
2746 [ "[ \"Alice\""
2747 , ", \"Bob\""
2748 , ", \"Chuck\""
2749 , "]"
2751 , D.reflow $
2752 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2753 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2754 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2758 ListIndentEnd row col ->
2759 let
2760 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2761 region = toRegion row col
2762 in
2763 Report.Report "UNFINISHED LIST" region [] $
2764 Code.toSnippet source surroundings (Just region)
2766 D.reflow $
2767 "I cannot find the end of this list:"
2769 D.stack
2770 [ D.fillSep $
2771 ["You","can","just","add","a","closing",D.dullyellow "]"
2772 ,"right","here,","and","I","will","be","all","set!"
2774 , D.toSimpleNote
2775 "I may be confused by indentation. For example, if you are trying to define\
2776 \ a list across multiple lines, I recommend using this format:"
2777 , D.indent 4 $ D.vcat $
2778 [ "[ \"Alice\""
2779 , ", \"Bob\""
2780 , ", \"Chuck\""
2781 , "]"
2783 , D.reflow $
2784 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2785 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2786 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2790 ListIndentExpr row col ->
2791 let
2792 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2793 region = toRegion row col
2794 in
2795 Report.Report "UNFINISHED LIST" region [] $
2796 Code.toSnippet source surroundings (Just region)
2798 D.reflow $
2799 "I was expecting to see another list entry after this comma:"
2801 D.stack
2802 [ D.reflow $
2803 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
2804 , D.toSimpleNote
2805 "I recommend using the following format for lists that span multiple lines:"
2806 , D.indent 4 $ D.vcat $
2807 [ "[ \"Alice\""
2808 , ", \"Bob\""
2809 , ", \"Chuck\""
2810 , "]"
2812 , D.reflow $
2813 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2814 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2815 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2820toFuncReport :: Code.Source -> Context -> Func -> Row -> Col -> Report.Report
2821toFuncReport source context func startRow startCol =
2822 case func of
2823 FuncSpace space row col ->
2824 toSpaceReport source space row col
2826 FuncArg pattern row col ->
2827 toPatternReport source PArg pattern row col
2829 FuncBody expr row col ->
2830 toExprReport source (InNode NFunc startRow startCol context) expr row col
2832 FuncArrow row col ->
2833 case Code.whatIsNext source row col of
2834 Code.Keyword keyword ->
2835 let
2836 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2837 region = toKeywordRegion row col keyword
2838 in
2839 Report.Report "RESERVED WORD" region [] $
2840 Code.toSnippet source surroundings (Just region)
2842 D.reflow $
2843 "I was parsing an anonymous function, but I got stuck here:"
2845 D.reflow $
2846 "It looks like you are trying to use `" ++ keyword ++ "` as an argument, but\
2847 \ it is a reserved word in this language. Try using a different argument name!"
2850 _ ->
2851 let
2852 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2853 region = toRegion row col
2854 in
2855 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
2856 Code.toSnippet source surroundings (Just region)
2858 D.reflow $
2859 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
2861 D.fillSep $
2862 ["The","syntax","for","anonymous","functions","is"
2863 ,D.dullyellow "(\\x -> x + 1)"
2864 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
2868 FuncIndentArg row col ->
2869 let
2870 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2871 region = toRegion row col
2872 in
2873 Report.Report "MISSING ARGUMENT" region [] $
2874 Code.toSnippet source surroundings (Just region)
2876 D.reflow $
2877 "I just saw the beginning of an anonymous function, so I was expecting to see an argument next:"
2879 D.stack
2880 [ D.fillSep
2881 ["Something","like",D.dullyellow"x","or",D.dullyellow "name" <> "."
2882 ,"Anything","that","starts","with","a","lower","case","letter!"
2884 , D.toSimpleNote $
2885 "The syntax for anonymous functions is (\\x -> x + 1) where the backslash\
2886 \ is meant to look a bit like a lambda if you squint. This visual pun seemed\
2887 \ like a better idea at the time!"
2891 FuncIndentArrow row col ->
2892 let
2893 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2894 region = toRegion row col
2895 in
2896 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
2897 Code.toSnippet source surroundings (Just region)
2899 D.reflow $
2900 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
2902 D.stack
2903 [ D.fillSep $
2904 ["The","syntax","for","anonymous","functions","is"
2905 ,D.dullyellow "(\\x -> x + 1)"
2906 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
2908 , D.toSimpleNote $
2909 "It is possible that I am confused about indetation! I generally recommend\
2910 \ switching to named functions if the definition cannot fit inline nicely, so\
2911 \ either (1) try to fit the whole anonymous function on one line or (2) break\
2912 \ the whole thing out into a named function. Things tend to be clearer that way!"
2916 FuncIndentBody row col ->
2917 let
2918 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2919 region = toRegion row col
2920 in
2921 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
2922 Code.toSnippet source surroundings (Just region)
2924 D.reflow $
2925 "I was expecting to see the body of your anonymous function next:"
2927 D.stack
2928 [ D.fillSep $
2929 ["The","syntax","for","anonymous","functions","is"
2930 ,D.dullyellow "(\\x -> x + 1)"
2931 ,"so","I","am","missing","all","the","stuff","after","the","arrow!"
2933 , D.toSimpleNote $
2934 "It is possible that I am confused about indetation! I generally recommend\
2935 \ switching to named functions if the definition cannot fit inline nicely, so\
2936 \ either (1) try to fit the whole anonymous function on one line or (2) break\
2937 \ the whole thing out into a named function. Things tend to be clearer that way!"
2943-- PATTERN
2946data PContext
2947 = PCase
2948 | PArg
2951toPatternReport :: Code.Source -> PContext -> Pattern -> Row -> Col -> Report.Report
2952toPatternReport source context pattern startRow startCol =
2953 case pattern of
2954 PRecord record row col ->
2955 toPRecordReport source record row col
2957 PTuple tuple row col ->
2958 toPTupleReport source context tuple row col
2960 PList list row col ->
2961 toPListReport source context list row col
2963 PStart row col ->
2964 case Code.whatIsNext source row col of
2965 Code.Keyword keyword ->
2966 let
2967 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2968 region = toKeywordRegion row col keyword
2969 aThing =
2970 case context of
2971 PArg -> "an argument"
2972 PCase -> "a pattern"
2973 in
2974 Report.Report "RESERVED WORD" region [] $
2975 Code.toSnippet source surroundings (Just region)
2977 D.reflow $
2978 "It looks like you are trying to use `" ++ keyword ++ "` as " ++ aThing ++ ":"
2980 D.reflow $
2981 "This is a reserved word! Try using some other name?"
2984 _ ->
2985 error "TODO PStart"
2987 PChar char row col ->
2988 toCharReport source char row col
2990 PString string row col ->
2991 toStringReport source string row col
2993 PNumber number row col ->
2994 toNumberReport source number row col
2996 PFloat width row col ->
2997 let
2998 region = toWiderRegion row col width
2999 in
3000 Report.Report "UNEXPECTED PATTERN" region [] $
3001 Code.toSnippet source region Nothing
3003 D.reflow $
3004 "I cannot pattern match with floating point numbers:"
3006 D.fillSep $
3007 ["Equality","on","floats","can","be","unreliable,","so","you","usually","want"
3008 ,"to","check","that","they","are","nearby","with","some","sort","of"
3009 ,D.dullyellow "(abs (actual - expected) < 0.001)","check."
3013 PAlias row col ->
3014 let
3015 region = toRegion row col
3016 in
3017 Report.Report "UNFINISHED PATTERN" region [] $
3018 Code.toSnippet source region Nothing $
3020 D.reflow $
3021 "I was expecting to see a variable name after the `as` keyword:"
3023 D.stack
3024 [ D.fillSep $
3025 ["The","`as`","keyword","lets","you","write","patterns","like"
3026 ,"((" <> D.dullyellow "x" <> "," <> D.dullyellow "y" <> ") " <> D.cyan "as" <> D.dullyellow " point" <> ")"
3027 ,"so","you","can","refer","to","individual","parts","of","the","tuple","with"
3028 ,D.dullyellow "x","and",D.dullyellow "y","or","you","refer","to","the","whole"
3029 ,"thing","with",D.dullyellow "point."
3031 , D.reflow $
3032 "So I was expecting to see a variable name after the `as` keyword here. Sometimes\
3033 \ people just want to use `as` as a variable name though. Try using a different name\
3034 \ in that case!"
3038 PWildcardNotVar name width row col ->
3039 let
3040 region = toWiderRegion row col (fromIntegral width)
3041 examples =
3042 case dropWhile (=='_') (Name.toChars name) of
3043 [] -> [D.dullyellow "x","or",D.dullyellow "age"]
3044 c:cs -> [D.dullyellow (D.fromChars (Char.toLower c : cs))]
3045 in
3046 Report.Report "UNEXPECTED NAME" region [] $
3047 Code.toSnippet source region Nothing $
3049 D.reflow $
3050 "Variable names cannot start with underscores like this:"
3052 D.fillSep $
3053 ["You","can","either","have","an","underscore","like",D.dullyellow "_","to"
3054 ,"ignore","the","value,","or","you","can","have","a","name","like"
3055 ] ++ examples ++ ["to","use","the","matched","value." ]
3058 PSpace space row col ->
3059 toSpaceReport source space row col
3061 PIndentStart row col ->
3062 error "TODO PIndentStart" row col
3064 PIndentAlias row col ->
3065 let
3066 region = toRegion row col
3067 in
3068 Report.Report "UNFINISHED PATTERN" region [] $
3069 Code.toSnippet source region Nothing $
3071 D.reflow $
3072 "I was expecting to see a variable name after the `as` keyword:"
3074 D.stack
3075 [ D.fillSep $
3076 ["The","`as`","keyword","lets","you","write","patterns","like"
3077 ,"((" <> D.dullyellow "x" <> "," <> D.dullyellow "y" <> ") " <> D.cyan "as" <> D.dullyellow " point" <> ")"
3078 ,"so","you","can","refer","to","individual","parts","of","the","tuple","with"
3079 ,D.dullyellow "x","and",D.dullyellow "y","or","you","refer","to","the","whole"
3080 ,"thing","with",D.dullyellow "point."
3082 , D.reflow $
3083 "So I was expecting to see a variable name after the `as` keyword here. Sometimes\
3084 \ people just want to use `as` as a variable name though. Try using a different name\
3085 \ in that case!"
3090toPRecordReport :: Code.Source -> PRecord -> Row -> Col -> Report.Report
3091toPRecordReport source record startRow startCol =
3092 case record of
3093 PRecordOpen row col ->
3094 toUnfinishRecordPatternReport source row col startRow startCol $
3095 D.reflow "I was expecting to see a field name next."
3097 PRecordEnd row col ->
3098 toUnfinishRecordPatternReport source row col startRow startCol $
3099 D.fillSep
3100 ["I","was","expecting","to","see","a","closing","curly","brace","next."
3101 ,"Try","adding","a",D.dullyellow "}","here?"
3104 PRecordField row col ->
3105 case Code.whatIsNext source row col of
3106 Code.Keyword keyword ->
3107 let
3108 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3109 region = toKeywordRegion row col keyword
3110 in
3111 Report.Report "RESERVED WORD" region [] $
3112 Code.toSnippet source surroundings (Just region)
3114 D.reflow $
3115 "I was not expecting to see `" ++ keyword ++ "` as a record field name:"
3117 D.reflow $
3118 "This is a reserved word, not available for variable names. Try another name!"
3121 _ ->
3122 toUnfinishRecordPatternReport source row col startRow startCol $
3123 D.reflow "I was expecting to see a field name next."
3125 PRecordSpace space row col ->
3126 toSpaceReport source space row col
3128 PRecordIndentOpen row col ->
3129 toUnfinishRecordPatternReport source row col startRow startCol $
3130 D.reflow "I was expecting to see a field name next."
3132 PRecordIndentEnd row col ->
3133 toUnfinishRecordPatternReport source row col startRow startCol $
3134 D.fillSep
3135 ["I","was","expecting","to","see","a","closing","curly","brace","next."
3136 ,"Try","adding","a",D.dullyellow "}","here?"
3139 PRecordIndentField row col ->
3140 toUnfinishRecordPatternReport source row col startRow startCol $
3141 D.reflow "I was expecting to see a field name next."
3144toUnfinishRecordPatternReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
3145toUnfinishRecordPatternReport source row col startRow startCol message =
3146 let
3147 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3148 region = toRegion row col
3149 in
3150 Report.Report "UNFINISHED RECORD PATTERN" region [] $
3151 Code.toSnippet source surroundings (Just region)
3153 D.reflow $
3154 "I was partway through parsing a record pattern, but I got stuck here:"
3156 D.stack
3157 [ message
3158 , D.toFancyHint $
3159 ["A","record","pattern","looks","like",D.dullyellow "{x,y}","or",D.dullyellow "{name,age}"
3160 ,"where","you","list","the","field","names","you","want","to","access."
3167toPTupleReport :: Code.Source -> PContext -> PTuple -> Row -> Col -> Report.Report
3168toPTupleReport source context tuple startRow startCol =
3169 case tuple of
3170 PTupleOpen row col ->
3171 case Code.whatIsNext source row col of
3172 Code.Keyword keyword ->
3173 let
3174 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3175 region = toKeywordRegion row col keyword
3176 in
3177 Report.Report "RESERVED WORD" region [] $
3178 Code.toSnippet source surroundings (Just region)
3180 D.reflow $
3181 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name:"
3183 D.reflow $
3184 "This is a reserved word! Try using some other name?"
3187 _ ->
3188 let
3189 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3190 region = toRegion row col
3191 in
3192 Report.Report "UNFINISHED PARENTHESES" region [] $
3193 Code.toSnippet source surroundings (Just region)
3195 D.reflow $
3196 "I just saw an open parenthesis, but I got stuck here:"
3198 D.fillSep
3199 ["I","was","expecting","so","see","a","pattern","next."
3200 ,"Maybe","it","will","end","up","being","something"
3201 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "?"
3205 PTupleEnd row col ->
3206 let
3207 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3208 region = toRegion row col
3209 in
3210 Report.Report "UNFINISHED PARENTHESES" region [] $
3211 Code.toSnippet source surroundings (Just region) $
3213 D.reflow $
3214 "I was expecting a closing parenthesis next:"
3216 D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
3219 PTupleExpr pattern row col ->
3220 toPatternReport source context pattern row col
3222 PTupleSpace space row col ->
3223 toSpaceReport source space row col
3225 PTupleIndentEnd row col ->
3226 let
3227 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3228 region = toRegion row col
3229 in
3230 Report.Report "UNFINISHED PARENTHESES" region [] $
3231 Code.toSnippet source surroundings (Just region) $
3233 D.reflow $
3234 "I was expecting a closing parenthesis next:"
3236 D.stack
3237 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
3238 , D.toSimpleNote $
3239 "I can get confused by indentation in cases like this, so\
3240 \ maybe you have a closing parenthesis but it is not indented enough?"
3244 PTupleIndentExpr1 row col ->
3245 let
3246 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3247 region = toRegion row col
3248 in
3249 Report.Report "UNFINISHED PARENTHESES" region [] $
3250 Code.toSnippet source surroundings (Just region) $
3252 D.reflow $
3253 "I just saw an open parenthesis, but then I got stuck here:"
3255 D.fillSep
3256 ["I","was","expecting","so","see","a","pattern","next."
3257 ,"Maybe","it","will","end","up","being","something"
3258 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "?"
3262 PTupleIndentExprN row col ->
3263 let
3264 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3265 region = toRegion row col
3266 in
3267 Report.Report "UNFINISHED TUPLE PATTERN" region [] $
3268 Code.toSnippet source surroundings (Just region) $
3270 D.reflow $
3271 "I am partway through parsing a tuple pattern, but I got stuck here:"
3273 D.stack
3274 [ D.fillSep
3275 ["I","was","expecting","so","see","a","pattern","next."
3276 ,"I","am","expecting","the","final","result","to","be","something"
3277 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "."
3279 , D.toSimpleNote $
3280 "I can get confused by indentation in cases like this, so the problem\
3281 \ may be that the next part is not indented enough?"
3286toPListReport :: Code.Source -> PContext -> PList -> Row -> Col -> Report.Report
3287toPListReport source context list startRow startCol =
3288 case list of
3289 PListOpen row col ->
3290 case Code.whatIsNext source row col of
3291 Code.Keyword keyword ->
3292 let
3293 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3294 region = toKeywordRegion row col keyword
3295 in
3296 Report.Report "RESERVED WORD" region [] $
3297 Code.toSnippet source surroundings (Just region)
3299 D.reflow $
3300 "It looks like you are trying to use `" ++ keyword ++ "` to name an element of a list:"
3302 D.reflow $
3303 "This is a reserved word though! Try using some other name?"
3306 _ ->
3307 let
3308 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3309 region = toRegion row col
3310 in
3311 Report.Report "UNFINISHED LIST PATTERN" region [] $
3312 Code.toSnippet source surroundings (Just region) $
3314 D.reflow $
3315 "I just saw an open square bracket, but then I got stuck here:"
3317 D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
3320 PListEnd row col ->
3321 let
3322 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3323 region = toRegion row col
3324 in
3325 Report.Report "UNFINISHED LIST PATTERN" region [] $
3326 Code.toSnippet source surroundings (Just region) $
3328 D.reflow $
3329 "I was expecting a closing square bracket to end this list pattern:"
3331 D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
3334 PListExpr pattern row col ->
3335 toPatternReport source context pattern row col
3337 PListSpace space row col ->
3338 toSpaceReport source space row col
3340 PListIndentOpen row col ->
3341 let
3342 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3343 region = toRegion row col
3344 in
3345 Report.Report "UNFINISHED LIST PATTERN" region [] $
3346 Code.toSnippet source surroundings (Just region) $
3348 D.reflow $
3349 "I just saw an open square bracket, but then I got stuck here:"
3351 D.stack
3352 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
3353 , D.toSimpleNote $
3354 "I can get confused by indentation in cases like this, so\
3355 \ maybe there is something next, but it is not indented enough?"
3359 PListIndentEnd row col ->
3360 let
3361 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3362 region = toRegion row col
3363 in
3364 Report.Report "UNFINISHED LIST PATTERN" region [] $
3365 Code.toSnippet source surroundings (Just region) $
3367 D.reflow $
3368 "I was expecting a closing square bracket to end this list pattern:"
3370 D.stack
3371 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
3372 , D.toSimpleNote $
3373 "I can get confused by indentation in cases like this, so\
3374 \ maybe you have a closing square bracket but it is not indented enough?"
3378 PListIndentExpr row col ->
3379 let
3380 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3381 region = toRegion row col
3382 in
3383 Report.Report "UNFINISHED LIST PATTERN" region [] $
3384 Code.toSnippet source surroundings (Just region) $
3386 D.reflow $
3387 "I am partway through parsing a list pattern, but I got stuck here:"
3389 D.stack
3390 [ D.reflow $
3391 "I was expecting to see another pattern next. Maybe a variable name."
3392 , D.toSimpleNote $
3393 "I can get confused by indentation in cases like this, so\
3394 \ maybe there is more to this pattern but it is not indented enough?"
3400-- TYPES
3403toTypeReport :: Code.Source -> Type -> Row -> Col -> Report.Report
3404toTypeReport source tipe startRow startCol =
3405 case tipe of
3406 TRecord record row col ->
3407 toTRecordReport source record row col
3409 TTuple tuple row col ->
3410 toTTupleReport source tuple row col
3412 TVariant row col ->
3413 error "TODO TVariant" row col startRow startCol
3415 TArrow row col ->
3416 error "TODO TArrow" row col
3418 TStart row col ->
3419 error "TODO TStart" row col
3421 TSpace space row col ->
3422 toSpaceReport source space row col
3424 TIndentStart row col ->
3425 error "TODO TIndentStart" row col
3429toTRecordReport :: Code.Source -> TRecord -> Row -> Col -> Report.Report
3430toTRecordReport source record startRow startCol =
3431 case record of
3432 TRecordOpen row col ->
3433 case Code.whatIsNext source row col of
3434 Code.Keyword keyword ->
3435 let
3436 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3437 region = toKeywordRegion row col keyword
3438 in
3439 Report.Report "RESERVED WORD" region [] $
3440 Code.toSnippet source surroundings (Just region)
3442 D.reflow $
3443 "I just started parsing a record type, but I got stuck on this field name:"
3445 D.reflow $
3446 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
3447 \ that is a reserved word. Try using a different name!"
3450 _ ->
3451 let
3452 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3453 region = toRegion row col
3454 in
3455 Report.Report "UNFINISHED RECORD TYPE" region [] $
3456 Code.toSnippet source surroundings (Just region)
3458 D.reflow $
3459 "I just started parsing a record type, but I got stuck here:"
3461 D.fillSep
3462 ["Record","types","look","like",D.dullyellow "{ name : String, age : Int },"
3463 ,"so","I","was","expecting","to","see","a","field","name","next."
3467 TRecordEnd row col ->
3468 let
3469 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3470 region = toRegion row col
3471 in
3472 Report.Report "UNFINISHED RECORD TYPE" region [] $
3473 Code.toSnippet source surroundings (Just region)
3475 D.reflow $
3476 "I am partway through parsing a record type, but I got stuck here:"
3478 D.stack
3479 [ D.fillSep
3480 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
3481 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
3483 , D.toSimpleNote $
3484 "When I get stuck like this, it usually means that there is a missing parenthesis\
3485 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
3489 TRecordField row col ->
3490 case Code.whatIsNext source row col of
3491 Code.Keyword keyword ->
3492 let
3493 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3494 region = toKeywordRegion row col keyword
3495 in
3496 Report.Report "RESERVED WORD" region [] $
3497 Code.toSnippet source surroundings (Just region)
3499 D.reflow $
3500 "I am partway through parsing a record type, but I got stuck on this field name:"
3502 D.reflow $
3503 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
3504 \ that is a reserved word. Try using a different name!"
3507 _ ->
3508 let
3509 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3510 region = toRegion row col
3511 in
3512 Report.Report "UNFINISHED RECORD TYPE" region [] $
3513 Code.toSnippet source surroundings (Just region)
3515 D.reflow $
3516 "I am partway through parsing a record type, but I got stuck after that last comma:"
3518 addNoteForRecordTypeError $
3519 D.reflow $
3520 "Trailing commas are not allowed in records, so I was expecting to see another\
3521 \ record field defined next. If you are done defining the record, the fix may\
3522 \ be to delete that last comma?"
3525 TRecordColon row col ->
3526 let
3527 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3528 region = toRegion row col
3529 in
3530 Report.Report "UNFINISHED RECORD TYPE" region [] $
3531 Code.toSnippet source surroundings (Just region)
3533 D.reflow $
3534 "I am partway through parsing a record type, but I got stuck here:"
3536 addNoteForRecordTypeError $
3537 D.fillSep $
3538 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
3539 ,"a","colon","next.","So","try","putting","an",D.green ":","sign","here?"
3543 TRecordType tipe row col ->
3544 toTypeReport source tipe row col
3546 TRecordSpace space row col ->
3547 toSpaceReport source space row col
3549 TRecordIndentOpen row col ->
3550 let
3551 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3552 region = toRegion row col
3553 in
3554 Report.Report "UNFINISHED RECORD TYPE" region [] $
3555 Code.toSnippet source surroundings (Just region)
3557 D.reflow $
3558 "I just saw the opening curly brace of a record type, but then I got stuck here:"
3560 addNoteForRecordTypeIndentError $
3561 D.fillSep $
3562 ["I","am","expecting","a","record","like",D.dullyellow "{ name : String, age : Int }","here."
3563 ,"Try","defining","some","fields","of","your","own?"
3567 TRecordIndentEnd row col ->
3568 let
3569 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3570 region = toRegion row col
3571 in
3572 Report.Report "UNFINISHED RECORD TYPE" region [] $
3573 Code.toSnippet source surroundings (Just region)
3575 D.reflow $
3576 "I was expecting to see a closing curly brace next:"
3578 addNoteForRecordTypeIndentError $
3579 D.fillSep $
3580 ["Try","putting","an",D.green "}","and","see","if","that","helps?"
3584 TRecordIndentField row col ->
3585 let
3586 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3587 region = toRegion row col
3588 in
3589 Report.Report "UNFINISHED RECORD TYPE" region [] $
3590 Code.toSnippet source surroundings (Just region)
3592 D.reflow $
3593 "I am partway through parsing a record type, but I got stuck after that last comma:"
3595 addNoteForRecordTypeIndentError $
3596 D.reflow $
3597 "Trailing commas are not allowed in record types, so the fix may be to\
3598 \ delete that last comma? Or maybe you were in the middle of defining\
3599 \ an additional field?"
3602 TRecordIndentColon row col ->
3603 let
3604 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3605 region = toRegion row col
3606 in
3607 Report.Report "UNFINISHED RECORD TYPE" region [] $
3608 Code.toSnippet source surroundings (Just region)
3610 D.reflow $
3611 "I am partway through parsing a record type. I just saw a record\
3612 \ field, so I was expecting to see a colon next:"
3614 addNoteForRecordTypeIndentError $
3615 D.fillSep $
3616 ["Try","putting","an",D.green ":","followed","by","a","type?"
3620 TRecordIndentType row col ->
3621 let
3622 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3623 region = toRegion row col
3624 in
3625 Report.Report "UNFINISHED RECORD TYPE" region [] $
3626 Code.toSnippet source surroundings (Just region)
3628 D.reflow $
3629 "I am partway through parsing a record type, and I was expecting to run into a type next:"
3631 addNoteForRecordTypeIndentError $
3632 D.fillSep $
3633 ["Try","putting","something,","like"
3634 ,D.dullyellow "Int","or",D.dullyellow "String","for","now?"
3639addNoteForRecordTypeError :: D.Doc -> D.Doc
3640addNoteForRecordTypeError normalRecommendation =
3641 D.stack $
3642 normalRecommendation
3644 [ D.toSimpleNote
3645 "If you are trying to define a record type across multiple lines, I recommend using this format:"
3646 , D.indent 4 $ D.vcat $
3647 [ "{ name : String"
3648 , ", age : Int"
3649 , ", height : Float"
3650 , "}"
3652 , D.reflow $
3653 "Notice that each line starts with some indentation. Usually two or four spaces. I\
3654 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
3655 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3659addNoteForRecordTypeIndentError :: D.Doc -> D.Doc
3660addNoteForRecordTypeIndentError normalRecommendation =
3661 D.stack $
3662 normalRecommendation
3664 [ D.toSimpleNote
3665 "I may be confused by indentation. For example, if you are trying to define\
3666 \ a record type across multiple lines, I recommend using this format:"
3667 , D.indent 4 $ D.vcat $
3668 [ "{ name : String"
3669 , ", age : Int"
3670 , ", height : Float"
3671 , "}"
3673 , D.reflow $
3674 "Notice that each line starts with some indentation. Usually two or four spaces. I\
3675 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
3676 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3680toTTupleReport :: Code.Source -> TTuple -> Row -> Col -> Report.Report
3681toTTupleReport source tuple startRow startCol =
3682 case tuple of
3683 TTupleOpen row col ->
3684 case Code.whatIsNext source row col of
3685 Code.Keyword keyword ->
3686 let
3687 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3688 region = toKeywordRegion row col keyword
3689 in
3690 Report.Report "RESERVED WORD" region [] $
3691 Code.toSnippet source surroundings (Just region)
3693 D.reflow $
3694 "I ran into a reserved word unexpectedly:"
3696 D.reflow $
3697 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name, but \
3698 \ it is a reserved word. Try using a different name!"
3701 _ ->
3702 let
3703 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3704 region = toRegion row col
3705 in
3706 Report.Report "UNFINISHED PARENTHESES" region [] $
3707 Code.toSnippet source surroundings (Just region)
3709 D.reflow $
3710 "I just saw an open parenthesis, so I was expecting to see a type next."
3712 D.fillSep $
3713 ["Something","like",D.dullyellow "(Maybe Int)","or"
3714 ,D.dullyellow "(List Person)" <> "."
3715 ,"Anything","where","you","are","putting","parentheses","around","normal","types."
3719 TTupleEnd row col ->
3720 let
3721 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3722 region = toRegion row col
3723 in
3724 Report.Report "UNFINISHED PARENTHESES" region [] $
3725 Code.toSnippet source surroundings (Just region)
3727 D.reflow $
3728 "I was expecting to see a closing parentheses next, but I got stuck here:"
3730 D.stack
3731 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
3732 , D.toSimpleNote $
3733 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
3734 \ unexpectedly. So there may be some earlier syntax trouble (like extra parenthesis\
3735 \ or missing brackets) that is confusing me."
3739 TTupleType tipe row col ->
3740 toTypeReport source tipe row col
3742 TTupleSpace space row col ->
3743 toSpaceReport source space row col
3745 TTupleIndentType1 row col ->
3746 let
3747 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3748 region = toRegion row col
3749 in
3750 Report.Report "UNFINISHED PARENTHESES" region [] $
3751 Code.toSnippet source surroundings (Just region)
3753 D.reflow $
3754 "I just saw an open parenthesis, so I was expecting to see a type next."
3756 D.stack
3757 [ D.fillSep $
3758 ["Something","like",D.dullyellow "(Maybe Int)","or"
3759 ,D.dullyellow "(List Person)" <> "."
3760 ,"Anything","where","you","are","putting","parentheses","around","normal","types."
3762 , D.toSimpleNote $
3763 "I can get confused by indentation in cases like this, so\
3764 \ maybe you have a type but it is not indented enough?"
3768 TTupleIndentTypeN row col ->
3769 let
3770 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3771 region = toRegion row col
3772 in
3773 Report.Report "UNFINISHED TUPLE TYPE" region [] $
3774 Code.toSnippet source surroundings (Just region)
3776 D.reflow $
3777 "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."
3779 D.stack
3780 [ D.fillSep $
3781 ["A","tuple","type","looks","like",D.dullyellow "(Float,Float)","or"
3782 ,D.dullyellow "(String,Int)" <> ","
3783 ,"so","I","think","there","is","a","type","missing","here?"
3785 , D.toSimpleNote $
3786 "I can get confused by indentation in cases like this, so\
3787 \ maybe you have an expression but it is not indented enough?"
3791 TTupleIndentEnd row col ->
3792 let
3793 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3794 region = toRegion row col
3795 in
3796 Report.Report "UNFINISHED PARENTHESES" region [] $
3797 Code.toSnippet source surroundings (Just region)
3799 D.reflow $
3800 "I was expecting to see a closing parenthesis next:"
3802 D.stack
3803 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
3804 , D.toSimpleNote $
3805 "I can get confused by indentation in cases like this, so\
3806 \ maybe you have a closing parenthesis but it is not indented enough?"