on 6e01ea5 help sign in
2644 lines 87 kB history raw
1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Reporting.Error.Syntax
4 ( Error(..)
5 --
6 , Module(..)
7 , Exposing(..)
8 --
9 , Decl(..)
10 , DeclType(..)
11 , TypeAlias(..)
12 , CustomType(..)
13 , DeclDef(..)
14 , Port(..)
15 --
16 , Expr(..)
17 , Record(..)
18 , Tuple(..)
19 , List(..)
20 , Func(..)
21 , Case(..)
22 , If(..)
23 , Let(..)
24 , Def(..)
25 , Destruct(..)
26 --
27 , Pattern(..)
28 , PRecord(..)
29 , PTuple(..)
30 , PList(..)
31 --
32 , Type(..)
33 , TRecord(..)
34 , TTuple(..)
35 --
36 , Char(..)
37 , String(..)
38 , Escape(..)
39 , Number(..)
40 --
41 , Space(..)
42 , toReport
43 )
44 where
47import Prelude hiding (Char, String)
48import qualified Data.Char as Char
49import qualified Data.Name as Name
50import Data.Word (Word16)
51import Numeric (showHex)
53import qualified Elm.ModuleName as ModuleName
54import Parse.Primitives (Row, Col)
55import Parse.Symbol (BadOperator(..))
56import qualified Reporting.Annotation as A
57import qualified Reporting.Doc as D
58import qualified Reporting.Report as Report
59import qualified Reporting.Render.Code as Code
63-- ALL SYNTAX ERRORS
66data Error
67 = ModuleNameUnspecified ModuleName.Raw
68 | ModuleNameMismatch ModuleName.Raw (A.Located ModuleName.Raw)
69 | UnexpectedPort A.Region
70 | NoPorts A.Region
71 | ParseError Module
75-- MODULE
78data Module
79 = ModuleSpace Space Row Col
80 | ModuleEndOfFile Row Col
81 --
82 | ModuleProblem Row Col
83 | ModuleName Row Col
84 | ModuleExposing Exposing Row Col
85 --
86 | PortModuleProblem Row Col
87 | PortModuleName Row Col
88 | PortModuleExposing Exposing Row Col
89 --
90 | Effect Row Col
91 --
92 | FreshLine Row Col
93 --
94 | ImportStart Row Col
95 | ImportName Row Col
96 | ImportAs Row Col
97 | ImportAlias Row Col
98 | ImportExposing Row Col
99 | ImportExposingList Exposing Row Col
100 | ImportEnd Row Col -- different based on col=1 or if greater
101 --
102 | ImportIndentName Row Col
103 | ImportIndentAlias Row Col
104 | ImportIndentExposingList Row Col
105 --
106 | Infix Row Col
107 --
108 | Declarations Decl Row Col
111data Exposing
112 = ExposingSpace Space Row Col
113 | ExposingStart Row Col
114 | ExposingValue Row Col
115 | ExposingOperator Row Col
116 | ExposingOperatorReserved BadOperator Row Col
117 | ExposingOperatorRightParen Row Col
118 | ExposingEnd Row Col
119 --
120 | ExposingTypePrivacy Row Col
121 | ExposingTypePrivacyDots Row Col
122 | ExposingTypePrivacyEnd Row Col
123 --
124 | ExposingIndentEnd Row Col
125 | ExposingIndentValue Row Col
126 | ExposingIndentValueEnd Row Col
127 | ExposingIndentTypePrivacy Row Col
128 | ExposingIndentTypePrivacyDots Row Col
129 | ExposingIndentTypePrivacyEnd Row Col
133-- DECLARATIONS
136data Decl
137 = DeclStart Row Col
138 | DeclSpace Space Row Col
139 --
140 | Port Port Row Col
141 | DeclType DeclType Row Col
142 | DeclDef Name.Name DeclDef Row Col
143 --
144 | DeclFreshLineStart Row Col
145 | DeclFreshLineAfterDocComment Row Col
148data DeclDef
149 = DeclDefSpace Space Row Col
150 | DeclDefEquals Row Col
151 | DeclDefType Type Row Col
152 | DeclDefArg Pattern Row Col
153 | DeclDefBody Expr Row Col
154 | DeclDefNameRepeat Row Col
155 | DeclDefNameMatch Name.Name Row Col
156 --
157 | DeclDefIndentType Row Col
158 | DeclDefIndentEquals Row Col
159 | DeclDefIndentBody Row Col
160 --
161 | DeclDefFreshLineAfterType Row Col
164data Port
165 = PortSpace Space Row Col
166 | PortName Row Col
167 | PortColon Row Col
168 | PortType Type Row Col
169 | PortIndentName Row Col
170 | PortIndentColon Row Col
171 | PortIndentType Row Col
175-- TYPE DECLARATIONS
178data DeclType
179 = DT_Space Space Row Col
180 | DT_Name Row Col
181 | DT_Alias TypeAlias Row Col
182 | DT_Union CustomType Row Col
183 --
184 | DT_IndentName Row Col
187data TypeAlias
188 = AliasSpace Space Row Col
189 | AliasName Row Col
190 | AliasEquals Row Col
191 | AliasBody Type Row Col
192 --
193 | AliasIndentEquals Row Col
194 | AliasIndentBody Row Col
197data CustomType
198 = CT_Space Space Row Col
199 | CT_Name Row Col
200 | CT_Equals Row Col
201 | CT_Bar Row Col
202 | CT_Variant Row Col
203 | CT_VariantArg Type Row Col
204 --
205 | CT_IndentEquals Row Col
206 | CT_IndentBar Row Col
207 | CT_IndentAfterBar Row Col
208 | CT_IndentAfterEquals Row Col
212-- EXPRESSIONS
215data Expr
216 = Let Let Row Col
217 | Case Case Row Col
218 | If If Row Col
219 | List List Row Col
220 | Record Record Row Col
221 | Tuple Tuple Row Col
222 | Func Func Row Col
223 --
224 | Dot Row Col
225 | Access Row Col
226 | OperatorRight Name.Name Row Col
227 | OperatorReserved BadOperator Row Col
228 --
229 | Start Row Col
230 | Char Char Row Col
231 | String String Row Col
232 | Number Number Row Col
233 | Space Space Row Col
234 | EndlessShader Row Col
235 | ShaderProblem [Char.Char] Row Col
236 | IndentOperatorRight Name.Name Row Col
237 | IndentMoreExpr Row Col
240data Record
241 = RecordOpen Row Col
242 | RecordEnd Row Col
243 | RecordField Row Col
244 | RecordEquals Row Col
245 | RecordExpr Expr Row Col
246 | RecordSpace Space Row Col
247 --
248 | RecordIndentOpen Row Col
249 | RecordIndentEnd Row Col
250 | RecordIndentField Row Col
251 | RecordIndentEquals Row Col
252 | RecordIndentExpr Row Col
255data Tuple
256 = TupleExpr Expr Row Col
257 | TupleSpace Space Row Col
258 | TupleEnd Row Col
259 | TupleOperatorClose Row Col
260 | TupleOperatorReserved BadOperator Row Col
261 --
262 | TupleIndentExpr1 Row Col
263 | TupleIndentExprN Row Col
264 | TupleIndentEnd Row Col
267data List
268 = ListSpace Space Row Col
269 | ListOpen Row Col
270 | ListExpr Expr Row Col
271 | ListEnd Row Col
272 --
273 | ListIndentOpen Row Col
274 | ListIndentEnd Row Col
275 | ListIndentExpr Row Col
278data Func
279 = FuncSpace Space Row Col
280 | FuncArg Pattern Row Col
281 | FuncBody Expr Row Col
282 | FuncArrow Row Col
283 --
284 | FuncIndentArg Row Col
285 | FuncIndentArrow Row Col
286 | FuncIndentBody Row Col
289data Case
290 = CaseSpace Space Row Col
291 | CaseOf Row Col
292 | CasePattern Pattern Row Col
293 | CaseArrow Row Col
294 | CaseExpr Expr Row Col
295 | CaseBranch Expr Row Col
296 --
297 | CaseIndentOf Row Col
298 | CaseIndentExpr Row Col
299 | CaseIndentPattern Row Col
300 | CaseIndentArrow Row Col
301 | CaseIndentBranch Row Col
302 | CasePatternAlignment Word16 Row Col
305data If
306 = IfSpace Space Row Col
307 | IfThen Row Col
308 | IfElse Row Col
309 | IfElseBranchStart Row Col
310 --
311 | IfCondition Expr Row Col
312 | IfThenBranch Expr Row Col
313 | IfElseBranch Expr Row Col
314 --
315 | IfIndentCondition Row Col
316 | IfIndentThen Row Col
317 | IfIndentThenBranch Row Col
318 | IfIndentElseBranch Row Col
319 | IfIndentElse Row Col
322data Let
323 = LetSpace Space Row Col
324 | LetIn Row Col
325 | LetDefAlignment Word16 Row Col
326 | LetDefName Row Col
327 | LetDef Name.Name Def Row Col
328 | LetDestruct Destruct Row Col
329 | LetBody Expr Row Col
330 | LetIndentDef Row Col
331 | LetIndentIn Row Col
332 | LetIndentBody Row Col
335data Def
336 = DefSpace Space Row Col
337 | DefType Type Row Col
338 | DefNameRepeat Name.Name Row Col
339 | DefNameMatch Name.Name Name.Name Row Col
340 | DefArg Pattern Row Col
341 | DefEquals Row Col
342 | DefBody Expr Row Col
343 | DefIndentEquals Row Col
344 | DefIndentType Row Col
345 | DefIndentBody Row Col
346 | DefAlignment Word16 Row Col
349data Destruct
350 = DestructSpace Space Row Col
351 | DestructPattern Pattern Row Col
352 | DestructEquals Row Col
353 | DestructBody Expr Row Col
354 | DestructIndentEquals Row Col
355 | DestructIndentBody Row Col
359-- PATTERNS
362data Pattern
363 = PRecord PRecord Row Col
364 | PTuple PTuple Row Col
365 | PList PList Row Col
366 --
367 | PStart Row Col
368 | PChar Char Row Col
369 | PString String Row Col
370 | PNumber Number Row Col
371 | PFloat Int Row Col
372 | PAlias Row Col
373 | PWildcardNotVar Int Row Col
374 | PSpace Space Row Col
375 --
376 | PIndentStart Row Col
377 | PIndentAlias Row Col
380data PRecord
381 = PRecordOpen Row Col
382 | PRecordEnd Row Col
383 | PRecordField Row Col
384 | PRecordSpace Space Row Col
385 --
386 | PRecordIndentOpen Row Col
387 | PRecordIndentEnd Row Col
388 | PRecordIndentField Row Col
391data PTuple
392 = PTupleOpen Row Col
393 | PTupleEnd Row Col
394 | PTupleExpr Pattern Row Col
395 | PTupleSpace Space Row Col
396 --
397 | PTupleIndentOpen Row Col
398 | PTupleIndentEnd Row Col
399 | PTupleIndentExpr Row Col
402data PList
403 = PListOpen Row Col
404 | PListEnd Row Col
405 | PListExpr Pattern Row Col
406 | PListSpace Space Row Col
407 --
408 | PListIndentOpen Row Col
409 | PListIndentEnd Row Col
410 | PListIndentExpr Row Col
414-- TYPES
417data Type
418 = TRecord TRecord Row Col
419 | TTuple TTuple Row Col
420 | TVariant Row Col
421 | TArrow Row Col
422 --
423 | TStart Row Col
424 | TSpace Space Row Col
425 --
426 | TIndentStart Row Col
429data TRecord
430 = TRecordOpen Row Col
431 | TRecordEnd Row Col
432 --
433 | TRecordField Row Col
434 | TRecordColon Row Col
435 | TRecordType Type Row Col
436 --
437 | TRecordSpace Space Row Col
438 --
439 | TRecordIndentOpen Row Col
440 | TRecordIndentField Row Col
441 | TRecordIndentColon Row Col
442 | TRecordIndentType Row Col
443 | TRecordIndentEnd Row Col
446data TTuple
447 = TTupleOpen Row Col
448 | TTupleEnd Row Col
449 | TTupleType Type Row Col
450 | TTupleSpace Space Row Col
451 --
452 | TTupleIndentOpen Row Col
453 | TTupleIndentType Row Col
454 | TTupleIndentEnd Row Col
458-- LITERALS
461data Char
462 = CharEndless
463 | CharEscape Escape
464 | CharNotString Word16
467data String
468 = StringEndless_Single
469 | StringEndless_Multi
470 | StringEscape Escape
473data Escape
474 = EscapeUnknown
475 | BadUnicodeFormat Word16
476 | BadUnicodeCode Word16
477 | BadUnicodeLength Word16 Int Int
480data Number
481 = NumberEnd
482 | NumberDot Int
483 | NumberHexDigit
484 | NumberNoLeadingZero
488-- MISC
491data Space
492 = HasTab
493 | EndlessMultiComment
497-- TO REPORT
500toReport :: Code.Source -> Error -> Report.Report
501toReport source err =
502 case err of
503 ModuleNameUnspecified name ->
504 let
505 region = toRegion 1 1
506 in
507 Report.Report "MODULE NAME MISSING" region [] $
508 D.stack
509 [ D.reflow $
510 "I need the module name to be declared at the top of this file, like this:"
511 , D.indent 4 $ D.green $ D.fromChars $
512 "module " ++ ModuleName.toChars name ++ " exposing (..)"
513 , D.reflow $
514 "Try adding that as the first line of your file!"
515 , D.toSimpleNote $
516 "It is best to replace (..) with an explicit list of types and\
517 \ functions you want to expose. When you know a value is only used\
518 \ within this module, you can refactor without worrying about uses\
519 \ elsewhere. Limiting exposed values can also speed up compilation\
520 \ because I can skip a bunch of work if I see that the exposed API\
521 \ has not changed."
522 ]
524 ModuleNameMismatch expectedName (A.At region actualName) ->
525 Report.Report "MODULE NAME MISMATCH" region [ModuleName.toChars expectedName] $
526 Code.toSnippet source region Nothing
527 (
528 "It looks like this module name is out of sync:"
529 ,
530 D.stack
531 [ D.reflow $
532 "I need it to match the file path, so I was expecting it to see `"
533 ++ ModuleName.toChars expectedName
534 ++ "` here. Make the following change, and you should be all set!"
535 , D.indent 4 $
536 D.dullyellow (D.fromName actualName) <> " -> " <> D.green (D.fromName expectedName)
537 , D.toSimpleNote $
538 "I require that module names correspond to file paths. This makes it much\
539 \ easier to explore unfamiliar codebases! So if you want to keep the current\
540 \ module name, try renaming the file instead."
541 ]
542 )
544 UnexpectedPort region ->
545 error "TODO UnexpectedPort" region
547 NoPorts region ->
548 error "TODO NoPorts" region
550 ParseError modul ->
551 toParseErrorReport source modul
554toParseErrorReport :: Code.Source -> Module -> Report.Report
555toParseErrorReport source modul =
556 case modul of
557 ModuleSpace space row col ->
558 toSpaceReport source space row col
560 ModuleEndOfFile row col ->
561 let
562 region = toRegion row col
563 in
564 Report.Report "EXPECTING END OF FILE" region [] $
565 Code.toSnippet source region Nothing
566 (
567 D.reflow $
568 "I was not expecting to see anything more here:"
569 ,
570 D.reflow $
571 "I think I have read all the declarations in the file and that there is nothing\
572 \ left to see, so whatever I am running into is confusing me a lot!"
573 )
575 ModuleProblem row col ->
576 let
577 region = toRegion row col
578 in
579 Report.Report "UNFINISHED MODULE DECLARATION" region [] $
580 Code.toSnippet source region Nothing
581 (
582 D.reflow $
583 "I am parsing an `module` declaration, but I got stuck here:"
584 ,
585 D.stack
586 [ D.reflow $
587 "Here are some examples of valid `module` declarations:"
588 , D.indent 4 $ D.vcat $
589 [ D.fillSep [D.blue "module","Main",D.blue "exposing","(..)"]
590 , D.fillSep [D.blue "module","Dict",D.blue "exposing","(Dict, empty, get)"]
591 ]
592 , D.reflow $
593 "I generally recommend using an explicit exposing list. I can skip compiling a bunch\
594 \ of files when the public interface of a module stays the same, so exposing fewer\
595 \ values can help improve compile times!"
596 ]
597 )
599 ModuleName row col ->
600 let
601 region = toRegion row col
602 in
603 Report.Report "EXPECTING MODULE NAME" region [] $
604 Code.toSnippet source region Nothing
605 (
606 D.reflow $
607 "I was parsing an `module` declaration until I got stuck here:"
608 ,
609 D.stack
610 [ D.reflow $
611 "I was expecting to see the module name next, like in these examples:"
612 , D.indent 4 $ D.vcat $
613 [ D.fillSep [D.blue "module","Dict",D.blue "exposing","(..)"]
614 , D.fillSep [D.blue "module","Maybe",D.blue "exposing","(..)"]
615 , D.fillSep [D.blue "module","Html.Attributes",D.blue "exposing","(..)"]
616 , D.fillSep [D.blue "module","Json.Decode",D.blue "exposing","(..)"]
617 ]
618 , D.reflow $
619 "Notice that the module names all start with capital letters. That is required!"
620 ]
621 )
623 ModuleExposing exposing row col ->
624 error "TODO ModuleExposing" exposing row col
626 PortModuleProblem row col ->
627 let
628 region = toRegion row col
629 in
630 Report.Report "UNFINISHED PORT MODULE DECLARATION" region [] $
631 Code.toSnippet source region Nothing
632 (
633 D.reflow $
634 "I am parsing an `port module` declaration, but I got stuck here:"
635 ,
636 D.stack
637 [ D.reflow $
638 "Here are some examples of valid `port module` declarations:"
639 , D.indent 4 $ D.vcat $
640 [ D.fillSep [D.blue "port",D.blue "module","WebSockets",D.blue "exposing","(send, listen, keepAlive)"]
641 , D.fillSep [D.blue "port",D.blue "module","Maps",D.blue "exposing","(Location, goto)"]
642 ]
643 , D.reflow $
644 "Go to the section in https://guide.elm-lang.org on ports for more information!"
645 ]
646 )
648 PortModuleName row col ->
649 let
650 region = toRegion row col
651 in
652 Report.Report "EXPECTING MODULE NAME" region [] $
653 Code.toSnippet source region Nothing
654 (
655 D.reflow $
656 "I was parsing an `module` declaration until I got stuck here:"
657 ,
658 D.stack
659 [ D.reflow $
660 "I was expecting to see the module name next, like in these examples:"
661 , D.indent 4 $ D.vcat $
662 [ D.fillSep [D.blue "port",D.blue "module","WebSockets",D.blue "exposing","(send, listen, keepAlive)"]
663 , D.fillSep [D.blue "port",D.blue "module","Maps",D.blue "exposing","(Location, goto)"]
664 ]
665 , D.reflow $
666 "Notice that the module names start with capital letters. That is required!"
667 ]
668 )
670 PortModuleExposing exposing row col ->
671 error "TODO PortModuleExposing" exposing row col
673 Effect row col ->
674 let
675 region = toRegion row col
676 in
677 Report.Report "BAD MODULE DECLARATION" region [] $
678 Code.toSnippet source region Nothing
679 (
680 D.reflow $
681 "I cannot parse this module declaration:"
682 ,
683 D.reflow $
684 "This type of module is reserved for the @elm organization. It is used to\
685 \ define certain effects, avoiding building them into the compiler."
686 )
688 FreshLine row col ->
689 let
690 region = toRegion row col
692 toBadFirstLineReport keyword =
693 Report.Report "TOO MUCH INDENTATION" region [] $
694 Code.toSnippet source region Nothing
695 (
696 D.reflow $
697 "This `" ++ keyword ++ "` should not have any spaces before it:"
698 ,
699 D.reflow $
700 "Delete the spaces before `" ++ keyword ++ "` until there are none left!"
701 )
703 in
704 case Code.whatIsNext source row col of
705 Code.Keyword "module" -> toBadFirstLineReport "module"
706 Code.Keyword "import" -> toBadFirstLineReport "import"
707 Code.Keyword "type" -> toBadFirstLineReport "type"
708 Code.Keyword "port" -> toBadFirstLineReport "port"
709 _ ->
710 Report.Report "SYNTAX PROBLEM" region [] $
711 Code.toSnippet source region Nothing
712 (
713 D.reflow $
714 "I got stuck here:"
715 ,
716 D.stack
717 [ D.reflow $
718 "I am not sure what is going on, but I recommend starting an Elm\
719 \ file with the following lines:"
720 , D.vcat
721 [ D.fillSep [D.blue "import","Html"]
722 , ""
723 , D.fillSep [D.green "main","="]
724 , D.indent 2 $ D.fillSep [D.cyan "Html" <> ".text",D.dullyellow "\"Hello!\""]
725 ]
726 , D.reflow $
727 "You should be able to copy those lines directly into your file. Check out\
728 \ some of the examples on https://elm-lang.org for more help getting started!"
729 , D.toSimpleNote $
730 "This can also happen when something is indented too much!"
731 ]
732 )
734 ImportStart row col ->
735 toImportReport source row col
737 ImportName row col ->
738 let
739 region = toRegion row col
740 in
741 Report.Report "EXPECTING IMPORT NAME" region [] $
742 Code.toSnippet source region Nothing
743 (
744 D.reflow $
745 "I was parsing an `import` until I got stuck here:"
746 ,
747 D.stack
748 [ D.reflow $
749 "I was expecting to see a module name next, like in these examples:"
750 , D.indent 4 $ D.vcat $
751 [ D.fillSep [D.blue "import","Dict"]
752 , D.fillSep [D.blue "import","Maybe"]
753 , D.fillSep [D.blue "import","Html.Attributes"]
754 , D.fillSep [D.blue "import","Json.Decode"]
755 ]
756 , D.reflow $
757 "Notice that the module names all start with capital letters. That is required!"
758 ]
759 )
761 ImportAs row col ->
762 toImportReport source row col
764 ImportAlias row col ->
765 let
766 region = toRegion row col
767 in
768 Report.Report "EXECTING IMPORT ALIAS" region [] $
769 Code.toSnippet source region Nothing
770 (
771 D.reflow $
772 "I was parsing an `import` until I got stuck here:"
773 ,
774 D.stack
775 [ D.reflow $
776 "I was expecting to see an alias next, like in these examples:"
777 , D.indent 4 $ D.vcat $
778 [ D.fillSep [D.blue "import","Html.Attributes",D.blue "as","Attr"]
779 , D.fillSep [D.blue "import","WebGL.Texture",D.blue "as","Texture"]
780 , D.fillSep [D.blue "import","Json.Decode",D.blue "as","D"]
781 ]
782 , D.reflow $
783 "Notice that the alias always starts with a capital letter. That is required!"
784 ]
785 )
787 ImportExposing row col ->
788 toImportReport source row col
790 ImportExposingList exposing row col ->
791 error "TODO ImportExposingList" exposing row col
793 ImportEnd row col ->
794 toImportReport source row col
796 ImportIndentName row col ->
797 toImportReport source row col
799 ImportIndentAlias row col ->
800 toImportReport source row col
802 ImportIndentExposingList row col ->
803 let
804 region = toRegion row col
805 in
806 Report.Report "UNFINISHED IMPORT" region [] $
807 Code.toSnippet source region Nothing
808 (
809 D.reflow $
810 "I was parsing an `import` until I got stuck here:"
811 ,
812 D.stack
813 [ D.reflow $
814 "I was expecting to see the list of exposed values next. For example, here\
815 \ are two ways to expose values from the `Html` module:"
816 , D.indent 4 $ D.vcat $
817 [ D.fillSep [D.blue "import","Html",D.blue "exposing","(..)"]
818 , D.fillSep [D.blue "import","Html",D.blue "exposing","(Html, div, text)"]
819 ]
820 , D.reflow $
821 "I generally recommend the second style. It is more explicit, making it\
822 \ much easier to figure out where values are coming from in large projects!"
823 ]
824 )
826 Infix row col ->
827 let
828 region = toRegion row col
829 in
830 Report.Report "BAD INFIX" region [] $
831 Code.toSnippet source region Nothing
832 (
833 D.reflow $
834 "Something went wrong in this infix operator declaration:"
835 ,
836 D.reflow $
837 "This feature is used by the @elm organization to define the\
838 \ languages built-in operators."
839 )
841 Declarations decl _ _ ->
842 toDeclarationsReport source decl
846-- IMPORTS
849toImportReport :: Code.Source -> Row -> Col -> Report.Report
850toImportReport source row col =
851 let
852 region = toRegion row col
853 in
854 Report.Report "UNFINISHED IMPORT" region [] $
855 Code.toSnippet source region Nothing
856 (
857 D.reflow $
858 "I am partway through parsing an import, but I got stuck here:"
859 ,
860 D.stack
861 [ D.reflow $
862 "Here are some examples of valid `import` declarations:"
863 , D.indent 4 $ D.vcat $
864 [ D.fillSep [D.blue "import","Html"]
865 , D.fillSep [D.blue "import","Html",D.blue "as","H"]
866 , D.fillSep [D.blue "import","Html",D.blue "exposing","(Html, div, text)"]
867 , D.fillSep [D.blue "import","Html",D.blue "as","H",D.blue "exposing","(..)"]
868 ]
869 , D.reflow $
870 "You are probably trying to import a different module, but try to make it look like one of these examples!"
871 ]
872 )
876-- SPACES
879toSpaceReport :: Code.Source -> Space -> Row -> Col -> Report.Report
880toSpaceReport source space row col =
881 case space of
882 HasTab ->
883 let
884 region = toRegion row col
885 in
886 Report.Report "NO TABS" region [] $
887 Code.toSnippet source region Nothing
888 (
889 D.reflow $
890 "I ran into a tab, but tabs are not allowed in Elm files."
891 ,
892 D.reflow $
893 "Replace the tab with spaces."
894 )
896 EndlessMultiComment ->
897 let
898 region = toWiderRegion row col 2
899 in
900 Report.Report "ENDLESS COMMENT" region [] $
901 Code.toSnippet source region Nothing
902 (
903 D.reflow $
904 "I cannot find the end of this multi-line comment:"
905 ,
906 D.stack -- "{-"
907 [ D.reflow "Add a -} somewhere after this to end the comment."
908 , D.toSimpleHint
909 "Multi-line comments can be nested in Elm, so {- {- -} -} is a comment\
910 \ that happens to contain another comment. Like parentheses and curly braces,\
911 \ the start and end markers must always be balanced. Maybe that is the problem?"
912 ]
913 )
917-- DECLARATIONS
920toRegion :: Row -> Col -> A.Region
921toRegion row col =
922 let
923 pos = A.Position row col
924 in
925 A.Region pos pos
928toWiderRegion :: Row -> Col -> Word16 -> A.Region
929toWiderRegion row col extra =
930 A.Region
931 (A.Position row col)
932 (A.Position row (col + extra))
935toDeclarationsReport :: Code.Source -> Decl -> Report.Report
936toDeclarationsReport source decl =
937 case decl of
938 DeclStart row col ->
939 error "TODO DeclStart" row col
941 DeclSpace space row col ->
942 toSpaceReport source space row col
944 Port port row col ->
945 error "TODO Port" port row col
947 DeclType declType row col ->
948 error "TODO DeclType" declType row col
950 DeclDef name declDef row col ->
951 toDeclDefReport source name declDef row col
953 DeclFreshLineStart row col ->
954 error "TODO DeclFreshLineStart" row col
956 DeclFreshLineAfterDocComment row col ->
957 error "TODO DeclFreshLineAfterDocComment" row col
960toDeclDefReport :: Code.Source -> Name.Name -> DeclDef -> Row -> Col -> Report.Report
961toDeclDefReport source name declDef startRow startCol =
962 case declDef of
963 DeclDefSpace space row col ->
964 toSpaceReport source space row col
966 DeclDefEquals row col ->
967 error "TODO DeclDefEquals" row col
969 DeclDefType tipe row col ->
970 error "TODO DeclDefType" tipe row col
972 DeclDefArg pattern row col ->
973 error "TODO DeclDefArg" pattern row col
975 DeclDefBody expr row col ->
976 toExprReport source (InDef name startRow startCol) expr row col
978 DeclDefNameRepeat row col ->
979 error "TODO DeclDefNameRepeat" name row col
981 DeclDefNameMatch defName row col ->
982 error "TODO DeclDefNameMatch" name defName row col
984 DeclDefIndentType row col ->
985 error "TODO DeclDefIndentType" row col
987 DeclDefIndentEquals row col ->
988 error "TODO DeclDefIndentEquals" row col
990 DeclDefIndentBody row col ->
991 error "TODO DeclDefIndentBody" row col
993 DeclDefFreshLineAfterType row col ->
994 error "TODO DeclDefFreshLineAfterType" row col
998-- CONTEXT
1001data Context
1002 = InNode Node Row Col Context
1003 | InDef Name.Name Row Col
1006data Node
1007 = NRecord
1008 | NParens
1009 | NList
1010 | NFunc
1011 | NCond
1012 | NThen
1013 | NElse
1014 deriving (Eq)
1017getDefName :: Context -> Name.Name
1018getDefName context =
1019 case context of
1020 InDef name _ _ -> name
1021 InNode _ _ _ c -> getDefName c
1024isWithin :: Node -> Context -> Bool
1025isWithin desiredNode context =
1026 case context of
1027 InDef _ _ _ -> False
1028 InNode actualNode _ _ _ -> desiredNode == actualNode
1032-- EXPR REPORTS
1035toExprReport :: Code.Source -> Context -> Expr -> Row -> Col -> Report.Report
1036toExprReport source context expr startRow startCol =
1037 case expr of
1038 Let _ _ _ ->
1039 error "TODO Let"
1041 Case _ _ _ ->
1042 error "TODO Case"
1044 If if_ row col ->
1045 toIfReport source context if_ row col
1047 List list row col ->
1048 toListReport source context list row col
1050 Record record row col ->
1051 toRecordReport source context record row col
1053 Tuple tuple row col ->
1054 toTupleReport source context tuple row col
1056 Func func row col ->
1057 toFuncReport source context func row col
1059 Dot row col ->
1060 let region = toRegion row col in
1061 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
1062 Code.toSnippet source region Nothing
1064 D.reflow $
1065 "I was expecting to see a record accessor here:"
1067 D.fillSep
1068 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
1069 ,"that","accesses","a","value","from","a","record."
1073 Access row col ->
1074 let region = toRegion row col in
1075 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
1076 Code.toSnippet source region Nothing
1078 D.reflow $
1079 "I am trying to parse a record accessor here:"
1081 D.stack
1083 D.fillSep
1084 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
1085 ,"that","accesses","a","value","from","a","record."
1088 D.toSimpleNote $
1089 "Record field names must start with a lower case letter!"
1093 OperatorRight op row col ->
1094 let region = toRegion row col in
1095 Report.Report "MISSING EXPRESSION" region [] $
1096 Code.toSnippet source region Nothing
1098 D.reflow $
1099 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
1101 D.stack
1102 [ D.fillSep $
1103 ["You","can","just","put","anything","for","now,","like"
1104 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1105 ,"Once","there","is","something","there,","I","can","probably"
1106 ,"give","a","more","specific","hint!"
1108 , D.toSimpleNote $
1109 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
1110 \ Or if I run into operators in unexpected spots. Point is, there are a\
1111 \ couple ways I can get confused and give sort of weird advice!"
1115 OperatorReserved operator row col ->
1116 toOperatorReport source context operator row col
1118 Start row col ->
1119 let
1120 (contextRow, contextCol, aThing) =
1121 case context of
1122 InDef name r c -> (r, c, "the `" ++ Name.toChars name ++ "` definition")
1123 InNode NRecord r c _ -> (r, c, "a record")
1124 InNode NParens r c _ -> (r, c, "some parentheses")
1125 InNode NList r c _ -> (r, c, "a list")
1126 InNode NFunc r c _ -> (r, c, "an anonymous function")
1127 InNode NCond r c _ -> (r, c, "an `if` expression")
1128 InNode NThen r c _ -> (r, c, "an `if` expression")
1129 InNode NElse r c _ -> (r, c, "an `if` expression")
1130 -- TODO check if this is actually the best way to get error messages here
1132 surroundings = A.Region (A.Position contextRow contextCol) (A.Position row col)
1133 region = toRegion row col
1134 in
1135 Report.Report "MISSING EXPRESSION" region [] $
1136 Code.toSnippet source surroundings (Just region)
1138 D.reflow $
1139 "I am partway through parsing " ++ aThing ++ ", but I got stuck here:"
1141 D.stack
1142 [ D.fillSep $
1143 ["I","was","expecting","to","see","an","expression","like"
1144 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1145 ,"Once","there","is","something","there,","I","can","probably"
1146 ,"give","a","more","specific","hint!"
1148 , D.toSimpleNote $
1149 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
1150 \ Or if I run into operators in unexpected spots. Point is, there are a\
1151 \ couple ways I can get confused and give sort of weird advice!"
1155 Char char row col ->
1156 toCharReport source char row col
1158 String string row col ->
1159 toStringReport source string row col
1161 Number number row col ->
1162 toNumberReport source number row col
1164 Space space row col ->
1165 toSpaceReport source space row col
1167 EndlessShader row col ->
1168 let
1169 region = toWiderRegion row col 6
1170 in
1171 Report.Report "ENDLESS SHADER" region [] $
1172 Code.toSnippet source region Nothing
1174 D.reflow "I cannot find the end of this shader:"
1176 D.reflow "Add a |] somewhere after this to end the shader."
1179 ShaderProblem problem row col ->
1180 let
1181 region = toRegion row col
1182 in
1183 Report.Report "SHADER PROBLEM" region [] $
1184 Code.toSnippet source region Nothing
1186 D.reflow $
1187 "I ran into a problem while parsing this GLSL block."
1189 D.stack
1190 [ D.reflow $
1191 "I use a 3rd party GLSL parser for now, and I did my best to extract their error message:"
1192 , D.indent 4 $ D.vcat $
1193 map D.fromChars (filter (/="") (lines problem))
1197 IndentOperatorRight op row col ->
1198 let
1199 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1200 region = toRegion row col
1201 in
1202 Report.Report "MISSING EXPRESSION" region [] $
1203 Code.toSnippet source surroundings (Just region)
1205 D.reflow $
1206 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
1208 D.stack
1210 D.fillSep $
1211 ["You","can","just","put","anything","for","now,","like"
1212 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1213 ,"Once","there","is","something","there,","I","can","probably"
1214 ,"give","a","more","specific","hint!"
1217 D.toSimpleNote $
1218 "I may be getting confused by your indentation? The easiest way to make sure\
1219 \ this is not an indentation problem is to put the expression on the right of\
1220 \ the " ++ Name.toChars op ++ " operator on the same line."
1224 IndentMoreExpr _ _ ->
1225 error "TODO IndentMoreExpr"
1229-- CHAR
1232toCharReport :: Code.Source -> Char -> Row -> Col -> Report.Report
1233toCharReport source char row col =
1234 case char of
1235 CharEndless ->
1236 let
1237 region = toRegion row col
1238 in
1239 Report.Report "MISSING SINGLE QUOTE" region [] $
1240 Code.toSnippet source region Nothing
1242 D.reflow $
1243 "I thought I was parsing a character, but I got to the end of\
1244 \ the line without seeing the closing single quote:"
1246 D.reflow $
1247 "Add a closing single quote here!"
1250 CharEscape escape ->
1251 toEscapeReport source escape row col
1253 CharNotString width ->
1254 let
1255 region = toWiderRegion row col width
1256 in
1257 Report.Report "NEEDS DOUBLE QUOTES" region [] $
1258 Code.toSnippet source region Nothing
1260 "The following string uses single quotes:"
1262 D.stack
1263 [ "Please switch to double quotes instead:"
1264 , D.indent 4 $
1265 D.dullyellow "'this'" <> " => " <> D.green "\"this\""
1266 , D.toSimpleNote $
1267 "Elm uses double quotes for strings like \"hello\", whereas it uses single\
1268 \ quotes for individual characters like 'a' and 'ø'. This distinction helps with\
1269 \ code like (String.any (\\c -> c == 'X') \"90210\") where you are inspecting\
1270 \ individual characters."
1276-- STRING
1279toStringReport :: Code.Source -> String -> Row -> Col -> Report.Report
1280toStringReport source string row col =
1281 case string of
1282 StringEndless_Single ->
1283 let
1284 region = toRegion row col
1285 in
1286 Report.Report "ENDLESS STRING" region [] $
1287 Code.toSnippet source region Nothing
1289 D.reflow $
1290 "I got to the end of the line without seeing the closing double quote:"
1292 D.stack
1293 [ D.fillSep $
1294 ["Strings","look","like",D.green "\"this\"","with","double"
1295 ,"quotes","on","each","end.","Is","the","closing","double"
1296 ,"quote","missing","in","your","code?"
1298 , D.link "Note" "Read" "TODO" "if you want a string that spans multiple lines."
1302 StringEndless_Multi ->
1303 let
1304 region = toWiderRegion row col 3
1305 in
1306 Report.Report "ENDLESS STRING" region [] $
1307 Code.toSnippet source region Nothing
1309 D.reflow $
1310 "I cannot find the end of this multi-line string:"
1312 D.stack
1313 [ D.reflow "Add a \"\"\" somewhere after this to end the string."
1314 , D.link "Hint" "Read" "TODO" "for more information on strings and multi-line strings."
1318 StringEscape escape ->
1319 toEscapeReport source escape row col
1323-- ESCAPES
1326toEscapeReport :: Code.Source -> Escape -> Row -> Col -> Report.Report
1327toEscapeReport source escape row col =
1328 case escape of
1329 EscapeUnknown ->
1330 let
1331 region = toWiderRegion row col 2
1332 in
1333 Report.Report "UNKNOWN ESCAPE" region [] $
1334 Code.toSnippet source region Nothing
1336 D.reflow $
1337 "Backslashes always start escaped characters, but I do not recognize this one:"
1339 D.stack
1340 [ D.reflow $
1341 "Valid escape characters include:"
1342 , D.dullyellow $ D.indent 4 $ D.vcat $
1343 [ "\\n"
1344 , "\\r"
1345 , "\\t"
1346 , "\\\""
1347 , "\\\'"
1348 , "\\\\"
1349 , "\\u{003D}"
1351 , D.reflow $
1352 "Do you want one of those instead? Maybe you need \\\\ to escape a backslash?"
1353 , D.toSimpleNote $
1354 "The last style lets encode ANY character by its Unicode code\
1355 \ point. That means \\u{0009} and \\t are the same. You can use\
1356 \ that style for anything not covered by the other six escapes!"
1360 BadUnicodeFormat width ->
1361 let
1362 region = toWiderRegion row col width
1363 in
1364 Report.Report "BAD UNICODE ESCAPE" region [] $
1365 Code.toSnippet source region Nothing
1367 D.reflow $
1368 "I ran into an invalid Unicode escape:"
1370 D.stack
1371 [ D.reflow $
1372 "Here are some examples of valid Unicode escapes:"
1373 , D.dullyellow $ D.indent 4 $ D.vcat $
1374 [ "\\u{0041}"
1375 , "\\u{03BB}"
1376 , "\\u{6728}"
1377 , "\\u{1F60A}"
1379 , D.reflow $
1380 "Notice that the code point is always surrounded by curly braces.\
1381 \ Maybe you are missing the opening or closing curly brace?"
1384 BadUnicodeCode width ->
1385 let
1386 region = toWiderRegion row col width
1387 in
1388 Report.Report "BAD UNICODE ESCAPE" region [] $
1389 Code.toSnippet source region Nothing
1391 D.reflow $
1392 "This is not a valid code point:"
1394 D.reflow $
1395 "The valid code points are between 0 and 10FFFF inclusive."
1398 BadUnicodeLength width numDigits badCode ->
1399 let
1400 region = toWiderRegion row col width
1401 in
1402 Report.Report "BAD UNICODE ESCAPE" region [] $
1403 Code.toSnippet source region Nothing $
1404 if numDigits < 4 then
1406 D.reflow $
1407 "Every code point needs at least four digits:"
1409 let
1410 goodCode = replicate (4 - numDigits) '0' ++ map Char.toUpper (showHex badCode "")
1411 suggestion = "\\u{" <> D.fromChars goodCode <> "}"
1412 in
1413 D.fillSep ["Try",D.green suggestion,"instead?"]
1416 else
1418 D.reflow $
1419 "This code point has too many digits:"
1421 D.fillSep $
1422 ["Valid","code","points","are","between"
1423 ,D.green "\\u{0000}","and",D.green "\\u{10FFFF}" <> ","
1424 ,"so","try","trimming","any","leading","zeros","until"
1425 ,"you","have","between","four","and","six","digits."
1431-- NUMBERS
1434toNumberReport :: Code.Source -> Number -> Row -> Col -> Report.Report
1435toNumberReport source number row col =
1436 let
1437 region = toRegion row col
1438 in
1439 case number of
1440 NumberEnd ->
1441 Report.Report "WEIRD NUMBER" region [] $
1442 Code.toSnippet source region Nothing
1444 D.reflow $
1445 "I thought I was reading a number, but I ran into some weird stuff here:"
1447 D.stack
1448 [ D.reflow $
1449 "I recognize numbers in the following formats:"
1450 , D.indent 4 $ D.vcat [ "42", "3.14", "6.022e23", "0x002B" ]
1451 , D.reflow $
1452 "So is there a way to write it like one of those?"
1456 NumberDot int ->
1457 Report.Report "WEIRD NUMBER" region [] $
1458 Code.toSnippet source region Nothing
1460 D.reflow $
1461 "Numbers cannot end with a dot like this:"
1463 D.fillSep
1464 ["Switching","to",D.green (D.fromChars (show int))
1465 ,"or",D.green (D.fromChars (show int ++ ".0"))
1466 ,"will","work","though!"
1470 NumberHexDigit ->
1471 Report.Report "WEIRD HEXIDECIMAL" region [] $
1472 Code.toSnippet source region Nothing
1474 D.reflow $
1475 "I thought I was reading a hexidecimal number until I got here:"
1477 D.stack
1478 [ D.reflow $
1479 "Valid hexidecimal digits include 0123456789abcdefABCDEF, so I can\
1480 \ only recognize things like this:"
1481 , D.indent 4 $ D.vcat [ "0x2B", "0x002B", "0x00ffb3" ]
1485 NumberNoLeadingZero ->
1486 Report.Report "LEADING ZEROS" region [] $
1487 Code.toSnippet source region Nothing
1489 D.reflow $
1490 "I do not accept numbers with leading zeros:"
1492 D.stack
1493 [ D.reflow $
1494 "Just delete the leading zeros and it should work!"
1495 , D.toSimpleNote $
1496 "Some languages let you to specify octal numbers by adding a leading zero.\
1497 \ So in C, writing 0111 is the same as writing 73. Some people are used to\
1498 \ that, but others probably want it to equal 111. Either path is going to\
1499 \ surprise people from certain backgrounds, so Elm tries to avoid this whole\
1500 \ situation."
1506-- OPERATORS
1509toOperatorReport :: Code.Source -> Context -> BadOperator -> Row -> Col -> Report.Report
1510toOperatorReport source context operator row col =
1511 case operator of
1512 BadDot ->
1513 let
1514 region = toRegion row col
1515 in
1516 Report.Report "UNEXPECTED SYMBOL" region [] $
1517 Code.toSnippet source region Nothing
1519 "I was not expecting this dot:"
1521 D.reflow $
1522 "Dots are for record access and decimal points, so\
1523 \ they cannot float around on their own. Maybe\
1524 \ there is some extra whitespace?"
1527 BadPipe ->
1528 let
1529 region = toRegion row col
1530 in
1531 Report.Report "UNEXPECTED SYMBOL" region [] $
1532 Code.toSnippet source region Nothing
1534 D.reflow $
1535 "I was not expecting this vertical bar:"
1537 D.reflow $
1538 "Vertical bars should only appear in custom type declarations. Maybe you want || instead?"
1541 BadArrow ->
1542 let
1543 region = toWiderRegion row col 2
1544 in
1545 Report.Report "UNEXPECTED ARROW" region [] $
1546 Code.toSnippet source region Nothing $
1547 if error "TODO inCase" then
1549 D.reflow $
1550 "I was not expecting to see an arrow here:"
1552 D.stack
1554 D.reflow $
1555 "I think I am parsing a `case` expression right now, so it makes sense to\
1556 \ see arrows around here. This one is confusing me though!"
1558 D.toSimpleHint $
1559 "I may be getting confused by the indentation. Every pattern in a `case` must be\
1560 \ exactly aligned (with exactly the same amount of indentation) so maybe this arrow\
1561 \ appears after the next `case` pattern (correctly!) but the pattern itself is\
1562 \ indented too far?"
1566 else
1568 D.reflow $
1569 "I was not expecting an arrow here:"
1571 D.reflow $
1572 "Arrows should only appear in `case` expressions and anonymous functions. Maybe\
1573 \ you want > or >= instead?"
1576 BadEquals ->
1577 let
1578 region = toRegion row col
1579 name = getDefName context
1580 in
1581 Report.Report "UNEXPECTED EQUALS" region [] $
1582 Code.toSnippet source region Nothing
1584 D.reflow $
1585 "I was not expecting to see this equals sign:"
1587 D.stack
1589 D.reflow "Maybe you want == instead? To check if two values are equal?"
1591 D.toSimpleNote $
1592 if isWithin NRecord context then
1593 "Records look like { x = 3, y = 4 } with the equals sign right\
1594 \ after the field name. So maybe you forgot a comma?"
1595 else
1596 "I may be getting confused by your indentation. Is this supposed to be part of\
1597 \ a definition AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
1598 \ the problem may be a bit before the equals sign. I need all definitions to\
1599 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
1600 \ this new definition is indented a bit too much."
1604 BadHasType ->
1605 let
1606 region = toRegion row col
1607 name = getDefName context
1608 in
1609 Report.Report "UNEXPECTED SYMBOL" region [] $
1610 Code.toSnippet source region Nothing $
1612 D.reflow $
1613 "I was not expecting to run into the \"has type\" symbol here:"
1615 D.stack
1617 D.fillSep
1618 ["Maybe","you","want",D.green "::","instead?"
1619 ,"To","put","something","on","the","front","of","a","list?"
1621 , D.toSimpleNote $
1622 "The single colon is reserved for type annotations and record types, but I think\
1623 \ I am parsing the definition of `" ++ Name.toChars name ++ "` right now."
1625 D.toSimpleNote $
1626 "I may be getting confused by your indentation. Is this supposed to be part of\
1627 \ a type annotation AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
1628 \ the problem may be a bit before the \"has type\" symbol. I need all definitions to\
1629 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
1630 \ this new definition is indented a bit too much."
1636-- IF
1639toIfReport :: Code.Source -> Context -> If -> Row -> Col -> Report.Report
1640toIfReport source context if_ startRow startCol =
1641 case if_ of
1642 IfSpace space row col ->
1643 toSpaceReport source space row col
1645 IfThen row col ->
1646 let
1647 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1648 region = toRegion row col
1649 in
1650 Report.Report "UNFINISHED IF" region [] $
1651 Code.toSnippet source surroundings (Just region)
1653 D.reflow $
1654 "I was expecting to see more of this `if` expression, but I got stuck here:"
1656 D.fillSep $
1657 ["I","was","expecting","to","see","the",D.green "then","keyword","next."
1661 IfElse row col ->
1662 let
1663 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1664 region = toRegion row col
1665 in
1666 Report.Report "UNFINISHED IF" region [] $
1667 Code.toSnippet source surroundings (Just region)
1669 D.reflow $
1670 "I was expecting to see more of this `if` expression, but I got stuck here:"
1672 D.fillSep $
1673 ["I","was","expecting","to","see","the",D.green "else","keyword","next."
1677 IfElseBranchStart row col ->
1678 let
1679 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1680 region = toRegion row col
1681 in
1682 Report.Report "UNFINISHED IF" region [] $
1683 Code.toSnippet source surroundings (Just region)
1685 D.reflow $
1686 "I just saw the start of an `else` branch, but then I got stuck here:"
1688 D.reflow $
1689 "I was expecting to see an expression next. Maybe it is not filled in yet?"
1692 IfCondition expr row col ->
1693 toExprReport source (InNode NCond startRow startCol context) expr row col
1695 IfThenBranch expr row col ->
1696 toExprReport source (InNode NThen startRow startCol context) expr row col
1698 IfElseBranch expr row col ->
1699 toExprReport source (InNode NElse startRow startCol context) expr row col
1701 IfIndentCondition row col ->
1702 let
1703 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1704 region = toRegion row col
1705 in
1706 Report.Report "UNFINISHED IF" region [] $
1707 Code.toSnippet source surroundings (Just region)
1709 D.reflow $
1710 "I was expecting to see more of this `if` expression, but I got stuck here:"
1712 D.stack
1713 [ D.fillSep $
1714 ["I","was","expecting","to","see","an","expression","like",D.dullyellow "x < 0"
1715 ,"that","evaluates","to","True","or","False."
1717 , D.toSimpleNote $
1718 "I can be confused by indentation. Maybe something is not indented enough?"
1722 IfIndentThen row col ->
1723 let
1724 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1725 region = toRegion row col
1726 in
1727 Report.Report "UNFINISHED IF" region [] $
1728 Code.toSnippet source surroundings (Just region)
1730 D.reflow $
1731 "I was expecting to see more of this `if` expression, but I got stuck here:"
1733 D.stack
1734 [ D.fillSep $
1735 ["I","was","expecting","to","see","the",D.green "then","keyword","next."
1737 , D.toSimpleNote $
1738 "I can be confused by indentation. Maybe something is not indented enough?"
1742 IfIndentThenBranch row col ->
1743 let
1744 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1745 region = toRegion row col
1746 in
1747 Report.Report "UNFINISHED IF" region [] $
1748 Code.toSnippet source surroundings (Just region)
1750 D.reflow $
1751 "I got stuck after the start of this `then` branch:"
1753 D.stack
1754 [ D.reflow $
1755 "I was expecting to see an expression next. Maybe it is not filled in yet?"
1756 , D.toSimpleNote $
1757 "I can be confused by indentation, so if the `then` branch is already\
1758 \ present, it may not be indented enough for me to recognize it."
1762 IfIndentElseBranch row col ->
1763 let
1764 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1765 region = toRegion row col
1766 in
1767 Report.Report "UNFINISHED IF" region [] $
1768 Code.toSnippet source surroundings (Just region)
1770 D.reflow $
1771 "I got stuck after the start of this `else` branch:"
1773 D.stack
1774 [ D.reflow $
1775 "I was expecting to see an expression next. Maybe it is not filled in yet?"
1776 , D.toSimpleNote $
1777 "I can be confused by indentation, so if the `else` branch is already\
1778 \ present, it may not be indented enough for me to recognize it."
1782 IfIndentElse row col ->
1783 let
1784 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1785 region = toRegion row col
1786 in
1787 Report.Report "UNFINISHED IF" region [] $
1788 Code.toSnippet source surroundings (Just region)
1790 D.reflow $
1791 "I was expecting to see an `else` branch after this:"
1793 D.stack
1794 [ D.reflow $
1795 "I know what to do when the condition is `True`, but not when it is `False`."
1796 , D.fillSep
1797 ["Add","an",D.green "else","branch","to","handle","that","scenario!"]
1803-- RECORD
1806toRecordReport :: Code.Source -> Context -> Record -> Row -> Col -> Report.Report
1807toRecordReport source context record startRow startCol =
1808 case record of
1809 RecordOpen row col ->
1810 let
1811 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1812 region = toRegion row col
1813 in
1814 case Code.whatIsNext source row col of
1815 Code.Keyword keyword ->
1816 Report.Report "RESERVED WORD" region [] $
1817 Code.toSnippet source surroundings (Just region)
1819 D.reflow $
1820 "I just started parsing a record, but I got stuck on this field name:"
1822 D.reflow $
1823 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
1824 \ that is a reserved word. Try using a different name!"
1827 _ ->
1828 Report.Report "UNFINISHED RECORD" region [] $
1829 Code.toSnippet source surroundings (Just region)
1831 D.reflow $
1832 "I just started parsing a record, but I got stuck here:"
1834 D.fillSep
1835 ["Records","look","like",D.dullyellow "{ x = 3, y = 4 },"
1836 ,"so","I","was","expecting","to","see","a","field","name","next."
1840 RecordEnd row col ->
1841 let
1842 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1843 region = toRegion row col
1844 in
1845 Report.Report "UNFINISHED RECORD" region [] $
1846 Code.toSnippet source surroundings (Just region)
1848 D.reflow $
1849 "I am partway through parsing a record, but I got stuck here:"
1851 D.stack
1852 [ D.fillSep
1853 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
1854 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
1856 , D.toSimpleNote $
1857 "When I get stuck like this, it usually means that there is a missing parenthesis\
1858 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
1862 RecordField row col ->
1863 let
1864 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1865 region = toRegion row col
1866 in
1867 case Code.whatIsNext source row col of
1868 Code.Keyword keyword ->
1869 Report.Report "RESERVED WORD" region [] $
1870 Code.toSnippet source surroundings (Just region)
1872 D.reflow $
1873 "I am partway through parsing a record, but I got stuck on this field name:"
1875 D.reflow $
1876 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
1877 \ that is a reserved word. Try using a different name!"
1880 _ ->
1881 Report.Report "UNFINISHED RECORD" region [] $
1882 Code.toSnippet source surroundings (Just region)
1884 D.reflow $
1885 "I am partway through parsing a record, but I got stuck after that last comma:"
1887 addNoteForRecordError $
1888 D.reflow $
1889 "Trailing commas are not allowed in records, so I was expecting to see another\
1890 \ record field defined next. If you are done defining the record, the fix may\
1891 \ be to delete that last comma?"
1894 RecordEquals row col ->
1895 let
1896 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1897 region = toRegion row col
1898 in
1899 Report.Report "UNFINISHED RECORD" region [] $
1900 Code.toSnippet source surroundings (Just region)
1902 D.reflow $
1903 "I am partway through parsing a record, but I got stuck here:"
1905 addNoteForRecordError $
1906 D.fillSep $
1907 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
1908 ,"an","equals","sign","next.","So","try","putting","an",D.green "=","sign","here?"
1912 RecordExpr expr row col ->
1913 toExprReport source (InNode NRecord startRow startCol context) expr row col
1915 RecordSpace space row col ->
1916 toSpaceReport source space row col
1918 RecordIndentOpen row col ->
1919 let
1920 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1921 region = toRegion row col
1922 in
1923 Report.Report "UNFINISHED RECORD" region [] $
1924 Code.toSnippet source surroundings (Just region)
1926 D.reflow $
1927 "I just saw the opening curly brace of a record, but then I got stuck here:"
1929 addNoteForRecordIndentError $
1930 D.fillSep $
1931 ["I","am","expecting","a","record","like",D.dullyellow "{ x = 3, y = 4 }","here."
1932 ,"Try","defining","some","fields","of","your","own?"
1936 RecordIndentEnd row col ->
1937 let
1938 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1939 region = toRegion row col
1940 in
1941 Report.Report "UNFINISHED RECORD" region [] $
1942 Code.toSnippet source surroundings (Just region)
1944 D.reflow $
1945 "I was expecting to see a closing curly brace next:"
1947 addNoteForRecordIndentError $
1948 D.fillSep $
1949 ["Try","putting","an",D.green "}","and","see","if","that","helps?"
1953 RecordIndentField row col ->
1954 let
1955 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1956 region = toRegion row col
1957 in
1958 Report.Report "UNFINISHED RECORD" region [] $
1959 Code.toSnippet source surroundings (Just region)
1961 D.reflow $
1962 "I am partway through parsing a record, but I got stuck after that last comma:"
1964 addNoteForRecordError $
1965 D.reflow $
1966 "Trailing commas are not allowed in records, so the fix may be to\
1967 \ delete that last comma? Or maybe you were in the middle of defining\
1968 \ an additional field?"
1971 RecordIndentEquals row col ->
1972 let
1973 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1974 region = toRegion row col
1975 in
1976 Report.Report "UNFINISHED RECORD" region [] $
1977 Code.toSnippet source surroundings (Just region)
1979 D.reflow $
1980 "I am partway through parsing a record. I just saw a record\
1981 \ field, so I was expecting to see an equals sign next:"
1983 addNoteForRecordIndentError $
1984 D.fillSep $
1985 ["Try","putting","an",D.green "=","followed","by","an","expression?"
1989 RecordIndentExpr row col ->
1990 let
1991 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1992 region = toRegion row col
1993 in
1994 Report.Report "UNFINISHED RECORD" region [] $
1995 Code.toSnippet source surroundings (Just region)
1997 D.reflow $
1998 "I am partway through parsing a record, and I was expecting to run into an expression next:"
2000 addNoteForRecordIndentError $
2001 D.fillSep $
2002 ["Try","putting","something,","like"
2003 ,D.dullyellow "42","or",D.dullyellow"\"hello\"","for","now?"
2008addNoteForRecordError :: D.Doc -> D.Doc
2009addNoteForRecordError normalRecommendation =
2010 D.stack $
2011 normalRecommendation
2013 [ D.toSimpleNote
2014 "If you are trying to define a record across multiple lines, I recommend using this format:"
2015 , D.indent 4 $ D.vcat $
2016 [ "{ name = \"Alice\""
2017 , ", age = 42"
2018 , ", height = 1.75"
2019 , "}"
2021 , D.reflow $
2022 "Notice that nothing comes directly after a newline. Each line starts with some spaces. I\
2023 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
2024 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2028addNoteForRecordIndentError :: D.Doc -> D.Doc
2029addNoteForRecordIndentError normalRecommendation =
2030 D.stack $
2031 normalRecommendation
2033 [ D.toSimpleNote
2034 "I may be confused by indentation. For example, if you are trying to define\
2035 \ a record across multiple lines, I recommend using this format:"
2036 , D.indent 4 $ D.vcat $
2037 [ "[ \"Alice\""
2038 , ", \"Bob\""
2039 , ", \"Chuck\""
2040 , "]"
2042 , D.reflow $
2043 "Notice that nothing comes directly after a newline. Each line starts with some spaces. I\
2044 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
2045 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2050-- TUPLE
2053toTupleReport :: Code.Source -> Context -> Tuple -> Row -> Col -> Report.Report
2054toTupleReport source context tuple startRow startCol =
2055 case tuple of
2056 TupleExpr expr row col ->
2057 toExprReport source (InNode NParens startRow startCol context) expr row col
2059 TupleSpace space row col ->
2060 toSpaceReport source space row col
2062 TupleEnd row col ->
2063 let
2064 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2065 region = toRegion row col
2066 in
2067 Report.Report "UNFINISHED PARENTHESES" region [] $
2068 Code.toSnippet source surroundings (Just region)
2070 D.reflow $
2071 "I was expecting to see a closing parentheses next, but I got stuck here:"
2073 D.stack
2074 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
2075 , D.toSimpleNote $
2076 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
2077 \ unexpectedly. So there may be some earlier syntax trouble (like extra parenthesis\
2078 \ or missing brackets) that is confusing me."
2082 TupleOperatorClose row col ->
2083 let
2084 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2085 region = toRegion row col
2086 in
2087 Report.Report "UNFINISHED OPERATOR FUNCTION" region [] $
2088 Code.toSnippet source surroundings (Just region)
2090 D.reflow "I was expecting a closing parenthesis here:"
2092 D.stack
2093 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
2094 , D.toSimpleNote $
2095 "I think I am parsing an operator function right now, so I am expecting to see\
2096 \ something like (+) or (&&) where an operator is surrounded by parentheses with\
2097 \ no extra spaces."
2101 TupleOperatorReserved operator 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 "UNEXPECTED SYMBOL" region [] $
2107 Code.toSnippet source surroundings (Just region)
2109 D.reflow $
2110 "I ran into an unexpected symbol here:"
2112 D.fillSep $
2113 case operator of
2114 BadDot -> ["Maybe","you","wanted","a","record","accessor","like",D.dullyellow ".x","or",D.dullyellow ".name","instead?"]
2115 BadPipe -> ["Try",D.dullyellow "(||)","instead?","To","turn","boolean","OR","into","a","function?"]
2116 BadArrow -> ["Maybe","you","wanted",D.dullyellow "(>)","or",D.dullyellow "(>=)","instead?"]
2117 BadEquals -> ["Try",D.dullyellow "(==)","instead?","To","make","a","function","that","checks","equality?"]
2118 BadHasType -> ["Try",D.dullyellow "(::)","instead?","To","add","values","to","the","front","of","lists?"]
2121 TupleIndentExpr1 row col ->
2122 let
2123 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2124 region = toRegion row col
2125 in
2126 Report.Report "UNFINISHED PARENTHESES" region [] $
2127 Code.toSnippet source surroundings (Just region)
2129 D.reflow $
2130 "I just saw an open parenthesis, so I was expecting to see an expression next."
2132 D.stack
2133 [ D.fillSep $
2134 ["Something","like",D.dullyellow "(4 + 5)","or"
2135 ,D.dullyellow "(String.reverse \"desserts\")" <> "."
2136 ,"Anything","where","you","are","putting","parentheses","around","normal","expressions."
2138 , D.toSimpleNote $
2139 "I can get confused by indentation in cases like this, so\
2140 \ maybe you have an expression but it is not indented enough?"
2144 TupleIndentExprN row col ->
2145 let
2146 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2147 region = toRegion row col
2148 in
2149 Report.Report "UNFINISHED TUPLE" region [] $
2150 Code.toSnippet source surroundings (Just region)
2152 D.reflow $
2153 "I think I am in the middle of parsing a tuple. I just saw a comma, so I was expecting to see expression next."
2155 D.stack
2156 [ D.fillSep $
2157 ["A","tuple","looks","like",D.dullyellow "(3,4)","or"
2158 ,D.dullyellow "(\"Tom\",42)" <> ","
2159 ,"so","I","think","there","is","an","expression","missing","here?"
2161 , D.toSimpleNote $
2162 "I can get confused by indentation in cases like this, so\
2163 \ maybe you have an expression but it is not indented enough?"
2167 TupleIndentEnd row col ->
2168 let
2169 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2170 region = toRegion row col
2171 in
2172 Report.Report "UNFINISHED PARENTHESES" region [] $
2173 Code.toSnippet source surroundings (Just region)
2175 D.reflow $
2176 "I was expecting to see a closing parenthesis next:"
2178 D.stack
2179 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
2180 , D.toSimpleNote $
2181 "I can get confused by indentation in cases like this, so\
2182 \ maybe you have a closing parenthesis but it is not indented enough?"
2187toListReport :: Code.Source -> Context -> List -> Row -> Col -> Report.Report
2188toListReport source context list startRow startCol =
2189 case list of
2190 ListSpace space row col ->
2191 toSpaceReport source space row col
2193 ListOpen row col ->
2194 let
2195 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2196 region = toRegion row col
2197 in
2198 Report.Report "UNFINISHED LIST" region [] $
2199 Code.toSnippet source surroundings (Just region)
2201 D.reflow $
2202 "I am partway through parsing a list, but I got stuck here:"
2204 D.stack
2205 [ D.fillSep
2206 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
2207 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
2209 , D.toSimpleNote $
2210 "When I get stuck like this, it usually means that there is a missing parenthesis\
2211 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
2215 ListExpr expr row col ->
2216 case expr of
2217 Start r c ->
2218 let
2219 surroundings = A.Region (A.Position startRow startCol) (A.Position r c)
2220 region = toRegion r c
2221 in
2222 Report.Report "UNFINISHED LIST" region [] $
2223 Code.toSnippet source surroundings (Just region)
2225 D.reflow $
2226 "I was expecting to see another list entry after that last comma:"
2228 D.stack
2229 [ D.reflow $
2230 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
2231 , D.toSimpleNote
2232 "I recommend using the following format for lists that span multiple lines:"
2233 , D.indent 4 $ D.vcat $
2234 [ "[ \"Alice\""
2235 , ", \"Bob\""
2236 , ", \"Chuck\""
2237 , "]"
2239 , D.reflow $
2240 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2241 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2242 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2246 _ ->
2247 toExprReport source (InNode NList startRow startCol context) expr row col
2249 ListEnd row col ->
2250 let
2251 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2252 region = toRegion row col
2253 in
2254 Report.Report "UNFINISHED LIST" region [] $
2255 Code.toSnippet source surroundings (Just region)
2257 D.reflow $
2258 "I am partway through parsing a list, but I got stuck here:"
2260 D.stack
2261 [ D.fillSep
2262 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
2263 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
2265 , D.toSimpleNote $
2266 "When I get stuck like this, it usually means that there is a missing parenthesis\
2267 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
2271 ListIndentOpen row col ->
2272 let
2273 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2274 region = toRegion row col
2275 in
2276 Report.Report "UNFINISHED LIST" region [] $
2277 Code.toSnippet source surroundings (Just region)
2279 D.reflow $
2280 "I cannot find the end of this list:"
2282 D.stack
2283 [ D.fillSep $
2284 ["You","could","change","it","to","something","like"
2285 ,D.dullyellow "[3,4,5]"
2286 ,"or","even","just"
2287 ,D.dullyellow "[]" <> "."
2288 ,"Anything","where","there","is","an","open","and","close","square","brace,"
2289 ,"and","where","the","elements","of","the","list","are","separated","by","commas."
2291 , D.toSimpleNote
2292 "I may be confused by indentation. For example, if you are trying to define\
2293 \ a list across multiple lines, I recommend using this format:"
2294 , D.indent 4 $ D.vcat $
2295 [ "[ \"Alice\""
2296 , ", \"Bob\""
2297 , ", \"Chuck\""
2298 , "]"
2300 , D.reflow $
2301 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2302 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2303 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2307 ListIndentEnd row col ->
2308 let
2309 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2310 region = toRegion row col
2311 in
2312 Report.Report "UNFINISHED LIST" region [] $
2313 Code.toSnippet source surroundings (Just region)
2315 D.reflow $
2316 "I cannot find the end of this list:"
2318 D.stack
2319 [ D.fillSep $
2320 ["You","can","just","add","a","closing",D.dullyellow "]"
2321 ,"right","here,","and","I","will","be","all","set!"
2323 , D.toSimpleNote
2324 "I may be confused by indentation. For example, if you are trying to define\
2325 \ a list across multiple lines, I recommend using this format:"
2326 , D.indent 4 $ D.vcat $
2327 [ "[ \"Alice\""
2328 , ", \"Bob\""
2329 , ", \"Chuck\""
2330 , "]"
2332 , D.reflow $
2333 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2334 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2335 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2339 ListIndentExpr row col ->
2340 let
2341 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2342 region = toRegion row col
2343 in
2344 Report.Report "UNFINISHED LIST" region [] $
2345 Code.toSnippet source surroundings (Just region)
2347 D.reflow $
2348 "I was expecting to see another list entry after this comma:"
2350 D.stack
2351 [ D.reflow $
2352 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
2353 , D.toSimpleNote
2354 "I recommend using the following format for lists that span multiple lines:"
2355 , D.indent 4 $ D.vcat $
2356 [ "[ \"Alice\""
2357 , ", \"Bob\""
2358 , ", \"Chuck\""
2359 , "]"
2361 , D.reflow $
2362 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2363 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2364 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2369toFuncReport :: Code.Source -> Context -> Func -> Row -> Col -> Report.Report
2370toFuncReport source context func startRow startCol =
2371 case func of
2372 FuncSpace space row col ->
2373 toSpaceReport source space row col
2375 FuncArg pattern row col ->
2376 error "TODO FuncArg" pattern row col
2378 FuncBody expr row col ->
2379 toExprReport source (InNode NFunc startRow startCol context) expr row col
2381 FuncArrow row col ->
2382 let
2383 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2384 region = toRegion row col
2385 in
2386 case Code.whatIsNext source row col of
2387 Code.Keyword keyword ->
2388 Report.Report "RESERVED WORD" region [] $
2389 Code.toSnippet source surroundings (Just region)
2391 D.reflow $
2392 "I was parsing an anonymous function, but I got stuck here:"
2394 D.reflow $
2395 "It looks like you are trying to use `" ++ keyword ++ "` as an argument, but\
2396 \ it is a reserved word in this language. Try using a different argument name!"
2399 _ ->
2400 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
2401 Code.toSnippet source surroundings (Just region)
2403 D.reflow $
2404 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
2406 D.fillSep $
2407 ["The","syntax","for","anonymous","functions","is"
2408 ,D.dullyellow "(\\x -> x + 1)"
2409 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
2413 FuncIndentArg row col ->
2414 let
2415 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2416 region = toRegion row col
2417 in
2418 Report.Report "MISSING ARGUMENT" region [] $
2419 Code.toSnippet source surroundings (Just region)
2421 D.reflow $
2422 "I just saw the beginning of an anonymous function, so I was expecting to see an argument next:"
2424 D.stack
2425 [ D.fillSep
2426 ["Something","like",D.dullyellow"x","or",D.dullyellow "name" <> "."
2427 ,"Anything","that","starts","with","a","lower","case","letter!"
2429 , D.toSimpleNote $
2430 "The syntax for anonymous functions is (\\x -> x + 1) where the backslash\
2431 \ is meant to look a bit like a lambda if you squint. This visual pun seemed\
2432 \ like a better idea at the time!"
2436 FuncIndentArrow row col ->
2437 let
2438 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2439 region = toRegion row col
2440 in
2441 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
2442 Code.toSnippet source surroundings (Just region)
2444 D.reflow $
2445 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
2447 D.stack
2448 [ D.fillSep $
2449 ["The","syntax","for","anonymous","functions","is"
2450 ,D.dullyellow "(\\x -> x + 1)"
2451 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
2453 , D.toSimpleNote $
2454 "It is possible that I am confused about indetation! I generally recommend\
2455 \ switching to named functions if the definition cannot fit inline nicely, so\
2456 \ either (1) try to fit the whole anonymous function on one line or (2) break\
2457 \ the whole thing out into a named function. Things tend to be clearer that way!"
2461 FuncIndentBody row col ->
2462 let
2463 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2464 region = toRegion row col
2465 in
2466 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
2467 Code.toSnippet source surroundings (Just region)
2469 D.reflow $
2470 "I was expecting to see the body of your anonymous function next:"
2472 D.stack
2473 [ D.fillSep $
2474 ["The","syntax","for","anonymous","functions","is"
2475 ,D.dullyellow "(\\x -> x + 1)"
2476 ,"so","I","am","missing","all","the","stuff","after","the","arrow!"
2478 , D.toSimpleNote $
2479 "It is possible that I am confused about indetation! I generally recommend\
2480 \ switching to named functions if the definition cannot fit inline nicely, so\
2481 \ either (1) try to fit the whole anonymous function on one line or (2) break\
2482 \ the whole thing out into a named function. Things tend to be clearer that way!"
2490 case err of
2491 CommentOnNothing region ->
2492 Report.Report "STRAY COMMENT" region [] $
2493 Code.toSnippet source region Nothing
2495 "This documentation comment is not followed by anything."
2497 D.reflow $
2498 "All documentation comments need to be right above the declaration they\
2499 \ describe. Maybe some code got deleted or commented out by accident? Or\
2500 \ maybe this comment is here by accident?"
2503 UnexpectedPort region ->
2504 Report.Report "UNEXPECTED PORTS" region [] $
2505 Code.toSnippet source region Nothing
2507 D.reflow $
2508 "You are declaring ports in a normal module."
2510 D.stack
2511 [ D.fillSep
2512 ["Switch","this","to","say",D.green "port module","instead,"
2513 ,"marking","that","this","module","contains","port","declarations."
2515 , D.link "Note"
2516 "Ports are not a traditional FFI for calling JS functions directly. They need a different mindset! Read"
2517 "ports"
2518 "to learn the syntax and how to use it effectively."
2522 NoPorts region ->
2523 Report.Report "NO PORTS" region [] $
2524 Code.toSnippet source region Nothing
2526 D.reflow $
2527 "This module does not declare any ports, but it says it will:"
2529 D.fillSep
2530 ["Switch","this","to",D.green "module"
2531 ,"and","you","should","be","all","set!"
2535 ParseError row col context expectation ->
2536 let
2537 pos = A.Position row col
2538 region = A.Region pos pos
2539 in
2540 case expectation of
2542 DocComment ->
2543 Report.Report "EXPECTING DOC COMMENT" region [] $
2544 Code.toSnippet source region Nothing
2546 D.reflow $
2547 "I was expecting a doc comment here:"
2549 D.reflowLink
2550 "Check out" "TODO" "for examples of doc comments."
2553 -- Parse.Number
2555 Precedence ->
2556 Report.Report "EXPECTING PRECEDENCE" region [] $
2557 Code.toSnippet source region Nothing
2559 D.reflow $
2560 "I was expecting the precedence here:"
2562 D.reflow $
2563 "I need a single digit between 0 and 9 inclusive."
2566 Wildcard ->
2567 Report.Report "EXPECTING A WILDCARD" region [] $
2568 Code.toSnippet source region Nothing
2570 D.reflow $
2571 "I was expecting a _ here:"
2573 D.reflow $
2574 "An underscore indicates that “I do not care about this value” and is\
2575 \ called a wildcard pattern because it will match with any type of values."
2578 WildcardNotVar startCol endCol ->
2579 let
2580 badRegion =
2581 A.Region (A.Position row startCol) (A.Position row endCol)
2582 in
2583 Report.Report "INVALID PATTERN" badRegion [] $
2584 Code.toSnippet source badRegion Nothing
2586 D.reflow $
2587 "I was expecting to see an underscore without any additional characters:"
2589 D.reflow $
2590 "There are two options. Either (1) remove the extra characters and ignore the\
2591 \ value or (2) remove the starting underscore to give the value a normal name."
2594 -- Parse.Pattern
2596 FloatInPattern ->
2597 Report.Report "INVALID PATTERN" region [] $
2598 Code.toSnippet source region Nothing
2600 D.reflow $
2601 "I cannot pattern match with floating point numbers:"
2603 D.reflow $
2604 "Equality on floats can be unreliable, so you usually want to check that they\
2605 \ are nearby with some sort of (abs (actual - expected) < 0.001) check."
2608 -- Parse.Expression
2610 MatchingName name ->
2611 Report.Report "EXPECTING A DEFINITION" region [] $
2612 Code.toSnippet source region Nothing
2614 D.reflow $
2615 "I just saw the type annotation for `" ++ Name.toChars name
2616 ++ "` so I was expecting to see its definition here:"
2618 D.reflow $
2619 "Type annotations always appear directly above the relevant\
2620 \ definition, without anything else (even doc comments) in between."
2626 TypeWithBadDefinition region annName defName ->
2627 Report.Report "ANNOTATION MISMATCH" region [] $
2628 Code.toSnippet source region Nothing
2630 D.reflow $
2631 "I see a `" <> Name.toChars annName
2632 <> "` annotation, but it is followed by a `"
2633 <> Name.toChars defName <> "` definition."
2635 D.fillSep
2636 ["The","annotation","and","definition","names","must","match!"
2637 ,"Is","there","a","typo","between"
2638 , D.dullyellow (D.fromName annName)
2639 ,"and"
2640 , D.dullyellow (D.fromName defName) <> "?"