on b5bc232 help sign in
4525 lines 159 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 | ExposingTypePrivacy Row Col
119 | ExposingEnd Row Col
120 --
121 | ExposingIndentEnd Row Col
122 | ExposingIndentValue Row Col
126-- DECLARATIONS
129data Decl
130 = DeclStart Row Col
131 | DeclSpace Space Row Col
132 --
133 | Port Port Row Col
134 | DeclType DeclType Row Col
135 | DeclDef Name.Name DeclDef Row Col
136 --
137 | DeclFreshLineStart Row Col
138 | DeclFreshLineAfterDocComment Row Col
141data DeclDef
142 = DeclDefSpace Space Row Col
143 | DeclDefEquals Row Col
144 | DeclDefType Type Row Col
145 | DeclDefArg Pattern Row Col
146 | DeclDefBody Expr Row Col
147 | DeclDefNameRepeat Row Col
148 | DeclDefNameMatch Name.Name Row Col
149 --
150 | DeclDefIndentType Row Col
151 | DeclDefIndentEquals Row Col
152 | DeclDefIndentBody Row Col
155data Port
156 = PortSpace Space Row Col
157 | PortName Row Col
158 | PortColon Row Col
159 | PortType Type Row Col
160 | PortIndentName Row Col
161 | PortIndentColon Row Col
162 | PortIndentType Row Col
166-- TYPE DECLARATIONS
169data DeclType
170 = DT_Space Space Row Col
171 | DT_Name Row Col
172 | DT_Alias TypeAlias Row Col
173 | DT_Union CustomType Row Col
174 --
175 | DT_IndentName Row Col
178data TypeAlias
179 = AliasSpace Space Row Col
180 | AliasName Row Col
181 | AliasEquals Row Col
182 | AliasBody Type Row Col
183 --
184 | AliasIndentEquals Row Col
185 | AliasIndentBody Row Col
188data CustomType
189 = CT_Space Space Row Col
190 | CT_Name Row Col
191 | CT_Equals Row Col
192 | CT_Bar Row Col
193 | CT_Variant Row Col
194 | CT_VariantArg Type Row Col
195 --
196 | CT_IndentEquals Row Col
197 | CT_IndentBar Row Col
198 | CT_IndentAfterBar Row Col
199 | CT_IndentAfterEquals Row Col
203-- EXPRESSIONS
206data Expr
207 = Let Let Row Col
208 | Case Case Row Col
209 | If If Row Col
210 | List List Row Col
211 | Record Record Row Col
212 | Tuple Tuple Row Col
213 | Func Func Row Col
214 --
215 | Dot Row Col
216 | Access Row Col
217 | OperatorRight Name.Name Row Col
218 | OperatorReserved BadOperator Row Col
219 --
220 | Start Row Col
221 | Char Char Row Col
222 | String String Row Col
223 | Number Number Row Col
224 | Space Space Row Col
225 | EndlessShader Row Col
226 | ShaderProblem [Char.Char] Row Col
227 | IndentOperatorRight Name.Name Row Col
228 | IndentMoreExpr Row Col
231data Record
232 = RecordOpen Row Col
233 | RecordEnd Row Col
234 | RecordField Row Col
235 | RecordEquals Row Col
236 | RecordExpr Expr Row Col
237 | RecordSpace Space Row Col
238 --
239 | RecordIndentOpen Row Col
240 | RecordIndentEnd Row Col
241 | RecordIndentField Row Col
242 | RecordIndentEquals Row Col
243 | RecordIndentExpr Row Col
246data Tuple
247 = TupleExpr Expr Row Col
248 | TupleSpace Space Row Col
249 | TupleEnd Row Col
250 | TupleOperatorClose Row Col
251 | TupleOperatorReserved BadOperator Row Col
252 --
253 | TupleIndentExpr1 Row Col
254 | TupleIndentExprN Row Col
255 | TupleIndentEnd Row Col
258data List
259 = ListSpace Space Row Col
260 | ListOpen Row Col
261 | ListExpr Expr Row Col
262 | ListEnd Row Col
263 --
264 | ListIndentOpen Row Col
265 | ListIndentEnd Row Col
266 | ListIndentExpr Row Col
269data Func
270 = FuncSpace Space Row Col
271 | FuncArg Pattern Row Col
272 | FuncBody Expr Row Col
273 | FuncArrow Row Col
274 --
275 | FuncIndentArg Row Col
276 | FuncIndentArrow Row Col
277 | FuncIndentBody Row Col
280data Case
281 = CaseSpace Space Row Col
282 | CaseOf Row Col
283 | CasePattern Pattern Row Col
284 | CaseArrow Row Col
285 | CaseExpr Expr Row Col
286 | CaseBranch Expr Row Col
287 --
288 | CaseIndentOf Row Col
289 | CaseIndentExpr Row Col
290 | CaseIndentPattern Row Col
291 | CaseIndentArrow Row Col
292 | CaseIndentBranch Row Col
293 | CasePatternAlignment Word16 Row Col
296data If
297 = IfSpace Space Row Col
298 | IfThen Row Col
299 | IfElse Row Col
300 | IfElseBranchStart Row Col
301 --
302 | IfCondition Expr Row Col
303 | IfThenBranch Expr Row Col
304 | IfElseBranch Expr Row Col
305 --
306 | IfIndentCondition Row Col
307 | IfIndentThen Row Col
308 | IfIndentThenBranch Row Col
309 | IfIndentElseBranch Row Col
310 | IfIndentElse Row Col
313data Let
314 = LetSpace Space Row Col
315 | LetIn Row Col
316 | LetDefAlignment Word16 Row Col
317 | LetDefName Row Col
318 | LetDef Name.Name Def Row Col
319 | LetDestruct Destruct Row Col
320 | LetBody Expr Row Col
321 | LetIndentDef Row Col
322 | LetIndentIn Row Col
323 | LetIndentBody Row Col
326data Def
327 = DefSpace Space Row Col
328 | DefType Type Row Col
329 | DefNameRepeat Name.Name Row Col
330 | DefNameMatch Name.Name Name.Name Row Col
331 | DefArg Pattern Row Col
332 | DefEquals Row Col
333 | DefBody Expr Row Col
334 | DefIndentEquals Row Col
335 | DefIndentType Row Col
336 | DefIndentBody Row Col
337 | DefAlignment Word16 Row Col
340data Destruct
341 = DestructSpace Space Row Col
342 | DestructPattern Pattern Row Col
343 | DestructEquals Row Col
344 | DestructBody Expr Row Col
345 | DestructIndentEquals Row Col
346 | DestructIndentBody Row Col
350-- PATTERNS
353data Pattern
354 = PRecord PRecord Row Col
355 | PTuple PTuple Row Col
356 | PList PList Row Col
357 --
358 | PStart Row Col
359 | PChar Char Row Col
360 | PString String Row Col
361 | PNumber Number Row Col
362 | PFloat Word16 Row Col
363 | PAlias Row Col
364 | PWildcardNotVar Name.Name Int Row Col
365 | PSpace Space Row Col
366 --
367 | PIndentStart Row Col
368 | PIndentAlias Row Col
371data PRecord
372 = PRecordOpen Row Col
373 | PRecordEnd Row Col
374 | PRecordField Row Col
375 | PRecordSpace Space Row Col
376 --
377 | PRecordIndentOpen Row Col
378 | PRecordIndentEnd Row Col
379 | PRecordIndentField Row Col
382data PTuple
383 = PTupleOpen Row Col
384 | PTupleEnd Row Col
385 | PTupleExpr Pattern Row Col
386 | PTupleSpace Space Row Col
387 --
388 | PTupleIndentEnd Row Col
389 | PTupleIndentExpr1 Row Col
390 | PTupleIndentExprN Row Col
393data PList
394 = PListOpen Row Col
395 | PListEnd Row Col
396 | PListExpr Pattern Row Col
397 | PListSpace Space Row Col
398 --
399 | PListIndentOpen Row Col
400 | PListIndentEnd Row Col
401 | PListIndentExpr Row Col
405-- TYPES
408data Type
409 = TRecord TRecord Row Col
410 | TTuple TTuple Row Col
411 | TArrow Row Col
412 --
413 | TStart Row Col
414 | TSpace Space Row Col
415 --
416 | TIndentStart Row Col
419data TRecord
420 = TRecordOpen Row Col
421 | TRecordEnd Row Col
422 --
423 | TRecordField Row Col
424 | TRecordColon Row Col
425 | TRecordType Type Row Col
426 --
427 | TRecordSpace Space Row Col
428 --
429 | TRecordIndentOpen Row Col
430 | TRecordIndentField Row Col
431 | TRecordIndentColon Row Col
432 | TRecordIndentType Row Col
433 | TRecordIndentEnd Row Col
436data TTuple
437 = TTupleOpen Row Col
438 | TTupleEnd Row Col
439 | TTupleType Type Row Col
440 | TTupleSpace Space Row Col
441 --
442 | TTupleIndentType1 Row Col
443 | TTupleIndentTypeN Row Col
444 | TTupleIndentEnd Row Col
448-- LITERALS
451data Char
452 = CharEndless
453 | CharEscape Escape
454 | CharNotString Word16
457data String
458 = StringEndless_Single
459 | StringEndless_Multi
460 | StringEscape Escape
463data Escape
464 = EscapeUnknown
465 | BadUnicodeFormat Word16
466 | BadUnicodeCode Word16
467 | BadUnicodeLength Word16 Int Int
470data Number
471 = NumberEnd
472 | NumberDot Int
473 | NumberHexDigit
474 | NumberNoLeadingZero
478-- MISC
481data Space
482 = HasTab
483 | EndlessMultiComment
487-- TO REPORT
490toReport :: Code.Source -> Error -> Report.Report
491toReport source err =
492 case err of
493 ModuleNameUnspecified name ->
494 let
495 region = toRegion 1 1
496 in
497 Report.Report "MODULE NAME MISSING" region [] $
498 D.stack
499 [ D.reflow $
500 "I need the module name to be declared at the top of this file, like this:"
501 , D.indent 4 $ D.fillSep $
502 [ D.cyan "module", D.fromName name, D.cyan "exposing", "(..)" ]
503 , D.reflow $
504 "Try adding that as the first line of your file!"
505 , D.toSimpleNote $
506 "It is best to replace (..) with an explicit list of types and\
507 \ functions you want to expose. When you know a value is only used\
508 \ within this module, you can refactor without worrying about uses\
509 \ elsewhere. Limiting exposed values can also speed up compilation\
510 \ because I can skip a bunch of work if I see that the exposed API\
511 \ has not changed."
512 ]
514 ModuleNameMismatch expectedName (A.At region actualName) ->
515 Report.Report "MODULE NAME MISMATCH" region [ModuleName.toChars expectedName] $
516 Code.toSnippet source region Nothing
517 (
518 "It looks like this module name is out of sync:"
519 ,
520 D.stack
521 [ D.reflow $
522 "I need it to match the file path, so I was expecting it to see `"
523 ++ ModuleName.toChars expectedName
524 ++ "` here. Make the following change, and you should be all set!"
525 , D.indent 4 $
526 D.dullyellow (D.fromName actualName) <> " -> " <> D.green (D.fromName expectedName)
527 , D.toSimpleNote $
528 "I require that module names correspond to file paths. This makes it much\
529 \ easier to explore unfamiliar codebases! So if you want to keep the current\
530 \ module name, try renaming the file instead."
531 ]
532 )
534 UnexpectedPort region ->
535 Report.Report "UNEXPECTED PORTS" region [] $
536 Code.toSnippet source region Nothing
537 (
538 D.reflow $
539 "You are declaring ports in a normal module."
540 ,
541 D.stack
542 [ D.fillSep
543 ["Switch","this","to","say",D.cyan "port module","instead,"
544 ,"marking","that","this","module","contains","port","declarations."
545 ]
546 , D.link "Note"
547 "Ports are not a traditional FFI for calling JS functions directly. They need a different mindset! Read"
548 "ports"
549 "to learn the syntax and how to use it effectively."
550 ]
551 )
553 NoPorts region ->
554 Report.Report "NO PORTS" region [] $
555 Code.toSnippet source region Nothing
556 (
557 D.reflow $
558 "This module does not declare any ports, but it says it will:"
559 ,
560 D.fillSep
561 ["Switch","this","to",D.cyan "module"
562 ,"and","you","should","be","all","set!"
563 ]
564 )
566 ParseError modul ->
567 toParseErrorReport source modul
570toParseErrorReport :: Code.Source -> Module -> Report.Report
571toParseErrorReport source modul =
572 case modul of
573 ModuleSpace space row col ->
574 toSpaceReport source space row col
576 ModuleEndOfFile row col ->
577 case Code.whatIsNext source row col of
578 Code.Keyword keyword ->
579 let
580 region = toKeywordRegion row col keyword
581 in
582 Report.Report "RESERVED WORD" region [] $
583 Code.toSnippet source region Nothing
584 (
585 D.reflow $
586 "I got stuck on this reserved word:"
587 ,
588 D.reflow $
589 "The name `" ++ keyword ++ "` is reserved, so try using a different name?"
590 )
592 Code.Operator op ->
593 let
594 region = toKeywordRegion row col op
595 in
596 Report.Report "UNEXPECTED SYMBOL" region [] $
597 Code.toSnippet source region Nothing
598 (
599 D.reflow $
600 "I ran into an unexpected symbol:"
601 ,
602 D.reflow $
603 "I was not expecting to see a " ++ op ++ " here. Try deleting it? Maybe\
604 \ I can give a better hint from there?"
605 )
607 Code.Close term bracket ->
608 let
609 region = toRegion row col
610 in
611 Report.Report ("UNEXPECTED " ++ map Char.toUpper term) region [] $
612 Code.toSnippet source region Nothing
613 (
614 D.reflow $
615 "I ran into an unexpected " ++ term ++ ":"
616 ,
617 D.reflow $
618 "This " ++ bracket : " does not match up with an earlier open " ++ term ++ ". Try deleting it?"
619 )
621 Code.Other ->
622 let
623 region = toRegion row col
624 in
625 Report.Report "SYNTAX PROBLEM" region [] $
626 Code.toSnippet source region Nothing
627 (
628 D.reflow $
629 "I got stuck here:"
630 ,
631 D.reflow $
632 "Whatever I am running into is confusing me a lot! Normally I can give fairly\
633 \ specific hints, but something is really tripping me up this time."
634 )
636 ModuleProblem row col ->
637 let
638 region = toRegion row col
639 in
640 Report.Report "UNFINISHED MODULE DECLARATION" region [] $
641 Code.toSnippet source region Nothing
642 (
643 D.reflow $
644 "I am parsing an `module` declaration, but I got stuck here:"
645 ,
646 D.stack
647 [ D.reflow $
648 "Here are some examples of valid `module` declarations:"
649 , D.indent 4 $ D.vcat $
650 [ D.fillSep [D.cyan "module","Main",D.cyan "exposing","(..)"]
651 , D.fillSep [D.cyan "module","Dict",D.cyan "exposing","(Dict, empty, get)"]
652 ]
653 , D.reflow $
654 "I generally recommend using an explicit exposing list. I can skip compiling a bunch\
655 \ of files when the public interface of a module stays the same, so exposing fewer\
656 \ values can help improve compile times!"
657 ]
658 )
660 ModuleName row col ->
661 let
662 region = toRegion row col
663 in
664 Report.Report "EXPECTING MODULE NAME" region [] $
665 Code.toSnippet source region Nothing
666 (
667 D.reflow $
668 "I was parsing an `module` declaration until I got stuck here:"
669 ,
670 D.stack
671 [ D.reflow $
672 "I was expecting to see the module name next, like in these examples:"
673 , D.indent 4 $ D.vcat $
674 [ D.fillSep [D.cyan "module","Dict",D.cyan "exposing","(..)"]
675 , D.fillSep [D.cyan "module","Maybe",D.cyan "exposing","(..)"]
676 , D.fillSep [D.cyan "module","Html.Attributes",D.cyan "exposing","(..)"]
677 , D.fillSep [D.cyan "module","Json.Decode",D.cyan "exposing","(..)"]
678 ]
679 , D.reflow $
680 "Notice that the module names all start with capital letters. That is required!"
681 ]
682 )
684 ModuleExposing exposing row col ->
685 toExposingReport source exposing row col
687 PortModuleProblem row col ->
688 let
689 region = toRegion row col
690 in
691 Report.Report "UNFINISHED PORT MODULE DECLARATION" region [] $
692 Code.toSnippet source region Nothing
693 (
694 D.reflow $
695 "I am parsing an `port module` declaration, but I got stuck here:"
696 ,
697 D.stack
698 [ D.reflow $
699 "Here are some examples of valid `port module` declarations:"
700 , D.indent 4 $ D.vcat $
701 [ D.fillSep [D.cyan "port",D.cyan "module","WebSockets",D.cyan "exposing","(send, listen, keepAlive)"]
702 , D.fillSep [D.cyan "port",D.cyan "module","Maps",D.cyan "exposing","(Location, goto)"]
703 ]
704 , D.link "Note" "Read" "ports" "for more help."
705 ]
706 )
708 PortModuleName row col ->
709 let
710 region = toRegion row col
711 in
712 Report.Report "EXPECTING MODULE NAME" region [] $
713 Code.toSnippet source region Nothing
714 (
715 D.reflow $
716 "I was parsing an `module` declaration until I got stuck here:"
717 ,
718 D.stack
719 [ D.reflow $
720 "I was expecting to see the module name next, like in these examples:"
721 , D.indent 4 $ D.vcat $
722 [ D.fillSep [D.cyan "port",D.cyan "module","WebSockets",D.cyan "exposing","(send, listen, keepAlive)"]
723 , D.fillSep [D.cyan "port",D.cyan "module","Maps",D.cyan "exposing","(Location, goto)"]
724 ]
725 , D.reflow $
726 "Notice that the module names start with capital letters. That is required!"
727 ]
728 )
730 PortModuleExposing exposing row col ->
731 toExposingReport source exposing row col
733 Effect row col ->
734 let
735 region = toRegion row col
736 in
737 Report.Report "BAD MODULE DECLARATION" region [] $
738 Code.toSnippet source region Nothing
739 (
740 D.reflow $
741 "I cannot parse this module declaration:"
742 ,
743 D.reflow $
744 "This type of module is reserved for the @elm organization. It is used to\
745 \ define certain effects, avoiding building them into the compiler."
746 )
748 FreshLine row col ->
749 let
750 region = toRegion row col
752 toBadFirstLineReport keyword =
753 Report.Report "TOO MUCH INDENTATION" region [] $
754 Code.toSnippet source region Nothing
755 (
756 D.reflow $
757 "This `" ++ keyword ++ "` should not have any spaces before it:"
758 ,
759 D.reflow $
760 "Delete the spaces before `" ++ keyword ++ "` until there are none left!"
761 )
763 in
764 case Code.whatIsNext source row col of
765 Code.Keyword "module" -> toBadFirstLineReport "module"
766 Code.Keyword "import" -> toBadFirstLineReport "import"
767 Code.Keyword "type" -> toBadFirstLineReport "type"
768 Code.Keyword "port" -> toBadFirstLineReport "port"
769 _ ->
770 Report.Report "SYNTAX PROBLEM" region [] $
771 Code.toSnippet source region Nothing
772 (
773 D.reflow $
774 "I got stuck here:"
775 ,
776 D.stack
777 [ D.reflow $
778 "I am not sure what is going on, but I recommend starting an Elm\
779 \ file with the following lines:"
780 , D.vcat
781 [ D.fillSep [D.cyan "import","Html"]
782 , ""
783 , D.fillSep [D.green "main","="]
784 , D.indent 2 $ D.fillSep [D.cyan "Html" <> ".text",D.dullyellow "\"Hello!\""]
785 ]
786 , D.reflow $
787 "You should be able to copy those lines directly into your file. Check out\
788 \ some of the examples on https://elm-lang.org for more help getting started!"
789 , D.toSimpleNote $
790 "This can also happen when something is indented too much!"
791 ]
792 )
794 ImportStart row col ->
795 toImportReport source row col
797 ImportName row col ->
798 let
799 region = toRegion row col
800 in
801 Report.Report "EXPECTING IMPORT NAME" region [] $
802 Code.toSnippet source region Nothing
803 (
804 D.reflow $
805 "I was parsing an `import` until I got stuck here:"
806 ,
807 D.stack
808 [ D.reflow $
809 "I was expecting to see a module name next, like in these examples:"
810 , D.indent 4 $ D.vcat $
811 [ D.fillSep [D.cyan "import","Dict"]
812 , D.fillSep [D.cyan "import","Maybe"]
813 , D.fillSep [D.cyan "import","Html.Attributes"]
814 , D.fillSep [D.cyan "import","Json.Decode"]
815 ]
816 , D.reflow $
817 "Notice that the module names all start with capital letters. That is required!"
818 ]
819 )
821 ImportAs row col ->
822 toImportReport source row col
824 ImportAlias row col ->
825 let
826 region = toRegion row col
827 in
828 Report.Report "EXECTING IMPORT ALIAS" region [] $
829 Code.toSnippet source region Nothing
830 (
831 D.reflow $
832 "I was parsing an `import` until I got stuck here:"
833 ,
834 D.stack
835 [ D.reflow $
836 "I was expecting to see an alias next, like in these examples:"
837 , D.indent 4 $ D.vcat $
838 [ D.fillSep [D.cyan "import","Html.Attributes",D.cyan "as","Attr"]
839 , D.fillSep [D.cyan "import","WebGL.Texture",D.cyan "as","Texture"]
840 , D.fillSep [D.cyan "import","Json.Decode",D.cyan "as","D"]
841 ]
842 , D.reflow $
843 "Notice that the alias always starts with a capital letter. That is required!"
844 ]
845 )
847 ImportExposing row col ->
848 toImportReport source row col
850 ImportExposingList exposing row col ->
851 toExposingReport source exposing row col
853 ImportEnd row col ->
854 toImportReport source row col
856 ImportIndentName row col ->
857 toImportReport source row col
859 ImportIndentAlias row col ->
860 toImportReport source row col
862 ImportIndentExposingList row col ->
863 let
864 region = toRegion row col
865 in
866 Report.Report "UNFINISHED IMPORT" region [] $
867 Code.toSnippet source region Nothing
868 (
869 D.reflow $
870 "I was parsing an `import` until I got stuck here:"
871 ,
872 D.stack
873 [ D.reflow $
874 "I was expecting to see the list of exposed values next. For example, here\
875 \ are two ways to expose values from the `Html` module:"
876 , D.indent 4 $ D.vcat $
877 [ D.fillSep [D.cyan "import","Html",D.cyan "exposing","(..)"]
878 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
879 ]
880 , D.reflow $
881 "I generally recommend the second style. It is more explicit, making it\
882 \ much easier to figure out where values are coming from in large projects!"
883 ]
884 )
886 Infix row col ->
887 let
888 region = toRegion row col
889 in
890 Report.Report "BAD INFIX" region [] $
891 Code.toSnippet source region Nothing
892 (
893 D.reflow $
894 "Something went wrong in this infix operator declaration:"
895 ,
896 D.reflow $
897 "This feature is used by the @elm organization to define the\
898 \ languages built-in operators."
899 )
901 Declarations decl _ _ ->
902 toDeclarationsReport source decl
906-- IMPORTS
909toImportReport :: Code.Source -> Row -> Col -> Report.Report
910toImportReport source row col =
911 let
912 region = toRegion row col
913 in
914 Report.Report "UNFINISHED IMPORT" region [] $
915 Code.toSnippet source region Nothing
916 (
917 D.reflow $
918 "I am partway through parsing an import, but I got stuck here:"
919 ,
920 D.stack
921 [ D.reflow $
922 "Here are some examples of valid `import` declarations:"
923 , D.indent 4 $ D.vcat $
924 [ D.fillSep [D.cyan "import","Html"]
925 , D.fillSep [D.cyan "import","Html",D.cyan "as","H"]
926 , D.fillSep [D.cyan "import","Html",D.cyan "as","H",D.cyan "exposing","(..)"]
927 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
928 ]
929 , D.reflow $
930 "You are probably trying to import a different module, but try to make it look like one of these examples!"
931 ]
932 )
936-- EXPOSING
939toExposingReport :: Code.Source -> Exposing -> Row -> Col -> Report.Report
940toExposingReport source exposing startRow startCol =
941 case exposing of
942 ExposingSpace space row col ->
943 toSpaceReport source space row col
945 ExposingStart row col ->
946 let
947 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
948 region = toRegion row col
949 in
950 Report.Report "PROBLEM IN EXPOSING" region [] $
951 Code.toSnippet source surroundings (Just region)
952 (
953 D.reflow $
954 "I want to parse exposed values, but I am getting stuck here:"
955 ,
956 D.stack
957 [ D.fillSep $
958 ["Exposed","values","are","always","surrounded","by","parentheses."
959 ,"So","try","adding","a",D.green "(","here?"
960 ]
961 , D.toSimpleNote "Here are some valid examples of `exposing` for reference:"
962 , D.indent 4 $ D.vcat $
963 [ D.fillSep [D.cyan "import","Html",D.cyan "exposing","(..)"]
964 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
965 ]
966 , D.reflow $
967 "If you are getting tripped up, you can just expose everything for now. It should\
968 \ get easier to make an explicit exposing list as you see more examples in the wild."
969 ]
970 )
972 ExposingValue row col ->
973 case Code.whatIsNext source row col of
974 Code.Keyword keyword ->
975 let
976 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
977 region = toKeywordRegion row col keyword
978 in
979 Report.Report "RESERVED WORD" region [] $
980 Code.toSnippet source surroundings (Just region)
981 (
982 D.reflow $
983 "I got stuck on this reserved word:"
984 ,
985 D.reflow $
986 "It looks like you are trying to expose `" ++ keyword ++ "` but that is a reserved word. Is there a typo?"
987 )
989 Code.Operator op ->
990 let
991 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
992 region = toKeywordRegion row col op
993 in
994 Report.Report "UNEXPECTED SYMBOL" region [] $
995 Code.toSnippet source surroundings (Just region)
996 (
997 D.reflow $
998 "I got stuck on this symbol:"
999 ,
1000 D.stack
1001 [ D.reflow $
1002 "If you are trying to expose an operator, add parentheses around it like this:"
1003 , D.indent 4 $ D.dullyellow (D.fromChars op) <> " -> " <> D.green ("(" <> D.fromChars op <> ")")
1007 _ ->
1008 let
1009 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1010 region = toRegion row col
1011 in
1012 Report.Report "PROBLEM IN EXPOSING" region [] $
1013 Code.toSnippet source surroundings (Just region)
1015 D.reflow $
1016 "I got stuck while parsing these exposed values:"
1018 D.stack
1019 [ D.reflow $
1020 "I do not have an exact recommendation, so here are some valid examples\
1021 \ of `exposing` for reference:"
1022 , D.indent 4 $ D.vcat $
1023 [ D.fillSep [D.cyan "import","Html",D.cyan "exposing","(..)"]
1024 , D.fillSep [D.cyan "import","Basics",D.cyan "exposing","(Int, Float, Bool(..), (+), not, sqrt)"]
1026 , D.reflow $
1027 "These examples show how to expose types, variants, operators, and functions. Everything\
1028 \ should be some permutation of these examples, just with different names."
1032 ExposingOperator row col ->
1033 let
1034 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1035 region = toRegion row col
1036 in
1037 Report.Report "PROBLEM IN EXPOSING" region [] $
1038 Code.toSnippet source surroundings (Just region)
1040 D.reflow $
1041 "I just saw an open parenthesis, so I was expecting an operator next:"
1043 D.fillSep $
1044 ["It","is","possible","to","expose","operators,","so","I","was","expecting"
1045 ,"to","see","something","like",D.dullyellow "(+)","or",D.dullyellow "(|=)"
1046 ,"or",D.dullyellow "(||)","after","I","saw","that","open","parenthesis."
1050 ExposingOperatorReserved op row col ->
1051 let
1052 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1053 region = toRegion row col
1054 in
1055 Report.Report "RESERVED SYMBOL" region [] $
1056 Code.toSnippet source surroundings (Just region)
1058 D.reflow $
1059 "I cannot expose this as an operator:"
1061 case op of
1062 BadDot -> D.reflow "Try getting rid of this entry? Maybe I can give you a better hint after that?"
1063 BadPipe -> D.fillSep ["Maybe","you","want",D.dullyellow "(||)","instead?"]
1064 BadArrow -> D.reflow "Try getting rid of this entry? Maybe I can give you a better hint after that?"
1065 BadEquals -> D.fillSep ["Maybe","you","want",D.dullyellow "(==)","instead?"]
1066 BadHasType -> D.fillSep ["Maybe","you","want",D.dullyellow "(::)","instead?"]
1069 ExposingOperatorRightParen row col ->
1070 let
1071 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1072 region = toRegion row col
1073 in
1074 Report.Report "PROBLEM IN EXPOSING" region [] $
1075 Code.toSnippet source surroundings (Just region)
1077 D.reflow $
1078 "It looks like you are exposing an operator, but I got stuck here:"
1080 D.fillSep $
1081 ["I","was","expecting","to","see","the","closing","parenthesis","immediately"
1082 ,"after","the","operator.","Try","adding","a",D.green ")","right","here?"
1086 ExposingEnd row col ->
1087 let
1088 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1089 region = toRegion row col
1090 in
1091 Report.Report "UNFINISHED EXPOSING" region [] $
1092 Code.toSnippet source surroundings (Just region)
1094 D.reflow $
1095 "I was partway through parsing exposed values, but I got stuck here:"
1097 D.reflow $
1098 "Maybe there is a comma missing before this?"
1101 ExposingTypePrivacy row col ->
1102 let
1103 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1104 region = toRegion row col
1105 in
1106 Report.Report "PROBLEM EXPOSING CUSTOM TYPE VARIANTS" region [] $
1107 Code.toSnippet source surroundings (Just region)
1109 D.reflow $
1110 "It looks like you are trying to expose the variants of a custom type:"
1112 D.stack
1113 [ D.fillSep $
1114 ["You","need","to","write","something","like"
1115 ,D.dullyellow "Status(..)","or",D.dullyellow "Entity(..)"
1116 ,"though.","It","is","all","or","nothing,","otherwise","`case`"
1117 ,"expressions","could","miss","a","variant","and","crash!"
1119 , D.toSimpleNote $
1120 "It is often best to keep the variants hidden! If someone pattern matches on\
1121 \ the variants, it is a MAJOR change if any new variants are added. Suddenly\
1122 \ their `case` expressions do not cover all variants! So if you do not need\
1123 \ people to pattern match, keep the variants hidden and expose functions to\
1124 \ construct values of this type. This way you can add new variants as a MINOR change!"
1128 ExposingIndentEnd row col ->
1129 let
1130 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1131 region = toRegion row col
1132 in
1133 Report.Report "UNFINISHED EXPOSING" region [] $
1134 Code.toSnippet source surroundings (Just region)
1136 D.reflow $
1137 "I was partway through parsing exposed values, but I got stuck here:"
1139 D.stack
1140 [ D.fillSep $
1141 ["I","was","expecting","a","closing","parenthesis."
1142 ,"Try","adding","a",D.green ")","right","here?"
1144 , D.toSimpleNote $
1145 "I can get confused when there is not enough indentation, so if you already\
1146 \ have a closing parenthesis, it probably just needs some spaces in front of it."
1150 ExposingIndentValue row col ->
1151 let
1152 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1153 region = toRegion row col
1154 in
1155 Report.Report "UNFINISHED EXPOSING" region [] $
1156 Code.toSnippet source surroundings (Just region)
1158 D.reflow $
1159 "I was partway through parsing exposed values, but I got stuck here:"
1161 D.reflow $
1162 "I was expecting another value to expose."
1167-- SPACES
1170toSpaceReport :: Code.Source -> Space -> Row -> Col -> Report.Report
1171toSpaceReport source space row col =
1172 case space of
1173 HasTab ->
1174 let
1175 region = toRegion row col
1176 in
1177 Report.Report "NO TABS" region [] $
1178 Code.toSnippet source region Nothing
1180 D.reflow $
1181 "I ran into a tab, but tabs are not allowed in Elm files."
1183 D.reflow $
1184 "Replace the tab with spaces."
1187 EndlessMultiComment ->
1188 let
1189 region = toWiderRegion row col 2
1190 in
1191 Report.Report "ENDLESS COMMENT" region [] $
1192 Code.toSnippet source region Nothing
1194 D.reflow $
1195 "I cannot find the end of this multi-line comment:"
1197 D.stack -- "{-"
1198 [ D.reflow "Add a -} somewhere after this to end the comment."
1199 , D.toSimpleHint
1200 "Multi-line comments can be nested in Elm, so {- {- -} -} is a comment\
1201 \ that happens to contain another comment. Like parentheses and curly braces,\
1202 \ the start and end markers must always be balanced. Maybe that is the problem?"
1208-- DECLARATIONS
1211toRegion :: Row -> Col -> A.Region
1212toRegion row col =
1213 let
1214 pos = A.Position row col
1215 in
1216 A.Region pos pos
1219toWiderRegion :: Row -> Col -> Word16 -> A.Region
1220toWiderRegion row col extra =
1221 A.Region
1222 (A.Position row col)
1223 (A.Position row (col + extra))
1226toKeywordRegion :: Row -> Col -> [Char.Char] -> A.Region
1227toKeywordRegion row col keyword =
1228 A.Region
1229 (A.Position row col)
1230 (A.Position row (col + fromIntegral (length keyword)))
1233toDeclarationsReport :: Code.Source -> Decl -> Report.Report
1234toDeclarationsReport source decl =
1235 case decl of
1236 DeclStart row col ->
1237 error "TODO DeclStart" row col
1239 DeclSpace space row col ->
1240 toSpaceReport source space row col
1242 Port port_ row col ->
1243 error "TODO Port" port_ row col
1245 DeclType declType row col ->
1246 toDeclTypeReport source declType row col
1248 DeclDef name declDef row col ->
1249 toDeclDefReport source name declDef row col
1251 DeclFreshLineStart row col ->
1252 error "TODO DeclFreshLineStart" row col
1254 DeclFreshLineAfterDocComment row col ->
1255 error "TODO DeclFreshLineAfterDocComment" row col
1259-- DECL TYPE
1262toDeclTypeReport :: Code.Source -> DeclType -> Row -> Col -> Report.Report
1263toDeclTypeReport source declType startRow startCol =
1264 case declType of
1265 DT_Space space row col ->
1266 toSpaceReport source space row col
1268 DT_Name row col ->
1269 let
1270 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1271 region = toRegion row col
1272 in
1273 Report.Report "EXPECTING TYPE NAME" region [] $
1274 Code.toSnippet source surroundings (Just region)
1276 D.reflow $
1277 "I think I am parsing a type declaration, but I got stuck here:"
1279 D.stack
1280 [ D.fillSep $
1281 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1282 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1284 , customTypeNote
1288 DT_Alias typeAlias row col ->
1289 toTypeAliasReport source typeAlias row col
1291 DT_Union customType row col ->
1292 toCustomTypeReport source customType row col
1294 DT_IndentName row col ->
1295 let
1296 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1297 region = toRegion row col
1298 in
1299 Report.Report "EXPECTING TYPE NAME" region [] $
1300 Code.toSnippet source surroundings (Just region)
1302 D.reflow $
1303 "I think I am parsing a type declaration, but I got stuck here:"
1305 D.stack
1306 [ D.fillSep $
1307 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1308 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1310 , customTypeNote
1315toTypeAliasReport :: Code.Source -> TypeAlias -> Row -> Col -> Report.Report
1316toTypeAliasReport source typeAlias startRow startCol =
1317 case typeAlias of
1318 AliasSpace space row col ->
1319 toSpaceReport source space row col
1321 AliasName row col ->
1322 let
1323 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1324 region = toRegion row col
1325 in
1326 Report.Report "EXPECTING TYPE ALIAS NAME" region [] $
1327 Code.toSnippet source surroundings (Just region)
1329 D.reflow $
1330 "I am partway through parsing a type alias, but I got stuck here:"
1332 D.stack
1333 [ D.fillSep $
1334 ["I","was","expecting","a","name","like",D.dullyellow "Person","or",D.dullyellow "Point"
1335 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1337 , typeAliasNote
1341 AliasEquals row col ->
1342 case Code.whatIsNext source row col of
1343 Code.Keyword keyword ->
1344 let
1345 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1346 region = toKeywordRegion row col keyword
1347 in
1348 Report.Report "RESERVED WORD" region [] $
1349 Code.toSnippet source surroundings (Just region)
1351 D.reflow $
1352 "I ran into a reserved word unexpectedly while parsing this type alias:"
1354 D.stack
1355 [ D.reflow $
1356 "It looks like you are trying use `" ++ keyword
1357 ++ "` as a type variable, but it is a reserved word. Try using a different name?"
1358 , typeAliasNote
1362 _ ->
1363 let
1364 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1365 region = toRegion row col
1366 in
1367 Report.Report "PROBLEM IN TYPE ALIAS" region [] $
1368 Code.toSnippet source surroundings (Just region)
1370 D.reflow $
1371 "I am partway through parsing a type alias, but I got stuck here:"
1373 D.stack
1374 [ D.reflow $
1375 "I was expecting to see a type variable or an an equals sign next."
1376 , typeAliasNote
1380 AliasBody tipe row col ->
1381 toTypeReport source tipe row col
1383 AliasIndentEquals row col ->
1384 let
1385 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1386 region = toRegion row col
1387 in
1388 Report.Report "UNFINISHED TYPE ALIAS" region [] $
1389 Code.toSnippet source surroundings (Just region)
1391 D.reflow $
1392 "I am partway through parsing a type alias, but I got stuck here:"
1394 D.stack
1395 [ D.reflow $
1396 "I was expecting to see a type variable or an an equals sign next."
1397 , typeAliasNote
1401 AliasIndentBody row col ->
1402 let
1403 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1404 region = toRegion row col
1405 in
1406 Report.Report "UNFINISHED TYPE ALIAS" region [] $
1407 Code.toSnippet source surroundings (Just region)
1409 D.reflow $
1410 "I am partway through parsing a type alias, but I got stuck here:"
1412 D.stack
1413 [ D.fillSep $
1414 ["I","was","expecting","to","see","a","type","next.","Something","as","simple"
1415 ,"as",D.dullyellow "Int","or",D.dullyellow "Float","would","work!"
1417 , typeAliasNote
1422typeAliasNote :: D.Doc
1423typeAliasNote =
1424 D.stack
1425 [ D.toSimpleNote $
1426 "Here is an example of a valid `type alias` for reference:"
1427 , D.vcat $
1428 [ D.indent 0 $ D.fillSep [D.cyan "type",D.cyan "alias",D.green "Person","="]
1429 , D.indent 2 $ D.vcat $
1430 ["{ name : String"
1431 ,", age : Int"
1432 ,", height : Float"
1433 ,"}"
1436 , D.reflow $
1437 "This would let us use `Person` as a shorthand for that record type. Using this\
1438 \ shorthand makes type annotations much easier to read, and makes changing code\
1439 \ easier if you decide later that there is more to a person than age and height!"
1443toCustomTypeReport :: Code.Source -> CustomType -> Row -> Col -> Report.Report
1444toCustomTypeReport source customType startRow startCol =
1445 case customType of
1446 CT_Space space row col ->
1447 toSpaceReport source space row col
1449 CT_Name row col ->
1450 let
1451 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1452 region = toRegion row col
1453 in
1454 Report.Report "EXPECTING TYPE NAME" region [] $
1455 Code.toSnippet source surroundings (Just region)
1457 D.reflow $
1458 "I think I am parsing a type declaration, but I got stuck here:"
1460 D.stack
1461 [ D.fillSep $
1462 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1463 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1465 , customTypeNote
1469 CT_Equals row col ->
1470 case Code.whatIsNext source row col of
1471 Code.Keyword keyword ->
1472 let
1473 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1474 region = toKeywordRegion row col keyword
1475 in
1476 Report.Report "RESERVED WORD" region [] $
1477 Code.toSnippet source surroundings (Just region)
1479 D.reflow $
1480 "I ran into a reserved word unexpectedly while parsing this custom type:"
1482 D.stack
1483 [ D.reflow $
1484 "It looks like you are trying use `" ++ keyword
1485 ++ "` as a type variable, but it is a reserved word. Try using a different name?"
1486 , customTypeNote
1490 _ ->
1491 let
1492 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1493 region = toRegion row col
1494 in
1495 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
1496 Code.toSnippet source surroundings (Just region)
1498 D.reflow $
1499 "I am partway through parsing a custom type, but I got stuck here:"
1501 D.stack
1502 [ D.reflow $
1503 "I was expecting to see a type variable or an an equals sign next."
1504 , customTypeNote
1508 CT_Bar row col ->
1509 let
1510 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1511 region = toRegion row col
1512 in
1513 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
1514 Code.toSnippet source surroundings (Just region)
1516 D.reflow $
1517 "I am partway through parsing a custom type, but I got stuck here:"
1519 D.stack
1520 [ D.reflow $
1521 "I was expecting to see a vertical bar like | next."
1522 , customTypeNote
1526 CT_Variant row col ->
1527 let
1528 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1529 region = toRegion row col
1530 in
1531 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
1532 Code.toSnippet source surroundings (Just region)
1534 D.reflow $
1535 "I am partway through parsing a custom type, but I got stuck here:"
1537 D.stack
1538 [ D.fillSep $
1539 ["I","was","expecting","to","see","a","variant","name","next."
1540 ,"Something","like",D.dullyellow "Success","or",D.dullyellow "Sandwich" <> "."
1541 ,"Any","name","that","starts","with","a","capital","letter","really!"
1543 , customTypeNote
1547 CT_VariantArg tipe row col ->
1548 toTypeReport source tipe row col
1550 CT_IndentEquals row col ->
1551 let
1552 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1553 region = toRegion row col
1554 in
1555 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1556 Code.toSnippet source surroundings (Just region)
1558 D.reflow $
1559 "I am partway through parsing a custom type, but I got stuck here:"
1561 D.stack
1562 [ D.reflow $
1563 "I was expecting to see a type variable or an an equals sign next."
1564 , customTypeNote
1568 CT_IndentBar row col ->
1569 let
1570 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1571 region = toRegion row col
1572 in
1573 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1574 Code.toSnippet source surroundings (Just region)
1576 D.reflow $
1577 "I am partway through parsing a custom type, but I got stuck here:"
1579 D.stack
1580 [ D.reflow $
1581 "I was expecting to see a vertical bar like | next."
1582 , customTypeNote
1586 CT_IndentAfterBar row col ->
1587 let
1588 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1589 region = toRegion row col
1590 in
1591 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1592 Code.toSnippet source surroundings (Just region)
1594 D.reflow $
1595 "I am partway through parsing a custom type, but I got stuck here:"
1597 D.stack
1598 [ D.reflow $
1599 "I just saw a vertical bar, so I was expecting to see another variant defined next."
1600 , customTypeNote
1604 CT_IndentAfterEquals row col ->
1605 let
1606 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1607 region = toRegion row col
1608 in
1609 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1610 Code.toSnippet source surroundings (Just region)
1612 D.reflow $
1613 "I am partway through parsing a custom type, but I got stuck here:"
1615 D.stack
1616 [ D.reflow $
1617 "I just saw an equals sign, so I was expecting to see the first variant defined next."
1618 , customTypeNote
1623customTypeNote :: D.Doc
1624customTypeNote =
1625 D.stack
1626 [ D.toSimpleNote $
1627 "Here is an example of a valid `type` declaration for reference:"
1628 , D.vcat $
1629 [ D.indent 0 $ D.fillSep [D.cyan "type",D.green "Status"]
1630 , D.indent 2 $ D.fillSep ["=","Failure"]
1631 , D.indent 2 $ D.fillSep ["|","Waiting"]
1632 , D.indent 2 $ D.fillSep ["|","Success","String"]
1634 , D.reflow $
1635 "This defines a new `Status` type with three variants. This could be useful if\
1636 \ we are waiting for an HTTP request. Maybe we start with `Waiting` and then\
1637 \ switch to `Failure` or `Success \"message from server\"` depending on how\
1638 \ things go. Notice that the Success variant has some associated data, allowing\
1639 \ us to store a String if the request goes well!"
1644-- DECL DEF
1647toDeclDefReport :: Code.Source -> Name.Name -> DeclDef -> Row -> Col -> Report.Report
1648toDeclDefReport source name declDef startRow startCol =
1649 case declDef of
1650 DeclDefSpace space row col ->
1651 toSpaceReport source space row col
1653 DeclDefEquals row col ->
1654 case Code.whatIsNext source row col of
1655 Code.Keyword keyword ->
1656 let
1657 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1658 region = toKeywordRegion row col keyword
1659 in
1660 Report.Report "RESERVED WORD" region [] $
1661 Code.toSnippet source surroundings (Just region)
1663 D.reflow $
1664 "It looks like you are trying to use `" ++ keyword ++ "` as an argument:"
1666 D.reflow $
1667 "This is a reserved word! Try using some other name?"
1670 Code.Operator op ->
1671 let
1672 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1673 region = toKeywordRegion row col op
1674 in
1675 Report.Report "UNEXPECTED SYMBOL" region [] $
1676 Code.toSnippet source surroundings (Just region)
1678 D.reflow $
1679 "I was not expecting to see this symbol here:"
1681 D.stack
1682 [ D.reflow $
1683 "I am not sure what is going wrong exactly, so here is a valid\
1684 \ definition (with an optional type annotation) for reference:"
1685 , D.vcat
1686 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
1687 , D.fillSep [D.green "add","x","y","="]
1688 , D.fillSep [" ","x","+","y"]
1690 , D.reflow $
1691 "Try to use that format with your `" ++ Name.toChars name ++ "` definition!"
1695 _ ->
1696 let
1697 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1698 region = toRegion row col
1699 in
1700 Report.Report "PROBLEM IN DEFINITION" region [] $
1701 Code.toSnippet source surroundings (Just region)
1703 D.reflow $
1704 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
1706 D.stack
1707 [ D.reflow $
1708 "I am not sure what is going wrong exactly, so here is a valid\
1709 \ definition (with an optional type annotation) for reference:"
1710 , D.vcat
1711 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
1712 , D.fillSep [D.green "add","x","y","="]
1713 , D.fillSep [" ","x","+","y"]
1715 , D.reflow $
1716 "Try to use that format!"
1720 DeclDefType tipe row col ->
1721 toTypeReport source tipe row col
1723 DeclDefArg pattern row col ->
1724 toPatternReport source PArg pattern row col
1726 DeclDefBody expr row col ->
1727 toExprReport source (InDef name startRow startCol) expr row col
1729 DeclDefNameRepeat row col ->
1730 let
1731 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1732 region = toRegion row col
1733 in
1734 Report.Report "EXPECTING DEFINITION" region [] $
1735 Code.toSnippet source surroundings (Just region)
1737 D.reflow $
1738 "I just saw the type annotation for `" ++ Name.toChars name
1739 ++ "` so I was expecting to see its definition here:"
1741 D.stack
1742 [ D.reflow $
1743 "Type annotations always appear directly above the relevant\
1744 \ definition, without anything else (even doc comments) in between."
1745 , declDefNote
1749 DeclDefNameMatch defName row col ->
1750 let
1751 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1752 region = toRegion row col
1753 in
1754 Report.Report "NAME MISMATCH" region [] $
1755 Code.toSnippet source surroundings (Just region)
1757 D.reflow $
1758 "I just saw a type annotation for `" ++ Name.toChars name ++ "`, but it is followed by a definition for `" ++ Name.toChars defName ++ "`:"
1760 D.stack
1761 [ D.reflow $
1762 "These names do not match! Is there a typo?"
1763 , D.indent 4 $ D.fillSep $
1764 [D.dullyellow (D.fromName defName),"->",D.green (D.fromName name)]
1768 DeclDefIndentType row col ->
1769 let
1770 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1771 region = toRegion row col
1772 in
1773 Report.Report "UNFINISHED DEFINITION" region [] $
1774 Code.toSnippet source surroundings (Just region)
1776 D.reflow $
1777 "I got stuck while parsing the `" ++ Name.toChars name ++ "` type annotation:"
1779 D.stack
1780 [ D.reflow $
1781 "I just saw a colon, so I am expecting to see a type next."
1782 , declDefNote
1786 DeclDefIndentEquals row col ->
1787 let
1788 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1789 region = toRegion row col
1790 in
1791 Report.Report "UNFINISHED DEFINITION" region [] $
1792 Code.toSnippet source surroundings (Just region)
1794 D.reflow $
1795 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
1797 D.stack
1798 [ D.reflow $
1799 "I was expecting to see an argument or an equals sign next."
1800 , declDefNote
1804 DeclDefIndentBody row col ->
1805 let
1806 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1807 region = toRegion row col
1808 in
1809 Report.Report "UNFINISHED DEFINITION" region [] $
1810 Code.toSnippet source surroundings (Just region)
1812 D.reflow $
1813 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
1815 D.stack
1816 [ D.reflow $
1817 "I was expecting to see an expression next. What is it equal to?"
1818 , declDefNote
1823declDefNote :: D.Doc
1824declDefNote =
1825 D.stack
1826 [ D.reflow $
1827 "Here is a valid definition (with a type annotation) for reference:"
1828 , D.vcat
1829 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
1830 , D.fillSep [D.green "add","x","y","="]
1831 , D.fillSep [" ","x","+","y"]
1833 , D.reflow $
1834 "The top line (called a \"type annotation\") is optional. You can leave it off\
1835 \ if you want. As you get more comfortable with Elm and as your project grows,\
1836 \ it becomes more and more valuable to add them though! They work great as\
1837 \ compiler-verified documentation, and they often improve error messages!"
1842-- CONTEXT
1845data Context
1846 = InNode Node Row Col Context
1847 | InDef Name.Name Row Col
1850data Node
1851 = NRecord
1852 | NParens
1853 | NList
1854 | NFunc
1855 | NCond
1856 | NThen
1857 | NElse
1858 | NCase
1859 | NBranch
1860 deriving (Eq)
1863getDefName :: Context -> Name.Name
1864getDefName context =
1865 case context of
1866 InDef name _ _ -> name
1867 InNode _ _ _ c -> getDefName c
1870isWithin :: Node -> Context -> Bool
1871isWithin desiredNode context =
1872 case context of
1873 InDef _ _ _ -> False
1874 InNode actualNode _ _ _ -> desiredNode == actualNode
1878-- EXPR REPORTS
1881toExprReport :: Code.Source -> Context -> Expr -> Row -> Col -> Report.Report
1882toExprReport source context expr startRow startCol =
1883 case expr of
1884 Let let_ row col ->
1885 toLetReport source context let_ row col
1887 Case case_ row col ->
1888 toCaseReport source context case_ row col
1890 If if_ row col ->
1891 toIfReport source context if_ row col
1893 List list row col ->
1894 toListReport source context list row col
1896 Record record row col ->
1897 toRecordReport source context record row col
1899 Tuple tuple row col ->
1900 toTupleReport source context tuple row col
1902 Func func row col ->
1903 toFuncReport source context func row col
1905 Dot row col ->
1906 let region = toRegion row col in
1907 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
1908 Code.toSnippet source region Nothing
1910 D.reflow $
1911 "I was expecting to see a record accessor here:"
1913 D.fillSep
1914 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
1915 ,"that","accesses","a","value","from","a","record."
1919 Access row col ->
1920 let region = toRegion row col in
1921 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
1922 Code.toSnippet source region Nothing
1924 D.reflow $
1925 "I am trying to parse a record accessor here:"
1927 D.stack
1929 D.fillSep
1930 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
1931 ,"that","accesses","a","value","from","a","record."
1934 D.toSimpleNote $
1935 "Record field names must start with a lower case letter!"
1939 OperatorRight op row col ->
1940 let region = toRegion row col in
1941 Report.Report "MISSING EXPRESSION" region [] $
1942 Code.toSnippet source region Nothing
1944 D.reflow $
1945 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
1947 D.stack
1948 [ D.fillSep $
1949 ["You","can","just","put","anything","for","now,","like"
1950 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1951 ,"Once","there","is","something","there,","I","can","probably"
1952 ,"give","a","more","specific","hint!"
1954 , D.toSimpleNote $
1955 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
1956 \ Or if I run into operators in unexpected spots. Point is, there are a\
1957 \ couple ways I can get confused and give sort of weird advice!"
1961 OperatorReserved operator row col ->
1962 toOperatorReport source context operator row col
1964 Start row col ->
1965 let
1966 (contextRow, contextCol, aThing) =
1967 case context of
1968 InDef name r c -> (r, c, "the `" ++ Name.toChars name ++ "` definition")
1969 InNode NRecord r c _ -> (r, c, "a record")
1970 InNode NParens r c _ -> (r, c, "some parentheses")
1971 InNode NList r c _ -> (r, c, "a list")
1972 InNode NFunc r c _ -> (r, c, "an anonymous function")
1973 InNode NCond r c _ -> (r, c, "an `if` expression")
1974 InNode NThen r c _ -> (r, c, "an `if` expression")
1975 InNode NElse r c _ -> (r, c, "an `if` expression")
1976 InNode NCase r c _ -> (r, c, "a `case` expression")
1977 InNode NBranch r c _ -> (r, c, "a `case` expression")
1978 -- TODO check if this is actually the best way to get error messages here
1980 surroundings = A.Region (A.Position contextRow contextCol) (A.Position row col)
1981 region = toRegion row col
1982 in
1983 Report.Report "MISSING EXPRESSION" region [] $
1984 Code.toSnippet source surroundings (Just region)
1986 D.reflow $
1987 "I am partway through parsing " ++ aThing ++ ", but I got stuck here:"
1989 D.stack
1990 [ D.fillSep $
1991 ["I","was","expecting","to","see","an","expression","like"
1992 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1993 ,"Once","there","is","something","there,","I","can","probably"
1994 ,"give","a","more","specific","hint!"
1996 , D.toSimpleNote $
1997 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
1998 \ Or if I run into operators in unexpected spots. Point is, there are a\
1999 \ couple ways I can get confused and give sort of weird advice!"
2003 Char char row col ->
2004 toCharReport source char row col
2006 String string row col ->
2007 toStringReport source string row col
2009 Number number row col ->
2010 toNumberReport source number row col
2012 Space space row col ->
2013 toSpaceReport source space row col
2015 EndlessShader row col ->
2016 let
2017 region = toWiderRegion row col 6
2018 in
2019 Report.Report "ENDLESS SHADER" region [] $
2020 Code.toSnippet source region Nothing
2022 D.reflow "I cannot find the end of this shader:"
2024 D.reflow "Add a |] somewhere after this to end the shader."
2027 ShaderProblem problem row col ->
2028 let
2029 region = toRegion row col
2030 in
2031 Report.Report "SHADER PROBLEM" region [] $
2032 Code.toSnippet source region Nothing
2034 D.reflow $
2035 "I ran into a problem while parsing this GLSL block."
2037 D.stack
2038 [ D.reflow $
2039 "I use a 3rd party GLSL parser for now, and I did my best to extract their error message:"
2040 , D.indent 4 $ D.vcat $
2041 map D.fromChars (filter (/="") (lines problem))
2045 IndentOperatorRight op row col ->
2046 let
2047 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2048 region = toRegion row col
2049 in
2050 Report.Report "MISSING EXPRESSION" region [] $
2051 Code.toSnippet source surroundings (Just region)
2053 D.reflow $
2054 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
2056 D.stack
2058 D.fillSep $
2059 ["You","can","just","put","anything","for","now,","like"
2060 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
2061 ,"Once","there","is","something","there,","I","can","probably"
2062 ,"give","a","more","specific","hint!"
2065 D.toSimpleNote $
2066 "I may be getting confused by your indentation? The easiest way to make sure\
2067 \ this is not an indentation problem is to put the expression on the right of\
2068 \ the " ++ Name.toChars op ++ " operator on the same line."
2072 IndentMoreExpr _ _ ->
2073 error "TODO IndentMoreExpr"
2077-- CHAR
2080toCharReport :: Code.Source -> Char -> Row -> Col -> Report.Report
2081toCharReport source char row col =
2082 case char of
2083 CharEndless ->
2084 let
2085 region = toRegion row col
2086 in
2087 Report.Report "MISSING SINGLE QUOTE" region [] $
2088 Code.toSnippet source region Nothing
2090 D.reflow $
2091 "I thought I was parsing a character, but I got to the end of\
2092 \ the line without seeing the closing single quote:"
2094 D.reflow $
2095 "Add a closing single quote here!"
2098 CharEscape escape ->
2099 toEscapeReport source escape row col
2101 CharNotString width ->
2102 let
2103 region = toWiderRegion row col width
2104 in
2105 Report.Report "NEEDS DOUBLE QUOTES" region [] $
2106 Code.toSnippet source region Nothing
2108 "The following string uses single quotes:"
2110 D.stack
2111 [ "Please switch to double quotes instead:"
2112 , D.indent 4 $
2113 D.dullyellow "'this'" <> " => " <> D.green "\"this\""
2114 , D.toSimpleNote $
2115 "Elm uses double quotes for strings like \"hello\", whereas it uses single\
2116 \ quotes for individual characters like 'a' and 'ø'. This distinction helps with\
2117 \ code like (String.any (\\c -> c == 'X') \"90210\") where you are inspecting\
2118 \ individual characters."
2124-- STRING
2127toStringReport :: Code.Source -> String -> Row -> Col -> Report.Report
2128toStringReport source string row col =
2129 case string of
2130 StringEndless_Single ->
2131 let
2132 region = toRegion row col
2133 in
2134 Report.Report "ENDLESS STRING" region [] $
2135 Code.toSnippet source region Nothing
2137 D.reflow $
2138 "I got to the end of the line without seeing the closing double quote:"
2140 D.stack
2141 [ D.fillSep $
2142 ["Strings","look","like",D.green "\"this\"","with","double"
2143 ,"quotes","on","each","end.","Is","the","closing","double"
2144 ,"quote","missing","in","your","code?"
2146 , D.link "Note" "Read" "TODO" "if you want a string that spans multiple lines."
2150 StringEndless_Multi ->
2151 let
2152 region = toWiderRegion row col 3
2153 in
2154 Report.Report "ENDLESS STRING" region [] $
2155 Code.toSnippet source region Nothing
2157 D.reflow $
2158 "I cannot find the end of this multi-line string:"
2160 D.stack
2161 [ D.reflow "Add a \"\"\" somewhere after this to end the string."
2162 , D.link "Hint" "Read" "TODO" "for more information on strings and multi-line strings."
2166 StringEscape escape ->
2167 toEscapeReport source escape row col
2171-- ESCAPES
2174toEscapeReport :: Code.Source -> Escape -> Row -> Col -> Report.Report
2175toEscapeReport source escape row col =
2176 case escape of
2177 EscapeUnknown ->
2178 let
2179 region = toWiderRegion row col 2
2180 in
2181 Report.Report "UNKNOWN ESCAPE" region [] $
2182 Code.toSnippet source region Nothing
2184 D.reflow $
2185 "Backslashes always start escaped characters, but I do not recognize this one:"
2187 D.stack
2188 [ D.reflow $
2189 "Valid escape characters include:"
2190 , D.dullyellow $ D.indent 4 $ D.vcat $
2191 [ "\\n"
2192 , "\\r"
2193 , "\\t"
2194 , "\\\""
2195 , "\\\'"
2196 , "\\\\"
2197 , "\\u{003D}"
2199 , D.reflow $
2200 "Do you want one of those instead? Maybe you need \\\\ to escape a backslash?"
2201 , D.toSimpleNote $
2202 "The last style lets encode ANY character by its Unicode code\
2203 \ point. That means \\u{0009} and \\t are the same. You can use\
2204 \ that style for anything not covered by the other six escapes!"
2208 BadUnicodeFormat width ->
2209 let
2210 region = toWiderRegion row col width
2211 in
2212 Report.Report "BAD UNICODE ESCAPE" region [] $
2213 Code.toSnippet source region Nothing
2215 D.reflow $
2216 "I ran into an invalid Unicode escape:"
2218 D.stack
2219 [ D.reflow $
2220 "Here are some examples of valid Unicode escapes:"
2221 , D.dullyellow $ D.indent 4 $ D.vcat $
2222 [ "\\u{0041}"
2223 , "\\u{03BB}"
2224 , "\\u{6728}"
2225 , "\\u{1F60A}"
2227 , D.reflow $
2228 "Notice that the code point is always surrounded by curly braces.\
2229 \ Maybe you are missing the opening or closing curly brace?"
2232 BadUnicodeCode width ->
2233 let
2234 region = toWiderRegion row col width
2235 in
2236 Report.Report "BAD UNICODE ESCAPE" region [] $
2237 Code.toSnippet source region Nothing
2239 D.reflow $
2240 "This is not a valid code point:"
2242 D.reflow $
2243 "The valid code points are between 0 and 10FFFF inclusive."
2246 BadUnicodeLength width numDigits badCode ->
2247 let
2248 region = toWiderRegion row col width
2249 in
2250 Report.Report "BAD UNICODE ESCAPE" region [] $
2251 Code.toSnippet source region Nothing $
2252 if numDigits < 4 then
2254 D.reflow $
2255 "Every code point needs at least four digits:"
2257 let
2258 goodCode = replicate (4 - numDigits) '0' ++ map Char.toUpper (showHex badCode "")
2259 suggestion = "\\u{" <> D.fromChars goodCode <> "}"
2260 in
2261 D.fillSep ["Try",D.green suggestion,"instead?"]
2264 else
2266 D.reflow $
2267 "This code point has too many digits:"
2269 D.fillSep $
2270 ["Valid","code","points","are","between"
2271 ,D.green "\\u{0000}","and",D.green "\\u{10FFFF}" <> ","
2272 ,"so","try","trimming","any","leading","zeros","until"
2273 ,"you","have","between","four","and","six","digits."
2279-- NUMBERS
2282toNumberReport :: Code.Source -> Number -> Row -> Col -> Report.Report
2283toNumberReport source number row col =
2284 let
2285 region = toRegion row col
2286 in
2287 case number of
2288 NumberEnd ->
2289 Report.Report "WEIRD NUMBER" region [] $
2290 Code.toSnippet source region Nothing
2292 D.reflow $
2293 "I thought I was reading a number, but I ran into some weird stuff here:"
2295 D.stack
2296 [ D.reflow $
2297 "I recognize numbers in the following formats:"
2298 , D.indent 4 $ D.vcat [ "42", "3.14", "6.022e23", "0x002B" ]
2299 , D.reflow $
2300 "So is there a way to write it like one of those?"
2304 NumberDot int ->
2305 Report.Report "WEIRD NUMBER" region [] $
2306 Code.toSnippet source region Nothing
2308 D.reflow $
2309 "Numbers cannot end with a dot like this:"
2311 D.fillSep
2312 ["Switching","to",D.green (D.fromChars (show int))
2313 ,"or",D.green (D.fromChars (show int ++ ".0"))
2314 ,"will","work","though!"
2318 NumberHexDigit ->
2319 Report.Report "WEIRD HEXIDECIMAL" region [] $
2320 Code.toSnippet source region Nothing
2322 D.reflow $
2323 "I thought I was reading a hexidecimal number until I got here:"
2325 D.stack
2326 [ D.reflow $
2327 "Valid hexidecimal digits include 0123456789abcdefABCDEF, so I can\
2328 \ only recognize things like this:"
2329 , D.indent 4 $ D.vcat [ "0x2B", "0x002B", "0x00ffb3" ]
2333 NumberNoLeadingZero ->
2334 Report.Report "LEADING ZEROS" region [] $
2335 Code.toSnippet source region Nothing
2337 D.reflow $
2338 "I do not accept numbers with leading zeros:"
2340 D.stack
2341 [ D.reflow $
2342 "Just delete the leading zeros and it should work!"
2343 , D.toSimpleNote $
2344 "Some languages let you to specify octal numbers by adding a leading zero.\
2345 \ So in C, writing 0111 is the same as writing 73. Some people are used to\
2346 \ that, but others probably want it to equal 111. Either path is going to\
2347 \ surprise people from certain backgrounds, so Elm tries to avoid this whole\
2348 \ situation."
2354-- OPERATORS
2357toOperatorReport :: Code.Source -> Context -> BadOperator -> Row -> Col -> Report.Report
2358toOperatorReport source context operator row col =
2359 case operator of
2360 BadDot ->
2361 let
2362 region = toRegion row col
2363 in
2364 Report.Report "UNEXPECTED SYMBOL" region [] $
2365 Code.toSnippet source region Nothing
2367 "I was not expecting this dot:"
2369 D.reflow $
2370 "Dots are for record access and decimal points, so\
2371 \ they cannot float around on their own. Maybe\
2372 \ there is some extra whitespace?"
2375 BadPipe ->
2376 let
2377 region = toRegion row col
2378 in
2379 Report.Report "UNEXPECTED SYMBOL" region [] $
2380 Code.toSnippet source region Nothing
2382 D.reflow $
2383 "I was not expecting this vertical bar:"
2385 D.reflow $
2386 "Vertical bars should only appear in custom type declarations. Maybe you want || instead?"
2389 BadArrow ->
2390 let
2391 region = toWiderRegion row col 2
2392 in
2393 Report.Report "UNEXPECTED ARROW" region [] $
2394 Code.toSnippet source region Nothing $
2395 if isWithin NBranch context then
2397 D.reflow $
2398 "I was not expecting to see an arrow here:"
2400 D.stack
2402 D.reflow $
2403 "I think I am parsing a `case` expression right now, so it makes sense to\
2404 \ see arrows around here. This one is confusing me though!"
2406 D.toSimpleHint $
2407 "I may be getting confused by the indentation. Every pattern in a `case` must be\
2408 \ exactly aligned (with exactly the same amount of indentation) so maybe this arrow\
2409 \ appears after the next `case` pattern (correctly!) but the pattern itself is\
2410 \ indented too far?"
2414 else
2416 D.reflow $
2417 "I was not expecting an arrow here:"
2419 D.reflow $
2420 "Arrows should only appear in `case` expressions and anonymous functions. Maybe\
2421 \ you want > or >= instead?"
2424 BadEquals ->
2425 let
2426 region = toRegion row col
2427 name = getDefName context
2428 in
2429 Report.Report "UNEXPECTED EQUALS" region [] $
2430 Code.toSnippet source region Nothing
2432 D.reflow $
2433 "I was not expecting to see this equals sign:"
2435 D.stack
2437 D.reflow "Maybe you want == instead? To check if two values are equal?"
2439 D.toSimpleNote $
2440 if isWithin NRecord context then
2441 "Records look like { x = 3, y = 4 } with the equals sign right\
2442 \ after the field name. So maybe you forgot a comma?"
2443 else
2444 "I may be getting confused by your indentation. Is this supposed to be part of\
2445 \ a definition AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
2446 \ the problem may be a bit before the equals sign. I need all definitions to\
2447 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
2448 \ this new definition is indented a bit too much."
2452 BadHasType ->
2453 let
2454 region = toRegion row col
2455 name = getDefName context
2456 in
2457 Report.Report "UNEXPECTED SYMBOL" region [] $
2458 Code.toSnippet source region Nothing $
2460 D.reflow $
2461 "I was not expecting to run into the \"has type\" symbol here:"
2463 D.stack
2465 D.fillSep
2466 ["Maybe","you","want",D.green "::","instead?"
2467 ,"To","put","something","on","the","front","of","a","list?"
2469 , D.toSimpleNote $
2470 "The single colon is reserved for type annotations and record types, but I think\
2471 \ I am parsing the definition of `" ++ Name.toChars name ++ "` right now."
2473 D.toSimpleNote $
2474 "I may be getting confused by your indentation. Is this supposed to be part of\
2475 \ a type annotation AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
2476 \ the problem may be a bit before the \"has type\" symbol. I need all definitions to\
2477 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
2478 \ this new definition is indented a bit too much."
2484-- CASE
2487toLetReport :: Code.Source -> Context -> Let -> Row -> Col -> Report.Report
2488toLetReport source context let_ startRow startCol =
2489 case let_ of
2490 LetSpace space row col ->
2491 toSpaceReport source space row col
2493 LetIn row col ->
2494 let
2495 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2496 region = toRegion row col
2497 in
2498 Report.Report "LET PROBLEM" region [] $
2499 Code.toSnippet source surroundings (Just region)
2501 D.reflow $
2502 "I was partway through parsing a `let` expression, but I got stuck here:"
2504 D.stack
2505 [ D.fillSep $
2506 ["Based","on","the","indentation,","I","was","expecting","to","see","the",D.cyan "in"
2507 ,"keyword","next.","Is","there","a","typo?"
2509 , D.toSimpleNote $
2510 "This can also happen if you are trying to define another value within the `let` but\
2511 \ it is not indented enough. Make sure each definition has exactly the same amount of\
2512 \ spaces before it. They should line up exactly!"
2516 LetDefAlignment _ row col ->
2517 let
2518 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2519 region = toRegion row col
2520 in
2521 Report.Report "LET PROBLEM" region [] $
2522 Code.toSnippet source surroundings (Just region)
2524 D.reflow $
2525 "I was partway through parsing a `let` expression, but I got stuck here:"
2527 D.stack
2528 [ D.fillSep $
2529 ["Based","on","the","indentation,","I","was","expecting","to","see","the",D.cyan "in"
2530 ,"keyword","next.","Is","there","a","typo?"
2532 , D.toSimpleNote $
2533 "This can also happen if you are trying to define another value within the `let` but\
2534 \ it is not indented enough. Make sure each definition has exactly the same amount of\
2535 \ spaces before it. The should line up exactly!"
2539 LetDefName row col ->
2540 case Code.whatIsNext source row col of
2541 Code.Keyword keyword ->
2542 let
2543 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2544 region = toKeywordRegion row col keyword
2545 in
2546 Report.Report "RESERVED WORD" region [] $
2547 Code.toSnippet source surroundings (Just region)
2549 D.reflow $
2550 "I was partway through parsing a `let` expression, but I got stuck here:"
2552 D.reflow $
2553 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name, but\
2554 \ it is a reserved word! Try using a different name instead."
2557 _ ->
2558 toUnfinishLetReport source row col startRow startCol $
2559 D.reflow $
2560 "I was expecting the name of a definition next."
2562 LetDef name def row col ->
2563 error "TODO LetDef" name def row col
2565 LetDestruct destruct row col ->
2566 error "TODO LetDestruct" destruct row col
2568 LetBody expr row col ->
2569 toExprReport source context expr row col
2571 LetIndentDef row col ->
2572 toUnfinishLetReport source row col startRow startCol $
2573 D.reflow $
2574 "I was expecting a value to be defined here."
2576 LetIndentIn row col ->
2577 toUnfinishLetReport source row col startRow startCol $
2578 D.fillSep $
2579 ["I","was","expecting","to","see","the",D.cyan "in","keyword","next."
2580 ,"Or","maybe","more","of","that","expression?"
2583 LetIndentBody row col ->
2584 toUnfinishLetReport source row col startRow startCol $
2585 D.reflow $
2586 "I was expecting an expression next. Tell me what should happen with the value you just defined!"
2589toUnfinishLetReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
2590toUnfinishLetReport source row col startRow startCol message =
2591 let
2592 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2593 region = toRegion row col
2594 in
2595 Report.Report "UNFINISHED LET" region [] $
2596 Code.toSnippet source surroundings (Just region)
2598 D.reflow $
2599 "I was partway through parsing a `let` expression, but I got stuck here:"
2601 D.stack
2602 [ message
2603 , D.toSimpleNote $
2604 "Here is an example with a valid `let` expression for reference:"
2605 , D.vcat $
2606 [ D.indent 0 $ D.fillSep [D.green "viewPerson","person","="]
2607 , D.indent 2 $ D.fillSep [D.cyan "let"]
2608 , D.indent 4 $ D.fillSep ["fullName","="]
2609 , D.indent 6 $ D.fillSep ["person.firstName","++",D.dullyellow "\" \"","++","person.lastName"]
2610 , D.indent 2 $ D.fillSep [D.cyan "in"]
2611 , D.indent 2 $ D.fillSep ["div","[]","[","text","fullName","]"]
2613 , D.reflow $
2614 "Here we defined a `viewPerson` function that turns a person into some HTML. We use\
2615 \ a `let` expression to define the `fullName` we want to show. Notice the indentation! The\
2616 \ `fullName` is indented more than the `let` keyword, and the actual value of `fullName` is\
2617 \ indented a bit more than that. That is important!"
2623-- CASE
2626toCaseReport :: Code.Source -> Context -> Case -> Row -> Col -> Report.Report
2627toCaseReport source context case_ startRow startCol =
2628 case case_ of
2629 CaseSpace space row col ->
2630 toSpaceReport source space row col
2632 CaseOf row col ->
2633 toUnfinishCaseReport source row col startRow startCol $
2634 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
2636 CasePattern pattern row col ->
2637 toPatternReport source PCase pattern row col
2639 CaseArrow row col ->
2640 case Code.whatIsNext source row col of
2641 Code.Keyword keyword ->
2642 let
2643 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2644 region = toKeywordRegion row col keyword
2645 in
2646 Report.Report "RESERVED WORD" region [] $
2647 Code.toSnippet source surroundings (Just region)
2649 D.reflow $
2650 "I am partway through parsing a `case` expression, but I got stuck here:"
2652 D.reflow $
2653 "It looks like you are trying to use `" ++ keyword ++ "` in one of your\
2654 \ patterns, but it is a reserved word. Try using a different name?"
2657 Code.Operator ":" ->
2658 let
2659 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2660 region = toRegion row col
2661 in
2662 Report.Report "UNEXPECTED OPERATOR" region [] $
2663 Code.toSnippet source surroundings (Just region)
2665 D.reflow $
2666 "I am partway through parsing a `case` expression, but I got stuck here:"
2668 D.fillSep $
2669 ["I","am","seeing",D.dullyellow ":","but","maybe","you","want",D.green "::","instead?"
2670 ,"For","pattern","matching","on","lists?"
2674 Code.Operator "=" ->
2675 let
2676 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2677 region = toRegion row col
2678 in
2679 Report.Report "UNEXPECTED OPERATOR" region [] $
2680 Code.toSnippet source surroundings (Just region)
2682 D.reflow $
2683 "I am partway through parsing a `case` expression, but I got stuck here:"
2685 D.fillSep $
2686 ["I","am","seeing",D.dullyellow "=","but","maybe","you","want",D.green "->","instead?"
2690 _ ->
2691 let
2692 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2693 region = toRegion row col
2694 in
2695 Report.Report "MISSING ARROW" region [] $
2696 Code.toSnippet source surroundings (Just region)
2698 D.reflow $
2699 "I am partway through parsing a `case` expression, but I got stuck here:"
2701 addNoteForCaseIndentError $
2702 D.reflow $
2703 "I was expecting to see an arrow next."
2706 CaseExpr expr row col ->
2707 toExprReport source (InNode NCase startRow startCol context) expr row col
2709 CaseBranch expr row col ->
2710 toExprReport source (InNode NBranch startRow startCol context) expr row col
2712 CaseIndentOf row col ->
2713 toUnfinishCaseReport source row col startRow startCol $
2714 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
2716 CaseIndentExpr row col ->
2717 toUnfinishCaseReport source row col startRow startCol $
2718 D.reflow "I was expecting to see a expression next."
2720 CaseIndentPattern row col ->
2721 toUnfinishCaseReport source row col startRow startCol $
2722 D.reflow "I was expecting to see a pattern next."
2724 CaseIndentArrow row col ->
2725 toUnfinishCaseReport source row col startRow startCol $
2726 D.fillSep
2727 ["I","just","saw","a","pattern,","so","I","was","expecting"
2728 ,"to","see","a",D.dullyellow "->","next."
2731 CaseIndentBranch row col ->
2732 toUnfinishCaseReport source row col startRow startCol $
2733 D.reflow $
2734 "I was expecting to see an expression next. What should I do when\
2735 \ I run into this particular pattern?"
2737 CasePatternAlignment indent row col ->
2738 toUnfinishCaseReport source row col startRow startCol $
2739 D.reflow $
2740 "I suspect this is a pattern that is not indented far enough? (" ++ show indent ++ " spaces)"
2743toUnfinishCaseReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
2744toUnfinishCaseReport source row col startRow startCol message =
2745 let
2746 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2747 region = toRegion row col
2748 in
2749 Report.Report "UNFINISHED CASE" region [] $
2750 Code.toSnippet source surroundings (Just region)
2752 D.reflow $
2753 "I was partway through parsing a `case` expression, but I got stuck here:"
2755 D.stack
2756 [ message
2757 , D.toSimpleNote $
2758 "Here is an example of a valid `case` expression for reference."
2759 , D.vcat $
2760 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
2761 , D.indent 6 $ D.fillSep [D.green "Just","width","->"]
2762 , D.indent 8 $ D.fillSep ["width","+",D.dullyellow "200"]
2763 , ""
2764 , D.indent 6 $ D.fillSep [D.green "Nothing","->"]
2765 , D.indent 8 $ D.fillSep [D.dullyellow "400"]
2767 , D.reflow $
2768 "Notice the indentation. Each pattern is aligned, and each branch is indented\
2769 \ a bit more than the corresponding pattern. That is important!"
2774addNoteForCaseIndentError :: D.Doc -> D.Doc
2775addNoteForCaseIndentError message =
2776 D.stack $
2777 message
2779 [ D.toSimpleNote $
2780 "Sometimes I get confused by indentation, so try to make your `case` look\
2781 \ something like this:"
2782 , D.vcat $
2783 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
2784 , D.indent 6 $ D.fillSep [D.green "Just","width","->"]
2785 , D.indent 8 $ D.fillSep ["width","+",D.dullyellow "200"]
2786 , ""
2787 , D.indent 6 $ D.fillSep [D.green "Nothing","->"]
2788 , D.indent 8 $ D.fillSep [D.dullyellow "400"]
2790 , D.reflow $
2791 "Notice the indentation! Each pattern is aligned, and each branch is indented\
2792 \ a bit more than the corresponding pattern. That is important!"
2797-- IF
2800toIfReport :: Code.Source -> Context -> If -> Row -> Col -> Report.Report
2801toIfReport source context if_ startRow startCol =
2802 case if_ of
2803 IfSpace space row col ->
2804 toSpaceReport source space row col
2806 IfThen row col ->
2807 let
2808 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2809 region = toRegion row col
2810 in
2811 Report.Report "UNFINISHED IF" region [] $
2812 Code.toSnippet source surroundings (Just region)
2814 D.reflow $
2815 "I was expecting to see more of this `if` expression, but I got stuck here:"
2817 D.fillSep $
2818 ["I","was","expecting","to","see","the",D.cyan "then","keyword","next."
2822 IfElse row col ->
2823 let
2824 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2825 region = toRegion row col
2826 in
2827 Report.Report "UNFINISHED IF" region [] $
2828 Code.toSnippet source surroundings (Just region)
2830 D.reflow $
2831 "I was expecting to see more of this `if` expression, but I got stuck here:"
2833 D.fillSep $
2834 ["I","was","expecting","to","see","the",D.cyan "else","keyword","next."
2838 IfElseBranchStart row col ->
2839 let
2840 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2841 region = toRegion row col
2842 in
2843 Report.Report "UNFINISHED IF" region [] $
2844 Code.toSnippet source surroundings (Just region)
2846 D.reflow $
2847 "I just saw the start of an `else` branch, but then I got stuck here:"
2849 D.reflow $
2850 "I was expecting to see an expression next. Maybe it is not filled in yet?"
2853 IfCondition expr row col ->
2854 toExprReport source (InNode NCond startRow startCol context) expr row col
2856 IfThenBranch expr row col ->
2857 toExprReport source (InNode NThen startRow startCol context) expr row col
2859 IfElseBranch expr row col ->
2860 toExprReport source (InNode NElse startRow startCol context) expr row col
2862 IfIndentCondition row col ->
2863 let
2864 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2865 region = toRegion row col
2866 in
2867 Report.Report "UNFINISHED IF" region [] $
2868 Code.toSnippet source surroundings (Just region)
2870 D.reflow $
2871 "I was expecting to see more of this `if` expression, but I got stuck here:"
2873 D.stack
2874 [ D.fillSep $
2875 ["I","was","expecting","to","see","an","expression","like",D.dullyellow "x < 0"
2876 ,"that","evaluates","to","True","or","False."
2878 , D.toSimpleNote $
2879 "I can be confused by indentation. Maybe something is not indented enough?"
2883 IfIndentThen row col ->
2884 let
2885 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2886 region = toRegion row col
2887 in
2888 Report.Report "UNFINISHED IF" region [] $
2889 Code.toSnippet source surroundings (Just region)
2891 D.reflow $
2892 "I was expecting to see more of this `if` expression, but I got stuck here:"
2894 D.stack
2895 [ D.fillSep $
2896 ["I","was","expecting","to","see","the",D.cyan "then","keyword","next."
2898 , D.toSimpleNote $
2899 "I can be confused by indentation. Maybe something is not indented enough?"
2903 IfIndentThenBranch row col ->
2904 let
2905 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2906 region = toRegion row col
2907 in
2908 Report.Report "UNFINISHED IF" region [] $
2909 Code.toSnippet source surroundings (Just region)
2911 D.reflow $
2912 "I got stuck after the start of this `then` branch:"
2914 D.stack
2915 [ D.reflow $
2916 "I was expecting to see an expression next. Maybe it is not filled in yet?"
2917 , D.toSimpleNote $
2918 "I can be confused by indentation, so if the `then` branch is already\
2919 \ present, it may not be indented enough for me to recognize it."
2923 IfIndentElseBranch row col ->
2924 let
2925 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2926 region = toRegion row col
2927 in
2928 Report.Report "UNFINISHED IF" region [] $
2929 Code.toSnippet source surroundings (Just region)
2931 D.reflow $
2932 "I got stuck after the start of this `else` branch:"
2934 D.stack
2935 [ D.reflow $
2936 "I was expecting to see an expression next. Maybe it is not filled in yet?"
2937 , D.toSimpleNote $
2938 "I can be confused by indentation, so if the `else` branch is already\
2939 \ present, it may not be indented enough for me to recognize it."
2943 IfIndentElse row col ->
2944 let
2945 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2946 region = toRegion row col
2947 in
2948 Report.Report "UNFINISHED IF" region [] $
2949 Code.toSnippet source surroundings (Just region)
2951 D.reflow $
2952 "I was expecting to see an `else` branch after this:"
2954 D.stack
2955 [ D.reflow $
2956 "I know what to do when the condition is `True`, but not when it is `False`."
2957 , D.fillSep
2958 ["Add","an",D.cyan "else","branch","to","handle","that","scenario!"]
2964-- RECORD
2967toRecordReport :: Code.Source -> Context -> Record -> Row -> Col -> Report.Report
2968toRecordReport source context record startRow startCol =
2969 case record of
2970 RecordOpen row col ->
2971 case Code.whatIsNext source row col of
2972 Code.Keyword keyword ->
2973 let
2974 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2975 region = toKeywordRegion row col keyword
2976 in
2977 Report.Report "RESERVED WORD" region [] $
2978 Code.toSnippet source surroundings (Just region)
2980 D.reflow $
2981 "I just started parsing a record, but I got stuck on this field name:"
2983 D.reflow $
2984 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
2985 \ that is a reserved word. Try using a different name!"
2988 _ ->
2989 let
2990 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2991 region = toRegion row col
2992 in
2993 Report.Report "UNFINISHED RECORD" region [] $
2994 Code.toSnippet source surroundings (Just region)
2996 D.reflow $
2997 "I just started parsing a record, but I got stuck here:"
2999 D.fillSep
3000 ["Records","look","like",D.dullyellow "{ x = 3, y = 4 },"
3001 ,"so","I","was","expecting","to","see","a","field","name","next."
3005 RecordEnd row col ->
3006 let
3007 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3008 region = toRegion row col
3009 in
3010 Report.Report "UNFINISHED RECORD" region [] $
3011 Code.toSnippet source surroundings (Just region)
3013 D.reflow $
3014 "I am partway through parsing a record, but I got stuck here:"
3016 D.stack
3017 [ D.fillSep
3018 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
3019 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
3021 , D.toSimpleNote $
3022 "When I get stuck like this, it usually means that there is a missing parenthesis\
3023 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
3027 RecordField row col ->
3028 case Code.whatIsNext source row col of
3029 Code.Keyword keyword ->
3030 let
3031 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3032 region = toKeywordRegion row col keyword
3033 in
3034 Report.Report "RESERVED WORD" region [] $
3035 Code.toSnippet source surroundings (Just region)
3037 D.reflow $
3038 "I am partway through parsing a record, but I got stuck on this field name:"
3040 D.reflow $
3041 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
3042 \ that is a reserved word. Try using a different name!"
3045 _ ->
3046 let
3047 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3048 region = toRegion row col
3049 in
3050 Report.Report "UNFINISHED RECORD" region [] $
3051 Code.toSnippet source surroundings (Just region)
3053 D.reflow $
3054 "I am partway through parsing a record, but I got stuck after that last comma:"
3056 addNoteForRecordError $
3057 D.reflow $
3058 "Trailing commas are not allowed in records, so I was expecting to see another\
3059 \ record field defined next. If you are done defining the record, the fix may\
3060 \ be to delete that last comma?"
3063 RecordEquals row col ->
3064 let
3065 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3066 region = toRegion row col
3067 in
3068 Report.Report "UNFINISHED RECORD" region [] $
3069 Code.toSnippet source surroundings (Just region)
3071 D.reflow $
3072 "I am partway through parsing a record, but I got stuck here:"
3074 addNoteForRecordError $
3075 D.fillSep $
3076 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
3077 ,"an","equals","sign","next.","So","try","putting","an",D.green "=","sign","here?"
3081 RecordExpr expr row col ->
3082 toExprReport source (InNode NRecord startRow startCol context) expr row col
3084 RecordSpace space row col ->
3085 toSpaceReport source space row col
3087 RecordIndentOpen row col ->
3088 let
3089 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3090 region = toRegion row col
3091 in
3092 Report.Report "UNFINISHED RECORD" region [] $
3093 Code.toSnippet source surroundings (Just region)
3095 D.reflow $
3096 "I just saw the opening curly brace of a record, but then I got stuck here:"
3098 addNoteForRecordIndentError $
3099 D.fillSep $
3100 ["I","am","expecting","a","record","like",D.dullyellow "{ x = 3, y = 4 }","here."
3101 ,"Try","defining","some","fields","of","your","own?"
3105 RecordIndentEnd row col ->
3106 let
3107 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3108 region = toRegion row col
3109 in
3110 Report.Report "UNFINISHED RECORD" region [] $
3111 Code.toSnippet source surroundings (Just region)
3113 D.reflow $
3114 "I was expecting to see a closing curly brace next:"
3116 addNoteForRecordIndentError $
3117 D.fillSep $
3118 ["Try","putting","an",D.green "}","and","see","if","that","helps?"
3122 RecordIndentField row col ->
3123 let
3124 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3125 region = toRegion row col
3126 in
3127 Report.Report "UNFINISHED RECORD" region [] $
3128 Code.toSnippet source surroundings (Just region)
3130 D.reflow $
3131 "I am partway through parsing a record, but I got stuck after that last comma:"
3133 addNoteForRecordError $
3134 D.reflow $
3135 "Trailing commas are not allowed in records, so the fix may be to\
3136 \ delete that last comma? Or maybe you were in the middle of defining\
3137 \ an additional field?"
3140 RecordIndentEquals row col ->
3141 let
3142 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3143 region = toRegion row col
3144 in
3145 Report.Report "UNFINISHED RECORD" region [] $
3146 Code.toSnippet source surroundings (Just region)
3148 D.reflow $
3149 "I am partway through parsing a record. I just saw a record\
3150 \ field, so I was expecting to see an equals sign next:"
3152 addNoteForRecordIndentError $
3153 D.fillSep $
3154 ["Try","putting","an",D.green "=","followed","by","an","expression?"
3158 RecordIndentExpr row col ->
3159 let
3160 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3161 region = toRegion row col
3162 in
3163 Report.Report "UNFINISHED RECORD" region [] $
3164 Code.toSnippet source surroundings (Just region)
3166 D.reflow $
3167 "I am partway through parsing a record, and I was expecting to run into an expression next:"
3169 addNoteForRecordIndentError $
3170 D.fillSep $
3171 ["Try","putting","something,","like"
3172 ,D.dullyellow "42","or",D.dullyellow"\"hello\"","for","now?"
3177addNoteForRecordError :: D.Doc -> D.Doc
3178addNoteForRecordError normalRecommendation =
3179 D.stack $
3180 normalRecommendation
3182 [ D.toSimpleNote
3183 "If you are trying to define a record across multiple lines, I recommend using this format:"
3184 , D.indent 4 $ D.vcat $
3185 [ "{ name = \"Alice\""
3186 , ", age = 42"
3187 , ", height = 1.75"
3188 , "}"
3190 , D.reflow $
3191 "Notice that each line starts with some indentation. Usually two or four spaces. I\
3192 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
3193 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3197addNoteForRecordIndentError :: D.Doc -> D.Doc
3198addNoteForRecordIndentError normalRecommendation =
3199 D.stack $
3200 normalRecommendation
3202 [ D.toSimpleNote
3203 "I may be confused by indentation. For example, if you are trying to define\
3204 \ a record across multiple lines, I recommend using this format:"
3205 , D.indent 4 $ D.vcat $
3206 [ "{ name = \"Alice\""
3207 , ", age = 42"
3208 , ", height = 1.75"
3209 , "}"
3211 , D.reflow $
3212 "Notice that each line starts with some indentation. Usually two or four spaces. I\
3213 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
3214 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3219-- TUPLE
3222toTupleReport :: Code.Source -> Context -> Tuple -> Row -> Col -> Report.Report
3223toTupleReport source context tuple startRow startCol =
3224 case tuple of
3225 TupleExpr expr row col ->
3226 toExprReport source (InNode NParens startRow startCol context) expr row col
3228 TupleSpace space row col ->
3229 toSpaceReport source space row col
3231 TupleEnd row col ->
3232 let
3233 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3234 region = toRegion row col
3235 in
3236 Report.Report "UNFINISHED PARENTHESES" region [] $
3237 Code.toSnippet source surroundings (Just region)
3239 D.reflow $
3240 "I was expecting to see a closing parentheses next, but I got stuck here:"
3242 D.stack
3243 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
3244 , D.toSimpleNote $
3245 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
3246 \ unexpectedly. So there may be some earlier syntax trouble (like extra parenthesis\
3247 \ or missing brackets) that is confusing me."
3251 TupleOperatorClose row col ->
3252 let
3253 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3254 region = toRegion row col
3255 in
3256 Report.Report "UNFINISHED OPERATOR FUNCTION" region [] $
3257 Code.toSnippet source surroundings (Just region)
3259 D.reflow "I was expecting a closing parenthesis here:"
3261 D.stack
3262 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
3263 , D.toSimpleNote $
3264 "I think I am parsing an operator function right now, so I am expecting to see\
3265 \ something like (+) or (&&) where an operator is surrounded by parentheses with\
3266 \ no extra spaces."
3270 TupleOperatorReserved operator row col ->
3271 let
3272 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3273 region = toRegion row col
3274 in
3275 Report.Report "UNEXPECTED SYMBOL" region [] $
3276 Code.toSnippet source surroundings (Just region)
3278 D.reflow $
3279 "I ran into an unexpected symbol here:"
3281 D.fillSep $
3282 case operator of
3283 BadDot -> ["Maybe","you","wanted","a","record","accessor","like",D.dullyellow ".x","or",D.dullyellow ".name","instead?"]
3284 BadPipe -> ["Try",D.dullyellow "(||)","instead?","To","turn","boolean","OR","into","a","function?"]
3285 BadArrow -> ["Maybe","you","wanted",D.dullyellow "(>)","or",D.dullyellow "(>=)","instead?"]
3286 BadEquals -> ["Try",D.dullyellow "(==)","instead?","To","make","a","function","that","checks","equality?"]
3287 BadHasType -> ["Try",D.dullyellow "(::)","instead?","To","add","values","to","the","front","of","lists?"]
3290 TupleIndentExpr1 row col ->
3291 let
3292 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3293 region = toRegion row col
3294 in
3295 Report.Report "UNFINISHED PARENTHESES" region [] $
3296 Code.toSnippet source surroundings (Just region)
3298 D.reflow $
3299 "I just saw an open parenthesis, so I was expecting to see an expression next."
3301 D.stack
3302 [ D.fillSep $
3303 ["Something","like",D.dullyellow "(4 + 5)","or"
3304 ,D.dullyellow "(String.reverse \"desserts\")" <> "."
3305 ,"Anything","where","you","are","putting","parentheses","around","normal","expressions."
3307 , D.toSimpleNote $
3308 "I can get confused by indentation in cases like this, so\
3309 \ maybe you have an expression but it is not indented enough?"
3313 TupleIndentExprN row col ->
3314 let
3315 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3316 region = toRegion row col
3317 in
3318 Report.Report "UNFINISHED TUPLE" region [] $
3319 Code.toSnippet source surroundings (Just region)
3321 D.reflow $
3322 "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."
3324 D.stack
3325 [ D.fillSep $
3326 ["A","tuple","looks","like",D.dullyellow "(3,4)","or"
3327 ,D.dullyellow "(\"Tom\",42)" <> ","
3328 ,"so","I","think","there","is","an","expression","missing","here?"
3330 , D.toSimpleNote $
3331 "I can get confused by indentation in cases like this, so\
3332 \ maybe you have an expression but it is not indented enough?"
3336 TupleIndentEnd row col ->
3337 let
3338 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3339 region = toRegion row col
3340 in
3341 Report.Report "UNFINISHED PARENTHESES" region [] $
3342 Code.toSnippet source surroundings (Just region)
3344 D.reflow $
3345 "I was expecting to see a closing parenthesis next:"
3347 D.stack
3348 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
3349 , D.toSimpleNote $
3350 "I can get confused by indentation in cases like this, so\
3351 \ maybe you have a closing parenthesis but it is not indented enough?"
3356toListReport :: Code.Source -> Context -> List -> Row -> Col -> Report.Report
3357toListReport source context list startRow startCol =
3358 case list of
3359 ListSpace space row col ->
3360 toSpaceReport source space row col
3362 ListOpen 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 "UNFINISHED LIST" region [] $
3368 Code.toSnippet source surroundings (Just region)
3370 D.reflow $
3371 "I am partway through parsing a list, but I got stuck here:"
3373 D.stack
3374 [ D.fillSep
3375 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
3376 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
3378 , D.toSimpleNote $
3379 "When I get stuck like this, it usually means that there is a missing parenthesis\
3380 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
3384 ListExpr expr row col ->
3385 case expr of
3386 Start r c ->
3387 let
3388 surroundings = A.Region (A.Position startRow startCol) (A.Position r c)
3389 region = toRegion r c
3390 in
3391 Report.Report "UNFINISHED LIST" region [] $
3392 Code.toSnippet source surroundings (Just region)
3394 D.reflow $
3395 "I was expecting to see another list entry after that last comma:"
3397 D.stack
3398 [ D.reflow $
3399 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
3400 , D.toSimpleNote
3401 "I recommend using the following format for lists that span multiple lines:"
3402 , D.indent 4 $ D.vcat $
3403 [ "[ \"Alice\""
3404 , ", \"Bob\""
3405 , ", \"Chuck\""
3406 , "]"
3408 , D.reflow $
3409 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
3410 \ This style can be jarring for people coming from C-like syntax, but folks generally\
3411 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3415 _ ->
3416 toExprReport source (InNode NList startRow startCol context) expr row col
3418 ListEnd row col ->
3419 let
3420 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3421 region = toRegion row col
3422 in
3423 Report.Report "UNFINISHED LIST" region [] $
3424 Code.toSnippet source surroundings (Just region)
3426 D.reflow $
3427 "I am partway through parsing a list, but I got stuck here:"
3429 D.stack
3430 [ D.fillSep
3431 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
3432 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
3434 , D.toSimpleNote $
3435 "When I get stuck like this, it usually means that there is a missing parenthesis\
3436 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
3440 ListIndentOpen row col ->
3441 let
3442 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3443 region = toRegion row col
3444 in
3445 Report.Report "UNFINISHED LIST" region [] $
3446 Code.toSnippet source surroundings (Just region)
3448 D.reflow $
3449 "I cannot find the end of this list:"
3451 D.stack
3452 [ D.fillSep $
3453 ["You","could","change","it","to","something","like"
3454 ,D.dullyellow "[3,4,5]"
3455 ,"or","even","just"
3456 ,D.dullyellow "[]" <> "."
3457 ,"Anything","where","there","is","an","open","and","close","square","brace,"
3458 ,"and","where","the","elements","of","the","list","are","separated","by","commas."
3460 , D.toSimpleNote
3461 "I may be confused by indentation. For example, if you are trying to define\
3462 \ a list across multiple lines, I recommend using this format:"
3463 , D.indent 4 $ D.vcat $
3464 [ "[ \"Alice\""
3465 , ", \"Bob\""
3466 , ", \"Chuck\""
3467 , "]"
3469 , D.reflow $
3470 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
3471 \ This style can be jarring for people coming from C-like syntax, but folks generally\
3472 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3476 ListIndentEnd row col ->
3477 let
3478 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3479 region = toRegion row col
3480 in
3481 Report.Report "UNFINISHED LIST" region [] $
3482 Code.toSnippet source surroundings (Just region)
3484 D.reflow $
3485 "I cannot find the end of this list:"
3487 D.stack
3488 [ D.fillSep $
3489 ["You","can","just","add","a","closing",D.dullyellow "]"
3490 ,"right","here,","and","I","will","be","all","set!"
3492 , D.toSimpleNote
3493 "I may be confused by indentation. For example, if you are trying to define\
3494 \ a list across multiple lines, I recommend using this format:"
3495 , D.indent 4 $ D.vcat $
3496 [ "[ \"Alice\""
3497 , ", \"Bob\""
3498 , ", \"Chuck\""
3499 , "]"
3501 , D.reflow $
3502 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
3503 \ This style can be jarring for people coming from C-like syntax, but folks generally\
3504 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3508 ListIndentExpr row col ->
3509 let
3510 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3511 region = toRegion row col
3512 in
3513 Report.Report "UNFINISHED LIST" region [] $
3514 Code.toSnippet source surroundings (Just region)
3516 D.reflow $
3517 "I was expecting to see another list entry after this comma:"
3519 D.stack
3520 [ D.reflow $
3521 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
3522 , D.toSimpleNote
3523 "I recommend using the following format for lists that span multiple lines:"
3524 , D.indent 4 $ D.vcat $
3525 [ "[ \"Alice\""
3526 , ", \"Bob\""
3527 , ", \"Chuck\""
3528 , "]"
3530 , D.reflow $
3531 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
3532 \ This style can be jarring for people coming from C-like syntax, but folks generally\
3533 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3538toFuncReport :: Code.Source -> Context -> Func -> Row -> Col -> Report.Report
3539toFuncReport source context func startRow startCol =
3540 case func of
3541 FuncSpace space row col ->
3542 toSpaceReport source space row col
3544 FuncArg pattern row col ->
3545 toPatternReport source PArg pattern row col
3547 FuncBody expr row col ->
3548 toExprReport source (InNode NFunc startRow startCol context) expr row col
3550 FuncArrow row col ->
3551 case Code.whatIsNext source row col of
3552 Code.Keyword keyword ->
3553 let
3554 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3555 region = toKeywordRegion row col keyword
3556 in
3557 Report.Report "RESERVED WORD" region [] $
3558 Code.toSnippet source surroundings (Just region)
3560 D.reflow $
3561 "I was parsing an anonymous function, but I got stuck here:"
3563 D.reflow $
3564 "It looks like you are trying to use `" ++ keyword ++ "` as an argument, but\
3565 \ it is a reserved word in this language. Try using a different argument name!"
3568 _ ->
3569 let
3570 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3571 region = toRegion row col
3572 in
3573 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
3574 Code.toSnippet source surroundings (Just region)
3576 D.reflow $
3577 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
3579 D.fillSep $
3580 ["The","syntax","for","anonymous","functions","is"
3581 ,D.dullyellow "(\\x -> x + 1)"
3582 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
3586 FuncIndentArg row col ->
3587 let
3588 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3589 region = toRegion row col
3590 in
3591 Report.Report "MISSING ARGUMENT" region [] $
3592 Code.toSnippet source surroundings (Just region)
3594 D.reflow $
3595 "I just saw the beginning of an anonymous function, so I was expecting to see an argument next:"
3597 D.stack
3598 [ D.fillSep
3599 ["Something","like",D.dullyellow"x","or",D.dullyellow "name" <> "."
3600 ,"Anything","that","starts","with","a","lower","case","letter!"
3602 , D.toSimpleNote $
3603 "The syntax for anonymous functions is (\\x -> x + 1) where the backslash\
3604 \ is meant to look a bit like a lambda if you squint. This visual pun seemed\
3605 \ like a better idea at the time!"
3609 FuncIndentArrow row col ->
3610 let
3611 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3612 region = toRegion row col
3613 in
3614 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
3615 Code.toSnippet source surroundings (Just region)
3617 D.reflow $
3618 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
3620 D.stack
3621 [ D.fillSep $
3622 ["The","syntax","for","anonymous","functions","is"
3623 ,D.dullyellow "(\\x -> x + 1)"
3624 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
3626 , D.toSimpleNote $
3627 "It is possible that I am confused about indetation! I generally recommend\
3628 \ switching to named functions if the definition cannot fit inline nicely, so\
3629 \ either (1) try to fit the whole anonymous function on one line or (2) break\
3630 \ the whole thing out into a named function. Things tend to be clearer that way!"
3634 FuncIndentBody row col ->
3635 let
3636 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3637 region = toRegion row col
3638 in
3639 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
3640 Code.toSnippet source surroundings (Just region)
3642 D.reflow $
3643 "I was expecting to see the body of your anonymous function next:"
3645 D.stack
3646 [ D.fillSep $
3647 ["The","syntax","for","anonymous","functions","is"
3648 ,D.dullyellow "(\\x -> x + 1)"
3649 ,"so","I","am","missing","all","the","stuff","after","the","arrow!"
3651 , D.toSimpleNote $
3652 "It is possible that I am confused about indetation! I generally recommend\
3653 \ switching to named functions if the definition cannot fit inline nicely, so\
3654 \ either (1) try to fit the whole anonymous function on one line or (2) break\
3655 \ the whole thing out into a named function. Things tend to be clearer that way!"
3661-- PATTERN
3664data PContext
3665 = PCase
3666 | PArg
3669toPatternReport :: Code.Source -> PContext -> Pattern -> Row -> Col -> Report.Report
3670toPatternReport source context pattern startRow startCol =
3671 case pattern of
3672 PRecord record row col ->
3673 toPRecordReport source record row col
3675 PTuple tuple row col ->
3676 toPTupleReport source context tuple row col
3678 PList list row col ->
3679 toPListReport source context list row col
3681 PStart row col ->
3682 case Code.whatIsNext source row col of
3683 Code.Keyword keyword ->
3684 let
3685 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3686 region = toKeywordRegion row col keyword
3687 aThing =
3688 case context of
3689 PArg -> "an argument"
3690 PCase -> "a pattern"
3691 in
3692 Report.Report "RESERVED WORD" region [] $
3693 Code.toSnippet source surroundings (Just region)
3695 D.reflow $
3696 "It looks like you are trying to use `" ++ keyword ++ "` as " ++ aThing ++ ":"
3698 D.reflow $
3699 "This is a reserved word! Try using some other name?"
3702 _ ->
3703 error "TODO PStart"
3705 PChar char row col ->
3706 toCharReport source char row col
3708 PString string row col ->
3709 toStringReport source string row col
3711 PNumber number row col ->
3712 toNumberReport source number row col
3714 PFloat width row col ->
3715 let
3716 region = toWiderRegion row col width
3717 in
3718 Report.Report "UNEXPECTED PATTERN" region [] $
3719 Code.toSnippet source region Nothing
3721 D.reflow $
3722 "I cannot pattern match with floating point numbers:"
3724 D.fillSep $
3725 ["Equality","on","floats","can","be","unreliable,","so","you","usually","want"
3726 ,"to","check","that","they","are","nearby","with","some","sort","of"
3727 ,D.dullyellow "(abs (actual - expected) < 0.001)","check."
3731 PAlias row col ->
3732 let
3733 region = toRegion row col
3734 in
3735 Report.Report "UNFINISHED PATTERN" region [] $
3736 Code.toSnippet source region Nothing $
3738 D.reflow $
3739 "I was expecting to see a variable name after the `as` keyword:"
3741 D.stack
3742 [ D.fillSep $
3743 ["The","`as`","keyword","lets","you","write","patterns","like"
3744 ,"((" <> D.dullyellow "x" <> "," <> D.dullyellow "y" <> ") " <> D.cyan "as" <> D.dullyellow " point" <> ")"
3745 ,"so","you","can","refer","to","individual","parts","of","the","tuple","with"
3746 ,D.dullyellow "x","and",D.dullyellow "y","or","you","refer","to","the","whole"
3747 ,"thing","with",D.dullyellow "point."
3749 , D.reflow $
3750 "So I was expecting to see a variable name after the `as` keyword here. Sometimes\
3751 \ people just want to use `as` as a variable name though. Try using a different name\
3752 \ in that case!"
3756 PWildcardNotVar name width row col ->
3757 let
3758 region = toWiderRegion row col (fromIntegral width)
3759 examples =
3760 case dropWhile (=='_') (Name.toChars name) of
3761 [] -> [D.dullyellow "x","or",D.dullyellow "age"]
3762 c:cs -> [D.dullyellow (D.fromChars (Char.toLower c : cs))]
3763 in
3764 Report.Report "UNEXPECTED NAME" region [] $
3765 Code.toSnippet source region Nothing $
3767 D.reflow $
3768 "Variable names cannot start with underscores like this:"
3770 D.fillSep $
3771 ["You","can","either","have","an","underscore","like",D.dullyellow "_","to"
3772 ,"ignore","the","value,","or","you","can","have","a","name","like"
3773 ] ++ examples ++ ["to","use","the","matched","value." ]
3776 PSpace space row col ->
3777 toSpaceReport source space row col
3779 PIndentStart row col ->
3780 error "TODO PIndentStart" row col
3782 PIndentAlias row col ->
3783 let
3784 region = toRegion row col
3785 in
3786 Report.Report "UNFINISHED PATTERN" region [] $
3787 Code.toSnippet source region Nothing $
3789 D.reflow $
3790 "I was expecting to see a variable name after the `as` keyword:"
3792 D.stack
3793 [ D.fillSep $
3794 ["The","`as`","keyword","lets","you","write","patterns","like"
3795 ,"((" <> D.dullyellow "x" <> "," <> D.dullyellow "y" <> ") " <> D.cyan "as" <> D.dullyellow " point" <> ")"
3796 ,"so","you","can","refer","to","individual","parts","of","the","tuple","with"
3797 ,D.dullyellow "x","and",D.dullyellow "y","or","you","refer","to","the","whole"
3798 ,"thing","with",D.dullyellow "point."
3800 , D.reflow $
3801 "So I was expecting to see a variable name after the `as` keyword here. Sometimes\
3802 \ people just want to use `as` as a variable name though. Try using a different name\
3803 \ in that case!"
3808toPRecordReport :: Code.Source -> PRecord -> Row -> Col -> Report.Report
3809toPRecordReport source record startRow startCol =
3810 case record of
3811 PRecordOpen row col ->
3812 toUnfinishRecordPatternReport source row col startRow startCol $
3813 D.reflow "I was expecting to see a field name next."
3815 PRecordEnd row col ->
3816 toUnfinishRecordPatternReport source row col startRow startCol $
3817 D.fillSep
3818 ["I","was","expecting","to","see","a","closing","curly","brace","next."
3819 ,"Try","adding","a",D.dullyellow "}","here?"
3822 PRecordField row col ->
3823 case Code.whatIsNext source row col of
3824 Code.Keyword keyword ->
3825 let
3826 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3827 region = toKeywordRegion row col keyword
3828 in
3829 Report.Report "RESERVED WORD" region [] $
3830 Code.toSnippet source surroundings (Just region)
3832 D.reflow $
3833 "I was not expecting to see `" ++ keyword ++ "` as a record field name:"
3835 D.reflow $
3836 "This is a reserved word, not available for variable names. Try another name!"
3839 _ ->
3840 toUnfinishRecordPatternReport source row col startRow startCol $
3841 D.reflow "I was expecting to see a field name next."
3843 PRecordSpace space row col ->
3844 toSpaceReport source space row col
3846 PRecordIndentOpen row col ->
3847 toUnfinishRecordPatternReport source row col startRow startCol $
3848 D.reflow "I was expecting to see a field name next."
3850 PRecordIndentEnd row col ->
3851 toUnfinishRecordPatternReport source row col startRow startCol $
3852 D.fillSep
3853 ["I","was","expecting","to","see","a","closing","curly","brace","next."
3854 ,"Try","adding","a",D.dullyellow "}","here?"
3857 PRecordIndentField row col ->
3858 toUnfinishRecordPatternReport source row col startRow startCol $
3859 D.reflow "I was expecting to see a field name next."
3862toUnfinishRecordPatternReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
3863toUnfinishRecordPatternReport source row col startRow startCol message =
3864 let
3865 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3866 region = toRegion row col
3867 in
3868 Report.Report "UNFINISHED RECORD PATTERN" region [] $
3869 Code.toSnippet source surroundings (Just region)
3871 D.reflow $
3872 "I was partway through parsing a record pattern, but I got stuck here:"
3874 D.stack
3875 [ message
3876 , D.toFancyHint $
3877 ["A","record","pattern","looks","like",D.dullyellow "{x,y}","or",D.dullyellow "{name,age}"
3878 ,"where","you","list","the","field","names","you","want","to","access."
3885toPTupleReport :: Code.Source -> PContext -> PTuple -> Row -> Col -> Report.Report
3886toPTupleReport source context tuple startRow startCol =
3887 case tuple of
3888 PTupleOpen row col ->
3889 case Code.whatIsNext source row col of
3890 Code.Keyword keyword ->
3891 let
3892 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3893 region = toKeywordRegion row col keyword
3894 in
3895 Report.Report "RESERVED WORD" region [] $
3896 Code.toSnippet source surroundings (Just region)
3898 D.reflow $
3899 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name:"
3901 D.reflow $
3902 "This is a reserved word! Try using some other name?"
3905 _ ->
3906 let
3907 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3908 region = toRegion row col
3909 in
3910 Report.Report "UNFINISHED PARENTHESES" region [] $
3911 Code.toSnippet source surroundings (Just region)
3913 D.reflow $
3914 "I just saw an open parenthesis, but I got stuck here:"
3916 D.fillSep
3917 ["I","was","expecting","so","see","a","pattern","next."
3918 ,"Maybe","it","will","end","up","being","something"
3919 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "?"
3923 PTupleEnd row col ->
3924 let
3925 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3926 region = toRegion row col
3927 in
3928 Report.Report "UNFINISHED PARENTHESES" region [] $
3929 Code.toSnippet source surroundings (Just region) $
3931 D.reflow $
3932 "I was expecting a closing parenthesis next:"
3934 D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
3937 PTupleExpr pattern row col ->
3938 toPatternReport source context pattern row col
3940 PTupleSpace space row col ->
3941 toSpaceReport source space row col
3943 PTupleIndentEnd row col ->
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 PARENTHESES" region [] $
3949 Code.toSnippet source surroundings (Just region) $
3951 D.reflow $
3952 "I was expecting a closing parenthesis next:"
3954 D.stack
3955 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
3956 , D.toSimpleNote $
3957 "I can get confused by indentation in cases like this, so\
3958 \ maybe you have a closing parenthesis but it is not indented enough?"
3962 PTupleIndentExpr1 row col ->
3963 let
3964 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3965 region = toRegion row col
3966 in
3967 Report.Report "UNFINISHED PARENTHESES" region [] $
3968 Code.toSnippet source surroundings (Just region) $
3970 D.reflow $
3971 "I just saw an open parenthesis, but then I got stuck here:"
3973 D.fillSep
3974 ["I","was","expecting","so","see","a","pattern","next."
3975 ,"Maybe","it","will","end","up","being","something"
3976 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "?"
3980 PTupleIndentExprN row col ->
3981 let
3982 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3983 region = toRegion row col
3984 in
3985 Report.Report "UNFINISHED TUPLE PATTERN" region [] $
3986 Code.toSnippet source surroundings (Just region) $
3988 D.reflow $
3989 "I am partway through parsing a tuple pattern, but I got stuck here:"
3991 D.stack
3992 [ D.fillSep
3993 ["I","was","expecting","so","see","a","pattern","next."
3994 ,"I","am","expecting","the","final","result","to","be","something"
3995 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "."
3997 , D.toSimpleNote $
3998 "I can get confused by indentation in cases like this, so the problem\
3999 \ may be that the next part is not indented enough?"
4004toPListReport :: Code.Source -> PContext -> PList -> Row -> Col -> Report.Report
4005toPListReport source context list startRow startCol =
4006 case list of
4007 PListOpen row col ->
4008 case Code.whatIsNext source row col of
4009 Code.Keyword keyword ->
4010 let
4011 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4012 region = toKeywordRegion row col keyword
4013 in
4014 Report.Report "RESERVED WORD" region [] $
4015 Code.toSnippet source surroundings (Just region)
4017 D.reflow $
4018 "It looks like you are trying to use `" ++ keyword ++ "` to name an element of a list:"
4020 D.reflow $
4021 "This is a reserved word though! Try using some other name?"
4024 _ ->
4025 let
4026 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4027 region = toRegion row col
4028 in
4029 Report.Report "UNFINISHED LIST PATTERN" region [] $
4030 Code.toSnippet source surroundings (Just region) $
4032 D.reflow $
4033 "I just saw an open square bracket, but then I got stuck here:"
4035 D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
4038 PListEnd row col ->
4039 let
4040 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4041 region = toRegion row col
4042 in
4043 Report.Report "UNFINISHED LIST PATTERN" region [] $
4044 Code.toSnippet source surroundings (Just region) $
4046 D.reflow $
4047 "I was expecting a closing square bracket to end this list pattern:"
4049 D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
4052 PListExpr pattern row col ->
4053 toPatternReport source context pattern row col
4055 PListSpace space row col ->
4056 toSpaceReport source space row col
4058 PListIndentOpen row col ->
4059 let
4060 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4061 region = toRegion row col
4062 in
4063 Report.Report "UNFINISHED LIST PATTERN" region [] $
4064 Code.toSnippet source surroundings (Just region) $
4066 D.reflow $
4067 "I just saw an open square bracket, but then I got stuck here:"
4069 D.stack
4070 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
4071 , D.toSimpleNote $
4072 "I can get confused by indentation in cases like this, so\
4073 \ maybe there is something next, but it is not indented enough?"
4077 PListIndentEnd 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 LIST PATTERN" region [] $
4083 Code.toSnippet source surroundings (Just region) $
4085 D.reflow $
4086 "I was expecting a closing square bracket to end this list pattern:"
4088 D.stack
4089 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
4090 , D.toSimpleNote $
4091 "I can get confused by indentation in cases like this, so\
4092 \ maybe you have a closing square bracket but it is not indented enough?"
4096 PListIndentExpr row col ->
4097 let
4098 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4099 region = toRegion row col
4100 in
4101 Report.Report "UNFINISHED LIST PATTERN" region [] $
4102 Code.toSnippet source surroundings (Just region) $
4104 D.reflow $
4105 "I am partway through parsing a list pattern, but I got stuck here:"
4107 D.stack
4108 [ D.reflow $
4109 "I was expecting to see another pattern next. Maybe a variable name."
4110 , D.toSimpleNote $
4111 "I can get confused by indentation in cases like this, so\
4112 \ maybe there is more to this pattern but it is not indented enough?"
4118-- TYPES
4121-- TODO add context? say something special if you are in type annotation vs custom type vs type alias?
4123toTypeReport :: Code.Source -> Type -> Row -> Col -> Report.Report
4124toTypeReport source tipe startRow startCol =
4125 case tipe of
4126 TRecord record row col ->
4127 toTRecordReport source record row col
4129 TTuple tuple row col ->
4130 toTTupleReport source tuple row col
4132 TArrow row col ->
4133 error "TODO TArrow" row col
4135 TStart row col ->
4136 error "TODO TStart" row col startRow startCol
4138 TSpace space row col ->
4139 toSpaceReport source space row col
4141 TIndentStart row col ->
4142 error "TODO TIndentStart" row col
4146toTRecordReport :: Code.Source -> TRecord -> Row -> Col -> Report.Report
4147toTRecordReport source record startRow startCol =
4148 case record of
4149 TRecordOpen row col ->
4150 case Code.whatIsNext source row col of
4151 Code.Keyword keyword ->
4152 let
4153 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4154 region = toKeywordRegion row col keyword
4155 in
4156 Report.Report "RESERVED WORD" region [] $
4157 Code.toSnippet source surroundings (Just region)
4159 D.reflow $
4160 "I just started parsing a record type, but I got stuck on this field name:"
4162 D.reflow $
4163 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
4164 \ that is a reserved word. Try using a different name!"
4167 _ ->
4168 let
4169 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4170 region = toRegion row col
4171 in
4172 Report.Report "UNFINISHED RECORD TYPE" region [] $
4173 Code.toSnippet source surroundings (Just region)
4175 D.reflow $
4176 "I just started parsing a record type, but I got stuck here:"
4178 D.fillSep
4179 ["Record","types","look","like",D.dullyellow "{ name : String, age : Int },"
4180 ,"so","I","was","expecting","to","see","a","field","name","next."
4184 TRecordEnd row col ->
4185 let
4186 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4187 region = toRegion row col
4188 in
4189 Report.Report "UNFINISHED RECORD TYPE" region [] $
4190 Code.toSnippet source surroundings (Just region)
4192 D.reflow $
4193 "I am partway through parsing a record type, but I got stuck here:"
4195 D.stack
4196 [ D.fillSep
4197 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
4198 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
4200 , D.toSimpleNote $
4201 "When I get stuck like this, it usually means that there is a missing parenthesis\
4202 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
4206 TRecordField row col ->
4207 case Code.whatIsNext source row col of
4208 Code.Keyword keyword ->
4209 let
4210 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4211 region = toKeywordRegion row col keyword
4212 in
4213 Report.Report "RESERVED WORD" region [] $
4214 Code.toSnippet source surroundings (Just region)
4216 D.reflow $
4217 "I am partway through parsing a record type, but I got stuck on this field name:"
4219 D.reflow $
4220 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
4221 \ that is a reserved word. Try using a different name!"
4224 _ ->
4225 let
4226 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4227 region = toRegion row col
4228 in
4229 Report.Report "UNFINISHED RECORD TYPE" region [] $
4230 Code.toSnippet source surroundings (Just region)
4232 D.reflow $
4233 "I am partway through parsing a record type, but I got stuck after that last comma:"
4235 addNoteForRecordTypeError $
4236 D.reflow $
4237 "Trailing commas are not allowed in records, so I was expecting to see another\
4238 \ record field defined next. If you are done defining the record, the fix may\
4239 \ be to delete that last comma?"
4242 TRecordColon row col ->
4243 let
4244 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4245 region = toRegion row col
4246 in
4247 Report.Report "UNFINISHED RECORD TYPE" region [] $
4248 Code.toSnippet source surroundings (Just region)
4250 D.reflow $
4251 "I am partway through parsing a record type, but I got stuck here:"
4253 addNoteForRecordTypeError $
4254 D.fillSep $
4255 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
4256 ,"a","colon","next.","So","try","putting","an",D.green ":","sign","here?"
4260 TRecordType tipe row col ->
4261 toTypeReport source tipe row col
4263 TRecordSpace space row col ->
4264 toSpaceReport source space row col
4266 TRecordIndentOpen row col ->
4267 let
4268 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4269 region = toRegion row col
4270 in
4271 Report.Report "UNFINISHED RECORD TYPE" region [] $
4272 Code.toSnippet source surroundings (Just region)
4274 D.reflow $
4275 "I just saw the opening curly brace of a record type, but then I got stuck here:"
4277 addNoteForRecordTypeIndentError $
4278 D.fillSep $
4279 ["I","am","expecting","a","record","like",D.dullyellow "{ name : String, age : Int }","here."
4280 ,"Try","defining","some","fields","of","your","own?"
4284 TRecordIndentEnd 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 RECORD TYPE" region [] $
4290 Code.toSnippet source surroundings (Just region)
4292 D.reflow $
4293 "I was expecting to see a closing curly brace next:"
4295 addNoteForRecordTypeIndentError $
4296 D.fillSep $
4297 ["Try","putting","an",D.green "}","and","see","if","that","helps?"
4301 TRecordIndentField row col ->
4302 let
4303 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4304 region = toRegion row col
4305 in
4306 Report.Report "UNFINISHED RECORD TYPE" region [] $
4307 Code.toSnippet source surroundings (Just region)
4309 D.reflow $
4310 "I am partway through parsing a record type, but I got stuck after that last comma:"
4312 addNoteForRecordTypeIndentError $
4313 D.reflow $
4314 "Trailing commas are not allowed in record types, so the fix may be to\
4315 \ delete that last comma? Or maybe you were in the middle of defining\
4316 \ an additional field?"
4319 TRecordIndentColon row col ->
4320 let
4321 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4322 region = toRegion row col
4323 in
4324 Report.Report "UNFINISHED RECORD TYPE" region [] $
4325 Code.toSnippet source surroundings (Just region)
4327 D.reflow $
4328 "I am partway through parsing a record type. I just saw a record\
4329 \ field, so I was expecting to see a colon next:"
4331 addNoteForRecordTypeIndentError $
4332 D.fillSep $
4333 ["Try","putting","an",D.green ":","followed","by","a","type?"
4337 TRecordIndentType row col ->
4338 let
4339 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4340 region = toRegion row col
4341 in
4342 Report.Report "UNFINISHED RECORD TYPE" region [] $
4343 Code.toSnippet source surroundings (Just region)
4345 D.reflow $
4346 "I am partway through parsing a record type, and I was expecting to run into a type next:"
4348 addNoteForRecordTypeIndentError $
4349 D.fillSep $
4350 ["Try","putting","something,","like"
4351 ,D.dullyellow "Int","or",D.dullyellow "String","for","now?"
4356addNoteForRecordTypeError :: D.Doc -> D.Doc
4357addNoteForRecordTypeError normalRecommendation =
4358 D.stack $
4359 normalRecommendation
4361 [ D.toSimpleNote
4362 "If you are trying to define a record type across multiple lines, I recommend using this format:"
4363 , D.indent 4 $ D.vcat $
4364 [ "{ name : String"
4365 , ", age : Int"
4366 , ", height : Float"
4367 , "}"
4369 , D.reflow $
4370 "Notice that each line starts with some indentation. Usually two or four spaces. I\
4371 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
4372 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
4376addNoteForRecordTypeIndentError :: D.Doc -> D.Doc
4377addNoteForRecordTypeIndentError normalRecommendation =
4378 D.stack $
4379 normalRecommendation
4381 [ D.toSimpleNote
4382 "I may be confused by indentation. For example, if you are trying to define\
4383 \ a record type across multiple lines, I recommend using this format:"
4384 , D.indent 4 $ D.vcat $
4385 [ "{ name : String"
4386 , ", age : Int"
4387 , ", height : Float"
4388 , "}"
4390 , D.reflow $
4391 "Notice that each line starts with some indentation. Usually two or four spaces. I\
4392 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
4393 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
4397toTTupleReport :: Code.Source -> TTuple -> Row -> Col -> Report.Report
4398toTTupleReport source tuple startRow startCol =
4399 case tuple of
4400 TTupleOpen row col ->
4401 case Code.whatIsNext source row col of
4402 Code.Keyword keyword ->
4403 let
4404 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4405 region = toKeywordRegion row col keyword
4406 in
4407 Report.Report "RESERVED WORD" region [] $
4408 Code.toSnippet source surroundings (Just region)
4410 D.reflow $
4411 "I ran into a reserved word unexpectedly:"
4413 D.reflow $
4414 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name, but \
4415 \ it is a reserved word. Try using a different name!"
4418 _ ->
4419 let
4420 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4421 region = toRegion row col
4422 in
4423 Report.Report "UNFINISHED PARENTHESES" region [] $
4424 Code.toSnippet source surroundings (Just region)
4426 D.reflow $
4427 "I just saw an open parenthesis, so I was expecting to see a type next."
4429 D.fillSep $
4430 ["Something","like",D.dullyellow "(Maybe Int)","or"
4431 ,D.dullyellow "(List Person)" <> "."
4432 ,"Anything","where","you","are","putting","parentheses","around","normal","types."
4436 TTupleEnd row col ->
4437 let
4438 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4439 region = toRegion row col
4440 in
4441 Report.Report "UNFINISHED PARENTHESES" region [] $
4442 Code.toSnippet source surroundings (Just region)
4444 D.reflow $
4445 "I was expecting to see a closing parentheses next, but I got stuck here:"
4447 D.stack
4448 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
4449 , D.toSimpleNote $
4450 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
4451 \ unexpectedly. So there may be some earlier syntax trouble (like extra parenthesis\
4452 \ or missing brackets) that is confusing me."
4456 TTupleType tipe row col ->
4457 toTypeReport source tipe row col
4459 TTupleSpace space row col ->
4460 toSpaceReport source space row col
4462 TTupleIndentType1 row col ->
4463 let
4464 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4465 region = toRegion row col
4466 in
4467 Report.Report "UNFINISHED PARENTHESES" region [] $
4468 Code.toSnippet source surroundings (Just region)
4470 D.reflow $
4471 "I just saw an open parenthesis, so I was expecting to see a type next."
4473 D.stack
4474 [ D.fillSep $
4475 ["Something","like",D.dullyellow "(Maybe Int)","or"
4476 ,D.dullyellow "(List Person)" <> "."
4477 ,"Anything","where","you","are","putting","parentheses","around","normal","types."
4479 , D.toSimpleNote $
4480 "I can get confused by indentation in cases like this, so\
4481 \ maybe you have a type but it is not indented enough?"
4485 TTupleIndentTypeN row col ->
4486 let
4487 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4488 region = toRegion row col
4489 in
4490 Report.Report "UNFINISHED TUPLE TYPE" region [] $
4491 Code.toSnippet source surroundings (Just region)
4493 D.reflow $
4494 "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."
4496 D.stack
4497 [ D.fillSep $
4498 ["A","tuple","type","looks","like",D.dullyellow "(Float,Float)","or"
4499 ,D.dullyellow "(String,Int)" <> ","
4500 ,"so","I","think","there","is","a","type","missing","here?"
4502 , D.toSimpleNote $
4503 "I can get confused by indentation in cases like this, so\
4504 \ maybe you have an expression but it is not indented enough?"
4508 TTupleIndentEnd row col ->
4509 let
4510 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4511 region = toRegion row col
4512 in
4513 Report.Report "UNFINISHED PARENTHESES" region [] $
4514 Code.toSnippet source surroundings (Just region)
4516 D.reflow $
4517 "I was expecting to see a closing parenthesis next:"
4519 D.stack
4520 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
4521 , D.toSimpleNote $
4522 "I can get confused by indentation in cases like this, so\
4523 \ maybe you have a closing parenthesis but it is not indented enough?"