on 6c98f99 help sign in
4301 lines 150 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
162data Port
163 = PortSpace Space Row Col
164 | PortName Row Col
165 | PortColon Row Col
166 | PortType Type Row Col
167 | PortIndentName Row Col
168 | PortIndentColon Row Col
169 | PortIndentType Row Col
173-- TYPE DECLARATIONS
176data DeclType
177 = DT_Space Space Row Col
178 | DT_Name Row Col
179 | DT_Alias TypeAlias Row Col
180 | DT_Union CustomType Row Col
181 --
182 | DT_IndentName Row Col
185data TypeAlias
186 = AliasSpace Space Row Col
187 | AliasName Row Col
188 | AliasEquals Row Col
189 | AliasBody Type Row Col
190 --
191 | AliasIndentEquals Row Col
192 | AliasIndentBody Row Col
195data CustomType
196 = CT_Space Space Row Col
197 | CT_Name Row Col
198 | CT_Equals Row Col
199 | CT_Bar Row Col
200 | CT_Variant Row Col
201 | CT_VariantArg Type Row Col
202 --
203 | CT_IndentEquals Row Col
204 | CT_IndentBar Row Col
205 | CT_IndentAfterBar Row Col
206 | CT_IndentAfterEquals Row Col
210-- EXPRESSIONS
213data Expr
214 = Let Let Row Col
215 | Case Case Row Col
216 | If If Row Col
217 | List List Row Col
218 | Record Record Row Col
219 | Tuple Tuple Row Col
220 | Func Func Row Col
221 --
222 | Dot Row Col
223 | Access Row Col
224 | OperatorRight Name.Name Row Col
225 | OperatorReserved BadOperator Row Col
226 --
227 | Start Row Col
228 | Char Char Row Col
229 | String String Row Col
230 | Number Number Row Col
231 | Space Space Row Col
232 | EndlessShader Row Col
233 | ShaderProblem [Char.Char] Row Col
234 | IndentOperatorRight Name.Name Row Col
235 | IndentMoreExpr Row Col
238data Record
239 = RecordOpen Row Col
240 | RecordEnd Row Col
241 | RecordField Row Col
242 | RecordEquals Row Col
243 | RecordExpr Expr Row Col
244 | RecordSpace Space Row Col
245 --
246 | RecordIndentOpen Row Col
247 | RecordIndentEnd Row Col
248 | RecordIndentField Row Col
249 | RecordIndentEquals Row Col
250 | RecordIndentExpr Row Col
253data Tuple
254 = TupleExpr Expr Row Col
255 | TupleSpace Space Row Col
256 | TupleEnd Row Col
257 | TupleOperatorClose Row Col
258 | TupleOperatorReserved BadOperator Row Col
259 --
260 | TupleIndentExpr1 Row Col
261 | TupleIndentExprN Row Col
262 | TupleIndentEnd Row Col
265data List
266 = ListSpace Space Row Col
267 | ListOpen Row Col
268 | ListExpr Expr Row Col
269 | ListEnd Row Col
270 --
271 | ListIndentOpen Row Col
272 | ListIndentEnd Row Col
273 | ListIndentExpr Row Col
276data Func
277 = FuncSpace Space Row Col
278 | FuncArg Pattern Row Col
279 | FuncBody Expr Row Col
280 | FuncArrow Row Col
281 --
282 | FuncIndentArg Row Col
283 | FuncIndentArrow Row Col
284 | FuncIndentBody Row Col
287data Case
288 = CaseSpace Space Row Col
289 | CaseOf Row Col
290 | CasePattern Pattern Row Col
291 | CaseArrow Row Col
292 | CaseExpr Expr Row Col
293 | CaseBranch Expr Row Col
294 --
295 | CaseIndentOf Row Col
296 | CaseIndentExpr Row Col
297 | CaseIndentPattern Row Col
298 | CaseIndentArrow Row Col
299 | CaseIndentBranch Row Col
300 | CasePatternAlignment Word16 Row Col
303data If
304 = IfSpace Space Row Col
305 | IfThen Row Col
306 | IfElse Row Col
307 | IfElseBranchStart Row Col
308 --
309 | IfCondition Expr Row Col
310 | IfThenBranch Expr Row Col
311 | IfElseBranch Expr Row Col
312 --
313 | IfIndentCondition Row Col
314 | IfIndentThen Row Col
315 | IfIndentThenBranch Row Col
316 | IfIndentElseBranch Row Col
317 | IfIndentElse Row Col
320data Let
321 = LetSpace Space Row Col
322 | LetIn Row Col
323 | LetDefAlignment Word16 Row Col
324 | LetDefName Row Col
325 | LetDef Name.Name Def Row Col
326 | LetDestruct Destruct Row Col
327 | LetBody Expr Row Col
328 | LetIndentDef Row Col
329 | LetIndentIn Row Col
330 | LetIndentBody Row Col
333data Def
334 = DefSpace Space Row Col
335 | DefType Type Row Col
336 | DefNameRepeat Name.Name Row Col
337 | DefNameMatch Name.Name Name.Name Row Col
338 | DefArg Pattern Row Col
339 | DefEquals Row Col
340 | DefBody Expr Row Col
341 | DefIndentEquals Row Col
342 | DefIndentType Row Col
343 | DefIndentBody Row Col
344 | DefAlignment Word16 Row Col
347data Destruct
348 = DestructSpace Space Row Col
349 | DestructPattern Pattern Row Col
350 | DestructEquals Row Col
351 | DestructBody Expr Row Col
352 | DestructIndentEquals Row Col
353 | DestructIndentBody Row Col
357-- PATTERNS
360data Pattern
361 = PRecord PRecord Row Col
362 | PTuple PTuple Row Col
363 | PList PList Row Col
364 --
365 | PStart Row Col
366 | PChar Char Row Col
367 | PString String Row Col
368 | PNumber Number Row Col
369 | PFloat Word16 Row Col
370 | PAlias Row Col
371 | PWildcardNotVar Name.Name Int Row Col
372 | PSpace Space Row Col
373 --
374 | PIndentStart Row Col
375 | PIndentAlias Row Col
378data PRecord
379 = PRecordOpen Row Col
380 | PRecordEnd Row Col
381 | PRecordField Row Col
382 | PRecordSpace Space Row Col
383 --
384 | PRecordIndentOpen Row Col
385 | PRecordIndentEnd Row Col
386 | PRecordIndentField Row Col
389data PTuple
390 = PTupleOpen Row Col
391 | PTupleEnd Row Col
392 | PTupleExpr Pattern Row Col
393 | PTupleSpace Space Row Col
394 --
395 | PTupleIndentEnd Row Col
396 | PTupleIndentExpr1 Row Col
397 | PTupleIndentExprN Row Col
400data PList
401 = PListOpen Row Col
402 | PListEnd Row Col
403 | PListExpr Pattern Row Col
404 | PListSpace Space Row Col
405 --
406 | PListIndentOpen Row Col
407 | PListIndentEnd Row Col
408 | PListIndentExpr Row Col
412-- TYPES
415data Type
416 = TRecord TRecord Row Col
417 | TTuple TTuple Row Col
418 | TArrow Row Col
419 --
420 | TStart Row Col
421 | TSpace Space Row Col
422 --
423 | TIndentStart Row Col
426data TRecord
427 = TRecordOpen Row Col
428 | TRecordEnd Row Col
429 --
430 | TRecordField Row Col
431 | TRecordColon Row Col
432 | TRecordType Type Row Col
433 --
434 | TRecordSpace Space Row Col
435 --
436 | TRecordIndentOpen Row Col
437 | TRecordIndentField Row Col
438 | TRecordIndentColon Row Col
439 | TRecordIndentType Row Col
440 | TRecordIndentEnd Row Col
443data TTuple
444 = TTupleOpen Row Col
445 | TTupleEnd Row Col
446 | TTupleType Type Row Col
447 | TTupleSpace Space Row Col
448 --
449 | TTupleIndentType1 Row Col
450 | TTupleIndentTypeN Row Col
451 | TTupleIndentEnd Row Col
455-- LITERALS
458data Char
459 = CharEndless
460 | CharEscape Escape
461 | CharNotString Word16
464data String
465 = StringEndless_Single
466 | StringEndless_Multi
467 | StringEscape Escape
470data Escape
471 = EscapeUnknown
472 | BadUnicodeFormat Word16
473 | BadUnicodeCode Word16
474 | BadUnicodeLength Word16 Int Int
477data Number
478 = NumberEnd
479 | NumberDot Int
480 | NumberHexDigit
481 | NumberNoLeadingZero
485-- MISC
488data Space
489 = HasTab
490 | EndlessMultiComment
494-- TO REPORT
497toReport :: Code.Source -> Error -> Report.Report
498toReport source err =
499 case err of
500 ModuleNameUnspecified name ->
501 let
502 region = toRegion 1 1
503 in
504 Report.Report "MODULE NAME MISSING" region [] $
505 D.stack
506 [ D.reflow $
507 "I need the module name to be declared at the top of this file, like this:"
508 , D.indent 4 $ D.fillSep $
509 [ D.cyan "module", D.fromName name, D.cyan "exposing", "(..)" ]
510 , D.reflow $
511 "Try adding that as the first line of your file!"
512 , D.toSimpleNote $
513 "It is best to replace (..) with an explicit list of types and\
514 \ functions you want to expose. When you know a value is only used\
515 \ within this module, you can refactor without worrying about uses\
516 \ elsewhere. Limiting exposed values can also speed up compilation\
517 \ because I can skip a bunch of work if I see that the exposed API\
518 \ has not changed."
519 ]
521 ModuleNameMismatch expectedName (A.At region actualName) ->
522 Report.Report "MODULE NAME MISMATCH" region [ModuleName.toChars expectedName] $
523 Code.toSnippet source region Nothing
524 (
525 "It looks like this module name is out of sync:"
526 ,
527 D.stack
528 [ D.reflow $
529 "I need it to match the file path, so I was expecting it to see `"
530 ++ ModuleName.toChars expectedName
531 ++ "` here. Make the following change, and you should be all set!"
532 , D.indent 4 $
533 D.dullyellow (D.fromName actualName) <> " -> " <> D.green (D.fromName expectedName)
534 , D.toSimpleNote $
535 "I require that module names correspond to file paths. This makes it much\
536 \ easier to explore unfamiliar codebases! So if you want to keep the current\
537 \ module name, try renaming the file instead."
538 ]
539 )
541 UnexpectedPort region ->
542 Report.Report "UNEXPECTED PORTS" region [] $
543 Code.toSnippet source region Nothing
544 (
545 D.reflow $
546 "You are declaring ports in a normal module."
547 ,
548 D.stack
549 [ D.fillSep
550 ["Switch","this","to","say",D.cyan "port module","instead,"
551 ,"marking","that","this","module","contains","port","declarations."
552 ]
553 , D.link "Note"
554 "Ports are not a traditional FFI for calling JS functions directly. They need a different mindset! Read"
555 "ports"
556 "to learn the syntax and how to use it effectively."
557 ]
558 )
560 NoPorts region ->
561 Report.Report "NO PORTS" region [] $
562 Code.toSnippet source region Nothing
563 (
564 D.reflow $
565 "This module does not declare any ports, but it says it will:"
566 ,
567 D.fillSep
568 ["Switch","this","to",D.cyan "module"
569 ,"and","you","should","be","all","set!"
570 ]
571 )
573 ParseError modul ->
574 toParseErrorReport source modul
577toParseErrorReport :: Code.Source -> Module -> Report.Report
578toParseErrorReport source modul =
579 case modul of
580 ModuleSpace space row col ->
581 toSpaceReport source space row col
583 ModuleEndOfFile row col ->
584 case Code.whatIsNext source row col of
585 Code.Keyword keyword ->
586 let
587 region = toKeywordRegion row col keyword
588 in
589 Report.Report "RESERVED WORD" region [] $
590 Code.toSnippet source region Nothing
591 (
592 D.reflow $
593 "I got stuck on this reserved word:"
594 ,
595 D.reflow $
596 "The name `" ++ keyword ++ "` is reserved, so try using a different name?"
597 )
599 Code.Operator op ->
600 let
601 region = toKeywordRegion row col op
602 in
603 Report.Report "UNEXPECTED SYMBOL" region [] $
604 Code.toSnippet source region Nothing
605 (
606 D.reflow $
607 "I ran into an unexpected symbol:"
608 ,
609 D.reflow $
610 "I was not expecting to see a " ++ op ++ " here. Try deleting it? Maybe\
611 \ I can give a better hint from there?"
612 )
614 Code.Close term bracket ->
615 let
616 region = toRegion row col
617 in
618 Report.Report ("UNEXPECTED " ++ map Char.toUpper term) region [] $
619 Code.toSnippet source region Nothing
620 (
621 D.reflow $
622 "I ran into an unexpected " ++ term ++ ":"
623 ,
624 D.reflow $
625 "This " ++ bracket : " does not match up with an earlier open " ++ term ++ ". Try deleting it?"
626 )
628 Code.Other ->
629 let
630 region = toRegion row col
631 in
632 Report.Report "SYNTAX PROBLEM" region [] $
633 Code.toSnippet source region Nothing
634 (
635 D.reflow $
636 "I got stuck here:"
637 ,
638 D.reflow $
639 "Whatever I am running into is confusing me a lot! Normally I can give fairly\
640 \ specific hints, but something is really tripping me up this time."
641 )
643 ModuleProblem row col ->
644 let
645 region = toRegion row col
646 in
647 Report.Report "UNFINISHED MODULE DECLARATION" region [] $
648 Code.toSnippet source region Nothing
649 (
650 D.reflow $
651 "I am parsing an `module` declaration, but I got stuck here:"
652 ,
653 D.stack
654 [ D.reflow $
655 "Here are some examples of valid `module` declarations:"
656 , D.indent 4 $ D.vcat $
657 [ D.fillSep [D.cyan "module","Main",D.cyan "exposing","(..)"]
658 , D.fillSep [D.cyan "module","Dict",D.cyan "exposing","(Dict, empty, get)"]
659 ]
660 , D.reflow $
661 "I generally recommend using an explicit exposing list. I can skip compiling a bunch\
662 \ of files when the public interface of a module stays the same, so exposing fewer\
663 \ values can help improve compile times!"
664 ]
665 )
667 ModuleName row col ->
668 let
669 region = toRegion row col
670 in
671 Report.Report "EXPECTING MODULE NAME" region [] $
672 Code.toSnippet source region Nothing
673 (
674 D.reflow $
675 "I was parsing an `module` declaration until I got stuck here:"
676 ,
677 D.stack
678 [ D.reflow $
679 "I was expecting to see the module name next, like in these examples:"
680 , D.indent 4 $ D.vcat $
681 [ D.fillSep [D.cyan "module","Dict",D.cyan "exposing","(..)"]
682 , D.fillSep [D.cyan "module","Maybe",D.cyan "exposing","(..)"]
683 , D.fillSep [D.cyan "module","Html.Attributes",D.cyan "exposing","(..)"]
684 , D.fillSep [D.cyan "module","Json.Decode",D.cyan "exposing","(..)"]
685 ]
686 , D.reflow $
687 "Notice that the module names all start with capital letters. That is required!"
688 ]
689 )
691 ModuleExposing exposing row col ->
692 error "TODO ModuleExposing" exposing row col
694 PortModuleProblem row col ->
695 let
696 region = toRegion row col
697 in
698 Report.Report "UNFINISHED PORT MODULE DECLARATION" region [] $
699 Code.toSnippet source region Nothing
700 (
701 D.reflow $
702 "I am parsing an `port module` declaration, but I got stuck here:"
703 ,
704 D.stack
705 [ D.reflow $
706 "Here are some examples of valid `port module` declarations:"
707 , D.indent 4 $ D.vcat $
708 [ D.fillSep [D.cyan "port",D.cyan "module","WebSockets",D.cyan "exposing","(send, listen, keepAlive)"]
709 , D.fillSep [D.cyan "port",D.cyan "module","Maps",D.cyan "exposing","(Location, goto)"]
710 ]
711 , D.link "Note" "Read" "ports" "for more help."
712 ]
713 )
715 PortModuleName row col ->
716 let
717 region = toRegion row col
718 in
719 Report.Report "EXPECTING MODULE NAME" region [] $
720 Code.toSnippet source region Nothing
721 (
722 D.reflow $
723 "I was parsing an `module` declaration until I got stuck here:"
724 ,
725 D.stack
726 [ D.reflow $
727 "I was expecting to see the module name next, like in these examples:"
728 , D.indent 4 $ D.vcat $
729 [ D.fillSep [D.cyan "port",D.cyan "module","WebSockets",D.cyan "exposing","(send, listen, keepAlive)"]
730 , D.fillSep [D.cyan "port",D.cyan "module","Maps",D.cyan "exposing","(Location, goto)"]
731 ]
732 , D.reflow $
733 "Notice that the module names start with capital letters. That is required!"
734 ]
735 )
737 PortModuleExposing exposing row col ->
738 error "TODO PortModuleExposing" exposing row col
740 Effect row col ->
741 let
742 region = toRegion row col
743 in
744 Report.Report "BAD MODULE DECLARATION" region [] $
745 Code.toSnippet source region Nothing
746 (
747 D.reflow $
748 "I cannot parse this module declaration:"
749 ,
750 D.reflow $
751 "This type of module is reserved for the @elm organization. It is used to\
752 \ define certain effects, avoiding building them into the compiler."
753 )
755 FreshLine row col ->
756 let
757 region = toRegion row col
759 toBadFirstLineReport keyword =
760 Report.Report "TOO MUCH INDENTATION" region [] $
761 Code.toSnippet source region Nothing
762 (
763 D.reflow $
764 "This `" ++ keyword ++ "` should not have any spaces before it:"
765 ,
766 D.reflow $
767 "Delete the spaces before `" ++ keyword ++ "` until there are none left!"
768 )
770 in
771 case Code.whatIsNext source row col of
772 Code.Keyword "module" -> toBadFirstLineReport "module"
773 Code.Keyword "import" -> toBadFirstLineReport "import"
774 Code.Keyword "type" -> toBadFirstLineReport "type"
775 Code.Keyword "port" -> toBadFirstLineReport "port"
776 _ ->
777 Report.Report "SYNTAX PROBLEM" region [] $
778 Code.toSnippet source region Nothing
779 (
780 D.reflow $
781 "I got stuck here:"
782 ,
783 D.stack
784 [ D.reflow $
785 "I am not sure what is going on, but I recommend starting an Elm\
786 \ file with the following lines:"
787 , D.vcat
788 [ D.fillSep [D.cyan "import","Html"]
789 , ""
790 , D.fillSep [D.green "main","="]
791 , D.indent 2 $ D.fillSep [D.cyan "Html" <> ".text",D.dullyellow "\"Hello!\""]
792 ]
793 , D.reflow $
794 "You should be able to copy those lines directly into your file. Check out\
795 \ some of the examples on https://elm-lang.org for more help getting started!"
796 , D.toSimpleNote $
797 "This can also happen when something is indented too much!"
798 ]
799 )
801 ImportStart row col ->
802 toImportReport source row col
804 ImportName row col ->
805 let
806 region = toRegion row col
807 in
808 Report.Report "EXPECTING IMPORT NAME" region [] $
809 Code.toSnippet source region Nothing
810 (
811 D.reflow $
812 "I was parsing an `import` until I got stuck here:"
813 ,
814 D.stack
815 [ D.reflow $
816 "I was expecting to see a module name next, like in these examples:"
817 , D.indent 4 $ D.vcat $
818 [ D.fillSep [D.cyan "import","Dict"]
819 , D.fillSep [D.cyan "import","Maybe"]
820 , D.fillSep [D.cyan "import","Html.Attributes"]
821 , D.fillSep [D.cyan "import","Json.Decode"]
822 ]
823 , D.reflow $
824 "Notice that the module names all start with capital letters. That is required!"
825 ]
826 )
828 ImportAs row col ->
829 toImportReport source row col
831 ImportAlias row col ->
832 let
833 region = toRegion row col
834 in
835 Report.Report "EXECTING IMPORT ALIAS" region [] $
836 Code.toSnippet source region Nothing
837 (
838 D.reflow $
839 "I was parsing an `import` until I got stuck here:"
840 ,
841 D.stack
842 [ D.reflow $
843 "I was expecting to see an alias next, like in these examples:"
844 , D.indent 4 $ D.vcat $
845 [ D.fillSep [D.cyan "import","Html.Attributes",D.cyan "as","Attr"]
846 , D.fillSep [D.cyan "import","WebGL.Texture",D.cyan "as","Texture"]
847 , D.fillSep [D.cyan "import","Json.Decode",D.cyan "as","D"]
848 ]
849 , D.reflow $
850 "Notice that the alias always starts with a capital letter. That is required!"
851 ]
852 )
854 ImportExposing row col ->
855 toImportReport source row col
857 ImportExposingList exposing row col ->
858 error "TODO ImportExposingList" exposing row col
860 ImportEnd row col ->
861 toImportReport source row col
863 ImportIndentName row col ->
864 toImportReport source row col
866 ImportIndentAlias row col ->
867 toImportReport source row col
869 ImportIndentExposingList row col ->
870 let
871 region = toRegion row col
872 in
873 Report.Report "UNFINISHED IMPORT" region [] $
874 Code.toSnippet source region Nothing
875 (
876 D.reflow $
877 "I was parsing an `import` until I got stuck here:"
878 ,
879 D.stack
880 [ D.reflow $
881 "I was expecting to see the list of exposed values next. For example, here\
882 \ are two ways to expose values from the `Html` module:"
883 , D.indent 4 $ D.vcat $
884 [ D.fillSep [D.cyan "import","Html",D.cyan "exposing","(..)"]
885 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
886 ]
887 , D.reflow $
888 "I generally recommend the second style. It is more explicit, making it\
889 \ much easier to figure out where values are coming from in large projects!"
890 ]
891 )
893 Infix row col ->
894 let
895 region = toRegion row col
896 in
897 Report.Report "BAD INFIX" region [] $
898 Code.toSnippet source region Nothing
899 (
900 D.reflow $
901 "Something went wrong in this infix operator declaration:"
902 ,
903 D.reflow $
904 "This feature is used by the @elm organization to define the\
905 \ languages built-in operators."
906 )
908 Declarations decl _ _ ->
909 toDeclarationsReport source decl
913-- IMPORTS
916toImportReport :: Code.Source -> Row -> Col -> Report.Report
917toImportReport source row col =
918 let
919 region = toRegion row col
920 in
921 Report.Report "UNFINISHED IMPORT" region [] $
922 Code.toSnippet source region Nothing
923 (
924 D.reflow $
925 "I am partway through parsing an import, but I got stuck here:"
926 ,
927 D.stack
928 [ D.reflow $
929 "Here are some examples of valid `import` declarations:"
930 , D.indent 4 $ D.vcat $
931 [ D.fillSep [D.cyan "import","Html"]
932 , D.fillSep [D.cyan "import","Html",D.cyan "as","H"]
933 , D.fillSep [D.cyan "import","Html",D.cyan "as","H",D.cyan "exposing","(..)"]
934 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
935 ]
936 , D.reflow $
937 "You are probably trying to import a different module, but try to make it look like one of these examples!"
938 ]
939 )
943-- SPACES
946toSpaceReport :: Code.Source -> Space -> Row -> Col -> Report.Report
947toSpaceReport source space row col =
948 case space of
949 HasTab ->
950 let
951 region = toRegion row col
952 in
953 Report.Report "NO TABS" region [] $
954 Code.toSnippet source region Nothing
955 (
956 D.reflow $
957 "I ran into a tab, but tabs are not allowed in Elm files."
958 ,
959 D.reflow $
960 "Replace the tab with spaces."
961 )
963 EndlessMultiComment ->
964 let
965 region = toWiderRegion row col 2
966 in
967 Report.Report "ENDLESS COMMENT" region [] $
968 Code.toSnippet source region Nothing
969 (
970 D.reflow $
971 "I cannot find the end of this multi-line comment:"
972 ,
973 D.stack -- "{-"
974 [ D.reflow "Add a -} somewhere after this to end the comment."
975 , D.toSimpleHint
976 "Multi-line comments can be nested in Elm, so {- {- -} -} is a comment\
977 \ that happens to contain another comment. Like parentheses and curly braces,\
978 \ the start and end markers must always be balanced. Maybe that is the problem?"
979 ]
980 )
984-- DECLARATIONS
987toRegion :: Row -> Col -> A.Region
988toRegion row col =
989 let
990 pos = A.Position row col
991 in
992 A.Region pos pos
995toWiderRegion :: Row -> Col -> Word16 -> A.Region
996toWiderRegion row col extra =
997 A.Region
998 (A.Position row col)
999 (A.Position row (col + extra))
1002toKeywordRegion :: Row -> Col -> [Char.Char] -> A.Region
1003toKeywordRegion row col keyword =
1004 A.Region
1005 (A.Position row col)
1006 (A.Position row (col + fromIntegral (length keyword)))
1009toDeclarationsReport :: Code.Source -> Decl -> Report.Report
1010toDeclarationsReport source decl =
1011 case decl of
1012 DeclStart row col ->
1013 error "TODO DeclStart" row col
1015 DeclSpace space row col ->
1016 toSpaceReport source space row col
1018 Port port_ row col ->
1019 error "TODO Port" port_ row col
1021 DeclType declType row col ->
1022 toDeclTypeReport source declType row col
1024 DeclDef name declDef row col ->
1025 toDeclDefReport source name declDef row col
1027 DeclFreshLineStart row col ->
1028 error "TODO DeclFreshLineStart" row col
1030 DeclFreshLineAfterDocComment row col ->
1031 error "TODO DeclFreshLineAfterDocComment" row col
1035-- DECL TYPE
1038toDeclTypeReport :: Code.Source -> DeclType -> Row -> Col -> Report.Report
1039toDeclTypeReport source declType startRow startCol =
1040 case declType of
1041 DT_Space space row col ->
1042 toSpaceReport source space row col
1044 DT_Name row col ->
1045 let
1046 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1047 region = toRegion row col
1048 in
1049 Report.Report "EXPECTING TYPE NAME" region [] $
1050 Code.toSnippet source surroundings (Just region)
1052 D.reflow $
1053 "I think I am parsing a type declaration, but I got stuck here:"
1055 D.stack
1056 [ D.fillSep $
1057 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1058 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1060 , customTypeNote
1064 DT_Alias typeAlias row col ->
1065 toTypeAliasReport source typeAlias row col
1067 DT_Union customType row col ->
1068 toCustomTypeReport source customType row col
1070 DT_IndentName row col ->
1071 let
1072 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1073 region = toRegion row col
1074 in
1075 Report.Report "EXPECTING TYPE NAME" region [] $
1076 Code.toSnippet source surroundings (Just region)
1078 D.reflow $
1079 "I think I am parsing a type declaration, but I got stuck here:"
1081 D.stack
1082 [ D.fillSep $
1083 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1084 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1086 , customTypeNote
1091toTypeAliasReport :: Code.Source -> TypeAlias -> Row -> Col -> Report.Report
1092toTypeAliasReport source typeAlias startRow startCol =
1093 case typeAlias of
1094 AliasSpace space row col ->
1095 toSpaceReport source space row col
1097 AliasName row col ->
1098 let
1099 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1100 region = toRegion row col
1101 in
1102 Report.Report "EXPECTING TYPE ALIAS NAME" region [] $
1103 Code.toSnippet source surroundings (Just region)
1105 D.reflow $
1106 "I am partway through parsing a type alias, but I got stuck here:"
1108 D.stack
1109 [ D.fillSep $
1110 ["I","was","expecting","a","name","like",D.dullyellow "Person","or",D.dullyellow "Point"
1111 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1113 , typeAliasNote
1117 AliasEquals row col ->
1118 case Code.whatIsNext source row col of
1119 Code.Keyword keyword ->
1120 let
1121 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1122 region = toKeywordRegion row col keyword
1123 in
1124 Report.Report "RESERVED WORD" region [] $
1125 Code.toSnippet source surroundings (Just region)
1127 D.reflow $
1128 "I ran into a reserved word unexpectedly while parsing this type alias:"
1130 D.stack
1131 [ D.reflow $
1132 "It looks like you are trying use `" ++ keyword
1133 ++ "` as a type variable, but it is a reserved word. Try using a different name?"
1134 , typeAliasNote
1138 _ ->
1139 let
1140 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1141 region = toRegion row col
1142 in
1143 Report.Report "PROBLEM IN TYPE ALIAS" region [] $
1144 Code.toSnippet source surroundings (Just region)
1146 D.reflow $
1147 "I am partway through parsing a type alias, but I got stuck here:"
1149 D.stack
1150 [ D.reflow $
1151 "I was expecting to see a type variable or an an equals sign next."
1152 , typeAliasNote
1156 AliasBody tipe row col ->
1157 toTypeReport source tipe row col
1159 AliasIndentEquals row col ->
1160 let
1161 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1162 region = toRegion row col
1163 in
1164 Report.Report "UNFINISHED TYPE ALIAS" region [] $
1165 Code.toSnippet source surroundings (Just region)
1167 D.reflow $
1168 "I am partway through parsing a type alias, but I got stuck here:"
1170 D.stack
1171 [ D.reflow $
1172 "I was expecting to see a type variable or an an equals sign next."
1173 , typeAliasNote
1177 AliasIndentBody row col ->
1178 let
1179 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1180 region = toRegion row col
1181 in
1182 Report.Report "UNFINISHED TYPE ALIAS" region [] $
1183 Code.toSnippet source surroundings (Just region)
1185 D.reflow $
1186 "I am partway through parsing a type alias, but I got stuck here:"
1188 D.stack
1189 [ D.fillSep $
1190 ["I","was","expecting","to","see","a","type","next.","Something","as","simple"
1191 ,"as",D.dullyellow "Int","or",D.dullyellow "Float","would","work!"
1193 , typeAliasNote
1198typeAliasNote :: D.Doc
1199typeAliasNote =
1200 D.stack
1201 [ D.toSimpleNote $
1202 "Here is an example of a valid `type alias` for reference:"
1203 , D.vcat $
1204 [ D.indent 0 $ D.fillSep [D.cyan "type",D.cyan "alias",D.green "Person","="]
1205 , D.indent 2 $ D.vcat $
1206 ["{ name : String"
1207 ,", age : Int"
1208 ,", height : Float"
1209 ,"}"
1212 , D.reflow $
1213 "This would let us use `Person` as a shorthand for that record type. Using this\
1214 \ shorthand makes type annotations much easier to read, and makes changing code\
1215 \ easier if you decide later that there is more to a person than age and height!"
1219toCustomTypeReport :: Code.Source -> CustomType -> Row -> Col -> Report.Report
1220toCustomTypeReport source customType startRow startCol =
1221 case customType of
1222 CT_Space space row col ->
1223 toSpaceReport source space row col
1225 CT_Name row col ->
1226 let
1227 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1228 region = toRegion row col
1229 in
1230 Report.Report "EXPECTING TYPE NAME" region [] $
1231 Code.toSnippet source surroundings (Just region)
1233 D.reflow $
1234 "I think I am parsing a type declaration, but I got stuck here:"
1236 D.stack
1237 [ D.fillSep $
1238 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1239 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1241 , customTypeNote
1245 CT_Equals row col ->
1246 case Code.whatIsNext source row col of
1247 Code.Keyword keyword ->
1248 let
1249 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1250 region = toKeywordRegion row col keyword
1251 in
1252 Report.Report "RESERVED WORD" region [] $
1253 Code.toSnippet source surroundings (Just region)
1255 D.reflow $
1256 "I ran into a reserved word unexpectedly while parsing this custom type:"
1258 D.stack
1259 [ D.reflow $
1260 "It looks like you are trying use `" ++ keyword
1261 ++ "` as a type variable, but it is a reserved word. Try using a different name?"
1262 , customTypeNote
1266 _ ->
1267 let
1268 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1269 region = toRegion row col
1270 in
1271 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
1272 Code.toSnippet source surroundings (Just region)
1274 D.reflow $
1275 "I am partway through parsing a custom type, but I got stuck here:"
1277 D.stack
1278 [ D.reflow $
1279 "I was expecting to see a type variable or an an equals sign next."
1280 , customTypeNote
1284 CT_Bar row col ->
1285 let
1286 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1287 region = toRegion row col
1288 in
1289 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
1290 Code.toSnippet source surroundings (Just region)
1292 D.reflow $
1293 "I am partway through parsing a custom type, but I got stuck here:"
1295 D.stack
1296 [ D.reflow $
1297 "I was expecting to see a vertical bar like | next."
1298 , customTypeNote
1302 CT_Variant row col ->
1303 let
1304 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1305 region = toRegion row col
1306 in
1307 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
1308 Code.toSnippet source surroundings (Just region)
1310 D.reflow $
1311 "I am partway through parsing a custom type, but I got stuck here:"
1313 D.stack
1314 [ D.fillSep $
1315 ["I","was","expecting","to","see","a","variant","name","next."
1316 ,"Something","like",D.dullyellow "Success","or",D.dullyellow "Sandwich" <> "."
1317 ,"Any","name","that","starts","with","a","capital","letter","really!"
1319 , customTypeNote
1323 CT_VariantArg tipe row col ->
1324 toTypeReport source tipe row col
1326 CT_IndentEquals row col ->
1327 let
1328 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1329 region = toRegion row col
1330 in
1331 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1332 Code.toSnippet source surroundings (Just region)
1334 D.reflow $
1335 "I am partway through parsing a custom type, but I got stuck here:"
1337 D.stack
1338 [ D.reflow $
1339 "I was expecting to see a type variable or an an equals sign next."
1340 , customTypeNote
1344 CT_IndentBar row col ->
1345 let
1346 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1347 region = toRegion row col
1348 in
1349 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1350 Code.toSnippet source surroundings (Just region)
1352 D.reflow $
1353 "I am partway through parsing a custom type, but I got stuck here:"
1355 D.stack
1356 [ D.reflow $
1357 "I was expecting to see a vertical bar like | next."
1358 , customTypeNote
1362 CT_IndentAfterBar row col ->
1363 let
1364 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1365 region = toRegion row col
1366 in
1367 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1368 Code.toSnippet source surroundings (Just region)
1370 D.reflow $
1371 "I am partway through parsing a custom type, but I got stuck here:"
1373 D.stack
1374 [ D.reflow $
1375 "I just saw a vertical bar, so I was expecting to see another variant defined next."
1376 , customTypeNote
1380 CT_IndentAfterEquals row col ->
1381 let
1382 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1383 region = toRegion row col
1384 in
1385 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1386 Code.toSnippet source surroundings (Just region)
1388 D.reflow $
1389 "I am partway through parsing a custom type, but I got stuck here:"
1391 D.stack
1392 [ D.reflow $
1393 "I just saw an equals sign, so I was expecting to see the first variant defined next."
1394 , customTypeNote
1399customTypeNote :: D.Doc
1400customTypeNote =
1401 D.stack
1402 [ D.toSimpleNote $
1403 "Here is an example of a valid `type` declaration for reference:"
1404 , D.vcat $
1405 [ D.indent 0 $ D.fillSep [D.cyan "type",D.green "Status"]
1406 , D.indent 2 $ D.fillSep ["=","Failure"]
1407 , D.indent 2 $ D.fillSep ["|","Waiting"]
1408 , D.indent 2 $ D.fillSep ["|","Success","String"]
1410 , D.reflow $
1411 "This defines a new `Status` type with three variants. This could be useful if\
1412 \ we are waiting for an HTTP request. Maybe we start with `Waiting` and then\
1413 \ switch to `Failure` or `Success \"message from server\"` depending on how\
1414 \ things go. Notice that the Success variant has some associated data, allowing\
1415 \ us to store a String if the request goes well!"
1420-- DECL DEF
1423toDeclDefReport :: Code.Source -> Name.Name -> DeclDef -> Row -> Col -> Report.Report
1424toDeclDefReport source name declDef startRow startCol =
1425 case declDef of
1426 DeclDefSpace space row col ->
1427 toSpaceReport source space row col
1429 DeclDefEquals row col ->
1430 case Code.whatIsNext source row col of
1431 Code.Keyword keyword ->
1432 let
1433 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1434 region = toKeywordRegion row col keyword
1435 in
1436 Report.Report "RESERVED WORD" region [] $
1437 Code.toSnippet source surroundings (Just region)
1439 D.reflow $
1440 "It looks like you are trying to use `" ++ keyword ++ "` as an argument:"
1442 D.reflow $
1443 "This is a reserved word! Try using some other name?"
1446 Code.Operator op ->
1447 let
1448 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1449 region = toKeywordRegion row col op
1450 in
1451 Report.Report "UNEXPECTED SYMBOL" region [] $
1452 Code.toSnippet source surroundings (Just region)
1454 D.reflow $
1455 "I was not expecting to see this symbol here:"
1457 D.stack
1458 [ D.reflow $
1459 "I am not sure what is going wrong exactly, so here is a valid\
1460 \ definition (with an optional type annotation) for reference:"
1461 , D.vcat
1462 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
1463 , D.fillSep [D.green "add","x","y","="]
1464 , D.fillSep [" ","x","+","y"]
1466 , D.reflow $
1467 "Try to use that format with your `" ++ Name.toChars name ++ "` definition!"
1471 _ ->
1472 let
1473 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1474 region = toRegion row col
1475 in
1476 Report.Report "PROBLEM IN DEFINITION" region [] $
1477 Code.toSnippet source surroundings (Just region)
1479 D.reflow $
1480 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
1482 D.stack
1483 [ D.reflow $
1484 "I am not sure what is going wrong exactly, so here is a valid\
1485 \ definition (with an optional type annotation) for reference:"
1486 , D.vcat
1487 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
1488 , D.fillSep [D.green "add","x","y","="]
1489 , D.fillSep [" ","x","+","y"]
1491 , D.reflow $
1492 "Try to use that format!"
1496 DeclDefType tipe row col ->
1497 toTypeReport source tipe row col
1499 DeclDefArg pattern row col ->
1500 toPatternReport source PArg pattern row col
1502 DeclDefBody expr row col ->
1503 toExprReport source (InDef name startRow startCol) expr row col
1505 DeclDefNameRepeat row col ->
1506 let
1507 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1508 region = toRegion row col
1509 in
1510 Report.Report "EXPECTING DEFINITION" region [] $
1511 Code.toSnippet source surroundings (Just region)
1513 D.reflow $
1514 "I just saw the type annotation for `" ++ Name.toChars name
1515 ++ "` so I was expecting to see its definition here:"
1517 D.stack
1518 [ D.reflow $
1519 "Type annotations always appear directly above the relevant\
1520 \ definition, without anything else (even doc comments) in between."
1521 , declDefNote
1525 DeclDefNameMatch defName row col ->
1526 let
1527 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1528 region = toRegion row col
1529 in
1530 Report.Report "NAME MISMATCH" region [] $
1531 Code.toSnippet source surroundings (Just region)
1533 D.reflow $
1534 "I just saw a type annotation for `" ++ Name.toChars name ++ "`, but it is followed by a definition for `" ++ Name.toChars defName ++ "`:"
1536 D.stack
1537 [ D.reflow $
1538 "These names do not match! Is there a typo?"
1539 , D.indent 4 $ D.fillSep $
1540 [D.dullyellow (D.fromName defName),"->",D.green (D.fromName name)]
1544 DeclDefIndentType row col ->
1545 let
1546 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1547 region = toRegion row col
1548 in
1549 Report.Report "UNFINISHED DEFINITION" region [] $
1550 Code.toSnippet source surroundings (Just region)
1552 D.reflow $
1553 "I got stuck while parsing the `" ++ Name.toChars name ++ "` type annotation:"
1555 D.stack
1556 [ D.reflow $
1557 "I just saw a colon, so I am expecting to see a type next."
1558 , declDefNote
1562 DeclDefIndentEquals row col ->
1563 let
1564 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1565 region = toRegion row col
1566 in
1567 Report.Report "UNFINISHED DEFINITION" region [] $
1568 Code.toSnippet source surroundings (Just region)
1570 D.reflow $
1571 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
1573 D.stack
1574 [ D.reflow $
1575 "I was expecting to see an argument or an equals sign next."
1576 , declDefNote
1580 DeclDefIndentBody row col ->
1581 let
1582 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1583 region = toRegion row col
1584 in
1585 Report.Report "UNFINISHED DEFINITION" region [] $
1586 Code.toSnippet source surroundings (Just region)
1588 D.reflow $
1589 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
1591 D.stack
1592 [ D.reflow $
1593 "I was expecting to see an expression next. What is it equal to?"
1594 , declDefNote
1599declDefNote :: D.Doc
1600declDefNote =
1601 D.stack
1602 [ D.reflow $
1603 "Here is a valid definition (with a type annotation) for reference:"
1604 , D.vcat
1605 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
1606 , D.fillSep [D.green "add","x","y","="]
1607 , D.fillSep [" ","x","+","y"]
1609 , D.reflow $
1610 "The top line (called a \"type annotation\") is optional. You can leave it off\
1611 \ if you want. As you get more comfortable with Elm and as your project grows,\
1612 \ it becomes more and more valuable to add them though! They work great as\
1613 \ compiler-verified documentation, and they often improve error messages!"
1618-- CONTEXT
1621data Context
1622 = InNode Node Row Col Context
1623 | InDef Name.Name Row Col
1626data Node
1627 = NRecord
1628 | NParens
1629 | NList
1630 | NFunc
1631 | NCond
1632 | NThen
1633 | NElse
1634 | NCase
1635 | NBranch
1636 deriving (Eq)
1639getDefName :: Context -> Name.Name
1640getDefName context =
1641 case context of
1642 InDef name _ _ -> name
1643 InNode _ _ _ c -> getDefName c
1646isWithin :: Node -> Context -> Bool
1647isWithin desiredNode context =
1648 case context of
1649 InDef _ _ _ -> False
1650 InNode actualNode _ _ _ -> desiredNode == actualNode
1654-- EXPR REPORTS
1657toExprReport :: Code.Source -> Context -> Expr -> Row -> Col -> Report.Report
1658toExprReport source context expr startRow startCol =
1659 case expr of
1660 Let let_ row col ->
1661 toLetReport source context let_ row col
1663 Case case_ row col ->
1664 toCaseReport source context case_ row col
1666 If if_ row col ->
1667 toIfReport source context if_ row col
1669 List list row col ->
1670 toListReport source context list row col
1672 Record record row col ->
1673 toRecordReport source context record row col
1675 Tuple tuple row col ->
1676 toTupleReport source context tuple row col
1678 Func func row col ->
1679 toFuncReport source context func row col
1681 Dot row col ->
1682 let region = toRegion row col in
1683 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
1684 Code.toSnippet source region Nothing
1686 D.reflow $
1687 "I was expecting to see a record accessor here:"
1689 D.fillSep
1690 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
1691 ,"that","accesses","a","value","from","a","record."
1695 Access row col ->
1696 let region = toRegion row col in
1697 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
1698 Code.toSnippet source region Nothing
1700 D.reflow $
1701 "I am trying to parse a record accessor here:"
1703 D.stack
1705 D.fillSep
1706 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
1707 ,"that","accesses","a","value","from","a","record."
1710 D.toSimpleNote $
1711 "Record field names must start with a lower case letter!"
1715 OperatorRight op row col ->
1716 let region = toRegion row col in
1717 Report.Report "MISSING EXPRESSION" region [] $
1718 Code.toSnippet source region Nothing
1720 D.reflow $
1721 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
1723 D.stack
1724 [ D.fillSep $
1725 ["You","can","just","put","anything","for","now,","like"
1726 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1727 ,"Once","there","is","something","there,","I","can","probably"
1728 ,"give","a","more","specific","hint!"
1730 , D.toSimpleNote $
1731 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
1732 \ Or if I run into operators in unexpected spots. Point is, there are a\
1733 \ couple ways I can get confused and give sort of weird advice!"
1737 OperatorReserved operator row col ->
1738 toOperatorReport source context operator row col
1740 Start row col ->
1741 let
1742 (contextRow, contextCol, aThing) =
1743 case context of
1744 InDef name r c -> (r, c, "the `" ++ Name.toChars name ++ "` definition")
1745 InNode NRecord r c _ -> (r, c, "a record")
1746 InNode NParens r c _ -> (r, c, "some parentheses")
1747 InNode NList r c _ -> (r, c, "a list")
1748 InNode NFunc r c _ -> (r, c, "an anonymous function")
1749 InNode NCond r c _ -> (r, c, "an `if` expression")
1750 InNode NThen r c _ -> (r, c, "an `if` expression")
1751 InNode NElse r c _ -> (r, c, "an `if` expression")
1752 InNode NCase r c _ -> (r, c, "a `case` expression")
1753 InNode NBranch r c _ -> (r, c, "a `case` expression")
1754 -- TODO check if this is actually the best way to get error messages here
1756 surroundings = A.Region (A.Position contextRow contextCol) (A.Position row col)
1757 region = toRegion row col
1758 in
1759 Report.Report "MISSING EXPRESSION" region [] $
1760 Code.toSnippet source surroundings (Just region)
1762 D.reflow $
1763 "I am partway through parsing " ++ aThing ++ ", but I got stuck here:"
1765 D.stack
1766 [ D.fillSep $
1767 ["I","was","expecting","to","see","an","expression","like"
1768 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1769 ,"Once","there","is","something","there,","I","can","probably"
1770 ,"give","a","more","specific","hint!"
1772 , D.toSimpleNote $
1773 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
1774 \ Or if I run into operators in unexpected spots. Point is, there are a\
1775 \ couple ways I can get confused and give sort of weird advice!"
1779 Char char row col ->
1780 toCharReport source char row col
1782 String string row col ->
1783 toStringReport source string row col
1785 Number number row col ->
1786 toNumberReport source number row col
1788 Space space row col ->
1789 toSpaceReport source space row col
1791 EndlessShader row col ->
1792 let
1793 region = toWiderRegion row col 6
1794 in
1795 Report.Report "ENDLESS SHADER" region [] $
1796 Code.toSnippet source region Nothing
1798 D.reflow "I cannot find the end of this shader:"
1800 D.reflow "Add a |] somewhere after this to end the shader."
1803 ShaderProblem problem row col ->
1804 let
1805 region = toRegion row col
1806 in
1807 Report.Report "SHADER PROBLEM" region [] $
1808 Code.toSnippet source region Nothing
1810 D.reflow $
1811 "I ran into a problem while parsing this GLSL block."
1813 D.stack
1814 [ D.reflow $
1815 "I use a 3rd party GLSL parser for now, and I did my best to extract their error message:"
1816 , D.indent 4 $ D.vcat $
1817 map D.fromChars (filter (/="") (lines problem))
1821 IndentOperatorRight op row col ->
1822 let
1823 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1824 region = toRegion row col
1825 in
1826 Report.Report "MISSING EXPRESSION" region [] $
1827 Code.toSnippet source surroundings (Just region)
1829 D.reflow $
1830 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
1832 D.stack
1834 D.fillSep $
1835 ["You","can","just","put","anything","for","now,","like"
1836 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1837 ,"Once","there","is","something","there,","I","can","probably"
1838 ,"give","a","more","specific","hint!"
1841 D.toSimpleNote $
1842 "I may be getting confused by your indentation? The easiest way to make sure\
1843 \ this is not an indentation problem is to put the expression on the right of\
1844 \ the " ++ Name.toChars op ++ " operator on the same line."
1848 IndentMoreExpr _ _ ->
1849 error "TODO IndentMoreExpr"
1853-- CHAR
1856toCharReport :: Code.Source -> Char -> Row -> Col -> Report.Report
1857toCharReport source char row col =
1858 case char of
1859 CharEndless ->
1860 let
1861 region = toRegion row col
1862 in
1863 Report.Report "MISSING SINGLE QUOTE" region [] $
1864 Code.toSnippet source region Nothing
1866 D.reflow $
1867 "I thought I was parsing a character, but I got to the end of\
1868 \ the line without seeing the closing single quote:"
1870 D.reflow $
1871 "Add a closing single quote here!"
1874 CharEscape escape ->
1875 toEscapeReport source escape row col
1877 CharNotString width ->
1878 let
1879 region = toWiderRegion row col width
1880 in
1881 Report.Report "NEEDS DOUBLE QUOTES" region [] $
1882 Code.toSnippet source region Nothing
1884 "The following string uses single quotes:"
1886 D.stack
1887 [ "Please switch to double quotes instead:"
1888 , D.indent 4 $
1889 D.dullyellow "'this'" <> " => " <> D.green "\"this\""
1890 , D.toSimpleNote $
1891 "Elm uses double quotes for strings like \"hello\", whereas it uses single\
1892 \ quotes for individual characters like 'a' and 'ø'. This distinction helps with\
1893 \ code like (String.any (\\c -> c == 'X') \"90210\") where you are inspecting\
1894 \ individual characters."
1900-- STRING
1903toStringReport :: Code.Source -> String -> Row -> Col -> Report.Report
1904toStringReport source string row col =
1905 case string of
1906 StringEndless_Single ->
1907 let
1908 region = toRegion row col
1909 in
1910 Report.Report "ENDLESS STRING" region [] $
1911 Code.toSnippet source region Nothing
1913 D.reflow $
1914 "I got to the end of the line without seeing the closing double quote:"
1916 D.stack
1917 [ D.fillSep $
1918 ["Strings","look","like",D.green "\"this\"","with","double"
1919 ,"quotes","on","each","end.","Is","the","closing","double"
1920 ,"quote","missing","in","your","code?"
1922 , D.link "Note" "Read" "TODO" "if you want a string that spans multiple lines."
1926 StringEndless_Multi ->
1927 let
1928 region = toWiderRegion row col 3
1929 in
1930 Report.Report "ENDLESS STRING" region [] $
1931 Code.toSnippet source region Nothing
1933 D.reflow $
1934 "I cannot find the end of this multi-line string:"
1936 D.stack
1937 [ D.reflow "Add a \"\"\" somewhere after this to end the string."
1938 , D.link "Hint" "Read" "TODO" "for more information on strings and multi-line strings."
1942 StringEscape escape ->
1943 toEscapeReport source escape row col
1947-- ESCAPES
1950toEscapeReport :: Code.Source -> Escape -> Row -> Col -> Report.Report
1951toEscapeReport source escape row col =
1952 case escape of
1953 EscapeUnknown ->
1954 let
1955 region = toWiderRegion row col 2
1956 in
1957 Report.Report "UNKNOWN ESCAPE" region [] $
1958 Code.toSnippet source region Nothing
1960 D.reflow $
1961 "Backslashes always start escaped characters, but I do not recognize this one:"
1963 D.stack
1964 [ D.reflow $
1965 "Valid escape characters include:"
1966 , D.dullyellow $ D.indent 4 $ D.vcat $
1967 [ "\\n"
1968 , "\\r"
1969 , "\\t"
1970 , "\\\""
1971 , "\\\'"
1972 , "\\\\"
1973 , "\\u{003D}"
1975 , D.reflow $
1976 "Do you want one of those instead? Maybe you need \\\\ to escape a backslash?"
1977 , D.toSimpleNote $
1978 "The last style lets encode ANY character by its Unicode code\
1979 \ point. That means \\u{0009} and \\t are the same. You can use\
1980 \ that style for anything not covered by the other six escapes!"
1984 BadUnicodeFormat width ->
1985 let
1986 region = toWiderRegion row col width
1987 in
1988 Report.Report "BAD UNICODE ESCAPE" region [] $
1989 Code.toSnippet source region Nothing
1991 D.reflow $
1992 "I ran into an invalid Unicode escape:"
1994 D.stack
1995 [ D.reflow $
1996 "Here are some examples of valid Unicode escapes:"
1997 , D.dullyellow $ D.indent 4 $ D.vcat $
1998 [ "\\u{0041}"
1999 , "\\u{03BB}"
2000 , "\\u{6728}"
2001 , "\\u{1F60A}"
2003 , D.reflow $
2004 "Notice that the code point is always surrounded by curly braces.\
2005 \ Maybe you are missing the opening or closing curly brace?"
2008 BadUnicodeCode width ->
2009 let
2010 region = toWiderRegion row col width
2011 in
2012 Report.Report "BAD UNICODE ESCAPE" region [] $
2013 Code.toSnippet source region Nothing
2015 D.reflow $
2016 "This is not a valid code point:"
2018 D.reflow $
2019 "The valid code points are between 0 and 10FFFF inclusive."
2022 BadUnicodeLength width numDigits badCode ->
2023 let
2024 region = toWiderRegion row col width
2025 in
2026 Report.Report "BAD UNICODE ESCAPE" region [] $
2027 Code.toSnippet source region Nothing $
2028 if numDigits < 4 then
2030 D.reflow $
2031 "Every code point needs at least four digits:"
2033 let
2034 goodCode = replicate (4 - numDigits) '0' ++ map Char.toUpper (showHex badCode "")
2035 suggestion = "\\u{" <> D.fromChars goodCode <> "}"
2036 in
2037 D.fillSep ["Try",D.green suggestion,"instead?"]
2040 else
2042 D.reflow $
2043 "This code point has too many digits:"
2045 D.fillSep $
2046 ["Valid","code","points","are","between"
2047 ,D.green "\\u{0000}","and",D.green "\\u{10FFFF}" <> ","
2048 ,"so","try","trimming","any","leading","zeros","until"
2049 ,"you","have","between","four","and","six","digits."
2055-- NUMBERS
2058toNumberReport :: Code.Source -> Number -> Row -> Col -> Report.Report
2059toNumberReport source number row col =
2060 let
2061 region = toRegion row col
2062 in
2063 case number of
2064 NumberEnd ->
2065 Report.Report "WEIRD NUMBER" region [] $
2066 Code.toSnippet source region Nothing
2068 D.reflow $
2069 "I thought I was reading a number, but I ran into some weird stuff here:"
2071 D.stack
2072 [ D.reflow $
2073 "I recognize numbers in the following formats:"
2074 , D.indent 4 $ D.vcat [ "42", "3.14", "6.022e23", "0x002B" ]
2075 , D.reflow $
2076 "So is there a way to write it like one of those?"
2080 NumberDot int ->
2081 Report.Report "WEIRD NUMBER" region [] $
2082 Code.toSnippet source region Nothing
2084 D.reflow $
2085 "Numbers cannot end with a dot like this:"
2087 D.fillSep
2088 ["Switching","to",D.green (D.fromChars (show int))
2089 ,"or",D.green (D.fromChars (show int ++ ".0"))
2090 ,"will","work","though!"
2094 NumberHexDigit ->
2095 Report.Report "WEIRD HEXIDECIMAL" region [] $
2096 Code.toSnippet source region Nothing
2098 D.reflow $
2099 "I thought I was reading a hexidecimal number until I got here:"
2101 D.stack
2102 [ D.reflow $
2103 "Valid hexidecimal digits include 0123456789abcdefABCDEF, so I can\
2104 \ only recognize things like this:"
2105 , D.indent 4 $ D.vcat [ "0x2B", "0x002B", "0x00ffb3" ]
2109 NumberNoLeadingZero ->
2110 Report.Report "LEADING ZEROS" region [] $
2111 Code.toSnippet source region Nothing
2113 D.reflow $
2114 "I do not accept numbers with leading zeros:"
2116 D.stack
2117 [ D.reflow $
2118 "Just delete the leading zeros and it should work!"
2119 , D.toSimpleNote $
2120 "Some languages let you to specify octal numbers by adding a leading zero.\
2121 \ So in C, writing 0111 is the same as writing 73. Some people are used to\
2122 \ that, but others probably want it to equal 111. Either path is going to\
2123 \ surprise people from certain backgrounds, so Elm tries to avoid this whole\
2124 \ situation."
2130-- OPERATORS
2133toOperatorReport :: Code.Source -> Context -> BadOperator -> Row -> Col -> Report.Report
2134toOperatorReport source context operator row col =
2135 case operator of
2136 BadDot ->
2137 let
2138 region = toRegion row col
2139 in
2140 Report.Report "UNEXPECTED SYMBOL" region [] $
2141 Code.toSnippet source region Nothing
2143 "I was not expecting this dot:"
2145 D.reflow $
2146 "Dots are for record access and decimal points, so\
2147 \ they cannot float around on their own. Maybe\
2148 \ there is some extra whitespace?"
2151 BadPipe ->
2152 let
2153 region = toRegion row col
2154 in
2155 Report.Report "UNEXPECTED SYMBOL" region [] $
2156 Code.toSnippet source region Nothing
2158 D.reflow $
2159 "I was not expecting this vertical bar:"
2161 D.reflow $
2162 "Vertical bars should only appear in custom type declarations. Maybe you want || instead?"
2165 BadArrow ->
2166 let
2167 region = toWiderRegion row col 2
2168 in
2169 Report.Report "UNEXPECTED ARROW" region [] $
2170 Code.toSnippet source region Nothing $
2171 if isWithin NBranch context then
2173 D.reflow $
2174 "I was not expecting to see an arrow here:"
2176 D.stack
2178 D.reflow $
2179 "I think I am parsing a `case` expression right now, so it makes sense to\
2180 \ see arrows around here. This one is confusing me though!"
2182 D.toSimpleHint $
2183 "I may be getting confused by the indentation. Every pattern in a `case` must be\
2184 \ exactly aligned (with exactly the same amount of indentation) so maybe this arrow\
2185 \ appears after the next `case` pattern (correctly!) but the pattern itself is\
2186 \ indented too far?"
2190 else
2192 D.reflow $
2193 "I was not expecting an arrow here:"
2195 D.reflow $
2196 "Arrows should only appear in `case` expressions and anonymous functions. Maybe\
2197 \ you want > or >= instead?"
2200 BadEquals ->
2201 let
2202 region = toRegion row col
2203 name = getDefName context
2204 in
2205 Report.Report "UNEXPECTED EQUALS" region [] $
2206 Code.toSnippet source region Nothing
2208 D.reflow $
2209 "I was not expecting to see this equals sign:"
2211 D.stack
2213 D.reflow "Maybe you want == instead? To check if two values are equal?"
2215 D.toSimpleNote $
2216 if isWithin NRecord context then
2217 "Records look like { x = 3, y = 4 } with the equals sign right\
2218 \ after the field name. So maybe you forgot a comma?"
2219 else
2220 "I may be getting confused by your indentation. Is this supposed to be part of\
2221 \ a definition AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
2222 \ the problem may be a bit before the equals sign. I need all definitions to\
2223 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
2224 \ this new definition is indented a bit too much."
2228 BadHasType ->
2229 let
2230 region = toRegion row col
2231 name = getDefName context
2232 in
2233 Report.Report "UNEXPECTED SYMBOL" region [] $
2234 Code.toSnippet source region Nothing $
2236 D.reflow $
2237 "I was not expecting to run into the \"has type\" symbol here:"
2239 D.stack
2241 D.fillSep
2242 ["Maybe","you","want",D.green "::","instead?"
2243 ,"To","put","something","on","the","front","of","a","list?"
2245 , D.toSimpleNote $
2246 "The single colon is reserved for type annotations and record types, but I think\
2247 \ I am parsing the definition of `" ++ Name.toChars name ++ "` right now."
2249 D.toSimpleNote $
2250 "I may be getting confused by your indentation. Is this supposed to be part of\
2251 \ a type annotation AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
2252 \ the problem may be a bit before the \"has type\" symbol. I need all definitions to\
2253 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
2254 \ this new definition is indented a bit too much."
2260-- CASE
2263toLetReport :: Code.Source -> Context -> Let -> Row -> Col -> Report.Report
2264toLetReport source context let_ startRow startCol =
2265 case let_ of
2266 LetSpace space row col ->
2267 toSpaceReport source space row col
2269 LetIn row col ->
2270 let
2271 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2272 region = toRegion row col
2273 in
2274 Report.Report "LET PROBLEM" region [] $
2275 Code.toSnippet source surroundings (Just region)
2277 D.reflow $
2278 "I was partway through parsing a `let` expression, but I got stuck here:"
2280 D.stack
2281 [ D.fillSep $
2282 ["Based","on","the","indentation,","I","was","expecting","to","see","the",D.cyan "in"
2283 ,"keyword","next.","Is","there","a","typo?"
2285 , D.toSimpleNote $
2286 "This can also happen if you are trying to define another value within the `let` but\
2287 \ it is not indented enough. Make sure each definition has exactly the same amount of\
2288 \ spaces before it. They should line up exactly!"
2292 LetDefAlignment _ row col ->
2293 let
2294 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2295 region = toRegion row col
2296 in
2297 Report.Report "LET PROBLEM" region [] $
2298 Code.toSnippet source surroundings (Just region)
2300 D.reflow $
2301 "I was partway through parsing a `let` expression, but I got stuck here:"
2303 D.stack
2304 [ D.fillSep $
2305 ["Based","on","the","indentation,","I","was","expecting","to","see","the",D.cyan "in"
2306 ,"keyword","next.","Is","there","a","typo?"
2308 , D.toSimpleNote $
2309 "This can also happen if you are trying to define another value within the `let` but\
2310 \ it is not indented enough. Make sure each definition has exactly the same amount of\
2311 \ spaces before it. The should line up exactly!"
2315 LetDefName row col ->
2316 case Code.whatIsNext source row col of
2317 Code.Keyword keyword ->
2318 let
2319 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2320 region = toKeywordRegion row col keyword
2321 in
2322 Report.Report "RESERVED WORD" region [] $
2323 Code.toSnippet source surroundings (Just region)
2325 D.reflow $
2326 "I was partway through parsing a `let` expression, but I got stuck here:"
2328 D.reflow $
2329 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name, but\
2330 \ it is a reserved word! Try using a different name instead."
2333 _ ->
2334 toUnfinishLetReport source row col startRow startCol $
2335 D.reflow $
2336 "I was expecting the name of a definition next."
2338 LetDef name def row col ->
2339 error "TODO LetDef" name def row col
2341 LetDestruct destruct row col ->
2342 error "TODO LetDestruct" destruct row col
2344 LetBody expr row col ->
2345 toExprReport source context expr row col
2347 LetIndentDef row col ->
2348 toUnfinishLetReport source row col startRow startCol $
2349 D.reflow $
2350 "I was expecting a value to be defined here."
2352 LetIndentIn row col ->
2353 toUnfinishLetReport source row col startRow startCol $
2354 D.fillSep $
2355 ["I","was","expecting","to","see","the",D.cyan "in","keyword","next."
2356 ,"Or","maybe","more","of","that","expression?"
2359 LetIndentBody row col ->
2360 toUnfinishLetReport source row col startRow startCol $
2361 D.reflow $
2362 "I was expecting an expression next. Tell me what should happen with the value you just defined!"
2365toUnfinishLetReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
2366toUnfinishLetReport source row col startRow startCol message =
2367 let
2368 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2369 region = toRegion row col
2370 in
2371 Report.Report "UNFINISHED LET" region [] $
2372 Code.toSnippet source surroundings (Just region)
2374 D.reflow $
2375 "I was partway through parsing a `let` expression, but I got stuck here:"
2377 D.stack
2378 [ message
2379 , D.toSimpleNote $
2380 "Here is an example with a valid `let` expression for reference:"
2381 , D.vcat $
2382 [ D.indent 0 $ D.fillSep [D.green "viewPerson","person","="]
2383 , D.indent 2 $ D.fillSep [D.cyan "let"]
2384 , D.indent 4 $ D.fillSep ["fullName","="]
2385 , D.indent 6 $ D.fillSep ["person.firstName","++",D.dullyellow "\" \"","++","person.lastName"]
2386 , D.indent 2 $ D.fillSep [D.cyan "in"]
2387 , D.indent 2 $ D.fillSep ["div","[]","[","text","fullName","]"]
2389 , D.reflow $
2390 "Here we defined a `viewPerson` function that turns a person into some HTML. We use\
2391 \ a `let` expression to define the `fullName` we want to show. Notice the indentation! The\
2392 \ `fullName` is indented more than the `let` keyword, and the actual value of `fullName` is\
2393 \ indented a bit more than that. That is important!"
2399-- CASE
2402toCaseReport :: Code.Source -> Context -> Case -> Row -> Col -> Report.Report
2403toCaseReport source context case_ startRow startCol =
2404 case case_ of
2405 CaseSpace space row col ->
2406 toSpaceReport source space row col
2408 CaseOf row col ->
2409 toUnfinishCaseReport source row col startRow startCol $
2410 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
2412 CasePattern pattern row col ->
2413 toPatternReport source PCase pattern row col
2415 CaseArrow row col ->
2416 case Code.whatIsNext source row col of
2417 Code.Keyword keyword ->
2418 let
2419 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2420 region = toKeywordRegion row col keyword
2421 in
2422 Report.Report "RESERVED WORD" region [] $
2423 Code.toSnippet source surroundings (Just region)
2425 D.reflow $
2426 "I am partway through parsing a `case` expression, but I got stuck here:"
2428 D.reflow $
2429 "It looks like you are trying to use `" ++ keyword ++ "` in one of your\
2430 \ patterns, but it is a reserved word. Try using a different name?"
2433 Code.Operator ":" ->
2434 let
2435 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2436 region = toRegion row col
2437 in
2438 Report.Report "UNEXPECTED OPERATOR" region [] $
2439 Code.toSnippet source surroundings (Just region)
2441 D.reflow $
2442 "I am partway through parsing a `case` expression, but I got stuck here:"
2444 D.fillSep $
2445 ["I","am","seeing",D.dullyellow ":","but","maybe","you","want",D.green "::","instead?"
2446 ,"For","pattern","matching","on","lists?"
2450 Code.Operator "=" ->
2451 let
2452 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2453 region = toRegion row col
2454 in
2455 Report.Report "UNEXPECTED OPERATOR" region [] $
2456 Code.toSnippet source surroundings (Just region)
2458 D.reflow $
2459 "I am partway through parsing a `case` expression, but I got stuck here:"
2461 D.fillSep $
2462 ["I","am","seeing",D.dullyellow "=","but","maybe","you","want",D.green "->","instead?"
2466 _ ->
2467 let
2468 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2469 region = toRegion row col
2470 in
2471 Report.Report "MISSING ARROW" region [] $
2472 Code.toSnippet source surroundings (Just region)
2474 D.reflow $
2475 "I am partway through parsing a `case` expression, but I got stuck here:"
2477 addNoteForCaseIndentError $
2478 D.reflow $
2479 "I was expecting to see an arrow next."
2482 CaseExpr expr row col ->
2483 toExprReport source (InNode NCase startRow startCol context) expr row col
2485 CaseBranch expr row col ->
2486 toExprReport source (InNode NBranch startRow startCol context) expr row col
2488 CaseIndentOf row col ->
2489 toUnfinishCaseReport source row col startRow startCol $
2490 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
2492 CaseIndentExpr row col ->
2493 toUnfinishCaseReport source row col startRow startCol $
2494 D.reflow "I was expecting to see a expression next."
2496 CaseIndentPattern row col ->
2497 toUnfinishCaseReport source row col startRow startCol $
2498 D.reflow "I was expecting to see a pattern next."
2500 CaseIndentArrow row col ->
2501 toUnfinishCaseReport source row col startRow startCol $
2502 D.fillSep
2503 ["I","just","saw","a","pattern,","so","I","was","expecting"
2504 ,"to","see","a",D.dullyellow "->","next."
2507 CaseIndentBranch row col ->
2508 toUnfinishCaseReport source row col startRow startCol $
2509 D.reflow $
2510 "I was expecting to see an expression next. What should I do when\
2511 \ I run into this particular pattern?"
2513 CasePatternAlignment indent row col ->
2514 toUnfinishCaseReport source row col startRow startCol $
2515 D.reflow $
2516 "I suspect this is a pattern that is not indented far enough? (" ++ show indent ++ " spaces)"
2519toUnfinishCaseReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
2520toUnfinishCaseReport source row col startRow startCol message =
2521 let
2522 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2523 region = toRegion row col
2524 in
2525 Report.Report "UNFINISHED CASE" region [] $
2526 Code.toSnippet source surroundings (Just region)
2528 D.reflow $
2529 "I was partway through parsing a `case` expression, but I got stuck here:"
2531 D.stack
2532 [ message
2533 , D.toSimpleNote $
2534 "Here is an example of a valid `case` expression for reference."
2535 , D.vcat $
2536 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
2537 , D.indent 6 $ D.fillSep [D.green "Just","width","->"]
2538 , D.indent 8 $ D.fillSep ["width","+",D.dullyellow "200"]
2539 , ""
2540 , D.indent 6 $ D.fillSep [D.green "Nothing","->"]
2541 , D.indent 8 $ D.fillSep [D.dullyellow "400"]
2543 , D.reflow $
2544 "Notice the indentation. Each pattern is aligned, and each branch is indented\
2545 \ a bit more than the corresponding pattern. That is important!"
2550addNoteForCaseIndentError :: D.Doc -> D.Doc
2551addNoteForCaseIndentError message =
2552 D.stack $
2553 message
2555 [ D.toSimpleNote $
2556 "Sometimes I get confused by indentation, so try to make your `case` look\
2557 \ something like this:"
2558 , D.vcat $
2559 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
2560 , D.indent 6 $ D.fillSep [D.green "Just","width","->"]
2561 , D.indent 8 $ D.fillSep ["width","+",D.dullyellow "200"]
2562 , ""
2563 , D.indent 6 $ D.fillSep [D.green "Nothing","->"]
2564 , D.indent 8 $ D.fillSep [D.dullyellow "400"]
2566 , D.reflow $
2567 "Notice the indentation! Each pattern is aligned, and each branch is indented\
2568 \ a bit more than the corresponding pattern. That is important!"
2573-- IF
2576toIfReport :: Code.Source -> Context -> If -> Row -> Col -> Report.Report
2577toIfReport source context if_ startRow startCol =
2578 case if_ of
2579 IfSpace space row col ->
2580 toSpaceReport source space row col
2582 IfThen row col ->
2583 let
2584 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2585 region = toRegion row col
2586 in
2587 Report.Report "UNFINISHED IF" region [] $
2588 Code.toSnippet source surroundings (Just region)
2590 D.reflow $
2591 "I was expecting to see more of this `if` expression, but I got stuck here:"
2593 D.fillSep $
2594 ["I","was","expecting","to","see","the",D.cyan "then","keyword","next."
2598 IfElse 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.fillSep $
2610 ["I","was","expecting","to","see","the",D.cyan "else","keyword","next."
2614 IfElseBranchStart row col ->
2615 let
2616 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2617 region = toRegion row col
2618 in
2619 Report.Report "UNFINISHED IF" region [] $
2620 Code.toSnippet source surroundings (Just region)
2622 D.reflow $
2623 "I just saw the start of an `else` branch, but then I got stuck here:"
2625 D.reflow $
2626 "I was expecting to see an expression next. Maybe it is not filled in yet?"
2629 IfCondition expr row col ->
2630 toExprReport source (InNode NCond startRow startCol context) expr row col
2632 IfThenBranch expr row col ->
2633 toExprReport source (InNode NThen startRow startCol context) expr row col
2635 IfElseBranch expr row col ->
2636 toExprReport source (InNode NElse startRow startCol context) expr row col
2638 IfIndentCondition 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 was expecting to see more of this `if` expression, but I got stuck here:"
2649 D.stack
2650 [ D.fillSep $
2651 ["I","was","expecting","to","see","an","expression","like",D.dullyellow "x < 0"
2652 ,"that","evaluates","to","True","or","False."
2654 , D.toSimpleNote $
2655 "I can be confused by indentation. Maybe something is not indented enough?"
2659 IfIndentThen row col ->
2660 let
2661 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2662 region = toRegion row col
2663 in
2664 Report.Report "UNFINISHED IF" region [] $
2665 Code.toSnippet source surroundings (Just region)
2667 D.reflow $
2668 "I was expecting to see more of this `if` expression, but I got stuck here:"
2670 D.stack
2671 [ D.fillSep $
2672 ["I","was","expecting","to","see","the",D.cyan "then","keyword","next."
2674 , D.toSimpleNote $
2675 "I can be confused by indentation. Maybe something is not indented enough?"
2679 IfIndentThenBranch row col ->
2680 let
2681 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2682 region = toRegion row col
2683 in
2684 Report.Report "UNFINISHED IF" region [] $
2685 Code.toSnippet source surroundings (Just region)
2687 D.reflow $
2688 "I got stuck after the start of this `then` branch:"
2690 D.stack
2691 [ D.reflow $
2692 "I was expecting to see an expression next. Maybe it is not filled in yet?"
2693 , D.toSimpleNote $
2694 "I can be confused by indentation, so if the `then` branch is already\
2695 \ present, it may not be indented enough for me to recognize it."
2699 IfIndentElseBranch row col ->
2700 let
2701 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2702 region = toRegion row col
2703 in
2704 Report.Report "UNFINISHED IF" region [] $
2705 Code.toSnippet source surroundings (Just region)
2707 D.reflow $
2708 "I got stuck after the start of this `else` branch:"
2710 D.stack
2711 [ D.reflow $
2712 "I was expecting to see an expression next. Maybe it is not filled in yet?"
2713 , D.toSimpleNote $
2714 "I can be confused by indentation, so if the `else` branch is already\
2715 \ present, it may not be indented enough for me to recognize it."
2719 IfIndentElse row col ->
2720 let
2721 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2722 region = toRegion row col
2723 in
2724 Report.Report "UNFINISHED IF" region [] $
2725 Code.toSnippet source surroundings (Just region)
2727 D.reflow $
2728 "I was expecting to see an `else` branch after this:"
2730 D.stack
2731 [ D.reflow $
2732 "I know what to do when the condition is `True`, but not when it is `False`."
2733 , D.fillSep
2734 ["Add","an",D.cyan "else","branch","to","handle","that","scenario!"]
2740-- RECORD
2743toRecordReport :: Code.Source -> Context -> Record -> Row -> Col -> Report.Report
2744toRecordReport source context record startRow startCol =
2745 case record of
2746 RecordOpen row col ->
2747 case Code.whatIsNext source row col of
2748 Code.Keyword keyword ->
2749 let
2750 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2751 region = toKeywordRegion row col keyword
2752 in
2753 Report.Report "RESERVED WORD" region [] $
2754 Code.toSnippet source surroundings (Just region)
2756 D.reflow $
2757 "I just started parsing a record, but I got stuck on this field name:"
2759 D.reflow $
2760 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
2761 \ that is a reserved word. Try using a different name!"
2764 _ ->
2765 let
2766 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2767 region = toRegion row col
2768 in
2769 Report.Report "UNFINISHED RECORD" region [] $
2770 Code.toSnippet source surroundings (Just region)
2772 D.reflow $
2773 "I just started parsing a record, but I got stuck here:"
2775 D.fillSep
2776 ["Records","look","like",D.dullyellow "{ x = 3, y = 4 },"
2777 ,"so","I","was","expecting","to","see","a","field","name","next."
2781 RecordEnd row col ->
2782 let
2783 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2784 region = toRegion row col
2785 in
2786 Report.Report "UNFINISHED RECORD" region [] $
2787 Code.toSnippet source surroundings (Just region)
2789 D.reflow $
2790 "I am partway through parsing a record, but I got stuck here:"
2792 D.stack
2793 [ D.fillSep
2794 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
2795 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
2797 , D.toSimpleNote $
2798 "When I get stuck like this, it usually means that there is a missing parenthesis\
2799 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
2803 RecordField row col ->
2804 case Code.whatIsNext source row col of
2805 Code.Keyword keyword ->
2806 let
2807 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2808 region = toKeywordRegion row col keyword
2809 in
2810 Report.Report "RESERVED WORD" region [] $
2811 Code.toSnippet source surroundings (Just region)
2813 D.reflow $
2814 "I am partway through parsing a record, but I got stuck on this field name:"
2816 D.reflow $
2817 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
2818 \ that is a reserved word. Try using a different name!"
2821 _ ->
2822 let
2823 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2824 region = toRegion row col
2825 in
2826 Report.Report "UNFINISHED RECORD" region [] $
2827 Code.toSnippet source surroundings (Just region)
2829 D.reflow $
2830 "I am partway through parsing a record, but I got stuck after that last comma:"
2832 addNoteForRecordError $
2833 D.reflow $
2834 "Trailing commas are not allowed in records, so I was expecting to see another\
2835 \ record field defined next. If you are done defining the record, the fix may\
2836 \ be to delete that last comma?"
2839 RecordEquals row col ->
2840 let
2841 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2842 region = toRegion row col
2843 in
2844 Report.Report "UNFINISHED RECORD" region [] $
2845 Code.toSnippet source surroundings (Just region)
2847 D.reflow $
2848 "I am partway through parsing a record, but I got stuck here:"
2850 addNoteForRecordError $
2851 D.fillSep $
2852 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
2853 ,"an","equals","sign","next.","So","try","putting","an",D.green "=","sign","here?"
2857 RecordExpr expr row col ->
2858 toExprReport source (InNode NRecord startRow startCol context) expr row col
2860 RecordSpace space row col ->
2861 toSpaceReport source space row col
2863 RecordIndentOpen row col ->
2864 let
2865 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2866 region = toRegion row col
2867 in
2868 Report.Report "UNFINISHED RECORD" region [] $
2869 Code.toSnippet source surroundings (Just region)
2871 D.reflow $
2872 "I just saw the opening curly brace of a record, but then I got stuck here:"
2874 addNoteForRecordIndentError $
2875 D.fillSep $
2876 ["I","am","expecting","a","record","like",D.dullyellow "{ x = 3, y = 4 }","here."
2877 ,"Try","defining","some","fields","of","your","own?"
2881 RecordIndentEnd row col ->
2882 let
2883 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2884 region = toRegion row col
2885 in
2886 Report.Report "UNFINISHED RECORD" region [] $
2887 Code.toSnippet source surroundings (Just region)
2889 D.reflow $
2890 "I was expecting to see a closing curly brace next:"
2892 addNoteForRecordIndentError $
2893 D.fillSep $
2894 ["Try","putting","an",D.green "}","and","see","if","that","helps?"
2898 RecordIndentField row col ->
2899 let
2900 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2901 region = toRegion row col
2902 in
2903 Report.Report "UNFINISHED RECORD" region [] $
2904 Code.toSnippet source surroundings (Just region)
2906 D.reflow $
2907 "I am partway through parsing a record, but I got stuck after that last comma:"
2909 addNoteForRecordError $
2910 D.reflow $
2911 "Trailing commas are not allowed in records, so the fix may be to\
2912 \ delete that last comma? Or maybe you were in the middle of defining\
2913 \ an additional field?"
2916 RecordIndentEquals row col ->
2917 let
2918 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2919 region = toRegion row col
2920 in
2921 Report.Report "UNFINISHED RECORD" region [] $
2922 Code.toSnippet source surroundings (Just region)
2924 D.reflow $
2925 "I am partway through parsing a record. I just saw a record\
2926 \ field, so I was expecting to see an equals sign next:"
2928 addNoteForRecordIndentError $
2929 D.fillSep $
2930 ["Try","putting","an",D.green "=","followed","by","an","expression?"
2934 RecordIndentExpr row col ->
2935 let
2936 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2937 region = toRegion row col
2938 in
2939 Report.Report "UNFINISHED RECORD" region [] $
2940 Code.toSnippet source surroundings (Just region)
2942 D.reflow $
2943 "I am partway through parsing a record, and I was expecting to run into an expression next:"
2945 addNoteForRecordIndentError $
2946 D.fillSep $
2947 ["Try","putting","something,","like"
2948 ,D.dullyellow "42","or",D.dullyellow"\"hello\"","for","now?"
2953addNoteForRecordError :: D.Doc -> D.Doc
2954addNoteForRecordError normalRecommendation =
2955 D.stack $
2956 normalRecommendation
2958 [ D.toSimpleNote
2959 "If you are trying to define a record across multiple lines, I recommend using this format:"
2960 , D.indent 4 $ D.vcat $
2961 [ "{ name = \"Alice\""
2962 , ", age = 42"
2963 , ", height = 1.75"
2964 , "}"
2966 , D.reflow $
2967 "Notice that each line starts with some indentation. Usually two or four spaces. I\
2968 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
2969 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2973addNoteForRecordIndentError :: D.Doc -> D.Doc
2974addNoteForRecordIndentError normalRecommendation =
2975 D.stack $
2976 normalRecommendation
2978 [ D.toSimpleNote
2979 "I may be confused by indentation. For example, if you are trying to define\
2980 \ a record across multiple lines, I recommend using this format:"
2981 , D.indent 4 $ D.vcat $
2982 [ "{ name = \"Alice\""
2983 , ", age = 42"
2984 , ", height = 1.75"
2985 , "}"
2987 , D.reflow $
2988 "Notice that each line starts with some indentation. Usually two or four spaces. I\
2989 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
2990 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2995-- TUPLE
2998toTupleReport :: Code.Source -> Context -> Tuple -> Row -> Col -> Report.Report
2999toTupleReport source context tuple startRow startCol =
3000 case tuple of
3001 TupleExpr expr row col ->
3002 toExprReport source (InNode NParens startRow startCol context) expr row col
3004 TupleSpace space row col ->
3005 toSpaceReport source space row col
3007 TupleEnd row col ->
3008 let
3009 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3010 region = toRegion row col
3011 in
3012 Report.Report "UNFINISHED PARENTHESES" region [] $
3013 Code.toSnippet source surroundings (Just region)
3015 D.reflow $
3016 "I was expecting to see a closing parentheses next, but I got stuck here:"
3018 D.stack
3019 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
3020 , D.toSimpleNote $
3021 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
3022 \ unexpectedly. So there may be some earlier syntax trouble (like extra parenthesis\
3023 \ or missing brackets) that is confusing me."
3027 TupleOperatorClose row col ->
3028 let
3029 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3030 region = toRegion row col
3031 in
3032 Report.Report "UNFINISHED OPERATOR FUNCTION" region [] $
3033 Code.toSnippet source surroundings (Just region)
3035 D.reflow "I was expecting a closing parenthesis here:"
3037 D.stack
3038 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
3039 , D.toSimpleNote $
3040 "I think I am parsing an operator function right now, so I am expecting to see\
3041 \ something like (+) or (&&) where an operator is surrounded by parentheses with\
3042 \ no extra spaces."
3046 TupleOperatorReserved operator row col ->
3047 let
3048 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3049 region = toRegion row col
3050 in
3051 Report.Report "UNEXPECTED SYMBOL" region [] $
3052 Code.toSnippet source surroundings (Just region)
3054 D.reflow $
3055 "I ran into an unexpected symbol here:"
3057 D.fillSep $
3058 case operator of
3059 BadDot -> ["Maybe","you","wanted","a","record","accessor","like",D.dullyellow ".x","or",D.dullyellow ".name","instead?"]
3060 BadPipe -> ["Try",D.dullyellow "(||)","instead?","To","turn","boolean","OR","into","a","function?"]
3061 BadArrow -> ["Maybe","you","wanted",D.dullyellow "(>)","or",D.dullyellow "(>=)","instead?"]
3062 BadEquals -> ["Try",D.dullyellow "(==)","instead?","To","make","a","function","that","checks","equality?"]
3063 BadHasType -> ["Try",D.dullyellow "(::)","instead?","To","add","values","to","the","front","of","lists?"]
3066 TupleIndentExpr1 row col ->
3067 let
3068 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3069 region = toRegion row col
3070 in
3071 Report.Report "UNFINISHED PARENTHESES" region [] $
3072 Code.toSnippet source surroundings (Just region)
3074 D.reflow $
3075 "I just saw an open parenthesis, so I was expecting to see an expression next."
3077 D.stack
3078 [ D.fillSep $
3079 ["Something","like",D.dullyellow "(4 + 5)","or"
3080 ,D.dullyellow "(String.reverse \"desserts\")" <> "."
3081 ,"Anything","where","you","are","putting","parentheses","around","normal","expressions."
3083 , D.toSimpleNote $
3084 "I can get confused by indentation in cases like this, so\
3085 \ maybe you have an expression but it is not indented enough?"
3089 TupleIndentExprN row col ->
3090 let
3091 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3092 region = toRegion row col
3093 in
3094 Report.Report "UNFINISHED TUPLE" region [] $
3095 Code.toSnippet source surroundings (Just region)
3097 D.reflow $
3098 "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."
3100 D.stack
3101 [ D.fillSep $
3102 ["A","tuple","looks","like",D.dullyellow "(3,4)","or"
3103 ,D.dullyellow "(\"Tom\",42)" <> ","
3104 ,"so","I","think","there","is","an","expression","missing","here?"
3106 , D.toSimpleNote $
3107 "I can get confused by indentation in cases like this, so\
3108 \ maybe you have an expression but it is not indented enough?"
3112 TupleIndentEnd row col ->
3113 let
3114 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3115 region = toRegion row col
3116 in
3117 Report.Report "UNFINISHED PARENTHESES" region [] $
3118 Code.toSnippet source surroundings (Just region)
3120 D.reflow $
3121 "I was expecting to see a closing parenthesis next:"
3123 D.stack
3124 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
3125 , D.toSimpleNote $
3126 "I can get confused by indentation in cases like this, so\
3127 \ maybe you have a closing parenthesis but it is not indented enough?"
3132toListReport :: Code.Source -> Context -> List -> Row -> Col -> Report.Report
3133toListReport source context list startRow startCol =
3134 case list of
3135 ListSpace space row col ->
3136 toSpaceReport source space row col
3138 ListOpen row col ->
3139 let
3140 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3141 region = toRegion row col
3142 in
3143 Report.Report "UNFINISHED LIST" region [] $
3144 Code.toSnippet source surroundings (Just region)
3146 D.reflow $
3147 "I am partway through parsing a list, but I got stuck here:"
3149 D.stack
3150 [ D.fillSep
3151 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
3152 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
3154 , D.toSimpleNote $
3155 "When I get stuck like this, it usually means that there is a missing parenthesis\
3156 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
3160 ListExpr expr row col ->
3161 case expr of
3162 Start r c ->
3163 let
3164 surroundings = A.Region (A.Position startRow startCol) (A.Position r c)
3165 region = toRegion r c
3166 in
3167 Report.Report "UNFINISHED LIST" region [] $
3168 Code.toSnippet source surroundings (Just region)
3170 D.reflow $
3171 "I was expecting to see another list entry after that last comma:"
3173 D.stack
3174 [ D.reflow $
3175 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
3176 , D.toSimpleNote
3177 "I recommend using the following format for lists that span multiple lines:"
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 _ ->
3192 toExprReport source (InNode NList startRow startCol context) expr row col
3194 ListEnd row col ->
3195 let
3196 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3197 region = toRegion row col
3198 in
3199 Report.Report "UNFINISHED LIST" region [] $
3200 Code.toSnippet source surroundings (Just region)
3202 D.reflow $
3203 "I am partway through parsing a list, but I got stuck here:"
3205 D.stack
3206 [ D.fillSep
3207 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
3208 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
3210 , D.toSimpleNote $
3211 "When I get stuck like this, it usually means that there is a missing parenthesis\
3212 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
3216 ListIndentOpen row col ->
3217 let
3218 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3219 region = toRegion row col
3220 in
3221 Report.Report "UNFINISHED LIST" region [] $
3222 Code.toSnippet source surroundings (Just region)
3224 D.reflow $
3225 "I cannot find the end of this list:"
3227 D.stack
3228 [ D.fillSep $
3229 ["You","could","change","it","to","something","like"
3230 ,D.dullyellow "[3,4,5]"
3231 ,"or","even","just"
3232 ,D.dullyellow "[]" <> "."
3233 ,"Anything","where","there","is","an","open","and","close","square","brace,"
3234 ,"and","where","the","elements","of","the","list","are","separated","by","commas."
3236 , D.toSimpleNote
3237 "I may be confused by indentation. For example, if you are trying to define\
3238 \ a list across multiple lines, I recommend using this format:"
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."
3252 ListIndentEnd row col ->
3253 let
3254 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3255 region = toRegion row col
3256 in
3257 Report.Report "UNFINISHED LIST" region [] $
3258 Code.toSnippet source surroundings (Just region)
3260 D.reflow $
3261 "I cannot find the end of this list:"
3263 D.stack
3264 [ D.fillSep $
3265 ["You","can","just","add","a","closing",D.dullyellow "]"
3266 ,"right","here,","and","I","will","be","all","set!"
3268 , D.toSimpleNote
3269 "I may be confused by indentation. For example, if you are trying to define\
3270 \ a list across multiple lines, I recommend using this format:"
3271 , D.indent 4 $ D.vcat $
3272 [ "[ \"Alice\""
3273 , ", \"Bob\""
3274 , ", \"Chuck\""
3275 , "]"
3277 , D.reflow $
3278 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
3279 \ This style can be jarring for people coming from C-like syntax, but folks generally\
3280 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3284 ListIndentExpr row col ->
3285 let
3286 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3287 region = toRegion row col
3288 in
3289 Report.Report "UNFINISHED LIST" region [] $
3290 Code.toSnippet source surroundings (Just region)
3292 D.reflow $
3293 "I was expecting to see another list entry after this comma:"
3295 D.stack
3296 [ D.reflow $
3297 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
3298 , D.toSimpleNote
3299 "I recommend using the following format for lists that span multiple lines:"
3300 , D.indent 4 $ D.vcat $
3301 [ "[ \"Alice\""
3302 , ", \"Bob\""
3303 , ", \"Chuck\""
3304 , "]"
3306 , D.reflow $
3307 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
3308 \ This style can be jarring for people coming from C-like syntax, but folks generally\
3309 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3314toFuncReport :: Code.Source -> Context -> Func -> Row -> Col -> Report.Report
3315toFuncReport source context func startRow startCol =
3316 case func of
3317 FuncSpace space row col ->
3318 toSpaceReport source space row col
3320 FuncArg pattern row col ->
3321 toPatternReport source PArg pattern row col
3323 FuncBody expr row col ->
3324 toExprReport source (InNode NFunc startRow startCol context) expr row col
3326 FuncArrow row col ->
3327 case Code.whatIsNext source row col of
3328 Code.Keyword keyword ->
3329 let
3330 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3331 region = toKeywordRegion row col keyword
3332 in
3333 Report.Report "RESERVED WORD" region [] $
3334 Code.toSnippet source surroundings (Just region)
3336 D.reflow $
3337 "I was parsing an anonymous function, but I got stuck here:"
3339 D.reflow $
3340 "It looks like you are trying to use `" ++ keyword ++ "` as an argument, but\
3341 \ it is a reserved word in this language. Try using a different argument name!"
3344 _ ->
3345 let
3346 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3347 region = toRegion row col
3348 in
3349 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
3350 Code.toSnippet source surroundings (Just region)
3352 D.reflow $
3353 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
3355 D.fillSep $
3356 ["The","syntax","for","anonymous","functions","is"
3357 ,D.dullyellow "(\\x -> x + 1)"
3358 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
3362 FuncIndentArg row col ->
3363 let
3364 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3365 region = toRegion row col
3366 in
3367 Report.Report "MISSING ARGUMENT" region [] $
3368 Code.toSnippet source surroundings (Just region)
3370 D.reflow $
3371 "I just saw the beginning of an anonymous function, so I was expecting to see an argument next:"
3373 D.stack
3374 [ D.fillSep
3375 ["Something","like",D.dullyellow"x","or",D.dullyellow "name" <> "."
3376 ,"Anything","that","starts","with","a","lower","case","letter!"
3378 , D.toSimpleNote $
3379 "The syntax for anonymous functions is (\\x -> x + 1) where the backslash\
3380 \ is meant to look a bit like a lambda if you squint. This visual pun seemed\
3381 \ like a better idea at the time!"
3385 FuncIndentArrow row col ->
3386 let
3387 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3388 region = toRegion row col
3389 in
3390 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
3391 Code.toSnippet source surroundings (Just region)
3393 D.reflow $
3394 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
3396 D.stack
3397 [ D.fillSep $
3398 ["The","syntax","for","anonymous","functions","is"
3399 ,D.dullyellow "(\\x -> x + 1)"
3400 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
3402 , D.toSimpleNote $
3403 "It is possible that I am confused about indetation! I generally recommend\
3404 \ switching to named functions if the definition cannot fit inline nicely, so\
3405 \ either (1) try to fit the whole anonymous function on one line or (2) break\
3406 \ the whole thing out into a named function. Things tend to be clearer that way!"
3410 FuncIndentBody row col ->
3411 let
3412 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3413 region = toRegion row col
3414 in
3415 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
3416 Code.toSnippet source surroundings (Just region)
3418 D.reflow $
3419 "I was expecting to see the body of your anonymous function next:"
3421 D.stack
3422 [ D.fillSep $
3423 ["The","syntax","for","anonymous","functions","is"
3424 ,D.dullyellow "(\\x -> x + 1)"
3425 ,"so","I","am","missing","all","the","stuff","after","the","arrow!"
3427 , D.toSimpleNote $
3428 "It is possible that I am confused about indetation! I generally recommend\
3429 \ switching to named functions if the definition cannot fit inline nicely, so\
3430 \ either (1) try to fit the whole anonymous function on one line or (2) break\
3431 \ the whole thing out into a named function. Things tend to be clearer that way!"
3437-- PATTERN
3440data PContext
3441 = PCase
3442 | PArg
3445toPatternReport :: Code.Source -> PContext -> Pattern -> Row -> Col -> Report.Report
3446toPatternReport source context pattern startRow startCol =
3447 case pattern of
3448 PRecord record row col ->
3449 toPRecordReport source record row col
3451 PTuple tuple row col ->
3452 toPTupleReport source context tuple row col
3454 PList list row col ->
3455 toPListReport source context list row col
3457 PStart row col ->
3458 case Code.whatIsNext source row col of
3459 Code.Keyword keyword ->
3460 let
3461 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3462 region = toKeywordRegion row col keyword
3463 aThing =
3464 case context of
3465 PArg -> "an argument"
3466 PCase -> "a pattern"
3467 in
3468 Report.Report "RESERVED WORD" region [] $
3469 Code.toSnippet source surroundings (Just region)
3471 D.reflow $
3472 "It looks like you are trying to use `" ++ keyword ++ "` as " ++ aThing ++ ":"
3474 D.reflow $
3475 "This is a reserved word! Try using some other name?"
3478 _ ->
3479 error "TODO PStart"
3481 PChar char row col ->
3482 toCharReport source char row col
3484 PString string row col ->
3485 toStringReport source string row col
3487 PNumber number row col ->
3488 toNumberReport source number row col
3490 PFloat width row col ->
3491 let
3492 region = toWiderRegion row col width
3493 in
3494 Report.Report "UNEXPECTED PATTERN" region [] $
3495 Code.toSnippet source region Nothing
3497 D.reflow $
3498 "I cannot pattern match with floating point numbers:"
3500 D.fillSep $
3501 ["Equality","on","floats","can","be","unreliable,","so","you","usually","want"
3502 ,"to","check","that","they","are","nearby","with","some","sort","of"
3503 ,D.dullyellow "(abs (actual - expected) < 0.001)","check."
3507 PAlias row col ->
3508 let
3509 region = toRegion row col
3510 in
3511 Report.Report "UNFINISHED PATTERN" region [] $
3512 Code.toSnippet source region Nothing $
3514 D.reflow $
3515 "I was expecting to see a variable name after the `as` keyword:"
3517 D.stack
3518 [ D.fillSep $
3519 ["The","`as`","keyword","lets","you","write","patterns","like"
3520 ,"((" <> D.dullyellow "x" <> "," <> D.dullyellow "y" <> ") " <> D.cyan "as" <> D.dullyellow " point" <> ")"
3521 ,"so","you","can","refer","to","individual","parts","of","the","tuple","with"
3522 ,D.dullyellow "x","and",D.dullyellow "y","or","you","refer","to","the","whole"
3523 ,"thing","with",D.dullyellow "point."
3525 , D.reflow $
3526 "So I was expecting to see a variable name after the `as` keyword here. Sometimes\
3527 \ people just want to use `as` as a variable name though. Try using a different name\
3528 \ in that case!"
3532 PWildcardNotVar name width row col ->
3533 let
3534 region = toWiderRegion row col (fromIntegral width)
3535 examples =
3536 case dropWhile (=='_') (Name.toChars name) of
3537 [] -> [D.dullyellow "x","or",D.dullyellow "age"]
3538 c:cs -> [D.dullyellow (D.fromChars (Char.toLower c : cs))]
3539 in
3540 Report.Report "UNEXPECTED NAME" region [] $
3541 Code.toSnippet source region Nothing $
3543 D.reflow $
3544 "Variable names cannot start with underscores like this:"
3546 D.fillSep $
3547 ["You","can","either","have","an","underscore","like",D.dullyellow "_","to"
3548 ,"ignore","the","value,","or","you","can","have","a","name","like"
3549 ] ++ examples ++ ["to","use","the","matched","value." ]
3552 PSpace space row col ->
3553 toSpaceReport source space row col
3555 PIndentStart row col ->
3556 error "TODO PIndentStart" row col
3558 PIndentAlias row col ->
3559 let
3560 region = toRegion row col
3561 in
3562 Report.Report "UNFINISHED PATTERN" region [] $
3563 Code.toSnippet source region Nothing $
3565 D.reflow $
3566 "I was expecting to see a variable name after the `as` keyword:"
3568 D.stack
3569 [ D.fillSep $
3570 ["The","`as`","keyword","lets","you","write","patterns","like"
3571 ,"((" <> D.dullyellow "x" <> "," <> D.dullyellow "y" <> ") " <> D.cyan "as" <> D.dullyellow " point" <> ")"
3572 ,"so","you","can","refer","to","individual","parts","of","the","tuple","with"
3573 ,D.dullyellow "x","and",D.dullyellow "y","or","you","refer","to","the","whole"
3574 ,"thing","with",D.dullyellow "point."
3576 , D.reflow $
3577 "So I was expecting to see a variable name after the `as` keyword here. Sometimes\
3578 \ people just want to use `as` as a variable name though. Try using a different name\
3579 \ in that case!"
3584toPRecordReport :: Code.Source -> PRecord -> Row -> Col -> Report.Report
3585toPRecordReport source record startRow startCol =
3586 case record of
3587 PRecordOpen row col ->
3588 toUnfinishRecordPatternReport source row col startRow startCol $
3589 D.reflow "I was expecting to see a field name next."
3591 PRecordEnd row col ->
3592 toUnfinishRecordPatternReport source row col startRow startCol $
3593 D.fillSep
3594 ["I","was","expecting","to","see","a","closing","curly","brace","next."
3595 ,"Try","adding","a",D.dullyellow "}","here?"
3598 PRecordField row col ->
3599 case Code.whatIsNext source row col of
3600 Code.Keyword keyword ->
3601 let
3602 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3603 region = toKeywordRegion row col keyword
3604 in
3605 Report.Report "RESERVED WORD" region [] $
3606 Code.toSnippet source surroundings (Just region)
3608 D.reflow $
3609 "I was not expecting to see `" ++ keyword ++ "` as a record field name:"
3611 D.reflow $
3612 "This is a reserved word, not available for variable names. Try another name!"
3615 _ ->
3616 toUnfinishRecordPatternReport source row col startRow startCol $
3617 D.reflow "I was expecting to see a field name next."
3619 PRecordSpace space row col ->
3620 toSpaceReport source space row col
3622 PRecordIndentOpen row col ->
3623 toUnfinishRecordPatternReport source row col startRow startCol $
3624 D.reflow "I was expecting to see a field name next."
3626 PRecordIndentEnd row col ->
3627 toUnfinishRecordPatternReport source row col startRow startCol $
3628 D.fillSep
3629 ["I","was","expecting","to","see","a","closing","curly","brace","next."
3630 ,"Try","adding","a",D.dullyellow "}","here?"
3633 PRecordIndentField row col ->
3634 toUnfinishRecordPatternReport source row col startRow startCol $
3635 D.reflow "I was expecting to see a field name next."
3638toUnfinishRecordPatternReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
3639toUnfinishRecordPatternReport source row col startRow startCol message =
3640 let
3641 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3642 region = toRegion row col
3643 in
3644 Report.Report "UNFINISHED RECORD PATTERN" region [] $
3645 Code.toSnippet source surroundings (Just region)
3647 D.reflow $
3648 "I was partway through parsing a record pattern, but I got stuck here:"
3650 D.stack
3651 [ message
3652 , D.toFancyHint $
3653 ["A","record","pattern","looks","like",D.dullyellow "{x,y}","or",D.dullyellow "{name,age}"
3654 ,"where","you","list","the","field","names","you","want","to","access."
3661toPTupleReport :: Code.Source -> PContext -> PTuple -> Row -> Col -> Report.Report
3662toPTupleReport source context tuple startRow startCol =
3663 case tuple of
3664 PTupleOpen row col ->
3665 case Code.whatIsNext source row col of
3666 Code.Keyword keyword ->
3667 let
3668 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3669 region = toKeywordRegion row col keyword
3670 in
3671 Report.Report "RESERVED WORD" region [] $
3672 Code.toSnippet source surroundings (Just region)
3674 D.reflow $
3675 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name:"
3677 D.reflow $
3678 "This is a reserved word! Try using some other name?"
3681 _ ->
3682 let
3683 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3684 region = toRegion row col
3685 in
3686 Report.Report "UNFINISHED PARENTHESES" region [] $
3687 Code.toSnippet source surroundings (Just region)
3689 D.reflow $
3690 "I just saw an open parenthesis, but I got stuck here:"
3692 D.fillSep
3693 ["I","was","expecting","so","see","a","pattern","next."
3694 ,"Maybe","it","will","end","up","being","something"
3695 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "?"
3699 PTupleEnd row col ->
3700 let
3701 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3702 region = toRegion row col
3703 in
3704 Report.Report "UNFINISHED PARENTHESES" region [] $
3705 Code.toSnippet source surroundings (Just region) $
3707 D.reflow $
3708 "I was expecting a closing parenthesis next:"
3710 D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
3713 PTupleExpr pattern row col ->
3714 toPatternReport source context pattern row col
3716 PTupleSpace space row col ->
3717 toSpaceReport source space row col
3719 PTupleIndentEnd row col ->
3720 let
3721 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3722 region = toRegion row col
3723 in
3724 Report.Report "UNFINISHED PARENTHESES" region [] $
3725 Code.toSnippet source surroundings (Just region) $
3727 D.reflow $
3728 "I was expecting a closing parenthesis next:"
3730 D.stack
3731 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
3732 , D.toSimpleNote $
3733 "I can get confused by indentation in cases like this, so\
3734 \ maybe you have a closing parenthesis but it is not indented enough?"
3738 PTupleIndentExpr1 row col ->
3739 let
3740 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3741 region = toRegion row col
3742 in
3743 Report.Report "UNFINISHED PARENTHESES" region [] $
3744 Code.toSnippet source surroundings (Just region) $
3746 D.reflow $
3747 "I just saw an open parenthesis, but then I got stuck here:"
3749 D.fillSep
3750 ["I","was","expecting","so","see","a","pattern","next."
3751 ,"Maybe","it","will","end","up","being","something"
3752 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "?"
3756 PTupleIndentExprN row col ->
3757 let
3758 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3759 region = toRegion row col
3760 in
3761 Report.Report "UNFINISHED TUPLE PATTERN" region [] $
3762 Code.toSnippet source surroundings (Just region) $
3764 D.reflow $
3765 "I am partway through parsing a tuple pattern, but I got stuck here:"
3767 D.stack
3768 [ D.fillSep
3769 ["I","was","expecting","so","see","a","pattern","next."
3770 ,"I","am","expecting","the","final","result","to","be","something"
3771 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "."
3773 , D.toSimpleNote $
3774 "I can get confused by indentation in cases like this, so the problem\
3775 \ may be that the next part is not indented enough?"
3780toPListReport :: Code.Source -> PContext -> PList -> Row -> Col -> Report.Report
3781toPListReport source context list startRow startCol =
3782 case list of
3783 PListOpen row col ->
3784 case Code.whatIsNext source row col of
3785 Code.Keyword keyword ->
3786 let
3787 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3788 region = toKeywordRegion row col keyword
3789 in
3790 Report.Report "RESERVED WORD" region [] $
3791 Code.toSnippet source surroundings (Just region)
3793 D.reflow $
3794 "It looks like you are trying to use `" ++ keyword ++ "` to name an element of a list:"
3796 D.reflow $
3797 "This is a reserved word though! Try using some other name?"
3800 _ ->
3801 let
3802 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3803 region = toRegion row col
3804 in
3805 Report.Report "UNFINISHED LIST PATTERN" region [] $
3806 Code.toSnippet source surroundings (Just region) $
3808 D.reflow $
3809 "I just saw an open square bracket, but then I got stuck here:"
3811 D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
3814 PListEnd row col ->
3815 let
3816 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3817 region = toRegion row col
3818 in
3819 Report.Report "UNFINISHED LIST PATTERN" region [] $
3820 Code.toSnippet source surroundings (Just region) $
3822 D.reflow $
3823 "I was expecting a closing square bracket to end this list pattern:"
3825 D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
3828 PListExpr pattern row col ->
3829 toPatternReport source context pattern row col
3831 PListSpace space row col ->
3832 toSpaceReport source space row col
3834 PListIndentOpen row col ->
3835 let
3836 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3837 region = toRegion row col
3838 in
3839 Report.Report "UNFINISHED LIST PATTERN" region [] $
3840 Code.toSnippet source surroundings (Just region) $
3842 D.reflow $
3843 "I just saw an open square bracket, but then I got stuck here:"
3845 D.stack
3846 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
3847 , D.toSimpleNote $
3848 "I can get confused by indentation in cases like this, so\
3849 \ maybe there is something next, but it is not indented enough?"
3853 PListIndentEnd row col ->
3854 let
3855 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3856 region = toRegion row col
3857 in
3858 Report.Report "UNFINISHED LIST PATTERN" region [] $
3859 Code.toSnippet source surroundings (Just region) $
3861 D.reflow $
3862 "I was expecting a closing square bracket to end this list pattern:"
3864 D.stack
3865 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
3866 , D.toSimpleNote $
3867 "I can get confused by indentation in cases like this, so\
3868 \ maybe you have a closing square bracket but it is not indented enough?"
3872 PListIndentExpr row col ->
3873 let
3874 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3875 region = toRegion row col
3876 in
3877 Report.Report "UNFINISHED LIST PATTERN" region [] $
3878 Code.toSnippet source surroundings (Just region) $
3880 D.reflow $
3881 "I am partway through parsing a list pattern, but I got stuck here:"
3883 D.stack
3884 [ D.reflow $
3885 "I was expecting to see another pattern next. Maybe a variable name."
3886 , D.toSimpleNote $
3887 "I can get confused by indentation in cases like this, so\
3888 \ maybe there is more to this pattern but it is not indented enough?"
3894-- TYPES
3897-- TODO add context? say something special if you are in type annotation vs custom type vs type alias?
3899toTypeReport :: Code.Source -> Type -> Row -> Col -> Report.Report
3900toTypeReport source tipe startRow startCol =
3901 case tipe of
3902 TRecord record row col ->
3903 toTRecordReport source record row col
3905 TTuple tuple row col ->
3906 toTTupleReport source tuple row col
3908 TArrow row col ->
3909 error "TODO TArrow" row col
3911 TStart row col ->
3912 error "TODO TStart" row col startRow startCol
3914 TSpace space row col ->
3915 toSpaceReport source space row col
3917 TIndentStart row col ->
3918 error "TODO TIndentStart" row col
3922toTRecordReport :: Code.Source -> TRecord -> Row -> Col -> Report.Report
3923toTRecordReport source record startRow startCol =
3924 case record of
3925 TRecordOpen row col ->
3926 case Code.whatIsNext source row col of
3927 Code.Keyword keyword ->
3928 let
3929 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3930 region = toKeywordRegion row col keyword
3931 in
3932 Report.Report "RESERVED WORD" region [] $
3933 Code.toSnippet source surroundings (Just region)
3935 D.reflow $
3936 "I just started parsing a record type, but I got stuck on this field name:"
3938 D.reflow $
3939 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
3940 \ that is a reserved word. Try using a different name!"
3943 _ ->
3944 let
3945 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3946 region = toRegion row col
3947 in
3948 Report.Report "UNFINISHED RECORD TYPE" region [] $
3949 Code.toSnippet source surroundings (Just region)
3951 D.reflow $
3952 "I just started parsing a record type, but I got stuck here:"
3954 D.fillSep
3955 ["Record","types","look","like",D.dullyellow "{ name : String, age : Int },"
3956 ,"so","I","was","expecting","to","see","a","field","name","next."
3960 TRecordEnd row col ->
3961 let
3962 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3963 region = toRegion row col
3964 in
3965 Report.Report "UNFINISHED RECORD TYPE" region [] $
3966 Code.toSnippet source surroundings (Just region)
3968 D.reflow $
3969 "I am partway through parsing a record type, but I got stuck here:"
3971 D.stack
3972 [ D.fillSep
3973 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
3974 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
3976 , D.toSimpleNote $
3977 "When I get stuck like this, it usually means that there is a missing parenthesis\
3978 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
3982 TRecordField row col ->
3983 case Code.whatIsNext source row col of
3984 Code.Keyword keyword ->
3985 let
3986 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3987 region = toKeywordRegion row col keyword
3988 in
3989 Report.Report "RESERVED WORD" region [] $
3990 Code.toSnippet source surroundings (Just region)
3992 D.reflow $
3993 "I am partway through parsing a record type, but I got stuck on this field name:"
3995 D.reflow $
3996 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
3997 \ that is a reserved word. Try using a different name!"
4000 _ ->
4001 let
4002 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4003 region = toRegion row col
4004 in
4005 Report.Report "UNFINISHED RECORD TYPE" region [] $
4006 Code.toSnippet source surroundings (Just region)
4008 D.reflow $
4009 "I am partway through parsing a record type, but I got stuck after that last comma:"
4011 addNoteForRecordTypeError $
4012 D.reflow $
4013 "Trailing commas are not allowed in records, so I was expecting to see another\
4014 \ record field defined next. If you are done defining the record, the fix may\
4015 \ be to delete that last comma?"
4018 TRecordColon row col ->
4019 let
4020 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4021 region = toRegion row col
4022 in
4023 Report.Report "UNFINISHED RECORD TYPE" region [] $
4024 Code.toSnippet source surroundings (Just region)
4026 D.reflow $
4027 "I am partway through parsing a record type, but I got stuck here:"
4029 addNoteForRecordTypeError $
4030 D.fillSep $
4031 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
4032 ,"a","colon","next.","So","try","putting","an",D.green ":","sign","here?"
4036 TRecordType tipe row col ->
4037 toTypeReport source tipe row col
4039 TRecordSpace space row col ->
4040 toSpaceReport source space row col
4042 TRecordIndentOpen row col ->
4043 let
4044 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4045 region = toRegion row col
4046 in
4047 Report.Report "UNFINISHED RECORD TYPE" region [] $
4048 Code.toSnippet source surroundings (Just region)
4050 D.reflow $
4051 "I just saw the opening curly brace of a record type, but then I got stuck here:"
4053 addNoteForRecordTypeIndentError $
4054 D.fillSep $
4055 ["I","am","expecting","a","record","like",D.dullyellow "{ name : String, age : Int }","here."
4056 ,"Try","defining","some","fields","of","your","own?"
4060 TRecordIndentEnd row col ->
4061 let
4062 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4063 region = toRegion row col
4064 in
4065 Report.Report "UNFINISHED RECORD TYPE" region [] $
4066 Code.toSnippet source surroundings (Just region)
4068 D.reflow $
4069 "I was expecting to see a closing curly brace next:"
4071 addNoteForRecordTypeIndentError $
4072 D.fillSep $
4073 ["Try","putting","an",D.green "}","and","see","if","that","helps?"
4077 TRecordIndentField row col ->
4078 let
4079 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4080 region = toRegion row col
4081 in
4082 Report.Report "UNFINISHED RECORD TYPE" region [] $
4083 Code.toSnippet source surroundings (Just region)
4085 D.reflow $
4086 "I am partway through parsing a record type, but I got stuck after that last comma:"
4088 addNoteForRecordTypeIndentError $
4089 D.reflow $
4090 "Trailing commas are not allowed in record types, so the fix may be to\
4091 \ delete that last comma? Or maybe you were in the middle of defining\
4092 \ an additional field?"
4095 TRecordIndentColon row col ->
4096 let
4097 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4098 region = toRegion row col
4099 in
4100 Report.Report "UNFINISHED RECORD TYPE" region [] $
4101 Code.toSnippet source surroundings (Just region)
4103 D.reflow $
4104 "I am partway through parsing a record type. I just saw a record\
4105 \ field, so I was expecting to see a colon next:"
4107 addNoteForRecordTypeIndentError $
4108 D.fillSep $
4109 ["Try","putting","an",D.green ":","followed","by","a","type?"
4113 TRecordIndentType row col ->
4114 let
4115 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4116 region = toRegion row col
4117 in
4118 Report.Report "UNFINISHED RECORD TYPE" region [] $
4119 Code.toSnippet source surroundings (Just region)
4121 D.reflow $
4122 "I am partway through parsing a record type, and I was expecting to run into a type next:"
4124 addNoteForRecordTypeIndentError $
4125 D.fillSep $
4126 ["Try","putting","something,","like"
4127 ,D.dullyellow "Int","or",D.dullyellow "String","for","now?"
4132addNoteForRecordTypeError :: D.Doc -> D.Doc
4133addNoteForRecordTypeError normalRecommendation =
4134 D.stack $
4135 normalRecommendation
4137 [ D.toSimpleNote
4138 "If you are trying to define a record type across multiple lines, I recommend using this format:"
4139 , D.indent 4 $ D.vcat $
4140 [ "{ name : String"
4141 , ", age : Int"
4142 , ", height : Float"
4143 , "}"
4145 , D.reflow $
4146 "Notice that each line starts with some indentation. Usually two or four spaces. I\
4147 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
4148 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
4152addNoteForRecordTypeIndentError :: D.Doc -> D.Doc
4153addNoteForRecordTypeIndentError normalRecommendation =
4154 D.stack $
4155 normalRecommendation
4157 [ D.toSimpleNote
4158 "I may be confused by indentation. For example, if you are trying to define\
4159 \ a record type across multiple lines, I recommend using this format:"
4160 , D.indent 4 $ D.vcat $
4161 [ "{ name : String"
4162 , ", age : Int"
4163 , ", height : Float"
4164 , "}"
4166 , D.reflow $
4167 "Notice that each line starts with some indentation. Usually two or four spaces. I\
4168 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
4169 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
4173toTTupleReport :: Code.Source -> TTuple -> Row -> Col -> Report.Report
4174toTTupleReport source tuple startRow startCol =
4175 case tuple of
4176 TTupleOpen row col ->
4177 case Code.whatIsNext source row col of
4178 Code.Keyword keyword ->
4179 let
4180 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4181 region = toKeywordRegion row col keyword
4182 in
4183 Report.Report "RESERVED WORD" region [] $
4184 Code.toSnippet source surroundings (Just region)
4186 D.reflow $
4187 "I ran into a reserved word unexpectedly:"
4189 D.reflow $
4190 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name, but \
4191 \ it is a reserved word. Try using a different name!"
4194 _ ->
4195 let
4196 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4197 region = toRegion row col
4198 in
4199 Report.Report "UNFINISHED PARENTHESES" region [] $
4200 Code.toSnippet source surroundings (Just region)
4202 D.reflow $
4203 "I just saw an open parenthesis, so I was expecting to see a type next."
4205 D.fillSep $
4206 ["Something","like",D.dullyellow "(Maybe Int)","or"
4207 ,D.dullyellow "(List Person)" <> "."
4208 ,"Anything","where","you","are","putting","parentheses","around","normal","types."
4212 TTupleEnd row col ->
4213 let
4214 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4215 region = toRegion row col
4216 in
4217 Report.Report "UNFINISHED PARENTHESES" region [] $
4218 Code.toSnippet source surroundings (Just region)
4220 D.reflow $
4221 "I was expecting to see a closing parentheses next, but I got stuck here:"
4223 D.stack
4224 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
4225 , D.toSimpleNote $
4226 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
4227 \ unexpectedly. So there may be some earlier syntax trouble (like extra parenthesis\
4228 \ or missing brackets) that is confusing me."
4232 TTupleType tipe row col ->
4233 toTypeReport source tipe row col
4235 TTupleSpace space row col ->
4236 toSpaceReport source space row col
4238 TTupleIndentType1 row col ->
4239 let
4240 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4241 region = toRegion row col
4242 in
4243 Report.Report "UNFINISHED PARENTHESES" region [] $
4244 Code.toSnippet source surroundings (Just region)
4246 D.reflow $
4247 "I just saw an open parenthesis, so I was expecting to see a type next."
4249 D.stack
4250 [ D.fillSep $
4251 ["Something","like",D.dullyellow "(Maybe Int)","or"
4252 ,D.dullyellow "(List Person)" <> "."
4253 ,"Anything","where","you","are","putting","parentheses","around","normal","types."
4255 , D.toSimpleNote $
4256 "I can get confused by indentation in cases like this, so\
4257 \ maybe you have a type but it is not indented enough?"
4261 TTupleIndentTypeN row col ->
4262 let
4263 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4264 region = toRegion row col
4265 in
4266 Report.Report "UNFINISHED TUPLE TYPE" region [] $
4267 Code.toSnippet source surroundings (Just region)
4269 D.reflow $
4270 "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."
4272 D.stack
4273 [ D.fillSep $
4274 ["A","tuple","type","looks","like",D.dullyellow "(Float,Float)","or"
4275 ,D.dullyellow "(String,Int)" <> ","
4276 ,"so","I","think","there","is","a","type","missing","here?"
4278 , D.toSimpleNote $
4279 "I can get confused by indentation in cases like this, so\
4280 \ maybe you have an expression but it is not indented enough?"
4284 TTupleIndentEnd row col ->
4285 let
4286 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4287 region = toRegion row col
4288 in
4289 Report.Report "UNFINISHED PARENTHESES" region [] $
4290 Code.toSnippet source surroundings (Just region)
4292 D.reflow $
4293 "I was expecting to see a closing parenthesis next:"
4295 D.stack
4296 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
4297 , D.toSimpleNote $
4298 "I can get confused by indentation in cases like this, so\
4299 \ maybe you have a closing parenthesis but it is not indented enough?"