on 38c2b40 help sign in
3671 lines 127 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 | TTupleIndentOpen Row Col
453 | TTupleIndentType Row Col
454 | TTupleIndentEnd Row Col
458-- LITERALS
461data Char
462 = CharEndless
463 | CharEscape Escape
464 | CharNotString Word16
467data String
468 = StringEndless_Single
469 | StringEndless_Multi
470 | StringEscape Escape
473data Escape
474 = EscapeUnknown
475 | BadUnicodeFormat Word16
476 | BadUnicodeCode Word16
477 | BadUnicodeLength Word16 Int Int
480data Number
481 = NumberEnd
482 | NumberDot Int
483 | NumberHexDigit
484 | NumberNoLeadingZero
488-- MISC
491data Space
492 = HasTab
493 | EndlessMultiComment
497-- TO REPORT
500toReport :: Code.Source -> Error -> Report.Report
501toReport source err =
502 case err of
503 ModuleNameUnspecified name ->
504 let
505 region = toRegion 1 1
506 in
507 Report.Report "MODULE NAME MISSING" region [] $
508 D.stack
509 [ D.reflow $
510 "I need the module name to be declared at the top of this file, like this:"
511 , D.indent 4 $ D.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))
960toDeclarationsReport :: Code.Source -> Decl -> Report.Report
961toDeclarationsReport source decl =
962 case decl of
963 DeclStart row col ->
964 error "TODO DeclStart" row col
966 DeclSpace space row col ->
967 toSpaceReport source space row col
969 Port port row col ->
970 error "TODO Port" port row col
972 DeclType declType row col ->
973 error "TODO DeclType" declType row col
975 DeclDef name declDef row col ->
976 toDeclDefReport source name declDef row col
978 DeclFreshLineStart row col ->
979 error "TODO DeclFreshLineStart" row col
981 DeclFreshLineAfterDocComment row col ->
982 error "TODO DeclFreshLineAfterDocComment" row col
985toDeclDefReport :: Code.Source -> Name.Name -> DeclDef -> Row -> Col -> Report.Report
986toDeclDefReport source name declDef startRow startCol =
987 case declDef of
988 DeclDefSpace space row col ->
989 toSpaceReport source space row col
991 DeclDefEquals row col ->
992 case Code.whatIsNext source row col of
993 Code.Keyword keyword ->
994 let
995 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
996 region = toWiderRegion row col (fromIntegral (length keyword))
997 in
998 Report.Report "RESERVED WORD" region [] $
999 Code.toSnippet source surroundings (Just region)
1001 D.reflow $
1002 "It looks like you are trying to use `" ++ keyword ++ "` as an argument:"
1004 D.reflow $
1005 "This is a reserved word! Try using some other name?"
1008 Code.Operator op ->
1009 let
1010 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1011 region = toWiderRegion row col (fromIntegral (length op))
1012 in
1013 Report.Report "UNEXPECTED SYMBOL" region [] $
1014 Code.toSnippet source surroundings (Just region)
1016 D.reflow $
1017 "I was not expecting to see this symbol here:"
1019 D.stack
1020 [ D.reflow $
1021 "I am not sure what is going wrong exactly, so here is a valid\
1022 \ definition (with an optional type annotation) for reference:"
1023 , D.vcat
1024 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
1025 , D.fillSep [D.green "add","x","y","="]
1026 , D.fillSep [" ","x","+","y"]
1028 , D.reflow $
1029 "Try to use that format with your `" ++ Name.toChars name ++ "` definition!"
1033 _ ->
1034 let
1035 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1036 region = toRegion row col
1037 in
1038 Report.Report "PROBLEM IN DEFINITION" region [] $
1039 Code.toSnippet source surroundings (Just region)
1041 D.reflow $
1042 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
1044 D.stack
1045 [ D.reflow $
1046 "I am not sure what is going wrong exactly, so here is a valid\
1047 \ definition (with an optional type annotation) for reference:"
1048 , D.vcat
1049 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
1050 , D.fillSep [D.green "add","x","y","="]
1051 , D.fillSep [" ","x","+","y"]
1053 , D.reflow $
1054 "Try to use that format!"
1058 DeclDefType tipe row col ->
1059 error "TODO DeclDefType" toTypeReport tipe row col
1061 DeclDefArg pattern row col ->
1062 toPatternReport source PArg pattern row col
1064 DeclDefBody expr row col ->
1065 toExprReport source (InDef name startRow startCol) expr row col
1067 DeclDefNameRepeat row col ->
1068 let
1069 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1070 region = toRegion row col
1071 in
1072 Report.Report "EXPECTING DEFINITION" region [] $
1073 Code.toSnippet source surroundings (Just region)
1075 D.reflow $
1076 "I just saw the type annotation for `" ++ Name.toChars name
1077 ++ "` so I was expecting to see its definition here:"
1079 D.reflow $
1080 "Type annotations always appear directly above the relevant\
1081 \ definition, without anything else (even doc comments) in between."
1084 DeclDefNameMatch defName row col ->
1085 let
1086 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1087 region = toRegion row col
1088 in
1089 Report.Report "NAME MISMATCH" region [] $
1090 Code.toSnippet source surroundings (Just region)
1092 D.reflow $
1093 "I just saw a type annotation for `" ++ Name.toChars name ++ "`, but it is followed by a definition for `" ++ Name.toChars defName ++ "`:"
1095 D.stack
1096 [ D.reflow $
1097 "These names do not match! Is there a typo?"
1098 , D.indent 4 $ D.fillSep $
1099 [D.dullyellow (D.fromName defName),"->",D.green (D.fromName name)]
1103 DeclDefIndentType row col ->
1104 error "TODO DeclDefIndentType" row col
1106 DeclDefIndentEquals row col ->
1107 error "TODO DeclDefIndentEquals" row col
1109 DeclDefIndentBody row col ->
1110 error "TODO DeclDefIndentBody" row col
1112 DeclDefFreshLineAfterType row col ->
1113 error "TODO DeclDefFreshLineAfterType" row col
1117-- CONTEXT
1120data Context
1121 = InNode Node Row Col Context
1122 | InDef Name.Name Row Col
1125data Node
1126 = NRecord
1127 | NParens
1128 | NList
1129 | NFunc
1130 | NCond
1131 | NThen
1132 | NElse
1133 | NCase
1134 | NBranch
1135 deriving (Eq)
1138getDefName :: Context -> Name.Name
1139getDefName context =
1140 case context of
1141 InDef name _ _ -> name
1142 InNode _ _ _ c -> getDefName c
1145isWithin :: Node -> Context -> Bool
1146isWithin desiredNode context =
1147 case context of
1148 InDef _ _ _ -> False
1149 InNode actualNode _ _ _ -> desiredNode == actualNode
1153-- EXPR REPORTS
1156toExprReport :: Code.Source -> Context -> Expr -> Row -> Col -> Report.Report
1157toExprReport source context expr startRow startCol =
1158 case expr of
1159 Let let_ row col ->
1160 toLetReport source context let_ row col
1162 Case case_ row col ->
1163 toCaseReport source context case_ row col
1165 If if_ row col ->
1166 toIfReport source context if_ row col
1168 List list row col ->
1169 toListReport source context list row col
1171 Record record row col ->
1172 toRecordReport source context record row col
1174 Tuple tuple row col ->
1175 toTupleReport source context tuple row col
1177 Func func row col ->
1178 toFuncReport source context func row col
1180 Dot row col ->
1181 let region = toRegion row col in
1182 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
1183 Code.toSnippet source region Nothing
1185 D.reflow $
1186 "I was expecting to see a record accessor here:"
1188 D.fillSep
1189 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
1190 ,"that","accesses","a","value","from","a","record."
1194 Access row col ->
1195 let region = toRegion row col in
1196 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
1197 Code.toSnippet source region Nothing
1199 D.reflow $
1200 "I am trying to parse a record accessor here:"
1202 D.stack
1204 D.fillSep
1205 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
1206 ,"that","accesses","a","value","from","a","record."
1209 D.toSimpleNote $
1210 "Record field names must start with a lower case letter!"
1214 OperatorRight op row col ->
1215 let region = toRegion row col in
1216 Report.Report "MISSING EXPRESSION" region [] $
1217 Code.toSnippet source region Nothing
1219 D.reflow $
1220 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
1222 D.stack
1223 [ D.fillSep $
1224 ["You","can","just","put","anything","for","now,","like"
1225 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1226 ,"Once","there","is","something","there,","I","can","probably"
1227 ,"give","a","more","specific","hint!"
1229 , D.toSimpleNote $
1230 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
1231 \ Or if I run into operators in unexpected spots. Point is, there are a\
1232 \ couple ways I can get confused and give sort of weird advice!"
1236 OperatorReserved operator row col ->
1237 toOperatorReport source context operator row col
1239 Start row col ->
1240 let
1241 (contextRow, contextCol, aThing) =
1242 case context of
1243 InDef name r c -> (r, c, "the `" ++ Name.toChars name ++ "` definition")
1244 InNode NRecord r c _ -> (r, c, "a record")
1245 InNode NParens r c _ -> (r, c, "some parentheses")
1246 InNode NList r c _ -> (r, c, "a list")
1247 InNode NFunc r c _ -> (r, c, "an anonymous function")
1248 InNode NCond r c _ -> (r, c, "an `if` expression")
1249 InNode NThen r c _ -> (r, c, "an `if` expression")
1250 InNode NElse r c _ -> (r, c, "an `if` expression")
1251 InNode NCase r c _ -> (r, c, "a `case` expression")
1252 InNode NBranch r c _ -> (r, c, "a `case` expression")
1253 -- TODO check if this is actually the best way to get error messages here
1255 surroundings = A.Region (A.Position contextRow contextCol) (A.Position row col)
1256 region = toRegion row col
1257 in
1258 Report.Report "MISSING EXPRESSION" region [] $
1259 Code.toSnippet source surroundings (Just region)
1261 D.reflow $
1262 "I am partway through parsing " ++ aThing ++ ", but I got stuck here:"
1264 D.stack
1265 [ D.fillSep $
1266 ["I","was","expecting","to","see","an","expression","like"
1267 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1268 ,"Once","there","is","something","there,","I","can","probably"
1269 ,"give","a","more","specific","hint!"
1271 , D.toSimpleNote $
1272 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
1273 \ Or if I run into operators in unexpected spots. Point is, there are a\
1274 \ couple ways I can get confused and give sort of weird advice!"
1278 Char char row col ->
1279 toCharReport source char row col
1281 String string row col ->
1282 toStringReport source string row col
1284 Number number row col ->
1285 toNumberReport source number row col
1287 Space space row col ->
1288 toSpaceReport source space row col
1290 EndlessShader row col ->
1291 let
1292 region = toWiderRegion row col 6
1293 in
1294 Report.Report "ENDLESS SHADER" region [] $
1295 Code.toSnippet source region Nothing
1297 D.reflow "I cannot find the end of this shader:"
1299 D.reflow "Add a |] somewhere after this to end the shader."
1302 ShaderProblem problem row col ->
1303 let
1304 region = toRegion row col
1305 in
1306 Report.Report "SHADER PROBLEM" region [] $
1307 Code.toSnippet source region Nothing
1309 D.reflow $
1310 "I ran into a problem while parsing this GLSL block."
1312 D.stack
1313 [ D.reflow $
1314 "I use a 3rd party GLSL parser for now, and I did my best to extract their error message:"
1315 , D.indent 4 $ D.vcat $
1316 map D.fromChars (filter (/="") (lines problem))
1320 IndentOperatorRight op row col ->
1321 let
1322 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1323 region = toRegion row col
1324 in
1325 Report.Report "MISSING EXPRESSION" region [] $
1326 Code.toSnippet source surroundings (Just region)
1328 D.reflow $
1329 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
1331 D.stack
1333 D.fillSep $
1334 ["You","can","just","put","anything","for","now,","like"
1335 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1336 ,"Once","there","is","something","there,","I","can","probably"
1337 ,"give","a","more","specific","hint!"
1340 D.toSimpleNote $
1341 "I may be getting confused by your indentation? The easiest way to make sure\
1342 \ this is not an indentation problem is to put the expression on the right of\
1343 \ the " ++ Name.toChars op ++ " operator on the same line."
1347 IndentMoreExpr _ _ ->
1348 error "TODO IndentMoreExpr"
1352-- CHAR
1355toCharReport :: Code.Source -> Char -> Row -> Col -> Report.Report
1356toCharReport source char row col =
1357 case char of
1358 CharEndless ->
1359 let
1360 region = toRegion row col
1361 in
1362 Report.Report "MISSING SINGLE QUOTE" region [] $
1363 Code.toSnippet source region Nothing
1365 D.reflow $
1366 "I thought I was parsing a character, but I got to the end of\
1367 \ the line without seeing the closing single quote:"
1369 D.reflow $
1370 "Add a closing single quote here!"
1373 CharEscape escape ->
1374 toEscapeReport source escape row col
1376 CharNotString width ->
1377 let
1378 region = toWiderRegion row col width
1379 in
1380 Report.Report "NEEDS DOUBLE QUOTES" region [] $
1381 Code.toSnippet source region Nothing
1383 "The following string uses single quotes:"
1385 D.stack
1386 [ "Please switch to double quotes instead:"
1387 , D.indent 4 $
1388 D.dullyellow "'this'" <> " => " <> D.green "\"this\""
1389 , D.toSimpleNote $
1390 "Elm uses double quotes for strings like \"hello\", whereas it uses single\
1391 \ quotes for individual characters like 'a' and 'ø'. This distinction helps with\
1392 \ code like (String.any (\\c -> c == 'X') \"90210\") where you are inspecting\
1393 \ individual characters."
1399-- STRING
1402toStringReport :: Code.Source -> String -> Row -> Col -> Report.Report
1403toStringReport source string row col =
1404 case string of
1405 StringEndless_Single ->
1406 let
1407 region = toRegion row col
1408 in
1409 Report.Report "ENDLESS STRING" region [] $
1410 Code.toSnippet source region Nothing
1412 D.reflow $
1413 "I got to the end of the line without seeing the closing double quote:"
1415 D.stack
1416 [ D.fillSep $
1417 ["Strings","look","like",D.green "\"this\"","with","double"
1418 ,"quotes","on","each","end.","Is","the","closing","double"
1419 ,"quote","missing","in","your","code?"
1421 , D.link "Note" "Read" "TODO" "if you want a string that spans multiple lines."
1425 StringEndless_Multi ->
1426 let
1427 region = toWiderRegion row col 3
1428 in
1429 Report.Report "ENDLESS STRING" region [] $
1430 Code.toSnippet source region Nothing
1432 D.reflow $
1433 "I cannot find the end of this multi-line string:"
1435 D.stack
1436 [ D.reflow "Add a \"\"\" somewhere after this to end the string."
1437 , D.link "Hint" "Read" "TODO" "for more information on strings and multi-line strings."
1441 StringEscape escape ->
1442 toEscapeReport source escape row col
1446-- ESCAPES
1449toEscapeReport :: Code.Source -> Escape -> Row -> Col -> Report.Report
1450toEscapeReport source escape row col =
1451 case escape of
1452 EscapeUnknown ->
1453 let
1454 region = toWiderRegion row col 2
1455 in
1456 Report.Report "UNKNOWN ESCAPE" region [] $
1457 Code.toSnippet source region Nothing
1459 D.reflow $
1460 "Backslashes always start escaped characters, but I do not recognize this one:"
1462 D.stack
1463 [ D.reflow $
1464 "Valid escape characters include:"
1465 , D.dullyellow $ D.indent 4 $ D.vcat $
1466 [ "\\n"
1467 , "\\r"
1468 , "\\t"
1469 , "\\\""
1470 , "\\\'"
1471 , "\\\\"
1472 , "\\u{003D}"
1474 , D.reflow $
1475 "Do you want one of those instead? Maybe you need \\\\ to escape a backslash?"
1476 , D.toSimpleNote $
1477 "The last style lets encode ANY character by its Unicode code\
1478 \ point. That means \\u{0009} and \\t are the same. You can use\
1479 \ that style for anything not covered by the other six escapes!"
1483 BadUnicodeFormat width ->
1484 let
1485 region = toWiderRegion row col width
1486 in
1487 Report.Report "BAD UNICODE ESCAPE" region [] $
1488 Code.toSnippet source region Nothing
1490 D.reflow $
1491 "I ran into an invalid Unicode escape:"
1493 D.stack
1494 [ D.reflow $
1495 "Here are some examples of valid Unicode escapes:"
1496 , D.dullyellow $ D.indent 4 $ D.vcat $
1497 [ "\\u{0041}"
1498 , "\\u{03BB}"
1499 , "\\u{6728}"
1500 , "\\u{1F60A}"
1502 , D.reflow $
1503 "Notice that the code point is always surrounded by curly braces.\
1504 \ Maybe you are missing the opening or closing curly brace?"
1507 BadUnicodeCode width ->
1508 let
1509 region = toWiderRegion row col width
1510 in
1511 Report.Report "BAD UNICODE ESCAPE" region [] $
1512 Code.toSnippet source region Nothing
1514 D.reflow $
1515 "This is not a valid code point:"
1517 D.reflow $
1518 "The valid code points are between 0 and 10FFFF inclusive."
1521 BadUnicodeLength width numDigits badCode ->
1522 let
1523 region = toWiderRegion row col width
1524 in
1525 Report.Report "BAD UNICODE ESCAPE" region [] $
1526 Code.toSnippet source region Nothing $
1527 if numDigits < 4 then
1529 D.reflow $
1530 "Every code point needs at least four digits:"
1532 let
1533 goodCode = replicate (4 - numDigits) '0' ++ map Char.toUpper (showHex badCode "")
1534 suggestion = "\\u{" <> D.fromChars goodCode <> "}"
1535 in
1536 D.fillSep ["Try",D.green suggestion,"instead?"]
1539 else
1541 D.reflow $
1542 "This code point has too many digits:"
1544 D.fillSep $
1545 ["Valid","code","points","are","between"
1546 ,D.green "\\u{0000}","and",D.green "\\u{10FFFF}" <> ","
1547 ,"so","try","trimming","any","leading","zeros","until"
1548 ,"you","have","between","four","and","six","digits."
1554-- NUMBERS
1557toNumberReport :: Code.Source -> Number -> Row -> Col -> Report.Report
1558toNumberReport source number row col =
1559 let
1560 region = toRegion row col
1561 in
1562 case number of
1563 NumberEnd ->
1564 Report.Report "WEIRD NUMBER" region [] $
1565 Code.toSnippet source region Nothing
1567 D.reflow $
1568 "I thought I was reading a number, but I ran into some weird stuff here:"
1570 D.stack
1571 [ D.reflow $
1572 "I recognize numbers in the following formats:"
1573 , D.indent 4 $ D.vcat [ "42", "3.14", "6.022e23", "0x002B" ]
1574 , D.reflow $
1575 "So is there a way to write it like one of those?"
1579 NumberDot int ->
1580 Report.Report "WEIRD NUMBER" region [] $
1581 Code.toSnippet source region Nothing
1583 D.reflow $
1584 "Numbers cannot end with a dot like this:"
1586 D.fillSep
1587 ["Switching","to",D.green (D.fromChars (show int))
1588 ,"or",D.green (D.fromChars (show int ++ ".0"))
1589 ,"will","work","though!"
1593 NumberHexDigit ->
1594 Report.Report "WEIRD HEXIDECIMAL" region [] $
1595 Code.toSnippet source region Nothing
1597 D.reflow $
1598 "I thought I was reading a hexidecimal number until I got here:"
1600 D.stack
1601 [ D.reflow $
1602 "Valid hexidecimal digits include 0123456789abcdefABCDEF, so I can\
1603 \ only recognize things like this:"
1604 , D.indent 4 $ D.vcat [ "0x2B", "0x002B", "0x00ffb3" ]
1608 NumberNoLeadingZero ->
1609 Report.Report "LEADING ZEROS" region [] $
1610 Code.toSnippet source region Nothing
1612 D.reflow $
1613 "I do not accept numbers with leading zeros:"
1615 D.stack
1616 [ D.reflow $
1617 "Just delete the leading zeros and it should work!"
1618 , D.toSimpleNote $
1619 "Some languages let you to specify octal numbers by adding a leading zero.\
1620 \ So in C, writing 0111 is the same as writing 73. Some people are used to\
1621 \ that, but others probably want it to equal 111. Either path is going to\
1622 \ surprise people from certain backgrounds, so Elm tries to avoid this whole\
1623 \ situation."
1629-- OPERATORS
1632toOperatorReport :: Code.Source -> Context -> BadOperator -> Row -> Col -> Report.Report
1633toOperatorReport source context operator row col =
1634 case operator of
1635 BadDot ->
1636 let
1637 region = toRegion row col
1638 in
1639 Report.Report "UNEXPECTED SYMBOL" region [] $
1640 Code.toSnippet source region Nothing
1642 "I was not expecting this dot:"
1644 D.reflow $
1645 "Dots are for record access and decimal points, so\
1646 \ they cannot float around on their own. Maybe\
1647 \ there is some extra whitespace?"
1650 BadPipe ->
1651 let
1652 region = toRegion row col
1653 in
1654 Report.Report "UNEXPECTED SYMBOL" region [] $
1655 Code.toSnippet source region Nothing
1657 D.reflow $
1658 "I was not expecting this vertical bar:"
1660 D.reflow $
1661 "Vertical bars should only appear in custom type declarations. Maybe you want || instead?"
1664 BadArrow ->
1665 let
1666 region = toWiderRegion row col 2
1667 in
1668 Report.Report "UNEXPECTED ARROW" region [] $
1669 Code.toSnippet source region Nothing $
1670 if isWithin NBranch context then
1672 D.reflow $
1673 "I was not expecting to see an arrow here:"
1675 D.stack
1677 D.reflow $
1678 "I think I am parsing a `case` expression right now, so it makes sense to\
1679 \ see arrows around here. This one is confusing me though!"
1681 D.toSimpleHint $
1682 "I may be getting confused by the indentation. Every pattern in a `case` must be\
1683 \ exactly aligned (with exactly the same amount of indentation) so maybe this arrow\
1684 \ appears after the next `case` pattern (correctly!) but the pattern itself is\
1685 \ indented too far?"
1689 else
1691 D.reflow $
1692 "I was not expecting an arrow here:"
1694 D.reflow $
1695 "Arrows should only appear in `case` expressions and anonymous functions. Maybe\
1696 \ you want > or >= instead?"
1699 BadEquals ->
1700 let
1701 region = toRegion row col
1702 name = getDefName context
1703 in
1704 Report.Report "UNEXPECTED EQUALS" region [] $
1705 Code.toSnippet source region Nothing
1707 D.reflow $
1708 "I was not expecting to see this equals sign:"
1710 D.stack
1712 D.reflow "Maybe you want == instead? To check if two values are equal?"
1714 D.toSimpleNote $
1715 if isWithin NRecord context then
1716 "Records look like { x = 3, y = 4 } with the equals sign right\
1717 \ after the field name. So maybe you forgot a comma?"
1718 else
1719 "I may be getting confused by your indentation. Is this supposed to be part of\
1720 \ a definition AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
1721 \ the problem may be a bit before the equals sign. I need all definitions to\
1722 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
1723 \ this new definition is indented a bit too much."
1727 BadHasType ->
1728 let
1729 region = toRegion row col
1730 name = getDefName context
1731 in
1732 Report.Report "UNEXPECTED SYMBOL" region [] $
1733 Code.toSnippet source region Nothing $
1735 D.reflow $
1736 "I was not expecting to run into the \"has type\" symbol here:"
1738 D.stack
1740 D.fillSep
1741 ["Maybe","you","want",D.green "::","instead?"
1742 ,"To","put","something","on","the","front","of","a","list?"
1744 , D.toSimpleNote $
1745 "The single colon is reserved for type annotations and record types, but I think\
1746 \ I am parsing the definition of `" ++ Name.toChars name ++ "` right now."
1748 D.toSimpleNote $
1749 "I may be getting confused by your indentation. Is this supposed to be part of\
1750 \ a type annotation AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
1751 \ the problem may be a bit before the \"has type\" symbol. I need all definitions to\
1752 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
1753 \ this new definition is indented a bit too much."
1759-- CASE
1762toLetReport :: Code.Source -> Context -> Let -> Row -> Col -> Report.Report
1763toLetReport source context let_ startRow startCol =
1764 case let_ of
1765 LetSpace space row col ->
1766 toSpaceReport source space row col
1768 LetIn row col ->
1769 let
1770 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1771 region = toRegion row col
1772 in
1773 Report.Report "LET PROBLEM" region [] $
1774 Code.toSnippet source surroundings (Just region)
1776 D.reflow $
1777 "I was partway through parsing a `let` expression, but I got stuck here:"
1779 D.stack
1780 [ D.fillSep $
1781 ["Based","on","the","indentation,","I","was","expecting","to","see","the",D.cyan "in"
1782 ,"keyword","next.","Is","there","a","typo?"
1784 , D.toSimpleNote $
1785 "This can also happen if you are trying to define another value within the `let` but\
1786 \ it is not indented enough. Make sure each definition has exactly the same amount of\
1787 \ spaces before it. They should line up exactly!"
1791 LetDefAlignment _ row col ->
1792 let
1793 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1794 region = toRegion row col
1795 in
1796 Report.Report "LET PROBLEM" region [] $
1797 Code.toSnippet source surroundings (Just region)
1799 D.reflow $
1800 "I was partway through parsing a `let` expression, but I got stuck here:"
1802 D.stack
1803 [ D.fillSep $
1804 ["Based","on","the","indentation,","I","was","expecting","to","see","the",D.cyan "in"
1805 ,"keyword","next.","Is","there","a","typo?"
1807 , D.toSimpleNote $
1808 "This can also happen if you are trying to define another value within the `let` but\
1809 \ it is not indented enough. Make sure each definition has exactly the same amount of\
1810 \ spaces before it. The should line up exactly!"
1814 LetDefName row col ->
1815 case Code.whatIsNext source row col of
1816 Code.Keyword keyword ->
1817 let
1818 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1819 region = toWiderRegion row col (fromIntegral (length keyword))
1820 in
1821 Report.Report "RESERVED WORD" region [] $
1822 Code.toSnippet source surroundings (Just region)
1824 D.reflow $
1825 "I was partway through parsing a `let` expression, but I got stuck here:"
1827 D.reflow $
1828 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name, but\
1829 \ it is a reserved word! Try using a different name instead."
1832 _ ->
1833 toUnfinishLetReport source row col startRow startCol $
1834 D.reflow $
1835 "I was expecting the name of a definition next."
1837 LetDef name def row col ->
1838 error "TODO LetDef" name def row col
1840 LetDestruct destruct row col ->
1841 error "TODO LetDestruct" destruct row col
1843 LetBody expr row col ->
1844 toExprReport source context expr row col
1846 LetIndentDef row col ->
1847 toUnfinishLetReport source row col startRow startCol $
1848 D.reflow $
1849 "I was expecting a value to be defined here."
1851 LetIndentIn row col ->
1852 toUnfinishLetReport source row col startRow startCol $
1853 D.fillSep $
1854 ["I","was","expecting","to","see","the",D.cyan "in","keyword","next."
1855 ,"Or","maybe","more","of","that","expression?"
1858 LetIndentBody row col ->
1859 toUnfinishLetReport source row col startRow startCol $
1860 D.reflow $
1861 "I was expecting an expression next. Tell me what should happen with the value you just defined!"
1864toUnfinishLetReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
1865toUnfinishLetReport source row col startRow startCol message =
1866 let
1867 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1868 region = toRegion row col
1869 in
1870 Report.Report "UNFINISHED LET" region [] $
1871 Code.toSnippet source surroundings (Just region)
1873 D.reflow $
1874 "I was partway through parsing a `let` expression, but I got stuck here:"
1876 D.stack
1877 [ message
1878 , D.toSimpleNote $
1879 "Here is an example with a valid `let` expression for reference:"
1880 , D.vcat $
1881 [ D.indent 0 $ D.fillSep [D.green "viewPerson","person","="]
1882 , D.indent 2 $ D.fillSep [D.cyan "let"]
1883 , D.indent 4 $ D.fillSep ["fullName","="]
1884 , D.indent 6 $ D.fillSep ["person.firstName","++",D.dullyellow "\" \"","++","person.lastName"]
1885 , D.indent 2 $ D.fillSep [D.cyan "in"]
1886 , D.indent 2 $ D.fillSep ["div","[]","[","text","fullName","]"]
1888 , D.reflow $
1889 "Here we defined a `viewPerson` function that turns a person into some HTML. We use\
1890 \ a `let` expression to define the `fullName` we want to show. Notice the indentation! The\
1891 \ `fullName` is indented more than the `let` keyword, and the actual value of `fullName` is\
1892 \ indented a bit more than that. That is important!"
1898-- CASE
1901toCaseReport :: Code.Source -> Context -> Case -> Row -> Col -> Report.Report
1902toCaseReport source context case_ startRow startCol =
1903 case case_ of
1904 CaseSpace space row col ->
1905 toSpaceReport source space row col
1907 CaseOf row col ->
1908 toUnfinishCaseReport source row col startRow startCol $
1909 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
1911 CasePattern pattern row col ->
1912 toPatternReport source PCase pattern row col
1914 CaseArrow row col ->
1915 let
1916 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1917 region = toRegion row col
1918 in
1919 case Code.whatIsNext source row col of
1920 Code.Keyword keyword ->
1921 Report.Report "RESERVED WORD" region [] $
1922 Code.toSnippet source surroundings (Just region)
1924 D.reflow $
1925 "I am partway through parsing a `case` expression, but I got stuck here:"
1927 D.reflow $
1928 "It looks like you are trying to use `" ++ keyword ++ "` in one of your\
1929 \ patterns, but it is a reserved word. Try using a different name?"
1932 Code.Operator ":" ->
1933 Report.Report "UNEXPECTED OPERATOR" region [] $
1934 Code.toSnippet source surroundings (Just region)
1936 D.reflow $
1937 "I am partway through parsing a `case` expression, but I got stuck here:"
1939 D.fillSep $
1940 ["I","am","seeing",D.dullyellow ":","but","maybe","you","want",D.green "::","instead?"
1941 ,"For","pattern","matching","on","lists?"
1945 Code.Operator "=" ->
1946 Report.Report "UNEXPECTED OPERATOR" region [] $
1947 Code.toSnippet source surroundings (Just region)
1949 D.reflow $
1950 "I am partway through parsing a `case` expression, but I got stuck here:"
1952 D.fillSep $
1953 ["I","am","seeing",D.dullyellow "=","but","maybe","you","want",D.green "->","instead?"
1957 _ ->
1958 Report.Report "MISSING ARROW" region [] $
1959 Code.toSnippet source surroundings (Just region)
1961 D.reflow $
1962 "I am partway through parsing a `case` expression, but I got stuck here:"
1964 addNoteForCaseIndentError $
1965 D.reflow $
1966 "I was expecting to see an arrow next."
1969 CaseExpr expr row col ->
1970 toExprReport source (InNode NCase startRow startCol context) expr row col
1972 CaseBranch expr row col ->
1973 toExprReport source (InNode NBranch startRow startCol context) expr row col
1975 CaseIndentOf row col ->
1976 toUnfinishCaseReport source row col startRow startCol $
1977 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
1979 CaseIndentExpr row col ->
1980 toUnfinishCaseReport source row col startRow startCol $
1981 D.reflow "I was expecting to see a expression next."
1983 CaseIndentPattern row col ->
1984 toUnfinishCaseReport source row col startRow startCol $
1985 D.reflow "I was expecting to see a pattern next."
1987 CaseIndentArrow row col ->
1988 toUnfinishCaseReport source row col startRow startCol $
1989 D.fillSep
1990 ["I","just","saw","a","pattern,","so","I","was","expecting"
1991 ,"to","see","a",D.dullyellow "->","next."
1994 CaseIndentBranch row col ->
1995 toUnfinishCaseReport source row col startRow startCol $
1996 D.reflow $
1997 "I was expecting to see an expression next. What should I do when\
1998 \ I run into this particular pattern?"
2000 CasePatternAlignment indent row col ->
2001 toUnfinishCaseReport source row col startRow startCol $
2002 D.reflow $
2003 "I suspect this is a pattern that is not indented far enough? (" ++ show indent ++ " spaces)"
2006toUnfinishCaseReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
2007toUnfinishCaseReport source row col startRow startCol message =
2008 let
2009 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2010 region = toRegion row col
2011 in
2012 Report.Report "UNFINISHED CASE" region [] $
2013 Code.toSnippet source surroundings (Just region)
2015 D.reflow $
2016 "I was partway through parsing a `case` expression, but I got stuck here:"
2018 D.stack
2019 [ message
2020 , D.toSimpleNote $
2021 "Here is an example of a valid `case` expression for reference."
2022 , D.vcat $
2023 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
2024 , D.indent 6 $ D.fillSep [D.green "Just","width","->"]
2025 , D.indent 8 $ D.fillSep ["width","+",D.dullyellow "200"]
2026 , ""
2027 , D.indent 6 $ D.fillSep [D.green "Nothing","->"]
2028 , D.indent 8 $ D.fillSep [D.dullyellow "400"]
2030 , D.reflow $
2031 "Notice the indentation. Each pattern is aligned, and each branch is indented\
2032 \ a bit more than the corresponding pattern. That is important!"
2037addNoteForCaseIndentError :: D.Doc -> D.Doc
2038addNoteForCaseIndentError message =
2039 D.stack $
2040 message
2042 [ D.toSimpleNote $
2043 "Sometimes I get confused by indentation, so try to make your `case` look\
2044 \ something like this:"
2045 , D.vcat $
2046 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
2047 , D.indent 6 $ D.fillSep [D.green "Just","width","->"]
2048 , D.indent 8 $ D.fillSep ["width","+",D.dullyellow "200"]
2049 , ""
2050 , D.indent 6 $ D.fillSep [D.green "Nothing","->"]
2051 , D.indent 8 $ D.fillSep [D.dullyellow "400"]
2053 , D.reflow $
2054 "Notice the indentation! Each pattern is aligned, and each branch is indented\
2055 \ a bit more than the corresponding pattern. That is important!"
2060-- IF
2063toIfReport :: Code.Source -> Context -> If -> Row -> Col -> Report.Report
2064toIfReport source context if_ startRow startCol =
2065 case if_ of
2066 IfSpace space row col ->
2067 toSpaceReport source space row col
2069 IfThen row col ->
2070 let
2071 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2072 region = toRegion row col
2073 in
2074 Report.Report "UNFINISHED IF" region [] $
2075 Code.toSnippet source surroundings (Just region)
2077 D.reflow $
2078 "I was expecting to see more of this `if` expression, but I got stuck here:"
2080 D.fillSep $
2081 ["I","was","expecting","to","see","the",D.cyan "then","keyword","next."
2085 IfElse row col ->
2086 let
2087 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2088 region = toRegion row col
2089 in
2090 Report.Report "UNFINISHED IF" region [] $
2091 Code.toSnippet source surroundings (Just region)
2093 D.reflow $
2094 "I was expecting to see more of this `if` expression, but I got stuck here:"
2096 D.fillSep $
2097 ["I","was","expecting","to","see","the",D.cyan "else","keyword","next."
2101 IfElseBranchStart row col ->
2102 let
2103 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2104 region = toRegion row col
2105 in
2106 Report.Report "UNFINISHED IF" region [] $
2107 Code.toSnippet source surroundings (Just region)
2109 D.reflow $
2110 "I just saw the start of an `else` branch, but then I got stuck here:"
2112 D.reflow $
2113 "I was expecting to see an expression next. Maybe it is not filled in yet?"
2116 IfCondition expr row col ->
2117 toExprReport source (InNode NCond startRow startCol context) expr row col
2119 IfThenBranch expr row col ->
2120 toExprReport source (InNode NThen startRow startCol context) expr row col
2122 IfElseBranch expr row col ->
2123 toExprReport source (InNode NElse startRow startCol context) expr row col
2125 IfIndentCondition row col ->
2126 let
2127 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2128 region = toRegion row col
2129 in
2130 Report.Report "UNFINISHED IF" region [] $
2131 Code.toSnippet source surroundings (Just region)
2133 D.reflow $
2134 "I was expecting to see more of this `if` expression, but I got stuck here:"
2136 D.stack
2137 [ D.fillSep $
2138 ["I","was","expecting","to","see","an","expression","like",D.dullyellow "x < 0"
2139 ,"that","evaluates","to","True","or","False."
2141 , D.toSimpleNote $
2142 "I can be confused by indentation. Maybe something is not indented enough?"
2146 IfIndentThen row col ->
2147 let
2148 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2149 region = toRegion row col
2150 in
2151 Report.Report "UNFINISHED IF" region [] $
2152 Code.toSnippet source surroundings (Just region)
2154 D.reflow $
2155 "I was expecting to see more of this `if` expression, but I got stuck here:"
2157 D.stack
2158 [ D.fillSep $
2159 ["I","was","expecting","to","see","the",D.cyan "then","keyword","next."
2161 , D.toSimpleNote $
2162 "I can be confused by indentation. Maybe something is not indented enough?"
2166 IfIndentThenBranch row col ->
2167 let
2168 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2169 region = toRegion row col
2170 in
2171 Report.Report "UNFINISHED IF" region [] $
2172 Code.toSnippet source surroundings (Just region)
2174 D.reflow $
2175 "I got stuck after the start of this `then` branch:"
2177 D.stack
2178 [ D.reflow $
2179 "I was expecting to see an expression next. Maybe it is not filled in yet?"
2180 , D.toSimpleNote $
2181 "I can be confused by indentation, so if the `then` branch is already\
2182 \ present, it may not be indented enough for me to recognize it."
2186 IfIndentElseBranch row col ->
2187 let
2188 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2189 region = toRegion row col
2190 in
2191 Report.Report "UNFINISHED IF" region [] $
2192 Code.toSnippet source surroundings (Just region)
2194 D.reflow $
2195 "I got stuck after the start of this `else` branch:"
2197 D.stack
2198 [ D.reflow $
2199 "I was expecting to see an expression next. Maybe it is not filled in yet?"
2200 , D.toSimpleNote $
2201 "I can be confused by indentation, so if the `else` branch is already\
2202 \ present, it may not be indented enough for me to recognize it."
2206 IfIndentElse row col ->
2207 let
2208 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2209 region = toRegion row col
2210 in
2211 Report.Report "UNFINISHED IF" region [] $
2212 Code.toSnippet source surroundings (Just region)
2214 D.reflow $
2215 "I was expecting to see an `else` branch after this:"
2217 D.stack
2218 [ D.reflow $
2219 "I know what to do when the condition is `True`, but not when it is `False`."
2220 , D.fillSep
2221 ["Add","an",D.cyan "else","branch","to","handle","that","scenario!"]
2227-- RECORD
2230toRecordReport :: Code.Source -> Context -> Record -> Row -> Col -> Report.Report
2231toRecordReport source context record startRow startCol =
2232 case record of
2233 RecordOpen row col ->
2234 let
2235 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2236 region = toRegion row col
2237 in
2238 case Code.whatIsNext source row col of
2239 Code.Keyword keyword ->
2240 Report.Report "RESERVED WORD" region [] $
2241 Code.toSnippet source surroundings (Just region)
2243 D.reflow $
2244 "I just started parsing a record, but I got stuck on this field name:"
2246 D.reflow $
2247 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
2248 \ that is a reserved word. Try using a different name!"
2251 _ ->
2252 Report.Report "UNFINISHED RECORD" region [] $
2253 Code.toSnippet source surroundings (Just region)
2255 D.reflow $
2256 "I just started parsing a record, but I got stuck here:"
2258 D.fillSep
2259 ["Records","look","like",D.dullyellow "{ x = 3, y = 4 },"
2260 ,"so","I","was","expecting","to","see","a","field","name","next."
2264 RecordEnd row col ->
2265 let
2266 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2267 region = toRegion row col
2268 in
2269 Report.Report "UNFINISHED RECORD" region [] $
2270 Code.toSnippet source surroundings (Just region)
2272 D.reflow $
2273 "I am partway through parsing a record, but I got stuck here:"
2275 D.stack
2276 [ D.fillSep
2277 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
2278 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
2280 , D.toSimpleNote $
2281 "When I get stuck like this, it usually means that there is a missing parenthesis\
2282 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
2286 RecordField row col ->
2287 case Code.whatIsNext source row col of
2288 Code.Keyword keyword ->
2289 let
2290 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2291 region = toWiderRegion row col (fromIntegral (length keyword))
2292 in
2293 Report.Report "RESERVED WORD" region [] $
2294 Code.toSnippet source surroundings (Just region)
2296 D.reflow $
2297 "I am partway through parsing a record, but I got stuck on this field name:"
2299 D.reflow $
2300 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
2301 \ that is a reserved word. Try using a different name!"
2304 _ ->
2305 let
2306 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2307 region = toRegion row col
2308 in
2309 Report.Report "UNFINISHED RECORD" region [] $
2310 Code.toSnippet source surroundings (Just region)
2312 D.reflow $
2313 "I am partway through parsing a record, but I got stuck after that last comma:"
2315 addNoteForRecordError $
2316 D.reflow $
2317 "Trailing commas are not allowed in records, so I was expecting to see another\
2318 \ record field defined next. If you are done defining the record, the fix may\
2319 \ be to delete that last comma?"
2322 RecordEquals row col ->
2323 let
2324 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2325 region = toRegion row col
2326 in
2327 Report.Report "UNFINISHED RECORD" region [] $
2328 Code.toSnippet source surroundings (Just region)
2330 D.reflow $
2331 "I am partway through parsing a record, but I got stuck here:"
2333 addNoteForRecordError $
2334 D.fillSep $
2335 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
2336 ,"an","equals","sign","next.","So","try","putting","an",D.green "=","sign","here?"
2340 RecordExpr expr row col ->
2341 toExprReport source (InNode NRecord startRow startCol context) expr row col
2343 RecordSpace space row col ->
2344 toSpaceReport source space row col
2346 RecordIndentOpen row col ->
2347 let
2348 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2349 region = toRegion row col
2350 in
2351 Report.Report "UNFINISHED RECORD" region [] $
2352 Code.toSnippet source surroundings (Just region)
2354 D.reflow $
2355 "I just saw the opening curly brace of a record, but then I got stuck here:"
2357 addNoteForRecordIndentError $
2358 D.fillSep $
2359 ["I","am","expecting","a","record","like",D.dullyellow "{ x = 3, y = 4 }","here."
2360 ,"Try","defining","some","fields","of","your","own?"
2364 RecordIndentEnd row col ->
2365 let
2366 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2367 region = toRegion row col
2368 in
2369 Report.Report "UNFINISHED RECORD" region [] $
2370 Code.toSnippet source surroundings (Just region)
2372 D.reflow $
2373 "I was expecting to see a closing curly brace next:"
2375 addNoteForRecordIndentError $
2376 D.fillSep $
2377 ["Try","putting","an",D.green "}","and","see","if","that","helps?"
2381 RecordIndentField row col ->
2382 let
2383 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2384 region = toRegion row col
2385 in
2386 Report.Report "UNFINISHED RECORD" region [] $
2387 Code.toSnippet source surroundings (Just region)
2389 D.reflow $
2390 "I am partway through parsing a record, but I got stuck after that last comma:"
2392 addNoteForRecordError $
2393 D.reflow $
2394 "Trailing commas are not allowed in records, so the fix may be to\
2395 \ delete that last comma? Or maybe you were in the middle of defining\
2396 \ an additional field?"
2399 RecordIndentEquals row col ->
2400 let
2401 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2402 region = toRegion row col
2403 in
2404 Report.Report "UNFINISHED RECORD" region [] $
2405 Code.toSnippet source surroundings (Just region)
2407 D.reflow $
2408 "I am partway through parsing a record. I just saw a record\
2409 \ field, so I was expecting to see an equals sign next:"
2411 addNoteForRecordIndentError $
2412 D.fillSep $
2413 ["Try","putting","an",D.green "=","followed","by","an","expression?"
2417 RecordIndentExpr row col ->
2418 let
2419 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2420 region = toRegion row col
2421 in
2422 Report.Report "UNFINISHED RECORD" region [] $
2423 Code.toSnippet source surroundings (Just region)
2425 D.reflow $
2426 "I am partway through parsing a record, and I was expecting to run into an expression next:"
2428 addNoteForRecordIndentError $
2429 D.fillSep $
2430 ["Try","putting","something,","like"
2431 ,D.dullyellow "42","or",D.dullyellow"\"hello\"","for","now?"
2436addNoteForRecordError :: D.Doc -> D.Doc
2437addNoteForRecordError normalRecommendation =
2438 D.stack $
2439 normalRecommendation
2441 [ D.toSimpleNote
2442 "If you are trying to define a record across multiple lines, I recommend using this format:"
2443 , D.indent 4 $ D.vcat $
2444 [ "{ name = \"Alice\""
2445 , ", age = 42"
2446 , ", height = 1.75"
2447 , "}"
2449 , D.reflow $
2450 "Notice that each line starts with some indentation. Usually two or four spaces. I\
2451 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
2452 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2456addNoteForRecordIndentError :: D.Doc -> D.Doc
2457addNoteForRecordIndentError normalRecommendation =
2458 D.stack $
2459 normalRecommendation
2461 [ D.toSimpleNote
2462 "I may be confused by indentation. For example, if you are trying to define\
2463 \ a record across multiple lines, I recommend using this format:"
2464 , D.indent 4 $ D.vcat $
2465 [ "{ name = \"Alice\""
2466 , ", age = 42"
2467 , ", height = 1.75"
2468 , "}"
2470 , D.reflow $
2471 "Notice that each line starts with some indentation. Usually two or four spaces. I\
2472 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
2473 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2478-- TUPLE
2481toTupleReport :: Code.Source -> Context -> Tuple -> Row -> Col -> Report.Report
2482toTupleReport source context tuple startRow startCol =
2483 case tuple of
2484 TupleExpr expr row col ->
2485 toExprReport source (InNode NParens startRow startCol context) expr row col
2487 TupleSpace space row col ->
2488 toSpaceReport source space row col
2490 TupleEnd row col ->
2491 let
2492 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2493 region = toRegion row col
2494 in
2495 Report.Report "UNFINISHED PARENTHESES" region [] $
2496 Code.toSnippet source surroundings (Just region)
2498 D.reflow $
2499 "I was expecting to see a closing parentheses next, but I got stuck here:"
2501 D.stack
2502 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
2503 , D.toSimpleNote $
2504 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
2505 \ unexpectedly. So there may be some earlier syntax trouble (like extra parenthesis\
2506 \ or missing brackets) that is confusing me."
2510 TupleOperatorClose row col ->
2511 let
2512 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2513 region = toRegion row col
2514 in
2515 Report.Report "UNFINISHED OPERATOR FUNCTION" region [] $
2516 Code.toSnippet source surroundings (Just region)
2518 D.reflow "I was expecting a closing parenthesis here:"
2520 D.stack
2521 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
2522 , D.toSimpleNote $
2523 "I think I am parsing an operator function right now, so I am expecting to see\
2524 \ something like (+) or (&&) where an operator is surrounded by parentheses with\
2525 \ no extra spaces."
2529 TupleOperatorReserved operator row col ->
2530 let
2531 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2532 region = toRegion row col
2533 in
2534 Report.Report "UNEXPECTED SYMBOL" region [] $
2535 Code.toSnippet source surroundings (Just region)
2537 D.reflow $
2538 "I ran into an unexpected symbol here:"
2540 D.fillSep $
2541 case operator of
2542 BadDot -> ["Maybe","you","wanted","a","record","accessor","like",D.dullyellow ".x","or",D.dullyellow ".name","instead?"]
2543 BadPipe -> ["Try",D.dullyellow "(||)","instead?","To","turn","boolean","OR","into","a","function?"]
2544 BadArrow -> ["Maybe","you","wanted",D.dullyellow "(>)","or",D.dullyellow "(>=)","instead?"]
2545 BadEquals -> ["Try",D.dullyellow "(==)","instead?","To","make","a","function","that","checks","equality?"]
2546 BadHasType -> ["Try",D.dullyellow "(::)","instead?","To","add","values","to","the","front","of","lists?"]
2549 TupleIndentExpr1 row col ->
2550 let
2551 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2552 region = toRegion row col
2553 in
2554 Report.Report "UNFINISHED PARENTHESES" region [] $
2555 Code.toSnippet source surroundings (Just region)
2557 D.reflow $
2558 "I just saw an open parenthesis, so I was expecting to see an expression next."
2560 D.stack
2561 [ D.fillSep $
2562 ["Something","like",D.dullyellow "(4 + 5)","or"
2563 ,D.dullyellow "(String.reverse \"desserts\")" <> "."
2564 ,"Anything","where","you","are","putting","parentheses","around","normal","expressions."
2566 , D.toSimpleNote $
2567 "I can get confused by indentation in cases like this, so\
2568 \ maybe you have an expression but it is not indented enough?"
2572 TupleIndentExprN 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 TUPLE" region [] $
2578 Code.toSnippet source surroundings (Just region)
2580 D.reflow $
2581 "I think I am in the middle of parsing a tuple. I just saw a comma, so I was expecting to see expression next."
2583 D.stack
2584 [ D.fillSep $
2585 ["A","tuple","looks","like",D.dullyellow "(3,4)","or"
2586 ,D.dullyellow "(\"Tom\",42)" <> ","
2587 ,"so","I","think","there","is","an","expression","missing","here?"
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 TupleIndentEnd 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 PARENTHESES" region [] $
2601 Code.toSnippet source surroundings (Just region)
2603 D.reflow $
2604 "I was expecting to see a closing parenthesis next:"
2606 D.stack
2607 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
2608 , D.toSimpleNote $
2609 "I can get confused by indentation in cases like this, so\
2610 \ maybe you have a closing parenthesis but it is not indented enough?"
2615toListReport :: Code.Source -> Context -> List -> Row -> Col -> Report.Report
2616toListReport source context list startRow startCol =
2617 case list of
2618 ListSpace space row col ->
2619 toSpaceReport source space row col
2621 ListOpen row col ->
2622 let
2623 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2624 region = toRegion row col
2625 in
2626 Report.Report "UNFINISHED LIST" region [] $
2627 Code.toSnippet source surroundings (Just region)
2629 D.reflow $
2630 "I am partway through parsing a list, but I got stuck here:"
2632 D.stack
2633 [ D.fillSep
2634 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
2635 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
2637 , D.toSimpleNote $
2638 "When I get stuck like this, it usually means that there is a missing parenthesis\
2639 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
2643 ListExpr expr row col ->
2644 case expr of
2645 Start r c ->
2646 let
2647 surroundings = A.Region (A.Position startRow startCol) (A.Position r c)
2648 region = toRegion r c
2649 in
2650 Report.Report "UNFINISHED LIST" region [] $
2651 Code.toSnippet source surroundings (Just region)
2653 D.reflow $
2654 "I was expecting to see another list entry after that last comma:"
2656 D.stack
2657 [ D.reflow $
2658 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
2659 , D.toSimpleNote
2660 "I recommend using the following format for lists that span multiple lines:"
2661 , D.indent 4 $ D.vcat $
2662 [ "[ \"Alice\""
2663 , ", \"Bob\""
2664 , ", \"Chuck\""
2665 , "]"
2667 , D.reflow $
2668 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2669 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2670 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2674 _ ->
2675 toExprReport source (InNode NList startRow startCol context) expr row col
2677 ListEnd row col ->
2678 let
2679 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2680 region = toRegion row col
2681 in
2682 Report.Report "UNFINISHED LIST" region [] $
2683 Code.toSnippet source surroundings (Just region)
2685 D.reflow $
2686 "I am partway through parsing a list, but I got stuck here:"
2688 D.stack
2689 [ D.fillSep
2690 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
2691 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
2693 , D.toSimpleNote $
2694 "When I get stuck like this, it usually means that there is a missing parenthesis\
2695 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
2699 ListIndentOpen row col ->
2700 let
2701 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2702 region = toRegion row col
2703 in
2704 Report.Report "UNFINISHED LIST" region [] $
2705 Code.toSnippet source surroundings (Just region)
2707 D.reflow $
2708 "I cannot find the end of this list:"
2710 D.stack
2711 [ D.fillSep $
2712 ["You","could","change","it","to","something","like"
2713 ,D.dullyellow "[3,4,5]"
2714 ,"or","even","just"
2715 ,D.dullyellow "[]" <> "."
2716 ,"Anything","where","there","is","an","open","and","close","square","brace,"
2717 ,"and","where","the","elements","of","the","list","are","separated","by","commas."
2719 , D.toSimpleNote
2720 "I may be confused by indentation. For example, if you are trying to define\
2721 \ a list across multiple lines, I recommend using this format:"
2722 , D.indent 4 $ D.vcat $
2723 [ "[ \"Alice\""
2724 , ", \"Bob\""
2725 , ", \"Chuck\""
2726 , "]"
2728 , D.reflow $
2729 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2730 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2731 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2735 ListIndentEnd row col ->
2736 let
2737 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2738 region = toRegion row col
2739 in
2740 Report.Report "UNFINISHED LIST" region [] $
2741 Code.toSnippet source surroundings (Just region)
2743 D.reflow $
2744 "I cannot find the end of this list:"
2746 D.stack
2747 [ D.fillSep $
2748 ["You","can","just","add","a","closing",D.dullyellow "]"
2749 ,"right","here,","and","I","will","be","all","set!"
2751 , D.toSimpleNote
2752 "I may be confused by indentation. For example, if you are trying to define\
2753 \ a list across multiple lines, I recommend using this format:"
2754 , D.indent 4 $ D.vcat $
2755 [ "[ \"Alice\""
2756 , ", \"Bob\""
2757 , ", \"Chuck\""
2758 , "]"
2760 , D.reflow $
2761 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2762 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2763 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2767 ListIndentExpr row col ->
2768 let
2769 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2770 region = toRegion row col
2771 in
2772 Report.Report "UNFINISHED LIST" region [] $
2773 Code.toSnippet source surroundings (Just region)
2775 D.reflow $
2776 "I was expecting to see another list entry after this comma:"
2778 D.stack
2779 [ D.reflow $
2780 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
2781 , D.toSimpleNote
2782 "I recommend using the following format for lists that span multiple lines:"
2783 , D.indent 4 $ D.vcat $
2784 [ "[ \"Alice\""
2785 , ", \"Bob\""
2786 , ", \"Chuck\""
2787 , "]"
2789 , D.reflow $
2790 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2791 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2792 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2797toFuncReport :: Code.Source -> Context -> Func -> Row -> Col -> Report.Report
2798toFuncReport source context func startRow startCol =
2799 case func of
2800 FuncSpace space row col ->
2801 toSpaceReport source space row col
2803 FuncArg pattern row col ->
2804 toPatternReport source PArg pattern row col
2806 FuncBody expr row col ->
2807 toExprReport source (InNode NFunc startRow startCol context) expr row col
2809 FuncArrow row col ->
2810 let
2811 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2812 region = toRegion row col
2813 in
2814 case Code.whatIsNext source row col of
2815 Code.Keyword keyword ->
2816 Report.Report "RESERVED WORD" region [] $
2817 Code.toSnippet source surroundings (Just region)
2819 D.reflow $
2820 "I was parsing an anonymous function, but I got stuck here:"
2822 D.reflow $
2823 "It looks like you are trying to use `" ++ keyword ++ "` as an argument, but\
2824 \ it is a reserved word in this language. Try using a different argument name!"
2827 _ ->
2828 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
2829 Code.toSnippet source surroundings (Just region)
2831 D.reflow $
2832 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
2834 D.fillSep $
2835 ["The","syntax","for","anonymous","functions","is"
2836 ,D.dullyellow "(\\x -> x + 1)"
2837 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
2841 FuncIndentArg row col ->
2842 let
2843 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2844 region = toRegion row col
2845 in
2846 Report.Report "MISSING ARGUMENT" region [] $
2847 Code.toSnippet source surroundings (Just region)
2849 D.reflow $
2850 "I just saw the beginning of an anonymous function, so I was expecting to see an argument next:"
2852 D.stack
2853 [ D.fillSep
2854 ["Something","like",D.dullyellow"x","or",D.dullyellow "name" <> "."
2855 ,"Anything","that","starts","with","a","lower","case","letter!"
2857 , D.toSimpleNote $
2858 "The syntax for anonymous functions is (\\x -> x + 1) where the backslash\
2859 \ is meant to look a bit like a lambda if you squint. This visual pun seemed\
2860 \ like a better idea at the time!"
2864 FuncIndentArrow row col ->
2865 let
2866 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2867 region = toRegion row col
2868 in
2869 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
2870 Code.toSnippet source surroundings (Just region)
2872 D.reflow $
2873 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
2875 D.stack
2876 [ D.fillSep $
2877 ["The","syntax","for","anonymous","functions","is"
2878 ,D.dullyellow "(\\x -> x + 1)"
2879 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
2881 , D.toSimpleNote $
2882 "It is possible that I am confused about indetation! I generally recommend\
2883 \ switching to named functions if the definition cannot fit inline nicely, so\
2884 \ either (1) try to fit the whole anonymous function on one line or (2) break\
2885 \ the whole thing out into a named function. Things tend to be clearer that way!"
2889 FuncIndentBody row col ->
2890 let
2891 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2892 region = toRegion row col
2893 in
2894 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
2895 Code.toSnippet source surroundings (Just region)
2897 D.reflow $
2898 "I was expecting to see the body of your anonymous function next:"
2900 D.stack
2901 [ D.fillSep $
2902 ["The","syntax","for","anonymous","functions","is"
2903 ,D.dullyellow "(\\x -> x + 1)"
2904 ,"so","I","am","missing","all","the","stuff","after","the","arrow!"
2906 , D.toSimpleNote $
2907 "It is possible that I am confused about indetation! I generally recommend\
2908 \ switching to named functions if the definition cannot fit inline nicely, so\
2909 \ either (1) try to fit the whole anonymous function on one line or (2) break\
2910 \ the whole thing out into a named function. Things tend to be clearer that way!"
2916-- PATTERN
2919data PContext
2920 = PCase
2921 | PArg
2924toPatternReport :: Code.Source -> PContext -> Pattern -> Row -> Col -> Report.Report
2925toPatternReport source context pattern startRow startCol =
2926 case pattern of
2927 PRecord record row col ->
2928 toPRecordReport source record row col
2930 PTuple tuple row col ->
2931 toPTupleReport source context tuple row col
2933 PList list row col ->
2934 toPListReport source context list row col
2936 PStart row col ->
2937 case Code.whatIsNext source row col of
2938 Code.Keyword keyword ->
2939 let
2940 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2941 region = toWiderRegion row col (fromIntegral (length keyword))
2942 aThing =
2943 case context of
2944 PArg -> "an argument"
2945 PCase -> "a pattern"
2946 in
2947 Report.Report "RESERVED WORD" region [] $
2948 Code.toSnippet source surroundings (Just region)
2950 D.reflow $
2951 "It looks like you are trying to use `" ++ keyword ++ "` as " ++ aThing ++ ":"
2953 D.reflow $
2954 "This is a reserved word! Try using some other name?"
2957 _ ->
2958 error "TODO PStart"
2960 PChar char row col ->
2961 toCharReport source char row col
2963 PString string row col ->
2964 toStringReport source string row col
2966 PNumber number row col ->
2967 toNumberReport source number row col
2969 PFloat width row col ->
2970 let
2971 region = toWiderRegion row col width
2972 in
2973 Report.Report "UNEXPECTED PATTERN" region [] $
2974 Code.toSnippet source region Nothing
2976 D.reflow $
2977 "I cannot pattern match with floating point numbers:"
2979 D.fillSep $
2980 ["Equality","on","floats","can","be","unreliable,","so","you","usually","want"
2981 ,"to","check","that","they","are","nearby","with","some","sort","of"
2982 ,D.dullyellow "(abs (actual - expected) < 0.001)","check."
2986 PAlias row col ->
2987 let
2988 region = toRegion row col
2989 in
2990 Report.Report "UNFINISHED PATTERN" region [] $
2991 Code.toSnippet source region Nothing $
2993 D.reflow $
2994 "I was expecting to see a variable name after the `as` keyword:"
2996 D.stack
2997 [ D.fillSep $
2998 ["The","`as`","keyword","lets","you","write","patterns","like"
2999 ,"((" <> D.dullyellow "x" <> "," <> D.dullyellow "y" <> ") " <> D.cyan "as" <> D.dullyellow " point" <> ")"
3000 ,"so","you","can","refer","to","individual","parts","of","the","tuple","with"
3001 ,D.dullyellow "x","and",D.dullyellow "y","or","you","refer","to","the","whole"
3002 ,"thing","with",D.dullyellow "point."
3004 , D.reflow $
3005 "So I was expecting to see a variable name after the `as` keyword here. Sometimes\
3006 \ people just want to use `as` as a variable name though. Try using a different name\
3007 \ in that case!"
3011 PWildcardNotVar name width row col ->
3012 let
3013 region = toWiderRegion row col (fromIntegral width)
3014 examples =
3015 case dropWhile (=='_') (Name.toChars name) of
3016 [] -> [D.dullyellow "x","or",D.dullyellow "age"]
3017 c:cs -> [D.dullyellow (D.fromChars (Char.toLower c : cs))]
3018 in
3019 Report.Report "UNEXPECTED NAME" region [] $
3020 Code.toSnippet source region Nothing $
3022 D.reflow $
3023 "Variable names cannot start with underscores like this:"
3025 D.fillSep $
3026 ["You","can","either","have","an","underscore","like",D.dullyellow "_","to"
3027 ,"ignore","the","value,","or","you","can","have","a","name","like"
3028 ] ++ examples ++ ["to","use","the","matched","value." ]
3031 PSpace space row col ->
3032 toSpaceReport source space row col
3034 PIndentStart row col ->
3035 error "TODO PIndentStart" row col
3037 PIndentAlias row col ->
3038 let
3039 region = toRegion row col
3040 in
3041 Report.Report "UNFINISHED PATTERN" region [] $
3042 Code.toSnippet source region Nothing $
3044 D.reflow $
3045 "I was expecting to see a variable name after the `as` keyword:"
3047 D.stack
3048 [ D.fillSep $
3049 ["The","`as`","keyword","lets","you","write","patterns","like"
3050 ,"((" <> D.dullyellow "x" <> "," <> D.dullyellow "y" <> ") " <> D.cyan "as" <> D.dullyellow " point" <> ")"
3051 ,"so","you","can","refer","to","individual","parts","of","the","tuple","with"
3052 ,D.dullyellow "x","and",D.dullyellow "y","or","you","refer","to","the","whole"
3053 ,"thing","with",D.dullyellow "point."
3055 , D.reflow $
3056 "So I was expecting to see a variable name after the `as` keyword here. Sometimes\
3057 \ people just want to use `as` as a variable name though. Try using a different name\
3058 \ in that case!"
3063toPRecordReport :: Code.Source -> PRecord -> Row -> Col -> Report.Report
3064toPRecordReport source record startRow startCol =
3065 case record of
3066 PRecordOpen row col ->
3067 toUnfinishRecordPatternReport source row col startRow startCol $
3068 D.reflow "I was expecting to see a field name next."
3070 PRecordEnd row col ->
3071 toUnfinishRecordPatternReport source row col startRow startCol $
3072 D.fillSep
3073 ["I","was","expecting","to","see","a","closing","curly","brace","next."
3074 ,"Try","adding","a",D.dullyellow "}","here?"
3077 PRecordField row col ->
3078 case Code.whatIsNext source row col of
3079 Code.Keyword keyword ->
3080 let
3081 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3082 region = toWiderRegion row col (fromIntegral (length keyword))
3083 in
3084 Report.Report "RESERVED WORD" region [] $
3085 Code.toSnippet source surroundings (Just region)
3087 D.reflow $
3088 "I was not expecting to see `" ++ keyword ++ "` as a record field name:"
3090 D.reflow $
3091 "This is a reserved word, not available for variable names. Try another name!"
3094 _ ->
3095 toUnfinishRecordPatternReport source row col startRow startCol $
3096 D.reflow "I was expecting to see a field name next."
3098 PRecordSpace space row col ->
3099 toSpaceReport source space row col
3101 PRecordIndentOpen row col ->
3102 toUnfinishRecordPatternReport source row col startRow startCol $
3103 D.reflow "I was expecting to see a field name next."
3105 PRecordIndentEnd row col ->
3106 toUnfinishRecordPatternReport source row col startRow startCol $
3107 D.fillSep
3108 ["I","was","expecting","to","see","a","closing","curly","brace","next."
3109 ,"Try","adding","a",D.dullyellow "}","here?"
3112 PRecordIndentField row col ->
3113 toUnfinishRecordPatternReport source row col startRow startCol $
3114 D.reflow "I was expecting to see a field name next."
3117toUnfinishRecordPatternReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
3118toUnfinishRecordPatternReport source row col startRow startCol message =
3119 let
3120 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3121 region = toRegion row col
3122 in
3123 Report.Report "UNFINISHED RECORD PATTERN" region [] $
3124 Code.toSnippet source surroundings (Just region)
3126 D.reflow $
3127 "I was partway through parsing a record pattern, but I got stuck here:"
3129 D.stack
3130 [ message
3131 , D.toFancyHint $
3132 ["A","record","pattern","looks","like",D.dullyellow "{x,y}","or",D.dullyellow "{name,age}"
3133 ,"where","you","list","the","field","names","you","want","to","access."
3140toPTupleReport :: Code.Source -> PContext -> PTuple -> Row -> Col -> Report.Report
3141toPTupleReport source context tuple startRow startCol =
3142 case tuple of
3143 PTupleOpen row col ->
3144 case Code.whatIsNext source row col of
3145 Code.Keyword keyword ->
3146 let
3147 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3148 region = toWiderRegion row col (fromIntegral (length keyword))
3149 in
3150 Report.Report "RESERVED WORD" region [] $
3151 Code.toSnippet source surroundings (Just region)
3153 D.reflow $
3154 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name:"
3156 D.reflow $
3157 "This is a reserved word! Try using some other name?"
3160 _ ->
3161 let
3162 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3163 region = toRegion row col
3164 in
3165 Report.Report "UNFINISHED PARENTHESES" region [] $
3166 Code.toSnippet source surroundings (Just region)
3168 D.reflow $
3169 "I just saw an open parenthesis, but I got stuck here:"
3171 D.fillSep
3172 ["I","was","expecting","so","see","a","pattern","next."
3173 ,"Maybe","it","will","end","up","being","something"
3174 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "?"
3178 PTupleEnd row col ->
3179 let
3180 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3181 region = toRegion row col
3182 in
3183 Report.Report "UNFINISHED PARENTHESES" region [] $
3184 Code.toSnippet source surroundings (Just region) $
3186 D.reflow $
3187 "I was expecting a closing parenthesis next:"
3189 D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
3192 PTupleExpr pattern row col ->
3193 toPatternReport source context pattern row col
3195 PTupleSpace space row col ->
3196 toSpaceReport source space row col
3198 PTupleIndentEnd row col ->
3199 let
3200 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3201 region = toRegion row col
3202 in
3203 Report.Report "UNFINISHED PARENTHESES" region [] $
3204 Code.toSnippet source surroundings (Just region) $
3206 D.reflow $
3207 "I was expecting a closing parenthesis next:"
3209 D.stack
3210 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
3211 , D.toSimpleNote $
3212 "I can get confused by indentation in cases like this, so\
3213 \ maybe you have a closing parenthesis but it is not indented enough?"
3217 PTupleIndentExpr1 row col ->
3218 let
3219 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3220 region = toRegion row col
3221 in
3222 Report.Report "UNFINISHED PARENTHESES" region [] $
3223 Code.toSnippet source surroundings (Just region) $
3225 D.reflow $
3226 "I just saw an open parenthesis, but then I got stuck here:"
3228 D.fillSep
3229 ["I","was","expecting","so","see","a","pattern","next."
3230 ,"Maybe","it","will","end","up","being","something"
3231 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "?"
3235 PTupleIndentExprN row col ->
3236 let
3237 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3238 region = toRegion row col
3239 in
3240 Report.Report "UNFINISHED TUPLE PATTERN" region [] $
3241 Code.toSnippet source surroundings (Just region) $
3243 D.reflow $
3244 "I am partway through parsing a tuple pattern, but I got stuck here:"
3246 D.stack
3247 [ D.fillSep
3248 ["I","was","expecting","so","see","a","pattern","next."
3249 ,"I","am","expecting","the","final","result","to","be","something"
3250 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "."
3252 , D.toSimpleNote $
3253 "I can get confused by indentation in cases like this, so the problem\
3254 \ may be that the next part is not indented enough?"
3259toPListReport :: Code.Source -> PContext -> PList -> Row -> Col -> Report.Report
3260toPListReport source context list startRow startCol =
3261 case list of
3262 PListOpen row col ->
3263 case Code.whatIsNext source row col of
3264 Code.Keyword keyword ->
3265 let
3266 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3267 region = toWiderRegion row col (fromIntegral (length keyword))
3268 in
3269 Report.Report "RESERVED WORD" region [] $
3270 Code.toSnippet source surroundings (Just region)
3272 D.reflow $
3273 "It looks like you are trying to use `" ++ keyword ++ "` to name an element of a list:"
3275 D.reflow $
3276 "This is a reserved word though! Try using some other name?"
3279 _ ->
3280 let
3281 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3282 region = toRegion row col
3283 in
3284 Report.Report "UNFINISHED LIST PATTERN" region [] $
3285 Code.toSnippet source surroundings (Just region) $
3287 D.reflow $
3288 "I just saw an open square bracket, but then I got stuck here:"
3290 D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
3293 PListEnd row col ->
3294 let
3295 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3296 region = toRegion row col
3297 in
3298 Report.Report "UNFINISHED LIST PATTERN" region [] $
3299 Code.toSnippet source surroundings (Just region) $
3301 D.reflow $
3302 "I was expecting a closing square bracket to end this list pattern:"
3304 D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
3307 PListExpr pattern row col ->
3308 toPatternReport source context pattern row col
3310 PListSpace space row col ->
3311 toSpaceReport source space row col
3313 PListIndentOpen row col ->
3314 let
3315 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3316 region = toRegion row col
3317 in
3318 Report.Report "UNFINISHED LIST PATTERN" region [] $
3319 Code.toSnippet source surroundings (Just region) $
3321 D.reflow $
3322 "I just saw an open square bracket, but then I got stuck here:"
3324 D.stack
3325 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
3326 , D.toSimpleNote $
3327 "I can get confused by indentation in cases like this, so\
3328 \ maybe there is something next, but it is not indented enough?"
3332 PListIndentEnd row col ->
3333 let
3334 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3335 region = toRegion row col
3336 in
3337 Report.Report "UNFINISHED LIST PATTERN" region [] $
3338 Code.toSnippet source surroundings (Just region) $
3340 D.reflow $
3341 "I was expecting a closing square bracket to end this list pattern:"
3343 D.stack
3344 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
3345 , D.toSimpleNote $
3346 "I can get confused by indentation in cases like this, so\
3347 \ maybe you have a closing square bracket but it is not indented enough?"
3351 PListIndentExpr row col ->
3352 let
3353 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3354 region = toRegion row col
3355 in
3356 Report.Report "UNFINISHED LIST PATTERN" region [] $
3357 Code.toSnippet source surroundings (Just region) $
3359 D.reflow $
3360 "I am partway through parsing a list pattern, but I got stuck here:"
3362 D.stack
3363 [ D.reflow $
3364 "I was expecting to see another pattern next. Maybe a variable name."
3365 , D.toSimpleNote $
3366 "I can get confused by indentation in cases like this, so\
3367 \ maybe there is more to this pattern but it is not indented enough?"
3373-- TYPES
3376toTypeReport :: Code.Source -> Type -> Row -> Col -> Report.Report
3377toTypeReport source tipe startRow startCol =
3378 case tipe of
3379 TRecord record row col ->
3380 toTRecordReport source record row col
3382 TTuple tuple row col ->
3383 toTTupleReport source tuple row col
3385 TVariant row col ->
3386 error "TODO TVariant" row col startRow startCol
3388 TArrow row col ->
3389 error "TODO TArrow" row col
3391 TStart row col ->
3392 error "TODO TStart" row col
3394 TSpace space row col ->
3395 toSpaceReport source space row col
3397 TIndentStart row col ->
3398 error "TODO TIndentStart" row col
3402toTRecordReport :: Code.Source -> TRecord -> Row -> Col -> Report.Report
3403toTRecordReport source record startRow startCol =
3404 case record of
3405 TRecordOpen row col ->
3406 let
3407 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3408 region = toRegion row col
3409 in
3410 case Code.whatIsNext source row col of
3411 Code.Keyword keyword ->
3412 Report.Report "RESERVED WORD" region [] $
3413 Code.toSnippet source surroundings (Just region)
3415 D.reflow $
3416 "I just started parsing a record type, but I got stuck on this field name:"
3418 D.reflow $
3419 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
3420 \ that is a reserved word. Try using a different name!"
3423 _ ->
3424 Report.Report "UNFINISHED RECORD TYPE" region [] $
3425 Code.toSnippet source surroundings (Just region)
3427 D.reflow $
3428 "I just started parsing a record type, but I got stuck here:"
3430 D.fillSep
3431 ["Record","types","look","like",D.dullyellow "{ name : String, age : Int },"
3432 ,"so","I","was","expecting","to","see","a","field","name","next."
3436 TRecordEnd row col ->
3437 let
3438 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3439 region = toRegion row col
3440 in
3441 Report.Report "UNFINISHED RECORD TYPE" region [] $
3442 Code.toSnippet source surroundings (Just region)
3444 D.reflow $
3445 "I am partway through parsing a record type, but I got stuck here:"
3447 D.stack
3448 [ D.fillSep
3449 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
3450 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
3452 , D.toSimpleNote $
3453 "When I get stuck like this, it usually means that there is a missing parenthesis\
3454 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
3458 TRecordField row col ->
3459 case Code.whatIsNext source row col of
3460 Code.Keyword keyword ->
3461 let
3462 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3463 region = toWiderRegion row col (fromIntegral (length keyword))
3464 in
3465 Report.Report "RESERVED WORD" region [] $
3466 Code.toSnippet source surroundings (Just region)
3468 D.reflow $
3469 "I am partway through parsing a record type, but I got stuck on this field name:"
3471 D.reflow $
3472 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
3473 \ that is a reserved word. Try using a different name!"
3476 _ ->
3477 let
3478 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3479 region = toRegion row col
3480 in
3481 Report.Report "UNFINISHED RECORD TYPE" region [] $
3482 Code.toSnippet source surroundings (Just region)
3484 D.reflow $
3485 "I am partway through parsing a record type, but I got stuck after that last comma:"
3487 addNoteForRecordTypeError $
3488 D.reflow $
3489 "Trailing commas are not allowed in records, so I was expecting to see another\
3490 \ record field defined next. If you are done defining the record, the fix may\
3491 \ be to delete that last comma?"
3494 TRecordColon row col ->
3495 let
3496 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3497 region = toRegion row col
3498 in
3499 Report.Report "UNFINISHED RECORD TYPE" region [] $
3500 Code.toSnippet source surroundings (Just region)
3502 D.reflow $
3503 "I am partway through parsing a record type, but I got stuck here:"
3505 addNoteForRecordTypeError $
3506 D.fillSep $
3507 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
3508 ,"a","colon","next.","So","try","putting","an",D.green ":","sign","here?"
3512 TRecordType tipe row col ->
3513 toTypeReport source tipe row col
3515 TRecordSpace space row col ->
3516 toSpaceReport source space row col
3518 TRecordIndentOpen row col ->
3519 let
3520 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3521 region = toRegion row col
3522 in
3523 Report.Report "UNFINISHED RECORD TYPE" region [] $
3524 Code.toSnippet source surroundings (Just region)
3526 D.reflow $
3527 "I just saw the opening curly brace of a record type, but then I got stuck here:"
3529 addNoteForRecordTypeIndentError $
3530 D.fillSep $
3531 ["I","am","expecting","a","record","like",D.dullyellow "{ name : String, age : Int }","here."
3532 ,"Try","defining","some","fields","of","your","own?"
3536 TRecordIndentEnd row col ->
3537 let
3538 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3539 region = toRegion row col
3540 in
3541 Report.Report "UNFINISHED RECORD TYPE" region [] $
3542 Code.toSnippet source surroundings (Just region)
3544 D.reflow $
3545 "I was expecting to see a closing curly brace next:"
3547 addNoteForRecordTypeIndentError $
3548 D.fillSep $
3549 ["Try","putting","an",D.green "}","and","see","if","that","helps?"
3553 TRecordIndentField row col ->
3554 let
3555 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3556 region = toRegion row col
3557 in
3558 Report.Report "UNFINISHED RECORD TYPE" region [] $
3559 Code.toSnippet source surroundings (Just region)
3561 D.reflow $
3562 "I am partway through parsing a record type, but I got stuck after that last comma:"
3564 addNoteForRecordTypeIndentError $
3565 D.reflow $
3566 "Trailing commas are not allowed in record types, so the fix may be to\
3567 \ delete that last comma? Or maybe you were in the middle of defining\
3568 \ an additional field?"
3571 TRecordIndentColon row col ->
3572 let
3573 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3574 region = toRegion row col
3575 in
3576 Report.Report "UNFINISHED RECORD TYPE" region [] $
3577 Code.toSnippet source surroundings (Just region)
3579 D.reflow $
3580 "I am partway through parsing a record type. I just saw a record\
3581 \ field, so I was expecting to see a colon next:"
3583 addNoteForRecordTypeIndentError $
3584 D.fillSep $
3585 ["Try","putting","an",D.green ":","followed","by","a","type?"
3589 TRecordIndentType row col ->
3590 let
3591 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3592 region = toRegion row col
3593 in
3594 Report.Report "UNFINISHED RECORD TYPE" region [] $
3595 Code.toSnippet source surroundings (Just region)
3597 D.reflow $
3598 "I am partway through parsing a record type, and I was expecting to run into a type next:"
3600 addNoteForRecordTypeIndentError $
3601 D.fillSep $
3602 ["Try","putting","something,","like"
3603 ,D.dullyellow "Int","or",D.dullyellow "String","for","now?"
3608addNoteForRecordTypeError :: D.Doc -> D.Doc
3609addNoteForRecordTypeError normalRecommendation =
3610 D.stack $
3611 normalRecommendation
3613 [ D.toSimpleNote
3614 "If you are trying to define a record type across multiple lines, I recommend using this format:"
3615 , D.indent 4 $ D.vcat $
3616 [ "{ name : String"
3617 , ", age : Int"
3618 , ", height : Float"
3619 , "}"
3621 , D.reflow $
3622 "Notice that each line starts with some indentation. Usually two or four spaces. I\
3623 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
3624 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3628addNoteForRecordTypeIndentError :: D.Doc -> D.Doc
3629addNoteForRecordTypeIndentError normalRecommendation =
3630 D.stack $
3631 normalRecommendation
3633 [ D.toSimpleNote
3634 "I may be confused by indentation. For example, if you are trying to define\
3635 \ a record type across multiple lines, I recommend using this format:"
3636 , D.indent 4 $ D.vcat $
3637 [ "{ name : String"
3638 , ", age : Int"
3639 , ", height : Float"
3640 , "}"
3642 , D.reflow $
3643 "Notice that each line starts with some indentation. Usually two or four spaces. I\
3644 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
3645 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3649toTTupleReport :: Code.Source -> TTuple -> Row -> Col -> Report.Report
3650toTTupleReport source tuple startRow startCol =
3651 case tuple of
3652 TTupleOpen row col ->
3653 error "TODO TTupleOpen" row col startRow startCol
3655 TTupleEnd row col ->
3656 error "TODO TTupleEnd" row col
3658 TTupleType tipe row col ->
3659 error "TODO TTupleType" tipe row col
3661 TTupleSpace space row col ->
3662 toSpaceReport source space row col
3664 TTupleIndentOpen row col ->
3665 error "TODO TTupleIndentOpen" row col
3667 TTupleIndentType row col ->
3668 error "TODO TTupleIndentType" row col
3670 TTupleIndentEnd row col ->
3671 error "TODO TTupleIndentEnd" row col