on dbf582a help sign in
5848 lines 211 kB history raw
1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Reporting.Error.Syntax
4 ( Error(..)
5 , toReport
6 --
7 , Module(..)
8 , Exposing(..)
9 --
10 , Decl(..)
11 , DeclType(..)
12 , TypeAlias(..)
13 , CustomType(..)
14 , DeclDef(..)
15 , Port(..)
16 --
17 , Expr(..)
18 , Record(..)
19 , Tuple(..)
20 , List(..)
21 , Func(..)
22 , Case(..)
23 , If(..)
24 , Let(..)
25 , Def(..)
26 , Destruct(..)
27 --
28 , Pattern(..)
29 , PRecord(..)
30 , PTuple(..)
31 , PList(..)
32 --
33 , Type(..)
34 , TRecord(..)
35 , TTuple(..)
36 --
37 , Char(..)
38 , String(..)
39 , Escape(..)
40 , Number(..)
41 --
42 , Space(..)
43 , toSpaceReport
44 )
45 where
48import Prelude hiding (Char, String)
49import qualified Data.Char as Char
50import qualified Data.Name as Name
51import Data.Word (Word16)
52import Numeric (showHex)
54import qualified Elm.ModuleName as ModuleName
55import Parse.Primitives (Row, Col)
56import Parse.Symbol (BadOperator(..))
57import qualified Reporting.Annotation as A
58import qualified Reporting.Doc as D
59import qualified Reporting.Report as Report
60import qualified Reporting.Render.Code as Code
64-- ALL SYNTAX ERRORS
67data Error
68 = ModuleNameUnspecified ModuleName.Raw
69 | ModuleNameMismatch ModuleName.Raw (A.Located ModuleName.Raw)
70 | UnexpectedPort A.Region
71 | NoPorts A.Region
72 | NoPortsInPackage (A.Located Name.Name)
73 | NoPortModulesInPackage A.Region
74 | NoEffectsOutsideKernel A.Region
75 | ParseError Module
79-- MODULE
82data Module
83 = ModuleSpace Space Row Col
84 | ModuleBadEnd Row Col
85 --
86 | ModuleProblem Row Col
87 | ModuleName Row Col
88 | ModuleExposing Exposing Row Col
89 --
90 | PortModuleProblem Row Col
91 | PortModuleName Row Col
92 | PortModuleExposing Exposing Row Col
93 --
94 | Effect Row Col
95 --
96 | FreshLine Row Col
97 --
98 | ImportStart Row Col
99 | ImportName Row Col
100 | ImportAs Row Col
101 | ImportAlias Row Col
102 | ImportExposing Row Col
103 | ImportExposingList Exposing Row Col
104 | ImportEnd Row Col -- different based on col=1 or if greater
105 --
106 | ImportIndentName Row Col
107 | ImportIndentAlias Row Col
108 | ImportIndentExposingList Row Col
109 --
110 | Infix Row Col
111 --
112 | Declarations Decl Row Col
115data Exposing
116 = ExposingSpace Space Row Col
117 | ExposingStart Row Col
118 | ExposingValue Row Col
119 | ExposingOperator Row Col
120 | ExposingOperatorReserved BadOperator Row Col
121 | ExposingOperatorRightParen Row Col
122 | ExposingTypePrivacy Row Col
123 | ExposingEnd Row Col
124 --
125 | ExposingIndentEnd Row Col
126 | ExposingIndentValue Row Col
130-- DECLARATIONS
133data Decl
134 = DeclStart Row Col
135 | DeclSpace Space Row Col
136 --
137 | Port Port Row Col
138 | DeclType DeclType Row Col
139 | DeclDef Name.Name DeclDef Row Col
140 --
141 | DeclFreshLineAfterDocComment Row Col
144data DeclDef
145 = DeclDefSpace Space Row Col
146 | DeclDefEquals Row Col
147 | DeclDefType Type Row Col
148 | DeclDefArg Pattern Row Col
149 | DeclDefBody Expr Row Col
150 | DeclDefNameRepeat Row Col
151 | DeclDefNameMatch Name.Name Row Col
152 --
153 | DeclDefIndentType Row Col
154 | DeclDefIndentEquals Row Col
155 | DeclDefIndentBody Row Col
158data Port
159 = PortSpace Space Row Col
160 | PortName Row Col
161 | PortColon Row Col
162 | PortType Type Row Col
163 | PortIndentName Row Col
164 | PortIndentColon Row Col
165 | PortIndentType Row Col
169-- TYPE DECLARATIONS
172data DeclType
173 = DT_Space Space Row Col
174 | DT_Name Row Col
175 | DT_Alias TypeAlias Row Col
176 | DT_Union CustomType Row Col
177 --
178 | DT_IndentName Row Col
181data TypeAlias
182 = AliasSpace Space Row Col
183 | AliasName Row Col
184 | AliasEquals Row Col
185 | AliasBody Type Row Col
186 --
187 | AliasIndentEquals Row Col
188 | AliasIndentBody Row Col
191data CustomType
192 = CT_Space Space Row Col
193 | CT_Name Row Col
194 | CT_Equals Row Col
195 | CT_Bar Row Col
196 | CT_Variant Row Col
197 | CT_VariantArg Type Row Col
198 --
199 | CT_IndentEquals Row Col
200 | CT_IndentBar Row Col
201 | CT_IndentAfterBar Row Col
202 | CT_IndentAfterEquals Row Col
206-- EXPRESSIONS
209data Expr
210 = Let Let Row Col
211 | Case Case Row Col
212 | If If Row Col
213 | List List Row Col
214 | Record Record Row Col
215 | Tuple Tuple Row Col
216 | Func Func Row Col
217 --
218 | Dot Row Col
219 | Access Row Col
220 | OperatorRight Name.Name Row Col
221 | OperatorReserved BadOperator Row Col
222 --
223 | Start Row Col
224 | Char Char Row Col
225 | String String Row Col
226 | Number Number Row Col
227 | Space Space Row Col
228 | EndlessShader Row Col
229 | ShaderProblem [Char.Char] Row Col
230 | IndentOperatorRight Name.Name Row Col
233data Record
234 = RecordOpen Row Col
235 | RecordEnd Row Col
236 | RecordField Row Col
237 | RecordEquals Row Col
238 | RecordExpr Expr Row Col
239 | RecordSpace Space Row Col
240 --
241 | RecordIndentOpen Row Col
242 | RecordIndentEnd Row Col
243 | RecordIndentField Row Col
244 | RecordIndentEquals Row Col
245 | RecordIndentExpr Row Col
248data Tuple
249 = TupleExpr Expr Row Col
250 | TupleSpace Space Row Col
251 | TupleEnd Row Col
252 | TupleOperatorClose Row Col
253 | TupleOperatorReserved BadOperator Row Col
254 --
255 | TupleIndentExpr1 Row Col
256 | TupleIndentExprN Row Col
257 | TupleIndentEnd Row Col
260data List
261 = ListSpace Space Row Col
262 | ListOpen Row Col
263 | ListExpr Expr Row Col
264 | ListEnd Row Col
265 --
266 | ListIndentOpen Row Col
267 | ListIndentEnd Row Col
268 | ListIndentExpr Row Col
271data Func
272 = FuncSpace Space Row Col
273 | FuncArg Pattern Row Col
274 | FuncBody Expr Row Col
275 | FuncArrow Row Col
276 --
277 | FuncIndentArg Row Col
278 | FuncIndentArrow Row Col
279 | FuncIndentBody Row Col
282data Case
283 = CaseSpace Space Row Col
284 | CaseOf Row Col
285 | CasePattern Pattern Row Col
286 | CaseArrow Row Col
287 | CaseExpr Expr Row Col
288 | CaseBranch Expr Row Col
289 --
290 | CaseIndentOf Row Col
291 | CaseIndentExpr Row Col
292 | CaseIndentPattern Row Col
293 | CaseIndentArrow Row Col
294 | CaseIndentBranch Row Col
295 | CasePatternAlignment Word16 Row Col
298data If
299 = IfSpace Space Row Col
300 | IfThen Row Col
301 | IfElse Row Col
302 | IfElseBranchStart Row Col
303 --
304 | IfCondition Expr Row Col
305 | IfThenBranch Expr Row Col
306 | IfElseBranch Expr Row Col
307 --
308 | IfIndentCondition Row Col
309 | IfIndentThen Row Col
310 | IfIndentThenBranch Row Col
311 | IfIndentElseBranch Row Col
312 | IfIndentElse Row Col
315data Let
316 = LetSpace Space Row Col
317 | LetIn Row Col
318 | LetDefAlignment Word16 Row Col
319 | LetDefName Row Col
320 | LetDef Name.Name Def Row Col
321 | LetDestruct Destruct Row Col
322 | LetBody Expr Row Col
323 | LetIndentDef Row Col
324 | LetIndentIn Row Col
325 | LetIndentBody Row Col
328data Def
329 = DefSpace Space Row Col
330 | DefType Type Row Col
331 | DefNameRepeat Row Col
332 | DefNameMatch Name.Name Row Col
333 | DefArg Pattern Row Col
334 | DefEquals Row Col
335 | DefBody Expr Row Col
336 | DefIndentEquals Row Col
337 | DefIndentType Row Col
338 | DefIndentBody Row Col
339 | DefAlignment Word16 Row Col
342data Destruct
343 = DestructSpace Space Row Col
344 | DestructPattern Pattern Row Col
345 | DestructEquals Row Col
346 | DestructBody Expr Row Col
347 | DestructIndentEquals Row Col
348 | DestructIndentBody Row Col
352-- PATTERNS
355data Pattern
356 = PRecord PRecord Row Col
357 | PTuple PTuple Row Col
358 | PList PList Row Col
359 --
360 | PStart Row Col
361 | PChar Char Row Col
362 | PString String Row Col
363 | PNumber Number Row Col
364 | PFloat Word16 Row Col
365 | PAlias Row Col
366 | PWildcardNotVar Name.Name Int Row Col
367 | PSpace Space Row Col
368 --
369 | PIndentStart Row Col
370 | PIndentAlias Row Col
373data PRecord
374 = PRecordOpen Row Col
375 | PRecordEnd Row Col
376 | PRecordField Row Col
377 | PRecordSpace Space Row Col
378 --
379 | PRecordIndentOpen Row Col
380 | PRecordIndentEnd Row Col
381 | PRecordIndentField Row Col
384data PTuple
385 = PTupleOpen Row Col
386 | PTupleEnd Row Col
387 | PTupleExpr Pattern Row Col
388 | PTupleSpace Space Row Col
389 --
390 | PTupleIndentEnd Row Col
391 | PTupleIndentExpr1 Row Col
392 | PTupleIndentExprN Row Col
395data PList
396 = PListOpen Row Col
397 | PListEnd Row Col
398 | PListExpr Pattern Row Col
399 | PListSpace Space Row Col
400 --
401 | PListIndentOpen Row Col
402 | PListIndentEnd Row Col
403 | PListIndentExpr Row Col
407-- TYPES
410data Type
411 = TRecord TRecord Row Col
412 | TTuple TTuple Row Col
413 --
414 | TStart Row Col
415 | TSpace Space Row Col
416 --
417 | TIndentStart Row Col
420data TRecord
421 = TRecordOpen Row Col
422 | TRecordEnd Row Col
423 --
424 | TRecordField Row Col
425 | TRecordColon Row Col
426 | TRecordType Type Row Col
427 --
428 | TRecordSpace Space Row Col
429 --
430 | TRecordIndentOpen Row Col
431 | TRecordIndentField Row Col
432 | TRecordIndentColon Row Col
433 | TRecordIndentType Row Col
434 | TRecordIndentEnd Row Col
437data TTuple
438 = TTupleOpen Row Col
439 | TTupleEnd Row Col
440 | TTupleType Type Row Col
441 | TTupleSpace Space Row Col
442 --
443 | TTupleIndentType1 Row Col
444 | TTupleIndentTypeN Row Col
445 | TTupleIndentEnd Row Col
449-- LITERALS
452data Char
453 = CharEndless
454 | CharEscape Escape
455 | CharNotString Word16
458data String
459 = StringEndless_Single
460 | StringEndless_Multi
461 | StringEscape Escape
464data Escape
465 = EscapeUnknown
466 | BadUnicodeFormat Word16
467 | BadUnicodeCode Word16
468 | BadUnicodeLength Word16 Int Int
471data Number
472 = NumberEnd
473 | NumberDot Int
474 | NumberHexDigit
475 | NumberNoLeadingZero
479-- MISC
482data Space
483 = HasTab
484 | EndlessMultiComment
488-- TO REPORT
491toReport :: Code.Source -> Error -> Report.Report
492toReport source err =
493 case err of
494 ModuleNameUnspecified name ->
495 let
496 region = toRegion 1 1
497 in
498 Report.Report "MODULE NAME MISSING" region [] $
499 D.stack
500 [ D.reflow $
501 "I need the module name to be declared at the top of this file, like this:"
502 , D.indent 4 $ D.fillSep $
503 [ D.cyan "module", D.fromName name, D.cyan "exposing", "(..)" ]
504 , D.reflow $
505 "Try adding that as the first line of your file!"
506 , D.toSimpleNote $
507 "It is best to replace (..) with an explicit list of types and\
508 \ functions you want to expose. When you know a value is only used\
509 \ within this module, you can refactor without worrying about uses\
510 \ elsewhere. Limiting exposed values can also speed up compilation\
511 \ because I can skip a bunch of work if I see that the exposed API\
512 \ has not changed."
513 ]
515 ModuleNameMismatch expectedName (A.At region actualName) ->
516 Report.Report "MODULE NAME MISMATCH" region [ModuleName.toChars expectedName] $
517 Code.toSnippet source region Nothing
518 (
519 "It looks like this module name is out of sync:"
520 ,
521 D.stack
522 [ D.reflow $
523 "I need it to match the file path, so I was expecting to see `"
524 ++ ModuleName.toChars expectedName
525 ++ "` here. Make the following change, and you should be all set!"
526 , D.indent 4 $
527 D.dullyellow (D.fromName actualName) <> " -> " <> D.green (D.fromName expectedName)
528 , D.toSimpleNote $
529 "I require that module names correspond to file paths. This makes it much\
530 \ easier to explore unfamiliar codebases! So if you want to keep the current\
531 \ module name, try renaming the file instead."
532 ]
533 )
535 UnexpectedPort region ->
536 Report.Report "UNEXPECTED PORTS" region [] $
537 Code.toSnippet source region Nothing
538 (
539 D.reflow $
540 "You are declaring ports in a normal module."
541 ,
542 D.stack
543 [ D.fillSep
544 ["Switch","this","to","say",D.cyan "port module","instead,"
545 ,"marking","that","this","module","contains","port","declarations."
546 ]
547 , D.link "Note"
548 "Ports are not a traditional FFI for calling JS functions directly. They need a different mindset! Read"
549 "ports"
550 "to learn the syntax and how to use it effectively."
551 ]
552 )
554 NoPorts region ->
555 Report.Report "NO PORTS" region [] $
556 Code.toSnippet source region Nothing
557 (
558 D.reflow $
559 "This module does not declare any ports, but it says it will:"
560 ,
561 D.fillSep
562 ["Switch","this","to",D.cyan "module"
563 ,"and","you","should","be","all","set!"
564 ]
565 )
567 NoPortsInPackage (A.At region _) ->
568 Report.Report "PACKAGES CANNOT HAVE PORTS" region [] $
569 Code.toSnippet source region Nothing
570 (
571 D.reflow $
572 "Packages cannot declare any ports, so I am getting stuck here:"
573 ,
574 D.stack
575 [ D.reflow $
576 "Remove this port declaration."
577 , noteForPortsInPackage
578 ]
579 )
581 NoPortModulesInPackage region ->
582 Report.Report "PACKAGES CANNOT HAVE PORTS" region [] $
583 Code.toSnippet source region Nothing
584 (
585 D.reflow $
586 "Packages cannot declare any ports, so I am getting stuck here:"
587 ,
588 D.stack
589 [ D.fillSep $
590 ["Remove","the",D.cyan "port","keyword","and","I"
591 ,"should","be","able","to","continue."
592 ]
593 , noteForPortsInPackage
594 ]
595 )
597 NoEffectsOutsideKernel region ->
598 Report.Report "INVALID EFFECT MODULE" region [] $
599 Code.toSnippet source region Nothing
600 (
601 D.reflow $
602 "It is not possible to declare an `effect module` outside the @elm organization,\
603 \ so I am getting stuck here:"
604 ,
605 D.stack
606 [ D.reflow $
607 "Switch to a normal module declaration."
608 , D.toSimpleNote $
609 "Effect modules are designed to allow certain core functionality to be\
610 \ defined separately from the compiler. So the @elm organization has access to\
611 \ this so that certain changes, extensions, and fixes can be introduced without\
612 \ needing to release new Elm binaries. For example, we want to make it possible\
613 \ to test effects, but this may require changes to the design of effect modules.\
614 \ By only having them defined in the @elm organization, that kind of design work\
615 \ can proceed much more smoothly."
616 ]
617 )
619 ParseError modul ->
620 toParseErrorReport source modul
623noteForPortsInPackage :: D.Doc
624noteForPortsInPackage =
625 D.stack
626 [ D.toSimpleNote $
627 "One of the major goals of the package ecosystem is to be completely written\
628 \ in Elm. This means when you install an Elm package, you can be sure you are safe\
629 \ from security issues on install and that you are not going to get any runtime\
630 \ exceptions coming from your new dependency. This design also sets the ecosystem\
631 \ up to target other platforms more easily (like mobile phones, WebAssembly, etc.)\
632 \ since no community code explicitly depends on JavaScript even existing."
633 , D.reflow $
634 "Given that overall goal, allowing ports in packages would lead to some pretty\
635 \ surprising behavior. If ports were allowed in packages, you could install a\
636 \ package but not realize that it brings in an indirect dependency that defines a\
637 \ port. Now you have a program that does not work and the fix is to realize that\
638 \ some JavaScript needs to be added for a dependency you did not even know about.\
639 \ That would be extremely frustrating! \"So why not allow the package author to\
640 \ include the necessary JS code as well?\" Now we are back in conflict with our\
641 \ overall goal to keep all community packages free from runtime exceptions."
642 ]
645toParseErrorReport :: Code.Source -> Module -> Report.Report
646toParseErrorReport source modul =
647 case modul of
648 ModuleSpace space row col ->
649 toSpaceReport source space row col
651 ModuleBadEnd row col ->
652 if col == 1
653 then toDeclStartReport source row col
654 else toWeirdEndReport source row col
656 ModuleProblem row col ->
657 let
658 region = toRegion row col
659 in
660 Report.Report "UNFINISHED MODULE DECLARATION" region [] $
661 Code.toSnippet source region Nothing
662 (
663 D.reflow $
664 "I am parsing an `module` declaration, but I got stuck here:"
665 ,
666 D.stack
667 [ D.reflow $
668 "Here are some examples of valid `module` declarations:"
669 , D.indent 4 $ D.vcat $
670 [ D.fillSep [D.cyan "module","Main",D.cyan "exposing","(..)"]
671 , D.fillSep [D.cyan "module","Dict",D.cyan "exposing","(Dict, empty, get)"]
672 ]
673 , D.reflow $
674 "I generally recommend using an explicit exposing list. I can skip compiling a bunch\
675 \ of files when the public interface of a module stays the same, so exposing fewer\
676 \ values can help improve compile times!"
677 ]
678 )
680 ModuleName row col ->
681 let
682 region = toRegion row col
683 in
684 Report.Report "EXPECTING MODULE NAME" region [] $
685 Code.toSnippet source region Nothing
686 (
687 D.reflow $
688 "I was parsing an `module` declaration until I got stuck here:"
689 ,
690 D.stack
691 [ D.reflow $
692 "I was expecting to see the module name next, like in these examples:"
693 , D.indent 4 $ D.vcat $
694 [ D.fillSep [D.cyan "module","Dict",D.cyan "exposing","(..)"]
695 , D.fillSep [D.cyan "module","Maybe",D.cyan "exposing","(..)"]
696 , D.fillSep [D.cyan "module","Html.Attributes",D.cyan "exposing","(..)"]
697 , D.fillSep [D.cyan "module","Json.Decode",D.cyan "exposing","(..)"]
698 ]
699 , D.reflow $
700 "Notice that the module names all start with capital letters. That is required!"
701 ]
702 )
704 ModuleExposing exposing row col ->
705 toExposingReport source exposing row col
707 PortModuleProblem row col ->
708 let
709 region = toRegion row col
710 in
711 Report.Report "UNFINISHED PORT MODULE DECLARATION" region [] $
712 Code.toSnippet source region Nothing
713 (
714 D.reflow $
715 "I am parsing an `port module` declaration, but I got stuck here:"
716 ,
717 D.stack
718 [ D.reflow $
719 "Here are some examples of valid `port module` declarations:"
720 , D.indent 4 $ D.vcat $
721 [ D.fillSep [D.cyan "port",D.cyan "module","WebSockets",D.cyan "exposing","(send, listen, keepAlive)"]
722 , D.fillSep [D.cyan "port",D.cyan "module","Maps",D.cyan "exposing","(Location, goto)"]
723 ]
724 , D.link "Note" "Read" "ports" "for more help."
725 ]
726 )
728 PortModuleName row col ->
729 let
730 region = toRegion row col
731 in
732 Report.Report "EXPECTING MODULE NAME" region [] $
733 Code.toSnippet source region Nothing
734 (
735 D.reflow $
736 "I was parsing an `module` declaration until I got stuck here:"
737 ,
738 D.stack
739 [ D.reflow $
740 "I was expecting to see the module name next, like in these examples:"
741 , D.indent 4 $ D.vcat $
742 [ D.fillSep [D.cyan "port",D.cyan "module","WebSockets",D.cyan "exposing","(send, listen, keepAlive)"]
743 , D.fillSep [D.cyan "port",D.cyan "module","Maps",D.cyan "exposing","(Location, goto)"]
744 ]
745 , D.reflow $
746 "Notice that the module names start with capital letters. That is required!"
747 ]
748 )
750 PortModuleExposing exposing row col ->
751 toExposingReport source exposing row col
753 Effect row col ->
754 let
755 region = toRegion row col
756 in
757 Report.Report "BAD MODULE DECLARATION" region [] $
758 Code.toSnippet source region Nothing
759 (
760 D.reflow $
761 "I cannot parse this module declaration:"
762 ,
763 D.reflow $
764 "This type of module is reserved for the @elm organization. It is used to\
765 \ define certain effects, avoiding building them into the compiler."
766 )
768 FreshLine row col ->
769 let
770 region = toRegion row col
772 toBadFirstLineReport keyword =
773 Report.Report "TOO MUCH INDENTATION" region [] $
774 Code.toSnippet source region Nothing
775 (
776 D.reflow $
777 "This `" ++ keyword ++ "` should not have any spaces before it:"
778 ,
779 D.reflow $
780 "Delete the spaces before `" ++ keyword ++ "` until there are none left!"
781 )
783 in
784 case Code.whatIsNext source row col of
785 Code.Keyword "module" -> toBadFirstLineReport "module"
786 Code.Keyword "import" -> toBadFirstLineReport "import"
787 Code.Keyword "type" -> toBadFirstLineReport "type"
788 Code.Keyword "port" -> toBadFirstLineReport "port"
789 _ ->
790 Report.Report "SYNTAX PROBLEM" region [] $
791 Code.toSnippet source region Nothing
792 (
793 D.reflow $
794 "I got stuck here:"
795 ,
796 D.stack
797 [ D.reflow $
798 "I am not sure what is going on, but I recommend starting an Elm\
799 \ file with the following lines:"
800 , D.indent 4 $ D.vcat $
801 [ D.fillSep [D.cyan "import","Html"]
802 , ""
803 , "main ="
804 , " Html.text " <> D.dullyellow "\"Hello!\""
805 ]
806 , D.reflow $
807 "You should be able to copy those lines directly into your file. Check out the\
808 \ examples at <https://elm-lang.org/examples> for more help getting started!"
809 , D.toSimpleNote $
810 "This can also happen when something is indented too much!"
811 ]
812 )
814 ImportStart row col ->
815 toImportReport source row col
817 ImportName row col ->
818 let
819 region = toRegion row col
820 in
821 Report.Report "EXPECTING IMPORT NAME" region [] $
822 Code.toSnippet source region Nothing
823 (
824 D.reflow $
825 "I was parsing an `import` until I got stuck here:"
826 ,
827 D.stack
828 [ D.reflow $
829 "I was expecting to see a module name next, like in these examples:"
830 , D.indent 4 $ D.vcat $
831 [ D.fillSep [D.cyan "import","Dict"]
832 , D.fillSep [D.cyan "import","Maybe"]
833 , D.fillSep [D.cyan "import","Html.Attributes",D.cyan "as","A"]
834 , D.fillSep [D.cyan "import","Json.Decode",D.cyan "exposing","(..)"]
835 ]
836 , D.reflow $
837 "Notice that the module names all start with capital letters. That is required!"
838 , D.reflowLink "Read" "imports" "to learn more."
839 ]
840 )
842 ImportAs row col ->
843 toImportReport source row col
845 ImportAlias row col ->
846 let
847 region = toRegion row col
848 in
849 Report.Report "EXPECTING IMPORT ALIAS" region [] $
850 Code.toSnippet source region Nothing
851 (
852 D.reflow $
853 "I was parsing an `import` until I got stuck here:"
854 ,
855 D.stack
856 [ D.reflow $
857 "I was expecting to see an alias next, like in these examples:"
858 , D.indent 4 $ D.vcat $
859 [ D.fillSep [D.cyan "import","Html.Attributes",D.cyan "as","Attr"]
860 , D.fillSep [D.cyan "import","WebGL.Texture",D.cyan "as","Texture"]
861 , D.fillSep [D.cyan "import","Json.Decode",D.cyan "as","D"]
862 ]
863 , D.reflow $
864 "Notice that the alias always starts with a capital letter. That is required!"
865 , D.reflowLink "Read" "imports" "to learn more."
866 ]
867 )
869 ImportExposing row col ->
870 toImportReport source row col
872 ImportExposingList exposing row col ->
873 toExposingReport source exposing row col
875 ImportEnd row col ->
876 toImportReport source row col
878 ImportIndentName row col ->
879 toImportReport source row col
881 ImportIndentAlias row col ->
882 toImportReport source row col
884 ImportIndentExposingList row col ->
885 let
886 region = toRegion row col
887 in
888 Report.Report "UNFINISHED IMPORT" region [] $
889 Code.toSnippet source region Nothing
890 (
891 D.reflow $
892 "I was parsing an `import` until I got stuck here:"
893 ,
894 D.stack
895 [ D.reflow $
896 "I was expecting to see the list of exposed values next. For example, here\
897 \ are two ways to expose values from the `Html` module:"
898 , D.indent 4 $ D.vcat $
899 [ D.fillSep [D.cyan "import","Html",D.cyan "exposing","(..)"]
900 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
901 ]
902 , D.reflow $
903 "I generally recommend the second style. It is more explicit, making it\
904 \ much easier to figure out where values are coming from in large projects!"
905 ]
906 )
908 Infix row col ->
909 let
910 region = toRegion row col
911 in
912 Report.Report "BAD INFIX" region [] $
913 Code.toSnippet source region Nothing
914 (
915 D.reflow $
916 "Something went wrong in this infix operator declaration:"
917 ,
918 D.reflow $
919 "This feature is used by the @elm organization to define the\
920 \ languages built-in operators."
921 )
923 Declarations decl _ _ ->
924 toDeclarationsReport source decl
928-- WEIRD END
931toWeirdEndReport :: Code.Source -> Row -> Col -> Report.Report
932toWeirdEndReport source row col =
933 case Code.whatIsNext source row col of
934 Code.Keyword keyword ->
935 let
936 region = toKeywordRegion row col keyword
937 in
938 Report.Report "RESERVED WORD" region [] $
939 Code.toSnippet source region Nothing
940 (
941 D.reflow $
942 "I got stuck on this reserved word:"
943 ,
944 D.reflow $
945 "The name `" ++ keyword ++ "` is reserved, so try using a different name?"
946 )
948 Code.Operator op ->
949 let
950 region = toKeywordRegion row col op
951 in
952 Report.Report "UNEXPECTED SYMBOL" region [] $
953 Code.toSnippet source region Nothing
954 (
955 D.reflow $
956 "I ran into an unexpected symbol:"
957 ,
958 D.reflow $
959 "I was not expecting to see a " ++ op ++ " here. Try deleting it? Maybe\
960 \ I can give a better hint from there?"
961 )
963 Code.Close term bracket ->
964 let
965 region = toRegion row col
966 in
967 Report.Report ("UNEXPECTED " ++ map Char.toUpper term) region [] $
968 Code.toSnippet source region Nothing
969 (
970 D.reflow $
971 "I ran into an unexpected " ++ term ++ ":"
972 ,
973 D.reflow $
974 "This " ++ bracket : " does not match up with an earlier open " ++ term ++ ". Try deleting it?"
975 )
977 Code.Lower c cs ->
978 let
979 region = toKeywordRegion row col (c:cs)
980 in
981 Report.Report "UNEXPECTED NAME" region [] $
982 Code.toSnippet source region Nothing
983 (
984 D.reflow $
985 "I got stuck on this name:"
986 ,
987 D.reflow $
988 "It is confusing me a lot! Normally I can give fairly specific hints, but\
989 \ something is really tripping me up this time."
990 )
992 Code.Upper c cs ->
993 let
994 region = toKeywordRegion row col (c:cs)
995 in
996 Report.Report "UNEXPECTED NAME" region [] $
997 Code.toSnippet source region Nothing
998 (
999 D.reflow $
1000 "I got stuck on this name:"
1002 D.reflow $
1003 "It is confusing me a lot! Normally I can give fairly specific hints, but\
1004 \ something is really tripping me up this time."
1007 Code.Other maybeChar ->
1008 let
1009 region = toRegion row col
1010 in
1011 case maybeChar of
1012 Just ';' ->
1013 Report.Report "UNEXPECTED SEMICOLON" region [] $
1014 Code.toSnippet source region Nothing
1016 D.reflow $
1017 "I got stuck on this semicolon:"
1019 D.stack
1020 [ D.reflow $ "Try removing it?"
1021 , D.toSimpleNote $
1022 "Some languages require semicolons at the end of each statement. These are\
1023 \ often called C-like languages, and they usually share a lot of language design\
1024 \ choices. (E.g. side-effects, for loops, etc.) Elm manages effects with commands\
1025 \ and subscriptions instead, so there is no special syntax for \"statements\" and\
1026 \ therefore no need to use semicolons to separate them. I think this will make\
1027 \ more sense as you work through <https://guide.elm-lang.org> though!"
1031 Just ',' ->
1032 Report.Report "UNEXPECTED COMMA" region [] $
1033 Code.toSnippet source region Nothing
1035 D.reflow $
1036 "I got stuck on this comma:"
1038 D.stack
1039 [ D.reflow $
1040 "I do not think I am parsing a list or tuple right now. Try deleting the comma?"
1041 , D.toSimpleNote $
1042 "If this is supposed to be part of a list, the problem may be a bit earlier.\
1043 \ Perhaps the opening [ is missing? Or perhaps some value in the list has an extra\
1044 \ closing ] that is making me think the list ended earlier? The same kinds of\
1045 \ things could be going wrong if this is supposed to be a tuple."
1049 Just '`' ->
1050 Report.Report "UNEXPECTED CHARACTER" region [] $
1051 Code.toSnippet source region Nothing
1053 D.reflow $
1054 "I got stuck on this character:"
1056 D.stack
1057 [ D.reflow $
1058 "It is not used for anything in Elm syntax. It is used for multi-line strings in\
1059 \ some languages though, so if you want a string that spans multiple lines, you\
1060 \ can use Elm's multi-line string syntax like this:"
1061 , D.dullyellow $ D.indent 4 $ D.vcat $
1062 [ "\"\"\""
1063 , "# Multi-line Strings"
1064 , ""
1065 , "- start with triple double quotes"
1066 , "- write whatever you want"
1067 , "- no need to escape newlines or double quotes"
1068 , "- end with triple double quotes"
1069 , "\"\"\""
1071 , D.reflow $
1072 "Otherwise I do not know what is going on! Try removing the character?"
1076 Just '$' ->
1077 Report.Report "UNEXPECTED SYMBOL" region [] $
1078 Code.toSnippet source region Nothing
1080 D.reflow $
1081 "I got stuck on this dollar sign:"
1083 D.reflow $
1084 "It is not used for anything in Elm syntax. Are you coming from a language where\
1085 \ dollar signs can be used in variable names? If so, try a name that (1) starts\
1086 \ with a letter and (2) only contains letters, numbers, and underscores."
1089 Just c | elem c ['#','@','!','%','~'] ->
1090 Report.Report "UNEXPECTED SYMBOL" region [] $
1091 Code.toSnippet source region Nothing
1093 D.reflow $
1094 "I got stuck on this symbol:"
1096 D.reflow $
1097 "It is not used for anything in Elm syntax. Try removing it?"
1100 _ ->
1101 Report.Report "SYNTAX PROBLEM" region [] $
1102 Code.toSnippet source region Nothing
1104 D.reflow $
1105 "I got stuck here:"
1107 D.reflow $
1108 "Whatever I am running into is confusing me a lot! Normally I can give fairly\
1109 \ specific hints, but something is really tripping me up this time."
1114-- IMPORTS
1117toImportReport :: Code.Source -> Row -> Col -> Report.Report
1118toImportReport source row col =
1119 let
1120 region = toRegion row col
1121 in
1122 Report.Report "UNFINISHED IMPORT" region [] $
1123 Code.toSnippet source region Nothing
1125 D.reflow $
1126 "I am partway through parsing an import, but I got stuck here:"
1128 D.stack
1129 [ D.reflow $
1130 "Here are some examples of valid `import` declarations:"
1131 , D.indent 4 $ D.vcat $
1132 [ D.fillSep [D.cyan "import","Html"]
1133 , D.fillSep [D.cyan "import","Html",D.cyan "as","H"]
1134 , D.fillSep [D.cyan "import","Html",D.cyan "as","H",D.cyan "exposing","(..)"]
1135 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
1137 , D.reflow $
1138 "You are probably trying to import a different module, but try to make it look like one of these examples!"
1139 , D.reflowLink "Read" "imports" "to learn more."
1145-- EXPOSING
1148toExposingReport :: Code.Source -> Exposing -> Row -> Col -> Report.Report
1149toExposingReport source exposing startRow startCol =
1150 case exposing of
1151 ExposingSpace space row col ->
1152 toSpaceReport source space row col
1154 ExposingStart row col ->
1155 let
1156 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1157 region = toRegion row col
1158 in
1159 Report.Report "PROBLEM IN EXPOSING" region [] $
1160 Code.toSnippet source surroundings (Just region)
1162 D.reflow $
1163 "I want to parse exposed values, but I am getting stuck here:"
1165 D.stack
1166 [ D.fillSep $
1167 ["Exposed","values","are","always","surrounded","by","parentheses."
1168 ,"So","try","adding","a",D.green "(","here?"
1170 , D.toSimpleNote "Here are some valid examples of `exposing` for reference:"
1171 , D.indent 4 $ D.vcat $
1172 [ D.fillSep [D.cyan "import","Html",D.cyan "exposing","(..)"]
1173 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
1175 , D.reflow $
1176 "If you are getting tripped up, you can just expose everything for now. It should\
1177 \ get easier to make an explicit exposing list as you see more examples in the wild."
1181 ExposingValue row col ->
1182 case Code.whatIsNext source row col of
1183 Code.Keyword keyword ->
1184 let
1185 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1186 region = toKeywordRegion row col keyword
1187 in
1188 Report.Report "RESERVED WORD" region [] $
1189 Code.toSnippet source surroundings (Just region)
1191 D.reflow $
1192 "I got stuck on this reserved word:"
1194 D.reflow $
1195 "It looks like you are trying to expose `" ++ keyword ++ "` but that is a reserved word. Is there a typo?"
1198 Code.Operator op ->
1199 let
1200 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1201 region = toKeywordRegion row col op
1202 in
1203 Report.Report "UNEXPECTED SYMBOL" region [] $
1204 Code.toSnippet source surroundings (Just region)
1206 D.reflow $
1207 "I got stuck on this symbol:"
1209 D.stack
1210 [ D.reflow $
1211 "If you are trying to expose an operator, add parentheses around it like this:"
1212 , D.indent 4 $ D.dullyellow (D.fromChars op) <> " -> " <> D.green ("(" <> D.fromChars op <> ")")
1216 _ ->
1217 let
1218 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1219 region = toRegion row col
1220 in
1221 Report.Report "PROBLEM IN EXPOSING" region [] $
1222 Code.toSnippet source surroundings (Just region)
1224 D.reflow $
1225 "I got stuck while parsing these exposed values:"
1227 D.stack
1228 [ D.reflow $
1229 "I do not have an exact recommendation, so here are some valid examples\
1230 \ of `exposing` for reference:"
1231 , D.indent 4 $ D.vcat $
1232 [ D.fillSep [D.cyan "import","Html",D.cyan "exposing","(..)"]
1233 , D.fillSep [D.cyan "import","Basics",D.cyan "exposing","(Int, Float, Bool(..), (+), not, sqrt)"]
1235 , D.reflow $
1236 "These examples show how to expose types, variants, operators, and functions. Everything\
1237 \ should be some permutation of these examples, just with different names."
1241 ExposingOperator row col ->
1242 let
1243 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1244 region = toRegion row col
1245 in
1246 Report.Report "PROBLEM IN EXPOSING" region [] $
1247 Code.toSnippet source surroundings (Just region)
1249 D.reflow $
1250 "I just saw an open parenthesis, so I was expecting an operator next:"
1252 D.fillSep $
1253 ["It","is","possible","to","expose","operators,","so","I","was","expecting"
1254 ,"to","see","something","like",D.dullyellow "(+)","or",D.dullyellow "(|=)"
1255 ,"or",D.dullyellow "(||)","after","I","saw","that","open","parenthesis."
1259 ExposingOperatorReserved op row col ->
1260 let
1261 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1262 region = toRegion row col
1263 in
1264 Report.Report "RESERVED SYMBOL" region [] $
1265 Code.toSnippet source surroundings (Just region)
1267 D.reflow $
1268 "I cannot expose this as an operator:"
1270 case op of
1271 BadDot -> D.reflow "Try getting rid of this entry? Maybe I can give you a better hint after that?"
1272 BadPipe -> D.fillSep ["Maybe","you","want",D.dullyellow "(||)","instead?"]
1273 BadArrow -> D.reflow "Try getting rid of this entry? Maybe I can give you a better hint after that?"
1274 BadEquals -> D.fillSep ["Maybe","you","want",D.dullyellow "(==)","instead?"]
1275 BadHasType -> D.fillSep ["Maybe","you","want",D.dullyellow "(::)","instead?"]
1278 ExposingOperatorRightParen row col ->
1279 let
1280 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1281 region = toRegion row col
1282 in
1283 Report.Report "PROBLEM IN EXPOSING" region [] $
1284 Code.toSnippet source surroundings (Just region)
1286 D.reflow $
1287 "It looks like you are exposing an operator, but I got stuck here:"
1289 D.fillSep $
1290 ["I","was","expecting","to","see","the","closing","parenthesis","immediately"
1291 ,"after","the","operator.","Try","adding","a",D.green ")","right","here?"
1295 ExposingEnd row col ->
1296 let
1297 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1298 region = toRegion row col
1299 in
1300 Report.Report "UNFINISHED EXPOSING" region [] $
1301 Code.toSnippet source surroundings (Just region)
1303 D.reflow $
1304 "I was partway through parsing exposed values, but I got stuck here:"
1306 D.reflow $
1307 "Maybe there is a comma missing before this?"
1310 ExposingTypePrivacy row col ->
1311 let
1312 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1313 region = toRegion row col
1314 in
1315 Report.Report "PROBLEM EXPOSING CUSTOM TYPE VARIANTS" region [] $
1316 Code.toSnippet source surroundings (Just region)
1318 D.reflow $
1319 "It looks like you are trying to expose the variants of a custom type:"
1321 D.stack
1322 [ D.fillSep $
1323 ["You","need","to","write","something","like"
1324 ,D.dullyellow "Status(..)","or",D.dullyellow "Entity(..)"
1325 ,"though.","It","is","all","or","nothing,","otherwise","`case`"
1326 ,"expressions","could","miss","a","variant","and","crash!"
1328 , D.toSimpleNote $
1329 "It is often best to keep the variants hidden! If someone pattern matches on\
1330 \ the variants, it is a MAJOR change if any new variants are added. Suddenly\
1331 \ their `case` expressions do not cover all variants! So if you do not need\
1332 \ people to pattern match, keep the variants hidden and expose functions to\
1333 \ construct values of this type. This way you can add new variants as a MINOR change!"
1337 ExposingIndentEnd row col ->
1338 let
1339 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1340 region = toRegion row col
1341 in
1342 Report.Report "UNFINISHED EXPOSING" region [] $
1343 Code.toSnippet source surroundings (Just region)
1345 D.reflow $
1346 "I was partway through parsing exposed values, but I got stuck here:"
1348 D.stack
1349 [ D.fillSep $
1350 ["I","was","expecting","a","closing","parenthesis."
1351 ,"Try","adding","a",D.green ")","right","here?"
1353 , D.toSimpleNote $
1354 "I can get confused when there is not enough indentation, so if you already\
1355 \ have a closing parenthesis, it probably just needs some spaces in front of it."
1359 ExposingIndentValue row col ->
1360 let
1361 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1362 region = toRegion row col
1363 in
1364 Report.Report "UNFINISHED EXPOSING" region [] $
1365 Code.toSnippet source surroundings (Just region)
1367 D.reflow $
1368 "I was partway through parsing exposed values, but I got stuck here:"
1370 D.reflow $
1371 "I was expecting another value to expose."
1376-- SPACES
1379toSpaceReport :: Code.Source -> Space -> Row -> Col -> Report.Report
1380toSpaceReport source space row col =
1381 case space of
1382 HasTab ->
1383 let
1384 region = toRegion row col
1385 in
1386 Report.Report "NO TABS" region [] $
1387 Code.toSnippet source region Nothing
1389 D.reflow $
1390 "I ran into a tab, but tabs are not allowed in Elm files."
1392 D.reflow $
1393 "Replace the tab with spaces."
1396 EndlessMultiComment ->
1397 let
1398 region = toWiderRegion row col 2
1399 in
1400 Report.Report "ENDLESS COMMENT" region [] $
1401 Code.toSnippet source region Nothing
1403 D.reflow $
1404 "I cannot find the end of this multi-line comment:"
1406 D.stack -- "{-"
1407 [ D.reflow "Add a -} somewhere after this to end the comment."
1408 , D.toSimpleHint
1409 "Multi-line comments can be nested in Elm, so {- {- -} -} is a comment\
1410 \ that happens to contain another comment. Like parentheses and curly braces,\
1411 \ the start and end markers must always be balanced. Maybe that is the problem?"
1417-- DECLARATIONS
1420toRegion :: Row -> Col -> A.Region
1421toRegion row col =
1422 let
1423 pos = A.Position row col
1424 in
1425 A.Region pos pos
1428toWiderRegion :: Row -> Col -> Word16 -> A.Region
1429toWiderRegion row col extra =
1430 A.Region
1431 (A.Position row col)
1432 (A.Position row (col + extra))
1435toKeywordRegion :: Row -> Col -> [Char.Char] -> A.Region
1436toKeywordRegion row col keyword =
1437 A.Region
1438 (A.Position row col)
1439 (A.Position row (col + fromIntegral (length keyword)))
1442toDeclarationsReport :: Code.Source -> Decl -> Report.Report
1443toDeclarationsReport source decl =
1444 case decl of
1445 DeclStart row col ->
1446 toDeclStartReport source row col
1448 DeclSpace space row col ->
1449 toSpaceReport source space row col
1451 Port port_ row col ->
1452 toPortReport source port_ row col
1454 DeclType declType row col ->
1455 toDeclTypeReport source declType row col
1457 DeclDef name declDef row col ->
1458 toDeclDefReport source name declDef row col
1460 DeclFreshLineAfterDocComment row col ->
1461 let
1462 region = toRegion row col
1463 in
1464 Report.Report "EXPECTING DECLARATION" region [] $
1465 Code.toSnippet source region Nothing
1467 D.reflow $
1468 "I just saw a doc comment, but then I got stuck here:"
1470 D.reflow $
1471 "I was expecting to see the corresponding declaration next, starting on a fresh\
1472 \ line with no indentation."
1476toDeclStartReport :: Code.Source -> Row -> Col -> Report.Report
1477toDeclStartReport source row col =
1478 case Code.whatIsNext source row col of
1479 Code.Close term bracket ->
1480 let
1481 region = toRegion row col
1482 in
1483 Report.Report ("STRAY " ++ map Char.toUpper term) region [] $
1484 Code.toSnippet source region Nothing
1486 D.reflow $
1487 "I was not expecting to see a " ++ term ++ " here:"
1488 , D.reflow $
1489 "This " ++ bracket : " does not match up with an earlier open " ++ term ++ ". Try deleting it?"
1492 Code.Keyword keyword ->
1493 let
1494 region = toKeywordRegion row col keyword
1495 in
1496 Report.Report "RESERVED WORD" region [] $
1497 Code.toSnippet source region Nothing
1499 D.reflow $
1500 "I was not expecting to run into the `" ++ keyword ++ "` keyword here:"
1502 case keyword of
1503 "import" ->
1504 D.reflow $
1505 "It is reserved for declaring imports at the top of your module. If you want\
1506 \ another import, try moving it up top with the other imports. If you want to\
1507 \ define a value or function, try changing the name to something else!"
1509 "case" ->
1510 D.stack
1511 [ D.reflow $
1512 "It is reserved for writing `case` expressions. Try using a different name?"
1513 , D.toSimpleNote $
1514 "If you are trying to write a `case` expression, it needs to be part of a\
1515 \ definition. So you could write something like this instead:"
1516 , D.indent 4 $ D.vcat $
1517 [ D.indent 0 $ D.fillSep ["getWidth","maybeWidth","="]
1518 , D.indent 2 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
1519 , D.indent 4 $ D.fillSep [D.blue "Just","width","->"]
1520 , D.indent 6 $ D.fillSep ["width","+",D.dullyellow "200"]
1521 , ""
1522 , D.indent 4 $ D.fillSep [D.blue "Nothing","->"]
1523 , D.indent 6 $ D.fillSep [D.dullyellow "400"]
1525 , D.reflow $
1526 "This defines a `getWidth` function that you can use elsewhere in your program."
1529 "if" ->
1530 D.stack
1531 [ D.reflow $
1532 "It is reserved for writing `if` expressions. Try using a different name?"
1533 , D.toSimpleNote $
1534 "If you are trying to write an `if` expression, it needs to be part of a\
1535 \ definition. So you could write something like this instead:"
1536 , D.indent 4 $ D.vcat $
1537 [ "greet name ="
1538 , D.fillSep $
1539 [" "
1540 ,D.cyan "if","name","==",D.dullyellow "\"Abraham Lincoln\""
1541 ,D.cyan "then",D.dullyellow "\"Greetings Mr. President.\""
1542 ,D.cyan "else",D.dullyellow "\"Hey!\""
1545 , D.reflow $
1546 "This defines a `reviewPowerLevel` function that you can use elsewhere in your program."
1549 _ ->
1550 D.reflow $
1551 "It is a reserved word. Try changing the name to something else?"
1554 Code.Upper c cs ->
1555 let
1556 region = toRegion row col
1557 in
1558 Report.Report "UNEXPECTED CAPITAL LETTER" region [] $
1559 Code.toSnippet source region Nothing
1561 D.reflow $
1562 "Declarations always start with a lower-case letter, so I am getting stuck here:"
1564 D.stack
1565 [ D.fillSep $
1566 ["Try","a","name","like"
1567 ,D.green (D.fromChars (Char.toLower c : cs))
1568 ,"instead?"
1570 , D.toSimpleNote $
1571 "Here are a couple valid declarations for reference:"
1572 , D.indent 4 $ D.vcat $
1573 [ "greet : String -> String"
1574 , "greet name ="
1575 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
1576 , ""
1577 , D.cyan "type" <> " User = Anonymous | LoggedIn String"
1579 , D.reflow $
1580 "Notice that they always start with a lower-case letter. Capitalization matters!"
1584 Code.Other (Just char) | elem char ['(', '{', '[', '+', '-', '*', '/', '^', '&', '|', '"', '\'', '!', '@', '#', '$', '%'] ->
1585 let
1586 region = toRegion row col
1587 in
1588 Report.Report "UNEXPECTED SYMBOL" region [] $
1589 Code.toSnippet source region Nothing
1591 D.reflow $
1592 "I am getting stuck because this line starts with the " ++ [char] ++ " symbol:"
1594 D.stack
1595 [ D.reflow $
1596 "When a line has no spaces at the beginning, I expect it to be a declaration like one of these:"
1597 , D.indent 4 $ D.vcat $
1598 [ "greet : String -> String"
1599 , "greet name ="
1600 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
1601 , ""
1602 , D.cyan "type" <> " User = Anonymous | LoggedIn String"
1604 , D.reflow $
1605 "If this is not supposed to be a declaration, try adding some spaces before it?"
1609 _ ->
1610 let
1611 region = toRegion row col
1612 in
1613 Report.Report "WEIRD DECLARATION" region [] $
1614 Code.toSnippet source region Nothing
1616 D.reflow $
1617 "I am trying to parse a declaration, but I am getting stuck here:"
1619 D.stack
1620 [ D.reflow $
1621 "When a line has no spaces at the beginning, I expect it to be a declaration like one of these:"
1622 , D.indent 4 $ D.vcat $
1623 [ "greet : String -> String"
1624 , "greet name ="
1625 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
1626 , ""
1627 , D.cyan "type" <> " User = Anonymous | LoggedIn String"
1629 , D.reflow $
1630 "Try to make your declaration look like one of those? Or if this is not\
1631 \ supposed to be a declaration, try adding some spaces before it?"
1636-- PORT
1639toPortReport :: Code.Source -> Port -> Row -> Col -> Report.Report
1640toPortReport source port_ startRow startCol =
1641 case port_ of
1642 PortSpace space row col ->
1643 toSpaceReport source space row col
1645 PortName row col ->
1646 case Code.whatIsNext source row col of
1647 Code.Keyword keyword ->
1648 let
1649 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1650 region = toKeywordRegion row col keyword
1651 in
1652 Report.Report "RESERVED WORD" region [] $
1653 Code.toSnippet source surroundings (Just region)
1655 D.reflow $
1656 "I cannot handle ports with names like this:"
1658 D.reflow $
1659 "You are trying to make a port named `" ++ keyword
1660 ++ "` but that is a reserved word. Try using some other name?"
1663 _ ->
1664 let
1665 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1666 region = toRegion row col
1667 in
1668 Report.Report "PORT PROBLEM" region [] $
1669 Code.toSnippet source surroundings (Just region)
1671 D.reflow $
1672 "I just saw the start of a `port` declaration, but then I got stuck here:"
1674 D.stack
1675 [ D.fillSep
1676 ["I","was","expecting","to","see","a","name","like"
1677 ,D.dullyellow "send","or",D.dullyellow "receive","next."
1678 ,"Something","that","starts","with","a","lower-case","letter."
1680 , portNote
1684 PortColon row col ->
1685 let
1686 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1687 region = toRegion row col
1688 in
1689 Report.Report "PORT PROBLEM" region [] $
1690 Code.toSnippet source surroundings (Just region)
1692 D.reflow $
1693 "I just saw the start of a `port` declaration, but then I got stuck here:"
1695 D.stack
1696 [ D.reflow $
1697 "I was expecting to see a colon next. And then a type that tells me\
1698 \ what type of values are going to flow through."
1699 , portNote
1703 PortType tipe row col ->
1704 toTypeReport source TC_Port tipe row col
1706 PortIndentName row col ->
1707 let
1708 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1709 region = toRegion row col
1710 in
1711 Report.Report "UNFINISHED PORT" region [] $
1712 Code.toSnippet source surroundings (Just region)
1714 D.reflow $
1715 "I just saw the start of a `port` declaration, but then I got stuck here:"
1717 D.stack
1718 [ D.fillSep
1719 ["I","was","expecting","to","see","a","name","like"
1720 ,D.dullyellow "send","or",D.dullyellow "receive","next."
1721 ,"Something","that","starts","with","a","lower-case","letter."
1723 , portNote
1727 PortIndentColon row col ->
1728 let
1729 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1730 region = toRegion row col
1731 in
1732 Report.Report "UNFINISHED PORT" region [] $
1733 Code.toSnippet source surroundings (Just region)
1735 D.reflow $
1736 "I just saw the start of a `port` declaration, but then I got stuck here:"
1738 D.stack
1739 [ D.reflow $
1740 "I was expecting to see a colon next. And then a type that tells me\
1741 \ what type of values are going to flow through."
1742 , portNote
1746 PortIndentType row col ->
1747 let
1748 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1749 region = toRegion row col
1750 in
1751 Report.Report "UNFINISHED PORT" region [] $
1752 Code.toSnippet source surroundings (Just region)
1754 D.reflow $
1755 "I just saw the start of a `port` declaration, but then I got stuck here:"
1757 D.stack
1758 [ D.reflow $
1759 "I was expecting to see a type next. Here are examples of outgoing and\
1760 \ incoming ports for reference:"
1761 , D.indent 4 $ D.vcat $
1762 [ D.fillSep [D.cyan "port","send",":","String -> Cmd msg"]
1763 , D.fillSep [D.cyan "port","receive",":","(String -> msg) -> Sub msg"]
1765 , D.reflow $
1766 "The first line defines a `send` port so you can send strings out to JavaScript.\
1767 \ Maybe you send them on a WebSocket or put them into IndexedDB. The second line\
1768 \ defines a `receive` port so you can receive strings from JavaScript. Maybe you\
1769 \ get receive messages when new WebSocket messages come in or when an entry in\
1770 \ IndexedDB changes for some external reason."
1775portNote :: D.Doc
1776portNote =
1777 D.stack
1778 [ D.toSimpleNote $
1779 "Here are some example `port` declarations for reference:"
1780 , D.indent 4 $ D.vcat $
1781 [ D.fillSep [D.cyan "port","send",":","String -> Cmd msg"]
1782 , D.fillSep [D.cyan "port","receive",":","(String -> msg) -> Sub msg"]
1784 , D.reflow $
1785 "The first line defines a `send` port so you can send strings out to JavaScript.\
1786 \ Maybe you send them on a WebSocket or put them into IndexedDB. The second line\
1787 \ defines a `receive` port so you can receive strings from JavaScript. Maybe you\
1788 \ get receive messages when new WebSocket messages come in or when the IndexedDB\
1789 \ is changed for some external reason."
1794-- DECL TYPE
1797toDeclTypeReport :: Code.Source -> DeclType -> Row -> Col -> Report.Report
1798toDeclTypeReport source declType startRow startCol =
1799 case declType of
1800 DT_Space space row col ->
1801 toSpaceReport source space row col
1803 DT_Name row col ->
1804 let
1805 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1806 region = toRegion row col
1807 in
1808 Report.Report "EXPECTING TYPE NAME" region [] $
1809 Code.toSnippet source surroundings (Just region)
1811 D.reflow $
1812 "I think I am parsing a type declaration, but I got stuck here:"
1814 D.stack
1815 [ D.fillSep $
1816 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1817 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1819 , customTypeNote
1823 DT_Alias typeAlias row col ->
1824 toTypeAliasReport source typeAlias row col
1826 DT_Union customType row col ->
1827 toCustomTypeReport source customType row col
1829 DT_IndentName row col ->
1830 let
1831 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1832 region = toRegion row col
1833 in
1834 Report.Report "EXPECTING TYPE NAME" region [] $
1835 Code.toSnippet source surroundings (Just region)
1837 D.reflow $
1838 "I think I am parsing a type declaration, but I got stuck here:"
1840 D.stack
1841 [ D.fillSep $
1842 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1843 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1845 , customTypeNote
1850toTypeAliasReport :: Code.Source -> TypeAlias -> Row -> Col -> Report.Report
1851toTypeAliasReport source typeAlias startRow startCol =
1852 case typeAlias of
1853 AliasSpace space row col ->
1854 toSpaceReport source space row col
1856 AliasName row col ->
1857 let
1858 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1859 region = toRegion row col
1860 in
1861 Report.Report "EXPECTING TYPE ALIAS NAME" region [] $
1862 Code.toSnippet source surroundings (Just region)
1864 D.reflow $
1865 "I am partway through parsing a type alias, but I got stuck here:"
1867 D.stack
1868 [ D.fillSep $
1869 ["I","was","expecting","a","name","like",D.dullyellow "Person","or",D.dullyellow "Point"
1870 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1872 , typeAliasNote
1876 AliasEquals row col ->
1877 case Code.whatIsNext source row col of
1878 Code.Keyword keyword ->
1879 let
1880 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1881 region = toKeywordRegion row col keyword
1882 in
1883 Report.Report "RESERVED WORD" region [] $
1884 Code.toSnippet source surroundings (Just region)
1886 D.reflow $
1887 "I ran into a reserved word unexpectedly while parsing this type alias:"
1889 D.stack
1890 [ D.reflow $
1891 "It looks like you are trying use `" ++ keyword
1892 ++ "` as a type variable, but it is a reserved word. Try using a different name?"
1893 , typeAliasNote
1897 _ ->
1898 let
1899 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1900 region = toRegion row col
1901 in
1902 Report.Report "PROBLEM IN TYPE ALIAS" region [] $
1903 Code.toSnippet source surroundings (Just region)
1905 D.reflow $
1906 "I am partway through parsing a type alias, but I got stuck here:"
1908 D.stack
1909 [ D.reflow $
1910 "I was expecting to see a type variable or an equals sign next."
1911 , typeAliasNote
1915 AliasBody tipe row col ->
1916 toTypeReport source TC_TypeAlias tipe row col
1918 AliasIndentEquals row col ->
1919 let
1920 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1921 region = toRegion row col
1922 in
1923 Report.Report "UNFINISHED TYPE ALIAS" region [] $
1924 Code.toSnippet source surroundings (Just region)
1926 D.reflow $
1927 "I am partway through parsing a type alias, but I got stuck here:"
1929 D.stack
1930 [ D.reflow $
1931 "I was expecting to see a type variable or an equals sign next."
1932 , typeAliasNote
1936 AliasIndentBody row col ->
1937 let
1938 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1939 region = toRegion row col
1940 in
1941 Report.Report "UNFINISHED TYPE ALIAS" region [] $
1942 Code.toSnippet source surroundings (Just region)
1944 D.reflow $
1945 "I am partway through parsing a type alias, but I got stuck here:"
1947 D.stack
1948 [ D.fillSep $
1949 ["I","was","expecting","to","see","a","type","next.","Something","as","simple"
1950 ,"as",D.dullyellow "Int","or",D.dullyellow "Float","would","work!"
1952 , typeAliasNote
1957typeAliasNote :: D.Doc
1958typeAliasNote =
1959 D.stack
1960 [ D.toSimpleNote $
1961 "Here is an example of a valid `type alias` for reference:"
1962 , D.vcat $
1963 [ D.indent 4 $ D.fillSep [D.cyan "type",D.cyan "alias","Person","="]
1964 , D.indent 6 $ D.vcat $
1965 ["{ name : String"
1966 ,", age : Int"
1967 ,", height : Float"
1968 ,"}"
1971 , D.reflow $
1972 "This would let us use `Person` as a shorthand for that record type. Using this\
1973 \ shorthand makes type annotations much easier to read, and makes changing code\
1974 \ easier if you decide later that there is more to a person than age and height!"
1978toCustomTypeReport :: Code.Source -> CustomType -> Row -> Col -> Report.Report
1979toCustomTypeReport source customType startRow startCol =
1980 case customType of
1981 CT_Space space row col ->
1982 toSpaceReport source space row col
1984 CT_Name row col ->
1985 let
1986 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1987 region = toRegion row col
1988 in
1989 Report.Report "EXPECTING TYPE NAME" region [] $
1990 Code.toSnippet source surroundings (Just region)
1992 D.reflow $
1993 "I think I am parsing a type declaration, but I got stuck here:"
1995 D.stack
1996 [ D.fillSep $
1997 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1998 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
2000 , customTypeNote
2004 CT_Equals row col ->
2005 case Code.whatIsNext source row col of
2006 Code.Keyword keyword ->
2007 let
2008 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2009 region = toKeywordRegion row col keyword
2010 in
2011 Report.Report "RESERVED WORD" region [] $
2012 Code.toSnippet source surroundings (Just region)
2014 D.reflow $
2015 "I ran into a reserved word unexpectedly while parsing this custom type:"
2017 D.stack
2018 [ D.reflow $
2019 "It looks like you are trying use `" ++ keyword
2020 ++ "` as a type variable, but it is a reserved word. Try using a different name?"
2021 , customTypeNote
2025 _ ->
2026 let
2027 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2028 region = toRegion row col
2029 in
2030 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
2031 Code.toSnippet source surroundings (Just region)
2033 D.reflow $
2034 "I am partway through parsing a custom type, but I got stuck here:"
2036 D.stack
2037 [ D.reflow $
2038 "I was expecting to see a type variable or an equals sign next."
2039 , customTypeNote
2043 CT_Bar row col ->
2044 let
2045 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2046 region = toRegion row col
2047 in
2048 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
2049 Code.toSnippet source surroundings (Just region)
2051 D.reflow $
2052 "I am partway through parsing a custom type, but I got stuck here:"
2054 D.stack
2055 [ D.reflow $
2056 "I was expecting to see a vertical bar like | next."
2057 , customTypeNote
2061 CT_Variant row col ->
2062 let
2063 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2064 region = toRegion row col
2065 in
2066 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
2067 Code.toSnippet source surroundings (Just region)
2069 D.reflow $
2070 "I am partway through parsing a custom type, but I got stuck here:"
2072 D.stack
2073 [ D.fillSep $
2074 ["I","was","expecting","to","see","a","variant","name","next."
2075 ,"Something","like",D.dullyellow "Success","or",D.dullyellow "Sandwich" <> "."
2076 ,"Any","name","that","starts","with","a","capital","letter","really!"
2078 , customTypeNote
2082 CT_VariantArg tipe row col ->
2083 toTypeReport source TC_CustomType tipe row col
2085 CT_IndentEquals row col ->
2086 let
2087 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2088 region = toRegion row col
2089 in
2090 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
2091 Code.toSnippet source surroundings (Just region)
2093 D.reflow $
2094 "I am partway through parsing a custom type, but I got stuck here:"
2096 D.stack
2097 [ D.reflow $
2098 "I was expecting to see a type variable or an equals sign next."
2099 , customTypeNote
2103 CT_IndentBar row col ->
2104 let
2105 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2106 region = toRegion row col
2107 in
2108 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
2109 Code.toSnippet source surroundings (Just region)
2111 D.reflow $
2112 "I am partway through parsing a custom type, but I got stuck here:"
2114 D.stack
2115 [ D.reflow $
2116 "I was expecting to see a vertical bar like | next."
2117 , customTypeNote
2121 CT_IndentAfterBar row col ->
2122 let
2123 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2124 region = toRegion row col
2125 in
2126 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
2127 Code.toSnippet source surroundings (Just region)
2129 D.reflow $
2130 "I am partway through parsing a custom type, but I got stuck here:"
2132 D.stack
2133 [ D.reflow $
2134 "I just saw a vertical bar, so I was expecting to see another variant defined next."
2135 , customTypeNote
2139 CT_IndentAfterEquals row col ->
2140 let
2141 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2142 region = toRegion row col
2143 in
2144 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
2145 Code.toSnippet source surroundings (Just region)
2147 D.reflow $
2148 "I am partway through parsing a custom type, but I got stuck here:"
2150 D.stack
2151 [ D.reflow $
2152 "I just saw an equals sign, so I was expecting to see the first variant defined next."
2153 , customTypeNote
2158customTypeNote :: D.Doc
2159customTypeNote =
2160 D.stack
2161 [ D.toSimpleNote $
2162 "Here is an example of a valid `type` declaration for reference:"
2163 , D.vcat $
2164 [ D.indent 4 $ D.fillSep [D.cyan "type","Status"]
2165 , D.indent 6 $ D.fillSep ["=","Failure"]
2166 , D.indent 6 $ D.fillSep ["|","Waiting"]
2167 , D.indent 6 $ D.fillSep ["|","Success","String"]
2169 , D.reflow $
2170 "This defines a new `Status` type with three variants. This could be useful if\
2171 \ we are waiting for an HTTP request. Maybe we start with `Waiting` and then\
2172 \ switch to `Failure` or `Success \"message from server\"` depending on how\
2173 \ things go. Notice that the Success variant has some associated data, allowing\
2174 \ us to store a String if the request goes well!"
2179-- DECL DEF
2182toDeclDefReport :: Code.Source -> Name.Name -> DeclDef -> Row -> Col -> Report.Report
2183toDeclDefReport source name declDef startRow startCol =
2184 case declDef of
2185 DeclDefSpace space row col ->
2186 toSpaceReport source space row col
2188 DeclDefEquals row col ->
2189 case Code.whatIsNext source row col of
2190 Code.Keyword keyword ->
2191 let
2192 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2193 region = toKeywordRegion row col keyword
2194 in
2195 Report.Report "RESERVED WORD" region [] $
2196 Code.toSnippet source surroundings (Just region)
2198 D.fillSep
2199 ["The","name"
2200 ,"`" <> D.cyan (D.fromChars keyword) <> "`"
2201 ,"is","reserved","in","Elm,","so","it","cannot"
2202 ,"be","used","as","an","argument","here:"
2205 D.stack
2206 [ D.reflow $
2207 "Try renaming it to something else."
2208 , case keyword of
2209 "as" ->
2210 D.toFancyNote
2211 ["This","keyword","is","reserved","for","pattern","matches","like"
2212 ,"((x,y)",D.cyan "as","point)","where","you","want","to","name","a","tuple","and"
2213 ,"the","values","it","contains."
2216 _ ->
2217 D.toSimpleNote $
2218 "The `" ++ keyword ++ "` keyword has a special meaning in Elm, so it can only be used in certain situations."
2222 Code.Operator "->" ->
2223 let
2224 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2225 region = toWiderRegion row col 2
2226 in
2227 Report.Report "MISSING COLON?" region [] $
2228 Code.toSnippet source surroundings (Just region)
2230 D.reflow $
2231 "I was not expecting to see an arrow here:"
2233 D.stack
2234 [ D.fillSep
2235 ["This","usually","means","a",D.green ":","is","missing","a","bit","earlier","in"
2236 ,"a","type","annotation.","It","could","be","something","else","though,","so"
2237 ,"here","is","a","valid","definition","for","reference:"
2239 , D.indent 4 $ D.vcat $
2240 [ "greet : String -> String"
2241 , "greet name ="
2242 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
2244 , D.reflow $
2245 "Try to use that format with your `" ++ Name.toChars name ++ "` definition!"
2249 Code.Operator op ->
2250 let
2251 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2252 region = toKeywordRegion row col op
2253 in
2254 Report.Report "UNEXPECTED SYMBOL" region [] $
2255 Code.toSnippet source surroundings (Just region)
2257 D.reflow $
2258 "I was not expecting to see this symbol here:"
2260 D.stack
2261 [ D.reflow $
2262 "I am not sure what is going wrong exactly, so here is a valid\
2263 \ definition (with an optional type annotation) for reference:"
2264 , D.indent 4 $ D.vcat $
2265 [ "greet : String -> String"
2266 , "greet name ="
2267 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
2269 , D.reflow $
2270 "Try to use that format with your `" ++ Name.toChars name ++ "` definition!"
2274 _ ->
2275 let
2276 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2277 region = toRegion row col
2278 in
2279 Report.Report "PROBLEM IN DEFINITION" region [] $
2280 Code.toSnippet source surroundings (Just region)
2282 D.reflow $
2283 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
2285 D.stack
2286 [ D.reflow $
2287 "I am not sure what is going wrong exactly, so here is a valid\
2288 \ definition (with an optional type annotation) for reference:"
2289 , D.indent 4 $ D.vcat $
2290 [ "greet : String -> String"
2291 , "greet name ="
2292 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
2294 , D.reflow $
2295 "Try to use that format!"
2299 DeclDefType tipe row col ->
2300 toTypeReport source (TC_Annotation name) tipe row col
2302 DeclDefArg pattern row col ->
2303 toPatternReport source PArg pattern row col
2305 DeclDefBody expr row col ->
2306 toExprReport source (InDef name startRow startCol) expr row col
2308 DeclDefNameRepeat row col ->
2309 let
2310 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2311 region = toRegion row col
2312 in
2313 Report.Report "EXPECTING DEFINITION" region [] $
2314 Code.toSnippet source surroundings (Just region)
2316 D.reflow $
2317 "I just saw the type annotation for `" ++ Name.toChars name
2318 ++ "` so I was expecting to see its definition here:"
2320 D.stack
2321 [ D.reflow $
2322 "Type annotations always appear directly above the relevant\
2323 \ definition, without anything else in between. (Not even doc comments!)"
2324 , declDefNote
2328 DeclDefNameMatch defName row col ->
2329 let
2330 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2331 region = toRegion row col
2332 in
2333 Report.Report "NAME MISMATCH" region [] $
2334 Code.toSnippet source surroundings (Just region)
2336 D.reflow $
2337 "I just saw a type annotation for `" ++ Name.toChars name ++ "`, but it is followed by a definition for `" ++ Name.toChars defName ++ "`:"
2339 D.stack
2340 [ D.reflow $
2341 "These names do not match! Is there a typo?"
2342 , D.indent 4 $ D.fillSep $
2343 [D.dullyellow (D.fromName defName),"->",D.green (D.fromName name)]
2347 DeclDefIndentType row col ->
2348 let
2349 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2350 region = toRegion row col
2351 in
2352 Report.Report "UNFINISHED DEFINITION" region [] $
2353 Code.toSnippet source surroundings (Just region)
2355 D.reflow $
2356 "I got stuck while parsing the `" ++ Name.toChars name ++ "` type annotation:"
2358 D.stack
2359 [ D.reflow $
2360 "I just saw a colon, so I am expecting to see a type next."
2361 , declDefNote
2365 DeclDefIndentEquals row col ->
2366 let
2367 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2368 region = toRegion row col
2369 in
2370 Report.Report "UNFINISHED DEFINITION" region [] $
2371 Code.toSnippet source surroundings (Just region)
2373 D.reflow $
2374 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
2376 D.stack
2377 [ D.reflow $
2378 "I was expecting to see an argument or an equals sign next."
2379 , declDefNote
2383 DeclDefIndentBody row col ->
2384 let
2385 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2386 region = toRegion row col
2387 in
2388 Report.Report "UNFINISHED DEFINITION" region [] $
2389 Code.toSnippet source surroundings (Just region)
2391 D.reflow $
2392 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
2394 D.stack
2395 [ D.reflow $
2396 "I was expecting to see an expression next. What is it equal to?"
2397 , declDefNote
2402declDefNote :: D.Doc
2403declDefNote =
2404 D.stack
2405 [ D.reflow $
2406 "Here is a valid definition (with a type annotation) for reference:"
2407 , D.indent 4 $ D.vcat $
2408 [ "greet : String -> String"
2409 , "greet name ="
2410 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
2412 , D.reflow $
2413 "The top line (called a \"type annotation\") is optional. You can leave it off\
2414 \ if you want. As you get more comfortable with Elm and as your project grows,\
2415 \ it becomes more and more valuable to add them though! They work great as\
2416 \ compiler-verified documentation, and they often improve error messages!"
2421-- CONTEXT
2424data Context
2425 = InNode Node Row Col Context
2426 | InDef Name.Name Row Col
2427 | InDestruct Row Col
2430data Node
2431 = NRecord
2432 | NParens
2433 | NList
2434 | NFunc
2435 | NCond
2436 | NThen
2437 | NElse
2438 | NCase
2439 | NBranch
2440 deriving (Eq)
2443getDefName :: Context -> Maybe Name.Name
2444getDefName context =
2445 case context of
2446 InDestruct _ _ -> Nothing
2447 InDef name _ _ -> Just name
2448 InNode _ _ _ c -> getDefName c
2451isWithin :: Node -> Context -> Bool
2452isWithin desiredNode context =
2453 case context of
2454 InDestruct _ _ -> False
2455 InDef _ _ _ -> False
2456 InNode actualNode _ _ _ -> desiredNode == actualNode
2460-- EXPR REPORTS
2463toExprReport :: Code.Source -> Context -> Expr -> Row -> Col -> Report.Report
2464toExprReport source context expr startRow startCol =
2465 case expr of
2466 Let let_ row col ->
2467 toLetReport source context let_ row col
2469 Case case_ row col ->
2470 toCaseReport source context case_ row col
2472 If if_ row col ->
2473 toIfReport source context if_ row col
2475 List list row col ->
2476 toListReport source context list row col
2478 Record record row col ->
2479 toRecordReport source context record row col
2481 Tuple tuple row col ->
2482 toTupleReport source context tuple row col
2484 Func func row col ->
2485 toFuncReport source context func row col
2487 Dot row col ->
2488 let region = toRegion row col in
2489 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
2490 Code.toSnippet source region Nothing
2492 D.reflow $
2493 "I was expecting to see a record accessor here:"
2495 D.fillSep
2496 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
2497 ,"that","accesses","a","value","from","a","record."
2501 Access row col ->
2502 let region = toRegion row col in
2503 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
2504 Code.toSnippet source region Nothing
2506 D.reflow $
2507 "I am trying to parse a record accessor here:"
2509 D.stack
2511 D.fillSep
2512 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
2513 ,"that","accesses","a","value","from","a","record."
2516 D.toSimpleNote $
2517 "Record field names must start with a lower case letter!"
2521 OperatorRight op row col ->
2522 let
2523 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2524 region = toRegion row col
2525 isMath = elem op ["-","+","*","/","^"]
2526 in
2527 Report.Report "MISSING EXPRESSION" region [] $
2528 Code.toSnippet source surroundings (Just region)
2530 D.reflow $
2531 "I just saw a " ++ Name.toChars op ++ " "
2532 ++ (if isMath then "sign" else "operator")
2533 ++ ", so I am getting stuck here:"
2535 if isMath then
2536 D.fillSep
2537 ["I","was","expecting","to","see","an","expression","next."
2538 ,"Something","like",D.dullyellow "42","or",D.dullyellow "1000"
2539 ,"that","makes","sense","with","a",D.fromName op,"sign."
2541 else if op == "&&" || op == "||" then
2542 D.fillSep
2543 ["I","was","expecting","to","see","an","expression","next."
2544 ,"Something","like",D.dullyellow "True","or",D.dullyellow "False"
2545 ,"that","makes","sense","with","boolean","logic."
2547 else if op == "|>" then
2548 D.reflow $
2549 "I was expecting to see a function next."
2550 else if op == "<|" then
2551 D.reflow $
2552 "I was expecting to see an argument next."
2553 else
2554 D.reflow $
2555 "I was expecting to see an expression next."
2558 OperatorReserved operator row col ->
2559 toOperatorReport source context operator row col
2561 Start row col ->
2562 let
2563 (contextRow, contextCol, aThing) =
2564 case context of
2565 InDestruct r c -> (r, c, "a definition")
2566 InDef name r c -> (r, c, "the `" ++ Name.toChars name ++ "` definition")
2567 InNode NRecord r c _ -> (r, c, "a record")
2568 InNode NParens r c _ -> (r, c, "some parentheses")
2569 InNode NList r c _ -> (r, c, "a list")
2570 InNode NFunc r c _ -> (r, c, "an anonymous function")
2571 InNode NCond r c _ -> (r, c, "an `if` expression")
2572 InNode NThen r c _ -> (r, c, "an `if` expression")
2573 InNode NElse r c _ -> (r, c, "an `if` expression")
2574 InNode NCase r c _ -> (r, c, "a `case` expression")
2575 InNode NBranch r c _ -> (r, c, "a `case` expression")
2577 surroundings = A.Region (A.Position contextRow contextCol) (A.Position row col)
2578 region = toRegion row col
2579 in
2580 Report.Report "MISSING EXPRESSION" region [] $
2581 Code.toSnippet source surroundings (Just region)
2583 D.reflow $
2584 "I am partway through parsing " ++ aThing ++ ", but I got stuck here:"
2586 D.stack
2587 [ D.fillSep $
2588 ["I","was","expecting","to","see","an","expression","like"
2589 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
2590 ,"Once","there","is","something","there,","I","can","probably"
2591 ,"give","a","more","specific","hint!"
2593 , D.toSimpleNote $
2594 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
2595 \ Or if I run into operators in unexpected spots. Point is, there are a\
2596 \ couple ways I can get confused and give sort of weird advice!"
2600 Char char row col ->
2601 toCharReport source char row col
2603 String string row col ->
2604 toStringReport source string row col
2606 Number number row col ->
2607 toNumberReport source number row col
2609 Space space row col ->
2610 toSpaceReport source space row col
2612 EndlessShader row col ->
2613 let
2614 region = toWiderRegion row col 6
2615 in
2616 Report.Report "ENDLESS SHADER" region [] $
2617 Code.toSnippet source region Nothing
2619 D.reflow "I cannot find the end of this shader:"
2621 D.reflow "Add a |] somewhere after this to end the shader."
2624 ShaderProblem problem row col ->
2625 let
2626 region = toRegion row col
2627 in
2628 Report.Report "SHADER PROBLEM" region [] $
2629 Code.toSnippet source region Nothing
2631 D.reflow $
2632 "I ran into a problem while parsing this GLSL block."
2634 D.stack
2635 [ D.reflow $
2636 "I use a 3rd party GLSL parser for now, and I did my best to extract their error message:"
2637 , D.indent 4 $ D.vcat $
2638 map D.fromChars (filter (/="") (lines problem))
2642 IndentOperatorRight op row col ->
2643 let
2644 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2645 region = toRegion row col
2646 in
2647 Report.Report "MISSING EXPRESSION" region [] $
2648 Code.toSnippet source surroundings (Just region)
2650 D.reflow $
2651 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
2653 D.stack
2655 D.fillSep $
2656 ["You","can","just","put","anything","for","now,","like"
2657 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
2658 ,"Once","there","is","something","there,","I","can","probably"
2659 ,"give","a","more","specific","hint!"
2662 D.toSimpleNote $
2663 "I may be getting confused by your indentation? The easiest way to make sure\
2664 \ this is not an indentation problem is to put the expression on the right of\
2665 \ the " ++ Name.toChars op ++ " operator on the same line."
2671-- CHAR
2674toCharReport :: Code.Source -> Char -> Row -> Col -> Report.Report
2675toCharReport source char row col =
2676 case char of
2677 CharEndless ->
2678 let
2679 region = toRegion row col
2680 in
2681 Report.Report "MISSING SINGLE QUOTE" region [] $
2682 Code.toSnippet source region Nothing
2684 D.reflow $
2685 "I thought I was parsing a character, but I got to the end of\
2686 \ the line without seeing the closing single quote:"
2688 D.reflow $
2689 "Add a closing single quote here!"
2692 CharEscape escape ->
2693 toEscapeReport source escape row col
2695 CharNotString width ->
2696 let
2697 region = toWiderRegion row col width
2698 in
2699 Report.Report "NEEDS DOUBLE QUOTES" region [] $
2700 Code.toSnippet source region Nothing
2702 "The following string uses single quotes:"
2704 D.stack
2705 [ "Please switch to double quotes instead:"
2706 , D.indent 4 $
2707 D.dullyellow "'this'" <> " => " <> D.green "\"this\""
2708 , D.toSimpleNote $
2709 "Elm uses double quotes for strings like \"hello\", whereas it uses single\
2710 \ quotes for individual characters like 'a' and 'ø'. This distinction helps with\
2711 \ code like (String.any (\\c -> c == 'X') \"90210\") where you are inspecting\
2712 \ individual characters."
2718-- STRING
2721toStringReport :: Code.Source -> String -> Row -> Col -> Report.Report
2722toStringReport source string row col =
2723 case string of
2724 StringEndless_Single ->
2725 let
2726 region = toRegion row col
2727 in
2728 Report.Report "ENDLESS STRING" region [] $
2729 Code.toSnippet source region Nothing
2731 D.reflow $
2732 "I got to the end of the line without seeing the closing double quote:"
2734 D.stack
2735 [ D.fillSep $
2736 ["Strings","look","like",D.green "\"this\"","with","double"
2737 ,"quotes","on","each","end.","Is","the","closing","double"
2738 ,"quote","missing","in","your","code?"
2740 , D.toSimpleNote $
2741 "For a string that spans multiple lines, you can use the multi-line string\
2742 \ syntax like this:"
2743 , D.dullyellow $ D.indent 4 $ D.vcat $
2744 [ "\"\"\""
2745 , "# Multi-line Strings"
2746 , ""
2747 , "- start with triple double quotes"
2748 , "- write whatever you want"
2749 , "- no need to escape newlines or double quotes"
2750 , "- end with triple double quotes"
2751 , "\"\"\""
2756 StringEndless_Multi ->
2757 let
2758 region = toWiderRegion row col 3
2759 in
2760 Report.Report "ENDLESS STRING" region [] $
2761 Code.toSnippet source region Nothing
2763 D.reflow $
2764 "I cannot find the end of this multi-line string:"
2766 D.stack
2767 [ D.reflow "Add a \"\"\" somewhere after this to end the string."
2768 , D.toSimpleNote $
2769 "Here is a valid multi-line string for reference:"
2770 , D.dullyellow $ D.indent 4 $ D.vcat $
2771 [ "\"\"\""
2772 , "# Multi-line Strings"
2773 , ""
2774 , "- start with triple double quotes"
2775 , "- write whatever you want"
2776 , "- no need to escape newlines or double quotes"
2777 , "- end with triple double quotes"
2778 , "\"\"\""
2783 StringEscape escape ->
2784 toEscapeReport source escape row col
2788-- ESCAPES
2791toEscapeReport :: Code.Source -> Escape -> Row -> Col -> Report.Report
2792toEscapeReport source escape row col =
2793 case escape of
2794 EscapeUnknown ->
2795 let
2796 region = toWiderRegion row col 2
2797 in
2798 Report.Report "UNKNOWN ESCAPE" region [] $
2799 Code.toSnippet source region Nothing
2801 D.reflow $
2802 "Backslashes always start escaped characters, but I do not recognize this one:"
2804 D.stack
2805 [ D.reflow $
2806 "Valid escape characters include:"
2807 , D.dullyellow $ D.indent 4 $ D.vcat $
2808 [ "\\n"
2809 , "\\r"
2810 , "\\t"
2811 , "\\\""
2812 , "\\\'"
2813 , "\\\\"
2814 , "\\u{003D}"
2816 , D.reflow $
2817 "Do you want one of those instead? Maybe you need \\\\ to escape a backslash?"
2818 , D.toSimpleNote $
2819 "The last style lets encode ANY character by its Unicode code\
2820 \ point. That means \\u{0009} and \\t are the same. You can use\
2821 \ that style for anything not covered by the other six escapes!"
2825 BadUnicodeFormat width ->
2826 let
2827 region = toWiderRegion row col width
2828 in
2829 Report.Report "BAD UNICODE ESCAPE" region [] $
2830 Code.toSnippet source region Nothing
2832 D.reflow $
2833 "I ran into an invalid Unicode escape:"
2835 D.stack
2836 [ D.reflow $
2837 "Here are some examples of valid Unicode escapes:"
2838 , D.dullyellow $ D.indent 4 $ D.vcat $
2839 [ "\\u{0041}"
2840 , "\\u{03BB}"
2841 , "\\u{6728}"
2842 , "\\u{1F60A}"
2844 , D.reflow $
2845 "Notice that the code point is always surrounded by curly braces.\
2846 \ Maybe you are missing the opening or closing curly brace?"
2849 BadUnicodeCode width ->
2850 let
2851 region = toWiderRegion row col width
2852 in
2853 Report.Report "BAD UNICODE ESCAPE" region [] $
2854 Code.toSnippet source region Nothing
2856 D.reflow $
2857 "This is not a valid code point:"
2859 D.reflow $
2860 "The valid code points are between 0 and 10FFFF inclusive."
2863 BadUnicodeLength width numDigits badCode ->
2864 let
2865 region = toWiderRegion row col width
2866 in
2867 Report.Report "BAD UNICODE ESCAPE" region [] $
2868 Code.toSnippet source region Nothing $
2869 if numDigits < 4 then
2871 D.reflow $
2872 "Every code point needs at least four digits:"
2874 let
2875 goodCode = replicate (4 - numDigits) '0' ++ map Char.toUpper (showHex badCode "")
2876 suggestion = "\\u{" <> D.fromChars goodCode <> "}"
2877 in
2878 D.fillSep ["Try",D.green suggestion,"instead?"]
2881 else
2883 D.reflow $
2884 "This code point has too many digits:"
2886 D.fillSep $
2887 ["Valid","code","points","are","between"
2888 ,D.green "\\u{0000}","and",D.green "\\u{10FFFF}" <> ","
2889 ,"so","try","trimming","any","leading","zeros","until"
2890 ,"you","have","between","four","and","six","digits."
2896-- NUMBERS
2899toNumberReport :: Code.Source -> Number -> Row -> Col -> Report.Report
2900toNumberReport source number row col =
2901 let
2902 region = toRegion row col
2903 in
2904 case number of
2905 NumberEnd ->
2906 Report.Report "WEIRD NUMBER" region [] $
2907 Code.toSnippet source region Nothing
2909 D.reflow $
2910 "I thought I was reading a number, but I ran into some weird stuff here:"
2912 D.stack
2913 [ D.reflow $
2914 "I recognize numbers in the following formats:"
2915 , D.indent 4 $ D.vcat [ "42", "3.14", "6.022e23", "0x002B" ]
2916 , D.reflow $
2917 "So is there a way to write it like one of those?"
2921 NumberDot int ->
2922 Report.Report "WEIRD NUMBER" region [] $
2923 Code.toSnippet source region Nothing
2925 D.reflow $
2926 "Numbers cannot end with a dot like this:"
2928 D.fillSep
2929 ["Switching","to",D.green (D.fromChars (show int))
2930 ,"or",D.green (D.fromChars (show int ++ ".0"))
2931 ,"will","work","though!"
2935 NumberHexDigit ->
2936 Report.Report "WEIRD HEXIDECIMAL" region [] $
2937 Code.toSnippet source region Nothing
2939 D.reflow $
2940 "I thought I was reading a hexidecimal number until I got here:"
2942 D.stack
2943 [ D.reflow $
2944 "Valid hexidecimal digits include 0123456789abcdefABCDEF, so I can\
2945 \ only recognize things like this:"
2946 , D.indent 4 $ D.vcat [ "0x2B", "0x002B", "0x00ffb3" ]
2950 NumberNoLeadingZero ->
2951 Report.Report "LEADING ZEROS" region [] $
2952 Code.toSnippet source region Nothing
2954 D.reflow $
2955 "I do not accept numbers with leading zeros:"
2957 D.stack
2958 [ D.reflow $
2959 "Just delete the leading zeros and it should work!"
2960 , D.toSimpleNote $
2961 "Some languages let you to specify octal numbers by adding a leading zero.\
2962 \ So in C, writing 0111 is the same as writing 73. Some people are used to\
2963 \ that, but others probably want it to equal 111. Either path is going to\
2964 \ surprise people from certain backgrounds, so Elm tries to avoid this whole\
2965 \ situation."
2971-- OPERATORS
2974toOperatorReport :: Code.Source -> Context -> BadOperator -> Row -> Col -> Report.Report
2975toOperatorReport source context operator row col =
2976 case operator of
2977 BadDot ->
2978 let
2979 region = toRegion row col
2980 in
2981 Report.Report "UNEXPECTED SYMBOL" region [] $
2982 Code.toSnippet source region Nothing
2984 "I was not expecting this dot:"
2986 D.reflow $
2987 "Dots are for record access and decimal points, so\
2988 \ they cannot float around on their own. Maybe\
2989 \ there is some extra whitespace?"
2992 BadPipe ->
2993 let
2994 region = toRegion row col
2995 in
2996 Report.Report "UNEXPECTED SYMBOL" region [] $
2997 Code.toSnippet source region Nothing
2999 D.reflow $
3000 "I was not expecting this vertical bar:"
3002 D.reflow $
3003 "Vertical bars should only appear in custom type declarations. Maybe you want || instead?"
3006 BadArrow ->
3007 let
3008 region = toWiderRegion row col 2
3009 in
3010 Report.Report "UNEXPECTED ARROW" region [] $
3011 Code.toSnippet source region Nothing $
3012 if isWithin NCase context then
3014 D.reflow $
3015 "I am parsing a `case` expression right now, but this arrow is confusing me:"
3017 D.stack
3018 [ D.reflow "Maybe the `of` keyword is missing on a previous line?"
3019 , noteForCaseError
3023 else if isWithin NBranch context then
3025 D.reflow $
3026 "I am parsing a `case` expression right now, but this arrow is confusing me:"
3028 D.stack
3029 [ D.reflow $
3030 "It makes sense to see arrows around here, so I suspect it is something earlier. Maybe this pattern is indented a bit farther than the previous patterns?"
3031 , noteForCaseIndentError
3035 else
3037 D.reflow $
3038 "I was partway through parsing an expression when I got stuck on this arrow:"
3040 D.stack
3041 [ "Arrows should only appear in `case` expressions and anonymous functions.\n\
3042 \Maybe it was supposed to be a > sign instead?"
3043 , D.toSimpleNote $
3044 "The syntax for anonymous functions is (\\x -> x + 1) so the arguments all appear\
3045 \ after the backslash and before the arrow. Maybe a backslash is missing earlier?"
3049 BadEquals ->
3050 let
3051 region = toRegion row col
3052 in
3053 Report.Report "UNEXPECTED EQUALS" region [] $
3054 Code.toSnippet source region Nothing
3056 D.reflow $
3057 "I was not expecting to see this equals sign:"
3059 D.stack
3061 D.reflow "Maybe you want == instead? To check if two values are equal?"
3063 D.toSimpleNote $
3064 if isWithin NRecord context then
3065 "Records look like { x = 3, y = 4 } with the equals sign right\
3066 \ after the field name. So maybe you forgot a comma?"
3067 else
3068 case getDefName context of
3069 Nothing ->
3070 "I may be getting confused by your indentation. I need all definitions to be indented\
3071 \ exactly the same amount, so if this is meant to be a new definition, it may have too\
3072 \ many spaces in front of it."
3074 Just name ->
3075 "I may be getting confused by your indentation. I think I am still parsing the `"
3076 ++ Name.toChars name ++ "` definition. Is this supposed to be part of a definition\
3077 \ after that? If so, the problem may be a bit before the equals sign. I need all\
3078 \ definitions to be indented exactly the same amount, so the problem may be that\
3079 \ this new definition has too many spaces in front of it."
3083 BadHasType ->
3084 let
3085 region = toRegion row col
3086 in
3087 Report.Report "UNEXPECTED SYMBOL" region [] $
3088 Code.toSnippet source region Nothing $
3090 D.reflow $
3091 "I was not expecting to run into the \"has type\" symbol here:"
3093 case getDefName context of
3094 Nothing ->
3095 D.fillSep
3096 ["Maybe","you","want",D.green "::","instead?"
3097 ,"To","put","something","on","the","front","of","a","list?"
3100 Just name ->
3101 D.stack
3103 D.fillSep
3104 ["Maybe","you","want",D.green "::","instead?"
3105 ,"To","put","something","on","the","front","of","a","list?"
3107 , D.toSimpleNote $
3108 "The single colon is reserved for type annotations and record types, but I think\
3109 \ I am parsing the definition of `" ++ Name.toChars name ++ "` right now."
3111 D.toSimpleNote $
3112 "I may be getting confused by your indentation. Is this supposed to be part of\
3113 \ a type annotation AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
3114 \ the problem may be a bit before the \"has type\" symbol. I need all definitions to\
3115 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
3116 \ this new definition is indented a bit too much."
3122-- CASE
3125toLetReport :: Code.Source -> Context -> Let -> Row -> Col -> Report.Report
3126toLetReport source context let_ startRow startCol =
3127 case let_ of
3128 LetSpace space row col ->
3129 toSpaceReport source space row col
3131 LetIn row col ->
3132 let
3133 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3134 region = toRegion row col
3135 in
3136 Report.Report "LET PROBLEM" region [] $
3137 Code.toSnippet source surroundings (Just region)
3139 D.reflow $
3140 "I was partway through parsing a `let` expression, but I got stuck here:"
3142 D.stack
3143 [ D.fillSep $
3144 ["Based","on","the","indentation,","I","was","expecting","to","see","the",D.cyan "in"
3145 ,"keyword","next.","Is","there","a","typo?"
3147 , D.toSimpleNote $
3148 "This can also happen if you are trying to define another value within the `let` but\
3149 \ it is not indented enough. Make sure each definition has exactly the same amount of\
3150 \ spaces before it. They should line up exactly!"
3154 LetDefAlignment _ row col ->
3155 let
3156 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3157 region = toRegion row col
3158 in
3159 Report.Report "LET PROBLEM" region [] $
3160 Code.toSnippet source surroundings (Just region)
3162 D.reflow $
3163 "I was partway through parsing a `let` expression, but I got stuck here:"
3165 D.stack
3166 [ D.fillSep $
3167 ["Based","on","the","indentation,","I","was","expecting","to","see","the",D.cyan "in"
3168 ,"keyword","next.","Is","there","a","typo?"
3170 , D.toSimpleNote $
3171 "This can also happen if you are trying to define another value within the `let` but\
3172 \ it is not indented enough. Make sure each definition has exactly the same amount of\
3173 \ spaces before it. They should line up exactly!"
3177 LetDefName row col ->
3178 case Code.whatIsNext source row col of
3179 Code.Keyword keyword ->
3180 let
3181 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3182 region = toKeywordRegion row col keyword
3183 in
3184 Report.Report "RESERVED WORD" region [] $
3185 Code.toSnippet source surroundings (Just region)
3187 D.reflow $
3188 "I was partway through parsing a `let` expression, but I got stuck here:"
3190 D.reflow $
3191 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name, but\
3192 \ it is a reserved word! Try using a different name instead."
3195 _ ->
3196 toUnfinishLetReport source row col startRow startCol $
3197 D.reflow $
3198 "I was expecting the name of a definition next."
3200 LetDef name def row col ->
3201 toLetDefReport source name def row col
3203 LetDestruct destruct row col ->
3204 toLetDestructReport source destruct row col
3206 LetBody expr row col ->
3207 toExprReport source context expr row col
3209 LetIndentDef row col ->
3210 toUnfinishLetReport source row col startRow startCol $
3211 D.reflow $
3212 "I was expecting a value to be defined here."
3214 LetIndentIn row col ->
3215 toUnfinishLetReport source row col startRow startCol $
3216 D.fillSep $
3217 ["I","was","expecting","to","see","the",D.cyan "in","keyword","next."
3218 ,"Or","maybe","more","of","that","expression?"
3221 LetIndentBody row col ->
3222 toUnfinishLetReport source row col startRow startCol $
3223 D.reflow $
3224 "I was expecting an expression next. Tell me what should happen with the value you just defined!"
3227toUnfinishLetReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
3228toUnfinishLetReport source row col startRow startCol message =
3229 let
3230 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3231 region = toRegion row col
3232 in
3233 Report.Report "UNFINISHED LET" region [] $
3234 Code.toSnippet source surroundings (Just region)
3236 D.reflow $
3237 "I was partway through parsing a `let` expression, but I got stuck here:"
3239 D.stack
3240 [ message
3241 , D.toSimpleNote $
3242 "Here is an example with a valid `let` expression for reference:"
3243 , D.indent 4 $ D.vcat $
3244 [ D.indent 0 $ D.fillSep ["viewPerson","person","="]
3245 , D.indent 2 $ D.fillSep [D.cyan "let"]
3246 , D.indent 4 $ D.fillSep ["fullName","="]
3247 , D.indent 6 $ D.fillSep ["person.firstName","++",D.dullyellow "\" \"","++","person.lastName"]
3248 , D.indent 2 $ D.fillSep [D.cyan "in"]
3249 , D.indent 2 $ D.fillSep ["div","[]","[","text","fullName","]"]
3251 , D.reflow $
3252 "Here we defined a `viewPerson` function that turns a person into some HTML. We use\
3253 \ a `let` expression to define the `fullName` we want to show. Notice the indentation! The\
3254 \ `fullName` is indented more than the `let` keyword, and the actual value of `fullName` is\
3255 \ indented a bit more than that. That is important!"
3260toLetDefReport :: Code.Source -> Name.Name -> Def -> Row -> Col -> Report.Report
3261toLetDefReport source name def startRow startCol =
3262 case def of
3263 DefSpace space row col ->
3264 toSpaceReport source space row col
3266 DefType tipe row col ->
3267 toTypeReport source (TC_Annotation name) tipe row col
3269 DefNameRepeat row col ->
3270 let
3271 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3272 region = toRegion row col
3273 in
3274 Report.Report "EXPECTING DEFINITION" region [] $
3275 Code.toSnippet source surroundings (Just region)
3277 D.reflow $
3278 "I just saw the type annotation for `" ++ Name.toChars name
3279 ++ "` so I was expecting to see its definition here:"
3281 D.stack
3282 [ D.reflow $
3283 "Type annotations always appear directly above the relevant\
3284 \ definition, without anything else in between."
3285 , defNote
3289 DefNameMatch defName row col ->
3290 let
3291 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3292 region = toRegion row col
3293 in
3294 Report.Report "NAME MISMATCH" region [] $
3295 Code.toSnippet source surroundings (Just region)
3297 D.reflow $
3298 "I just saw a type annotation for `" ++ Name.toChars name ++ "`, but it is followed by a definition for `" ++ Name.toChars defName ++ "`:"
3300 D.stack
3301 [ D.reflow $
3302 "These names do not match! Is there a typo?"
3303 , D.indent 4 $ D.fillSep $
3304 [D.dullyellow (D.fromName defName),"->",D.green (D.fromName name)]
3308 DefArg pattern row col ->
3309 toPatternReport source PArg pattern row col
3311 DefEquals row col ->
3312 case Code.whatIsNext source row col of
3313 Code.Keyword keyword ->
3314 let
3315 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3316 region = toKeywordRegion row col keyword
3317 in
3318 Report.Report "RESERVED WORD" region [] $
3319 Code.toSnippet source surroundings (Just region)
3321 D.fillSep
3322 ["The","name"
3323 ,"`" <> D.cyan (D.fromChars keyword) <> "`"
3324 ,"is","reserved","in","Elm,","so","it","cannot"
3325 ,"be","used","as","an","argument","here:"
3328 D.stack
3329 [ D.reflow $
3330 "Try renaming it to something else."
3331 , case keyword of
3332 "as" ->
3333 D.toFancyNote
3334 ["This","keyword","is","reserved","for","pattern","matches","like"
3335 ,"((x,y)",D.cyan "as","point)","where","you","want","to","name","a","tuple","and"
3336 ,"the","values","it","contains."
3339 _ ->
3340 D.toSimpleNote $
3341 "The `" ++ keyword ++ "` keyword has a special meaning in Elm, so it can only be used in certain situations."
3345 Code.Operator "->" ->
3346 let
3347 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3348 region = toWiderRegion row col 2
3349 in
3350 Report.Report "MISSING COLON?" region [] $
3351 Code.toSnippet source surroundings (Just region)
3353 D.reflow $
3354 "I was not expecting to see an arrow here:"
3356 D.stack
3357 [ D.fillSep
3358 ["This","usually","means","a",D.green ":","is","missing","a","bit","earlier","in"
3359 ,"a","type","annotation.","It","could","be","something","else","though,","so"
3360 ,"here","is","a","valid","definition","for","reference:"
3362 , D.indent 4 $ D.vcat $
3363 [ "greet : String -> String"
3364 , "greet name ="
3365 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
3367 , D.reflow $
3368 "Try to use that format with your `" ++ Name.toChars name ++ "` definition!"
3372 Code.Operator op ->
3373 let
3374 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3375 region = toKeywordRegion row col op
3376 in
3377 Report.Report "UNEXPECTED SYMBOL" region [] $
3378 Code.toSnippet source surroundings (Just region)
3380 D.reflow $
3381 "I was not expecting to see this symbol here:"
3383 D.stack
3384 [ D.reflow $
3385 "I am not sure what is going wrong exactly, so here is a valid\
3386 \ definition (with an optional type annotation) for reference:"
3387 , D.indent 4 $ D.vcat $
3388 [ "greet : String -> String"
3389 , "greet name ="
3390 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
3392 , D.reflow $
3393 "Try to use that format with your `" ++ Name.toChars name ++ "` definition!"
3397 _ ->
3398 let
3399 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3400 region = toRegion row col
3401 in
3402 Report.Report "PROBLEM IN DEFINITION" region [] $
3403 Code.toSnippet source surroundings (Just region)
3405 D.reflow $
3406 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
3408 D.stack
3409 [ D.reflow $
3410 "I am not sure what is going wrong exactly, so here is a valid\
3411 \ definition (with an optional type annotation) for reference:"
3412 , D.indent 4 $ D.vcat $
3413 [ "greet : String -> String"
3414 , "greet name ="
3415 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
3417 , D.reflow $
3418 "Try to use that format!"
3422 DefBody expr row col ->
3423 toExprReport source (InDef name startRow startCol) expr row col
3425 DefIndentEquals row col ->
3426 let
3427 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3428 region = toRegion row col
3429 in
3430 Report.Report "UNFINISHED DEFINITION" region [] $
3431 Code.toSnippet source surroundings (Just region)
3433 D.reflow $
3434 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
3436 D.stack
3437 [ D.reflow $
3438 "I was expecting to see an argument or an equals sign next."
3439 , defNote
3443 DefIndentType row col ->
3444 let
3445 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3446 region = toRegion row col
3447 in
3448 Report.Report "UNFINISHED DEFINITION" region [] $
3449 Code.toSnippet source surroundings (Just region)
3451 D.reflow $
3452 "I got stuck while parsing the `" ++ Name.toChars name ++ "` type annotation:"
3454 D.stack
3455 [ D.reflow $
3456 "I just saw a colon, so I am expecting to see a type next."
3457 , defNote
3461 DefIndentBody row col ->
3462 let
3463 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3464 region = toRegion row col
3465 in
3466 Report.Report "UNFINISHED DEFINITION" region [] $
3467 Code.toSnippet source surroundings (Just region)
3469 D.reflow $
3470 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
3472 D.stack
3473 [ D.reflow $
3474 "I was expecting to see an expression next. What is it equal to?"
3475 , declDefNote
3479 DefAlignment indent row col ->
3480 let
3481 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3482 region = toRegion row col
3483 offset = indent - col
3484 in
3485 Report.Report "PROBLEM IN DEFINITION" region [] $
3486 Code.toSnippet source surroundings (Just region)
3488 D.reflow $
3489 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
3491 D.reflow $
3492 "I just saw a type annotation indented " ++ show indent ++ " spaces, so I was\
3493 \ expecting to see the corresponding definition next with the exact same amount\
3494 \ of indentation. It looks like this line needs "
3495 ++ show offset ++ " more " ++ (if offset == 1 then "space" else "spaces") ++ "?"
3500defNote :: D.Doc
3501defNote =
3502 D.stack
3503 [ D.reflow $
3504 "Here is a valid definition (with a type annotation) for reference:"
3505 , D.indent 4 $ D.vcat $
3506 [ "greet : String -> String"
3507 , "greet name ="
3508 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
3510 , D.reflow $
3511 "The top line (called a \"type annotation\") is optional. You can leave it off\
3512 \ if you want. As you get more comfortable with Elm and as your project grows,\
3513 \ it becomes more and more valuable to add them though! They work great as\
3514 \ compiler-verified documentation, and they often improve error messages!"
3518toLetDestructReport :: Code.Source -> Destruct -> Row -> Col -> Report.Report
3519toLetDestructReport source destruct startRow startCol =
3520 case destruct of
3521 DestructSpace space row col ->
3522 toSpaceReport source space row col
3524 DestructPattern pattern row col ->
3525 toPatternReport source PLet pattern row col
3527 DestructEquals row col ->
3528 let
3529 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3530 region = toRegion row col
3531 in
3532 Report.Report "PROBLEM IN DEFINITION" region [] $
3533 Code.toSnippet source surroundings (Just region)
3535 D.reflow $
3536 "I got stuck trying to parse this definition:"
3538 case Code.whatIsNext source row col of
3539 Code.Operator ":" ->
3540 D.stack
3541 [ D.reflow $
3542 "I was expecting to see an equals sign next, followed by an expression\
3543 \ telling me what to compute."
3544 , D.toSimpleNote $
3545 "It looks like you may be trying to write a type annotation? It is not\
3546 \ possible to add type annotations on destructuring definitions like this.\
3547 \ You can assign a name to the overall structure, put a type annotation on\
3548 \ that, and then destructure separately though."
3551 _ ->
3552 D.reflow $
3553 "I was expecting to see an equals sign next, followed by an expression\
3554 \ telling me what to compute."
3557 DestructBody expr row col ->
3558 toExprReport source (InDestruct startRow startCol) expr row col
3560 DestructIndentEquals row col ->
3561 let
3562 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3563 region = toRegion row col
3564 in
3565 Report.Report "UNFINISHED DEFINITION" region [] $
3566 Code.toSnippet source surroundings (Just region)
3568 D.reflow $
3569 "I got stuck trying to parse this definition:"
3571 D.reflow $
3572 "I was expecting to see an equals sign next, followed by an expression\
3573 \ telling me what to compute."
3576 DestructIndentBody row col ->
3577 let
3578 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3579 region = toRegion row col
3580 in
3581 Report.Report "UNFINISHED DEFINITION" region [] $
3582 Code.toSnippet source surroundings (Just region)
3584 D.reflow $
3585 "I got stuck while parsing this definition:"
3587 D.reflow $
3588 "I was expecting to see an expression next. What is it equal to?"
3593-- CASE
3596toCaseReport :: Code.Source -> Context -> Case -> Row -> Col -> Report.Report
3597toCaseReport source context case_ startRow startCol =
3598 case case_ of
3599 CaseSpace space row col ->
3600 toSpaceReport source space row col
3602 CaseOf row col ->
3603 toUnfinishCaseReport source row col startRow startCol $
3604 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
3606 CasePattern pattern row col ->
3607 toPatternReport source PCase pattern row col
3609 CaseArrow row col ->
3610 case Code.whatIsNext source row col of
3611 Code.Keyword keyword ->
3612 let
3613 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3614 region = toKeywordRegion row col keyword
3615 in
3616 Report.Report "RESERVED WORD" region [] $
3617 Code.toSnippet source surroundings (Just region)
3619 D.reflow $
3620 "I am partway through parsing a `case` expression, but I got stuck here:"
3622 D.reflow $
3623 "It looks like you are trying to use `" ++ keyword ++ "` in one of your\
3624 \ patterns, but it is a reserved word. Try using a different name?"
3627 Code.Operator ":" ->
3628 let
3629 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3630 region = toRegion row col
3631 in
3632 Report.Report "UNEXPECTED OPERATOR" region [] $
3633 Code.toSnippet source surroundings (Just region)
3635 D.reflow $
3636 "I am partway through parsing a `case` expression, but I got stuck here:"
3638 D.fillSep $
3639 ["I","am","seeing",D.dullyellow ":","but","maybe","you","want",D.green "::","instead?"
3640 ,"For","pattern","matching","on","lists?"
3644 Code.Operator "=" ->
3645 let
3646 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3647 region = toRegion row col
3648 in
3649 Report.Report "UNEXPECTED OPERATOR" region [] $
3650 Code.toSnippet source surroundings (Just region)
3652 D.reflow $
3653 "I am partway through parsing a `case` expression, but I got stuck here:"
3655 D.fillSep $
3656 ["I","am","seeing",D.dullyellow "=","but","maybe","you","want",D.green "->","instead?"
3660 _ ->
3661 let
3662 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3663 region = toRegion row col
3664 in
3665 Report.Report "MISSING ARROW" region [] $
3666 Code.toSnippet source surroundings (Just region)
3668 D.reflow $
3669 "I am partway through parsing a `case` expression, but I got stuck here:"
3671 D.stack
3672 [ D.reflow "I was expecting to see an arrow next."
3673 , noteForCaseIndentError
3677 CaseExpr expr row col ->
3678 toExprReport source (InNode NCase startRow startCol context) expr row col
3680 CaseBranch expr row col ->
3681 toExprReport source (InNode NBranch startRow startCol context) expr row col
3683 CaseIndentOf row col ->
3684 toUnfinishCaseReport source row col startRow startCol $
3685 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
3687 CaseIndentExpr row col ->
3688 toUnfinishCaseReport source row col startRow startCol $
3689 D.reflow "I was expecting to see a expression next."
3691 CaseIndentPattern row col ->
3692 toUnfinishCaseReport source row col startRow startCol $
3693 D.reflow "I was expecting to see a pattern next."
3695 CaseIndentArrow row col ->
3696 toUnfinishCaseReport source row col startRow startCol $
3697 D.fillSep
3698 ["I","just","saw","a","pattern,","so","I","was","expecting"
3699 ,"to","see","a",D.dullyellow "->","next."
3702 CaseIndentBranch row col ->
3703 toUnfinishCaseReport source row col startRow startCol $
3704 D.reflow $
3705 "I was expecting to see an expression next. What should I do when\
3706 \ I run into this particular pattern?"
3708 CasePatternAlignment indent row col ->
3709 toUnfinishCaseReport source row col startRow startCol $
3710 D.reflow $
3711 "I suspect this is a pattern that is not indented far enough? (" ++ show indent ++ " spaces)"
3714toUnfinishCaseReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
3715toUnfinishCaseReport source row col startRow startCol message =
3716 let
3717 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3718 region = toRegion row col
3719 in
3720 Report.Report "UNFINISHED CASE" region [] $
3721 Code.toSnippet source surroundings (Just region)
3723 D.reflow $
3724 "I was partway through parsing a `case` expression, but I got stuck here:"
3726 D.stack
3727 [ message
3728 , noteForCaseError
3733noteForCaseError :: D.Doc
3734noteForCaseError =
3735 D.stack
3736 [ D.toSimpleNote $
3737 "Here is an example of a valid `case` expression for reference."
3738 , D.vcat $
3739 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
3740 , D.indent 6 $ D.fillSep [D.blue "Just","width","->"]
3741 , D.indent 8 $ D.fillSep ["width","+",D.dullyellow "200"]
3742 , ""
3743 , D.indent 6 $ D.fillSep [D.blue "Nothing","->"]
3744 , D.indent 8 $ D.fillSep [D.dullyellow "400"]
3746 , D.reflow $
3747 "Notice the indentation. Each pattern is aligned, and each branch is indented\
3748 \ a bit more than the corresponding pattern. That is important!"
3752noteForCaseIndentError :: D.Doc
3753noteForCaseIndentError =
3754 D.stack
3755 [ D.toSimpleNote $
3756 "Sometimes I get confused by indentation, so try to make your `case` look\
3757 \ something like this:"
3758 , D.vcat $
3759 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
3760 , D.indent 6 $ D.fillSep [D.blue "Just","width","->"]
3761 , D.indent 8 $ D.fillSep ["width","+",D.dullyellow "200"]
3762 , ""
3763 , D.indent 6 $ D.fillSep [D.blue "Nothing","->"]
3764 , D.indent 8 $ D.fillSep [D.dullyellow "400"]
3766 , D.reflow $
3767 "Notice the indentation! Patterns are aligned with each other. Same indentation.\
3768 \ The expressions after each arrow are all indented a bit more than the patterns.\
3769 \ That is important!"
3774-- IF
3777toIfReport :: Code.Source -> Context -> If -> Row -> Col -> Report.Report
3778toIfReport source context if_ startRow startCol =
3779 case if_ of
3780 IfSpace space row col ->
3781 toSpaceReport source space row col
3783 IfThen row col ->
3784 let
3785 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3786 region = toRegion row col
3787 in
3788 Report.Report "UNFINISHED IF" region [] $
3789 Code.toSnippet source surroundings (Just region)
3791 D.reflow $
3792 "I was expecting to see more of this `if` expression, but I got stuck here:"
3794 D.fillSep $
3795 ["I","was","expecting","to","see","the",D.cyan "then","keyword","next."
3799 IfElse row col ->
3800 let
3801 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3802 region = toRegion row col
3803 in
3804 Report.Report "UNFINISHED IF" region [] $
3805 Code.toSnippet source surroundings (Just region)
3807 D.reflow $
3808 "I was expecting to see more of this `if` expression, but I got stuck here:"
3810 D.fillSep $
3811 ["I","was","expecting","to","see","the",D.cyan "else","keyword","next."
3815 IfElseBranchStart row col ->
3816 let
3817 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3818 region = toRegion row col
3819 in
3820 Report.Report "UNFINISHED IF" region [] $
3821 Code.toSnippet source surroundings (Just region)
3823 D.reflow $
3824 "I just saw the start of an `else` branch, but then I got stuck here:"
3826 D.reflow $
3827 "I was expecting to see an expression next. Maybe it is not filled in yet?"
3830 IfCondition expr row col ->
3831 toExprReport source (InNode NCond startRow startCol context) expr row col
3833 IfThenBranch expr row col ->
3834 toExprReport source (InNode NThen startRow startCol context) expr row col
3836 IfElseBranch expr row col ->
3837 toExprReport source (InNode NElse startRow startCol context) expr row col
3839 IfIndentCondition row col ->
3840 let
3841 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3842 region = toRegion row col
3843 in
3844 Report.Report "UNFINISHED IF" region [] $
3845 Code.toSnippet source surroundings (Just region)
3847 D.reflow $
3848 "I was expecting to see more of this `if` expression, but I got stuck here:"
3850 D.stack
3851 [ D.fillSep $
3852 ["I","was","expecting","to","see","an","expression","like",D.dullyellow "x < 0"
3853 ,"that","evaluates","to","True","or","False."
3855 , D.toSimpleNote $
3856 "I can be confused by indentation. Maybe something is not indented enough?"
3860 IfIndentThen row col ->
3861 let
3862 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3863 region = toRegion row col
3864 in
3865 Report.Report "UNFINISHED IF" region [] $
3866 Code.toSnippet source surroundings (Just region)
3868 D.reflow $
3869 "I was expecting to see more of this `if` expression, but I got stuck here:"
3871 D.stack
3872 [ D.fillSep $
3873 ["I","was","expecting","to","see","the",D.cyan "then","keyword","next."
3875 , D.toSimpleNote $
3876 "I can be confused by indentation. Maybe something is not indented enough?"
3880 IfIndentThenBranch row col ->
3881 let
3882 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3883 region = toRegion row col
3884 in
3885 Report.Report "UNFINISHED IF" region [] $
3886 Code.toSnippet source surroundings (Just region)
3888 D.reflow $
3889 "I got stuck after the start of this `then` branch:"
3891 D.stack
3892 [ D.reflow $
3893 "I was expecting to see an expression next. Maybe it is not filled in yet?"
3894 , D.toSimpleNote $
3895 "I can be confused by indentation, so if the `then` branch is already\
3896 \ present, it may not be indented enough for me to recognize it."
3900 IfIndentElseBranch row col ->
3901 let
3902 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3903 region = toRegion row col
3904 in
3905 Report.Report "UNFINISHED IF" region [] $
3906 Code.toSnippet source surroundings (Just region)
3908 D.reflow $
3909 "I got stuck after the start of this `else` branch:"
3911 D.stack
3912 [ D.reflow $
3913 "I was expecting to see an expression next. Maybe it is not filled in yet?"
3914 , D.toSimpleNote $
3915 "I can be confused by indentation, so if the `else` branch is already\
3916 \ present, it may not be indented enough for me to recognize it."
3920 IfIndentElse row col ->
3921 case Code.nextLineStartsWithKeyword "else" source row of
3922 Just (elseRow, elseCol) ->
3923 let
3924 surroundings = A.Region (A.Position startRow startCol) (A.Position elseRow elseCol)
3925 region = toWiderRegion elseRow elseCol 4
3926 in
3927 Report.Report "WEIRD ELSE BRANCH" region [] $
3928 Code.toSnippet source surroundings (Just region)
3930 D.reflow $
3931 "I was partway through an `if` expression when I got stuck here:"
3933 D.fillSep $
3934 ["I","think","this",D.cyan "else","keyword","needs","to","be","indented","more."
3935 ,"Try","adding","some","spaces","before","it."
3939 Nothing ->
3940 let
3941 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3942 region = toRegion row col
3943 in
3944 Report.Report "UNFINISHED IF" region [] $
3945 Code.toSnippet source surroundings (Just region)
3947 D.reflow $
3948 "I was expecting to see an `else` branch after this:"
3950 D.stack
3951 [ D.fillSep
3952 ["I","know","what","to","do","when","the","condition","is","True,"
3953 ,"but","what","happens","when","it","is","False?"
3954 ,"Add","an",D.cyan "else","branch","to","handle","that","scenario!"
3961-- RECORD
3964toRecordReport :: Code.Source -> Context -> Record -> Row -> Col -> Report.Report
3965toRecordReport source context record startRow startCol =
3966 case record of
3967 RecordOpen row col ->
3968 case Code.whatIsNext source row col of
3969 Code.Keyword keyword ->
3970 let
3971 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3972 region = toKeywordRegion row col keyword
3973 in
3974 Report.Report "RESERVED WORD" region [] $
3975 Code.toSnippet source surroundings (Just region)
3977 D.reflow $
3978 "I just started parsing a record, but I got stuck on this field name:"
3980 D.reflow $
3981 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
3982 \ that is a reserved word. Try using a different name!"
3985 _ ->
3986 let
3987 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3988 region = toRegion row col
3989 in
3990 Report.Report "PROBLEM IN RECORD" region [] $
3991 Code.toSnippet source surroundings (Just region)
3993 D.reflow $
3994 "I just started parsing a record, but I got stuck here:"
3996 D.stack
3997 [ D.fillSep
3998 ["I","was","expecting","to","see","a","record","field","defined","next,"
3999 ,"so","I","am","looking","for","a","name","like"
4000 ,D.dullyellow "userName","or",D.dullyellow "plantHeight" <> "."
4002 , D.toSimpleNote $
4003 "Field names must start with a lower-case letter. After that, you can use\
4004 \ any sequence of letters, numbers, and underscores."
4005 , noteForRecordError
4009 RecordEnd row col ->
4010 let
4011 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4012 region = toRegion row col
4013 in
4014 Report.Report "PROBLEM IN RECORD" region [] $
4015 Code.toSnippet source surroundings (Just region)
4017 D.reflow $
4018 "I am partway through parsing a record, but I got stuck here:"
4020 D.stack
4021 [ D.fillSep
4022 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
4023 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
4025 , D.toSimpleNote $
4026 "When I get stuck like this, it usually means that there is a missing parenthesis\
4027 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
4031 RecordField row col ->
4032 case Code.whatIsNext source row col of
4033 Code.Keyword keyword ->
4034 let
4035 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4036 region = toKeywordRegion row col keyword
4037 in
4038 Report.Report "RESERVED WORD" region [] $
4039 Code.toSnippet source surroundings (Just region)
4041 D.reflow $
4042 "I am partway through parsing a record, but I got stuck on this field name:"
4044 D.reflow $
4045 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
4046 \ that is a reserved word. Try using a different name!"
4049 Code.Other (Just ',') ->
4050 let
4051 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4052 region = toRegion row col
4053 in
4054 Report.Report "EXTRA COMMA" region [] $
4055 Code.toSnippet source surroundings (Just region)
4057 D.reflow $
4058 "I am partway through parsing a record, but I got stuck here:"
4060 D.stack
4061 [ D.reflow $
4062 "I am seeing two commas in a row. This is the second one!"
4063 , D.reflow $
4064 "Just delete one of the commas and you should be all set!"
4065 , noteForRecordError
4069 Code.Close _ '}' ->
4070 let
4071 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4072 region = toRegion row col
4073 in
4074 Report.Report "EXTRA COMMA" region [] $
4075 Code.toSnippet source surroundings (Just region)
4077 D.reflow $
4078 "I am partway through parsing a record, but I got stuck here:"
4080 D.stack
4081 [ D.reflow $
4082 "Trailing commas are not allowed in records. Try deleting the comma that appears\
4083 \ before this closing curly brace."
4084 , noteForRecordError
4088 _ ->
4089 let
4090 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4091 region = toRegion row col
4092 in
4093 Report.Report "PROBLEM IN RECORD" region [] $
4094 Code.toSnippet source surroundings (Just region)
4096 D.reflow $
4097 "I am partway through parsing a record, but I got stuck here:"
4099 D.stack
4100 [ D.fillSep
4101 ["I","was","expecting","to","see","another","record","field","defined","next,"
4102 ,"so","I","am","looking","for","a","name","like"
4103 ,D.dullyellow "userName","or",D.dullyellow "plantHeight" <> "."
4105 , D.toSimpleNote $
4106 "Field names must start with a lower-case letter. After that, you can use\
4107 \ any sequence of letters, numbers, and underscores."
4108 , noteForRecordError
4112 RecordEquals row col ->
4113 let
4114 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4115 region = toRegion row col
4116 in
4117 Report.Report "PROBLEM IN RECORD" region [] $
4118 Code.toSnippet source surroundings (Just region)
4120 D.reflow $
4121 "I am partway through parsing a record, but I got stuck here:"
4123 D.stack
4124 [ D.fillSep $
4125 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
4126 ,"an","equals","sign","next.","So","try","putting","an",D.green "=","sign","here?"
4128 , noteForRecordError
4132 RecordExpr expr row col ->
4133 toExprReport source (InNode NRecord startRow startCol context) expr row col
4135 RecordSpace space row col ->
4136 toSpaceReport source space row col
4138 RecordIndentOpen row col ->
4139 let
4140 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4141 region = toRegion row col
4142 in
4143 Report.Report "UNFINISHED RECORD" region [] $
4144 Code.toSnippet source surroundings (Just region)
4146 D.reflow $
4147 "I just saw the opening curly brace of a record, but then I got stuck here:"
4149 D.stack
4150 [ D.fillSep $
4151 ["I","am","expecting","a","record","like",D.dullyellow "{ x = 3, y = 4 }","here."
4152 ,"Try","defining","some","fields","of","your","own?"
4154 , noteForRecordIndentError
4158 RecordIndentEnd row col ->
4159 case Code.nextLineStartsWithCloseCurly source row of
4160 Just (curlyRow, curlyCol) ->
4161 let
4162 surroundings = A.Region (A.Position startRow startCol) (A.Position curlyRow curlyCol)
4163 region = toRegion curlyRow curlyCol
4164 in
4165 Report.Report "NEED MORE INDENTATION" region [] $
4166 Code.toSnippet source surroundings (Just region)
4168 D.reflow $
4169 "I was partway through parsing a record, but I got stuck here:"
4171 D.stack
4172 [ D.reflow $
4173 "I need this curly brace to be indented more. Try adding some spaces before it!"
4174 , noteForRecordError
4178 Nothing ->
4179 let
4180 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4181 region = toRegion row col
4182 in
4183 Report.Report "UNFINISHED RECORD" region [] $
4184 Code.toSnippet source surroundings (Just region)
4186 D.reflow $
4187 "I was partway through parsing a record, but I got stuck here:"
4189 D.stack
4190 [ D.fillSep $
4191 ["I","was","expecting","to","see","a","closing","curly","brace","next."
4192 ,"Try","putting","a",D.green "}","next","and","see","if","that","helps?"
4194 , noteForRecordIndentError
4198 RecordIndentField row col ->
4199 let
4200 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4201 region = toRegion row col
4202 in
4203 Report.Report "UNFINISHED RECORD" region [] $
4204 Code.toSnippet source surroundings (Just region)
4206 D.reflow $
4207 "I am partway through parsing a record, but I got stuck after that last comma:"
4209 D.stack
4210 [ D.reflow $
4211 "Trailing commas are not allowed in records, so the fix may be to\
4212 \ delete that last comma? Or maybe you were in the middle of defining\
4213 \ an additional field?"
4214 , noteForRecordError
4218 RecordIndentEquals row col ->
4219 let
4220 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4221 region = toRegion row col
4222 in
4223 Report.Report "UNFINISHED RECORD" region [] $
4224 Code.toSnippet source surroundings (Just region)
4226 D.reflow $
4227 "I am partway through parsing a record. I just saw a record\
4228 \ field, so I was expecting to see an equals sign next:"
4230 D.stack
4231 [ D.fillSep $
4232 ["Try","putting","an",D.green "=","followed","by","an","expression?"
4234 , noteForRecordIndentError
4238 RecordIndentExpr row col ->
4239 let
4240 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4241 region = toRegion row col
4242 in
4243 Report.Report "UNFINISHED RECORD" region [] $
4244 Code.toSnippet source surroundings (Just region)
4246 D.reflow $
4247 "I am partway through parsing a record, and I was expecting to run into an expression next:"
4249 D.stack
4250 [ D.fillSep $
4251 ["Try","putting","something","like"
4252 ,D.dullyellow "42","or",D.dullyellow"\"hello\"","for","now?"
4254 , noteForRecordIndentError
4259noteForRecordError :: D.Doc
4260noteForRecordError =
4261 D.stack $
4262 [ D.toSimpleNote
4263 "If you are trying to define a record across multiple lines, I recommend using this format:"
4264 , D.indent 4 $ D.vcat $
4265 [ "{ name = " <> D.dullyellow "\"Alice\""
4266 , ", age = " <> D.dullyellow "42"
4267 , ", height = " <> D.dullyellow "1.75"
4268 , "}"
4270 , D.reflow $
4271 "Notice that each line starts with some indentation. Usually two or four spaces.\
4272 \ This is the stylistic convention in the Elm ecosystem."
4276noteForRecordIndentError :: D.Doc
4277noteForRecordIndentError =
4278 D.stack
4279 [ D.toSimpleNote
4280 "I may be confused by indentation. For example, if you are trying to define\
4281 \ a record across multiple lines, I recommend using this format:"
4282 , D.indent 4 $ D.vcat $
4283 [ "{ name = " <> D.dullyellow "\"Alice\""
4284 , ", age = " <> D.dullyellow "42"
4285 , ", height = " <> D.dullyellow "1.75"
4286 , "}"
4288 , D.reflow $
4289 "Notice that each line starts with some indentation. Usually two or four spaces.\
4290 \ This is the stylistic convention in the Elm ecosystem!"
4295-- TUPLE
4298toTupleReport :: Code.Source -> Context -> Tuple -> Row -> Col -> Report.Report
4299toTupleReport source context tuple startRow startCol =
4300 case tuple of
4301 TupleExpr expr row col ->
4302 toExprReport source (InNode NParens startRow startCol context) expr row col
4304 TupleSpace space row col ->
4305 toSpaceReport source space row col
4307 TupleEnd row col ->
4308 let
4309 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4310 region = toRegion row col
4311 in
4312 Report.Report "UNFINISHED PARENTHESES" region [] $
4313 Code.toSnippet source surroundings (Just region)
4315 D.reflow $
4316 "I was expecting to see a closing parentheses next, but I got stuck here:"
4318 D.stack
4319 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
4320 , D.toSimpleNote $
4321 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
4322 \ unexpectedly. So there may be some earlier syntax trouble (like extra parenthesis\
4323 \ or missing brackets) that is confusing me."
4327 TupleOperatorClose row col ->
4328 let
4329 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4330 region = toRegion row col
4331 in
4332 Report.Report "UNFINISHED OPERATOR FUNCTION" region [] $
4333 Code.toSnippet source surroundings (Just region)
4335 D.reflow "I was expecting a closing parenthesis here:"
4337 D.stack
4338 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
4339 , D.toSimpleNote $
4340 "I think I am parsing an operator function right now, so I am expecting to see\
4341 \ something like (+) or (&&) where an operator is surrounded by parentheses with\
4342 \ no extra spaces."
4346 TupleOperatorReserved operator row col ->
4347 let
4348 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4349 region = toRegion row col
4350 in
4351 Report.Report "UNEXPECTED SYMBOL" region [] $
4352 Code.toSnippet source surroundings (Just region)
4354 D.reflow $
4355 "I ran into an unexpected symbol here:"
4357 D.fillSep $
4358 case operator of
4359 BadDot -> ["Maybe","you","wanted","a","record","accessor","like",D.dullyellow ".x","or",D.dullyellow ".name","instead?"]
4360 BadPipe -> ["Try",D.dullyellow "(||)","instead?","To","turn","boolean","OR","into","a","function?"]
4361 BadArrow -> ["Maybe","you","wanted",D.dullyellow "(>)","or",D.dullyellow "(>=)","instead?"]
4362 BadEquals -> ["Try",D.dullyellow "(==)","instead?","To","make","a","function","that","checks","equality?"]
4363 BadHasType -> ["Try",D.dullyellow "(::)","instead?","To","add","values","to","the","front","of","lists?"]
4366 TupleIndentExpr1 row col ->
4367 let
4368 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4369 region = toRegion row col
4370 in
4371 Report.Report "UNFINISHED PARENTHESES" region [] $
4372 Code.toSnippet source surroundings (Just region)
4374 D.reflow $
4375 "I just saw an open parenthesis, so I was expecting to see an expression next."
4377 D.stack
4378 [ D.fillSep $
4379 ["Something","like",D.dullyellow "(4 + 5)","or"
4380 ,D.dullyellow "(String.reverse \"desserts\")" <> "."
4381 ,"Anything","where","you","are","putting","parentheses","around","normal","expressions."
4383 , D.toSimpleNote $
4384 "I can get confused by indentation in cases like this, so\
4385 \ maybe you have an expression but it is not indented enough?"
4389 TupleIndentExprN row col ->
4390 let
4391 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4392 region = toRegion row col
4393 in
4394 Report.Report "UNFINISHED TUPLE" region [] $
4395 Code.toSnippet source surroundings (Just region)
4397 D.reflow $
4398 "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."
4400 D.stack
4401 [ D.fillSep $
4402 ["A","tuple","looks","like",D.dullyellow "(3,4)","or"
4403 ,D.dullyellow "(\"Tom\",42)" <> ","
4404 ,"so","I","think","there","is","an","expression","missing","here?"
4406 , D.toSimpleNote $
4407 "I can get confused by indentation in cases like this, so\
4408 \ maybe you have an expression but it is not indented enough?"
4412 TupleIndentEnd row col ->
4413 let
4414 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4415 region = toRegion row col
4416 in
4417 Report.Report "UNFINISHED PARENTHESES" region [] $
4418 Code.toSnippet source surroundings (Just region)
4420 D.reflow $
4421 "I was expecting to see a closing parenthesis next:"
4423 D.stack
4424 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
4425 , D.toSimpleNote $
4426 "I can get confused by indentation in cases like this, so\
4427 \ maybe you have a closing parenthesis but it is not indented enough?"
4432toListReport :: Code.Source -> Context -> List -> Row -> Col -> Report.Report
4433toListReport source context list startRow startCol =
4434 case list of
4435 ListSpace space row col ->
4436 toSpaceReport source space row col
4438 ListOpen row col ->
4439 let
4440 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4441 region = toRegion row col
4442 in
4443 Report.Report "UNFINISHED LIST" region [] $
4444 Code.toSnippet source surroundings (Just region)
4446 D.reflow $
4447 "I am partway through parsing a list, but I got stuck here:"
4449 D.stack
4450 [ D.fillSep
4451 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
4452 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
4454 , D.toSimpleNote $
4455 "When I get stuck like this, it usually means that there is a missing parenthesis\
4456 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
4460 ListExpr expr row col ->
4461 case expr of
4462 Start r c ->
4463 let
4464 surroundings = A.Region (A.Position startRow startCol) (A.Position r c)
4465 region = toRegion r c
4466 in
4467 Report.Report "UNFINISHED LIST" region [] $
4468 Code.toSnippet source surroundings (Just region)
4470 D.reflow $
4471 "I was expecting to see another list entry after that last comma:"
4473 D.stack
4474 [ D.reflow $
4475 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
4476 , D.toSimpleNote
4477 "I recommend using the following format for lists that span multiple lines:"
4478 , D.indent 4 $ D.vcat $
4479 [ "[ " <> D.dullyellow "\"Alice\""
4480 , ", " <> D.dullyellow "\"Bob\""
4481 , ", " <> D.dullyellow "\"Chuck\""
4482 , "]"
4484 , D.reflow $
4485 "Notice that each line starts with some indentation. Usually two or four spaces.\
4486 \ This is the stylistic convention in the Elm ecosystem."
4490 _ ->
4491 toExprReport source (InNode NList startRow startCol context) expr row col
4493 ListEnd row col ->
4494 let
4495 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4496 region = toRegion row col
4497 in
4498 Report.Report "UNFINISHED LIST" region [] $
4499 Code.toSnippet source surroundings (Just region)
4501 D.reflow $
4502 "I am partway through parsing a list, but I got stuck here:"
4504 D.stack
4505 [ D.fillSep
4506 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
4507 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
4509 , D.toSimpleNote $
4510 "When I get stuck like this, it usually means that there is a missing parenthesis\
4511 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
4515 ListIndentOpen row col ->
4516 let
4517 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4518 region = toRegion row col
4519 in
4520 Report.Report "UNFINISHED LIST" region [] $
4521 Code.toSnippet source surroundings (Just region)
4523 D.reflow $
4524 "I cannot find the end of this list:"
4526 D.stack
4527 [ D.fillSep $
4528 ["You","could","change","it","to","something","like"
4529 ,D.dullyellow "[3,4,5]"
4530 ,"or","even","just"
4531 ,D.dullyellow "[]" <> "."
4532 ,"Anything","where","there","is","an","open","and","close","square","brace,"
4533 ,"and","where","the","elements","of","the","list","are","separated","by","commas."
4535 , D.toSimpleNote
4536 "I may be confused by indentation. For example, if you are trying to define\
4537 \ a list across multiple lines, I recommend using this format:"
4538 , D.indent 4 $ D.vcat $
4539 [ "[ " <> D.dullyellow "\"Alice\""
4540 , ", " <> D.dullyellow "\"Bob\""
4541 , ", " <> D.dullyellow "\"Chuck\""
4542 , "]"
4544 , D.reflow $
4545 "Notice that each line starts with some indentation. Usually two or four spaces.\
4546 \ This is the stylistic convention in the Elm ecosystem."
4550 ListIndentEnd row col ->
4551 let
4552 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4553 region = toRegion row col
4554 in
4555 Report.Report "UNFINISHED LIST" region [] $
4556 Code.toSnippet source surroundings (Just region)
4558 D.reflow $
4559 "I cannot find the end of this list:"
4561 D.stack
4562 [ D.fillSep $
4563 ["You","can","just","add","a","closing",D.dullyellow "]"
4564 ,"right","here,","and","I","will","be","all","set!"
4566 , D.toSimpleNote
4567 "I may be confused by indentation. For example, if you are trying to define\
4568 \ a list across multiple lines, I recommend using this format:"
4569 , D.indent 4 $ D.vcat $
4570 [ "[ " <> D.dullyellow "\"Alice\""
4571 , ", " <> D.dullyellow "\"Bob\""
4572 , ", " <> D.dullyellow "\"Chuck\""
4573 , "]"
4575 , D.reflow $
4576 "Notice that each line starts with some indentation. Usually two or four spaces.\
4577 \ This is the stylistic convention in the Elm ecosystem."
4581 ListIndentExpr row col ->
4582 let
4583 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4584 region = toRegion row col
4585 in
4586 Report.Report "UNFINISHED LIST" region [] $
4587 Code.toSnippet source surroundings (Just region)
4589 D.reflow $
4590 "I was expecting to see another list entry after this comma:"
4592 D.stack
4593 [ D.reflow $
4594 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
4595 , D.toSimpleNote
4596 "I recommend using the following format for lists that span multiple lines:"
4597 , D.indent 4 $ D.vcat $
4598 [ "[ " <> D.dullyellow "\"Alice\""
4599 , ", " <> D.dullyellow "\"Bob\""
4600 , ", " <> D.dullyellow "\"Chuck\""
4601 , "]"
4603 , D.reflow $
4604 "Notice that each line starts with some indentation. Usually two or four spaces.\
4605 \ This is the stylistic convention in the Elm ecosystem."
4610toFuncReport :: Code.Source -> Context -> Func -> Row -> Col -> Report.Report
4611toFuncReport source context func startRow startCol =
4612 case func of
4613 FuncSpace space row col ->
4614 toSpaceReport source space row col
4616 FuncArg pattern row col ->
4617 toPatternReport source PArg pattern row col
4619 FuncBody expr row col ->
4620 toExprReport source (InNode NFunc startRow startCol context) expr row col
4622 FuncArrow row col ->
4623 case Code.whatIsNext source row col of
4624 Code.Keyword keyword ->
4625 let
4626 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4627 region = toKeywordRegion row col keyword
4628 in
4629 Report.Report "RESERVED WORD" region [] $
4630 Code.toSnippet source surroundings (Just region)
4632 D.reflow $
4633 "I was parsing an anonymous function, but I got stuck here:"
4635 D.reflow $
4636 "It looks like you are trying to use `" ++ keyword ++ "` as an argument, but\
4637 \ it is a reserved word in this language. Try using a different argument name!"
4640 _ ->
4641 let
4642 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4643 region = toRegion row col
4644 in
4645 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
4646 Code.toSnippet source surroundings (Just region)
4648 D.reflow $
4649 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
4651 D.fillSep $
4652 ["The","syntax","for","anonymous","functions","is"
4653 ,D.dullyellow "(\\x -> x + 1)"
4654 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
4658 FuncIndentArg row col ->
4659 let
4660 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4661 region = toRegion row col
4662 in
4663 Report.Report "MISSING ARGUMENT" region [] $
4664 Code.toSnippet source surroundings (Just region)
4666 D.reflow $
4667 "I just saw the beginning of an anonymous function, so I was expecting to see an argument next:"
4669 D.stack
4670 [ D.fillSep
4671 ["Something","like",D.dullyellow"x","or",D.dullyellow "name" <> "."
4672 ,"Anything","that","starts","with","a","lower","case","letter!"
4674 , D.toSimpleNote $
4675 "The syntax for anonymous functions is (\\x -> x + 1) where the backslash\
4676 \ is meant to look a bit like a lambda if you squint. This visual pun seemed\
4677 \ like a better idea at the time!"
4681 FuncIndentArrow row col ->
4682 let
4683 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4684 region = toRegion row col
4685 in
4686 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
4687 Code.toSnippet source surroundings (Just region)
4689 D.reflow $
4690 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
4692 D.stack
4693 [ D.fillSep $
4694 ["The","syntax","for","anonymous","functions","is"
4695 ,D.dullyellow "(\\x -> x + 1)"
4696 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
4698 , D.toSimpleNote $
4699 "It is possible that I am confused about indetation! I generally recommend\
4700 \ switching to named functions if the definition cannot fit inline nicely, so\
4701 \ either (1) try to fit the whole anonymous function on one line or (2) break\
4702 \ the whole thing out into a named function. Things tend to be clearer that way!"
4706 FuncIndentBody row col ->
4707 let
4708 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4709 region = toRegion row col
4710 in
4711 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
4712 Code.toSnippet source surroundings (Just region)
4714 D.reflow $
4715 "I was expecting to see the body of your anonymous function next:"
4717 D.stack
4718 [ D.fillSep $
4719 ["The","syntax","for","anonymous","functions","is"
4720 ,D.dullyellow "(\\x -> x + 1)"
4721 ,"so","I","am","missing","all","the","stuff","after","the","arrow!"
4723 , D.toSimpleNote $
4724 "It is possible that I am confused about indetation! I generally recommend\
4725 \ switching to named functions if the definition cannot fit inline nicely, so\
4726 \ either (1) try to fit the whole anonymous function on one line or (2) break\
4727 \ the whole thing out into a named function. Things tend to be clearer that way!"
4733-- PATTERN
4736data PContext
4737 = PCase
4738 | PArg
4739 | PLet
4742toPatternReport :: Code.Source -> PContext -> Pattern -> Row -> Col -> Report.Report
4743toPatternReport source context pattern startRow startCol =
4744 case pattern of
4745 PRecord record row col ->
4746 toPRecordReport source record row col
4748 PTuple tuple row col ->
4749 toPTupleReport source context tuple row col
4751 PList list row col ->
4752 toPListReport source context list row col
4754 PStart row col ->
4755 case Code.whatIsNext source row col of
4756 Code.Keyword keyword ->
4757 let
4758 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4759 region = toKeywordRegion row col keyword
4760 inThisThing =
4761 case context of
4762 PArg -> "as an argument"
4763 PCase -> "in this pattern"
4764 PLet -> "in this pattern"
4765 in
4766 Report.Report "RESERVED WORD" region [] $
4767 Code.toSnippet source surroundings (Just region)
4769 D.reflow $
4770 "It looks like you are trying to use `" ++ keyword ++ "` " ++ inThisThing ++ ":"
4772 D.reflow $
4773 "This is a reserved word! Try using some other name?"
4776 Code.Operator "-" ->
4777 let
4778 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4779 region = toRegion row col
4780 in
4781 Report.Report "UNEXPECTED SYMBOL" region [] $
4782 Code.toSnippet source surroundings (Just region)
4784 D.reflow $
4785 "I ran into a minus sign unexpectedly in this pattern:"
4787 D.reflow $
4788 "It is not possible to pattern match on negative numbers at this\
4789 \ time. Try using an `if` expression for that sort of thing for now."
4792 _ ->
4793 let
4794 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4795 region = toRegion row col
4796 in
4797 Report.Report "PROBLEM IN PATTERN" region [] $
4798 Code.toSnippet source surroundings (Just region)
4800 D.reflow $
4801 "I wanted to parse a pattern next, but I got stuck here:"
4803 D.fillSep $
4804 ["I","am","not","sure","why","I","am","getting","stuck","exactly."
4805 ,"I","just","know","that","I","want","a","pattern","next."
4806 ,"Something","as","simple","as"
4807 ,D.dullyellow "maybeHeight","or",D.dullyellow "result"
4808 ,"would","work!"
4812 PChar char row col ->
4813 toCharReport source char row col
4815 PString string row col ->
4816 toStringReport source string row col
4818 PNumber number row col ->
4819 toNumberReport source number row col
4821 PFloat width row col ->
4822 let
4823 region = toWiderRegion row col width
4824 in
4825 Report.Report "UNEXPECTED PATTERN" region [] $
4826 Code.toSnippet source region Nothing
4828 D.reflow $
4829 "I cannot pattern match with floating point numbers:"
4831 D.fillSep $
4832 ["Equality","on","floats","can","be","unreliable,","so","you","usually","want"
4833 ,"to","check","that","they","are","nearby","with","some","sort","of"
4834 ,D.dullyellow "(abs (actual - expected) < 0.001)","check."
4838 PAlias row col ->
4839 let
4840 region = toRegion row col
4841 in
4842 Report.Report "UNFINISHED PATTERN" region [] $
4843 Code.toSnippet source region Nothing $
4845 D.reflow $
4846 "I was expecting to see a variable name after the `as` keyword:"
4848 D.stack
4849 [ D.fillSep $
4850 ["The","`as`","keyword","lets","you","write","patterns","like"
4851 ,"((" <> D.dullyellow "x" <> "," <> D.dullyellow "y" <> ") " <> D.cyan "as" <> D.dullyellow " point" <> ")"
4852 ,"so","you","can","refer","to","individual","parts","of","the","tuple","with"
4853 ,D.dullyellow "x","and",D.dullyellow "y","or","you","refer","to","the","whole"
4854 ,"thing","with",D.dullyellow "point" <> "."
4856 , D.reflow $
4857 "So I was expecting to see a variable name after the `as` keyword here. Sometimes\
4858 \ people just want to use `as` as a variable name though. Try using a different name\
4859 \ in that case!"
4863 PWildcardNotVar name width row col ->
4864 let
4865 region = toWiderRegion row col (fromIntegral width)
4866 examples =
4867 case dropWhile (=='_') (Name.toChars name) of
4868 [] -> [D.dullyellow "x","or",D.dullyellow "age"]
4869 c:cs -> [D.dullyellow (D.fromChars (Char.toLower c : cs))]
4870 in
4871 Report.Report "UNEXPECTED NAME" region [] $
4872 Code.toSnippet source region Nothing $
4874 D.reflow $
4875 "Variable names cannot start with underscores like this:"
4877 D.fillSep $
4878 ["You","can","either","have","an","underscore","like",D.dullyellow "_","to"
4879 ,"ignore","the","value,","or","you","can","have","a","name","like"
4880 ] ++ examples ++ ["to","use","the","matched","value." ]
4883 PSpace space row col ->
4884 toSpaceReport source space row col
4886 PIndentStart row col ->
4887 let
4888 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4889 region = toRegion row col
4890 in
4891 Report.Report "UNFINISHED PATTERN" region [] $
4892 Code.toSnippet source surroundings (Just region)
4894 D.reflow $
4895 "I wanted to parse a pattern next, but I got stuck here:"
4897 D.stack
4898 [ D.fillSep $
4899 ["I","am","not","sure","why","I","am","getting","stuck","exactly."
4900 ,"I","just","know","that","I","want","a","pattern","next."
4901 ,"Something","as","simple","as"
4902 ,D.dullyellow "maybeHeight","or",D.dullyellow "result"
4903 ,"would","work!"
4905 , D.toSimpleNote $
4906 "I can get confused by indentation. If you think there is a pattern next, maybe\
4907 \ it needs to be indented a bit more?"
4911 PIndentAlias row col ->
4912 let
4913 region = toRegion row col
4914 in
4915 Report.Report "UNFINISHED PATTERN" region [] $
4916 Code.toSnippet source region Nothing $
4918 D.reflow $
4919 "I was expecting to see a variable name after the `as` keyword:"
4921 D.stack
4922 [ D.fillSep $
4923 ["The","`as`","keyword","lets","you","write","patterns","like"
4924 ,"((" <> D.dullyellow "x" <> "," <> D.dullyellow "y" <> ") " <> D.cyan "as" <> D.dullyellow " point" <> ")"
4925 ,"so","you","can","refer","to","individual","parts","of","the","tuple","with"
4926 ,D.dullyellow "x","and",D.dullyellow "y","or","you","refer","to","the","whole"
4927 ,"thing","with",D.dullyellow "point."
4929 , D.reflow $
4930 "So I was expecting to see a variable name after the `as` keyword here. Sometimes\
4931 \ people just want to use `as` as a variable name though. Try using a different name\
4932 \ in that case!"
4937toPRecordReport :: Code.Source -> PRecord -> Row -> Col -> Report.Report
4938toPRecordReport source record startRow startCol =
4939 case record of
4940 PRecordOpen row col ->
4941 toUnfinishRecordPatternReport source row col startRow startCol $
4942 D.reflow "I was expecting to see a field name next."
4944 PRecordEnd row col ->
4945 toUnfinishRecordPatternReport source row col startRow startCol $
4946 D.fillSep
4947 ["I","was","expecting","to","see","a","closing","curly","brace","next."
4948 ,"Try","adding","a",D.dullyellow "}","here?"
4951 PRecordField row col ->
4952 case Code.whatIsNext source row col of
4953 Code.Keyword keyword ->
4954 let
4955 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4956 region = toKeywordRegion row col keyword
4957 in
4958 Report.Report "RESERVED WORD" region [] $
4959 Code.toSnippet source surroundings (Just region)
4961 D.reflow $
4962 "I was not expecting to see `" ++ keyword ++ "` as a record field name:"
4964 D.reflow $
4965 "This is a reserved word, not available for variable names. Try another name!"
4968 _ ->
4969 toUnfinishRecordPatternReport source row col startRow startCol $
4970 D.reflow "I was expecting to see a field name next."
4972 PRecordSpace space row col ->
4973 toSpaceReport source space row col
4975 PRecordIndentOpen row col ->
4976 toUnfinishRecordPatternReport source row col startRow startCol $
4977 D.reflow "I was expecting to see a field name next."
4979 PRecordIndentEnd row col ->
4980 toUnfinishRecordPatternReport source row col startRow startCol $
4981 D.fillSep
4982 ["I","was","expecting","to","see","a","closing","curly","brace","next."
4983 ,"Try","adding","a",D.dullyellow "}","here?"
4986 PRecordIndentField row col ->
4987 toUnfinishRecordPatternReport source row col startRow startCol $
4988 D.reflow "I was expecting to see a field name next."
4991toUnfinishRecordPatternReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
4992toUnfinishRecordPatternReport source row col startRow startCol message =
4993 let
4994 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4995 region = toRegion row col
4996 in
4997 Report.Report "UNFINISHED RECORD PATTERN" region [] $
4998 Code.toSnippet source surroundings (Just region)
5000 D.reflow $
5001 "I was partway through parsing a record pattern, but I got stuck here:"
5003 D.stack
5004 [ message
5005 , D.toFancyHint $
5006 ["A","record","pattern","looks","like",D.dullyellow "{x,y}","or",D.dullyellow "{name,age}"
5007 ,"where","you","list","the","field","names","you","want","to","access."
5014toPTupleReport :: Code.Source -> PContext -> PTuple -> Row -> Col -> Report.Report
5015toPTupleReport source context tuple startRow startCol =
5016 case tuple of
5017 PTupleOpen row col ->
5018 case Code.whatIsNext source row col of
5019 Code.Keyword keyword ->
5020 let
5021 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5022 region = toKeywordRegion row col keyword
5023 in
5024 Report.Report "RESERVED WORD" region [] $
5025 Code.toSnippet source surroundings (Just region)
5027 D.reflow $
5028 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name:"
5030 D.reflow $
5031 "This is a reserved word! Try using some other name?"
5034 _ ->
5035 let
5036 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5037 region = toRegion row col
5038 in
5039 Report.Report "UNFINISHED PARENTHESES" region [] $
5040 Code.toSnippet source surroundings (Just region)
5042 D.reflow $
5043 "I just saw an open parenthesis, but I got stuck here:"
5045 D.fillSep
5046 ["I","was","expecting","to","see","a","pattern","next."
5047 ,"Maybe","it","will","end","up","being","something"
5048 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "?"
5052 PTupleEnd row col ->
5053 case Code.whatIsNext source row col of
5054 Code.Keyword keyword ->
5055 let
5056 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5057 region = toKeywordRegion row col keyword
5058 in
5059 Report.Report "RESERVED WORD" region [] $
5060 Code.toSnippet source surroundings (Just region) $
5062 D.reflow $
5063 "I ran into a reserved word in this pattern:"
5065 D.reflow $
5066 "The `" ++ keyword ++ "` keyword is reserved. Try using a different name instead!"
5069 Code.Operator op ->
5070 let
5071 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5072 region = toKeywordRegion row col op
5073 in
5074 Report.Report "UNEXPECTED SYMBOL" region [] $
5075 Code.toSnippet source surroundings (Just region) $
5077 D.reflow $
5078 "I ran into the " ++ op ++ " symbol unexpectedly in this pattern:"
5080 D.reflow $
5081 "Only the :: symbol that works in patterns. It is useful if you\
5082 \ are pattern matching on lists, trying to get the first element\
5083 \ off the front. Did you want that instead?"
5086 Code.Close term bracket ->
5087 let
5088 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5089 region = toRegion row col
5090 in
5091 Report.Report ("STRAY " ++ map Char.toUpper term) region [] $
5092 Code.toSnippet source surroundings (Just region) $
5094 D.reflow $
5095 "I ran into a an unexpected " ++ term ++ " in this pattern:"
5097 D.reflow $
5098 "This " ++ bracket : " does not match up with an earlier open " ++ term ++ ". Try deleting it?"
5101 _ ->
5102 let
5103 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5104 region = toRegion row col
5105 in
5106 Report.Report "UNFINISHED PARENTHESES" region [] $
5107 Code.toSnippet source surroundings (Just region) $
5109 D.reflow $
5110 "I was partway through parsing a pattern, but I got stuck here:"
5112 D.fillSep
5113 ["I","was","expecting","a","closing","parenthesis","next,","so"
5114 ,"try","adding","a",D.dullyellow ")","to","see","if","that","helps?"
5118 PTupleExpr pattern row col ->
5119 toPatternReport source context pattern row col
5121 PTupleSpace space row col ->
5122 toSpaceReport source space row col
5124 PTupleIndentEnd row col ->
5125 let
5126 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5127 region = toRegion row col
5128 in
5129 Report.Report "UNFINISHED PARENTHESES" region [] $
5130 Code.toSnippet source surroundings (Just region) $
5132 D.reflow $
5133 "I was expecting a closing parenthesis next:"
5135 D.stack
5136 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
5137 , D.toSimpleNote $
5138 "I can get confused by indentation in cases like this, so\
5139 \ maybe you have a closing parenthesis but it is not indented enough?"
5143 PTupleIndentExpr1 row col ->
5144 let
5145 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5146 region = toRegion row col
5147 in
5148 Report.Report "UNFINISHED PARENTHESES" region [] $
5149 Code.toSnippet source surroundings (Just region) $
5151 D.reflow $
5152 "I just saw an open parenthesis, but then I got stuck here:"
5154 D.fillSep
5155 ["I","was","expecting","to","see","a","pattern","next."
5156 ,"Maybe","it","will","end","up","being","something"
5157 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "?"
5161 PTupleIndentExprN row col ->
5162 let
5163 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5164 region = toRegion row col
5165 in
5166 Report.Report "UNFINISHED TUPLE PATTERN" region [] $
5167 Code.toSnippet source surroundings (Just region) $
5169 D.reflow $
5170 "I am partway through parsing a tuple pattern, but I got stuck here:"
5172 D.stack
5173 [ D.fillSep
5174 ["I","was","expecting","to","see","a","pattern","next."
5175 ,"I","am","expecting","the","final","result","to","be","something"
5176 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "."
5178 , D.toSimpleNote $
5179 "I can get confused by indentation in cases like this, so the problem\
5180 \ may be that the next part is not indented enough?"
5185toPListReport :: Code.Source -> PContext -> PList -> Row -> Col -> Report.Report
5186toPListReport source context list startRow startCol =
5187 case list of
5188 PListOpen row col ->
5189 case Code.whatIsNext source row col of
5190 Code.Keyword keyword ->
5191 let
5192 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5193 region = toKeywordRegion row col keyword
5194 in
5195 Report.Report "RESERVED WORD" region [] $
5196 Code.toSnippet source surroundings (Just region)
5198 D.reflow $
5199 "It looks like you are trying to use `" ++ keyword ++ "` to name an element of a list:"
5201 D.reflow $
5202 "This is a reserved word though! Try using some other name?"
5205 _ ->
5206 let
5207 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5208 region = toRegion row col
5209 in
5210 Report.Report "UNFINISHED LIST PATTERN" region [] $
5211 Code.toSnippet source surroundings (Just region) $
5213 D.reflow $
5214 "I just saw an open square bracket, but then I got stuck here:"
5216 D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
5219 PListEnd row col ->
5220 let
5221 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5222 region = toRegion row col
5223 in
5224 Report.Report "UNFINISHED LIST PATTERN" region [] $
5225 Code.toSnippet source surroundings (Just region) $
5227 D.reflow $
5228 "I was expecting a closing square bracket to end this list pattern:"
5230 D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
5233 PListExpr pattern row col ->
5234 toPatternReport source context pattern row col
5236 PListSpace space row col ->
5237 toSpaceReport source space row col
5239 PListIndentOpen row col ->
5240 let
5241 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5242 region = toRegion row col
5243 in
5244 Report.Report "UNFINISHED LIST PATTERN" region [] $
5245 Code.toSnippet source surroundings (Just region) $
5247 D.reflow $
5248 "I just saw an open square bracket, but then I got stuck here:"
5250 D.stack
5251 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
5252 , D.toSimpleNote $
5253 "I can get confused by indentation in cases like this, so\
5254 \ maybe there is something next, but it is not indented enough?"
5258 PListIndentEnd row col ->
5259 let
5260 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5261 region = toRegion row col
5262 in
5263 Report.Report "UNFINISHED LIST PATTERN" region [] $
5264 Code.toSnippet source surroundings (Just region) $
5266 D.reflow $
5267 "I was expecting a closing square bracket to end this list pattern:"
5269 D.stack
5270 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
5271 , D.toSimpleNote $
5272 "I can get confused by indentation in cases like this, so\
5273 \ maybe you have a closing square bracket but it is not indented enough?"
5277 PListIndentExpr row col ->
5278 let
5279 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5280 region = toRegion row col
5281 in
5282 Report.Report "UNFINISHED LIST PATTERN" region [] $
5283 Code.toSnippet source surroundings (Just region) $
5285 D.reflow $
5286 "I am partway through parsing a list pattern, but I got stuck here:"
5288 D.stack
5289 [ D.reflow $
5290 "I was expecting to see another pattern next. Maybe a variable name."
5291 , D.toSimpleNote $
5292 "I can get confused by indentation in cases like this, so\
5293 \ maybe there is more to this pattern but it is not indented enough?"
5299-- TYPES
5302data TContext
5303 = TC_Annotation Name.Name
5304 | TC_CustomType
5305 | TC_TypeAlias
5306 | TC_Port
5309toTypeReport :: Code.Source -> TContext -> Type -> Row -> Col -> Report.Report
5310toTypeReport source context tipe startRow startCol =
5311 case tipe of
5312 TRecord record row col ->
5313 toTRecordReport source context record row col
5315 TTuple tuple row col ->
5316 toTTupleReport source context tuple row col
5318 TStart row col ->
5319 case Code.whatIsNext source row col of
5320 Code.Keyword keyword ->
5321 let
5322 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5323 region = toKeywordRegion row col keyword
5324 in
5325 Report.Report "RESERVED WORD" region [] $
5326 Code.toSnippet source surroundings (Just region)
5328 D.reflow $
5329 "I was expecting to see a type next, but I got stuck on this reserved word:"
5331 D.reflow $
5332 "It looks like you are trying to use `" ++ keyword ++ "` as a type variable, but \
5333 \ it is a reserved word. Try using a different name!"
5336 _ ->
5337 let
5338 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5339 region = toRegion row col
5341 thing =
5342 case context of
5343 TC_Annotation _ -> "type annotation"
5344 TC_CustomType -> "custom type"
5345 TC_TypeAlias -> "type alias"
5346 TC_Port -> "port"
5348 something =
5349 case context of
5350 TC_Annotation name -> "the `" ++ Name.toChars name ++ "` type annotation"
5351 TC_CustomType -> "a custom type"
5352 TC_TypeAlias -> "a type alias"
5353 TC_Port -> "a port"
5354 in
5355 Report.Report ("PROBLEM IN " ++ map Char.toUpper thing) region [] $
5356 Code.toSnippet source surroundings (Just region)
5358 D.reflow $
5359 "I was partway through parsing " ++ something ++ ", but I got stuck here:"
5361 D.fillSep $
5362 ["I","was","expecting","to","see","a","type","next."
5363 ,"Try","putting",D.dullyellow "Int","or",D.dullyellow "String","for","now?"
5367 TSpace space row col ->
5368 toSpaceReport source space row col
5370 TIndentStart row col ->
5371 let
5372 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5373 region = toRegion row col
5375 thing =
5376 case context of
5377 TC_Annotation _ -> "type annotation"
5378 TC_CustomType -> "custom type"
5379 TC_TypeAlias -> "type alias"
5380 TC_Port -> "port"
5381 in
5382 Report.Report ("UNFINISHED " ++ map Char.toUpper thing) region [] $
5383 Code.toSnippet source surroundings (Just region)
5385 D.reflow $
5386 "I was partway through parsing a " ++ thing ++ ", but I got stuck here:"
5388 D.stack
5389 [ D.fillSep $
5390 ["I","was","expecting","to","see","a","type","next."
5391 ,"Try","putting",D.dullyellow "Int","or",D.dullyellow "String","for","now?"
5393 , D.toSimpleNote $
5394 "I can get confused by indentation. If you think there is already a type\
5395 \ next, maybe it is not indented enough?"
5400toTRecordReport :: Code.Source -> TContext -> TRecord -> Row -> Col -> Report.Report
5401toTRecordReport source context record startRow startCol =
5402 case record of
5403 TRecordOpen row col ->
5404 case Code.whatIsNext source row col of
5405 Code.Keyword keyword ->
5406 let
5407 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5408 region = toKeywordRegion row col keyword
5409 in
5410 Report.Report "RESERVED WORD" region [] $
5411 Code.toSnippet source surroundings (Just region)
5413 D.reflow $
5414 "I just started parsing a record type, but I got stuck on this field name:"
5416 D.reflow $
5417 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
5418 \ that is a reserved word. Try using a different name!"
5421 _ ->
5422 let
5423 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5424 region = toRegion row col
5425 in
5426 Report.Report "UNFINISHED RECORD TYPE" region [] $
5427 Code.toSnippet source surroundings (Just region)
5429 D.reflow $
5430 "I just started parsing a record type, but I got stuck here:"
5432 D.fillSep
5433 ["Record","types","look","like",D.dullyellow "{ name : String, age : Int },"
5434 ,"so","I","was","expecting","to","see","a","field","name","next."
5438 TRecordEnd row col ->
5439 let
5440 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5441 region = toRegion row col
5442 in
5443 Report.Report "UNFINISHED RECORD TYPE" region [] $
5444 Code.toSnippet source surroundings (Just region)
5446 D.reflow $
5447 "I am partway through parsing a record type, but I got stuck here:"
5449 D.stack
5450 [ D.fillSep
5451 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
5452 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
5454 , D.toSimpleNote $
5455 "When I get stuck like this, it usually means that there is a missing parenthesis\
5456 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
5460 TRecordField row col ->
5461 case Code.whatIsNext source row col of
5462 Code.Keyword keyword ->
5463 let
5464 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5465 region = toKeywordRegion row col keyword
5466 in
5467 Report.Report "RESERVED WORD" region [] $
5468 Code.toSnippet source surroundings (Just region)
5470 D.reflow $
5471 "I am partway through parsing a record type, but I got stuck on this field name:"
5473 D.reflow $
5474 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
5475 \ that is a reserved word. Try using a different name!"
5478 Code.Other (Just ',') ->
5479 let
5480 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5481 region = toRegion row col
5482 in
5483 Report.Report "EXTRA COMMA" region [] $
5484 Code.toSnippet source surroundings (Just region)
5486 D.reflow $
5487 "I am partway through parsing a record type, but I got stuck here:"
5489 D.stack
5490 [ D.reflow $
5491 "I am seeing two commas in a row. This is the second one!"
5492 , D.reflow $
5493 "Just delete one of the commas and you should be all set!"
5494 , noteForRecordTypeError
5498 Code.Close _ '}' ->
5499 let
5500 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5501 region = toRegion row col
5502 in
5503 Report.Report "EXTRA COMMA" region [] $
5504 Code.toSnippet source surroundings (Just region)
5506 D.reflow $
5507 "I am partway through parsing a record type, but I got stuck here:"
5509 D.stack
5510 [ D.reflow $
5511 "Trailing commas are not allowed in record types. Try deleting the comma that\
5512 \ appears before this closing curly brace."
5513 , noteForRecordTypeError
5517 _ ->
5518 let
5519 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5520 region = toRegion row col
5521 in
5522 Report.Report "PROBLEM IN RECORD TYPE" region [] $
5523 Code.toSnippet source surroundings (Just region)
5525 D.reflow $
5526 "I am partway through parsing a record type, but I got stuck here:"
5528 D.stack
5529 [ D.fillSep
5530 ["I","was","expecting","to","see","another","record","field","defined","next,"
5531 ,"so","I","am","looking","for","a","name","like"
5532 ,D.dullyellow "userName","or",D.dullyellow "plantHeight" <> "."
5534 , noteForRecordTypeError
5538 TRecordColon row col ->
5539 let
5540 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5541 region = toRegion row col
5542 in
5543 Report.Report "UNFINISHED RECORD TYPE" region [] $
5544 Code.toSnippet source surroundings (Just region)
5546 D.reflow $
5547 "I am partway through parsing a record type, but I got stuck here:"
5549 D.stack
5550 [ D.fillSep $
5551 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
5552 ,"a","colon","next.","So","try","putting","an",D.green ":","sign","here?"
5554 , noteForRecordTypeError
5558 TRecordType tipe row col ->
5559 toTypeReport source context tipe row col
5561 TRecordSpace space row col ->
5562 toSpaceReport source space row col
5564 TRecordIndentOpen row col ->
5565 let
5566 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5567 region = toRegion row col
5568 in
5569 Report.Report "UNFINISHED RECORD TYPE" region [] $
5570 Code.toSnippet source surroundings (Just region)
5572 D.reflow $
5573 "I just saw the opening curly brace of a record type, but then I got stuck here:"
5575 D.stack
5576 [ D.fillSep $
5577 ["I","am","expecting","a","record","like",D.dullyellow "{ name : String, age : Int }","here."
5578 ,"Try","defining","some","fields","of","your","own?"
5580 , noteForRecordTypeIndentError
5584 TRecordIndentEnd row col ->
5585 case Code.nextLineStartsWithCloseCurly source row of
5586 Just (curlyRow, curlyCol) ->
5587 let
5588 surroundings = A.Region (A.Position startRow startCol) (A.Position curlyRow curlyCol)
5589 region = toRegion curlyRow curlyCol
5590 in
5591 Report.Report "NEED MORE INDENTATION" region [] $
5592 Code.toSnippet source surroundings (Just region)
5594 D.reflow $
5595 "I was partway through parsing a record type, but I got stuck here:"
5597 D.stack
5598 [ D.reflow $
5599 "I need this curly brace to be indented more. Try adding some spaces before it!"
5600 , noteForRecordTypeError
5604 Nothing ->
5605 let
5606 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5607 region = toRegion row col
5608 in
5609 Report.Report "UNFINISHED RECORD TYPE" region [] $
5610 Code.toSnippet source surroundings (Just region)
5612 D.reflow $
5613 "I was partway through parsing a record type, but I got stuck here:"
5615 D.stack
5616 [ D.fillSep $
5617 ["I","was","expecting","to","see","a","closing","curly","brace","next."
5618 ,"Try","putting","a",D.green "}","next","and","see","if","that","helps?"
5620 , noteForRecordTypeIndentError
5624 TRecordIndentField row col ->
5625 let
5626 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5627 region = toRegion row col
5628 in
5629 Report.Report "UNFINISHED RECORD TYPE" region [] $
5630 Code.toSnippet source surroundings (Just region)
5632 D.reflow $
5633 "I am partway through parsing a record type, but I got stuck after that last comma:"
5635 D.stack
5636 [ D.reflow $
5637 "Trailing commas are not allowed in record types, so the fix may be to\
5638 \ delete that last comma? Or maybe you were in the middle of defining\
5639 \ an additional field?"
5640 , noteForRecordTypeIndentError
5644 TRecordIndentColon row col ->
5645 let
5646 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5647 region = toRegion row col
5648 in
5649 Report.Report "UNFINISHED RECORD TYPE" region [] $
5650 Code.toSnippet source surroundings (Just region)
5652 D.reflow $
5653 "I am partway through parsing a record type. I just saw a record\
5654 \ field, so I was expecting to see a colon next:"
5656 D.stack
5657 [ D.fillSep $
5658 ["Try","putting","an",D.green ":","followed","by","a","type?"
5660 , noteForRecordTypeIndentError
5664 TRecordIndentType row col ->
5665 let
5666 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5667 region = toRegion row col
5668 in
5669 Report.Report "UNFINISHED RECORD TYPE" region [] $
5670 Code.toSnippet source surroundings (Just region)
5672 D.reflow $
5673 "I am partway through parsing a record type, and I was expecting to run into a type next:"
5675 D.stack
5676 [ D.fillSep $
5677 ["Try","putting","something","like"
5678 ,D.dullyellow "Int","or",D.dullyellow "String","for","now?"
5680 , noteForRecordTypeIndentError
5685noteForRecordTypeError :: D.Doc
5686noteForRecordTypeError =
5687 D.stack $
5688 [ D.toSimpleNote
5689 "If you are trying to define a record type across multiple lines, I recommend using this format:"
5690 , D.indent 4 $ D.vcat $
5691 [ "{ name : String"
5692 , ", age : Int"
5693 , ", height : Float"
5694 , "}"
5696 , D.reflow $
5697 "Notice that each line starts with some indentation. Usually two or four spaces.\
5698 \ This is the stylistic convention in the Elm ecosystem."
5702noteForRecordTypeIndentError :: D.Doc
5703noteForRecordTypeIndentError =
5704 D.stack $
5705 [ D.toSimpleNote
5706 "I may be confused by indentation. For example, if you are trying to define\
5707 \ a record type across multiple lines, I recommend using this format:"
5708 , D.indent 4 $ D.vcat $
5709 [ "{ name : String"
5710 , ", age : Int"
5711 , ", height : Float"
5712 , "}"
5714 , D.reflow $
5715 "Notice that each line starts with some indentation. Usually two or four spaces.\
5716 \ This is the stylistic convention in the Elm ecosystem."
5720toTTupleReport :: Code.Source -> TContext -> TTuple -> Row -> Col -> Report.Report
5721toTTupleReport source context tuple startRow startCol =
5722 case tuple of
5723 TTupleOpen row col ->
5724 case Code.whatIsNext source row col of
5725 Code.Keyword keyword ->
5726 let
5727 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5728 region = toKeywordRegion row col keyword
5729 in
5730 Report.Report "RESERVED WORD" region [] $
5731 Code.toSnippet source surroundings (Just region)
5733 D.reflow $
5734 "I ran into a reserved word unexpectedly:"
5736 D.reflow $
5737 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name, but \
5738 \ it is a reserved word. Try using a different name!"
5741 _ ->
5742 let
5743 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5744 region = toRegion row col
5745 in
5746 Report.Report "UNFINISHED PARENTHESES" region [] $
5747 Code.toSnippet source surroundings (Just region)
5749 D.reflow $
5750 "I just saw an open parenthesis, so I was expecting to see a type next."
5752 D.fillSep $
5753 ["Something","like",D.dullyellow "(Maybe Int)","or"
5754 ,D.dullyellow "(List Person)" <> "."
5755 ,"Anything","where","you","are","putting","parentheses","around","normal","types."
5759 TTupleEnd row col ->
5760 let
5761 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5762 region = toRegion row col
5763 in
5764 Report.Report "UNFINISHED PARENTHESES" region [] $
5765 Code.toSnippet source surroundings (Just region)
5767 D.reflow $
5768 "I was expecting to see a closing parenthesis next, but I got stuck here:"
5770 D.stack
5771 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
5772 , D.toSimpleNote $
5773 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
5774 \ unexpectedly. So there may be some earlier syntax trouble (like extra parenthesis\
5775 \ or missing brackets) that is confusing me."
5779 TTupleType tipe row col ->
5780 toTypeReport source context tipe row col
5782 TTupleSpace space row col ->
5783 toSpaceReport source space row col
5785 TTupleIndentType1 row col ->
5786 let
5787 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5788 region = toRegion row col
5789 in
5790 Report.Report "UNFINISHED PARENTHESES" region [] $
5791 Code.toSnippet source surroundings (Just region)
5793 D.reflow $
5794 "I just saw an open parenthesis, so I was expecting to see a type next."
5796 D.stack
5797 [ D.fillSep $
5798 ["Something","like",D.dullyellow "(Maybe Int)","or"
5799 ,D.dullyellow "(List Person)" <> "."
5800 ,"Anything","where","you","are","putting","parentheses","around","normal","types."
5802 , D.toSimpleNote $
5803 "I can get confused by indentation in cases like this, so\
5804 \ maybe you have a type but it is not indented enough?"
5808 TTupleIndentTypeN row col ->
5809 let
5810 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5811 region = toRegion row col
5812 in
5813 Report.Report "UNFINISHED TUPLE TYPE" region [] $
5814 Code.toSnippet source surroundings (Just region)
5816 D.reflow $
5817 "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."
5819 D.stack
5820 [ D.fillSep $
5821 ["A","tuple","type","looks","like",D.dullyellow "(Float,Float)","or"
5822 ,D.dullyellow "(String,Int)" <> ","
5823 ,"so","I","think","there","is","a","type","missing","here?"
5825 , D.toSimpleNote $
5826 "I can get confused by indentation in cases like this, so\
5827 \ maybe you have an expression but it is not indented enough?"
5831 TTupleIndentEnd row col ->
5832 let
5833 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5834 region = toRegion row col
5835 in
5836 Report.Report "UNFINISHED PARENTHESES" region [] $
5837 Code.toSnippet source surroundings (Just region)
5839 D.reflow $
5840 "I was expecting to see a closing parenthesis next:"
5842 D.stack
5843 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
5844 , D.toSimpleNote $
5845 "I can get confused by indentation in cases like this, so\
5846 \ maybe you have a closing parenthesis but it is not indented enough?"