on c8e3b8a help sign in
5823 lines 212 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 case Code.whatIsNext source row col of
653 Code.Keyword keyword ->
654 let
655 region = toKeywordRegion row col keyword
656 in
657 Report.Report "RESERVED WORD" region [] $
658 Code.toSnippet source region Nothing
659 (
660 D.reflow $
661 "I got stuck on this reserved word:"
662 ,
663 D.reflow $
664 "The name `" ++ keyword ++ "` is reserved, so try using a different name?"
665 )
667 Code.Operator op ->
668 let
669 region = toKeywordRegion row col op
670 in
671 Report.Report "UNEXPECTED SYMBOL" region [] $
672 Code.toSnippet source region Nothing
673 (
674 D.reflow $
675 "I ran into an unexpected symbol:"
676 ,
677 D.reflow $
678 "I was not expecting to see a " ++ op ++ " here. Try deleting it? Maybe\
679 \ I can give a better hint from there?"
680 )
682 Code.Close term bracket ->
683 let
684 region = toRegion row col
685 in
686 Report.Report ("UNEXPECTED " ++ map Char.toUpper term) region [] $
687 Code.toSnippet source region Nothing
688 (
689 D.reflow $
690 "I ran into an unexpected " ++ term ++ ":"
691 ,
692 D.reflow $
693 "This " ++ bracket : " does not match up with an earlier open " ++ term ++ ". Try deleting it?"
694 )
696 Code.Lower c cs ->
697 let
698 region = toKeywordRegion row col (c:cs)
699 in
700 Report.Report "UNEXPECTED NAME" region [] $
701 Code.toSnippet source region Nothing
702 (
703 D.reflow $
704 "I got stuck on this name:"
705 ,
706 D.reflow $
707 "It is confusing me a lot! Normally I can give fairly specific hints, but\
708 \ something is really tripping me up this time."
709 )
711 Code.Upper c cs ->
712 let
713 region = toKeywordRegion row col (c:cs)
714 in
715 Report.Report "UNEXPECTED NAME" region [] $
716 Code.toSnippet source region Nothing
717 (
718 D.reflow $
719 "I got stuck on this name:"
720 ,
721 D.reflow $
722 "It is confusing me a lot! Normally I can give fairly specific hints, but\
723 \ something is really tripping me up this time."
724 )
726 Code.Other maybeChar ->
727 let
728 region = toRegion row col
729 in
730 case maybeChar of
731 Just ';' ->
732 Report.Report "UNEXPECTED SEMICOLON" region [] $
733 Code.toSnippet source region Nothing
734 (
735 D.reflow $
736 "I got stuck on this semicolon:"
737 ,
738 D.stack
739 [ D.reflow $ "Try removing it?"
740 , D.toSimpleNote $
741 "Some languages require semicolons at the end of each statement. These are\
742 \ often called C-like languages, and they usually share a lot of language design\
743 \ choices. (E.g. side-effects, for loops, etc.) Elm manages effects with commands\
744 \ and subscriptions instead, so there is no special syntax for \"statements\" and\
745 \ therefore no need to use semicolons to separate them. I think this will make\
746 \ more sense as you work through <https://guide.elm-lang.org> though!"
747 ]
748 )
750 Just ',' ->
751 Report.Report "UNEXPECTED COMMA" region [] $
752 Code.toSnippet source region Nothing
753 (
754 D.reflow $
755 "I got stuck on this comma:"
756 ,
757 D.stack
758 [ D.reflow $
759 "I do not think I am parsing a list or tuple right now. Try deleting the comma?"
760 , D.toSimpleNote $
761 "If this is supposed to be part of a list, the problem may be a bit earlier.\
762 \ Perhaps the opening [ is missing? Or perhaps some value in the list has an extra\
763 \ closing ] that is making me think the list ended earlier? The same kinds of\
764 \ things could be going wrong if this is supposed to be a tuple."
765 ]
766 )
768 Just '`' ->
769 Report.Report "UNEXPECTED CHARACTER" region [] $
770 Code.toSnippet source region Nothing
771 (
772 D.reflow $
773 "I got stuck on this character:"
774 ,
775 D.stack
776 [ D.reflow $
777 "It is not used for anything in Elm syntax. It is used for multi-line strings in\
778 \ some languages though, so if you want a string that spans multiple lines, you\
779 \ can use Elm's multi-line string syntax like this:"
780 , D.dullyellow $ D.indent 4 $ D.vcat $
781 [ "\"\"\""
782 , "# Multi-line Strings"
783 , ""
784 , "- start with triple double quotes"
785 , "- write whatever you want"
786 , "- no need to escape newlines or double quotes"
787 , "- end with triple double quotes"
788 , "\"\"\""
789 ]
790 , D.reflow $
791 "Otherwise I do not know what is going on! Try removing the character?"
792 ]
793 )
795 Just '$' ->
796 Report.Report "UNEXPECTED SYMBOL" region [] $
797 Code.toSnippet source region Nothing
798 (
799 D.reflow $
800 "I got stuck on this dollar sign:"
801 ,
802 D.reflow $
803 "It is not used for anything in Elm syntax. Are you coming from a language where\
804 \ dollar signs can be used in variable names? If so, try a name that (1) starts\
805 \ with a letter and (2) only contains letters, numbers, and underscores."
806 )
808 Just c | elem c ['#','@','!','%','~'] ->
809 Report.Report "UNEXPECTED SYMBOL" region [] $
810 Code.toSnippet source region Nothing
811 (
812 D.reflow $
813 "I got stuck on this symbol:"
814 ,
815 D.reflow $
816 "It is not used for anything in Elm syntax. Try removing it?"
817 )
819 _ ->
820 Report.Report "SYNTAX PROBLEM" region [] $
821 Code.toSnippet source region Nothing
822 (
823 D.reflow $
824 "I got stuck here:"
825 ,
826 D.reflow $
827 "Whatever I am running into is confusing me a lot! Normally I can give fairly\
828 \ specific hints, but something is really tripping me up this time."
829 )
831 ModuleProblem row col ->
832 let
833 region = toRegion row col
834 in
835 Report.Report "UNFINISHED MODULE DECLARATION" region [] $
836 Code.toSnippet source region Nothing
837 (
838 D.reflow $
839 "I am parsing an `module` declaration, but I got stuck here:"
840 ,
841 D.stack
842 [ D.reflow $
843 "Here are some examples of valid `module` declarations:"
844 , D.indent 4 $ D.vcat $
845 [ D.fillSep [D.cyan "module","Main",D.cyan "exposing","(..)"]
846 , D.fillSep [D.cyan "module","Dict",D.cyan "exposing","(Dict, empty, get)"]
847 ]
848 , D.reflow $
849 "I generally recommend using an explicit exposing list. I can skip compiling a bunch\
850 \ of files when the public interface of a module stays the same, so exposing fewer\
851 \ values can help improve compile times!"
852 ]
853 )
855 ModuleName row col ->
856 let
857 region = toRegion row col
858 in
859 Report.Report "EXPECTING MODULE NAME" region [] $
860 Code.toSnippet source region Nothing
861 (
862 D.reflow $
863 "I was parsing an `module` declaration until I got stuck here:"
864 ,
865 D.stack
866 [ D.reflow $
867 "I was expecting to see the module name next, like in these examples:"
868 , D.indent 4 $ D.vcat $
869 [ D.fillSep [D.cyan "module","Dict",D.cyan "exposing","(..)"]
870 , D.fillSep [D.cyan "module","Maybe",D.cyan "exposing","(..)"]
871 , D.fillSep [D.cyan "module","Html.Attributes",D.cyan "exposing","(..)"]
872 , D.fillSep [D.cyan "module","Json.Decode",D.cyan "exposing","(..)"]
873 ]
874 , D.reflow $
875 "Notice that the module names all start with capital letters. That is required!"
876 ]
877 )
879 ModuleExposing exposing row col ->
880 toExposingReport source exposing row col
882 PortModuleProblem row col ->
883 let
884 region = toRegion row col
885 in
886 Report.Report "UNFINISHED PORT MODULE DECLARATION" region [] $
887 Code.toSnippet source region Nothing
888 (
889 D.reflow $
890 "I am parsing an `port module` declaration, but I got stuck here:"
891 ,
892 D.stack
893 [ D.reflow $
894 "Here are some examples of valid `port module` declarations:"
895 , D.indent 4 $ D.vcat $
896 [ D.fillSep [D.cyan "port",D.cyan "module","WebSockets",D.cyan "exposing","(send, listen, keepAlive)"]
897 , D.fillSep [D.cyan "port",D.cyan "module","Maps",D.cyan "exposing","(Location, goto)"]
898 ]
899 , D.link "Note" "Read" "ports" "for more help."
900 ]
901 )
903 PortModuleName row col ->
904 let
905 region = toRegion row col
906 in
907 Report.Report "EXPECTING MODULE NAME" region [] $
908 Code.toSnippet source region Nothing
909 (
910 D.reflow $
911 "I was parsing an `module` declaration until I got stuck here:"
912 ,
913 D.stack
914 [ D.reflow $
915 "I was expecting to see the module name next, like in these examples:"
916 , D.indent 4 $ D.vcat $
917 [ D.fillSep [D.cyan "port",D.cyan "module","WebSockets",D.cyan "exposing","(send, listen, keepAlive)"]
918 , D.fillSep [D.cyan "port",D.cyan "module","Maps",D.cyan "exposing","(Location, goto)"]
919 ]
920 , D.reflow $
921 "Notice that the module names start with capital letters. That is required!"
922 ]
923 )
925 PortModuleExposing exposing row col ->
926 toExposingReport source exposing row col
928 Effect row col ->
929 let
930 region = toRegion row col
931 in
932 Report.Report "BAD MODULE DECLARATION" region [] $
933 Code.toSnippet source region Nothing
934 (
935 D.reflow $
936 "I cannot parse this module declaration:"
937 ,
938 D.reflow $
939 "This type of module is reserved for the @elm organization. It is used to\
940 \ define certain effects, avoiding building them into the compiler."
941 )
943 FreshLine row col ->
944 let
945 region = toRegion row col
947 toBadFirstLineReport keyword =
948 Report.Report "TOO MUCH INDENTATION" region [] $
949 Code.toSnippet source region Nothing
950 (
951 D.reflow $
952 "This `" ++ keyword ++ "` should not have any spaces before it:"
953 ,
954 D.reflow $
955 "Delete the spaces before `" ++ keyword ++ "` until there are none left!"
956 )
958 in
959 case Code.whatIsNext source row col of
960 Code.Keyword "module" -> toBadFirstLineReport "module"
961 Code.Keyword "import" -> toBadFirstLineReport "import"
962 Code.Keyword "type" -> toBadFirstLineReport "type"
963 Code.Keyword "port" -> toBadFirstLineReport "port"
964 _ ->
965 Report.Report "SYNTAX PROBLEM" region [] $
966 Code.toSnippet source region Nothing
967 (
968 D.reflow $
969 "I got stuck here:"
970 ,
971 D.stack
972 [ D.reflow $
973 "I am not sure what is going on, but I recommend starting an Elm\
974 \ file with the following lines:"
975 , D.indent 4 $ D.vcat $
976 [ D.fillSep [D.cyan "import","Html"]
977 , ""
978 , "main ="
979 , " Html.text " <> D.dullyellow "\"Hello!\""
980 ]
981 , D.reflow $
982 "You should be able to copy those lines directly into your file. Check out the\
983 \ examples at <https://elm-lang.org/examples> for more help getting started!"
984 , D.toSimpleNote $
985 "This can also happen when something is indented too much!"
986 ]
987 )
989 ImportStart row col ->
990 toImportReport source row col
992 ImportName row col ->
993 let
994 region = toRegion row col
995 in
996 Report.Report "EXPECTING IMPORT NAME" region [] $
997 Code.toSnippet source region Nothing
998 (
999 D.reflow $
1000 "I was parsing an `import` until I got stuck here:"
1002 D.stack
1003 [ D.reflow $
1004 "I was expecting to see a module name next, like in these examples:"
1005 , D.indent 4 $ D.vcat $
1006 [ D.fillSep [D.cyan "import","Dict"]
1007 , D.fillSep [D.cyan "import","Maybe"]
1008 , D.fillSep [D.cyan "import","Html.Attributes",D.cyan "as","A"]
1009 , D.fillSep [D.cyan "import","Json.Decode",D.cyan "exposing","(..)"]
1011 , D.reflow $
1012 "Notice that the module names all start with capital letters. That is required!"
1016 ImportAs row col ->
1017 toImportReport source row col
1019 ImportAlias row col ->
1020 let
1021 region = toRegion row col
1022 in
1023 Report.Report "EXPECTING IMPORT ALIAS" region [] $
1024 Code.toSnippet source region Nothing
1026 D.reflow $
1027 "I was parsing an `import` until I got stuck here:"
1029 D.stack
1030 [ D.reflow $
1031 "I was expecting to see an alias next, like in these examples:"
1032 , D.indent 4 $ D.vcat $
1033 [ D.fillSep [D.cyan "import","Html.Attributes",D.cyan "as","Attr"]
1034 , D.fillSep [D.cyan "import","WebGL.Texture",D.cyan "as","Texture"]
1035 , D.fillSep [D.cyan "import","Json.Decode",D.cyan "as","D"]
1037 , D.reflow $
1038 "Notice that the alias always starts with a capital letter. That is required!"
1042 ImportExposing row col ->
1043 toImportReport source row col
1045 ImportExposingList exposing row col ->
1046 toExposingReport source exposing row col
1048 ImportEnd row col ->
1049 toImportReport source row col
1051 ImportIndentName row col ->
1052 toImportReport source row col
1054 ImportIndentAlias row col ->
1055 toImportReport source row col
1057 ImportIndentExposingList row col ->
1058 let
1059 region = toRegion row col
1060 in
1061 Report.Report "UNFINISHED IMPORT" region [] $
1062 Code.toSnippet source region Nothing
1064 D.reflow $
1065 "I was parsing an `import` until I got stuck here:"
1067 D.stack
1068 [ D.reflow $
1069 "I was expecting to see the list of exposed values next. For example, here\
1070 \ are two ways to expose values from the `Html` module:"
1071 , D.indent 4 $ D.vcat $
1072 [ D.fillSep [D.cyan "import","Html",D.cyan "exposing","(..)"]
1073 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
1075 , D.reflow $
1076 "I generally recommend the second style. It is more explicit, making it\
1077 \ much easier to figure out where values are coming from in large projects!"
1081 Infix row col ->
1082 let
1083 region = toRegion row col
1084 in
1085 Report.Report "BAD INFIX" region [] $
1086 Code.toSnippet source region Nothing
1088 D.reflow $
1089 "Something went wrong in this infix operator declaration:"
1091 D.reflow $
1092 "This feature is used by the @elm organization to define the\
1093 \ languages built-in operators."
1096 Declarations decl _ _ ->
1097 toDeclarationsReport source decl
1101-- IMPORTS
1104toImportReport :: Code.Source -> Row -> Col -> Report.Report
1105toImportReport source row col =
1106 let
1107 region = toRegion row col
1108 in
1109 Report.Report "UNFINISHED IMPORT" region [] $
1110 Code.toSnippet source region Nothing
1112 D.reflow $
1113 "I am partway through parsing an import, but I got stuck here:"
1115 D.stack
1116 [ D.reflow $
1117 "Here are some examples of valid `import` declarations:"
1118 , D.indent 4 $ D.vcat $
1119 [ D.fillSep [D.cyan "import","Html"]
1120 , D.fillSep [D.cyan "import","Html",D.cyan "as","H"]
1121 , D.fillSep [D.cyan "import","Html",D.cyan "as","H",D.cyan "exposing","(..)"]
1122 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
1124 , D.reflow $
1125 "You are probably trying to import a different module, but try to make it look like one of these examples!"
1131-- EXPOSING
1134toExposingReport :: Code.Source -> Exposing -> Row -> Col -> Report.Report
1135toExposingReport source exposing startRow startCol =
1136 case exposing of
1137 ExposingSpace space row col ->
1138 toSpaceReport source space row col
1140 ExposingStart row col ->
1141 let
1142 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1143 region = toRegion row col
1144 in
1145 Report.Report "PROBLEM IN EXPOSING" region [] $
1146 Code.toSnippet source surroundings (Just region)
1148 D.reflow $
1149 "I want to parse exposed values, but I am getting stuck here:"
1151 D.stack
1152 [ D.fillSep $
1153 ["Exposed","values","are","always","surrounded","by","parentheses."
1154 ,"So","try","adding","a",D.green "(","here?"
1156 , D.toSimpleNote "Here are some valid examples of `exposing` for reference:"
1157 , D.indent 4 $ D.vcat $
1158 [ D.fillSep [D.cyan "import","Html",D.cyan "exposing","(..)"]
1159 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
1161 , D.reflow $
1162 "If you are getting tripped up, you can just expose everything for now. It should\
1163 \ get easier to make an explicit exposing list as you see more examples in the wild."
1167 ExposingValue row col ->
1168 case Code.whatIsNext source row col of
1169 Code.Keyword keyword ->
1170 let
1171 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1172 region = toKeywordRegion row col keyword
1173 in
1174 Report.Report "RESERVED WORD" region [] $
1175 Code.toSnippet source surroundings (Just region)
1177 D.reflow $
1178 "I got stuck on this reserved word:"
1180 D.reflow $
1181 "It looks like you are trying to expose `" ++ keyword ++ "` but that is a reserved word. Is there a typo?"
1184 Code.Operator op ->
1185 let
1186 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1187 region = toKeywordRegion row col op
1188 in
1189 Report.Report "UNEXPECTED SYMBOL" region [] $
1190 Code.toSnippet source surroundings (Just region)
1192 D.reflow $
1193 "I got stuck on this symbol:"
1195 D.stack
1196 [ D.reflow $
1197 "If you are trying to expose an operator, add parentheses around it like this:"
1198 , D.indent 4 $ D.dullyellow (D.fromChars op) <> " -> " <> D.green ("(" <> D.fromChars op <> ")")
1202 _ ->
1203 let
1204 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1205 region = toRegion row col
1206 in
1207 Report.Report "PROBLEM IN EXPOSING" region [] $
1208 Code.toSnippet source surroundings (Just region)
1210 D.reflow $
1211 "I got stuck while parsing these exposed values:"
1213 D.stack
1214 [ D.reflow $
1215 "I do not have an exact recommendation, so here are some valid examples\
1216 \ of `exposing` for reference:"
1217 , D.indent 4 $ D.vcat $
1218 [ D.fillSep [D.cyan "import","Html",D.cyan "exposing","(..)"]
1219 , D.fillSep [D.cyan "import","Basics",D.cyan "exposing","(Int, Float, Bool(..), (+), not, sqrt)"]
1221 , D.reflow $
1222 "These examples show how to expose types, variants, operators, and functions. Everything\
1223 \ should be some permutation of these examples, just with different names."
1227 ExposingOperator row col ->
1228 let
1229 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1230 region = toRegion row col
1231 in
1232 Report.Report "PROBLEM IN EXPOSING" region [] $
1233 Code.toSnippet source surroundings (Just region)
1235 D.reflow $
1236 "I just saw an open parenthesis, so I was expecting an operator next:"
1238 D.fillSep $
1239 ["It","is","possible","to","expose","operators,","so","I","was","expecting"
1240 ,"to","see","something","like",D.dullyellow "(+)","or",D.dullyellow "(|=)"
1241 ,"or",D.dullyellow "(||)","after","I","saw","that","open","parenthesis."
1245 ExposingOperatorReserved op row col ->
1246 let
1247 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1248 region = toRegion row col
1249 in
1250 Report.Report "RESERVED SYMBOL" region [] $
1251 Code.toSnippet source surroundings (Just region)
1253 D.reflow $
1254 "I cannot expose this as an operator:"
1256 case op of
1257 BadDot -> D.reflow "Try getting rid of this entry? Maybe I can give you a better hint after that?"
1258 BadPipe -> D.fillSep ["Maybe","you","want",D.dullyellow "(||)","instead?"]
1259 BadArrow -> D.reflow "Try getting rid of this entry? Maybe I can give you a better hint after that?"
1260 BadEquals -> D.fillSep ["Maybe","you","want",D.dullyellow "(==)","instead?"]
1261 BadHasType -> D.fillSep ["Maybe","you","want",D.dullyellow "(::)","instead?"]
1264 ExposingOperatorRightParen row col ->
1265 let
1266 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1267 region = toRegion row col
1268 in
1269 Report.Report "PROBLEM IN EXPOSING" region [] $
1270 Code.toSnippet source surroundings (Just region)
1272 D.reflow $
1273 "It looks like you are exposing an operator, but I got stuck here:"
1275 D.fillSep $
1276 ["I","was","expecting","to","see","the","closing","parenthesis","immediately"
1277 ,"after","the","operator.","Try","adding","a",D.green ")","right","here?"
1281 ExposingEnd row col ->
1282 let
1283 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1284 region = toRegion row col
1285 in
1286 Report.Report "UNFINISHED EXPOSING" region [] $
1287 Code.toSnippet source surroundings (Just region)
1289 D.reflow $
1290 "I was partway through parsing exposed values, but I got stuck here:"
1292 D.reflow $
1293 "Maybe there is a comma missing before this?"
1296 ExposingTypePrivacy row col ->
1297 let
1298 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1299 region = toRegion row col
1300 in
1301 Report.Report "PROBLEM EXPOSING CUSTOM TYPE VARIANTS" region [] $
1302 Code.toSnippet source surroundings (Just region)
1304 D.reflow $
1305 "It looks like you are trying to expose the variants of a custom type:"
1307 D.stack
1308 [ D.fillSep $
1309 ["You","need","to","write","something","like"
1310 ,D.dullyellow "Status(..)","or",D.dullyellow "Entity(..)"
1311 ,"though.","It","is","all","or","nothing,","otherwise","`case`"
1312 ,"expressions","could","miss","a","variant","and","crash!"
1314 , D.toSimpleNote $
1315 "It is often best to keep the variants hidden! If someone pattern matches on\
1316 \ the variants, it is a MAJOR change if any new variants are added. Suddenly\
1317 \ their `case` expressions do not cover all variants! So if you do not need\
1318 \ people to pattern match, keep the variants hidden and expose functions to\
1319 \ construct values of this type. This way you can add new variants as a MINOR change!"
1323 ExposingIndentEnd row col ->
1324 let
1325 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1326 region = toRegion row col
1327 in
1328 Report.Report "UNFINISHED EXPOSING" region [] $
1329 Code.toSnippet source surroundings (Just region)
1331 D.reflow $
1332 "I was partway through parsing exposed values, but I got stuck here:"
1334 D.stack
1335 [ D.fillSep $
1336 ["I","was","expecting","a","closing","parenthesis."
1337 ,"Try","adding","a",D.green ")","right","here?"
1339 , D.toSimpleNote $
1340 "I can get confused when there is not enough indentation, so if you already\
1341 \ have a closing parenthesis, it probably just needs some spaces in front of it."
1345 ExposingIndentValue row col ->
1346 let
1347 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1348 region = toRegion row col
1349 in
1350 Report.Report "UNFINISHED EXPOSING" region [] $
1351 Code.toSnippet source surroundings (Just region)
1353 D.reflow $
1354 "I was partway through parsing exposed values, but I got stuck here:"
1356 D.reflow $
1357 "I was expecting another value to expose."
1362-- SPACES
1365toSpaceReport :: Code.Source -> Space -> Row -> Col -> Report.Report
1366toSpaceReport source space row col =
1367 case space of
1368 HasTab ->
1369 let
1370 region = toRegion row col
1371 in
1372 Report.Report "NO TABS" region [] $
1373 Code.toSnippet source region Nothing
1375 D.reflow $
1376 "I ran into a tab, but tabs are not allowed in Elm files."
1378 D.reflow $
1379 "Replace the tab with spaces."
1382 EndlessMultiComment ->
1383 let
1384 region = toWiderRegion row col 2
1385 in
1386 Report.Report "ENDLESS COMMENT" region [] $
1387 Code.toSnippet source region Nothing
1389 D.reflow $
1390 "I cannot find the end of this multi-line comment:"
1392 D.stack -- "{-"
1393 [ D.reflow "Add a -} somewhere after this to end the comment."
1394 , D.toSimpleHint
1395 "Multi-line comments can be nested in Elm, so {- {- -} -} is a comment\
1396 \ that happens to contain another comment. Like parentheses and curly braces,\
1397 \ the start and end markers must always be balanced. Maybe that is the problem?"
1403-- DECLARATIONS
1406toRegion :: Row -> Col -> A.Region
1407toRegion row col =
1408 let
1409 pos = A.Position row col
1410 in
1411 A.Region pos pos
1414toWiderRegion :: Row -> Col -> Word16 -> A.Region
1415toWiderRegion row col extra =
1416 A.Region
1417 (A.Position row col)
1418 (A.Position row (col + extra))
1421toKeywordRegion :: Row -> Col -> [Char.Char] -> A.Region
1422toKeywordRegion row col keyword =
1423 A.Region
1424 (A.Position row col)
1425 (A.Position row (col + fromIntegral (length keyword)))
1428toDeclarationsReport :: Code.Source -> Decl -> Report.Report
1429toDeclarationsReport source decl =
1430 case decl of
1431 DeclStart row col ->
1432 case Code.whatIsNext source row col of
1433 Code.Close term bracket ->
1434 let
1435 region = toRegion row col
1436 in
1437 Report.Report ("STRAY " ++ map Char.toUpper term) region [] $
1438 Code.toSnippet source region Nothing
1440 D.reflow $
1441 "I was not expecting to see a " ++ term ++ " here:"
1442 , D.reflow $
1443 "This " ++ bracket : " does not match up with an earlier open " ++ term ++ ". Try deleting it?"
1446 Code.Keyword keyword ->
1447 let
1448 region = toKeywordRegion row col keyword
1449 in
1450 Report.Report "RESERVED WORD" region [] $
1451 Code.toSnippet source region Nothing
1453 D.reflow $
1454 "I was not expecting to run into the `" ++ keyword ++ "` keyword here:"
1456 case keyword of
1457 "import" ->
1458 D.reflow $
1459 "It is reserved for declaring imports at the top of your module. If you want\
1460 \ another import, try moving it up top with the other imports. If you want to\
1461 \ define a value or function, try changing the name to something else!"
1463 "case" ->
1464 D.stack
1465 [ D.reflow $
1466 "It is reserved for writing `case` expressions. Try using a different name?"
1467 , D.toSimpleNote $
1468 "If you are trying to write a `case` expression, it needs to be part of a\
1469 \ definition. So you could write something like this instead:"
1470 , D.indent 4 $ D.vcat $
1471 [ D.indent 0 $ D.fillSep ["getWidth","maybeWidth","="]
1472 , D.indent 2 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
1473 , D.indent 4 $ D.fillSep [D.blue "Just","width","->"]
1474 , D.indent 6 $ D.fillSep ["width","+",D.dullyellow "200"]
1475 , ""
1476 , D.indent 4 $ D.fillSep [D.blue "Nothing","->"]
1477 , D.indent 6 $ D.fillSep [D.dullyellow "400"]
1479 , D.reflow $
1480 "This defines a `getWidth` function that you can use elsewhere in your program."
1483 "if" ->
1484 D.stack
1485 [ D.reflow $
1486 "It is reserved for writing `if` expressions. Try using a different name?"
1487 , D.toSimpleNote $
1488 "If you are trying to write an `if` expression, it needs to be part of a\
1489 \ definition. So you could write something like this instead:"
1490 , D.indent 4 $ D.vcat $
1491 [ "greet name ="
1492 , D.fillSep $
1493 [" "
1494 ,D.cyan "if","name","==",D.dullyellow "\"Abraham Lincoln\""
1495 ,D.cyan "then",D.dullyellow "\"Greetings Mr. President.\""
1496 ,D.cyan "else",D.dullyellow "\"Hey!\""
1499 , D.reflow $
1500 "This defines a `reviewPowerLevel` function that you can use elsewhere in your program."
1503 _ ->
1504 D.reflow $
1505 "It is a reserved word. Try changing the name to something else?"
1508 Code.Upper c cs ->
1509 let
1510 region = toRegion row col
1511 in
1512 Report.Report "UNEXPECTED CAPITAL LETTER" region [] $
1513 Code.toSnippet source region Nothing
1515 D.reflow $
1516 "Declarations always start with a lower-case letter, so I am getting stuck here:"
1518 D.stack
1519 [ D.fillSep $
1520 ["Try","a","name","like"
1521 ,D.green (D.fromChars (Char.toLower c : cs))
1522 ,"instead?"
1524 , D.toSimpleNote $
1525 "Here are a couple valid declarations for reference:"
1526 , D.indent 4 $ D.vcat $
1527 [ "greet : String -> String"
1528 , "greet name ="
1529 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
1530 , ""
1531 , D.cyan "type" <> " User = Anonymous | LoggedIn String"
1533 , D.reflow $
1534 "Notice that they always start with a lower-case letter. Capitalization matters!"
1538 Code.Other (Just char) | elem char ['(', '{', '[', '+', '-', '*', '/', '^', '&', '|', '"', '\'', '!', '@', '#', '$', '%'] ->
1539 let
1540 region = toRegion row col
1541 in
1542 Report.Report "UNEXPECTED SYMBOL" region [] $
1543 Code.toSnippet source region Nothing
1545 D.reflow $
1546 "I am getting stuck because this line starts with the " ++ [char] ++ " symbol:"
1548 D.stack
1549 [ D.reflow $
1550 "When a line has no spaces at the beginning, I expect it to be a declaration like one of these:"
1551 , D.indent 4 $ D.vcat $
1552 [ "greet : String -> String"
1553 , "greet name ="
1554 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
1555 , ""
1556 , D.cyan "type" <> " User = Anonymous | LoggedIn String"
1558 , D.reflow $
1559 "If this is not supposed to be a declaration, try adding some spaces before it?"
1563 _ ->
1564 let
1565 region = toRegion row col
1566 in
1567 Report.Report "WEIRD DECLARATION" region [] $
1568 Code.toSnippet source region Nothing
1570 D.reflow $
1571 "I am trying to parse a declaration, but I am getting stuck here:"
1573 D.stack
1574 [ D.reflow $
1575 "I am not sure what is going wrong, so here are a couple valid declarations for reference:"
1576 , D.indent 4 $ D.vcat $
1577 [ "greet : String -> String"
1578 , "greet name ="
1579 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
1580 , ""
1581 , D.cyan "type" <> " User = Anonymous | LoggedIn String"
1583 , D.reflow $
1584 "Try to make your declaration look like one of those?"
1588 DeclSpace space row col ->
1589 toSpaceReport source space row col
1591 Port port_ row col ->
1592 toPortReport source port_ row col
1594 DeclType declType row col ->
1595 toDeclTypeReport source declType row col
1597 DeclDef name declDef row col ->
1598 toDeclDefReport source name declDef row col
1600 DeclFreshLineAfterDocComment row col ->
1601 let
1602 region = toRegion row col
1603 in
1604 Report.Report "EXPECTING DECLARATION" region [] $
1605 Code.toSnippet source region Nothing
1607 D.reflow $
1608 "I just saw a doc comment, but then I got stuck here:"
1610 D.reflow $
1611 "I was expecting to see the corresponding declaration next, starting on a fresh\
1612 \ line with no indentation."
1617-- PORT
1620toPortReport :: Code.Source -> Port -> Row -> Col -> Report.Report
1621toPortReport source port_ startRow startCol =
1622 case port_ of
1623 PortSpace space row col ->
1624 toSpaceReport source space row col
1626 PortName row col ->
1627 case Code.whatIsNext source row col of
1628 Code.Keyword keyword ->
1629 let
1630 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1631 region = toKeywordRegion row col keyword
1632 in
1633 Report.Report "RESERVED WORD" region [] $
1634 Code.toSnippet source surroundings (Just region)
1636 D.reflow $
1637 "I cannot handle ports with names like this:"
1639 D.reflow $
1640 "You are trying to make a port named `" ++ keyword
1641 ++ "` but that is a reserved word. Try using some other name?"
1644 _ ->
1645 let
1646 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1647 region = toRegion row col
1648 in
1649 Report.Report "PORT PROBLEM" region [] $
1650 Code.toSnippet source surroundings (Just region)
1652 D.reflow $
1653 "I just saw the start of a `port` declaration, but then I got stuck here:"
1655 D.stack
1656 [ D.fillSep
1657 ["I","was","expecting","to","see","a","name","like"
1658 ,D.dullyellow "send","or",D.dullyellow "receive","next."
1659 ,"Something","that","starts","with","a","lower-case","letter."
1661 , portNote
1665 PortColon row col ->
1666 let
1667 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1668 region = toRegion row col
1669 in
1670 Report.Report "PORT PROBLEM" region [] $
1671 Code.toSnippet source surroundings (Just region)
1673 D.reflow $
1674 "I just saw the start of a `port` declaration, but then I got stuck here:"
1676 D.stack
1677 [ D.reflow $
1678 "I was expecting to see a colon next. And then a type that tells me\
1679 \ what type of values are going to flow through."
1680 , portNote
1684 PortType tipe row col ->
1685 toTypeReport source TC_Port tipe row col
1687 PortIndentName row col ->
1688 let
1689 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1690 region = toRegion row col
1691 in
1692 Report.Report "UNFINISHED PORT" region [] $
1693 Code.toSnippet source surroundings (Just region)
1695 D.reflow $
1696 "I just saw the start of a `port` declaration, but then I got stuck here:"
1698 D.stack
1699 [ D.fillSep
1700 ["I","was","expecting","to","see","a","name","like"
1701 ,D.dullyellow "send","or",D.dullyellow "receive","next."
1702 ,"Something","that","starts","with","a","lower-case","letter."
1704 , portNote
1708 PortIndentColon row col ->
1709 let
1710 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1711 region = toRegion row col
1712 in
1713 Report.Report "UNFINISHED PORT" region [] $
1714 Code.toSnippet source surroundings (Just region)
1716 D.reflow $
1717 "I just saw the start of a `port` declaration, but then I got stuck here:"
1719 D.stack
1720 [ D.reflow $
1721 "I was expecting to see a colon next. And then a type that tells me\
1722 \ what type of values are going to flow through."
1723 , portNote
1727 PortIndentType 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 type next. Here are examples of outgoing and\
1741 \ incoming ports for reference:"
1742 , D.indent 4 $ D.vcat $
1743 [ D.fillSep [D.cyan "port","send",":","String -> Cmd msg"]
1744 , D.fillSep [D.cyan "port","receive",":","(String -> msg) -> Sub msg"]
1746 , D.reflow $
1747 "The first line defines a `send` port so you can send strings out to JavaScript.\
1748 \ Maybe you send them on a WebSocket or put them into IndexedDB. The second line\
1749 \ defines a `receive` port so you can receive strings from JavaScript. Maybe you\
1750 \ get receive messages when new WebSocket messages come in or when an entry in\
1751 \ IndexedDB changes for some external reason."
1756portNote :: D.Doc
1757portNote =
1758 D.stack
1759 [ D.toSimpleNote $
1760 "Here are some example `port` declarations 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 the IndexedDB\
1770 \ is changed for some external reason."
1775-- DECL TYPE
1778toDeclTypeReport :: Code.Source -> DeclType -> Row -> Col -> Report.Report
1779toDeclTypeReport source declType startRow startCol =
1780 case declType of
1781 DT_Space space row col ->
1782 toSpaceReport source space row col
1784 DT_Name row col ->
1785 let
1786 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1787 region = toRegion row col
1788 in
1789 Report.Report "EXPECTING TYPE NAME" region [] $
1790 Code.toSnippet source surroundings (Just region)
1792 D.reflow $
1793 "I think I am parsing a type declaration, but I got stuck here:"
1795 D.stack
1796 [ D.fillSep $
1797 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1798 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1800 , customTypeNote
1804 DT_Alias typeAlias row col ->
1805 toTypeAliasReport source typeAlias row col
1807 DT_Union customType row col ->
1808 toCustomTypeReport source customType row col
1810 DT_IndentName row col ->
1811 let
1812 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1813 region = toRegion row col
1814 in
1815 Report.Report "EXPECTING TYPE NAME" region [] $
1816 Code.toSnippet source surroundings (Just region)
1818 D.reflow $
1819 "I think I am parsing a type declaration, but I got stuck here:"
1821 D.stack
1822 [ D.fillSep $
1823 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1824 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1826 , customTypeNote
1831toTypeAliasReport :: Code.Source -> TypeAlias -> Row -> Col -> Report.Report
1832toTypeAliasReport source typeAlias startRow startCol =
1833 case typeAlias of
1834 AliasSpace space row col ->
1835 toSpaceReport source space row col
1837 AliasName row col ->
1838 let
1839 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1840 region = toRegion row col
1841 in
1842 Report.Report "EXPECTING TYPE ALIAS NAME" region [] $
1843 Code.toSnippet source surroundings (Just region)
1845 D.reflow $
1846 "I am partway through parsing a type alias, but I got stuck here:"
1848 D.stack
1849 [ D.fillSep $
1850 ["I","was","expecting","a","name","like",D.dullyellow "Person","or",D.dullyellow "Point"
1851 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1853 , typeAliasNote
1857 AliasEquals row col ->
1858 case Code.whatIsNext source row col of
1859 Code.Keyword keyword ->
1860 let
1861 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1862 region = toKeywordRegion row col keyword
1863 in
1864 Report.Report "RESERVED WORD" region [] $
1865 Code.toSnippet source surroundings (Just region)
1867 D.reflow $
1868 "I ran into a reserved word unexpectedly while parsing this type alias:"
1870 D.stack
1871 [ D.reflow $
1872 "It looks like you are trying use `" ++ keyword
1873 ++ "` as a type variable, but it is a reserved word. Try using a different name?"
1874 , typeAliasNote
1878 _ ->
1879 let
1880 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1881 region = toRegion row col
1882 in
1883 Report.Report "PROBLEM IN TYPE ALIAS" region [] $
1884 Code.toSnippet source surroundings (Just region)
1886 D.reflow $
1887 "I am partway through parsing a type alias, but I got stuck here:"
1889 D.stack
1890 [ D.reflow $
1891 "I was expecting to see a type variable or an equals sign next."
1892 , typeAliasNote
1896 AliasBody tipe row col ->
1897 toTypeReport source TC_TypeAlias tipe row col
1899 AliasIndentEquals row col ->
1900 let
1901 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1902 region = toRegion row col
1903 in
1904 Report.Report "UNFINISHED TYPE ALIAS" region [] $
1905 Code.toSnippet source surroundings (Just region)
1907 D.reflow $
1908 "I am partway through parsing a type alias, but I got stuck here:"
1910 D.stack
1911 [ D.reflow $
1912 "I was expecting to see a type variable or an equals sign next."
1913 , typeAliasNote
1917 AliasIndentBody row col ->
1918 let
1919 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1920 region = toRegion row col
1921 in
1922 Report.Report "UNFINISHED TYPE ALIAS" region [] $
1923 Code.toSnippet source surroundings (Just region)
1925 D.reflow $
1926 "I am partway through parsing a type alias, but I got stuck here:"
1928 D.stack
1929 [ D.fillSep $
1930 ["I","was","expecting","to","see","a","type","next.","Something","as","simple"
1931 ,"as",D.dullyellow "Int","or",D.dullyellow "Float","would","work!"
1933 , typeAliasNote
1938typeAliasNote :: D.Doc
1939typeAliasNote =
1940 D.stack
1941 [ D.toSimpleNote $
1942 "Here is an example of a valid `type alias` for reference:"
1943 , D.vcat $
1944 [ D.indent 4 $ D.fillSep [D.cyan "type",D.cyan "alias","Person","="]
1945 , D.indent 6 $ D.vcat $
1946 ["{ name : String"
1947 ,", age : Int"
1948 ,", height : Float"
1949 ,"}"
1952 , D.reflow $
1953 "This would let us use `Person` as a shorthand for that record type. Using this\
1954 \ shorthand makes type annotations much easier to read, and makes changing code\
1955 \ easier if you decide later that there is more to a person than age and height!"
1959toCustomTypeReport :: Code.Source -> CustomType -> Row -> Col -> Report.Report
1960toCustomTypeReport source customType startRow startCol =
1961 case customType of
1962 CT_Space space row col ->
1963 toSpaceReport source space row col
1965 CT_Name row col ->
1966 let
1967 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1968 region = toRegion row col
1969 in
1970 Report.Report "EXPECTING TYPE NAME" region [] $
1971 Code.toSnippet source surroundings (Just region)
1973 D.reflow $
1974 "I think I am parsing a type declaration, but I got stuck here:"
1976 D.stack
1977 [ D.fillSep $
1978 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1979 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1981 , customTypeNote
1985 CT_Equals row col ->
1986 case Code.whatIsNext source row col of
1987 Code.Keyword keyword ->
1988 let
1989 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1990 region = toKeywordRegion row col keyword
1991 in
1992 Report.Report "RESERVED WORD" region [] $
1993 Code.toSnippet source surroundings (Just region)
1995 D.reflow $
1996 "I ran into a reserved word unexpectedly while parsing this custom type:"
1998 D.stack
1999 [ D.reflow $
2000 "It looks like you are trying use `" ++ keyword
2001 ++ "` as a type variable, but it is a reserved word. Try using a different name?"
2002 , customTypeNote
2006 _ ->
2007 let
2008 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2009 region = toRegion row col
2010 in
2011 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
2012 Code.toSnippet source surroundings (Just region)
2014 D.reflow $
2015 "I am partway through parsing a custom type, but I got stuck here:"
2017 D.stack
2018 [ D.reflow $
2019 "I was expecting to see a type variable or an equals sign next."
2020 , customTypeNote
2024 CT_Bar row col ->
2025 let
2026 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2027 region = toRegion row col
2028 in
2029 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
2030 Code.toSnippet source surroundings (Just region)
2032 D.reflow $
2033 "I am partway through parsing a custom type, but I got stuck here:"
2035 D.stack
2036 [ D.reflow $
2037 "I was expecting to see a vertical bar like | next."
2038 , customTypeNote
2042 CT_Variant row col ->
2043 let
2044 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2045 region = toRegion row col
2046 in
2047 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
2048 Code.toSnippet source surroundings (Just region)
2050 D.reflow $
2051 "I am partway through parsing a custom type, but I got stuck here:"
2053 D.stack
2054 [ D.fillSep $
2055 ["I","was","expecting","to","see","a","variant","name","next."
2056 ,"Something","like",D.dullyellow "Success","or",D.dullyellow "Sandwich" <> "."
2057 ,"Any","name","that","starts","with","a","capital","letter","really!"
2059 , customTypeNote
2063 CT_VariantArg tipe row col ->
2064 toTypeReport source TC_CustomType tipe row col
2066 CT_IndentEquals row col ->
2067 let
2068 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2069 region = toRegion row col
2070 in
2071 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
2072 Code.toSnippet source surroundings (Just region)
2074 D.reflow $
2075 "I am partway through parsing a custom type, but I got stuck here:"
2077 D.stack
2078 [ D.reflow $
2079 "I was expecting to see a type variable or an equals sign next."
2080 , customTypeNote
2084 CT_IndentBar row col ->
2085 let
2086 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2087 region = toRegion row col
2088 in
2089 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
2090 Code.toSnippet source surroundings (Just region)
2092 D.reflow $
2093 "I am partway through parsing a custom type, but I got stuck here:"
2095 D.stack
2096 [ D.reflow $
2097 "I was expecting to see a vertical bar like | next."
2098 , customTypeNote
2102 CT_IndentAfterBar row col ->
2103 let
2104 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2105 region = toRegion row col
2106 in
2107 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
2108 Code.toSnippet source surroundings (Just region)
2110 D.reflow $
2111 "I am partway through parsing a custom type, but I got stuck here:"
2113 D.stack
2114 [ D.reflow $
2115 "I just saw a vertical bar, so I was expecting to see another variant defined next."
2116 , customTypeNote
2120 CT_IndentAfterEquals row col ->
2121 let
2122 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2123 region = toRegion row col
2124 in
2125 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
2126 Code.toSnippet source surroundings (Just region)
2128 D.reflow $
2129 "I am partway through parsing a custom type, but I got stuck here:"
2131 D.stack
2132 [ D.reflow $
2133 "I just saw an equals sign, so I was expecting to see the first variant defined next."
2134 , customTypeNote
2139customTypeNote :: D.Doc
2140customTypeNote =
2141 D.stack
2142 [ D.toSimpleNote $
2143 "Here is an example of a valid `type` declaration for reference:"
2144 , D.vcat $
2145 [ D.indent 4 $ D.fillSep [D.cyan "type","Status"]
2146 , D.indent 6 $ D.fillSep ["=","Failure"]
2147 , D.indent 6 $ D.fillSep ["|","Waiting"]
2148 , D.indent 6 $ D.fillSep ["|","Success","String"]
2150 , D.reflow $
2151 "This defines a new `Status` type with three variants. This could be useful if\
2152 \ we are waiting for an HTTP request. Maybe we start with `Waiting` and then\
2153 \ switch to `Failure` or `Success \"message from server\"` depending on how\
2154 \ things go. Notice that the Success variant has some associated data, allowing\
2155 \ us to store a String if the request goes well!"
2160-- DECL DEF
2163toDeclDefReport :: Code.Source -> Name.Name -> DeclDef -> Row -> Col -> Report.Report
2164toDeclDefReport source name declDef startRow startCol =
2165 case declDef of
2166 DeclDefSpace space row col ->
2167 toSpaceReport source space row col
2169 DeclDefEquals row col ->
2170 case Code.whatIsNext source row col of
2171 Code.Keyword keyword ->
2172 let
2173 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2174 region = toKeywordRegion row col keyword
2175 in
2176 Report.Report "RESERVED WORD" region [] $
2177 Code.toSnippet source surroundings (Just region)
2179 D.fillSep
2180 ["The","name"
2181 ,"`" <> D.cyan (D.fromChars keyword) <> "`"
2182 ,"is","reserved","in","Elm,","so","it","cannot"
2183 ,"be","used","as","an","argument","here:"
2186 D.stack
2187 [ D.reflow $
2188 "Try renaming it to something else."
2189 , case keyword of
2190 "as" ->
2191 D.toFancyNote
2192 ["This","keyword","is","reserved","for","pattern","matches","like"
2193 ,"((x,y)",D.cyan "as","point)","where","you","want","to","name","a","tuple","and"
2194 ,"the","values","it","contains."
2197 _ ->
2198 D.toSimpleNote $
2199 "The `" ++ keyword ++ "` keyword has a special meaning in Elm, so it can only be used in certain situations."
2203 Code.Operator "->" ->
2204 let
2205 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2206 region = toWiderRegion row col 2
2207 in
2208 Report.Report "MISSING COLON?" region [] $
2209 Code.toSnippet source surroundings (Just region)
2211 D.reflow $
2212 "I was not expecting to see an arrow here:"
2214 D.stack
2215 [ D.fillSep
2216 ["This","usually","means","a",D.green ":","is","missing","a","bit","earlier","in"
2217 ,"a","type","annotation.","It","could","be","something","else","though,","so"
2218 ,"here","is","a","valid","definition","for","reference:"
2220 , D.indent 4 $ D.vcat $
2221 [ "greet : String -> String"
2222 , "greet name ="
2223 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
2225 , D.reflow $
2226 "Try to use that format with your `" ++ Name.toChars name ++ "` definition!"
2230 Code.Operator op ->
2231 let
2232 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2233 region = toKeywordRegion row col op
2234 in
2235 Report.Report "UNEXPECTED SYMBOL" region [] $
2236 Code.toSnippet source surroundings (Just region)
2238 D.reflow $
2239 "I was not expecting to see this symbol here:"
2241 D.stack
2242 [ D.reflow $
2243 "I am not sure what is going wrong exactly, so here is a valid\
2244 \ definition (with an optional type annotation) for reference:"
2245 , D.indent 4 $ D.vcat $
2246 [ "greet : String -> String"
2247 , "greet name ="
2248 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
2250 , D.reflow $
2251 "Try to use that format with your `" ++ Name.toChars name ++ "` definition!"
2255 _ ->
2256 let
2257 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2258 region = toRegion row col
2259 in
2260 Report.Report "PROBLEM IN DEFINITION" region [] $
2261 Code.toSnippet source surroundings (Just region)
2263 D.reflow $
2264 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
2266 D.stack
2267 [ D.reflow $
2268 "I am not sure what is going wrong exactly, so here is a valid\
2269 \ definition (with an optional type annotation) for reference:"
2270 , D.indent 4 $ D.vcat $
2271 [ "greet : String -> String"
2272 , "greet name ="
2273 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
2275 , D.reflow $
2276 "Try to use that format!"
2280 DeclDefType tipe row col ->
2281 toTypeReport source (TC_Annotation name) tipe row col
2283 DeclDefArg pattern row col ->
2284 toPatternReport source PArg pattern row col
2286 DeclDefBody expr row col ->
2287 toExprReport source (InDef name startRow startCol) expr row col
2289 DeclDefNameRepeat row col ->
2290 let
2291 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2292 region = toRegion row col
2293 in
2294 Report.Report "EXPECTING DEFINITION" region [] $
2295 Code.toSnippet source surroundings (Just region)
2297 D.reflow $
2298 "I just saw the type annotation for `" ++ Name.toChars name
2299 ++ "` so I was expecting to see its definition here:"
2301 D.stack
2302 [ D.reflow $
2303 "Type annotations always appear directly above the relevant\
2304 \ definition, without anything else in between. (Not even doc comments!)"
2305 , declDefNote
2309 DeclDefNameMatch defName row col ->
2310 let
2311 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2312 region = toRegion row col
2313 in
2314 Report.Report "NAME MISMATCH" region [] $
2315 Code.toSnippet source surroundings (Just region)
2317 D.reflow $
2318 "I just saw a type annotation for `" ++ Name.toChars name ++ "`, but it is followed by a definition for `" ++ Name.toChars defName ++ "`:"
2320 D.stack
2321 [ D.reflow $
2322 "These names do not match! Is there a typo?"
2323 , D.indent 4 $ D.fillSep $
2324 [D.dullyellow (D.fromName defName),"->",D.green (D.fromName name)]
2328 DeclDefIndentType 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 "UNFINISHED DEFINITION" region [] $
2334 Code.toSnippet source surroundings (Just region)
2336 D.reflow $
2337 "I got stuck while parsing the `" ++ Name.toChars name ++ "` type annotation:"
2339 D.stack
2340 [ D.reflow $
2341 "I just saw a colon, so I am expecting to see a type next."
2342 , declDefNote
2346 DeclDefIndentEquals row col ->
2347 let
2348 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2349 region = toRegion row col
2350 in
2351 Report.Report "UNFINISHED DEFINITION" region [] $
2352 Code.toSnippet source surroundings (Just region)
2354 D.reflow $
2355 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
2357 D.stack
2358 [ D.reflow $
2359 "I was expecting to see an argument or an equals sign next."
2360 , declDefNote
2364 DeclDefIndentBody row col ->
2365 let
2366 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2367 region = toRegion row col
2368 in
2369 Report.Report "UNFINISHED DEFINITION" region [] $
2370 Code.toSnippet source surroundings (Just region)
2372 D.reflow $
2373 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
2375 D.stack
2376 [ D.reflow $
2377 "I was expecting to see an expression next. What is it equal to?"
2378 , declDefNote
2383declDefNote :: D.Doc
2384declDefNote =
2385 D.stack
2386 [ D.reflow $
2387 "Here is a valid definition (with a type annotation) for reference:"
2388 , D.indent 4 $ D.vcat $
2389 [ "greet : String -> String"
2390 , "greet name ="
2391 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
2393 , D.reflow $
2394 "The top line (called a \"type annotation\") is optional. You can leave it off\
2395 \ if you want. As you get more comfortable with Elm and as your project grows,\
2396 \ it becomes more and more valuable to add them though! They work great as\
2397 \ compiler-verified documentation, and they often improve error messages!"
2402-- CONTEXT
2405data Context
2406 = InNode Node Row Col Context
2407 | InDef Name.Name Row Col
2408 | InDestruct Row Col
2411data Node
2412 = NRecord
2413 | NParens
2414 | NList
2415 | NFunc
2416 | NCond
2417 | NThen
2418 | NElse
2419 | NCase
2420 | NBranch
2421 deriving (Eq)
2424getDefName :: Context -> Maybe Name.Name
2425getDefName context =
2426 case context of
2427 InDestruct _ _ -> Nothing
2428 InDef name _ _ -> Just name
2429 InNode _ _ _ c -> getDefName c
2432isWithin :: Node -> Context -> Bool
2433isWithin desiredNode context =
2434 case context of
2435 InDestruct _ _ -> False
2436 InDef _ _ _ -> False
2437 InNode actualNode _ _ _ -> desiredNode == actualNode
2441-- EXPR REPORTS
2444toExprReport :: Code.Source -> Context -> Expr -> Row -> Col -> Report.Report
2445toExprReport source context expr startRow startCol =
2446 case expr of
2447 Let let_ row col ->
2448 toLetReport source context let_ row col
2450 Case case_ row col ->
2451 toCaseReport source context case_ row col
2453 If if_ row col ->
2454 toIfReport source context if_ row col
2456 List list row col ->
2457 toListReport source context list row col
2459 Record record row col ->
2460 toRecordReport source context record row col
2462 Tuple tuple row col ->
2463 toTupleReport source context tuple row col
2465 Func func row col ->
2466 toFuncReport source context func row col
2468 Dot row col ->
2469 let region = toRegion row col in
2470 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
2471 Code.toSnippet source region Nothing
2473 D.reflow $
2474 "I was expecting to see a record accessor here:"
2476 D.fillSep
2477 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
2478 ,"that","accesses","a","value","from","a","record."
2482 Access row col ->
2483 let region = toRegion row col in
2484 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
2485 Code.toSnippet source region Nothing
2487 D.reflow $
2488 "I am trying to parse a record accessor here:"
2490 D.stack
2492 D.fillSep
2493 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
2494 ,"that","accesses","a","value","from","a","record."
2497 D.toSimpleNote $
2498 "Record field names must start with a lower case letter!"
2502 OperatorRight op row col ->
2503 let
2504 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2505 region = toRegion row col
2506 isMath = elem op ["-","+","*","/","^"]
2507 in
2508 Report.Report "MISSING EXPRESSION" region [] $
2509 Code.toSnippet source surroundings (Just region)
2511 D.reflow $
2512 "I just saw a " ++ Name.toChars op ++ " "
2513 ++ (if isMath then "sign" else "operator")
2514 ++ ", so I am getting stuck here:"
2516 if isMath then
2517 D.fillSep
2518 ["I","was","expecting","to","see","an","expression","next."
2519 ,"Something","like",D.dullyellow "42","or",D.dullyellow "1000"
2520 ,"that","makes","sense","with","a",D.fromName op,"sign."
2522 else if op == "&&" || op == "||" then
2523 D.fillSep
2524 ["I","was","expecting","to","see","an","expression","next."
2525 ,"Something","like",D.dullyellow "True","or",D.dullyellow "False"
2526 ,"that","makes","sense","with","boolean","logic."
2528 else if op == "|>" then
2529 D.reflow $
2530 "I was expecting to see a function next."
2531 else if op == "<|" then
2532 D.reflow $
2533 "I was expecting to see an argument next."
2534 else
2535 D.reflow $
2536 "I was expecting to see an expression next."
2539 OperatorReserved operator row col ->
2540 toOperatorReport source context operator row col
2542 Start row col ->
2543 let
2544 (contextRow, contextCol, aThing) =
2545 case context of
2546 InDestruct r c -> (r, c, "a definition")
2547 InDef name r c -> (r, c, "the `" ++ Name.toChars name ++ "` definition")
2548 InNode NRecord r c _ -> (r, c, "a record")
2549 InNode NParens r c _ -> (r, c, "some parentheses")
2550 InNode NList r c _ -> (r, c, "a list")
2551 InNode NFunc r c _ -> (r, c, "an anonymous function")
2552 InNode NCond r c _ -> (r, c, "an `if` expression")
2553 InNode NThen r c _ -> (r, c, "an `if` expression")
2554 InNode NElse r c _ -> (r, c, "an `if` expression")
2555 InNode NCase r c _ -> (r, c, "a `case` expression")
2556 InNode NBranch r c _ -> (r, c, "a `case` expression")
2558 surroundings = A.Region (A.Position contextRow contextCol) (A.Position row col)
2559 region = toRegion row col
2560 in
2561 Report.Report "MISSING EXPRESSION" region [] $
2562 Code.toSnippet source surroundings (Just region)
2564 D.reflow $
2565 "I am partway through parsing " ++ aThing ++ ", but I got stuck here:"
2567 D.stack
2568 [ D.fillSep $
2569 ["I","was","expecting","to","see","an","expression","like"
2570 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
2571 ,"Once","there","is","something","there,","I","can","probably"
2572 ,"give","a","more","specific","hint!"
2574 , D.toSimpleNote $
2575 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
2576 \ Or if I run into operators in unexpected spots. Point is, there are a\
2577 \ couple ways I can get confused and give sort of weird advice!"
2581 Char char row col ->
2582 toCharReport source char row col
2584 String string row col ->
2585 toStringReport source string row col
2587 Number number row col ->
2588 toNumberReport source number row col
2590 Space space row col ->
2591 toSpaceReport source space row col
2593 EndlessShader row col ->
2594 let
2595 region = toWiderRegion row col 6
2596 in
2597 Report.Report "ENDLESS SHADER" region [] $
2598 Code.toSnippet source region Nothing
2600 D.reflow "I cannot find the end of this shader:"
2602 D.reflow "Add a |] somewhere after this to end the shader."
2605 ShaderProblem problem row col ->
2606 let
2607 region = toRegion row col
2608 in
2609 Report.Report "SHADER PROBLEM" region [] $
2610 Code.toSnippet source region Nothing
2612 D.reflow $
2613 "I ran into a problem while parsing this GLSL block."
2615 D.stack
2616 [ D.reflow $
2617 "I use a 3rd party GLSL parser for now, and I did my best to extract their error message:"
2618 , D.indent 4 $ D.vcat $
2619 map D.fromChars (filter (/="") (lines problem))
2623 IndentOperatorRight op row col ->
2624 let
2625 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2626 region = toRegion row col
2627 in
2628 Report.Report "MISSING EXPRESSION" region [] $
2629 Code.toSnippet source surroundings (Just region)
2631 D.reflow $
2632 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
2634 D.stack
2636 D.fillSep $
2637 ["You","can","just","put","anything","for","now,","like"
2638 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
2639 ,"Once","there","is","something","there,","I","can","probably"
2640 ,"give","a","more","specific","hint!"
2643 D.toSimpleNote $
2644 "I may be getting confused by your indentation? The easiest way to make sure\
2645 \ this is not an indentation problem is to put the expression on the right of\
2646 \ the " ++ Name.toChars op ++ " operator on the same line."
2652-- CHAR
2655toCharReport :: Code.Source -> Char -> Row -> Col -> Report.Report
2656toCharReport source char row col =
2657 case char of
2658 CharEndless ->
2659 let
2660 region = toRegion row col
2661 in
2662 Report.Report "MISSING SINGLE QUOTE" region [] $
2663 Code.toSnippet source region Nothing
2665 D.reflow $
2666 "I thought I was parsing a character, but I got to the end of\
2667 \ the line without seeing the closing single quote:"
2669 D.reflow $
2670 "Add a closing single quote here!"
2673 CharEscape escape ->
2674 toEscapeReport source escape row col
2676 CharNotString width ->
2677 let
2678 region = toWiderRegion row col width
2679 in
2680 Report.Report "NEEDS DOUBLE QUOTES" region [] $
2681 Code.toSnippet source region Nothing
2683 "The following string uses single quotes:"
2685 D.stack
2686 [ "Please switch to double quotes instead:"
2687 , D.indent 4 $
2688 D.dullyellow "'this'" <> " => " <> D.green "\"this\""
2689 , D.toSimpleNote $
2690 "Elm uses double quotes for strings like \"hello\", whereas it uses single\
2691 \ quotes for individual characters like 'a' and 'ø'. This distinction helps with\
2692 \ code like (String.any (\\c -> c == 'X') \"90210\") where you are inspecting\
2693 \ individual characters."
2699-- STRING
2702toStringReport :: Code.Source -> String -> Row -> Col -> Report.Report
2703toStringReport source string row col =
2704 case string of
2705 StringEndless_Single ->
2706 let
2707 region = toRegion row col
2708 in
2709 Report.Report "ENDLESS STRING" region [] $
2710 Code.toSnippet source region Nothing
2712 D.reflow $
2713 "I got to the end of the line without seeing the closing double quote:"
2715 D.stack
2716 [ D.fillSep $
2717 ["Strings","look","like",D.green "\"this\"","with","double"
2718 ,"quotes","on","each","end.","Is","the","closing","double"
2719 ,"quote","missing","in","your","code?"
2721 , D.toSimpleNote $
2722 "For a string that spans multiple lines, you can use the multi-line string\
2723 \ syntax like this:"
2724 , D.dullyellow $ D.indent 4 $ D.vcat $
2725 [ "\"\"\""
2726 , "# Multi-line Strings"
2727 , ""
2728 , "- start with triple double quotes"
2729 , "- write whatever you want"
2730 , "- no need to escape newlines or double quotes"
2731 , "- end with triple double quotes"
2732 , "\"\"\""
2737 StringEndless_Multi ->
2738 let
2739 region = toWiderRegion row col 3
2740 in
2741 Report.Report "ENDLESS STRING" region [] $
2742 Code.toSnippet source region Nothing
2744 D.reflow $
2745 "I cannot find the end of this multi-line string:"
2747 D.stack
2748 [ D.reflow "Add a \"\"\" somewhere after this to end the string."
2749 , D.toSimpleNote $
2750 "Here is a valid multi-line string for reference:"
2751 , D.dullyellow $ D.indent 4 $ D.vcat $
2752 [ "\"\"\""
2753 , "# Multi-line Strings"
2754 , ""
2755 , "- start with triple double quotes"
2756 , "- write whatever you want"
2757 , "- no need to escape newlines or double quotes"
2758 , "- end with triple double quotes"
2759 , "\"\"\""
2764 StringEscape escape ->
2765 toEscapeReport source escape row col
2769-- ESCAPES
2772toEscapeReport :: Code.Source -> Escape -> Row -> Col -> Report.Report
2773toEscapeReport source escape row col =
2774 case escape of
2775 EscapeUnknown ->
2776 let
2777 region = toWiderRegion row col 2
2778 in
2779 Report.Report "UNKNOWN ESCAPE" region [] $
2780 Code.toSnippet source region Nothing
2782 D.reflow $
2783 "Backslashes always start escaped characters, but I do not recognize this one:"
2785 D.stack
2786 [ D.reflow $
2787 "Valid escape characters include:"
2788 , D.dullyellow $ D.indent 4 $ D.vcat $
2789 [ "\\n"
2790 , "\\r"
2791 , "\\t"
2792 , "\\\""
2793 , "\\\'"
2794 , "\\\\"
2795 , "\\u{003D}"
2797 , D.reflow $
2798 "Do you want one of those instead? Maybe you need \\\\ to escape a backslash?"
2799 , D.toSimpleNote $
2800 "The last style lets encode ANY character by its Unicode code\
2801 \ point. That means \\u{0009} and \\t are the same. You can use\
2802 \ that style for anything not covered by the other six escapes!"
2806 BadUnicodeFormat width ->
2807 let
2808 region = toWiderRegion row col width
2809 in
2810 Report.Report "BAD UNICODE ESCAPE" region [] $
2811 Code.toSnippet source region Nothing
2813 D.reflow $
2814 "I ran into an invalid Unicode escape:"
2816 D.stack
2817 [ D.reflow $
2818 "Here are some examples of valid Unicode escapes:"
2819 , D.dullyellow $ D.indent 4 $ D.vcat $
2820 [ "\\u{0041}"
2821 , "\\u{03BB}"
2822 , "\\u{6728}"
2823 , "\\u{1F60A}"
2825 , D.reflow $
2826 "Notice that the code point is always surrounded by curly braces.\
2827 \ Maybe you are missing the opening or closing curly brace?"
2830 BadUnicodeCode width ->
2831 let
2832 region = toWiderRegion row col width
2833 in
2834 Report.Report "BAD UNICODE ESCAPE" region [] $
2835 Code.toSnippet source region Nothing
2837 D.reflow $
2838 "This is not a valid code point:"
2840 D.reflow $
2841 "The valid code points are between 0 and 10FFFF inclusive."
2844 BadUnicodeLength width numDigits badCode ->
2845 let
2846 region = toWiderRegion row col width
2847 in
2848 Report.Report "BAD UNICODE ESCAPE" region [] $
2849 Code.toSnippet source region Nothing $
2850 if numDigits < 4 then
2852 D.reflow $
2853 "Every code point needs at least four digits:"
2855 let
2856 goodCode = replicate (4 - numDigits) '0' ++ map Char.toUpper (showHex badCode "")
2857 suggestion = "\\u{" <> D.fromChars goodCode <> "}"
2858 in
2859 D.fillSep ["Try",D.green suggestion,"instead?"]
2862 else
2864 D.reflow $
2865 "This code point has too many digits:"
2867 D.fillSep $
2868 ["Valid","code","points","are","between"
2869 ,D.green "\\u{0000}","and",D.green "\\u{10FFFF}" <> ","
2870 ,"so","try","trimming","any","leading","zeros","until"
2871 ,"you","have","between","four","and","six","digits."
2877-- NUMBERS
2880toNumberReport :: Code.Source -> Number -> Row -> Col -> Report.Report
2881toNumberReport source number row col =
2882 let
2883 region = toRegion row col
2884 in
2885 case number of
2886 NumberEnd ->
2887 Report.Report "WEIRD NUMBER" region [] $
2888 Code.toSnippet source region Nothing
2890 D.reflow $
2891 "I thought I was reading a number, but I ran into some weird stuff here:"
2893 D.stack
2894 [ D.reflow $
2895 "I recognize numbers in the following formats:"
2896 , D.indent 4 $ D.vcat [ "42", "3.14", "6.022e23", "0x002B" ]
2897 , D.reflow $
2898 "So is there a way to write it like one of those?"
2902 NumberDot int ->
2903 Report.Report "WEIRD NUMBER" region [] $
2904 Code.toSnippet source region Nothing
2906 D.reflow $
2907 "Numbers cannot end with a dot like this:"
2909 D.fillSep
2910 ["Switching","to",D.green (D.fromChars (show int))
2911 ,"or",D.green (D.fromChars (show int ++ ".0"))
2912 ,"will","work","though!"
2916 NumberHexDigit ->
2917 Report.Report "WEIRD HEXIDECIMAL" region [] $
2918 Code.toSnippet source region Nothing
2920 D.reflow $
2921 "I thought I was reading a hexidecimal number until I got here:"
2923 D.stack
2924 [ D.reflow $
2925 "Valid hexidecimal digits include 0123456789abcdefABCDEF, so I can\
2926 \ only recognize things like this:"
2927 , D.indent 4 $ D.vcat [ "0x2B", "0x002B", "0x00ffb3" ]
2931 NumberNoLeadingZero ->
2932 Report.Report "LEADING ZEROS" region [] $
2933 Code.toSnippet source region Nothing
2935 D.reflow $
2936 "I do not accept numbers with leading zeros:"
2938 D.stack
2939 [ D.reflow $
2940 "Just delete the leading zeros and it should work!"
2941 , D.toSimpleNote $
2942 "Some languages let you to specify octal numbers by adding a leading zero.\
2943 \ So in C, writing 0111 is the same as writing 73. Some people are used to\
2944 \ that, but others probably want it to equal 111. Either path is going to\
2945 \ surprise people from certain backgrounds, so Elm tries to avoid this whole\
2946 \ situation."
2952-- OPERATORS
2955toOperatorReport :: Code.Source -> Context -> BadOperator -> Row -> Col -> Report.Report
2956toOperatorReport source context operator row col =
2957 case operator of
2958 BadDot ->
2959 let
2960 region = toRegion row col
2961 in
2962 Report.Report "UNEXPECTED SYMBOL" region [] $
2963 Code.toSnippet source region Nothing
2965 "I was not expecting this dot:"
2967 D.reflow $
2968 "Dots are for record access and decimal points, so\
2969 \ they cannot float around on their own. Maybe\
2970 \ there is some extra whitespace?"
2973 BadPipe ->
2974 let
2975 region = toRegion row col
2976 in
2977 Report.Report "UNEXPECTED SYMBOL" region [] $
2978 Code.toSnippet source region Nothing
2980 D.reflow $
2981 "I was not expecting this vertical bar:"
2983 D.reflow $
2984 "Vertical bars should only appear in custom type declarations. Maybe you want || instead?"
2987 BadArrow ->
2988 let
2989 region = toWiderRegion row col 2
2990 in
2991 Report.Report "UNEXPECTED ARROW" region [] $
2992 Code.toSnippet source region Nothing $
2993 if isWithin NCase context then
2995 D.reflow $
2996 "I am parsing a `case` expression right now, but this arrow is confusing me:"
2998 D.stack
2999 [ D.reflow "Maybe the `of` keyword is missing on a previous line?"
3000 , noteForCaseError
3004 else if isWithin NBranch context then
3006 D.reflow $
3007 "I am parsing a `case` expression right now, but this arrow is confusing me:"
3009 D.stack
3010 [ D.reflow $
3011 "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?"
3012 , noteForCaseIndentError
3016 else
3018 D.reflow $
3019 "I was partway through parsing an expression when I got stuck on this arrow:"
3021 D.stack
3022 [ "Arrows should only appear in `case` expressions and anonymous functions.\n\
3023 \Maybe it was supposed to be a > sign instead?"
3024 , D.toSimpleNote $
3025 "The syntax for anonymous functions is (\\x -> x + 1) so the arguments all appear\
3026 \ after the backslash and before the arrow. Maybe a backslash is missing earlier?"
3030 BadEquals ->
3031 let
3032 region = toRegion row col
3033 in
3034 Report.Report "UNEXPECTED EQUALS" region [] $
3035 Code.toSnippet source region Nothing
3037 D.reflow $
3038 "I was not expecting to see this equals sign:"
3040 D.stack
3042 D.reflow "Maybe you want == instead? To check if two values are equal?"
3044 D.toSimpleNote $
3045 if isWithin NRecord context then
3046 "Records look like { x = 3, y = 4 } with the equals sign right\
3047 \ after the field name. So maybe you forgot a comma?"
3048 else
3049 case getDefName context of
3050 Nothing ->
3051 "I may be getting confused by your indentation. I need all definitions to be indented\
3052 \ exactly the same amount, so if this is meant to be a new definition, it may have too\
3053 \ many spaces in front of it."
3055 Just name ->
3056 "I may be getting confused by your indentation. I think I am still parsing the `"
3057 ++ Name.toChars name ++ "` definition. Is this supposed to be part of a definition\
3058 \ after that? If so, the problem may be a bit before the equals sign. I need all\
3059 \ definitions to be indented exactly the same amount, so the problem may be that\
3060 \ this new definition has too many spaces in front of it."
3064 BadHasType ->
3065 let
3066 region = toRegion row col
3067 in
3068 Report.Report "UNEXPECTED SYMBOL" region [] $
3069 Code.toSnippet source region Nothing $
3071 D.reflow $
3072 "I was not expecting to run into the \"has type\" symbol here:"
3074 case getDefName context of
3075 Nothing ->
3076 D.fillSep
3077 ["Maybe","you","want",D.green "::","instead?"
3078 ,"To","put","something","on","the","front","of","a","list?"
3081 Just name ->
3082 D.stack
3084 D.fillSep
3085 ["Maybe","you","want",D.green "::","instead?"
3086 ,"To","put","something","on","the","front","of","a","list?"
3088 , D.toSimpleNote $
3089 "The single colon is reserved for type annotations and record types, but I think\
3090 \ I am parsing the definition of `" ++ Name.toChars name ++ "` right now."
3092 D.toSimpleNote $
3093 "I may be getting confused by your indentation. Is this supposed to be part of\
3094 \ a type annotation AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
3095 \ the problem may be a bit before the \"has type\" symbol. I need all definitions to\
3096 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
3097 \ this new definition is indented a bit too much."
3103-- CASE
3106toLetReport :: Code.Source -> Context -> Let -> Row -> Col -> Report.Report
3107toLetReport source context let_ startRow startCol =
3108 case let_ of
3109 LetSpace space row col ->
3110 toSpaceReport source space row col
3112 LetIn row col ->
3113 let
3114 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3115 region = toRegion row col
3116 in
3117 Report.Report "LET PROBLEM" region [] $
3118 Code.toSnippet source surroundings (Just region)
3120 D.reflow $
3121 "I was partway through parsing a `let` expression, but I got stuck here:"
3123 D.stack
3124 [ D.fillSep $
3125 ["Based","on","the","indentation,","I","was","expecting","to","see","the",D.cyan "in"
3126 ,"keyword","next.","Is","there","a","typo?"
3128 , D.toSimpleNote $
3129 "This can also happen if you are trying to define another value within the `let` but\
3130 \ it is not indented enough. Make sure each definition has exactly the same amount of\
3131 \ spaces before it. They should line up exactly!"
3135 LetDefAlignment _ row col ->
3136 let
3137 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3138 region = toRegion row col
3139 in
3140 Report.Report "LET PROBLEM" region [] $
3141 Code.toSnippet source surroundings (Just region)
3143 D.reflow $
3144 "I was partway through parsing a `let` expression, but I got stuck here:"
3146 D.stack
3147 [ D.fillSep $
3148 ["Based","on","the","indentation,","I","was","expecting","to","see","the",D.cyan "in"
3149 ,"keyword","next.","Is","there","a","typo?"
3151 , D.toSimpleNote $
3152 "This can also happen if you are trying to define another value within the `let` but\
3153 \ it is not indented enough. Make sure each definition has exactly the same amount of\
3154 \ spaces before it. They should line up exactly!"
3158 LetDefName row col ->
3159 case Code.whatIsNext source row col of
3160 Code.Keyword keyword ->
3161 let
3162 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3163 region = toKeywordRegion row col keyword
3164 in
3165 Report.Report "RESERVED WORD" region [] $
3166 Code.toSnippet source surroundings (Just region)
3168 D.reflow $
3169 "I was partway through parsing a `let` expression, but I got stuck here:"
3171 D.reflow $
3172 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name, but\
3173 \ it is a reserved word! Try using a different name instead."
3176 _ ->
3177 toUnfinishLetReport source row col startRow startCol $
3178 D.reflow $
3179 "I was expecting the name of a definition next."
3181 LetDef name def row col ->
3182 toLetDefReport source name def row col
3184 LetDestruct destruct row col ->
3185 toLetDestructReport source destruct row col
3187 LetBody expr row col ->
3188 toExprReport source context expr row col
3190 LetIndentDef row col ->
3191 toUnfinishLetReport source row col startRow startCol $
3192 D.reflow $
3193 "I was expecting a value to be defined here."
3195 LetIndentIn row col ->
3196 toUnfinishLetReport source row col startRow startCol $
3197 D.fillSep $
3198 ["I","was","expecting","to","see","the",D.cyan "in","keyword","next."
3199 ,"Or","maybe","more","of","that","expression?"
3202 LetIndentBody row col ->
3203 toUnfinishLetReport source row col startRow startCol $
3204 D.reflow $
3205 "I was expecting an expression next. Tell me what should happen with the value you just defined!"
3208toUnfinishLetReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
3209toUnfinishLetReport source row col startRow startCol message =
3210 let
3211 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3212 region = toRegion row col
3213 in
3214 Report.Report "UNFINISHED LET" region [] $
3215 Code.toSnippet source surroundings (Just region)
3217 D.reflow $
3218 "I was partway through parsing a `let` expression, but I got stuck here:"
3220 D.stack
3221 [ message
3222 , D.toSimpleNote $
3223 "Here is an example with a valid `let` expression for reference:"
3224 , D.indent 4 $ D.vcat $
3225 [ D.indent 0 $ D.fillSep ["viewPerson","person","="]
3226 , D.indent 2 $ D.fillSep [D.cyan "let"]
3227 , D.indent 4 $ D.fillSep ["fullName","="]
3228 , D.indent 6 $ D.fillSep ["person.firstName","++",D.dullyellow "\" \"","++","person.lastName"]
3229 , D.indent 2 $ D.fillSep [D.cyan "in"]
3230 , D.indent 2 $ D.fillSep ["div","[]","[","text","fullName","]"]
3232 , D.reflow $
3233 "Here we defined a `viewPerson` function that turns a person into some HTML. We use\
3234 \ a `let` expression to define the `fullName` we want to show. Notice the indentation! The\
3235 \ `fullName` is indented more than the `let` keyword, and the actual value of `fullName` is\
3236 \ indented a bit more than that. That is important!"
3241toLetDefReport :: Code.Source -> Name.Name -> Def -> Row -> Col -> Report.Report
3242toLetDefReport source name def startRow startCol =
3243 case def of
3244 DefSpace space row col ->
3245 toSpaceReport source space row col
3247 DefType tipe row col ->
3248 toTypeReport source (TC_Annotation name) tipe row col
3250 DefNameRepeat row col ->
3251 let
3252 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3253 region = toRegion row col
3254 in
3255 Report.Report "EXPECTING DEFINITION" region [] $
3256 Code.toSnippet source surroundings (Just region)
3258 D.reflow $
3259 "I just saw the type annotation for `" ++ Name.toChars name
3260 ++ "` so I was expecting to see its definition here:"
3262 D.stack
3263 [ D.reflow $
3264 "Type annotations always appear directly above the relevant\
3265 \ definition, without anything else in between."
3266 , defNote
3270 DefNameMatch defName row col ->
3271 let
3272 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3273 region = toRegion row col
3274 in
3275 Report.Report "NAME MISMATCH" region [] $
3276 Code.toSnippet source surroundings (Just region)
3278 D.reflow $
3279 "I just saw a type annotation for `" ++ Name.toChars name ++ "`, but it is followed by a definition for `" ++ Name.toChars defName ++ "`:"
3281 D.stack
3282 [ D.reflow $
3283 "These names do not match! Is there a typo?"
3284 , D.indent 4 $ D.fillSep $
3285 [D.dullyellow (D.fromName defName),"->",D.green (D.fromName name)]
3289 DefArg pattern row col ->
3290 toPatternReport source PArg pattern row col
3292 DefEquals row col ->
3293 case Code.whatIsNext source row col of
3294 Code.Keyword keyword ->
3295 let
3296 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3297 region = toKeywordRegion row col keyword
3298 in
3299 Report.Report "RESERVED WORD" region [] $
3300 Code.toSnippet source surroundings (Just region)
3302 D.fillSep
3303 ["The","name"
3304 ,"`" <> D.cyan (D.fromChars keyword) <> "`"
3305 ,"is","reserved","in","Elm,","so","it","cannot"
3306 ,"be","used","as","an","argument","here:"
3309 D.stack
3310 [ D.reflow $
3311 "Try renaming it to something else."
3312 , case keyword of
3313 "as" ->
3314 D.toFancyNote
3315 ["This","keyword","is","reserved","for","pattern","matches","like"
3316 ,"((x,y)",D.cyan "as","point)","where","you","want","to","name","a","tuple","and"
3317 ,"the","values","it","contains."
3320 _ ->
3321 D.toSimpleNote $
3322 "The `" ++ keyword ++ "` keyword has a special meaning in Elm, so it can only be used in certain situations."
3326 Code.Operator "->" ->
3327 let
3328 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3329 region = toWiderRegion row col 2
3330 in
3331 Report.Report "MISSING COLON?" region [] $
3332 Code.toSnippet source surroundings (Just region)
3334 D.reflow $
3335 "I was not expecting to see an arrow here:"
3337 D.stack
3338 [ D.fillSep
3339 ["This","usually","means","a",D.green ":","is","missing","a","bit","earlier","in"
3340 ,"a","type","annotation.","It","could","be","something","else","though,","so"
3341 ,"here","is","a","valid","definition","for","reference:"
3343 , D.indent 4 $ D.vcat $
3344 [ "greet : String -> String"
3345 , "greet name ="
3346 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
3348 , D.reflow $
3349 "Try to use that format with your `" ++ Name.toChars name ++ "` definition!"
3353 Code.Operator op ->
3354 let
3355 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3356 region = toKeywordRegion row col op
3357 in
3358 Report.Report "UNEXPECTED SYMBOL" region [] $
3359 Code.toSnippet source surroundings (Just region)
3361 D.reflow $
3362 "I was not expecting to see this symbol here:"
3364 D.stack
3365 [ D.reflow $
3366 "I am not sure what is going wrong exactly, so here is a valid\
3367 \ definition (with an optional type annotation) for reference:"
3368 , D.indent 4 $ D.vcat $
3369 [ "greet : String -> String"
3370 , "greet name ="
3371 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
3373 , D.reflow $
3374 "Try to use that format with your `" ++ Name.toChars name ++ "` definition!"
3378 _ ->
3379 let
3380 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3381 region = toRegion row col
3382 in
3383 Report.Report "PROBLEM IN DEFINITION" region [] $
3384 Code.toSnippet source surroundings (Just region)
3386 D.reflow $
3387 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
3389 D.stack
3390 [ D.reflow $
3391 "I am not sure what is going wrong exactly, so here is a valid\
3392 \ definition (with an optional type annotation) for reference:"
3393 , D.indent 4 $ D.vcat $
3394 [ "greet : String -> String"
3395 , "greet name ="
3396 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
3398 , D.reflow $
3399 "Try to use that format!"
3403 DefBody expr row col ->
3404 toExprReport source (InDef name startRow startCol) expr row col
3406 DefIndentEquals row col ->
3407 let
3408 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3409 region = toRegion row col
3410 in
3411 Report.Report "UNFINISHED DEFINITION" region [] $
3412 Code.toSnippet source surroundings (Just region)
3414 D.reflow $
3415 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
3417 D.stack
3418 [ D.reflow $
3419 "I was expecting to see an argument or an equals sign next."
3420 , defNote
3424 DefIndentType row col ->
3425 let
3426 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3427 region = toRegion row col
3428 in
3429 Report.Report "UNFINISHED DEFINITION" region [] $
3430 Code.toSnippet source surroundings (Just region)
3432 D.reflow $
3433 "I got stuck while parsing the `" ++ Name.toChars name ++ "` type annotation:"
3435 D.stack
3436 [ D.reflow $
3437 "I just saw a colon, so I am expecting to see a type next."
3438 , defNote
3442 DefIndentBody row col ->
3443 let
3444 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3445 region = toRegion row col
3446 in
3447 Report.Report "UNFINISHED DEFINITION" region [] $
3448 Code.toSnippet source surroundings (Just region)
3450 D.reflow $
3451 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
3453 D.stack
3454 [ D.reflow $
3455 "I was expecting to see an expression next. What is it equal to?"
3456 , declDefNote
3460 DefAlignment indent row col ->
3461 let
3462 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3463 region = toRegion row col
3464 offset = indent - col
3465 in
3466 Report.Report "PROBLEM IN 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.reflow $
3473 "I just saw a type annotation indented " ++ show indent ++ " spaces, so I was\
3474 \ expecting to see the corresponding definition next with the exact same amount\
3475 \ of indentation. It looks like this line needs "
3476 ++ show offset ++ " more " ++ (if offset == 1 then "space" else "spaces") ++ "?"
3481defNote :: D.Doc
3482defNote =
3483 D.stack
3484 [ D.reflow $
3485 "Here is a valid definition (with a type annotation) for reference:"
3486 , D.indent 4 $ D.vcat $
3487 [ "greet : String -> String"
3488 , "greet name ="
3489 , " " <> D.dullyellow "\"Hello \"" <> " ++ name ++ " <> D.dullyellow "\"!\""
3491 , D.reflow $
3492 "The top line (called a \"type annotation\") is optional. You can leave it off\
3493 \ if you want. As you get more comfortable with Elm and as your project grows,\
3494 \ it becomes more and more valuable to add them though! They work great as\
3495 \ compiler-verified documentation, and they often improve error messages!"
3499toLetDestructReport :: Code.Source -> Destruct -> Row -> Col -> Report.Report
3500toLetDestructReport source destruct startRow startCol =
3501 case destruct of
3502 DestructSpace space row col ->
3503 toSpaceReport source space row col
3505 DestructPattern pattern row col ->
3506 toPatternReport source PLet pattern row col
3508 DestructEquals row col ->
3509 let
3510 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3511 region = toRegion row col
3512 in
3513 Report.Report "PROBLEM IN DEFINITION" region [] $
3514 Code.toSnippet source surroundings (Just region)
3516 D.reflow $
3517 "I got stuck trying to parse this definition:"
3519 case Code.whatIsNext source row col of
3520 Code.Operator ":" ->
3521 D.stack
3522 [ D.reflow $
3523 "I was expecting to see an equals sign next, followed by an expression\
3524 \ telling me what to compute."
3525 , D.toSimpleNote $
3526 "It looks like you may be trying to write a type annotation? It is not\
3527 \ possible to add type annotations on destructuring definitions like this.\
3528 \ You can assign a name to the overall structure, put a type annotation on\
3529 \ that, and then destructure separately though."
3532 _ ->
3533 D.reflow $
3534 "I was expecting to see an equals sign next, followed by an expression\
3535 \ telling me what to compute."
3538 DestructBody expr row col ->
3539 toExprReport source (InDestruct startRow startCol) expr row col
3541 DestructIndentEquals row col ->
3542 let
3543 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3544 region = toRegion row col
3545 in
3546 Report.Report "UNFINISHED DEFINITION" region [] $
3547 Code.toSnippet source surroundings (Just region)
3549 D.reflow $
3550 "I got stuck trying to parse this definition:"
3552 D.reflow $
3553 "I was expecting to see an equals sign next, followed by an expression\
3554 \ telling me what to compute."
3557 DestructIndentBody row col ->
3558 let
3559 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3560 region = toRegion row col
3561 in
3562 Report.Report "UNFINISHED DEFINITION" region [] $
3563 Code.toSnippet source surroundings (Just region)
3565 D.reflow $
3566 "I got stuck while parsing this definition:"
3568 D.reflow $
3569 "I was expecting to see an expression next. What is it equal to?"
3574-- CASE
3577toCaseReport :: Code.Source -> Context -> Case -> Row -> Col -> Report.Report
3578toCaseReport source context case_ startRow startCol =
3579 case case_ of
3580 CaseSpace space row col ->
3581 toSpaceReport source space row col
3583 CaseOf row col ->
3584 toUnfinishCaseReport source row col startRow startCol $
3585 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
3587 CasePattern pattern row col ->
3588 toPatternReport source PCase pattern row col
3590 CaseArrow row col ->
3591 case Code.whatIsNext source row col of
3592 Code.Keyword keyword ->
3593 let
3594 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3595 region = toKeywordRegion row col keyword
3596 in
3597 Report.Report "RESERVED WORD" region [] $
3598 Code.toSnippet source surroundings (Just region)
3600 D.reflow $
3601 "I am partway through parsing a `case` expression, but I got stuck here:"
3603 D.reflow $
3604 "It looks like you are trying to use `" ++ keyword ++ "` in one of your\
3605 \ patterns, but it is a reserved word. Try using a different name?"
3608 Code.Operator ":" ->
3609 let
3610 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3611 region = toRegion row col
3612 in
3613 Report.Report "UNEXPECTED OPERATOR" region [] $
3614 Code.toSnippet source surroundings (Just region)
3616 D.reflow $
3617 "I am partway through parsing a `case` expression, but I got stuck here:"
3619 D.fillSep $
3620 ["I","am","seeing",D.dullyellow ":","but","maybe","you","want",D.green "::","instead?"
3621 ,"For","pattern","matching","on","lists?"
3625 Code.Operator "=" ->
3626 let
3627 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3628 region = toRegion row col
3629 in
3630 Report.Report "UNEXPECTED OPERATOR" region [] $
3631 Code.toSnippet source surroundings (Just region)
3633 D.reflow $
3634 "I am partway through parsing a `case` expression, but I got stuck here:"
3636 D.fillSep $
3637 ["I","am","seeing",D.dullyellow "=","but","maybe","you","want",D.green "->","instead?"
3641 _ ->
3642 let
3643 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3644 region = toRegion row col
3645 in
3646 Report.Report "MISSING ARROW" region [] $
3647 Code.toSnippet source surroundings (Just region)
3649 D.reflow $
3650 "I am partway through parsing a `case` expression, but I got stuck here:"
3652 D.stack
3653 [ D.reflow "I was expecting to see an arrow next."
3654 , noteForCaseIndentError
3658 CaseExpr expr row col ->
3659 toExprReport source (InNode NCase startRow startCol context) expr row col
3661 CaseBranch expr row col ->
3662 toExprReport source (InNode NBranch startRow startCol context) expr row col
3664 CaseIndentOf row col ->
3665 toUnfinishCaseReport source row col startRow startCol $
3666 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
3668 CaseIndentExpr row col ->
3669 toUnfinishCaseReport source row col startRow startCol $
3670 D.reflow "I was expecting to see a expression next."
3672 CaseIndentPattern row col ->
3673 toUnfinishCaseReport source row col startRow startCol $
3674 D.reflow "I was expecting to see a pattern next."
3676 CaseIndentArrow row col ->
3677 toUnfinishCaseReport source row col startRow startCol $
3678 D.fillSep
3679 ["I","just","saw","a","pattern,","so","I","was","expecting"
3680 ,"to","see","a",D.dullyellow "->","next."
3683 CaseIndentBranch row col ->
3684 toUnfinishCaseReport source row col startRow startCol $
3685 D.reflow $
3686 "I was expecting to see an expression next. What should I do when\
3687 \ I run into this particular pattern?"
3689 CasePatternAlignment indent row col ->
3690 toUnfinishCaseReport source row col startRow startCol $
3691 D.reflow $
3692 "I suspect this is a pattern that is not indented far enough? (" ++ show indent ++ " spaces)"
3695toUnfinishCaseReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
3696toUnfinishCaseReport source row col startRow startCol message =
3697 let
3698 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3699 region = toRegion row col
3700 in
3701 Report.Report "UNFINISHED CASE" region [] $
3702 Code.toSnippet source surroundings (Just region)
3704 D.reflow $
3705 "I was partway through parsing a `case` expression, but I got stuck here:"
3707 D.stack
3708 [ message
3709 , noteForCaseError
3714noteForCaseError :: D.Doc
3715noteForCaseError =
3716 D.stack
3717 [ D.toSimpleNote $
3718 "Here is an example of a valid `case` expression for reference."
3719 , D.vcat $
3720 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
3721 , D.indent 6 $ D.fillSep [D.blue "Just","width","->"]
3722 , D.indent 8 $ D.fillSep ["width","+",D.dullyellow "200"]
3723 , ""
3724 , D.indent 6 $ D.fillSep [D.blue "Nothing","->"]
3725 , D.indent 8 $ D.fillSep [D.dullyellow "400"]
3727 , D.reflow $
3728 "Notice the indentation. Each pattern is aligned, and each branch is indented\
3729 \ a bit more than the corresponding pattern. That is important!"
3733noteForCaseIndentError :: D.Doc
3734noteForCaseIndentError =
3735 D.stack
3736 [ D.toSimpleNote $
3737 "Sometimes I get confused by indentation, so try to make your `case` look\
3738 \ something like this:"
3739 , D.vcat $
3740 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
3741 , D.indent 6 $ D.fillSep [D.blue "Just","width","->"]
3742 , D.indent 8 $ D.fillSep ["width","+",D.dullyellow "200"]
3743 , ""
3744 , D.indent 6 $ D.fillSep [D.blue "Nothing","->"]
3745 , D.indent 8 $ D.fillSep [D.dullyellow "400"]
3747 , D.reflow $
3748 "Notice the indentation! Patterns are aligned with each other. Same indentation.\
3749 \ The expressions after each arrow are all indented a bit more than the patterns.\
3750 \ That is important!"
3755-- IF
3758toIfReport :: Code.Source -> Context -> If -> Row -> Col -> Report.Report
3759toIfReport source context if_ startRow startCol =
3760 case if_ of
3761 IfSpace space row col ->
3762 toSpaceReport source space row col
3764 IfThen row col ->
3765 let
3766 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3767 region = toRegion row col
3768 in
3769 Report.Report "UNFINISHED IF" region [] $
3770 Code.toSnippet source surroundings (Just region)
3772 D.reflow $
3773 "I was expecting to see more of this `if` expression, but I got stuck here:"
3775 D.fillSep $
3776 ["I","was","expecting","to","see","the",D.cyan "then","keyword","next."
3780 IfElse row col ->
3781 let
3782 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3783 region = toRegion row col
3784 in
3785 Report.Report "UNFINISHED IF" region [] $
3786 Code.toSnippet source surroundings (Just region)
3788 D.reflow $
3789 "I was expecting to see more of this `if` expression, but I got stuck here:"
3791 D.fillSep $
3792 ["I","was","expecting","to","see","the",D.cyan "else","keyword","next."
3796 IfElseBranchStart row col ->
3797 let
3798 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3799 region = toRegion row col
3800 in
3801 Report.Report "UNFINISHED IF" region [] $
3802 Code.toSnippet source surroundings (Just region)
3804 D.reflow $
3805 "I just saw the start of an `else` branch, but then I got stuck here:"
3807 D.reflow $
3808 "I was expecting to see an expression next. Maybe it is not filled in yet?"
3811 IfCondition expr row col ->
3812 toExprReport source (InNode NCond startRow startCol context) expr row col
3814 IfThenBranch expr row col ->
3815 toExprReport source (InNode NThen startRow startCol context) expr row col
3817 IfElseBranch expr row col ->
3818 toExprReport source (InNode NElse startRow startCol context) expr row col
3820 IfIndentCondition row col ->
3821 let
3822 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3823 region = toRegion row col
3824 in
3825 Report.Report "UNFINISHED IF" region [] $
3826 Code.toSnippet source surroundings (Just region)
3828 D.reflow $
3829 "I was expecting to see more of this `if` expression, but I got stuck here:"
3831 D.stack
3832 [ D.fillSep $
3833 ["I","was","expecting","to","see","an","expression","like",D.dullyellow "x < 0"
3834 ,"that","evaluates","to","True","or","False."
3836 , D.toSimpleNote $
3837 "I can be confused by indentation. Maybe something is not indented enough?"
3841 IfIndentThen row col ->
3842 let
3843 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3844 region = toRegion row col
3845 in
3846 Report.Report "UNFINISHED IF" region [] $
3847 Code.toSnippet source surroundings (Just region)
3849 D.reflow $
3850 "I was expecting to see more of this `if` expression, but I got stuck here:"
3852 D.stack
3853 [ D.fillSep $
3854 ["I","was","expecting","to","see","the",D.cyan "then","keyword","next."
3856 , D.toSimpleNote $
3857 "I can be confused by indentation. Maybe something is not indented enough?"
3861 IfIndentThenBranch row col ->
3862 let
3863 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3864 region = toRegion row col
3865 in
3866 Report.Report "UNFINISHED IF" region [] $
3867 Code.toSnippet source surroundings (Just region)
3869 D.reflow $
3870 "I got stuck after the start of this `then` branch:"
3872 D.stack
3873 [ D.reflow $
3874 "I was expecting to see an expression next. Maybe it is not filled in yet?"
3875 , D.toSimpleNote $
3876 "I can be confused by indentation, so if the `then` branch is already\
3877 \ present, it may not be indented enough for me to recognize it."
3881 IfIndentElseBranch row col ->
3882 let
3883 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3884 region = toRegion row col
3885 in
3886 Report.Report "UNFINISHED IF" region [] $
3887 Code.toSnippet source surroundings (Just region)
3889 D.reflow $
3890 "I got stuck after the start of this `else` branch:"
3892 D.stack
3893 [ D.reflow $
3894 "I was expecting to see an expression next. Maybe it is not filled in yet?"
3895 , D.toSimpleNote $
3896 "I can be confused by indentation, so if the `else` branch is already\
3897 \ present, it may not be indented enough for me to recognize it."
3901 IfIndentElse row col ->
3902 case Code.nextLineStartsWithKeyword "else" source row of
3903 Just (elseRow, elseCol) ->
3904 let
3905 surroundings = A.Region (A.Position startRow startCol) (A.Position elseRow elseCol)
3906 region = toWiderRegion elseRow elseCol 4
3907 in
3908 Report.Report "WEIRD ELSE BRANCH" region [] $
3909 Code.toSnippet source surroundings (Just region)
3911 D.reflow $
3912 "I was partway through an `if` expression when I got stuck here:"
3914 D.fillSep $
3915 ["I","think","this",D.cyan "else","keyword","needs","to","be","indented","more."
3916 ,"Try","adding","some","spaces","before","it."
3920 Nothing ->
3921 let
3922 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3923 region = toRegion row col
3924 in
3925 Report.Report "UNFINISHED IF" region [] $
3926 Code.toSnippet source surroundings (Just region)
3928 D.reflow $
3929 "I was expecting to see an `else` branch after this:"
3931 D.stack
3932 [ D.fillSep
3933 ["I","know","what","to","do","when","the","condition","is","True,"
3934 ,"but","what","happens","when","it","is","False?"
3935 ,"Add","an",D.cyan "else","branch","to","handle","that","scenario!"
3942-- RECORD
3945toRecordReport :: Code.Source -> Context -> Record -> Row -> Col -> Report.Report
3946toRecordReport source context record startRow startCol =
3947 case record of
3948 RecordOpen row col ->
3949 case Code.whatIsNext source row col of
3950 Code.Keyword keyword ->
3951 let
3952 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3953 region = toKeywordRegion row col keyword
3954 in
3955 Report.Report "RESERVED WORD" region [] $
3956 Code.toSnippet source surroundings (Just region)
3958 D.reflow $
3959 "I just started parsing a record, but I got stuck on this field name:"
3961 D.reflow $
3962 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
3963 \ that is a reserved word. Try using a different name!"
3966 _ ->
3967 let
3968 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3969 region = toRegion row col
3970 in
3971 Report.Report "PROBLEM IN RECORD" region [] $
3972 Code.toSnippet source surroundings (Just region)
3974 D.reflow $
3975 "I just started parsing a record, but I got stuck here:"
3977 D.stack
3978 [ D.fillSep
3979 ["I","was","expecting","to","see","a","record","field","defined","next,"
3980 ,"so","I","am","looking","for","a","name","like"
3981 ,D.dullyellow "userName","or",D.dullyellow "plantHeight" <> "."
3983 , D.toSimpleNote $
3984 "Field names must start with a lower-case letter. After that, you can use\
3985 \ any sequence of letters, numbers, and underscores."
3986 , noteForRecordError
3990 RecordEnd row col ->
3991 let
3992 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3993 region = toRegion row col
3994 in
3995 Report.Report "PROBLEM IN RECORD" region [] $
3996 Code.toSnippet source surroundings (Just region)
3998 D.reflow $
3999 "I am partway through parsing a record, but I got stuck here:"
4001 D.stack
4002 [ D.fillSep
4003 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
4004 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
4006 , D.toSimpleNote $
4007 "When I get stuck like this, it usually means that there is a missing parenthesis\
4008 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
4012 RecordField row col ->
4013 case Code.whatIsNext source row col of
4014 Code.Keyword keyword ->
4015 let
4016 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4017 region = toKeywordRegion row col keyword
4018 in
4019 Report.Report "RESERVED WORD" region [] $
4020 Code.toSnippet source surroundings (Just region)
4022 D.reflow $
4023 "I am partway through parsing a record, but I got stuck on this field name:"
4025 D.reflow $
4026 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
4027 \ that is a reserved word. Try using a different name!"
4030 Code.Other (Just ',') ->
4031 let
4032 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4033 region = toRegion row col
4034 in
4035 Report.Report "EXTRA COMMA" region [] $
4036 Code.toSnippet source surroundings (Just region)
4038 D.reflow $
4039 "I am partway through parsing a record, but I got stuck here:"
4041 D.stack
4042 [ D.reflow $
4043 "I am seeing two commas in a row. This is the second one!"
4044 , D.reflow $
4045 "Just delete one of the commas and you should be all set!"
4046 , noteForRecordError
4050 Code.Close _ '}' ->
4051 let
4052 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4053 region = toRegion row col
4054 in
4055 Report.Report "EXTRA COMMA" region [] $
4056 Code.toSnippet source surroundings (Just region)
4058 D.reflow $
4059 "I am partway through parsing a record, but I got stuck here:"
4061 D.stack
4062 [ D.reflow $
4063 "Trailing commas are not allowed in records. Try deleting the comma that appears\
4064 \ before this closing curly brace."
4065 , noteForRecordError
4069 _ ->
4070 let
4071 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4072 region = toRegion row col
4073 in
4074 Report.Report "PROBLEM IN RECORD" 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.fillSep
4082 ["I","was","expecting","to","see","another","record","field","defined","next,"
4083 ,"so","I","am","looking","for","a","name","like"
4084 ,D.dullyellow "userName","or",D.dullyellow "plantHeight" <> "."
4086 , D.toSimpleNote $
4087 "Field names must start with a lower-case letter. After that, you can use\
4088 \ any sequence of letters, numbers, and underscores."
4089 , noteForRecordError
4093 RecordEquals row col ->
4094 let
4095 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4096 region = toRegion row col
4097 in
4098 Report.Report "PROBLEM IN RECORD" region [] $
4099 Code.toSnippet source surroundings (Just region)
4101 D.reflow $
4102 "I am partway through parsing a record, but I got stuck here:"
4104 D.stack
4105 [ D.fillSep $
4106 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
4107 ,"an","equals","sign","next.","So","try","putting","an",D.green "=","sign","here?"
4109 , noteForRecordError
4113 RecordExpr expr row col ->
4114 toExprReport source (InNode NRecord startRow startCol context) expr row col
4116 RecordSpace space row col ->
4117 toSpaceReport source space row col
4119 RecordIndentOpen row col ->
4120 let
4121 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4122 region = toRegion row col
4123 in
4124 Report.Report "UNFINISHED RECORD" region [] $
4125 Code.toSnippet source surroundings (Just region)
4127 D.reflow $
4128 "I just saw the opening curly brace of a record, but then I got stuck here:"
4130 addNoteForRecordIndentError $
4131 D.fillSep $
4132 ["I","am","expecting","a","record","like",D.dullyellow "{ x = 3, y = 4 }","here."
4133 ,"Try","defining","some","fields","of","your","own?"
4137 RecordIndentEnd row col ->
4138 case Code.nextLineStartsWithCloseCurly source row of
4139 Just (curlyRow, curlyCol) ->
4140 let
4141 surroundings = A.Region (A.Position startRow startCol) (A.Position curlyRow curlyCol)
4142 region = toRegion curlyRow curlyCol
4143 in
4144 Report.Report "NEED MORE INDENTATION" region [] $
4145 Code.toSnippet source surroundings (Just region)
4147 D.reflow $
4148 "I was partway through parsing a record, but I got stuck here:"
4150 D.stack
4151 [ D.reflow $
4152 "I need this curly brace to be indented more. Try adding some spaces before it!"
4153 , noteForRecordError
4157 Nothing ->
4158 let
4159 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4160 region = toRegion row col
4161 in
4162 Report.Report "UNFINISHED RECORD" region [] $
4163 Code.toSnippet source surroundings (Just region)
4165 D.reflow $
4166 "I was partway through parsing a record, but I got stuck here:"
4168 addNoteForRecordIndentError $
4169 D.fillSep $
4170 ["I","was","expecting","to","see","a","closing","curly","brace","next."
4171 ,"Try","putting","a",D.green "}","next","and","see","if","that","helps?"
4175 RecordIndentField row col ->
4176 let
4177 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4178 region = toRegion row col
4179 in
4180 Report.Report "UNFINISHED RECORD" region [] $
4181 Code.toSnippet source surroundings (Just region)
4183 D.reflow $
4184 "I am partway through parsing a record, but I got stuck after that last comma:"
4186 D.stack
4187 [ D.reflow $
4188 "Trailing commas are not allowed in records, so the fix may be to\
4189 \ delete that last comma? Or maybe you were in the middle of defining\
4190 \ an additional field?"
4191 , noteForRecordError
4195 RecordIndentEquals row col ->
4196 let
4197 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4198 region = toRegion row col
4199 in
4200 Report.Report "UNFINISHED RECORD" region [] $
4201 Code.toSnippet source surroundings (Just region)
4203 D.reflow $
4204 "I am partway through parsing a record. I just saw a record\
4205 \ field, so I was expecting to see an equals sign next:"
4207 addNoteForRecordIndentError $
4208 D.fillSep $
4209 ["Try","putting","an",D.green "=","followed","by","an","expression?"
4213 RecordIndentExpr row col ->
4214 let
4215 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4216 region = toRegion row col
4217 in
4218 Report.Report "UNFINISHED RECORD" region [] $
4219 Code.toSnippet source surroundings (Just region)
4221 D.reflow $
4222 "I am partway through parsing a record, and I was expecting to run into an expression next:"
4224 addNoteForRecordIndentError $
4225 D.fillSep $
4226 ["Try","putting","something","like"
4227 ,D.dullyellow "42","or",D.dullyellow"\"hello\"","for","now?"
4232noteForRecordError :: D.Doc
4233noteForRecordError =
4234 D.stack $
4235 [ D.toSimpleNote
4236 "If you are trying to define a record across multiple lines, I recommend using this format:"
4237 , D.indent 4 $ D.vcat $
4238 [ "{ name = " <> D.dullyellow "\"Alice\""
4239 , ", age = " <> D.dullyellow "42"
4240 , ", height = " <> D.dullyellow "1.75"
4241 , "}"
4243 , D.reflow $
4244 "Notice that each line starts with some indentation. Usually two or four spaces.\
4245 \ This is the stylistic convention in the Elm ecosystem."
4249addNoteForRecordIndentError :: D.Doc -> D.Doc
4250addNoteForRecordIndentError normalRecommendation =
4251 D.stack $
4252 normalRecommendation
4254 [ D.toSimpleNote
4255 "I may be confused by indentation. For example, if you are trying to define\
4256 \ a record across multiple lines, I recommend using this format:"
4257 , D.indent 4 $ D.vcat $
4258 [ "{ name = " <> D.dullyellow "\"Alice\""
4259 , ", age = " <> D.dullyellow "42"
4260 , ", height = " <> D.dullyellow "1.75"
4261 , "}"
4263 , D.reflow $
4264 "Notice that each line starts with some indentation. Usually two or four spaces.\
4265 \ This is the stylistic convention in the Elm ecosystem!"
4270-- TUPLE
4273toTupleReport :: Code.Source -> Context -> Tuple -> Row -> Col -> Report.Report
4274toTupleReport source context tuple startRow startCol =
4275 case tuple of
4276 TupleExpr expr row col ->
4277 toExprReport source (InNode NParens startRow startCol context) expr row col
4279 TupleSpace space row col ->
4280 toSpaceReport source space row col
4282 TupleEnd row col ->
4283 let
4284 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4285 region = toRegion row col
4286 in
4287 Report.Report "UNFINISHED PARENTHESES" region [] $
4288 Code.toSnippet source surroundings (Just region)
4290 D.reflow $
4291 "I was expecting to see a closing parentheses next, but I got stuck here:"
4293 D.stack
4294 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
4295 , D.toSimpleNote $
4296 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
4297 \ unexpectedly. So there may be some earlier syntax trouble (like extra parenthesis\
4298 \ or missing brackets) that is confusing me."
4302 TupleOperatorClose row col ->
4303 let
4304 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4305 region = toRegion row col
4306 in
4307 Report.Report "UNFINISHED OPERATOR FUNCTION" region [] $
4308 Code.toSnippet source surroundings (Just region)
4310 D.reflow "I was expecting a closing parenthesis here:"
4312 D.stack
4313 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
4314 , D.toSimpleNote $
4315 "I think I am parsing an operator function right now, so I am expecting to see\
4316 \ something like (+) or (&&) where an operator is surrounded by parentheses with\
4317 \ no extra spaces."
4321 TupleOperatorReserved operator row col ->
4322 let
4323 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4324 region = toRegion row col
4325 in
4326 Report.Report "UNEXPECTED SYMBOL" region [] $
4327 Code.toSnippet source surroundings (Just region)
4329 D.reflow $
4330 "I ran into an unexpected symbol here:"
4332 D.fillSep $
4333 case operator of
4334 BadDot -> ["Maybe","you","wanted","a","record","accessor","like",D.dullyellow ".x","or",D.dullyellow ".name","instead?"]
4335 BadPipe -> ["Try",D.dullyellow "(||)","instead?","To","turn","boolean","OR","into","a","function?"]
4336 BadArrow -> ["Maybe","you","wanted",D.dullyellow "(>)","or",D.dullyellow "(>=)","instead?"]
4337 BadEquals -> ["Try",D.dullyellow "(==)","instead?","To","make","a","function","that","checks","equality?"]
4338 BadHasType -> ["Try",D.dullyellow "(::)","instead?","To","add","values","to","the","front","of","lists?"]
4341 TupleIndentExpr1 row col ->
4342 let
4343 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4344 region = toRegion row col
4345 in
4346 Report.Report "UNFINISHED PARENTHESES" region [] $
4347 Code.toSnippet source surroundings (Just region)
4349 D.reflow $
4350 "I just saw an open parenthesis, so I was expecting to see an expression next."
4352 D.stack
4353 [ D.fillSep $
4354 ["Something","like",D.dullyellow "(4 + 5)","or"
4355 ,D.dullyellow "(String.reverse \"desserts\")" <> "."
4356 ,"Anything","where","you","are","putting","parentheses","around","normal","expressions."
4358 , D.toSimpleNote $
4359 "I can get confused by indentation in cases like this, so\
4360 \ maybe you have an expression but it is not indented enough?"
4364 TupleIndentExprN row col ->
4365 let
4366 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4367 region = toRegion row col
4368 in
4369 Report.Report "UNFINISHED TUPLE" region [] $
4370 Code.toSnippet source surroundings (Just region)
4372 D.reflow $
4373 "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."
4375 D.stack
4376 [ D.fillSep $
4377 ["A","tuple","looks","like",D.dullyellow "(3,4)","or"
4378 ,D.dullyellow "(\"Tom\",42)" <> ","
4379 ,"so","I","think","there","is","an","expression","missing","here?"
4381 , D.toSimpleNote $
4382 "I can get confused by indentation in cases like this, so\
4383 \ maybe you have an expression but it is not indented enough?"
4387 TupleIndentEnd row col ->
4388 let
4389 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4390 region = toRegion row col
4391 in
4392 Report.Report "UNFINISHED PARENTHESES" region [] $
4393 Code.toSnippet source surroundings (Just region)
4395 D.reflow $
4396 "I was expecting to see a closing parenthesis next:"
4398 D.stack
4399 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
4400 , D.toSimpleNote $
4401 "I can get confused by indentation in cases like this, so\
4402 \ maybe you have a closing parenthesis but it is not indented enough?"
4407toListReport :: Code.Source -> Context -> List -> Row -> Col -> Report.Report
4408toListReport source context list startRow startCol =
4409 case list of
4410 ListSpace space row col ->
4411 toSpaceReport source space row col
4413 ListOpen row col ->
4414 let
4415 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4416 region = toRegion row col
4417 in
4418 Report.Report "UNFINISHED LIST" region [] $
4419 Code.toSnippet source surroundings (Just region)
4421 D.reflow $
4422 "I am partway through parsing a list, but I got stuck here:"
4424 D.stack
4425 [ D.fillSep
4426 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
4427 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
4429 , D.toSimpleNote $
4430 "When I get stuck like this, it usually means that there is a missing parenthesis\
4431 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
4435 ListExpr expr row col ->
4436 case expr of
4437 Start r c ->
4438 let
4439 surroundings = A.Region (A.Position startRow startCol) (A.Position r c)
4440 region = toRegion r c
4441 in
4442 Report.Report "UNFINISHED LIST" region [] $
4443 Code.toSnippet source surroundings (Just region)
4445 D.reflow $
4446 "I was expecting to see another list entry after that last comma:"
4448 D.stack
4449 [ D.reflow $
4450 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
4451 , D.toSimpleNote
4452 "I recommend using the following format for lists that span multiple lines:"
4453 , D.indent 4 $ D.vcat $
4454 [ "[ " <> D.dullyellow "\"Alice\""
4455 , ", " <> D.dullyellow "\"Bob\""
4456 , ", " <> D.dullyellow "\"Chuck\""
4457 , "]"
4459 , D.reflow $
4460 "Notice that each line starts with some indentation. Usually two or four spaces.\
4461 \ This is the stylistic convention in the Elm ecosystem."
4465 _ ->
4466 toExprReport source (InNode NList startRow startCol context) expr row col
4468 ListEnd row col ->
4469 let
4470 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4471 region = toRegion row col
4472 in
4473 Report.Report "UNFINISHED LIST" region [] $
4474 Code.toSnippet source surroundings (Just region)
4476 D.reflow $
4477 "I am partway through parsing a list, but I got stuck here:"
4479 D.stack
4480 [ D.fillSep
4481 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
4482 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
4484 , D.toSimpleNote $
4485 "When I get stuck like this, it usually means that there is a missing parenthesis\
4486 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
4490 ListIndentOpen row col ->
4491 let
4492 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4493 region = toRegion row col
4494 in
4495 Report.Report "UNFINISHED LIST" region [] $
4496 Code.toSnippet source surroundings (Just region)
4498 D.reflow $
4499 "I cannot find the end of this list:"
4501 D.stack
4502 [ D.fillSep $
4503 ["You","could","change","it","to","something","like"
4504 ,D.dullyellow "[3,4,5]"
4505 ,"or","even","just"
4506 ,D.dullyellow "[]" <> "."
4507 ,"Anything","where","there","is","an","open","and","close","square","brace,"
4508 ,"and","where","the","elements","of","the","list","are","separated","by","commas."
4510 , D.toSimpleNote
4511 "I may be confused by indentation. For example, if you are trying to define\
4512 \ a list across multiple lines, I recommend using this format:"
4513 , D.indent 4 $ D.vcat $
4514 [ "[ " <> D.dullyellow "\"Alice\""
4515 , ", " <> D.dullyellow "\"Bob\""
4516 , ", " <> D.dullyellow "\"Chuck\""
4517 , "]"
4519 , D.reflow $
4520 "Notice that each line starts with some indentation. Usually two or four spaces.\
4521 \ This is the stylistic convention in the Elm ecosystem."
4525 ListIndentEnd row col ->
4526 let
4527 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4528 region = toRegion row col
4529 in
4530 Report.Report "UNFINISHED LIST" region [] $
4531 Code.toSnippet source surroundings (Just region)
4533 D.reflow $
4534 "I cannot find the end of this list:"
4536 D.stack
4537 [ D.fillSep $
4538 ["You","can","just","add","a","closing",D.dullyellow "]"
4539 ,"right","here,","and","I","will","be","all","set!"
4541 , D.toSimpleNote
4542 "I may be confused by indentation. For example, if you are trying to define\
4543 \ a list across multiple lines, I recommend using this format:"
4544 , D.indent 4 $ D.vcat $
4545 [ "[ " <> D.dullyellow "\"Alice\""
4546 , ", " <> D.dullyellow "\"Bob\""
4547 , ", " <> D.dullyellow "\"Chuck\""
4548 , "]"
4550 , D.reflow $
4551 "Notice that each line starts with some indentation. Usually two or four spaces.\
4552 \ This is the stylistic convention in the Elm ecosystem."
4556 ListIndentExpr row col ->
4557 let
4558 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4559 region = toRegion row col
4560 in
4561 Report.Report "UNFINISHED LIST" region [] $
4562 Code.toSnippet source surroundings (Just region)
4564 D.reflow $
4565 "I was expecting to see another list entry after this comma:"
4567 D.stack
4568 [ D.reflow $
4569 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
4570 , D.toSimpleNote
4571 "I recommend using the following format for lists that span multiple lines:"
4572 , D.indent 4 $ D.vcat $
4573 [ "[ " <> D.dullyellow "\"Alice\""
4574 , ", " <> D.dullyellow "\"Bob\""
4575 , ", " <> D.dullyellow "\"Chuck\""
4576 , "]"
4578 , D.reflow $
4579 "Notice that each line starts with some indentation. Usually two or four spaces.\
4580 \ This is the stylistic convention in the Elm ecosystem."
4585toFuncReport :: Code.Source -> Context -> Func -> Row -> Col -> Report.Report
4586toFuncReport source context func startRow startCol =
4587 case func of
4588 FuncSpace space row col ->
4589 toSpaceReport source space row col
4591 FuncArg pattern row col ->
4592 toPatternReport source PArg pattern row col
4594 FuncBody expr row col ->
4595 toExprReport source (InNode NFunc startRow startCol context) expr row col
4597 FuncArrow row col ->
4598 case Code.whatIsNext source row col of
4599 Code.Keyword keyword ->
4600 let
4601 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4602 region = toKeywordRegion row col keyword
4603 in
4604 Report.Report "RESERVED WORD" region [] $
4605 Code.toSnippet source surroundings (Just region)
4607 D.reflow $
4608 "I was parsing an anonymous function, but I got stuck here:"
4610 D.reflow $
4611 "It looks like you are trying to use `" ++ keyword ++ "` as an argument, but\
4612 \ it is a reserved word in this language. Try using a different argument name!"
4615 _ ->
4616 let
4617 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4618 region = toRegion row col
4619 in
4620 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
4621 Code.toSnippet source surroundings (Just region)
4623 D.reflow $
4624 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
4626 D.fillSep $
4627 ["The","syntax","for","anonymous","functions","is"
4628 ,D.dullyellow "(\\x -> x + 1)"
4629 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
4633 FuncIndentArg row col ->
4634 let
4635 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4636 region = toRegion row col
4637 in
4638 Report.Report "MISSING ARGUMENT" region [] $
4639 Code.toSnippet source surroundings (Just region)
4641 D.reflow $
4642 "I just saw the beginning of an anonymous function, so I was expecting to see an argument next:"
4644 D.stack
4645 [ D.fillSep
4646 ["Something","like",D.dullyellow"x","or",D.dullyellow "name" <> "."
4647 ,"Anything","that","starts","with","a","lower","case","letter!"
4649 , D.toSimpleNote $
4650 "The syntax for anonymous functions is (\\x -> x + 1) where the backslash\
4651 \ is meant to look a bit like a lambda if you squint. This visual pun seemed\
4652 \ like a better idea at the time!"
4656 FuncIndentArrow row col ->
4657 let
4658 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4659 region = toRegion row col
4660 in
4661 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
4662 Code.toSnippet source surroundings (Just region)
4664 D.reflow $
4665 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
4667 D.stack
4668 [ D.fillSep $
4669 ["The","syntax","for","anonymous","functions","is"
4670 ,D.dullyellow "(\\x -> x + 1)"
4671 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
4673 , D.toSimpleNote $
4674 "It is possible that I am confused about indetation! I generally recommend\
4675 \ switching to named functions if the definition cannot fit inline nicely, so\
4676 \ either (1) try to fit the whole anonymous function on one line or (2) break\
4677 \ the whole thing out into a named function. Things tend to be clearer that way!"
4681 FuncIndentBody 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 was expecting to see the body of your anonymous function 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","all","the","stuff","after","the","arrow!"
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!"
4708-- PATTERN
4711data PContext
4712 = PCase
4713 | PArg
4714 | PLet
4717toPatternReport :: Code.Source -> PContext -> Pattern -> Row -> Col -> Report.Report
4718toPatternReport source context pattern startRow startCol =
4719 case pattern of
4720 PRecord record row col ->
4721 toPRecordReport source record row col
4723 PTuple tuple row col ->
4724 toPTupleReport source context tuple row col
4726 PList list row col ->
4727 toPListReport source context list row col
4729 PStart row col ->
4730 case Code.whatIsNext source row col of
4731 Code.Keyword keyword ->
4732 let
4733 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4734 region = toKeywordRegion row col keyword
4735 inThisThing =
4736 case context of
4737 PArg -> "as an argument"
4738 PCase -> "in this pattern"
4739 PLet -> "in this pattern"
4740 in
4741 Report.Report "RESERVED WORD" region [] $
4742 Code.toSnippet source surroundings (Just region)
4744 D.reflow $
4745 "It looks like you are trying to use `" ++ keyword ++ "` " ++ inThisThing ++ ":"
4747 D.reflow $
4748 "This is a reserved word! Try using some other name?"
4751 Code.Operator "-" ->
4752 let
4753 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4754 region = toRegion row col
4755 in
4756 Report.Report "UNEXPECTED SYMBOL" region [] $
4757 Code.toSnippet source surroundings (Just region)
4759 D.reflow $
4760 "I ran into a minus sign unexpectedly in this pattern:"
4762 D.reflow $
4763 "It is not possible to pattern match on negative numbers at this\
4764 \ time. Try using an `if` expression for that sort of thing for now."
4767 _ ->
4768 let
4769 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4770 region = toRegion row col
4771 in
4772 Report.Report "PROBLEM IN PATTERN" region [] $
4773 Code.toSnippet source surroundings (Just region)
4775 D.reflow $
4776 "I wanted to parse a pattern next, but I got stuck here:"
4778 D.fillSep $
4779 ["I","am","not","sure","why","I","am","getting","stuck","exactly."
4780 ,"I","just","know","that","I","want","a","pattern","next."
4781 ,"Something","as","simple","as"
4782 ,D.dullyellow "maybeHeight","or",D.dullyellow "result"
4783 ,"would","work!"
4787 PChar char row col ->
4788 toCharReport source char row col
4790 PString string row col ->
4791 toStringReport source string row col
4793 PNumber number row col ->
4794 toNumberReport source number row col
4796 PFloat width row col ->
4797 let
4798 region = toWiderRegion row col width
4799 in
4800 Report.Report "UNEXPECTED PATTERN" region [] $
4801 Code.toSnippet source region Nothing
4803 D.reflow $
4804 "I cannot pattern match with floating point numbers:"
4806 D.fillSep $
4807 ["Equality","on","floats","can","be","unreliable,","so","you","usually","want"
4808 ,"to","check","that","they","are","nearby","with","some","sort","of"
4809 ,D.dullyellow "(abs (actual - expected) < 0.001)","check."
4813 PAlias row col ->
4814 let
4815 region = toRegion row col
4816 in
4817 Report.Report "UNFINISHED PATTERN" region [] $
4818 Code.toSnippet source region Nothing $
4820 D.reflow $
4821 "I was expecting to see a variable name after the `as` keyword:"
4823 D.stack
4824 [ D.fillSep $
4825 ["The","`as`","keyword","lets","you","write","patterns","like"
4826 ,"((" <> D.dullyellow "x" <> "," <> D.dullyellow "y" <> ") " <> D.cyan "as" <> D.dullyellow " point" <> ")"
4827 ,"so","you","can","refer","to","individual","parts","of","the","tuple","with"
4828 ,D.dullyellow "x","and",D.dullyellow "y","or","you","refer","to","the","whole"
4829 ,"thing","with",D.dullyellow "point" <> "."
4831 , D.reflow $
4832 "So I was expecting to see a variable name after the `as` keyword here. Sometimes\
4833 \ people just want to use `as` as a variable name though. Try using a different name\
4834 \ in that case!"
4838 PWildcardNotVar name width row col ->
4839 let
4840 region = toWiderRegion row col (fromIntegral width)
4841 examples =
4842 case dropWhile (=='_') (Name.toChars name) of
4843 [] -> [D.dullyellow "x","or",D.dullyellow "age"]
4844 c:cs -> [D.dullyellow (D.fromChars (Char.toLower c : cs))]
4845 in
4846 Report.Report "UNEXPECTED NAME" region [] $
4847 Code.toSnippet source region Nothing $
4849 D.reflow $
4850 "Variable names cannot start with underscores like this:"
4852 D.fillSep $
4853 ["You","can","either","have","an","underscore","like",D.dullyellow "_","to"
4854 ,"ignore","the","value,","or","you","can","have","a","name","like"
4855 ] ++ examples ++ ["to","use","the","matched","value." ]
4858 PSpace space row col ->
4859 toSpaceReport source space row col
4861 PIndentStart row col ->
4862 let
4863 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4864 region = toRegion row col
4865 in
4866 Report.Report "UNFINISHED PATTERN" region [] $
4867 Code.toSnippet source surroundings (Just region)
4869 D.reflow $
4870 "I wanted to parse a pattern next, but I got stuck here:"
4872 D.stack
4873 [ D.fillSep $
4874 ["I","am","not","sure","why","I","am","getting","stuck","exactly."
4875 ,"I","just","know","that","I","want","a","pattern","next."
4876 ,"Something","as","simple","as"
4877 ,D.dullyellow "maybeHeight","or",D.dullyellow "result"
4878 ,"would","work!"
4880 , D.toSimpleNote $
4881 "I can get confused by indentation. If you think there is a pattern next, maybe\
4882 \ it needs to be indented a bit more?"
4886 PIndentAlias row col ->
4887 let
4888 region = toRegion row col
4889 in
4890 Report.Report "UNFINISHED PATTERN" region [] $
4891 Code.toSnippet source region Nothing $
4893 D.reflow $
4894 "I was expecting to see a variable name after the `as` keyword:"
4896 D.stack
4897 [ D.fillSep $
4898 ["The","`as`","keyword","lets","you","write","patterns","like"
4899 ,"((" <> D.dullyellow "x" <> "," <> D.dullyellow "y" <> ") " <> D.cyan "as" <> D.dullyellow " point" <> ")"
4900 ,"so","you","can","refer","to","individual","parts","of","the","tuple","with"
4901 ,D.dullyellow "x","and",D.dullyellow "y","or","you","refer","to","the","whole"
4902 ,"thing","with",D.dullyellow "point."
4904 , D.reflow $
4905 "So I was expecting to see a variable name after the `as` keyword here. Sometimes\
4906 \ people just want to use `as` as a variable name though. Try using a different name\
4907 \ in that case!"
4912toPRecordReport :: Code.Source -> PRecord -> Row -> Col -> Report.Report
4913toPRecordReport source record startRow startCol =
4914 case record of
4915 PRecordOpen row col ->
4916 toUnfinishRecordPatternReport source row col startRow startCol $
4917 D.reflow "I was expecting to see a field name next."
4919 PRecordEnd row col ->
4920 toUnfinishRecordPatternReport source row col startRow startCol $
4921 D.fillSep
4922 ["I","was","expecting","to","see","a","closing","curly","brace","next."
4923 ,"Try","adding","a",D.dullyellow "}","here?"
4926 PRecordField row col ->
4927 case Code.whatIsNext source row col of
4928 Code.Keyword keyword ->
4929 let
4930 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4931 region = toKeywordRegion row col keyword
4932 in
4933 Report.Report "RESERVED WORD" region [] $
4934 Code.toSnippet source surroundings (Just region)
4936 D.reflow $
4937 "I was not expecting to see `" ++ keyword ++ "` as a record field name:"
4939 D.reflow $
4940 "This is a reserved word, not available for variable names. Try another name!"
4943 _ ->
4944 toUnfinishRecordPatternReport source row col startRow startCol $
4945 D.reflow "I was expecting to see a field name next."
4947 PRecordSpace space row col ->
4948 toSpaceReport source space row col
4950 PRecordIndentOpen row col ->
4951 toUnfinishRecordPatternReport source row col startRow startCol $
4952 D.reflow "I was expecting to see a field name next."
4954 PRecordIndentEnd row col ->
4955 toUnfinishRecordPatternReport source row col startRow startCol $
4956 D.fillSep
4957 ["I","was","expecting","to","see","a","closing","curly","brace","next."
4958 ,"Try","adding","a",D.dullyellow "}","here?"
4961 PRecordIndentField row col ->
4962 toUnfinishRecordPatternReport source row col startRow startCol $
4963 D.reflow "I was expecting to see a field name next."
4966toUnfinishRecordPatternReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
4967toUnfinishRecordPatternReport source row col startRow startCol message =
4968 let
4969 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4970 region = toRegion row col
4971 in
4972 Report.Report "UNFINISHED RECORD PATTERN" region [] $
4973 Code.toSnippet source surroundings (Just region)
4975 D.reflow $
4976 "I was partway through parsing a record pattern, but I got stuck here:"
4978 D.stack
4979 [ message
4980 , D.toFancyHint $
4981 ["A","record","pattern","looks","like",D.dullyellow "{x,y}","or",D.dullyellow "{name,age}"
4982 ,"where","you","list","the","field","names","you","want","to","access."
4989toPTupleReport :: Code.Source -> PContext -> PTuple -> Row -> Col -> Report.Report
4990toPTupleReport source context tuple startRow startCol =
4991 case tuple of
4992 PTupleOpen row col ->
4993 case Code.whatIsNext source row col of
4994 Code.Keyword keyword ->
4995 let
4996 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4997 region = toKeywordRegion row col keyword
4998 in
4999 Report.Report "RESERVED WORD" region [] $
5000 Code.toSnippet source surroundings (Just region)
5002 D.reflow $
5003 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name:"
5005 D.reflow $
5006 "This is a reserved word! Try using some other name?"
5009 _ ->
5010 let
5011 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5012 region = toRegion row col
5013 in
5014 Report.Report "UNFINISHED PARENTHESES" region [] $
5015 Code.toSnippet source surroundings (Just region)
5017 D.reflow $
5018 "I just saw an open parenthesis, but I got stuck here:"
5020 D.fillSep
5021 ["I","was","expecting","to","see","a","pattern","next."
5022 ,"Maybe","it","will","end","up","being","something"
5023 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "?"
5027 PTupleEnd row col ->
5028 case Code.whatIsNext source row col of
5029 Code.Keyword keyword ->
5030 let
5031 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5032 region = toKeywordRegion row col keyword
5033 in
5034 Report.Report "RESERVED WORD" region [] $
5035 Code.toSnippet source surroundings (Just region) $
5037 D.reflow $
5038 "I ran into a reserved word in this pattern:"
5040 D.reflow $
5041 "The `" ++ keyword ++ "` keyword is reserved. Try using a different name instead!"
5044 Code.Operator op ->
5045 let
5046 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5047 region = toKeywordRegion row col op
5048 in
5049 Report.Report "UNEXPECTED SYMBOL" region [] $
5050 Code.toSnippet source surroundings (Just region) $
5052 D.reflow $
5053 "I ran into the " ++ op ++ " symbol unexpectedly in this pattern:"
5055 D.reflow $
5056 "Only the :: symbol that works in patterns. It is useful if you\
5057 \ are pattern matching on lists, trying to get the first element\
5058 \ off the front. Did you want that instead?"
5061 Code.Close term bracket ->
5062 let
5063 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5064 region = toRegion row col
5065 in
5066 Report.Report ("STRAY " ++ map Char.toUpper term) region [] $
5067 Code.toSnippet source surroundings (Just region) $
5069 D.reflow $
5070 "I ran into a an unexpected " ++ term ++ " in this pattern:"
5072 D.reflow $
5073 "This " ++ bracket : " does not match up with an earlier open " ++ term ++ ". Try deleting it?"
5076 _ ->
5077 let
5078 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5079 region = toRegion row col
5080 in
5081 Report.Report "UNFINISHED PARENTHESES" region [] $
5082 Code.toSnippet source surroundings (Just region) $
5084 D.reflow $
5085 "I was partway through parsing a pattern, but I got stuck here:"
5087 D.fillSep
5088 ["I","was","expecting","a","closing","parenthesis","next,","so"
5089 ,"try","adding","a",D.dullyellow ")","to","see","if","that","helps?"
5093 PTupleExpr pattern row col ->
5094 toPatternReport source context pattern row col
5096 PTupleSpace space row col ->
5097 toSpaceReport source space row col
5099 PTupleIndentEnd row col ->
5100 let
5101 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5102 region = toRegion row col
5103 in
5104 Report.Report "UNFINISHED PARENTHESES" region [] $
5105 Code.toSnippet source surroundings (Just region) $
5107 D.reflow $
5108 "I was expecting a closing parenthesis next:"
5110 D.stack
5111 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
5112 , D.toSimpleNote $
5113 "I can get confused by indentation in cases like this, so\
5114 \ maybe you have a closing parenthesis but it is not indented enough?"
5118 PTupleIndentExpr1 row col ->
5119 let
5120 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5121 region = toRegion row col
5122 in
5123 Report.Report "UNFINISHED PARENTHESES" region [] $
5124 Code.toSnippet source surroundings (Just region) $
5126 D.reflow $
5127 "I just saw an open parenthesis, but then I got stuck here:"
5129 D.fillSep
5130 ["I","was","expecting","to","see","a","pattern","next."
5131 ,"Maybe","it","will","end","up","being","something"
5132 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "?"
5136 PTupleIndentExprN row col ->
5137 let
5138 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5139 region = toRegion row col
5140 in
5141 Report.Report "UNFINISHED TUPLE PATTERN" region [] $
5142 Code.toSnippet source surroundings (Just region) $
5144 D.reflow $
5145 "I am partway through parsing a tuple pattern, but I got stuck here:"
5147 D.stack
5148 [ D.fillSep
5149 ["I","was","expecting","to","see","a","pattern","next."
5150 ,"I","am","expecting","the","final","result","to","be","something"
5151 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "."
5153 , D.toSimpleNote $
5154 "I can get confused by indentation in cases like this, so the problem\
5155 \ may be that the next part is not indented enough?"
5160toPListReport :: Code.Source -> PContext -> PList -> Row -> Col -> Report.Report
5161toPListReport source context list startRow startCol =
5162 case list of
5163 PListOpen row col ->
5164 case Code.whatIsNext source row col of
5165 Code.Keyword keyword ->
5166 let
5167 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5168 region = toKeywordRegion row col keyword
5169 in
5170 Report.Report "RESERVED WORD" region [] $
5171 Code.toSnippet source surroundings (Just region)
5173 D.reflow $
5174 "It looks like you are trying to use `" ++ keyword ++ "` to name an element of a list:"
5176 D.reflow $
5177 "This is a reserved word though! Try using some other name?"
5180 _ ->
5181 let
5182 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5183 region = toRegion row col
5184 in
5185 Report.Report "UNFINISHED LIST PATTERN" region [] $
5186 Code.toSnippet source surroundings (Just region) $
5188 D.reflow $
5189 "I just saw an open square bracket, but then I got stuck here:"
5191 D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
5194 PListEnd row col ->
5195 let
5196 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5197 region = toRegion row col
5198 in
5199 Report.Report "UNFINISHED LIST PATTERN" region [] $
5200 Code.toSnippet source surroundings (Just region) $
5202 D.reflow $
5203 "I was expecting a closing square bracket to end this list pattern:"
5205 D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
5208 PListExpr pattern row col ->
5209 toPatternReport source context pattern row col
5211 PListSpace space row col ->
5212 toSpaceReport source space row col
5214 PListIndentOpen row col ->
5215 let
5216 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5217 region = toRegion row col
5218 in
5219 Report.Report "UNFINISHED LIST PATTERN" region [] $
5220 Code.toSnippet source surroundings (Just region) $
5222 D.reflow $
5223 "I just saw an open square bracket, but then I got stuck here:"
5225 D.stack
5226 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
5227 , D.toSimpleNote $
5228 "I can get confused by indentation in cases like this, so\
5229 \ maybe there is something next, but it is not indented enough?"
5233 PListIndentEnd row col ->
5234 let
5235 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5236 region = toRegion row col
5237 in
5238 Report.Report "UNFINISHED LIST PATTERN" region [] $
5239 Code.toSnippet source surroundings (Just region) $
5241 D.reflow $
5242 "I was expecting a closing square bracket to end this list pattern:"
5244 D.stack
5245 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
5246 , D.toSimpleNote $
5247 "I can get confused by indentation in cases like this, so\
5248 \ maybe you have a closing square bracket but it is not indented enough?"
5252 PListIndentExpr row col ->
5253 let
5254 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5255 region = toRegion row col
5256 in
5257 Report.Report "UNFINISHED LIST PATTERN" region [] $
5258 Code.toSnippet source surroundings (Just region) $
5260 D.reflow $
5261 "I am partway through parsing a list pattern, but I got stuck here:"
5263 D.stack
5264 [ D.reflow $
5265 "I was expecting to see another pattern next. Maybe a variable name."
5266 , D.toSimpleNote $
5267 "I can get confused by indentation in cases like this, so\
5268 \ maybe there is more to this pattern but it is not indented enough?"
5274-- TYPES
5277data TContext
5278 = TC_Annotation Name.Name
5279 | TC_CustomType
5280 | TC_TypeAlias
5281 | TC_Port
5284toTypeReport :: Code.Source -> TContext -> Type -> Row -> Col -> Report.Report
5285toTypeReport source context tipe startRow startCol =
5286 case tipe of
5287 TRecord record row col ->
5288 toTRecordReport source context record row col
5290 TTuple tuple row col ->
5291 toTTupleReport source context tuple row col
5293 TStart row col ->
5294 case Code.whatIsNext source row col of
5295 Code.Keyword keyword ->
5296 let
5297 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5298 region = toKeywordRegion row col keyword
5299 in
5300 Report.Report "RESERVED WORD" region [] $
5301 Code.toSnippet source surroundings (Just region)
5303 D.reflow $
5304 "I was expecting to see a type next, but I got stuck on this reserved word:"
5306 D.reflow $
5307 "It looks like you are trying to use `" ++ keyword ++ "` as a type variable, but \
5308 \ it is a reserved word. Try using a different name!"
5311 _ ->
5312 let
5313 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5314 region = toRegion row col
5316 thing =
5317 case context of
5318 TC_Annotation _ -> "type annotation"
5319 TC_CustomType -> "custom type"
5320 TC_TypeAlias -> "type alias"
5321 TC_Port -> "port"
5323 something =
5324 case context of
5325 TC_Annotation name -> "the `" ++ Name.toChars name ++ "` type annotation"
5326 TC_CustomType -> "a custom type"
5327 TC_TypeAlias -> "a type alias"
5328 TC_Port -> "a port"
5329 in
5330 Report.Report ("PROBLEM IN " ++ map Char.toUpper thing) region [] $
5331 Code.toSnippet source surroundings (Just region)
5333 D.reflow $
5334 "I was partway through parsing " ++ something ++ ", but I got stuck here:"
5336 D.fillSep $
5337 ["I","was","expecting","to","see","a","type","next."
5338 ,"Try","putting",D.dullyellow "Int","or",D.dullyellow "String","for","now?"
5342 TSpace space row col ->
5343 toSpaceReport source space row col
5345 TIndentStart row col ->
5346 let
5347 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5348 region = toRegion row col
5350 thing =
5351 case context of
5352 TC_Annotation _ -> "type annotation"
5353 TC_CustomType -> "custom type"
5354 TC_TypeAlias -> "type alias"
5355 TC_Port -> "port"
5356 in
5357 Report.Report ("UNFINISHED " ++ map Char.toUpper thing) region [] $
5358 Code.toSnippet source surroundings (Just region)
5360 D.reflow $
5361 "I was partway through parsing a " ++ thing ++ ", but I got stuck here:"
5363 D.stack
5364 [ D.fillSep $
5365 ["I","was","expecting","to","see","a","type","next."
5366 ,"Try","putting",D.dullyellow "Int","or",D.dullyellow "String","for","now?"
5368 , D.toSimpleNote $
5369 "I can get confused by indentation. If you think there is already a type\
5370 \ next, maybe it is not indented enough?"
5375toTRecordReport :: Code.Source -> TContext -> TRecord -> Row -> Col -> Report.Report
5376toTRecordReport source context record startRow startCol =
5377 case record of
5378 TRecordOpen row col ->
5379 case Code.whatIsNext source row col of
5380 Code.Keyword keyword ->
5381 let
5382 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5383 region = toKeywordRegion row col keyword
5384 in
5385 Report.Report "RESERVED WORD" region [] $
5386 Code.toSnippet source surroundings (Just region)
5388 D.reflow $
5389 "I just started parsing a record type, but I got stuck on this field name:"
5391 D.reflow $
5392 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
5393 \ that is a reserved word. Try using a different name!"
5396 _ ->
5397 let
5398 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5399 region = toRegion row col
5400 in
5401 Report.Report "UNFINISHED RECORD TYPE" region [] $
5402 Code.toSnippet source surroundings (Just region)
5404 D.reflow $
5405 "I just started parsing a record type, but I got stuck here:"
5407 D.fillSep
5408 ["Record","types","look","like",D.dullyellow "{ name : String, age : Int },"
5409 ,"so","I","was","expecting","to","see","a","field","name","next."
5413 TRecordEnd row col ->
5414 let
5415 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5416 region = toRegion row col
5417 in
5418 Report.Report "UNFINISHED RECORD TYPE" region [] $
5419 Code.toSnippet source surroundings (Just region)
5421 D.reflow $
5422 "I am partway through parsing a record type, but I got stuck here:"
5424 D.stack
5425 [ D.fillSep
5426 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
5427 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
5429 , D.toSimpleNote $
5430 "When I get stuck like this, it usually means that there is a missing parenthesis\
5431 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
5435 TRecordField row col ->
5436 case Code.whatIsNext source row col of
5437 Code.Keyword keyword ->
5438 let
5439 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5440 region = toKeywordRegion row col keyword
5441 in
5442 Report.Report "RESERVED WORD" region [] $
5443 Code.toSnippet source surroundings (Just region)
5445 D.reflow $
5446 "I am partway through parsing a record type, but I got stuck on this field name:"
5448 D.reflow $
5449 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
5450 \ that is a reserved word. Try using a different name!"
5453 Code.Other (Just ',') ->
5454 let
5455 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5456 region = toRegion row col
5457 in
5458 Report.Report "EXTRA COMMA" region [] $
5459 Code.toSnippet source surroundings (Just region)
5461 D.reflow $
5462 "I am partway through parsing a record type, but I got stuck here:"
5464 D.stack
5465 [ D.reflow $
5466 "I am seeing two commas in a row. This is the second one!"
5467 , D.reflow $
5468 "Just delete one of the commas and you should be all set!"
5469 , noteForRecordTypeError
5473 Code.Close _ '}' ->
5474 let
5475 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5476 region = toRegion row col
5477 in
5478 Report.Report "EXTRA COMMA" region [] $
5479 Code.toSnippet source surroundings (Just region)
5481 D.reflow $
5482 "I am partway through parsing a record type, but I got stuck here:"
5484 D.stack
5485 [ D.reflow $
5486 "Trailing commas are not allowed in record types. Try deleting the comma that\
5487 \ appears before this closing curly brace."
5488 , noteForRecordTypeError
5492 _ ->
5493 let
5494 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5495 region = toRegion row col
5496 in
5497 Report.Report "PROBLEM IN RECORD TYPE" region [] $
5498 Code.toSnippet source surroundings (Just region)
5500 D.reflow $
5501 "I am partway through parsing a record type, but I got stuck here:"
5503 D.stack
5504 [ D.fillSep
5505 ["I","was","expecting","to","see","another","record","field","defined","next,"
5506 ,"so","I","am","looking","for","a","name","like"
5507 ,D.dullyellow "userName","or",D.dullyellow "plantHeight" <> "."
5509 , noteForRecordTypeError
5513 TRecordColon row col ->
5514 let
5515 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5516 region = toRegion row col
5517 in
5518 Report.Report "UNFINISHED RECORD TYPE" region [] $
5519 Code.toSnippet source surroundings (Just region)
5521 D.reflow $
5522 "I am partway through parsing a record type, but I got stuck here:"
5524 D.stack
5525 [ D.fillSep $
5526 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
5527 ,"a","colon","next.","So","try","putting","an",D.green ":","sign","here?"
5529 , noteForRecordTypeError
5533 TRecordType tipe row col ->
5534 toTypeReport source context tipe row col
5536 TRecordSpace space row col ->
5537 toSpaceReport source space row col
5539 TRecordIndentOpen row col ->
5540 let
5541 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5542 region = toRegion row col
5543 in
5544 Report.Report "UNFINISHED RECORD TYPE" region [] $
5545 Code.toSnippet source surroundings (Just region)
5547 D.reflow $
5548 "I just saw the opening curly brace of a record type, but then I got stuck here:"
5550 D.stack
5551 [ D.fillSep $
5552 ["I","am","expecting","a","record","like",D.dullyellow "{ name : String, age : Int }","here."
5553 ,"Try","defining","some","fields","of","your","own?"
5555 , noteForRecordTypeIndentError
5559 TRecordIndentEnd row col ->
5560 case Code.nextLineStartsWithCloseCurly source row of
5561 Just (curlyRow, curlyCol) ->
5562 let
5563 surroundings = A.Region (A.Position startRow startCol) (A.Position curlyRow curlyCol)
5564 region = toRegion curlyRow curlyCol
5565 in
5566 Report.Report "NEED MORE INDENTATION" region [] $
5567 Code.toSnippet source surroundings (Just region)
5569 D.reflow $
5570 "I was partway through parsing a record type, but I got stuck here:"
5572 D.stack
5573 [ D.reflow $
5574 "I need this curly brace to be indented more. Try adding some spaces before it!"
5575 , noteForRecordTypeError
5579 Nothing ->
5580 let
5581 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5582 region = toRegion row col
5583 in
5584 Report.Report "UNFINISHED RECORD TYPE" region [] $
5585 Code.toSnippet source surroundings (Just region)
5587 D.reflow $
5588 "I was partway through parsing a record type, but I got stuck here:"
5590 D.stack
5591 [ D.fillSep $
5592 ["I","was","expecting","to","see","a","closing","curly","brace","next."
5593 ,"Try","putting","a",D.green "}","next","and","see","if","that","helps?"
5595 , noteForRecordTypeIndentError
5599 TRecordIndentField row col ->
5600 let
5601 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5602 region = toRegion row col
5603 in
5604 Report.Report "UNFINISHED RECORD TYPE" region [] $
5605 Code.toSnippet source surroundings (Just region)
5607 D.reflow $
5608 "I am partway through parsing a record type, but I got stuck after that last comma:"
5610 D.stack
5611 [ D.reflow $
5612 "Trailing commas are not allowed in record types, so the fix may be to\
5613 \ delete that last comma? Or maybe you were in the middle of defining\
5614 \ an additional field?"
5615 , noteForRecordTypeIndentError
5619 TRecordIndentColon row col ->
5620 let
5621 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5622 region = toRegion row col
5623 in
5624 Report.Report "UNFINISHED RECORD TYPE" region [] $
5625 Code.toSnippet source surroundings (Just region)
5627 D.reflow $
5628 "I am partway through parsing a record type. I just saw a record\
5629 \ field, so I was expecting to see a colon next:"
5631 D.stack
5632 [ D.fillSep $
5633 ["Try","putting","an",D.green ":","followed","by","a","type?"
5635 , noteForRecordTypeIndentError
5639 TRecordIndentType row col ->
5640 let
5641 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5642 region = toRegion row col
5643 in
5644 Report.Report "UNFINISHED RECORD TYPE" region [] $
5645 Code.toSnippet source surroundings (Just region)
5647 D.reflow $
5648 "I am partway through parsing a record type, and I was expecting to run into a type next:"
5650 D.stack
5651 [ D.fillSep $
5652 ["Try","putting","something","like"
5653 ,D.dullyellow "Int","or",D.dullyellow "String","for","now?"
5655 , noteForRecordTypeIndentError
5660noteForRecordTypeError :: D.Doc
5661noteForRecordTypeError =
5662 D.stack $
5663 [ D.toSimpleNote
5664 "If you are trying to define a record type across multiple lines, I recommend using this format:"
5665 , D.indent 4 $ D.vcat $
5666 [ "{ name : String"
5667 , ", age : Int"
5668 , ", height : Float"
5669 , "}"
5671 , D.reflow $
5672 "Notice that each line starts with some indentation. Usually two or four spaces.\
5673 \ This is the stylistic convention in the Elm ecosystem."
5677noteForRecordTypeIndentError :: D.Doc
5678noteForRecordTypeIndentError =
5679 D.stack $
5680 [ D.toSimpleNote
5681 "I may be confused by indentation. For example, if you are trying to define\
5682 \ a record type across multiple lines, I recommend using this format:"
5683 , D.indent 4 $ D.vcat $
5684 [ "{ name : String"
5685 , ", age : Int"
5686 , ", height : Float"
5687 , "}"
5689 , D.reflow $
5690 "Notice that each line starts with some indentation. Usually two or four spaces.\
5691 \ This is the stylistic convention in the Elm ecosystem."
5695toTTupleReport :: Code.Source -> TContext -> TTuple -> Row -> Col -> Report.Report
5696toTTupleReport source context tuple startRow startCol =
5697 case tuple of
5698 TTupleOpen row col ->
5699 case Code.whatIsNext source row col of
5700 Code.Keyword keyword ->
5701 let
5702 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5703 region = toKeywordRegion row col keyword
5704 in
5705 Report.Report "RESERVED WORD" region [] $
5706 Code.toSnippet source surroundings (Just region)
5708 D.reflow $
5709 "I ran into a reserved word unexpectedly:"
5711 D.reflow $
5712 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name, but \
5713 \ it is a reserved word. Try using a different name!"
5716 _ ->
5717 let
5718 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5719 region = toRegion row col
5720 in
5721 Report.Report "UNFINISHED PARENTHESES" region [] $
5722 Code.toSnippet source surroundings (Just region)
5724 D.reflow $
5725 "I just saw an open parenthesis, so I was expecting to see a type next."
5727 D.fillSep $
5728 ["Something","like",D.dullyellow "(Maybe Int)","or"
5729 ,D.dullyellow "(List Person)" <> "."
5730 ,"Anything","where","you","are","putting","parentheses","around","normal","types."
5734 TTupleEnd row col ->
5735 let
5736 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5737 region = toRegion row col
5738 in
5739 Report.Report "UNFINISHED PARENTHESES" region [] $
5740 Code.toSnippet source surroundings (Just region)
5742 D.reflow $
5743 "I was expecting to see a closing parenthesis next, but I got stuck here:"
5745 D.stack
5746 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
5747 , D.toSimpleNote $
5748 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
5749 \ unexpectedly. So there may be some earlier syntax trouble (like extra parenthesis\
5750 \ or missing brackets) that is confusing me."
5754 TTupleType tipe row col ->
5755 toTypeReport source context tipe row col
5757 TTupleSpace space row col ->
5758 toSpaceReport source space row col
5760 TTupleIndentType1 row col ->
5761 let
5762 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5763 region = toRegion row col
5764 in
5765 Report.Report "UNFINISHED PARENTHESES" region [] $
5766 Code.toSnippet source surroundings (Just region)
5768 D.reflow $
5769 "I just saw an open parenthesis, so I was expecting to see a type next."
5771 D.stack
5772 [ D.fillSep $
5773 ["Something","like",D.dullyellow "(Maybe Int)","or"
5774 ,D.dullyellow "(List Person)" <> "."
5775 ,"Anything","where","you","are","putting","parentheses","around","normal","types."
5777 , D.toSimpleNote $
5778 "I can get confused by indentation in cases like this, so\
5779 \ maybe you have a type but it is not indented enough?"
5783 TTupleIndentTypeN row col ->
5784 let
5785 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5786 region = toRegion row col
5787 in
5788 Report.Report "UNFINISHED TUPLE TYPE" region [] $
5789 Code.toSnippet source surroundings (Just region)
5791 D.reflow $
5792 "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."
5794 D.stack
5795 [ D.fillSep $
5796 ["A","tuple","type","looks","like",D.dullyellow "(Float,Float)","or"
5797 ,D.dullyellow "(String,Int)" <> ","
5798 ,"so","I","think","there","is","a","type","missing","here?"
5800 , D.toSimpleNote $
5801 "I can get confused by indentation in cases like this, so\
5802 \ maybe you have an expression but it is not indented enough?"
5806 TTupleIndentEnd row col ->
5807 let
5808 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5809 region = toRegion row col
5810 in
5811 Report.Report "UNFINISHED PARENTHESES" region [] $
5812 Code.toSnippet source surroundings (Just region)
5814 D.reflow $
5815 "I was expecting to see a closing parenthesis next:"
5817 D.stack
5818 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
5819 , D.toSimpleNote $
5820 "I can get confused by indentation in cases like this, so\
5821 \ maybe you have a closing parenthesis but it is not indented enough?"