on 4d4225d help sign in
4240 lines 147 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 | TArrow Row Col
421 --
422 | TStart Row Col
423 | TSpace Space Row Col
424 --
425 | TIndentStart Row Col
428data TRecord
429 = TRecordOpen Row Col
430 | TRecordEnd Row Col
431 --
432 | TRecordField Row Col
433 | TRecordColon Row Col
434 | TRecordType Type Row Col
435 --
436 | TRecordSpace Space Row Col
437 --
438 | TRecordIndentOpen Row Col
439 | TRecordIndentField Row Col
440 | TRecordIndentColon Row Col
441 | TRecordIndentType Row Col
442 | TRecordIndentEnd Row Col
445data TTuple
446 = TTupleOpen Row Col
447 | TTupleEnd Row Col
448 | TTupleType Type Row Col
449 | TTupleSpace Space Row Col
450 --
451 | TTupleIndentType1 Row Col
452 | TTupleIndentTypeN Row Col
453 | TTupleIndentEnd Row Col
457-- LITERALS
460data Char
461 = CharEndless
462 | CharEscape Escape
463 | CharNotString Word16
466data String
467 = StringEndless_Single
468 | StringEndless_Multi
469 | StringEscape Escape
472data Escape
473 = EscapeUnknown
474 | BadUnicodeFormat Word16
475 | BadUnicodeCode Word16
476 | BadUnicodeLength Word16 Int Int
479data Number
480 = NumberEnd
481 | NumberDot Int
482 | NumberHexDigit
483 | NumberNoLeadingZero
487-- MISC
490data Space
491 = HasTab
492 | EndlessMultiComment
496-- TO REPORT
499toReport :: Code.Source -> Error -> Report.Report
500toReport source err =
501 case err of
502 ModuleNameUnspecified name ->
503 let
504 region = toRegion 1 1
505 in
506 Report.Report "MODULE NAME MISSING" region [] $
507 D.stack
508 [ D.reflow $
509 "I need the module name to be declared at the top of this file, like this:"
510 , D.indent 4 $ D.fillSep $
511 [ D.cyan "module", D.fromName name, D.cyan "exposing", "(..)" ]
512 , D.reflow $
513 "Try adding that as the first line of your file!"
514 , D.toSimpleNote $
515 "It is best to replace (..) with an explicit list of types and\
516 \ functions you want to expose. When you know a value is only used\
517 \ within this module, you can refactor without worrying about uses\
518 \ elsewhere. Limiting exposed values can also speed up compilation\
519 \ because I can skip a bunch of work if I see that the exposed API\
520 \ has not changed."
521 ]
523 ModuleNameMismatch expectedName (A.At region actualName) ->
524 Report.Report "MODULE NAME MISMATCH" region [ModuleName.toChars expectedName] $
525 Code.toSnippet source region Nothing
526 (
527 "It looks like this module name is out of sync:"
528 ,
529 D.stack
530 [ D.reflow $
531 "I need it to match the file path, so I was expecting it to see `"
532 ++ ModuleName.toChars expectedName
533 ++ "` here. Make the following change, and you should be all set!"
534 , D.indent 4 $
535 D.dullyellow (D.fromName actualName) <> " -> " <> D.green (D.fromName expectedName)
536 , D.toSimpleNote $
537 "I require that module names correspond to file paths. This makes it much\
538 \ easier to explore unfamiliar codebases! So if you want to keep the current\
539 \ module name, try renaming the file instead."
540 ]
541 )
543 UnexpectedPort region ->
544 Report.Report "UNEXPECTED PORTS" region [] $
545 Code.toSnippet source region Nothing
546 (
547 D.reflow $
548 "You are declaring ports in a normal module."
549 ,
550 D.stack
551 [ D.fillSep
552 ["Switch","this","to","say",D.cyan "port module","instead,"
553 ,"marking","that","this","module","contains","port","declarations."
554 ]
555 , D.link "Note"
556 "Ports are not a traditional FFI for calling JS functions directly. They need a different mindset! Read"
557 "ports"
558 "to learn the syntax and how to use it effectively."
559 ]
560 )
562 NoPorts region ->
563 Report.Report "NO PORTS" region [] $
564 Code.toSnippet source region Nothing
565 (
566 D.reflow $
567 "This module does not declare any ports, but it says it will:"
568 ,
569 D.fillSep
570 ["Switch","this","to",D.cyan "module"
571 ,"and","you","should","be","all","set!"
572 ]
573 )
575 ParseError modul ->
576 toParseErrorReport source modul
579toParseErrorReport :: Code.Source -> Module -> Report.Report
580toParseErrorReport source modul =
581 case modul of
582 ModuleSpace space row col ->
583 toSpaceReport source space row col
585 ModuleEndOfFile row col ->
586 case Code.whatIsNext source row col of
587 Code.Keyword keyword ->
588 let
589 region = toKeywordRegion row col keyword
590 in
591 Report.Report "RESERVED WORD" region [] $
592 Code.toSnippet source region Nothing
593 (
594 D.reflow $
595 "I got stuck on this reserved word:"
596 ,
597 D.reflow $
598 "The name `" ++ keyword ++ "` is reserved, so try using a different name?"
599 )
601 Code.Operator op ->
602 let
603 region = toKeywordRegion row col op
604 in
605 Report.Report "UNEXPECTED SYMBOL" region [] $
606 Code.toSnippet source region Nothing
607 (
608 D.reflow $
609 "I ran into an unexpected symbol:"
610 ,
611 D.reflow $
612 "I was not expecting to see a " ++ op ++ " here. Try deleting it? Maybe\
613 \ I can give a better hint from there?"
614 )
616 Code.Close term bracket ->
617 let
618 region = toRegion row col
619 in
620 Report.Report ("UNEXPECTED " ++ map Char.toUpper term) region [] $
621 Code.toSnippet source region Nothing
622 (
623 D.reflow $
624 "I ran into an unexpected " ++ term ++ ":"
625 ,
626 D.reflow $
627 "This " ++ bracket : " does not match up with an earlier open " ++ term ++ ". Try deleting it?"
628 )
630 Code.Other ->
631 let
632 region = toRegion row col
633 in
634 Report.Report "SYNTAX PROBLEM" region [] $
635 Code.toSnippet source region Nothing
636 (
637 D.reflow $
638 "I got stuck here:"
639 ,
640 D.reflow $
641 "Whatever I am running into is confusing me a lot! Normally I can give fairly\
642 \ specific hints, but something is really tripping me up this time."
643 )
645 ModuleProblem row col ->
646 let
647 region = toRegion row col
648 in
649 Report.Report "UNFINISHED MODULE DECLARATION" region [] $
650 Code.toSnippet source region Nothing
651 (
652 D.reflow $
653 "I am parsing an `module` declaration, but I got stuck here:"
654 ,
655 D.stack
656 [ D.reflow $
657 "Here are some examples of valid `module` declarations:"
658 , D.indent 4 $ D.vcat $
659 [ D.fillSep [D.cyan "module","Main",D.cyan "exposing","(..)"]
660 , D.fillSep [D.cyan "module","Dict",D.cyan "exposing","(Dict, empty, get)"]
661 ]
662 , D.reflow $
663 "I generally recommend using an explicit exposing list. I can skip compiling a bunch\
664 \ of files when the public interface of a module stays the same, so exposing fewer\
665 \ values can help improve compile times!"
666 ]
667 )
669 ModuleName row col ->
670 let
671 region = toRegion row col
672 in
673 Report.Report "EXPECTING MODULE NAME" region [] $
674 Code.toSnippet source region Nothing
675 (
676 D.reflow $
677 "I was parsing an `module` declaration until I got stuck here:"
678 ,
679 D.stack
680 [ D.reflow $
681 "I was expecting to see the module name next, like in these examples:"
682 , D.indent 4 $ D.vcat $
683 [ D.fillSep [D.cyan "module","Dict",D.cyan "exposing","(..)"]
684 , D.fillSep [D.cyan "module","Maybe",D.cyan "exposing","(..)"]
685 , D.fillSep [D.cyan "module","Html.Attributes",D.cyan "exposing","(..)"]
686 , D.fillSep [D.cyan "module","Json.Decode",D.cyan "exposing","(..)"]
687 ]
688 , D.reflow $
689 "Notice that the module names all start with capital letters. That is required!"
690 ]
691 )
693 ModuleExposing exposing row col ->
694 error "TODO ModuleExposing" exposing row col
696 PortModuleProblem row col ->
697 let
698 region = toRegion row col
699 in
700 Report.Report "UNFINISHED PORT MODULE DECLARATION" region [] $
701 Code.toSnippet source region Nothing
702 (
703 D.reflow $
704 "I am parsing an `port module` declaration, but I got stuck here:"
705 ,
706 D.stack
707 [ D.reflow $
708 "Here are some examples of valid `port module` declarations:"
709 , D.indent 4 $ D.vcat $
710 [ D.fillSep [D.cyan "port",D.cyan "module","WebSockets",D.cyan "exposing","(send, listen, keepAlive)"]
711 , D.fillSep [D.cyan "port",D.cyan "module","Maps",D.cyan "exposing","(Location, goto)"]
712 ]
713 , D.link "Note" "Read" "ports" "for more help."
714 ]
715 )
717 PortModuleName row col ->
718 let
719 region = toRegion row col
720 in
721 Report.Report "EXPECTING MODULE NAME" region [] $
722 Code.toSnippet source region Nothing
723 (
724 D.reflow $
725 "I was parsing an `module` declaration until I got stuck here:"
726 ,
727 D.stack
728 [ D.reflow $
729 "I was expecting to see the module name next, like in these examples:"
730 , D.indent 4 $ D.vcat $
731 [ D.fillSep [D.cyan "port",D.cyan "module","WebSockets",D.cyan "exposing","(send, listen, keepAlive)"]
732 , D.fillSep [D.cyan "port",D.cyan "module","Maps",D.cyan "exposing","(Location, goto)"]
733 ]
734 , D.reflow $
735 "Notice that the module names start with capital letters. That is required!"
736 ]
737 )
739 PortModuleExposing exposing row col ->
740 error "TODO PortModuleExposing" exposing row col
742 Effect row col ->
743 let
744 region = toRegion row col
745 in
746 Report.Report "BAD MODULE DECLARATION" region [] $
747 Code.toSnippet source region Nothing
748 (
749 D.reflow $
750 "I cannot parse this module declaration:"
751 ,
752 D.reflow $
753 "This type of module is reserved for the @elm organization. It is used to\
754 \ define certain effects, avoiding building them into the compiler."
755 )
757 FreshLine row col ->
758 let
759 region = toRegion row col
761 toBadFirstLineReport keyword =
762 Report.Report "TOO MUCH INDENTATION" region [] $
763 Code.toSnippet source region Nothing
764 (
765 D.reflow $
766 "This `" ++ keyword ++ "` should not have any spaces before it:"
767 ,
768 D.reflow $
769 "Delete the spaces before `" ++ keyword ++ "` until there are none left!"
770 )
772 in
773 case Code.whatIsNext source row col of
774 Code.Keyword "module" -> toBadFirstLineReport "module"
775 Code.Keyword "import" -> toBadFirstLineReport "import"
776 Code.Keyword "type" -> toBadFirstLineReport "type"
777 Code.Keyword "port" -> toBadFirstLineReport "port"
778 _ ->
779 Report.Report "SYNTAX PROBLEM" region [] $
780 Code.toSnippet source region Nothing
781 (
782 D.reflow $
783 "I got stuck here:"
784 ,
785 D.stack
786 [ D.reflow $
787 "I am not sure what is going on, but I recommend starting an Elm\
788 \ file with the following lines:"
789 , D.vcat
790 [ D.fillSep [D.cyan "import","Html"]
791 , ""
792 , D.fillSep [D.green "main","="]
793 , D.indent 2 $ D.fillSep [D.cyan "Html" <> ".text",D.dullyellow "\"Hello!\""]
794 ]
795 , D.reflow $
796 "You should be able to copy those lines directly into your file. Check out\
797 \ some of the examples on https://elm-lang.org for more help getting started!"
798 , D.toSimpleNote $
799 "This can also happen when something is indented too much!"
800 ]
801 )
803 ImportStart row col ->
804 toImportReport source row col
806 ImportName row col ->
807 let
808 region = toRegion row col
809 in
810 Report.Report "EXPECTING IMPORT NAME" region [] $
811 Code.toSnippet source region Nothing
812 (
813 D.reflow $
814 "I was parsing an `import` until I got stuck here:"
815 ,
816 D.stack
817 [ D.reflow $
818 "I was expecting to see a module name next, like in these examples:"
819 , D.indent 4 $ D.vcat $
820 [ D.fillSep [D.cyan "import","Dict"]
821 , D.fillSep [D.cyan "import","Maybe"]
822 , D.fillSep [D.cyan "import","Html.Attributes"]
823 , D.fillSep [D.cyan "import","Json.Decode"]
824 ]
825 , D.reflow $
826 "Notice that the module names all start with capital letters. That is required!"
827 ]
828 )
830 ImportAs row col ->
831 toImportReport source row col
833 ImportAlias row col ->
834 let
835 region = toRegion row col
836 in
837 Report.Report "EXECTING IMPORT ALIAS" region [] $
838 Code.toSnippet source region Nothing
839 (
840 D.reflow $
841 "I was parsing an `import` until I got stuck here:"
842 ,
843 D.stack
844 [ D.reflow $
845 "I was expecting to see an alias next, like in these examples:"
846 , D.indent 4 $ D.vcat $
847 [ D.fillSep [D.cyan "import","Html.Attributes",D.cyan "as","Attr"]
848 , D.fillSep [D.cyan "import","WebGL.Texture",D.cyan "as","Texture"]
849 , D.fillSep [D.cyan "import","Json.Decode",D.cyan "as","D"]
850 ]
851 , D.reflow $
852 "Notice that the alias always starts with a capital letter. That is required!"
853 ]
854 )
856 ImportExposing row col ->
857 toImportReport source row col
859 ImportExposingList exposing row col ->
860 error "TODO ImportExposingList" exposing row col
862 ImportEnd row col ->
863 toImportReport source row col
865 ImportIndentName row col ->
866 toImportReport source row col
868 ImportIndentAlias row col ->
869 toImportReport source row col
871 ImportIndentExposingList row col ->
872 let
873 region = toRegion row col
874 in
875 Report.Report "UNFINISHED IMPORT" region [] $
876 Code.toSnippet source region Nothing
877 (
878 D.reflow $
879 "I was parsing an `import` until I got stuck here:"
880 ,
881 D.stack
882 [ D.reflow $
883 "I was expecting to see the list of exposed values next. For example, here\
884 \ are two ways to expose values from the `Html` module:"
885 , D.indent 4 $ D.vcat $
886 [ D.fillSep [D.cyan "import","Html",D.cyan "exposing","(..)"]
887 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
888 ]
889 , D.reflow $
890 "I generally recommend the second style. It is more explicit, making it\
891 \ much easier to figure out where values are coming from in large projects!"
892 ]
893 )
895 Infix row col ->
896 let
897 region = toRegion row col
898 in
899 Report.Report "BAD INFIX" region [] $
900 Code.toSnippet source region Nothing
901 (
902 D.reflow $
903 "Something went wrong in this infix operator declaration:"
904 ,
905 D.reflow $
906 "This feature is used by the @elm organization to define the\
907 \ languages built-in operators."
908 )
910 Declarations decl _ _ ->
911 toDeclarationsReport source decl
915-- IMPORTS
918toImportReport :: Code.Source -> Row -> Col -> Report.Report
919toImportReport source row col =
920 let
921 region = toRegion row col
922 in
923 Report.Report "UNFINISHED IMPORT" region [] $
924 Code.toSnippet source region Nothing
925 (
926 D.reflow $
927 "I am partway through parsing an import, but I got stuck here:"
928 ,
929 D.stack
930 [ D.reflow $
931 "Here are some examples of valid `import` declarations:"
932 , D.indent 4 $ D.vcat $
933 [ D.fillSep [D.cyan "import","Html"]
934 , D.fillSep [D.cyan "import","Html",D.cyan "as","H"]
935 , D.fillSep [D.cyan "import","Html",D.cyan "as","H",D.cyan "exposing","(..)"]
936 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
937 ]
938 , D.reflow $
939 "You are probably trying to import a different module, but try to make it look like one of these examples!"
940 ]
941 )
945-- SPACES
948toSpaceReport :: Code.Source -> Space -> Row -> Col -> Report.Report
949toSpaceReport source space row col =
950 case space of
951 HasTab ->
952 let
953 region = toRegion row col
954 in
955 Report.Report "NO TABS" region [] $
956 Code.toSnippet source region Nothing
957 (
958 D.reflow $
959 "I ran into a tab, but tabs are not allowed in Elm files."
960 ,
961 D.reflow $
962 "Replace the tab with spaces."
963 )
965 EndlessMultiComment ->
966 let
967 region = toWiderRegion row col 2
968 in
969 Report.Report "ENDLESS COMMENT" region [] $
970 Code.toSnippet source region Nothing
971 (
972 D.reflow $
973 "I cannot find the end of this multi-line comment:"
974 ,
975 D.stack -- "{-"
976 [ D.reflow "Add a -} somewhere after this to end the comment."
977 , D.toSimpleHint
978 "Multi-line comments can be nested in Elm, so {- {- -} -} is a comment\
979 \ that happens to contain another comment. Like parentheses and curly braces,\
980 \ the start and end markers must always be balanced. Maybe that is the problem?"
981 ]
982 )
986-- DECLARATIONS
989toRegion :: Row -> Col -> A.Region
990toRegion row col =
991 let
992 pos = A.Position row col
993 in
994 A.Region pos pos
997toWiderRegion :: Row -> Col -> Word16 -> A.Region
998toWiderRegion row col extra =
999 A.Region
1000 (A.Position row col)
1001 (A.Position row (col + extra))
1004toKeywordRegion :: Row -> Col -> [Char.Char] -> A.Region
1005toKeywordRegion row col keyword =
1006 A.Region
1007 (A.Position row col)
1008 (A.Position row (col + fromIntegral (length keyword)))
1011toDeclarationsReport :: Code.Source -> Decl -> Report.Report
1012toDeclarationsReport source decl =
1013 case decl of
1014 DeclStart row col ->
1015 error "TODO DeclStart" row col
1017 DeclSpace space row col ->
1018 toSpaceReport source space row col
1020 Port port_ row col ->
1021 error "TODO Port" port_ row col
1023 DeclType declType row col ->
1024 toDeclTypeReport source declType row col
1026 DeclDef name declDef row col ->
1027 toDeclDefReport source name declDef row col
1029 DeclFreshLineStart row col ->
1030 error "TODO DeclFreshLineStart" row col
1032 DeclFreshLineAfterDocComment row col ->
1033 error "TODO DeclFreshLineAfterDocComment" row col
1037-- DECL TYPE
1040toDeclTypeReport :: Code.Source -> DeclType -> Row -> Col -> Report.Report
1041toDeclTypeReport source declType startRow startCol =
1042 case declType of
1043 DT_Space space row col ->
1044 toSpaceReport source space row col
1046 DT_Name row col ->
1047 let
1048 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1049 region = toRegion row col
1050 in
1051 Report.Report "EXPECTING TYPE NAME" region [] $
1052 Code.toSnippet source surroundings (Just region)
1054 D.reflow $
1055 "I think I am parsing a type declaration, but I got stuck here:"
1057 D.stack
1058 [ D.fillSep $
1059 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1060 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1062 , customTypeNote
1066 DT_Alias typeAlias row col ->
1067 toTypeAliasReport source typeAlias row col
1069 DT_Union customType row col ->
1070 toCustomTypeReport source customType row col
1072 DT_IndentName row col ->
1073 let
1074 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1075 region = toRegion row col
1076 in
1077 Report.Report "EXPECTING TYPE NAME" region [] $
1078 Code.toSnippet source surroundings (Just region)
1080 D.reflow $
1081 "I think I am parsing a type declaration, but I got stuck here:"
1083 D.stack
1084 [ D.fillSep $
1085 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1086 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1088 , customTypeNote
1093toTypeAliasReport :: Code.Source -> TypeAlias -> Row -> Col -> Report.Report
1094toTypeAliasReport source typeAlias startRow startCol =
1095 case typeAlias of
1096 AliasSpace space row col ->
1097 toSpaceReport source space row col
1099 AliasName row col ->
1100 let
1101 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1102 region = toRegion row col
1103 in
1104 Report.Report "EXPECTING TYPE ALIAS NAME" region [] $
1105 Code.toSnippet source surroundings (Just region)
1107 D.reflow $
1108 "I am partway through parsing a type alias, but I got stuck here:"
1110 D.stack
1111 [ D.fillSep $
1112 ["I","was","expecting","a","name","like",D.dullyellow "Person","or",D.dullyellow "Point"
1113 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1115 , typeAliasNote
1119 AliasEquals row col ->
1120 case Code.whatIsNext source row col of
1121 Code.Keyword keyword ->
1122 let
1123 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1124 region = toKeywordRegion row col keyword
1125 in
1126 Report.Report "RESERVED WORD" region [] $
1127 Code.toSnippet source surroundings (Just region)
1129 D.reflow $
1130 "I ran into a reserved word unexpectedly while parsing this type alias:"
1132 D.stack
1133 [ D.reflow $
1134 "It looks like you are trying use `" ++ keyword
1135 ++ "` as a type variable, but it is a reserved word. Try using a different name?"
1136 , typeAliasNote
1140 _ ->
1141 let
1142 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1143 region = toRegion row col
1144 in
1145 Report.Report "PROBLEM IN TYPE ALIAS" region [] $
1146 Code.toSnippet source surroundings (Just region)
1148 D.reflow $
1149 "I am partway through parsing a type alias, but I got stuck here:"
1151 D.stack
1152 [ D.reflow $
1153 "I was expecting to see a type variable or an an equals sign next."
1154 , typeAliasNote
1158 AliasBody tipe row col ->
1159 toTypeReport source tipe row col
1161 AliasIndentEquals row col ->
1162 let
1163 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1164 region = toRegion row col
1165 in
1166 Report.Report "UNFINISHED TYPE ALIAS" region [] $
1167 Code.toSnippet source surroundings (Just region)
1169 D.reflow $
1170 "I am partway through parsing a type alias, but I got stuck here:"
1172 D.stack
1173 [ D.reflow $
1174 "I was expecting to see a type variable or an an equals sign next."
1175 , typeAliasNote
1179 AliasIndentBody row col ->
1180 let
1181 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1182 region = toRegion row col
1183 in
1184 Report.Report "UNFINISHED TYPE ALIAS" region [] $
1185 Code.toSnippet source surroundings (Just region)
1187 D.reflow $
1188 "I am partway through parsing a type alias, but I got stuck here:"
1190 D.stack
1191 [ D.fillSep $
1192 ["I","was","expecting","to","see","a","type","next.","Something","as","simple"
1193 ,"as",D.dullyellow "Int","or",D.dullyellow "Float","would","work!"
1195 , typeAliasNote
1200typeAliasNote :: D.Doc
1201typeAliasNote =
1202 D.stack
1203 [ D.toSimpleNote $
1204 "Here is an example of a valid `type alias` for reference:"
1205 , D.vcat $
1206 [ D.indent 0 $ D.fillSep [D.cyan "type",D.cyan "alias",D.green "Person","="]
1207 , D.indent 2 $ D.vcat $
1208 ["{ name : String"
1209 ,", age : Int"
1210 ,", height : Float"
1211 ,"}"
1214 , D.reflow $
1215 "This would let us use `Person` as a shorthand for that record type. Using this\
1216 \ shorthand makes type annotations much easier to read, and makes changing code\
1217 \ easier if you decide later that there is more to a person than age and height!"
1221toCustomTypeReport :: Code.Source -> CustomType -> Row -> Col -> Report.Report
1222toCustomTypeReport source customType startRow startCol =
1223 case customType of
1224 CT_Space space row col ->
1225 toSpaceReport source space row col
1227 CT_Name row col ->
1228 let
1229 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1230 region = toRegion row col
1231 in
1232 Report.Report "EXPECTING TYPE NAME" region [] $
1233 Code.toSnippet source surroundings (Just region)
1235 D.reflow $
1236 "I think I am parsing a type declaration, but I got stuck here:"
1238 D.stack
1239 [ D.fillSep $
1240 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1241 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1243 , customTypeNote
1247 CT_Equals row col ->
1248 case Code.whatIsNext source row col of
1249 Code.Keyword keyword ->
1250 let
1251 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1252 region = toKeywordRegion row col keyword
1253 in
1254 Report.Report "RESERVED WORD" region [] $
1255 Code.toSnippet source surroundings (Just region)
1257 D.reflow $
1258 "I ran into a reserved word unexpectedly while parsing this custom type:"
1260 D.stack
1261 [ D.reflow $
1262 "It looks like you are trying use `" ++ keyword
1263 ++ "` as a type variable, but it is a reserved word. Try using a different name?"
1264 , customTypeNote
1268 _ ->
1269 let
1270 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1271 region = toRegion row col
1272 in
1273 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
1274 Code.toSnippet source surroundings (Just region)
1276 D.reflow $
1277 "I am partway through parsing a custom type, but I got stuck here:"
1279 D.stack
1280 [ D.reflow $
1281 "I was expecting to see a type variable or an an equals sign next."
1282 , customTypeNote
1286 CT_Bar row col ->
1287 let
1288 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1289 region = toRegion row col
1290 in
1291 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
1292 Code.toSnippet source surroundings (Just region)
1294 D.reflow $
1295 "I am partway through parsing a custom type, but I got stuck here:"
1297 D.stack
1298 [ D.reflow $
1299 "I was expecting to see a vertical bar like | next."
1300 , customTypeNote
1304 CT_Variant row col ->
1305 let
1306 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1307 region = toRegion row col
1308 in
1309 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
1310 Code.toSnippet source surroundings (Just region)
1312 D.reflow $
1313 "I am partway through parsing a custom type, but I got stuck here:"
1315 D.stack
1316 [ D.fillSep $
1317 ["I","was","expecting","to","see","a","variant","name","next."
1318 ,"Something","like",D.dullyellow "Success","or",D.dullyellow "Sandwich" <> "."
1319 ,"Any","name","that","starts","with","a","capital","letter","really!"
1321 , customTypeNote
1325 CT_VariantArg tipe row col ->
1326 toTypeReport source tipe row col
1328 CT_IndentEquals row col ->
1329 let
1330 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1331 region = toRegion row col
1332 in
1333 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1334 Code.toSnippet source surroundings (Just region)
1336 D.reflow $
1337 "I am partway through parsing a custom type, but I got stuck here:"
1339 D.stack
1340 [ D.reflow $
1341 "I was expecting to see a type variable or an an equals sign next."
1342 , customTypeNote
1346 CT_IndentBar row col ->
1347 let
1348 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1349 region = toRegion row col
1350 in
1351 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1352 Code.toSnippet source surroundings (Just region)
1354 D.reflow $
1355 "I am partway through parsing a custom type, but I got stuck here:"
1357 D.stack
1358 [ D.reflow $
1359 "I was expecting to see a vertical bar like | next."
1360 , customTypeNote
1364 CT_IndentAfterBar row col ->
1365 let
1366 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1367 region = toRegion row col
1368 in
1369 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1370 Code.toSnippet source surroundings (Just region)
1372 D.reflow $
1373 "I am partway through parsing a custom type, but I got stuck here:"
1375 D.stack
1376 [ D.reflow $
1377 "I just saw a vertical bar, so I was expecting to see another variant defined next."
1378 , customTypeNote
1382 CT_IndentAfterEquals row col ->
1383 let
1384 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1385 region = toRegion row col
1386 in
1387 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1388 Code.toSnippet source surroundings (Just region)
1390 D.reflow $
1391 "I am partway through parsing a custom type, but I got stuck here:"
1393 D.stack
1394 [ D.reflow $
1395 "I just saw an equals sign, so I was expecting to see the first variant defined next."
1396 , customTypeNote
1401customTypeNote :: D.Doc
1402customTypeNote =
1403 D.stack
1404 [ D.toSimpleNote $
1405 "Here is an example of a valid `type` declaration for reference:"
1406 , D.vcat $
1407 [ D.indent 0 $ D.fillSep [D.cyan "type",D.green "Status"]
1408 , D.indent 2 $ D.fillSep ["=","Failure"]
1409 , D.indent 2 $ D.fillSep ["|","Waiting"]
1410 , D.indent 2 $ D.fillSep ["|","Success","String"]
1412 , D.reflow $
1413 "This defines a new `Status` type with three variants. This could be useful if\
1414 \ we are waiting for an HTTP request. Maybe we start with `Waiting` and then\
1415 \ switch to `Failure` or `Success \"message from server\"` depending on how\
1416 \ things go. Notice that the Success variant has some associated data, allowing\
1417 \ us to store a String if the request goes well!"
1422-- DECL DEF
1425toDeclDefReport :: Code.Source -> Name.Name -> DeclDef -> Row -> Col -> Report.Report
1426toDeclDefReport source name declDef startRow startCol =
1427 case declDef of
1428 DeclDefSpace space row col ->
1429 toSpaceReport source space row col
1431 DeclDefEquals row col ->
1432 case Code.whatIsNext source row col of
1433 Code.Keyword keyword ->
1434 let
1435 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1436 region = toKeywordRegion row col keyword
1437 in
1438 Report.Report "RESERVED WORD" region [] $
1439 Code.toSnippet source surroundings (Just region)
1441 D.reflow $
1442 "It looks like you are trying to use `" ++ keyword ++ "` as an argument:"
1444 D.reflow $
1445 "This is a reserved word! Try using some other name?"
1448 Code.Operator op ->
1449 let
1450 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1451 region = toKeywordRegion row col op
1452 in
1453 Report.Report "UNEXPECTED SYMBOL" region [] $
1454 Code.toSnippet source surroundings (Just region)
1456 D.reflow $
1457 "I was not expecting to see this symbol here:"
1459 D.stack
1460 [ D.reflow $
1461 "I am not sure what is going wrong exactly, so here is a valid\
1462 \ definition (with an optional type annotation) for reference:"
1463 , D.vcat
1464 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
1465 , D.fillSep [D.green "add","x","y","="]
1466 , D.fillSep [" ","x","+","y"]
1468 , D.reflow $
1469 "Try to use that format with your `" ++ Name.toChars name ++ "` definition!"
1473 _ ->
1474 let
1475 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1476 region = toRegion row col
1477 in
1478 Report.Report "PROBLEM IN DEFINITION" region [] $
1479 Code.toSnippet source surroundings (Just region)
1481 D.reflow $
1482 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
1484 D.stack
1485 [ D.reflow $
1486 "I am not sure what is going wrong exactly, so here is a valid\
1487 \ definition (with an optional type annotation) for reference:"
1488 , D.vcat
1489 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
1490 , D.fillSep [D.green "add","x","y","="]
1491 , D.fillSep [" ","x","+","y"]
1493 , D.reflow $
1494 "Try to use that format!"
1498 DeclDefType tipe row col ->
1499 toTypeReport source tipe row col
1501 DeclDefArg pattern row col ->
1502 toPatternReport source PArg pattern row col
1504 DeclDefBody expr row col ->
1505 toExprReport source (InDef name startRow startCol) expr row col
1507 DeclDefNameRepeat row col ->
1508 let
1509 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1510 region = toRegion row col
1511 in
1512 Report.Report "EXPECTING DEFINITION" region [] $
1513 Code.toSnippet source surroundings (Just region)
1515 D.reflow $
1516 "I just saw the type annotation for `" ++ Name.toChars name
1517 ++ "` so I was expecting to see its definition here:"
1519 D.reflow $
1520 "Type annotations always appear directly above the relevant\
1521 \ definition, without anything else (even doc comments) in between."
1524 DeclDefNameMatch defName row col ->
1525 let
1526 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1527 region = toRegion row col
1528 in
1529 Report.Report "NAME MISMATCH" region [] $
1530 Code.toSnippet source surroundings (Just region)
1532 D.reflow $
1533 "I just saw a type annotation for `" ++ Name.toChars name ++ "`, but it is followed by a definition for `" ++ Name.toChars defName ++ "`:"
1535 D.stack
1536 [ D.reflow $
1537 "These names do not match! Is there a typo?"
1538 , D.indent 4 $ D.fillSep $
1539 [D.dullyellow (D.fromName defName),"->",D.green (D.fromName name)]
1543 DeclDefIndentType row col ->
1544 error "TODO DeclDefIndentType" row col
1546 DeclDefIndentEquals row col ->
1547 error "TODO DeclDefIndentEquals" row col
1549 DeclDefIndentBody row col ->
1550 error "TODO DeclDefIndentBody" row col
1552 DeclDefFreshLineAfterType row col ->
1553 error "TODO DeclDefFreshLineAfterType" row col
1557-- CONTEXT
1560data Context
1561 = InNode Node Row Col Context
1562 | InDef Name.Name Row Col
1565data Node
1566 = NRecord
1567 | NParens
1568 | NList
1569 | NFunc
1570 | NCond
1571 | NThen
1572 | NElse
1573 | NCase
1574 | NBranch
1575 deriving (Eq)
1578getDefName :: Context -> Name.Name
1579getDefName context =
1580 case context of
1581 InDef name _ _ -> name
1582 InNode _ _ _ c -> getDefName c
1585isWithin :: Node -> Context -> Bool
1586isWithin desiredNode context =
1587 case context of
1588 InDef _ _ _ -> False
1589 InNode actualNode _ _ _ -> desiredNode == actualNode
1593-- EXPR REPORTS
1596toExprReport :: Code.Source -> Context -> Expr -> Row -> Col -> Report.Report
1597toExprReport source context expr startRow startCol =
1598 case expr of
1599 Let let_ row col ->
1600 toLetReport source context let_ row col
1602 Case case_ row col ->
1603 toCaseReport source context case_ row col
1605 If if_ row col ->
1606 toIfReport source context if_ row col
1608 List list row col ->
1609 toListReport source context list row col
1611 Record record row col ->
1612 toRecordReport source context record row col
1614 Tuple tuple row col ->
1615 toTupleReport source context tuple row col
1617 Func func row col ->
1618 toFuncReport source context func row col
1620 Dot row col ->
1621 let region = toRegion row col in
1622 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
1623 Code.toSnippet source region Nothing
1625 D.reflow $
1626 "I was expecting to see a record accessor here:"
1628 D.fillSep
1629 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
1630 ,"that","accesses","a","value","from","a","record."
1634 Access row col ->
1635 let region = toRegion row col in
1636 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
1637 Code.toSnippet source region Nothing
1639 D.reflow $
1640 "I am trying to parse a record accessor here:"
1642 D.stack
1644 D.fillSep
1645 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
1646 ,"that","accesses","a","value","from","a","record."
1649 D.toSimpleNote $
1650 "Record field names must start with a lower case letter!"
1654 OperatorRight op row col ->
1655 let region = toRegion row col in
1656 Report.Report "MISSING EXPRESSION" region [] $
1657 Code.toSnippet source region Nothing
1659 D.reflow $
1660 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
1662 D.stack
1663 [ D.fillSep $
1664 ["You","can","just","put","anything","for","now,","like"
1665 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1666 ,"Once","there","is","something","there,","I","can","probably"
1667 ,"give","a","more","specific","hint!"
1669 , D.toSimpleNote $
1670 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
1671 \ Or if I run into operators in unexpected spots. Point is, there are a\
1672 \ couple ways I can get confused and give sort of weird advice!"
1676 OperatorReserved operator row col ->
1677 toOperatorReport source context operator row col
1679 Start row col ->
1680 let
1681 (contextRow, contextCol, aThing) =
1682 case context of
1683 InDef name r c -> (r, c, "the `" ++ Name.toChars name ++ "` definition")
1684 InNode NRecord r c _ -> (r, c, "a record")
1685 InNode NParens r c _ -> (r, c, "some parentheses")
1686 InNode NList r c _ -> (r, c, "a list")
1687 InNode NFunc r c _ -> (r, c, "an anonymous function")
1688 InNode NCond r c _ -> (r, c, "an `if` expression")
1689 InNode NThen r c _ -> (r, c, "an `if` expression")
1690 InNode NElse r c _ -> (r, c, "an `if` expression")
1691 InNode NCase r c _ -> (r, c, "a `case` expression")
1692 InNode NBranch r c _ -> (r, c, "a `case` expression")
1693 -- TODO check if this is actually the best way to get error messages here
1695 surroundings = A.Region (A.Position contextRow contextCol) (A.Position row col)
1696 region = toRegion row col
1697 in
1698 Report.Report "MISSING EXPRESSION" region [] $
1699 Code.toSnippet source surroundings (Just region)
1701 D.reflow $
1702 "I am partway through parsing " ++ aThing ++ ", but I got stuck here:"
1704 D.stack
1705 [ D.fillSep $
1706 ["I","was","expecting","to","see","an","expression","like"
1707 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1708 ,"Once","there","is","something","there,","I","can","probably"
1709 ,"give","a","more","specific","hint!"
1711 , D.toSimpleNote $
1712 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
1713 \ Or if I run into operators in unexpected spots. Point is, there are a\
1714 \ couple ways I can get confused and give sort of weird advice!"
1718 Char char row col ->
1719 toCharReport source char row col
1721 String string row col ->
1722 toStringReport source string row col
1724 Number number row col ->
1725 toNumberReport source number row col
1727 Space space row col ->
1728 toSpaceReport source space row col
1730 EndlessShader row col ->
1731 let
1732 region = toWiderRegion row col 6
1733 in
1734 Report.Report "ENDLESS SHADER" region [] $
1735 Code.toSnippet source region Nothing
1737 D.reflow "I cannot find the end of this shader:"
1739 D.reflow "Add a |] somewhere after this to end the shader."
1742 ShaderProblem problem row col ->
1743 let
1744 region = toRegion row col
1745 in
1746 Report.Report "SHADER PROBLEM" region [] $
1747 Code.toSnippet source region Nothing
1749 D.reflow $
1750 "I ran into a problem while parsing this GLSL block."
1752 D.stack
1753 [ D.reflow $
1754 "I use a 3rd party GLSL parser for now, and I did my best to extract their error message:"
1755 , D.indent 4 $ D.vcat $
1756 map D.fromChars (filter (/="") (lines problem))
1760 IndentOperatorRight op row col ->
1761 let
1762 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1763 region = toRegion row col
1764 in
1765 Report.Report "MISSING EXPRESSION" region [] $
1766 Code.toSnippet source surroundings (Just region)
1768 D.reflow $
1769 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
1771 D.stack
1773 D.fillSep $
1774 ["You","can","just","put","anything","for","now,","like"
1775 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1776 ,"Once","there","is","something","there,","I","can","probably"
1777 ,"give","a","more","specific","hint!"
1780 D.toSimpleNote $
1781 "I may be getting confused by your indentation? The easiest way to make sure\
1782 \ this is not an indentation problem is to put the expression on the right of\
1783 \ the " ++ Name.toChars op ++ " operator on the same line."
1787 IndentMoreExpr _ _ ->
1788 error "TODO IndentMoreExpr"
1792-- CHAR
1795toCharReport :: Code.Source -> Char -> Row -> Col -> Report.Report
1796toCharReport source char row col =
1797 case char of
1798 CharEndless ->
1799 let
1800 region = toRegion row col
1801 in
1802 Report.Report "MISSING SINGLE QUOTE" region [] $
1803 Code.toSnippet source region Nothing
1805 D.reflow $
1806 "I thought I was parsing a character, but I got to the end of\
1807 \ the line without seeing the closing single quote:"
1809 D.reflow $
1810 "Add a closing single quote here!"
1813 CharEscape escape ->
1814 toEscapeReport source escape row col
1816 CharNotString width ->
1817 let
1818 region = toWiderRegion row col width
1819 in
1820 Report.Report "NEEDS DOUBLE QUOTES" region [] $
1821 Code.toSnippet source region Nothing
1823 "The following string uses single quotes:"
1825 D.stack
1826 [ "Please switch to double quotes instead:"
1827 , D.indent 4 $
1828 D.dullyellow "'this'" <> " => " <> D.green "\"this\""
1829 , D.toSimpleNote $
1830 "Elm uses double quotes for strings like \"hello\", whereas it uses single\
1831 \ quotes for individual characters like 'a' and 'ø'. This distinction helps with\
1832 \ code like (String.any (\\c -> c == 'X') \"90210\") where you are inspecting\
1833 \ individual characters."
1839-- STRING
1842toStringReport :: Code.Source -> String -> Row -> Col -> Report.Report
1843toStringReport source string row col =
1844 case string of
1845 StringEndless_Single ->
1846 let
1847 region = toRegion row col
1848 in
1849 Report.Report "ENDLESS STRING" region [] $
1850 Code.toSnippet source region Nothing
1852 D.reflow $
1853 "I got to the end of the line without seeing the closing double quote:"
1855 D.stack
1856 [ D.fillSep $
1857 ["Strings","look","like",D.green "\"this\"","with","double"
1858 ,"quotes","on","each","end.","Is","the","closing","double"
1859 ,"quote","missing","in","your","code?"
1861 , D.link "Note" "Read" "TODO" "if you want a string that spans multiple lines."
1865 StringEndless_Multi ->
1866 let
1867 region = toWiderRegion row col 3
1868 in
1869 Report.Report "ENDLESS STRING" region [] $
1870 Code.toSnippet source region Nothing
1872 D.reflow $
1873 "I cannot find the end of this multi-line string:"
1875 D.stack
1876 [ D.reflow "Add a \"\"\" somewhere after this to end the string."
1877 , D.link "Hint" "Read" "TODO" "for more information on strings and multi-line strings."
1881 StringEscape escape ->
1882 toEscapeReport source escape row col
1886-- ESCAPES
1889toEscapeReport :: Code.Source -> Escape -> Row -> Col -> Report.Report
1890toEscapeReport source escape row col =
1891 case escape of
1892 EscapeUnknown ->
1893 let
1894 region = toWiderRegion row col 2
1895 in
1896 Report.Report "UNKNOWN ESCAPE" region [] $
1897 Code.toSnippet source region Nothing
1899 D.reflow $
1900 "Backslashes always start escaped characters, but I do not recognize this one:"
1902 D.stack
1903 [ D.reflow $
1904 "Valid escape characters include:"
1905 , D.dullyellow $ D.indent 4 $ D.vcat $
1906 [ "\\n"
1907 , "\\r"
1908 , "\\t"
1909 , "\\\""
1910 , "\\\'"
1911 , "\\\\"
1912 , "\\u{003D}"
1914 , D.reflow $
1915 "Do you want one of those instead? Maybe you need \\\\ to escape a backslash?"
1916 , D.toSimpleNote $
1917 "The last style lets encode ANY character by its Unicode code\
1918 \ point. That means \\u{0009} and \\t are the same. You can use\
1919 \ that style for anything not covered by the other six escapes!"
1923 BadUnicodeFormat width ->
1924 let
1925 region = toWiderRegion row col width
1926 in
1927 Report.Report "BAD UNICODE ESCAPE" region [] $
1928 Code.toSnippet source region Nothing
1930 D.reflow $
1931 "I ran into an invalid Unicode escape:"
1933 D.stack
1934 [ D.reflow $
1935 "Here are some examples of valid Unicode escapes:"
1936 , D.dullyellow $ D.indent 4 $ D.vcat $
1937 [ "\\u{0041}"
1938 , "\\u{03BB}"
1939 , "\\u{6728}"
1940 , "\\u{1F60A}"
1942 , D.reflow $
1943 "Notice that the code point is always surrounded by curly braces.\
1944 \ Maybe you are missing the opening or closing curly brace?"
1947 BadUnicodeCode width ->
1948 let
1949 region = toWiderRegion row col width
1950 in
1951 Report.Report "BAD UNICODE ESCAPE" region [] $
1952 Code.toSnippet source region Nothing
1954 D.reflow $
1955 "This is not a valid code point:"
1957 D.reflow $
1958 "The valid code points are between 0 and 10FFFF inclusive."
1961 BadUnicodeLength width numDigits badCode ->
1962 let
1963 region = toWiderRegion row col width
1964 in
1965 Report.Report "BAD UNICODE ESCAPE" region [] $
1966 Code.toSnippet source region Nothing $
1967 if numDigits < 4 then
1969 D.reflow $
1970 "Every code point needs at least four digits:"
1972 let
1973 goodCode = replicate (4 - numDigits) '0' ++ map Char.toUpper (showHex badCode "")
1974 suggestion = "\\u{" <> D.fromChars goodCode <> "}"
1975 in
1976 D.fillSep ["Try",D.green suggestion,"instead?"]
1979 else
1981 D.reflow $
1982 "This code point has too many digits:"
1984 D.fillSep $
1985 ["Valid","code","points","are","between"
1986 ,D.green "\\u{0000}","and",D.green "\\u{10FFFF}" <> ","
1987 ,"so","try","trimming","any","leading","zeros","until"
1988 ,"you","have","between","four","and","six","digits."
1994-- NUMBERS
1997toNumberReport :: Code.Source -> Number -> Row -> Col -> Report.Report
1998toNumberReport source number row col =
1999 let
2000 region = toRegion row col
2001 in
2002 case number of
2003 NumberEnd ->
2004 Report.Report "WEIRD NUMBER" region [] $
2005 Code.toSnippet source region Nothing
2007 D.reflow $
2008 "I thought I was reading a number, but I ran into some weird stuff here:"
2010 D.stack
2011 [ D.reflow $
2012 "I recognize numbers in the following formats:"
2013 , D.indent 4 $ D.vcat [ "42", "3.14", "6.022e23", "0x002B" ]
2014 , D.reflow $
2015 "So is there a way to write it like one of those?"
2019 NumberDot int ->
2020 Report.Report "WEIRD NUMBER" region [] $
2021 Code.toSnippet source region Nothing
2023 D.reflow $
2024 "Numbers cannot end with a dot like this:"
2026 D.fillSep
2027 ["Switching","to",D.green (D.fromChars (show int))
2028 ,"or",D.green (D.fromChars (show int ++ ".0"))
2029 ,"will","work","though!"
2033 NumberHexDigit ->
2034 Report.Report "WEIRD HEXIDECIMAL" region [] $
2035 Code.toSnippet source region Nothing
2037 D.reflow $
2038 "I thought I was reading a hexidecimal number until I got here:"
2040 D.stack
2041 [ D.reflow $
2042 "Valid hexidecimal digits include 0123456789abcdefABCDEF, so I can\
2043 \ only recognize things like this:"
2044 , D.indent 4 $ D.vcat [ "0x2B", "0x002B", "0x00ffb3" ]
2048 NumberNoLeadingZero ->
2049 Report.Report "LEADING ZEROS" region [] $
2050 Code.toSnippet source region Nothing
2052 D.reflow $
2053 "I do not accept numbers with leading zeros:"
2055 D.stack
2056 [ D.reflow $
2057 "Just delete the leading zeros and it should work!"
2058 , D.toSimpleNote $
2059 "Some languages let you to specify octal numbers by adding a leading zero.\
2060 \ So in C, writing 0111 is the same as writing 73. Some people are used to\
2061 \ that, but others probably want it to equal 111. Either path is going to\
2062 \ surprise people from certain backgrounds, so Elm tries to avoid this whole\
2063 \ situation."
2069-- OPERATORS
2072toOperatorReport :: Code.Source -> Context -> BadOperator -> Row -> Col -> Report.Report
2073toOperatorReport source context operator row col =
2074 case operator of
2075 BadDot ->
2076 let
2077 region = toRegion row col
2078 in
2079 Report.Report "UNEXPECTED SYMBOL" region [] $
2080 Code.toSnippet source region Nothing
2082 "I was not expecting this dot:"
2084 D.reflow $
2085 "Dots are for record access and decimal points, so\
2086 \ they cannot float around on their own. Maybe\
2087 \ there is some extra whitespace?"
2090 BadPipe ->
2091 let
2092 region = toRegion row col
2093 in
2094 Report.Report "UNEXPECTED SYMBOL" region [] $
2095 Code.toSnippet source region Nothing
2097 D.reflow $
2098 "I was not expecting this vertical bar:"
2100 D.reflow $
2101 "Vertical bars should only appear in custom type declarations. Maybe you want || instead?"
2104 BadArrow ->
2105 let
2106 region = toWiderRegion row col 2
2107 in
2108 Report.Report "UNEXPECTED ARROW" region [] $
2109 Code.toSnippet source region Nothing $
2110 if isWithin NBranch context then
2112 D.reflow $
2113 "I was not expecting to see an arrow here:"
2115 D.stack
2117 D.reflow $
2118 "I think I am parsing a `case` expression right now, so it makes sense to\
2119 \ see arrows around here. This one is confusing me though!"
2121 D.toSimpleHint $
2122 "I may be getting confused by the indentation. Every pattern in a `case` must be\
2123 \ exactly aligned (with exactly the same amount of indentation) so maybe this arrow\
2124 \ appears after the next `case` pattern (correctly!) but the pattern itself is\
2125 \ indented too far?"
2129 else
2131 D.reflow $
2132 "I was not expecting an arrow here:"
2134 D.reflow $
2135 "Arrows should only appear in `case` expressions and anonymous functions. Maybe\
2136 \ you want > or >= instead?"
2139 BadEquals ->
2140 let
2141 region = toRegion row col
2142 name = getDefName context
2143 in
2144 Report.Report "UNEXPECTED EQUALS" region [] $
2145 Code.toSnippet source region Nothing
2147 D.reflow $
2148 "I was not expecting to see this equals sign:"
2150 D.stack
2152 D.reflow "Maybe you want == instead? To check if two values are equal?"
2154 D.toSimpleNote $
2155 if isWithin NRecord context then
2156 "Records look like { x = 3, y = 4 } with the equals sign right\
2157 \ after the field name. So maybe you forgot a comma?"
2158 else
2159 "I may be getting confused by your indentation. Is this supposed to be part of\
2160 \ a definition AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
2161 \ the problem may be a bit before the equals sign. I need all definitions to\
2162 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
2163 \ this new definition is indented a bit too much."
2167 BadHasType ->
2168 let
2169 region = toRegion row col
2170 name = getDefName context
2171 in
2172 Report.Report "UNEXPECTED SYMBOL" region [] $
2173 Code.toSnippet source region Nothing $
2175 D.reflow $
2176 "I was not expecting to run into the \"has type\" symbol here:"
2178 D.stack
2180 D.fillSep
2181 ["Maybe","you","want",D.green "::","instead?"
2182 ,"To","put","something","on","the","front","of","a","list?"
2184 , D.toSimpleNote $
2185 "The single colon is reserved for type annotations and record types, but I think\
2186 \ I am parsing the definition of `" ++ Name.toChars name ++ "` right now."
2188 D.toSimpleNote $
2189 "I may be getting confused by your indentation. Is this supposed to be part of\
2190 \ a type annotation AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
2191 \ the problem may be a bit before the \"has type\" symbol. I need all definitions to\
2192 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
2193 \ this new definition is indented a bit too much."
2199-- CASE
2202toLetReport :: Code.Source -> Context -> Let -> Row -> Col -> Report.Report
2203toLetReport source context let_ startRow startCol =
2204 case let_ of
2205 LetSpace space row col ->
2206 toSpaceReport source space row col
2208 LetIn row col ->
2209 let
2210 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2211 region = toRegion row col
2212 in
2213 Report.Report "LET PROBLEM" region [] $
2214 Code.toSnippet source surroundings (Just region)
2216 D.reflow $
2217 "I was partway through parsing a `let` expression, but I got stuck here:"
2219 D.stack
2220 [ D.fillSep $
2221 ["Based","on","the","indentation,","I","was","expecting","to","see","the",D.cyan "in"
2222 ,"keyword","next.","Is","there","a","typo?"
2224 , D.toSimpleNote $
2225 "This can also happen if you are trying to define another value within the `let` but\
2226 \ it is not indented enough. Make sure each definition has exactly the same amount of\
2227 \ spaces before it. They should line up exactly!"
2231 LetDefAlignment _ row col ->
2232 let
2233 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2234 region = toRegion row col
2235 in
2236 Report.Report "LET PROBLEM" region [] $
2237 Code.toSnippet source surroundings (Just region)
2239 D.reflow $
2240 "I was partway through parsing a `let` expression, but I got stuck here:"
2242 D.stack
2243 [ D.fillSep $
2244 ["Based","on","the","indentation,","I","was","expecting","to","see","the",D.cyan "in"
2245 ,"keyword","next.","Is","there","a","typo?"
2247 , D.toSimpleNote $
2248 "This can also happen if you are trying to define another value within the `let` but\
2249 \ it is not indented enough. Make sure each definition has exactly the same amount of\
2250 \ spaces before it. The should line up exactly!"
2254 LetDefName row col ->
2255 case Code.whatIsNext source row col of
2256 Code.Keyword keyword ->
2257 let
2258 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2259 region = toKeywordRegion row col keyword
2260 in
2261 Report.Report "RESERVED WORD" region [] $
2262 Code.toSnippet source surroundings (Just region)
2264 D.reflow $
2265 "I was partway through parsing a `let` expression, but I got stuck here:"
2267 D.reflow $
2268 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name, but\
2269 \ it is a reserved word! Try using a different name instead."
2272 _ ->
2273 toUnfinishLetReport source row col startRow startCol $
2274 D.reflow $
2275 "I was expecting the name of a definition next."
2277 LetDef name def row col ->
2278 error "TODO LetDef" name def row col
2280 LetDestruct destruct row col ->
2281 error "TODO LetDestruct" destruct row col
2283 LetBody expr row col ->
2284 toExprReport source context expr row col
2286 LetIndentDef row col ->
2287 toUnfinishLetReport source row col startRow startCol $
2288 D.reflow $
2289 "I was expecting a value to be defined here."
2291 LetIndentIn row col ->
2292 toUnfinishLetReport source row col startRow startCol $
2293 D.fillSep $
2294 ["I","was","expecting","to","see","the",D.cyan "in","keyword","next."
2295 ,"Or","maybe","more","of","that","expression?"
2298 LetIndentBody row col ->
2299 toUnfinishLetReport source row col startRow startCol $
2300 D.reflow $
2301 "I was expecting an expression next. Tell me what should happen with the value you just defined!"
2304toUnfinishLetReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
2305toUnfinishLetReport source row col startRow startCol message =
2306 let
2307 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2308 region = toRegion row col
2309 in
2310 Report.Report "UNFINISHED LET" region [] $
2311 Code.toSnippet source surroundings (Just region)
2313 D.reflow $
2314 "I was partway through parsing a `let` expression, but I got stuck here:"
2316 D.stack
2317 [ message
2318 , D.toSimpleNote $
2319 "Here is an example with a valid `let` expression for reference:"
2320 , D.vcat $
2321 [ D.indent 0 $ D.fillSep [D.green "viewPerson","person","="]
2322 , D.indent 2 $ D.fillSep [D.cyan "let"]
2323 , D.indent 4 $ D.fillSep ["fullName","="]
2324 , D.indent 6 $ D.fillSep ["person.firstName","++",D.dullyellow "\" \"","++","person.lastName"]
2325 , D.indent 2 $ D.fillSep [D.cyan "in"]
2326 , D.indent 2 $ D.fillSep ["div","[]","[","text","fullName","]"]
2328 , D.reflow $
2329 "Here we defined a `viewPerson` function that turns a person into some HTML. We use\
2330 \ a `let` expression to define the `fullName` we want to show. Notice the indentation! The\
2331 \ `fullName` is indented more than the `let` keyword, and the actual value of `fullName` is\
2332 \ indented a bit more than that. That is important!"
2338-- CASE
2341toCaseReport :: Code.Source -> Context -> Case -> Row -> Col -> Report.Report
2342toCaseReport source context case_ startRow startCol =
2343 case case_ of
2344 CaseSpace space row col ->
2345 toSpaceReport source space row col
2347 CaseOf row col ->
2348 toUnfinishCaseReport source row col startRow startCol $
2349 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
2351 CasePattern pattern row col ->
2352 toPatternReport source PCase pattern row col
2354 CaseArrow row col ->
2355 case Code.whatIsNext source row col of
2356 Code.Keyword keyword ->
2357 let
2358 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2359 region = toKeywordRegion row col keyword
2360 in
2361 Report.Report "RESERVED WORD" region [] $
2362 Code.toSnippet source surroundings (Just region)
2364 D.reflow $
2365 "I am partway through parsing a `case` expression, but I got stuck here:"
2367 D.reflow $
2368 "It looks like you are trying to use `" ++ keyword ++ "` in one of your\
2369 \ patterns, but it is a reserved word. Try using a different name?"
2372 Code.Operator ":" ->
2373 let
2374 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2375 region = toRegion row col
2376 in
2377 Report.Report "UNEXPECTED OPERATOR" region [] $
2378 Code.toSnippet source surroundings (Just region)
2380 D.reflow $
2381 "I am partway through parsing a `case` expression, but I got stuck here:"
2383 D.fillSep $
2384 ["I","am","seeing",D.dullyellow ":","but","maybe","you","want",D.green "::","instead?"
2385 ,"For","pattern","matching","on","lists?"
2389 Code.Operator "=" ->
2390 let
2391 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2392 region = toRegion row col
2393 in
2394 Report.Report "UNEXPECTED OPERATOR" region [] $
2395 Code.toSnippet source surroundings (Just region)
2397 D.reflow $
2398 "I am partway through parsing a `case` expression, but I got stuck here:"
2400 D.fillSep $
2401 ["I","am","seeing",D.dullyellow "=","but","maybe","you","want",D.green "->","instead?"
2405 _ ->
2406 let
2407 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2408 region = toRegion row col
2409 in
2410 Report.Report "MISSING ARROW" region [] $
2411 Code.toSnippet source surroundings (Just region)
2413 D.reflow $
2414 "I am partway through parsing a `case` expression, but I got stuck here:"
2416 addNoteForCaseIndentError $
2417 D.reflow $
2418 "I was expecting to see an arrow next."
2421 CaseExpr expr row col ->
2422 toExprReport source (InNode NCase startRow startCol context) expr row col
2424 CaseBranch expr row col ->
2425 toExprReport source (InNode NBranch startRow startCol context) expr row col
2427 CaseIndentOf row col ->
2428 toUnfinishCaseReport source row col startRow startCol $
2429 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
2431 CaseIndentExpr row col ->
2432 toUnfinishCaseReport source row col startRow startCol $
2433 D.reflow "I was expecting to see a expression next."
2435 CaseIndentPattern row col ->
2436 toUnfinishCaseReport source row col startRow startCol $
2437 D.reflow "I was expecting to see a pattern next."
2439 CaseIndentArrow row col ->
2440 toUnfinishCaseReport source row col startRow startCol $
2441 D.fillSep
2442 ["I","just","saw","a","pattern,","so","I","was","expecting"
2443 ,"to","see","a",D.dullyellow "->","next."
2446 CaseIndentBranch row col ->
2447 toUnfinishCaseReport source row col startRow startCol $
2448 D.reflow $
2449 "I was expecting to see an expression next. What should I do when\
2450 \ I run into this particular pattern?"
2452 CasePatternAlignment indent row col ->
2453 toUnfinishCaseReport source row col startRow startCol $
2454 D.reflow $
2455 "I suspect this is a pattern that is not indented far enough? (" ++ show indent ++ " spaces)"
2458toUnfinishCaseReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
2459toUnfinishCaseReport source row col startRow startCol message =
2460 let
2461 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2462 region = toRegion row col
2463 in
2464 Report.Report "UNFINISHED CASE" region [] $
2465 Code.toSnippet source surroundings (Just region)
2467 D.reflow $
2468 "I was partway through parsing a `case` expression, but I got stuck here:"
2470 D.stack
2471 [ message
2472 , D.toSimpleNote $
2473 "Here is an example of a valid `case` expression for reference."
2474 , D.vcat $
2475 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
2476 , D.indent 6 $ D.fillSep [D.green "Just","width","->"]
2477 , D.indent 8 $ D.fillSep ["width","+",D.dullyellow "200"]
2478 , ""
2479 , D.indent 6 $ D.fillSep [D.green "Nothing","->"]
2480 , D.indent 8 $ D.fillSep [D.dullyellow "400"]
2482 , D.reflow $
2483 "Notice the indentation. Each pattern is aligned, and each branch is indented\
2484 \ a bit more than the corresponding pattern. That is important!"
2489addNoteForCaseIndentError :: D.Doc -> D.Doc
2490addNoteForCaseIndentError message =
2491 D.stack $
2492 message
2494 [ D.toSimpleNote $
2495 "Sometimes I get confused by indentation, so try to make your `case` look\
2496 \ something like this:"
2497 , D.vcat $
2498 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
2499 , D.indent 6 $ D.fillSep [D.green "Just","width","->"]
2500 , D.indent 8 $ D.fillSep ["width","+",D.dullyellow "200"]
2501 , ""
2502 , D.indent 6 $ D.fillSep [D.green "Nothing","->"]
2503 , D.indent 8 $ D.fillSep [D.dullyellow "400"]
2505 , D.reflow $
2506 "Notice the indentation! Each pattern is aligned, and each branch is indented\
2507 \ a bit more than the corresponding pattern. That is important!"
2512-- IF
2515toIfReport :: Code.Source -> Context -> If -> Row -> Col -> Report.Report
2516toIfReport source context if_ startRow startCol =
2517 case if_ of
2518 IfSpace space row col ->
2519 toSpaceReport source space row col
2521 IfThen row col ->
2522 let
2523 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2524 region = toRegion row col
2525 in
2526 Report.Report "UNFINISHED IF" region [] $
2527 Code.toSnippet source surroundings (Just region)
2529 D.reflow $
2530 "I was expecting to see more of this `if` expression, but I got stuck here:"
2532 D.fillSep $
2533 ["I","was","expecting","to","see","the",D.cyan "then","keyword","next."
2537 IfElse row col ->
2538 let
2539 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2540 region = toRegion row col
2541 in
2542 Report.Report "UNFINISHED IF" region [] $
2543 Code.toSnippet source surroundings (Just region)
2545 D.reflow $
2546 "I was expecting to see more of this `if` expression, but I got stuck here:"
2548 D.fillSep $
2549 ["I","was","expecting","to","see","the",D.cyan "else","keyword","next."
2553 IfElseBranchStart row col ->
2554 let
2555 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2556 region = toRegion row col
2557 in
2558 Report.Report "UNFINISHED IF" region [] $
2559 Code.toSnippet source surroundings (Just region)
2561 D.reflow $
2562 "I just saw the start of an `else` branch, but then I got stuck here:"
2564 D.reflow $
2565 "I was expecting to see an expression next. Maybe it is not filled in yet?"
2568 IfCondition expr row col ->
2569 toExprReport source (InNode NCond startRow startCol context) expr row col
2571 IfThenBranch expr row col ->
2572 toExprReport source (InNode NThen startRow startCol context) expr row col
2574 IfElseBranch expr row col ->
2575 toExprReport source (InNode NElse startRow startCol context) expr row col
2577 IfIndentCondition row col ->
2578 let
2579 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2580 region = toRegion row col
2581 in
2582 Report.Report "UNFINISHED IF" region [] $
2583 Code.toSnippet source surroundings (Just region)
2585 D.reflow $
2586 "I was expecting to see more of this `if` expression, but I got stuck here:"
2588 D.stack
2589 [ D.fillSep $
2590 ["I","was","expecting","to","see","an","expression","like",D.dullyellow "x < 0"
2591 ,"that","evaluates","to","True","or","False."
2593 , D.toSimpleNote $
2594 "I can be confused by indentation. Maybe something is not indented enough?"
2598 IfIndentThen row col ->
2599 let
2600 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2601 region = toRegion row col
2602 in
2603 Report.Report "UNFINISHED IF" region [] $
2604 Code.toSnippet source surroundings (Just region)
2606 D.reflow $
2607 "I was expecting to see more of this `if` expression, but I got stuck here:"
2609 D.stack
2610 [ D.fillSep $
2611 ["I","was","expecting","to","see","the",D.cyan "then","keyword","next."
2613 , D.toSimpleNote $
2614 "I can be confused by indentation. Maybe something is not indented enough?"
2618 IfIndentThenBranch row col ->
2619 let
2620 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2621 region = toRegion row col
2622 in
2623 Report.Report "UNFINISHED IF" region [] $
2624 Code.toSnippet source surroundings (Just region)
2626 D.reflow $
2627 "I got stuck after the start of this `then` branch:"
2629 D.stack
2630 [ D.reflow $
2631 "I was expecting to see an expression next. Maybe it is not filled in yet?"
2632 , D.toSimpleNote $
2633 "I can be confused by indentation, so if the `then` branch is already\
2634 \ present, it may not be indented enough for me to recognize it."
2638 IfIndentElseBranch row col ->
2639 let
2640 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2641 region = toRegion row col
2642 in
2643 Report.Report "UNFINISHED IF" region [] $
2644 Code.toSnippet source surroundings (Just region)
2646 D.reflow $
2647 "I got stuck after the start of this `else` branch:"
2649 D.stack
2650 [ D.reflow $
2651 "I was expecting to see an expression next. Maybe it is not filled in yet?"
2652 , D.toSimpleNote $
2653 "I can be confused by indentation, so if the `else` branch is already\
2654 \ present, it may not be indented enough for me to recognize it."
2658 IfIndentElse row col ->
2659 let
2660 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2661 region = toRegion row col
2662 in
2663 Report.Report "UNFINISHED IF" region [] $
2664 Code.toSnippet source surroundings (Just region)
2666 D.reflow $
2667 "I was expecting to see an `else` branch after this:"
2669 D.stack
2670 [ D.reflow $
2671 "I know what to do when the condition is `True`, but not when it is `False`."
2672 , D.fillSep
2673 ["Add","an",D.cyan "else","branch","to","handle","that","scenario!"]
2679-- RECORD
2682toRecordReport :: Code.Source -> Context -> Record -> Row -> Col -> Report.Report
2683toRecordReport source context record startRow startCol =
2684 case record of
2685 RecordOpen row col ->
2686 case Code.whatIsNext source row col of
2687 Code.Keyword keyword ->
2688 let
2689 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2690 region = toKeywordRegion row col keyword
2691 in
2692 Report.Report "RESERVED WORD" region [] $
2693 Code.toSnippet source surroundings (Just region)
2695 D.reflow $
2696 "I just started parsing a record, but I got stuck on this field name:"
2698 D.reflow $
2699 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
2700 \ that is a reserved word. Try using a different name!"
2703 _ ->
2704 let
2705 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2706 region = toRegion row col
2707 in
2708 Report.Report "UNFINISHED RECORD" region [] $
2709 Code.toSnippet source surroundings (Just region)
2711 D.reflow $
2712 "I just started parsing a record, but I got stuck here:"
2714 D.fillSep
2715 ["Records","look","like",D.dullyellow "{ x = 3, y = 4 },"
2716 ,"so","I","was","expecting","to","see","a","field","name","next."
2720 RecordEnd row col ->
2721 let
2722 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2723 region = toRegion row col
2724 in
2725 Report.Report "UNFINISHED RECORD" region [] $
2726 Code.toSnippet source surroundings (Just region)
2728 D.reflow $
2729 "I am partway through parsing a record, but I got stuck here:"
2731 D.stack
2732 [ D.fillSep
2733 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
2734 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
2736 , D.toSimpleNote $
2737 "When I get stuck like this, it usually means that there is a missing parenthesis\
2738 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
2742 RecordField row col ->
2743 case Code.whatIsNext source row col of
2744 Code.Keyword keyword ->
2745 let
2746 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2747 region = toKeywordRegion row col keyword
2748 in
2749 Report.Report "RESERVED WORD" region [] $
2750 Code.toSnippet source surroundings (Just region)
2752 D.reflow $
2753 "I am partway through parsing a record, but I got stuck on this field name:"
2755 D.reflow $
2756 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
2757 \ that is a reserved word. Try using a different name!"
2760 _ ->
2761 let
2762 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2763 region = toRegion row col
2764 in
2765 Report.Report "UNFINISHED RECORD" region [] $
2766 Code.toSnippet source surroundings (Just region)
2768 D.reflow $
2769 "I am partway through parsing a record, but I got stuck after that last comma:"
2771 addNoteForRecordError $
2772 D.reflow $
2773 "Trailing commas are not allowed in records, so I was expecting to see another\
2774 \ record field defined next. If you are done defining the record, the fix may\
2775 \ be to delete that last comma?"
2778 RecordEquals row col ->
2779 let
2780 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2781 region = toRegion row col
2782 in
2783 Report.Report "UNFINISHED RECORD" region [] $
2784 Code.toSnippet source surroundings (Just region)
2786 D.reflow $
2787 "I am partway through parsing a record, but I got stuck here:"
2789 addNoteForRecordError $
2790 D.fillSep $
2791 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
2792 ,"an","equals","sign","next.","So","try","putting","an",D.green "=","sign","here?"
2796 RecordExpr expr row col ->
2797 toExprReport source (InNode NRecord startRow startCol context) expr row col
2799 RecordSpace space row col ->
2800 toSpaceReport source space row col
2802 RecordIndentOpen row col ->
2803 let
2804 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2805 region = toRegion row col
2806 in
2807 Report.Report "UNFINISHED RECORD" region [] $
2808 Code.toSnippet source surroundings (Just region)
2810 D.reflow $
2811 "I just saw the opening curly brace of a record, but then I got stuck here:"
2813 addNoteForRecordIndentError $
2814 D.fillSep $
2815 ["I","am","expecting","a","record","like",D.dullyellow "{ x = 3, y = 4 }","here."
2816 ,"Try","defining","some","fields","of","your","own?"
2820 RecordIndentEnd row col ->
2821 let
2822 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2823 region = toRegion row col
2824 in
2825 Report.Report "UNFINISHED RECORD" region [] $
2826 Code.toSnippet source surroundings (Just region)
2828 D.reflow $
2829 "I was expecting to see a closing curly brace next:"
2831 addNoteForRecordIndentError $
2832 D.fillSep $
2833 ["Try","putting","an",D.green "}","and","see","if","that","helps?"
2837 RecordIndentField row col ->
2838 let
2839 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2840 region = toRegion row col
2841 in
2842 Report.Report "UNFINISHED RECORD" region [] $
2843 Code.toSnippet source surroundings (Just region)
2845 D.reflow $
2846 "I am partway through parsing a record, but I got stuck after that last comma:"
2848 addNoteForRecordError $
2849 D.reflow $
2850 "Trailing commas are not allowed in records, so the fix may be to\
2851 \ delete that last comma? Or maybe you were in the middle of defining\
2852 \ an additional field?"
2855 RecordIndentEquals row col ->
2856 let
2857 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2858 region = toRegion row col
2859 in
2860 Report.Report "UNFINISHED RECORD" region [] $
2861 Code.toSnippet source surroundings (Just region)
2863 D.reflow $
2864 "I am partway through parsing a record. I just saw a record\
2865 \ field, so I was expecting to see an equals sign next:"
2867 addNoteForRecordIndentError $
2868 D.fillSep $
2869 ["Try","putting","an",D.green "=","followed","by","an","expression?"
2873 RecordIndentExpr row col ->
2874 let
2875 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2876 region = toRegion row col
2877 in
2878 Report.Report "UNFINISHED RECORD" region [] $
2879 Code.toSnippet source surroundings (Just region)
2881 D.reflow $
2882 "I am partway through parsing a record, and I was expecting to run into an expression next:"
2884 addNoteForRecordIndentError $
2885 D.fillSep $
2886 ["Try","putting","something,","like"
2887 ,D.dullyellow "42","or",D.dullyellow"\"hello\"","for","now?"
2892addNoteForRecordError :: D.Doc -> D.Doc
2893addNoteForRecordError normalRecommendation =
2894 D.stack $
2895 normalRecommendation
2897 [ D.toSimpleNote
2898 "If you are trying to define a record across multiple lines, I recommend using this format:"
2899 , D.indent 4 $ D.vcat $
2900 [ "{ name = \"Alice\""
2901 , ", age = 42"
2902 , ", height = 1.75"
2903 , "}"
2905 , D.reflow $
2906 "Notice that each line starts with some indentation. Usually two or four spaces. I\
2907 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
2908 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2912addNoteForRecordIndentError :: D.Doc -> D.Doc
2913addNoteForRecordIndentError normalRecommendation =
2914 D.stack $
2915 normalRecommendation
2917 [ D.toSimpleNote
2918 "I may be confused by indentation. For example, if you are trying to define\
2919 \ a record across multiple lines, I recommend using this format:"
2920 , D.indent 4 $ D.vcat $
2921 [ "{ name = \"Alice\""
2922 , ", age = 42"
2923 , ", height = 1.75"
2924 , "}"
2926 , D.reflow $
2927 "Notice that each line starts with some indentation. Usually two or four spaces. I\
2928 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
2929 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2934-- TUPLE
2937toTupleReport :: Code.Source -> Context -> Tuple -> Row -> Col -> Report.Report
2938toTupleReport source context tuple startRow startCol =
2939 case tuple of
2940 TupleExpr expr row col ->
2941 toExprReport source (InNode NParens startRow startCol context) expr row col
2943 TupleSpace space row col ->
2944 toSpaceReport source space row col
2946 TupleEnd row col ->
2947 let
2948 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2949 region = toRegion row col
2950 in
2951 Report.Report "UNFINISHED PARENTHESES" region [] $
2952 Code.toSnippet source surroundings (Just region)
2954 D.reflow $
2955 "I was expecting to see a closing parentheses next, but I got stuck here:"
2957 D.stack
2958 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
2959 , D.toSimpleNote $
2960 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
2961 \ unexpectedly. So there may be some earlier syntax trouble (like extra parenthesis\
2962 \ or missing brackets) that is confusing me."
2966 TupleOperatorClose row col ->
2967 let
2968 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2969 region = toRegion row col
2970 in
2971 Report.Report "UNFINISHED OPERATOR FUNCTION" region [] $
2972 Code.toSnippet source surroundings (Just region)
2974 D.reflow "I was expecting a closing parenthesis here:"
2976 D.stack
2977 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
2978 , D.toSimpleNote $
2979 "I think I am parsing an operator function right now, so I am expecting to see\
2980 \ something like (+) or (&&) where an operator is surrounded by parentheses with\
2981 \ no extra spaces."
2985 TupleOperatorReserved operator row col ->
2986 let
2987 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2988 region = toRegion row col
2989 in
2990 Report.Report "UNEXPECTED SYMBOL" region [] $
2991 Code.toSnippet source surroundings (Just region)
2993 D.reflow $
2994 "I ran into an unexpected symbol here:"
2996 D.fillSep $
2997 case operator of
2998 BadDot -> ["Maybe","you","wanted","a","record","accessor","like",D.dullyellow ".x","or",D.dullyellow ".name","instead?"]
2999 BadPipe -> ["Try",D.dullyellow "(||)","instead?","To","turn","boolean","OR","into","a","function?"]
3000 BadArrow -> ["Maybe","you","wanted",D.dullyellow "(>)","or",D.dullyellow "(>=)","instead?"]
3001 BadEquals -> ["Try",D.dullyellow "(==)","instead?","To","make","a","function","that","checks","equality?"]
3002 BadHasType -> ["Try",D.dullyellow "(::)","instead?","To","add","values","to","the","front","of","lists?"]
3005 TupleIndentExpr1 row col ->
3006 let
3007 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3008 region = toRegion row col
3009 in
3010 Report.Report "UNFINISHED PARENTHESES" region [] $
3011 Code.toSnippet source surroundings (Just region)
3013 D.reflow $
3014 "I just saw an open parenthesis, so I was expecting to see an expression next."
3016 D.stack
3017 [ D.fillSep $
3018 ["Something","like",D.dullyellow "(4 + 5)","or"
3019 ,D.dullyellow "(String.reverse \"desserts\")" <> "."
3020 ,"Anything","where","you","are","putting","parentheses","around","normal","expressions."
3022 , D.toSimpleNote $
3023 "I can get confused by indentation in cases like this, so\
3024 \ maybe you have an expression but it is not indented enough?"
3028 TupleIndentExprN row col ->
3029 let
3030 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3031 region = toRegion row col
3032 in
3033 Report.Report "UNFINISHED TUPLE" region [] $
3034 Code.toSnippet source surroundings (Just region)
3036 D.reflow $
3037 "I think I am in the middle of parsing a tuple. I just saw a comma, so I was expecting to see an expression next."
3039 D.stack
3040 [ D.fillSep $
3041 ["A","tuple","looks","like",D.dullyellow "(3,4)","or"
3042 ,D.dullyellow "(\"Tom\",42)" <> ","
3043 ,"so","I","think","there","is","an","expression","missing","here?"
3045 , D.toSimpleNote $
3046 "I can get confused by indentation in cases like this, so\
3047 \ maybe you have an expression but it is not indented enough?"
3051 TupleIndentEnd row col ->
3052 let
3053 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3054 region = toRegion row col
3055 in
3056 Report.Report "UNFINISHED PARENTHESES" region [] $
3057 Code.toSnippet source surroundings (Just region)
3059 D.reflow $
3060 "I was expecting to see a closing parenthesis next:"
3062 D.stack
3063 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
3064 , D.toSimpleNote $
3065 "I can get confused by indentation in cases like this, so\
3066 \ maybe you have a closing parenthesis but it is not indented enough?"
3071toListReport :: Code.Source -> Context -> List -> Row -> Col -> Report.Report
3072toListReport source context list startRow startCol =
3073 case list of
3074 ListSpace space row col ->
3075 toSpaceReport source space row col
3077 ListOpen row col ->
3078 let
3079 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3080 region = toRegion row col
3081 in
3082 Report.Report "UNFINISHED LIST" region [] $
3083 Code.toSnippet source surroundings (Just region)
3085 D.reflow $
3086 "I am partway through parsing a list, but I got stuck here:"
3088 D.stack
3089 [ D.fillSep
3090 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
3091 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
3093 , D.toSimpleNote $
3094 "When I get stuck like this, it usually means that there is a missing parenthesis\
3095 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
3099 ListExpr expr row col ->
3100 case expr of
3101 Start r c ->
3102 let
3103 surroundings = A.Region (A.Position startRow startCol) (A.Position r c)
3104 region = toRegion r c
3105 in
3106 Report.Report "UNFINISHED LIST" region [] $
3107 Code.toSnippet source surroundings (Just region)
3109 D.reflow $
3110 "I was expecting to see another list entry after that last comma:"
3112 D.stack
3113 [ D.reflow $
3114 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
3115 , D.toSimpleNote
3116 "I recommend using the following format for lists that span multiple lines:"
3117 , D.indent 4 $ D.vcat $
3118 [ "[ \"Alice\""
3119 , ", \"Bob\""
3120 , ", \"Chuck\""
3121 , "]"
3123 , D.reflow $
3124 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
3125 \ This style can be jarring for people coming from C-like syntax, but folks generally\
3126 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3130 _ ->
3131 toExprReport source (InNode NList startRow startCol context) expr row col
3133 ListEnd row col ->
3134 let
3135 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3136 region = toRegion row col
3137 in
3138 Report.Report "UNFINISHED LIST" region [] $
3139 Code.toSnippet source surroundings (Just region)
3141 D.reflow $
3142 "I am partway through parsing a list, but I got stuck here:"
3144 D.stack
3145 [ D.fillSep
3146 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
3147 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
3149 , D.toSimpleNote $
3150 "When I get stuck like this, it usually means that there is a missing parenthesis\
3151 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
3155 ListIndentOpen row col ->
3156 let
3157 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3158 region = toRegion row col
3159 in
3160 Report.Report "UNFINISHED LIST" region [] $
3161 Code.toSnippet source surroundings (Just region)
3163 D.reflow $
3164 "I cannot find the end of this list:"
3166 D.stack
3167 [ D.fillSep $
3168 ["You","could","change","it","to","something","like"
3169 ,D.dullyellow "[3,4,5]"
3170 ,"or","even","just"
3171 ,D.dullyellow "[]" <> "."
3172 ,"Anything","where","there","is","an","open","and","close","square","brace,"
3173 ,"and","where","the","elements","of","the","list","are","separated","by","commas."
3175 , D.toSimpleNote
3176 "I may be confused by indentation. For example, if you are trying to define\
3177 \ a list across multiple lines, I recommend using this format:"
3178 , D.indent 4 $ D.vcat $
3179 [ "[ \"Alice\""
3180 , ", \"Bob\""
3181 , ", \"Chuck\""
3182 , "]"
3184 , D.reflow $
3185 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
3186 \ This style can be jarring for people coming from C-like syntax, but folks generally\
3187 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3191 ListIndentEnd row col ->
3192 let
3193 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3194 region = toRegion row col
3195 in
3196 Report.Report "UNFINISHED LIST" region [] $
3197 Code.toSnippet source surroundings (Just region)
3199 D.reflow $
3200 "I cannot find the end of this list:"
3202 D.stack
3203 [ D.fillSep $
3204 ["You","can","just","add","a","closing",D.dullyellow "]"
3205 ,"right","here,","and","I","will","be","all","set!"
3207 , D.toSimpleNote
3208 "I may be confused by indentation. For example, if you are trying to define\
3209 \ a list across multiple lines, I recommend using this format:"
3210 , D.indent 4 $ D.vcat $
3211 [ "[ \"Alice\""
3212 , ", \"Bob\""
3213 , ", \"Chuck\""
3214 , "]"
3216 , D.reflow $
3217 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
3218 \ This style can be jarring for people coming from C-like syntax, but folks generally\
3219 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3223 ListIndentExpr row col ->
3224 let
3225 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3226 region = toRegion row col
3227 in
3228 Report.Report "UNFINISHED LIST" region [] $
3229 Code.toSnippet source surroundings (Just region)
3231 D.reflow $
3232 "I was expecting to see another list entry after this comma:"
3234 D.stack
3235 [ D.reflow $
3236 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
3237 , D.toSimpleNote
3238 "I recommend using the following format for lists that span multiple lines:"
3239 , D.indent 4 $ D.vcat $
3240 [ "[ \"Alice\""
3241 , ", \"Bob\""
3242 , ", \"Chuck\""
3243 , "]"
3245 , D.reflow $
3246 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
3247 \ This style can be jarring for people coming from C-like syntax, but folks generally\
3248 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3253toFuncReport :: Code.Source -> Context -> Func -> Row -> Col -> Report.Report
3254toFuncReport source context func startRow startCol =
3255 case func of
3256 FuncSpace space row col ->
3257 toSpaceReport source space row col
3259 FuncArg pattern row col ->
3260 toPatternReport source PArg pattern row col
3262 FuncBody expr row col ->
3263 toExprReport source (InNode NFunc startRow startCol context) expr row col
3265 FuncArrow row col ->
3266 case Code.whatIsNext source row col of
3267 Code.Keyword keyword ->
3268 let
3269 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3270 region = toKeywordRegion row col keyword
3271 in
3272 Report.Report "RESERVED WORD" region [] $
3273 Code.toSnippet source surroundings (Just region)
3275 D.reflow $
3276 "I was parsing an anonymous function, but I got stuck here:"
3278 D.reflow $
3279 "It looks like you are trying to use `" ++ keyword ++ "` as an argument, but\
3280 \ it is a reserved word in this language. Try using a different argument name!"
3283 _ ->
3284 let
3285 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3286 region = toRegion row col
3287 in
3288 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
3289 Code.toSnippet source surroundings (Just region)
3291 D.reflow $
3292 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
3294 D.fillSep $
3295 ["The","syntax","for","anonymous","functions","is"
3296 ,D.dullyellow "(\\x -> x + 1)"
3297 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
3301 FuncIndentArg row col ->
3302 let
3303 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3304 region = toRegion row col
3305 in
3306 Report.Report "MISSING ARGUMENT" region [] $
3307 Code.toSnippet source surroundings (Just region)
3309 D.reflow $
3310 "I just saw the beginning of an anonymous function, so I was expecting to see an argument next:"
3312 D.stack
3313 [ D.fillSep
3314 ["Something","like",D.dullyellow"x","or",D.dullyellow "name" <> "."
3315 ,"Anything","that","starts","with","a","lower","case","letter!"
3317 , D.toSimpleNote $
3318 "The syntax for anonymous functions is (\\x -> x + 1) where the backslash\
3319 \ is meant to look a bit like a lambda if you squint. This visual pun seemed\
3320 \ like a better idea at the time!"
3324 FuncIndentArrow row col ->
3325 let
3326 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3327 region = toRegion row col
3328 in
3329 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
3330 Code.toSnippet source surroundings (Just region)
3332 D.reflow $
3333 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
3335 D.stack
3336 [ D.fillSep $
3337 ["The","syntax","for","anonymous","functions","is"
3338 ,D.dullyellow "(\\x -> x + 1)"
3339 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
3341 , D.toSimpleNote $
3342 "It is possible that I am confused about indetation! I generally recommend\
3343 \ switching to named functions if the definition cannot fit inline nicely, so\
3344 \ either (1) try to fit the whole anonymous function on one line or (2) break\
3345 \ the whole thing out into a named function. Things tend to be clearer that way!"
3349 FuncIndentBody row col ->
3350 let
3351 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3352 region = toRegion row col
3353 in
3354 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
3355 Code.toSnippet source surroundings (Just region)
3357 D.reflow $
3358 "I was expecting to see the body of your anonymous function next:"
3360 D.stack
3361 [ D.fillSep $
3362 ["The","syntax","for","anonymous","functions","is"
3363 ,D.dullyellow "(\\x -> x + 1)"
3364 ,"so","I","am","missing","all","the","stuff","after","the","arrow!"
3366 , D.toSimpleNote $
3367 "It is possible that I am confused about indetation! I generally recommend\
3368 \ switching to named functions if the definition cannot fit inline nicely, so\
3369 \ either (1) try to fit the whole anonymous function on one line or (2) break\
3370 \ the whole thing out into a named function. Things tend to be clearer that way!"
3376-- PATTERN
3379data PContext
3380 = PCase
3381 | PArg
3384toPatternReport :: Code.Source -> PContext -> Pattern -> Row -> Col -> Report.Report
3385toPatternReport source context pattern startRow startCol =
3386 case pattern of
3387 PRecord record row col ->
3388 toPRecordReport source record row col
3390 PTuple tuple row col ->
3391 toPTupleReport source context tuple row col
3393 PList list row col ->
3394 toPListReport source context list row col
3396 PStart row col ->
3397 case Code.whatIsNext source row col of
3398 Code.Keyword keyword ->
3399 let
3400 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3401 region = toKeywordRegion row col keyword
3402 aThing =
3403 case context of
3404 PArg -> "an argument"
3405 PCase -> "a pattern"
3406 in
3407 Report.Report "RESERVED WORD" region [] $
3408 Code.toSnippet source surroundings (Just region)
3410 D.reflow $
3411 "It looks like you are trying to use `" ++ keyword ++ "` as " ++ aThing ++ ":"
3413 D.reflow $
3414 "This is a reserved word! Try using some other name?"
3417 _ ->
3418 error "TODO PStart"
3420 PChar char row col ->
3421 toCharReport source char row col
3423 PString string row col ->
3424 toStringReport source string row col
3426 PNumber number row col ->
3427 toNumberReport source number row col
3429 PFloat width row col ->
3430 let
3431 region = toWiderRegion row col width
3432 in
3433 Report.Report "UNEXPECTED PATTERN" region [] $
3434 Code.toSnippet source region Nothing
3436 D.reflow $
3437 "I cannot pattern match with floating point numbers:"
3439 D.fillSep $
3440 ["Equality","on","floats","can","be","unreliable,","so","you","usually","want"
3441 ,"to","check","that","they","are","nearby","with","some","sort","of"
3442 ,D.dullyellow "(abs (actual - expected) < 0.001)","check."
3446 PAlias row col ->
3447 let
3448 region = toRegion row col
3449 in
3450 Report.Report "UNFINISHED PATTERN" region [] $
3451 Code.toSnippet source region Nothing $
3453 D.reflow $
3454 "I was expecting to see a variable name after the `as` keyword:"
3456 D.stack
3457 [ D.fillSep $
3458 ["The","`as`","keyword","lets","you","write","patterns","like"
3459 ,"((" <> D.dullyellow "x" <> "," <> D.dullyellow "y" <> ") " <> D.cyan "as" <> D.dullyellow " point" <> ")"
3460 ,"so","you","can","refer","to","individual","parts","of","the","tuple","with"
3461 ,D.dullyellow "x","and",D.dullyellow "y","or","you","refer","to","the","whole"
3462 ,"thing","with",D.dullyellow "point."
3464 , D.reflow $
3465 "So I was expecting to see a variable name after the `as` keyword here. Sometimes\
3466 \ people just want to use `as` as a variable name though. Try using a different name\
3467 \ in that case!"
3471 PWildcardNotVar name width row col ->
3472 let
3473 region = toWiderRegion row col (fromIntegral width)
3474 examples =
3475 case dropWhile (=='_') (Name.toChars name) of
3476 [] -> [D.dullyellow "x","or",D.dullyellow "age"]
3477 c:cs -> [D.dullyellow (D.fromChars (Char.toLower c : cs))]
3478 in
3479 Report.Report "UNEXPECTED NAME" region [] $
3480 Code.toSnippet source region Nothing $
3482 D.reflow $
3483 "Variable names cannot start with underscores like this:"
3485 D.fillSep $
3486 ["You","can","either","have","an","underscore","like",D.dullyellow "_","to"
3487 ,"ignore","the","value,","or","you","can","have","a","name","like"
3488 ] ++ examples ++ ["to","use","the","matched","value." ]
3491 PSpace space row col ->
3492 toSpaceReport source space row col
3494 PIndentStart row col ->
3495 error "TODO PIndentStart" row col
3497 PIndentAlias row col ->
3498 let
3499 region = toRegion row col
3500 in
3501 Report.Report "UNFINISHED PATTERN" region [] $
3502 Code.toSnippet source region Nothing $
3504 D.reflow $
3505 "I was expecting to see a variable name after the `as` keyword:"
3507 D.stack
3508 [ D.fillSep $
3509 ["The","`as`","keyword","lets","you","write","patterns","like"
3510 ,"((" <> D.dullyellow "x" <> "," <> D.dullyellow "y" <> ") " <> D.cyan "as" <> D.dullyellow " point" <> ")"
3511 ,"so","you","can","refer","to","individual","parts","of","the","tuple","with"
3512 ,D.dullyellow "x","and",D.dullyellow "y","or","you","refer","to","the","whole"
3513 ,"thing","with",D.dullyellow "point."
3515 , D.reflow $
3516 "So I was expecting to see a variable name after the `as` keyword here. Sometimes\
3517 \ people just want to use `as` as a variable name though. Try using a different name\
3518 \ in that case!"
3523toPRecordReport :: Code.Source -> PRecord -> Row -> Col -> Report.Report
3524toPRecordReport source record startRow startCol =
3525 case record of
3526 PRecordOpen row col ->
3527 toUnfinishRecordPatternReport source row col startRow startCol $
3528 D.reflow "I was expecting to see a field name next."
3530 PRecordEnd row col ->
3531 toUnfinishRecordPatternReport source row col startRow startCol $
3532 D.fillSep
3533 ["I","was","expecting","to","see","a","closing","curly","brace","next."
3534 ,"Try","adding","a",D.dullyellow "}","here?"
3537 PRecordField row col ->
3538 case Code.whatIsNext source row col of
3539 Code.Keyword keyword ->
3540 let
3541 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3542 region = toKeywordRegion row col keyword
3543 in
3544 Report.Report "RESERVED WORD" region [] $
3545 Code.toSnippet source surroundings (Just region)
3547 D.reflow $
3548 "I was not expecting to see `" ++ keyword ++ "` as a record field name:"
3550 D.reflow $
3551 "This is a reserved word, not available for variable names. Try another name!"
3554 _ ->
3555 toUnfinishRecordPatternReport source row col startRow startCol $
3556 D.reflow "I was expecting to see a field name next."
3558 PRecordSpace space row col ->
3559 toSpaceReport source space row col
3561 PRecordIndentOpen row col ->
3562 toUnfinishRecordPatternReport source row col startRow startCol $
3563 D.reflow "I was expecting to see a field name next."
3565 PRecordIndentEnd row col ->
3566 toUnfinishRecordPatternReport source row col startRow startCol $
3567 D.fillSep
3568 ["I","was","expecting","to","see","a","closing","curly","brace","next."
3569 ,"Try","adding","a",D.dullyellow "}","here?"
3572 PRecordIndentField row col ->
3573 toUnfinishRecordPatternReport source row col startRow startCol $
3574 D.reflow "I was expecting to see a field name next."
3577toUnfinishRecordPatternReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
3578toUnfinishRecordPatternReport source row col startRow startCol message =
3579 let
3580 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3581 region = toRegion row col
3582 in
3583 Report.Report "UNFINISHED RECORD PATTERN" region [] $
3584 Code.toSnippet source surroundings (Just region)
3586 D.reflow $
3587 "I was partway through parsing a record pattern, but I got stuck here:"
3589 D.stack
3590 [ message
3591 , D.toFancyHint $
3592 ["A","record","pattern","looks","like",D.dullyellow "{x,y}","or",D.dullyellow "{name,age}"
3593 ,"where","you","list","the","field","names","you","want","to","access."
3600toPTupleReport :: Code.Source -> PContext -> PTuple -> Row -> Col -> Report.Report
3601toPTupleReport source context tuple startRow startCol =
3602 case tuple of
3603 PTupleOpen row col ->
3604 case Code.whatIsNext source row col of
3605 Code.Keyword keyword ->
3606 let
3607 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3608 region = toKeywordRegion row col keyword
3609 in
3610 Report.Report "RESERVED WORD" region [] $
3611 Code.toSnippet source surroundings (Just region)
3613 D.reflow $
3614 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name:"
3616 D.reflow $
3617 "This is a reserved word! Try using some other name?"
3620 _ ->
3621 let
3622 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3623 region = toRegion row col
3624 in
3625 Report.Report "UNFINISHED PARENTHESES" region [] $
3626 Code.toSnippet source surroundings (Just region)
3628 D.reflow $
3629 "I just saw an open parenthesis, but I got stuck here:"
3631 D.fillSep
3632 ["I","was","expecting","so","see","a","pattern","next."
3633 ,"Maybe","it","will","end","up","being","something"
3634 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "?"
3638 PTupleEnd row col ->
3639 let
3640 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3641 region = toRegion row col
3642 in
3643 Report.Report "UNFINISHED PARENTHESES" region [] $
3644 Code.toSnippet source surroundings (Just region) $
3646 D.reflow $
3647 "I was expecting a closing parenthesis next:"
3649 D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
3652 PTupleExpr pattern row col ->
3653 toPatternReport source context pattern row col
3655 PTupleSpace space row col ->
3656 toSpaceReport source space row col
3658 PTupleIndentEnd row col ->
3659 let
3660 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3661 region = toRegion row col
3662 in
3663 Report.Report "UNFINISHED PARENTHESES" region [] $
3664 Code.toSnippet source surroundings (Just region) $
3666 D.reflow $
3667 "I was expecting a closing parenthesis next:"
3669 D.stack
3670 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
3671 , D.toSimpleNote $
3672 "I can get confused by indentation in cases like this, so\
3673 \ maybe you have a closing parenthesis but it is not indented enough?"
3677 PTupleIndentExpr1 row col ->
3678 let
3679 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3680 region = toRegion row col
3681 in
3682 Report.Report "UNFINISHED PARENTHESES" region [] $
3683 Code.toSnippet source surroundings (Just region) $
3685 D.reflow $
3686 "I just saw an open parenthesis, but then I got stuck here:"
3688 D.fillSep
3689 ["I","was","expecting","so","see","a","pattern","next."
3690 ,"Maybe","it","will","end","up","being","something"
3691 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "?"
3695 PTupleIndentExprN row col ->
3696 let
3697 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3698 region = toRegion row col
3699 in
3700 Report.Report "UNFINISHED TUPLE PATTERN" region [] $
3701 Code.toSnippet source surroundings (Just region) $
3703 D.reflow $
3704 "I am partway through parsing a tuple pattern, but I got stuck here:"
3706 D.stack
3707 [ D.fillSep
3708 ["I","was","expecting","so","see","a","pattern","next."
3709 ,"I","am","expecting","the","final","result","to","be","something"
3710 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "."
3712 , D.toSimpleNote $
3713 "I can get confused by indentation in cases like this, so the problem\
3714 \ may be that the next part is not indented enough?"
3719toPListReport :: Code.Source -> PContext -> PList -> Row -> Col -> Report.Report
3720toPListReport source context list startRow startCol =
3721 case list of
3722 PListOpen row col ->
3723 case Code.whatIsNext source row col of
3724 Code.Keyword keyword ->
3725 let
3726 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3727 region = toKeywordRegion row col keyword
3728 in
3729 Report.Report "RESERVED WORD" region [] $
3730 Code.toSnippet source surroundings (Just region)
3732 D.reflow $
3733 "It looks like you are trying to use `" ++ keyword ++ "` to name an element of a list:"
3735 D.reflow $
3736 "This is a reserved word though! Try using some other name?"
3739 _ ->
3740 let
3741 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3742 region = toRegion row col
3743 in
3744 Report.Report "UNFINISHED LIST PATTERN" region [] $
3745 Code.toSnippet source surroundings (Just region) $
3747 D.reflow $
3748 "I just saw an open square bracket, but then I got stuck here:"
3750 D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
3753 PListEnd row col ->
3754 let
3755 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3756 region = toRegion row col
3757 in
3758 Report.Report "UNFINISHED LIST PATTERN" region [] $
3759 Code.toSnippet source surroundings (Just region) $
3761 D.reflow $
3762 "I was expecting a closing square bracket to end this list pattern:"
3764 D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
3767 PListExpr pattern row col ->
3768 toPatternReport source context pattern row col
3770 PListSpace space row col ->
3771 toSpaceReport source space row col
3773 PListIndentOpen row col ->
3774 let
3775 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3776 region = toRegion row col
3777 in
3778 Report.Report "UNFINISHED LIST PATTERN" region [] $
3779 Code.toSnippet source surroundings (Just region) $
3781 D.reflow $
3782 "I just saw an open square bracket, but then I got stuck here:"
3784 D.stack
3785 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
3786 , D.toSimpleNote $
3787 "I can get confused by indentation in cases like this, so\
3788 \ maybe there is something next, but it is not indented enough?"
3792 PListIndentEnd row col ->
3793 let
3794 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3795 region = toRegion row col
3796 in
3797 Report.Report "UNFINISHED LIST PATTERN" region [] $
3798 Code.toSnippet source surroundings (Just region) $
3800 D.reflow $
3801 "I was expecting a closing square bracket to end this list pattern:"
3803 D.stack
3804 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
3805 , D.toSimpleNote $
3806 "I can get confused by indentation in cases like this, so\
3807 \ maybe you have a closing square bracket but it is not indented enough?"
3811 PListIndentExpr row col ->
3812 let
3813 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3814 region = toRegion row col
3815 in
3816 Report.Report "UNFINISHED LIST PATTERN" region [] $
3817 Code.toSnippet source surroundings (Just region) $
3819 D.reflow $
3820 "I am partway through parsing a list pattern, but I got stuck here:"
3822 D.stack
3823 [ D.reflow $
3824 "I was expecting to see another pattern next. Maybe a variable name."
3825 , D.toSimpleNote $
3826 "I can get confused by indentation in cases like this, so\
3827 \ maybe there is more to this pattern but it is not indented enough?"
3833-- TYPES
3836-- TODO add context? say something special if you are in type annotation vs custom type vs type alias?
3838toTypeReport :: Code.Source -> Type -> Row -> Col -> Report.Report
3839toTypeReport source tipe startRow startCol =
3840 case tipe of
3841 TRecord record row col ->
3842 toTRecordReport source record row col
3844 TTuple tuple row col ->
3845 toTTupleReport source tuple row col
3847 TArrow row col ->
3848 error "TODO TArrow" row col
3850 TStart row col ->
3851 error "TODO TStart" row col startRow startCol
3853 TSpace space row col ->
3854 toSpaceReport source space row col
3856 TIndentStart row col ->
3857 error "TODO TIndentStart" row col
3861toTRecordReport :: Code.Source -> TRecord -> Row -> Col -> Report.Report
3862toTRecordReport source record startRow startCol =
3863 case record of
3864 TRecordOpen row col ->
3865 case Code.whatIsNext source row col of
3866 Code.Keyword keyword ->
3867 let
3868 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3869 region = toKeywordRegion row col keyword
3870 in
3871 Report.Report "RESERVED WORD" region [] $
3872 Code.toSnippet source surroundings (Just region)
3874 D.reflow $
3875 "I just started parsing a record type, but I got stuck on this field name:"
3877 D.reflow $
3878 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
3879 \ that is a reserved word. Try using a different name!"
3882 _ ->
3883 let
3884 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3885 region = toRegion row col
3886 in
3887 Report.Report "UNFINISHED RECORD TYPE" region [] $
3888 Code.toSnippet source surroundings (Just region)
3890 D.reflow $
3891 "I just started parsing a record type, but I got stuck here:"
3893 D.fillSep
3894 ["Record","types","look","like",D.dullyellow "{ name : String, age : Int },"
3895 ,"so","I","was","expecting","to","see","a","field","name","next."
3899 TRecordEnd row col ->
3900 let
3901 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3902 region = toRegion row col
3903 in
3904 Report.Report "UNFINISHED RECORD TYPE" region [] $
3905 Code.toSnippet source surroundings (Just region)
3907 D.reflow $
3908 "I am partway through parsing a record type, but I got stuck here:"
3910 D.stack
3911 [ D.fillSep
3912 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
3913 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
3915 , D.toSimpleNote $
3916 "When I get stuck like this, it usually means that there is a missing parenthesis\
3917 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
3921 TRecordField row col ->
3922 case Code.whatIsNext source row col of
3923 Code.Keyword keyword ->
3924 let
3925 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3926 region = toKeywordRegion row col keyword
3927 in
3928 Report.Report "RESERVED WORD" region [] $
3929 Code.toSnippet source surroundings (Just region)
3931 D.reflow $
3932 "I am partway through parsing a record type, but I got stuck on this field name:"
3934 D.reflow $
3935 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
3936 \ that is a reserved word. Try using a different name!"
3939 _ ->
3940 let
3941 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3942 region = toRegion row col
3943 in
3944 Report.Report "UNFINISHED RECORD TYPE" region [] $
3945 Code.toSnippet source surroundings (Just region)
3947 D.reflow $
3948 "I am partway through parsing a record type, but I got stuck after that last comma:"
3950 addNoteForRecordTypeError $
3951 D.reflow $
3952 "Trailing commas are not allowed in records, so I was expecting to see another\
3953 \ record field defined next. If you are done defining the record, the fix may\
3954 \ be to delete that last comma?"
3957 TRecordColon row col ->
3958 let
3959 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3960 region = toRegion row col
3961 in
3962 Report.Report "UNFINISHED RECORD TYPE" region [] $
3963 Code.toSnippet source surroundings (Just region)
3965 D.reflow $
3966 "I am partway through parsing a record type, but I got stuck here:"
3968 addNoteForRecordTypeError $
3969 D.fillSep $
3970 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
3971 ,"a","colon","next.","So","try","putting","an",D.green ":","sign","here?"
3975 TRecordType tipe row col ->
3976 toTypeReport source tipe row col
3978 TRecordSpace space row col ->
3979 toSpaceReport source space row col
3981 TRecordIndentOpen row col ->
3982 let
3983 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3984 region = toRegion row col
3985 in
3986 Report.Report "UNFINISHED RECORD TYPE" region [] $
3987 Code.toSnippet source surroundings (Just region)
3989 D.reflow $
3990 "I just saw the opening curly brace of a record type, but then I got stuck here:"
3992 addNoteForRecordTypeIndentError $
3993 D.fillSep $
3994 ["I","am","expecting","a","record","like",D.dullyellow "{ name : String, age : Int }","here."
3995 ,"Try","defining","some","fields","of","your","own?"
3999 TRecordIndentEnd row col ->
4000 let
4001 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4002 region = toRegion row col
4003 in
4004 Report.Report "UNFINISHED RECORD TYPE" region [] $
4005 Code.toSnippet source surroundings (Just region)
4007 D.reflow $
4008 "I was expecting to see a closing curly brace next:"
4010 addNoteForRecordTypeIndentError $
4011 D.fillSep $
4012 ["Try","putting","an",D.green "}","and","see","if","that","helps?"
4016 TRecordIndentField row col ->
4017 let
4018 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4019 region = toRegion row col
4020 in
4021 Report.Report "UNFINISHED RECORD TYPE" region [] $
4022 Code.toSnippet source surroundings (Just region)
4024 D.reflow $
4025 "I am partway through parsing a record type, but I got stuck after that last comma:"
4027 addNoteForRecordTypeIndentError $
4028 D.reflow $
4029 "Trailing commas are not allowed in record types, so the fix may be to\
4030 \ delete that last comma? Or maybe you were in the middle of defining\
4031 \ an additional field?"
4034 TRecordIndentColon row col ->
4035 let
4036 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4037 region = toRegion row col
4038 in
4039 Report.Report "UNFINISHED RECORD TYPE" region [] $
4040 Code.toSnippet source surroundings (Just region)
4042 D.reflow $
4043 "I am partway through parsing a record type. I just saw a record\
4044 \ field, so I was expecting to see a colon next:"
4046 addNoteForRecordTypeIndentError $
4047 D.fillSep $
4048 ["Try","putting","an",D.green ":","followed","by","a","type?"
4052 TRecordIndentType row col ->
4053 let
4054 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4055 region = toRegion row col
4056 in
4057 Report.Report "UNFINISHED RECORD TYPE" region [] $
4058 Code.toSnippet source surroundings (Just region)
4060 D.reflow $
4061 "I am partway through parsing a record type, and I was expecting to run into a type next:"
4063 addNoteForRecordTypeIndentError $
4064 D.fillSep $
4065 ["Try","putting","something,","like"
4066 ,D.dullyellow "Int","or",D.dullyellow "String","for","now?"
4071addNoteForRecordTypeError :: D.Doc -> D.Doc
4072addNoteForRecordTypeError normalRecommendation =
4073 D.stack $
4074 normalRecommendation
4076 [ D.toSimpleNote
4077 "If you are trying to define a record type across multiple lines, I recommend using this format:"
4078 , D.indent 4 $ D.vcat $
4079 [ "{ name : String"
4080 , ", age : Int"
4081 , ", height : Float"
4082 , "}"
4084 , D.reflow $
4085 "Notice that each line starts with some indentation. Usually two or four spaces. I\
4086 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
4087 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
4091addNoteForRecordTypeIndentError :: D.Doc -> D.Doc
4092addNoteForRecordTypeIndentError normalRecommendation =
4093 D.stack $
4094 normalRecommendation
4096 [ D.toSimpleNote
4097 "I may be confused by indentation. For example, if you are trying to define\
4098 \ a record type across multiple lines, I recommend using this format:"
4099 , D.indent 4 $ D.vcat $
4100 [ "{ name : String"
4101 , ", age : Int"
4102 , ", height : Float"
4103 , "}"
4105 , D.reflow $
4106 "Notice that each line starts with some indentation. Usually two or four spaces. I\
4107 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
4108 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
4112toTTupleReport :: Code.Source -> TTuple -> Row -> Col -> Report.Report
4113toTTupleReport source tuple startRow startCol =
4114 case tuple of
4115 TTupleOpen row col ->
4116 case Code.whatIsNext source row col of
4117 Code.Keyword keyword ->
4118 let
4119 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4120 region = toKeywordRegion row col keyword
4121 in
4122 Report.Report "RESERVED WORD" region [] $
4123 Code.toSnippet source surroundings (Just region)
4125 D.reflow $
4126 "I ran into a reserved word unexpectedly:"
4128 D.reflow $
4129 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name, but \
4130 \ it is a reserved word. Try using a different name!"
4133 _ ->
4134 let
4135 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4136 region = toRegion row col
4137 in
4138 Report.Report "UNFINISHED PARENTHESES" region [] $
4139 Code.toSnippet source surroundings (Just region)
4141 D.reflow $
4142 "I just saw an open parenthesis, so I was expecting to see a type next."
4144 D.fillSep $
4145 ["Something","like",D.dullyellow "(Maybe Int)","or"
4146 ,D.dullyellow "(List Person)" <> "."
4147 ,"Anything","where","you","are","putting","parentheses","around","normal","types."
4151 TTupleEnd row col ->
4152 let
4153 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4154 region = toRegion row col
4155 in
4156 Report.Report "UNFINISHED PARENTHESES" region [] $
4157 Code.toSnippet source surroundings (Just region)
4159 D.reflow $
4160 "I was expecting to see a closing parentheses next, but I got stuck here:"
4162 D.stack
4163 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
4164 , D.toSimpleNote $
4165 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
4166 \ unexpectedly. So there may be some earlier syntax trouble (like extra parenthesis\
4167 \ or missing brackets) that is confusing me."
4171 TTupleType tipe row col ->
4172 toTypeReport source tipe row col
4174 TTupleSpace space row col ->
4175 toSpaceReport source space row col
4177 TTupleIndentType1 row col ->
4178 let
4179 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4180 region = toRegion row col
4181 in
4182 Report.Report "UNFINISHED PARENTHESES" region [] $
4183 Code.toSnippet source surroundings (Just region)
4185 D.reflow $
4186 "I just saw an open parenthesis, so I was expecting to see a type next."
4188 D.stack
4189 [ D.fillSep $
4190 ["Something","like",D.dullyellow "(Maybe Int)","or"
4191 ,D.dullyellow "(List Person)" <> "."
4192 ,"Anything","where","you","are","putting","parentheses","around","normal","types."
4194 , D.toSimpleNote $
4195 "I can get confused by indentation in cases like this, so\
4196 \ maybe you have a type but it is not indented enough?"
4200 TTupleIndentTypeN row col ->
4201 let
4202 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4203 region = toRegion row col
4204 in
4205 Report.Report "UNFINISHED TUPLE TYPE" region [] $
4206 Code.toSnippet source surroundings (Just region)
4208 D.reflow $
4209 "I think I am in the middle of parsing a tuple type. I just saw a comma, so I was expecting to see a type next."
4211 D.stack
4212 [ D.fillSep $
4213 ["A","tuple","type","looks","like",D.dullyellow "(Float,Float)","or"
4214 ,D.dullyellow "(String,Int)" <> ","
4215 ,"so","I","think","there","is","a","type","missing","here?"
4217 , D.toSimpleNote $
4218 "I can get confused by indentation in cases like this, so\
4219 \ maybe you have an expression but it is not indented enough?"
4223 TTupleIndentEnd row col ->
4224 let
4225 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4226 region = toRegion row col
4227 in
4228 Report.Report "UNFINISHED PARENTHESES" region [] $
4229 Code.toSnippet source surroundings (Just region)
4231 D.reflow $
4232 "I was expecting to see a closing parenthesis next:"
4234 D.stack
4235 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
4236 , D.toSimpleNote $
4237 "I can get confused by indentation in cases like this, so\
4238 \ maybe you have a closing parenthesis but it is not indented enough?"