on 9acff26 help sign in
5272 lines 189 kB history raw
1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Reporting.Error.Syntax
4 ( Error(..)
5 --
6 , Module(..)
7 , Exposing(..)
8 --
9 , Decl(..)
10 , DeclType(..)
11 , TypeAlias(..)
12 , CustomType(..)
13 , DeclDef(..)
14 , Port(..)
15 --
16 , Expr(..)
17 , Record(..)
18 , Tuple(..)
19 , List(..)
20 , Func(..)
21 , Case(..)
22 , If(..)
23 , Let(..)
24 , Def(..)
25 , Destruct(..)
26 --
27 , Pattern(..)
28 , PRecord(..)
29 , PTuple(..)
30 , PList(..)
31 --
32 , Type(..)
33 , TRecord(..)
34 , TTuple(..)
35 --
36 , Char(..)
37 , String(..)
38 , Escape(..)
39 , Number(..)
40 --
41 , Space(..)
42 , toReport
43 )
44 where
47import Prelude hiding (Char, String)
48import qualified Data.Char as Char
49import qualified Data.Name as Name
50import Data.Word (Word16)
51import Numeric (showHex)
53import qualified Elm.ModuleName as ModuleName
54import Parse.Primitives (Row, Col)
55import Parse.Symbol (BadOperator(..))
56import qualified Reporting.Annotation as A
57import qualified Reporting.Doc as D
58import qualified Reporting.Report as Report
59import qualified Reporting.Render.Code as Code
63-- ALL SYNTAX ERRORS
66data Error
67 = ModuleNameUnspecified ModuleName.Raw
68 | ModuleNameMismatch ModuleName.Raw (A.Located ModuleName.Raw)
69 | UnexpectedPort A.Region
70 | NoPorts A.Region
71 | ParseError Module
75-- MODULE
78data Module
79 = ModuleSpace Space Row Col
80 | ModuleBadEnd Row Col
81 --
82 | ModuleProblem Row Col
83 | ModuleName Row Col
84 | ModuleExposing Exposing Row Col
85 --
86 | PortModuleProblem Row Col
87 | PortModuleName Row Col
88 | PortModuleExposing Exposing Row Col
89 --
90 | Effect Row Col
91 --
92 | FreshLine Row Col
93 --
94 | ImportStart Row Col
95 | ImportName Row Col
96 | ImportAs Row Col
97 | ImportAlias Row Col
98 | ImportExposing Row Col
99 | ImportExposingList Exposing Row Col
100 | ImportEnd Row Col -- different based on col=1 or if greater
101 --
102 | ImportIndentName Row Col
103 | ImportIndentAlias Row Col
104 | ImportIndentExposingList Row Col
105 --
106 | Infix Row Col
107 --
108 | Declarations Decl Row Col
111data Exposing
112 = ExposingSpace Space Row Col
113 | ExposingStart Row Col
114 | ExposingValue Row Col
115 | ExposingOperator Row Col
116 | ExposingOperatorReserved BadOperator Row Col
117 | ExposingOperatorRightParen Row Col
118 | ExposingTypePrivacy Row Col
119 | ExposingEnd Row Col
120 --
121 | ExposingIndentEnd Row Col
122 | ExposingIndentValue Row Col
126-- DECLARATIONS
129data Decl
130 = DeclStart Row Col
131 | DeclSpace Space Row Col
132 --
133 | Port Port Row Col
134 | DeclType DeclType Row Col
135 | DeclDef Name.Name DeclDef Row Col
136 --
137 | DeclFreshLineAfterDocComment Row Col
140data DeclDef
141 = DeclDefSpace Space Row Col
142 | DeclDefEquals Row Col
143 | DeclDefType Type Row Col
144 | DeclDefArg Pattern Row Col
145 | DeclDefBody Expr Row Col
146 | DeclDefNameRepeat Row Col
147 | DeclDefNameMatch Name.Name Row Col
148 --
149 | DeclDefIndentType Row Col
150 | DeclDefIndentEquals Row Col
151 | DeclDefIndentBody Row Col
154data Port
155 = PortSpace Space Row Col
156 | PortName Row Col
157 | PortColon Row Col
158 | PortType Type Row Col
159 | PortIndentName Row Col
160 | PortIndentColon Row Col
161 | PortIndentType Row Col
165-- TYPE DECLARATIONS
168data DeclType
169 = DT_Space Space Row Col
170 | DT_Name Row Col
171 | DT_Alias TypeAlias Row Col
172 | DT_Union CustomType Row Col
173 --
174 | DT_IndentName Row Col
177data TypeAlias
178 = AliasSpace Space Row Col
179 | AliasName Row Col
180 | AliasEquals Row Col
181 | AliasBody Type Row Col
182 --
183 | AliasIndentEquals Row Col
184 | AliasIndentBody Row Col
187data CustomType
188 = CT_Space Space Row Col
189 | CT_Name Row Col
190 | CT_Equals Row Col
191 | CT_Bar Row Col
192 | CT_Variant Row Col
193 | CT_VariantArg Type Row Col
194 --
195 | CT_IndentEquals Row Col
196 | CT_IndentBar Row Col
197 | CT_IndentAfterBar Row Col
198 | CT_IndentAfterEquals Row Col
202-- EXPRESSIONS
205data Expr
206 = Let Let Row Col
207 | Case Case Row Col
208 | If If Row Col
209 | List List Row Col
210 | Record Record Row Col
211 | Tuple Tuple Row Col
212 | Func Func Row Col
213 --
214 | Dot Row Col
215 | Access Row Col
216 | OperatorRight Name.Name Row Col
217 | OperatorReserved BadOperator Row Col
218 --
219 | Start Row Col
220 | Char Char Row Col
221 | String String Row Col
222 | Number Number Row Col
223 | Space Space Row Col
224 | EndlessShader Row Col
225 | ShaderProblem [Char.Char] Row Col
226 | IndentOperatorRight Name.Name Row Col
229data Record
230 = RecordOpen Row Col
231 | RecordEnd Row Col
232 | RecordField Row Col
233 | RecordEquals Row Col
234 | RecordExpr Expr Row Col
235 | RecordSpace Space Row Col
236 --
237 | RecordIndentOpen Row Col
238 | RecordIndentEnd Row Col
239 | RecordIndentField Row Col
240 | RecordIndentEquals Row Col
241 | RecordIndentExpr Row Col
244data Tuple
245 = TupleExpr Expr Row Col
246 | TupleSpace Space Row Col
247 | TupleEnd Row Col
248 | TupleOperatorClose Row Col
249 | TupleOperatorReserved BadOperator Row Col
250 --
251 | TupleIndentExpr1 Row Col
252 | TupleIndentExprN Row Col
253 | TupleIndentEnd Row Col
256data List
257 = ListSpace Space Row Col
258 | ListOpen Row Col
259 | ListExpr Expr Row Col
260 | ListEnd Row Col
261 --
262 | ListIndentOpen Row Col
263 | ListIndentEnd Row Col
264 | ListIndentExpr Row Col
267data Func
268 = FuncSpace Space Row Col
269 | FuncArg Pattern Row Col
270 | FuncBody Expr Row Col
271 | FuncArrow Row Col
272 --
273 | FuncIndentArg Row Col
274 | FuncIndentArrow Row Col
275 | FuncIndentBody Row Col
278data Case
279 = CaseSpace Space Row Col
280 | CaseOf Row Col
281 | CasePattern Pattern Row Col
282 | CaseArrow Row Col
283 | CaseExpr Expr Row Col
284 | CaseBranch Expr Row Col
285 --
286 | CaseIndentOf Row Col
287 | CaseIndentExpr Row Col
288 | CaseIndentPattern Row Col
289 | CaseIndentArrow Row Col
290 | CaseIndentBranch Row Col
291 | CasePatternAlignment Word16 Row Col
294data If
295 = IfSpace Space Row Col
296 | IfThen Row Col
297 | IfElse Row Col
298 | IfElseBranchStart Row Col
299 --
300 | IfCondition Expr Row Col
301 | IfThenBranch Expr Row Col
302 | IfElseBranch Expr Row Col
303 --
304 | IfIndentCondition Row Col
305 | IfIndentThen Row Col
306 | IfIndentThenBranch Row Col
307 | IfIndentElseBranch Row Col
308 | IfIndentElse Row Col
311data Let
312 = LetSpace Space Row Col
313 | LetIn Row Col
314 | LetDefAlignment Word16 Row Col
315 | LetDefName Row Col
316 | LetDef Name.Name Def Row Col
317 | LetDestruct Destruct Row Col
318 | LetBody Expr Row Col
319 | LetIndentDef Row Col
320 | LetIndentIn Row Col
321 | LetIndentBody Row Col
324data Def
325 = DefSpace Space Row Col
326 | DefType Type Row Col
327 | DefNameRepeat Row Col
328 | DefNameMatch Name.Name Row Col
329 | DefArg Pattern Row Col
330 | DefEquals Row Col
331 | DefBody Expr Row Col
332 | DefIndentEquals Row Col
333 | DefIndentType Row Col
334 | DefIndentBody Row Col
335 | DefAlignment Word16 Row Col
338data Destruct
339 = DestructSpace Space Row Col
340 | DestructPattern Pattern Row Col
341 | DestructEquals Row Col
342 | DestructBody Expr Row Col
343 | DestructIndentEquals Row Col
344 | DestructIndentBody Row Col
348-- PATTERNS
351data Pattern
352 = PRecord PRecord Row Col
353 | PTuple PTuple Row Col
354 | PList PList Row Col
355 --
356 | PStart Row Col
357 | PChar Char Row Col
358 | PString String Row Col
359 | PNumber Number Row Col
360 | PFloat Word16 Row Col
361 | PAlias Row Col
362 | PWildcardNotVar Name.Name Int Row Col
363 | PSpace Space Row Col
364 --
365 | PIndentStart Row Col
366 | PIndentAlias Row Col
369data PRecord
370 = PRecordOpen Row Col
371 | PRecordEnd Row Col
372 | PRecordField Row Col
373 | PRecordSpace Space Row Col
374 --
375 | PRecordIndentOpen Row Col
376 | PRecordIndentEnd Row Col
377 | PRecordIndentField Row Col
380data PTuple
381 = PTupleOpen Row Col
382 | PTupleEnd Row Col
383 | PTupleExpr Pattern Row Col
384 | PTupleSpace Space Row Col
385 --
386 | PTupleIndentEnd Row Col
387 | PTupleIndentExpr1 Row Col
388 | PTupleIndentExprN Row Col
391data PList
392 = PListOpen Row Col
393 | PListEnd Row Col
394 | PListExpr Pattern Row Col
395 | PListSpace Space Row Col
396 --
397 | PListIndentOpen Row Col
398 | PListIndentEnd Row Col
399 | PListIndentExpr Row Col
403-- TYPES
406data Type
407 = TRecord TRecord Row Col
408 | TTuple TTuple Row Col
409 --
410 | TStart Row Col
411 | TSpace Space Row Col
412 --
413 | TIndentStart Row Col
416data TRecord
417 = TRecordOpen Row Col
418 | TRecordEnd Row Col
419 --
420 | TRecordField Row Col
421 | TRecordColon Row Col
422 | TRecordType Type Row Col
423 --
424 | TRecordSpace Space Row Col
425 --
426 | TRecordIndentOpen Row Col
427 | TRecordIndentField Row Col
428 | TRecordIndentColon Row Col
429 | TRecordIndentType Row Col
430 | TRecordIndentEnd Row Col
433data TTuple
434 = TTupleOpen Row Col
435 | TTupleEnd Row Col
436 | TTupleType Type Row Col
437 | TTupleSpace Space Row Col
438 --
439 | TTupleIndentType1 Row Col
440 | TTupleIndentTypeN Row Col
441 | TTupleIndentEnd Row Col
445-- LITERALS
448data Char
449 = CharEndless
450 | CharEscape Escape
451 | CharNotString Word16
454data String
455 = StringEndless_Single
456 | StringEndless_Multi
457 | StringEscape Escape
460data Escape
461 = EscapeUnknown
462 | BadUnicodeFormat Word16
463 | BadUnicodeCode Word16
464 | BadUnicodeLength Word16 Int Int
467data Number
468 = NumberEnd
469 | NumberDot Int
470 | NumberHexDigit
471 | NumberNoLeadingZero
475-- MISC
478data Space
479 = HasTab
480 | EndlessMultiComment
484-- TO REPORT
487toReport :: Code.Source -> Error -> Report.Report
488toReport source err =
489 case err of
490 ModuleNameUnspecified name ->
491 let
492 region = toRegion 1 1
493 in
494 Report.Report "MODULE NAME MISSING" region [] $
495 D.stack
496 [ D.reflow $
497 "I need the module name to be declared at the top of this file, like this:"
498 , D.indent 4 $ D.fillSep $
499 [ D.cyan "module", D.fromName name, D.cyan "exposing", "(..)" ]
500 , D.reflow $
501 "Try adding that as the first line of your file!"
502 , D.toSimpleNote $
503 "It is best to replace (..) with an explicit list of types and\
504 \ functions you want to expose. When you know a value is only used\
505 \ within this module, you can refactor without worrying about uses\
506 \ elsewhere. Limiting exposed values can also speed up compilation\
507 \ because I can skip a bunch of work if I see that the exposed API\
508 \ has not changed."
509 ]
511 ModuleNameMismatch expectedName (A.At region actualName) ->
512 Report.Report "MODULE NAME MISMATCH" region [ModuleName.toChars expectedName] $
513 Code.toSnippet source region Nothing
514 (
515 "It looks like this module name is out of sync:"
516 ,
517 D.stack
518 [ D.reflow $
519 "I need it to match the file path, so I was expecting it to see `"
520 ++ ModuleName.toChars expectedName
521 ++ "` here. Make the following change, and you should be all set!"
522 , D.indent 4 $
523 D.dullyellow (D.fromName actualName) <> " -> " <> D.green (D.fromName expectedName)
524 , D.toSimpleNote $
525 "I require that module names correspond to file paths. This makes it much\
526 \ easier to explore unfamiliar codebases! So if you want to keep the current\
527 \ module name, try renaming the file instead."
528 ]
529 )
531 UnexpectedPort region ->
532 Report.Report "UNEXPECTED PORTS" region [] $
533 Code.toSnippet source region Nothing
534 (
535 D.reflow $
536 "You are declaring ports in a normal module."
537 ,
538 D.stack
539 [ D.fillSep
540 ["Switch","this","to","say",D.cyan "port module","instead,"
541 ,"marking","that","this","module","contains","port","declarations."
542 ]
543 , D.link "Note"
544 "Ports are not a traditional FFI for calling JS functions directly. They need a different mindset! Read"
545 "ports"
546 "to learn the syntax and how to use it effectively."
547 ]
548 )
550 NoPorts region ->
551 Report.Report "NO PORTS" region [] $
552 Code.toSnippet source region Nothing
553 (
554 D.reflow $
555 "This module does not declare any ports, but it says it will:"
556 ,
557 D.fillSep
558 ["Switch","this","to",D.cyan "module"
559 ,"and","you","should","be","all","set!"
560 ]
561 )
563 ParseError modul ->
564 toParseErrorReport source modul
567toParseErrorReport :: Code.Source -> Module -> Report.Report
568toParseErrorReport source modul =
569 case modul of
570 ModuleSpace space row col ->
571 toSpaceReport source space row col
573 ModuleBadEnd row col ->
574 case Code.whatIsNext source row col of
575 Code.Keyword keyword ->
576 let
577 region = toKeywordRegion row col keyword
578 in
579 Report.Report "RESERVED WORD" region [] $
580 Code.toSnippet source region Nothing
581 (
582 D.reflow $
583 "I got stuck on this reserved word:"
584 ,
585 D.reflow $
586 "The name `" ++ keyword ++ "` is reserved, so try using a different name?"
587 )
589 Code.Operator op ->
590 let
591 region = toKeywordRegion row col op
592 in
593 Report.Report "UNEXPECTED SYMBOL" region [] $
594 Code.toSnippet source region Nothing
595 (
596 D.reflow $
597 "I ran into an unexpected symbol:"
598 ,
599 D.reflow $
600 "I was not expecting to see a " ++ op ++ " here. Try deleting it? Maybe\
601 \ I can give a better hint from there?"
602 )
604 Code.Close term bracket ->
605 let
606 region = toRegion row col
607 in
608 Report.Report ("UNEXPECTED " ++ map Char.toUpper term) region [] $
609 Code.toSnippet source region Nothing
610 (
611 D.reflow $
612 "I ran into an unexpected " ++ term ++ ":"
613 ,
614 D.reflow $
615 "This " ++ bracket : " does not match up with an earlier open " ++ term ++ ". Try deleting it?"
616 )
618 Code.Other ->
619 let
620 region = toRegion row col
621 in
622 Report.Report "SYNTAX PROBLEM" region [] $
623 Code.toSnippet source region Nothing
624 (
625 D.reflow $
626 "I got stuck here:"
627 ,
628 D.reflow $
629 "Whatever I am running into is confusing me a lot! Normally I can give fairly\
630 \ specific hints, but something is really tripping me up this time."
631 )
633 ModuleProblem row col ->
634 let
635 region = toRegion row col
636 in
637 Report.Report "UNFINISHED MODULE DECLARATION" region [] $
638 Code.toSnippet source region Nothing
639 (
640 D.reflow $
641 "I am parsing an `module` declaration, but I got stuck here:"
642 ,
643 D.stack
644 [ D.reflow $
645 "Here are some examples of valid `module` declarations:"
646 , D.indent 4 $ D.vcat $
647 [ D.fillSep [D.cyan "module","Main",D.cyan "exposing","(..)"]
648 , D.fillSep [D.cyan "module","Dict",D.cyan "exposing","(Dict, empty, get)"]
649 ]
650 , D.reflow $
651 "I generally recommend using an explicit exposing list. I can skip compiling a bunch\
652 \ of files when the public interface of a module stays the same, so exposing fewer\
653 \ values can help improve compile times!"
654 ]
655 )
657 ModuleName row col ->
658 let
659 region = toRegion row col
660 in
661 Report.Report "EXPECTING MODULE NAME" region [] $
662 Code.toSnippet source region Nothing
663 (
664 D.reflow $
665 "I was parsing an `module` declaration until I got stuck here:"
666 ,
667 D.stack
668 [ D.reflow $
669 "I was expecting to see the module name next, like in these examples:"
670 , D.indent 4 $ D.vcat $
671 [ D.fillSep [D.cyan "module","Dict",D.cyan "exposing","(..)"]
672 , D.fillSep [D.cyan "module","Maybe",D.cyan "exposing","(..)"]
673 , D.fillSep [D.cyan "module","Html.Attributes",D.cyan "exposing","(..)"]
674 , D.fillSep [D.cyan "module","Json.Decode",D.cyan "exposing","(..)"]
675 ]
676 , D.reflow $
677 "Notice that the module names all start with capital letters. That is required!"
678 ]
679 )
681 ModuleExposing exposing row col ->
682 toExposingReport source exposing row col
684 PortModuleProblem row col ->
685 let
686 region = toRegion row col
687 in
688 Report.Report "UNFINISHED PORT MODULE DECLARATION" region [] $
689 Code.toSnippet source region Nothing
690 (
691 D.reflow $
692 "I am parsing an `port module` declaration, but I got stuck here:"
693 ,
694 D.stack
695 [ D.reflow $
696 "Here are some examples of valid `port module` declarations:"
697 , D.indent 4 $ D.vcat $
698 [ D.fillSep [D.cyan "port",D.cyan "module","WebSockets",D.cyan "exposing","(send, listen, keepAlive)"]
699 , D.fillSep [D.cyan "port",D.cyan "module","Maps",D.cyan "exposing","(Location, goto)"]
700 ]
701 , D.link "Note" "Read" "ports" "for more help."
702 ]
703 )
705 PortModuleName row col ->
706 let
707 region = toRegion row col
708 in
709 Report.Report "EXPECTING MODULE NAME" region [] $
710 Code.toSnippet source region Nothing
711 (
712 D.reflow $
713 "I was parsing an `module` declaration until I got stuck here:"
714 ,
715 D.stack
716 [ D.reflow $
717 "I was expecting to see the module name next, like in these examples:"
718 , D.indent 4 $ D.vcat $
719 [ D.fillSep [D.cyan "port",D.cyan "module","WebSockets",D.cyan "exposing","(send, listen, keepAlive)"]
720 , D.fillSep [D.cyan "port",D.cyan "module","Maps",D.cyan "exposing","(Location, goto)"]
721 ]
722 , D.reflow $
723 "Notice that the module names start with capital letters. That is required!"
724 ]
725 )
727 PortModuleExposing exposing row col ->
728 toExposingReport source exposing row col
730 Effect row col ->
731 let
732 region = toRegion row col
733 in
734 Report.Report "BAD MODULE DECLARATION" region [] $
735 Code.toSnippet source region Nothing
736 (
737 D.reflow $
738 "I cannot parse this module declaration:"
739 ,
740 D.reflow $
741 "This type of module is reserved for the @elm organization. It is used to\
742 \ define certain effects, avoiding building them into the compiler."
743 )
745 FreshLine row col ->
746 let
747 region = toRegion row col
749 toBadFirstLineReport keyword =
750 Report.Report "TOO MUCH INDENTATION" region [] $
751 Code.toSnippet source region Nothing
752 (
753 D.reflow $
754 "This `" ++ keyword ++ "` should not have any spaces before it:"
755 ,
756 D.reflow $
757 "Delete the spaces before `" ++ keyword ++ "` until there are none left!"
758 )
760 in
761 case Code.whatIsNext source row col of
762 Code.Keyword "module" -> toBadFirstLineReport "module"
763 Code.Keyword "import" -> toBadFirstLineReport "import"
764 Code.Keyword "type" -> toBadFirstLineReport "type"
765 Code.Keyword "port" -> toBadFirstLineReport "port"
766 _ ->
767 Report.Report "SYNTAX PROBLEM" region [] $
768 Code.toSnippet source region Nothing
769 (
770 D.reflow $
771 "I got stuck here:"
772 ,
773 D.stack
774 [ D.reflow $
775 "I am not sure what is going on, but I recommend starting an Elm\
776 \ file with the following lines:"
777 , D.vcat
778 [ D.fillSep [D.cyan "import","Html"]
779 , ""
780 , D.fillSep [D.green "main","="]
781 , D.indent 2 $ D.fillSep [D.cyan "Html" <> ".text",D.dullyellow "\"Hello!\""]
782 ]
783 , D.reflow $
784 "You should be able to copy those lines directly into your file. Check out\
785 \ some of the examples on https://elm-lang.org for more help getting started!"
786 , D.toSimpleNote $
787 "This can also happen when something is indented too much!"
788 ]
789 )
791 ImportStart row col ->
792 toImportReport source row col
794 ImportName row col ->
795 let
796 region = toRegion row col
797 in
798 Report.Report "EXPECTING IMPORT NAME" region [] $
799 Code.toSnippet source region Nothing
800 (
801 D.reflow $
802 "I was parsing an `import` until I got stuck here:"
803 ,
804 D.stack
805 [ D.reflow $
806 "I was expecting to see a module name next, like in these examples:"
807 , D.indent 4 $ D.vcat $
808 [ D.fillSep [D.cyan "import","Dict"]
809 , D.fillSep [D.cyan "import","Maybe"]
810 , D.fillSep [D.cyan "import","Html.Attributes"]
811 , D.fillSep [D.cyan "import","Json.Decode"]
812 ]
813 , D.reflow $
814 "Notice that the module names all start with capital letters. That is required!"
815 ]
816 )
818 ImportAs row col ->
819 toImportReport source row col
821 ImportAlias row col ->
822 let
823 region = toRegion row col
824 in
825 Report.Report "EXECTING IMPORT ALIAS" region [] $
826 Code.toSnippet source region Nothing
827 (
828 D.reflow $
829 "I was parsing an `import` until I got stuck here:"
830 ,
831 D.stack
832 [ D.reflow $
833 "I was expecting to see an alias next, like in these examples:"
834 , D.indent 4 $ D.vcat $
835 [ D.fillSep [D.cyan "import","Html.Attributes",D.cyan "as","Attr"]
836 , D.fillSep [D.cyan "import","WebGL.Texture",D.cyan "as","Texture"]
837 , D.fillSep [D.cyan "import","Json.Decode",D.cyan "as","D"]
838 ]
839 , D.reflow $
840 "Notice that the alias always starts with a capital letter. That is required!"
841 ]
842 )
844 ImportExposing row col ->
845 toImportReport source row col
847 ImportExposingList exposing row col ->
848 toExposingReport source exposing row col
850 ImportEnd row col ->
851 toImportReport source row col
853 ImportIndentName row col ->
854 toImportReport source row col
856 ImportIndentAlias row col ->
857 toImportReport source row col
859 ImportIndentExposingList row col ->
860 let
861 region = toRegion row col
862 in
863 Report.Report "UNFINISHED IMPORT" region [] $
864 Code.toSnippet source region Nothing
865 (
866 D.reflow $
867 "I was parsing an `import` until I got stuck here:"
868 ,
869 D.stack
870 [ D.reflow $
871 "I was expecting to see the list of exposed values next. For example, here\
872 \ are two ways to expose values from the `Html` module:"
873 , D.indent 4 $ D.vcat $
874 [ D.fillSep [D.cyan "import","Html",D.cyan "exposing","(..)"]
875 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
876 ]
877 , D.reflow $
878 "I generally recommend the second style. It is more explicit, making it\
879 \ much easier to figure out where values are coming from in large projects!"
880 ]
881 )
883 Infix row col ->
884 let
885 region = toRegion row col
886 in
887 Report.Report "BAD INFIX" region [] $
888 Code.toSnippet source region Nothing
889 (
890 D.reflow $
891 "Something went wrong in this infix operator declaration:"
892 ,
893 D.reflow $
894 "This feature is used by the @elm organization to define the\
895 \ languages built-in operators."
896 )
898 Declarations decl _ _ ->
899 toDeclarationsReport source decl
903-- IMPORTS
906toImportReport :: Code.Source -> Row -> Col -> Report.Report
907toImportReport source row col =
908 let
909 region = toRegion row col
910 in
911 Report.Report "UNFINISHED IMPORT" region [] $
912 Code.toSnippet source region Nothing
913 (
914 D.reflow $
915 "I am partway through parsing an import, but I got stuck here:"
916 ,
917 D.stack
918 [ D.reflow $
919 "Here are some examples of valid `import` declarations:"
920 , D.indent 4 $ D.vcat $
921 [ D.fillSep [D.cyan "import","Html"]
922 , D.fillSep [D.cyan "import","Html",D.cyan "as","H"]
923 , D.fillSep [D.cyan "import","Html",D.cyan "as","H",D.cyan "exposing","(..)"]
924 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
925 ]
926 , D.reflow $
927 "You are probably trying to import a different module, but try to make it look like one of these examples!"
928 ]
929 )
933-- EXPOSING
936toExposingReport :: Code.Source -> Exposing -> Row -> Col -> Report.Report
937toExposingReport source exposing startRow startCol =
938 case exposing of
939 ExposingSpace space row col ->
940 toSpaceReport source space row col
942 ExposingStart row col ->
943 let
944 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
945 region = toRegion row col
946 in
947 Report.Report "PROBLEM IN EXPOSING" region [] $
948 Code.toSnippet source surroundings (Just region)
949 (
950 D.reflow $
951 "I want to parse exposed values, but I am getting stuck here:"
952 ,
953 D.stack
954 [ D.fillSep $
955 ["Exposed","values","are","always","surrounded","by","parentheses."
956 ,"So","try","adding","a",D.green "(","here?"
957 ]
958 , D.toSimpleNote "Here are some valid examples of `exposing` for reference:"
959 , D.indent 4 $ D.vcat $
960 [ D.fillSep [D.cyan "import","Html",D.cyan "exposing","(..)"]
961 , D.fillSep [D.cyan "import","Html",D.cyan "exposing","(Html, div, text)"]
962 ]
963 , D.reflow $
964 "If you are getting tripped up, you can just expose everything for now. It should\
965 \ get easier to make an explicit exposing list as you see more examples in the wild."
966 ]
967 )
969 ExposingValue row col ->
970 case Code.whatIsNext source row col of
971 Code.Keyword keyword ->
972 let
973 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
974 region = toKeywordRegion row col keyword
975 in
976 Report.Report "RESERVED WORD" region [] $
977 Code.toSnippet source surroundings (Just region)
978 (
979 D.reflow $
980 "I got stuck on this reserved word:"
981 ,
982 D.reflow $
983 "It looks like you are trying to expose `" ++ keyword ++ "` but that is a reserved word. Is there a typo?"
984 )
986 Code.Operator op ->
987 let
988 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
989 region = toKeywordRegion row col op
990 in
991 Report.Report "UNEXPECTED SYMBOL" region [] $
992 Code.toSnippet source surroundings (Just region)
993 (
994 D.reflow $
995 "I got stuck on this symbol:"
996 ,
997 D.stack
998 [ D.reflow $
999 "If you are trying to expose an operator, add parentheses around it like this:"
1000 , D.indent 4 $ D.dullyellow (D.fromChars op) <> " -> " <> D.green ("(" <> D.fromChars op <> ")")
1004 _ ->
1005 let
1006 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1007 region = toRegion row col
1008 in
1009 Report.Report "PROBLEM IN EXPOSING" region [] $
1010 Code.toSnippet source surroundings (Just region)
1012 D.reflow $
1013 "I got stuck while parsing these exposed values:"
1015 D.stack
1016 [ D.reflow $
1017 "I do not have an exact recommendation, so here are some valid examples\
1018 \ of `exposing` for reference:"
1019 , D.indent 4 $ D.vcat $
1020 [ D.fillSep [D.cyan "import","Html",D.cyan "exposing","(..)"]
1021 , D.fillSep [D.cyan "import","Basics",D.cyan "exposing","(Int, Float, Bool(..), (+), not, sqrt)"]
1023 , D.reflow $
1024 "These examples show how to expose types, variants, operators, and functions. Everything\
1025 \ should be some permutation of these examples, just with different names."
1029 ExposingOperator row col ->
1030 let
1031 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1032 region = toRegion row col
1033 in
1034 Report.Report "PROBLEM IN EXPOSING" region [] $
1035 Code.toSnippet source surroundings (Just region)
1037 D.reflow $
1038 "I just saw an open parenthesis, so I was expecting an operator next:"
1040 D.fillSep $
1041 ["It","is","possible","to","expose","operators,","so","I","was","expecting"
1042 ,"to","see","something","like",D.dullyellow "(+)","or",D.dullyellow "(|=)"
1043 ,"or",D.dullyellow "(||)","after","I","saw","that","open","parenthesis."
1047 ExposingOperatorReserved op row col ->
1048 let
1049 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1050 region = toRegion row col
1051 in
1052 Report.Report "RESERVED SYMBOL" region [] $
1053 Code.toSnippet source surroundings (Just region)
1055 D.reflow $
1056 "I cannot expose this as an operator:"
1058 case op of
1059 BadDot -> D.reflow "Try getting rid of this entry? Maybe I can give you a better hint after that?"
1060 BadPipe -> D.fillSep ["Maybe","you","want",D.dullyellow "(||)","instead?"]
1061 BadArrow -> D.reflow "Try getting rid of this entry? Maybe I can give you a better hint after that?"
1062 BadEquals -> D.fillSep ["Maybe","you","want",D.dullyellow "(==)","instead?"]
1063 BadHasType -> D.fillSep ["Maybe","you","want",D.dullyellow "(::)","instead?"]
1066 ExposingOperatorRightParen row col ->
1067 let
1068 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1069 region = toRegion row col
1070 in
1071 Report.Report "PROBLEM IN EXPOSING" region [] $
1072 Code.toSnippet source surroundings (Just region)
1074 D.reflow $
1075 "It looks like you are exposing an operator, but I got stuck here:"
1077 D.fillSep $
1078 ["I","was","expecting","to","see","the","closing","parenthesis","immediately"
1079 ,"after","the","operator.","Try","adding","a",D.green ")","right","here?"
1083 ExposingEnd row col ->
1084 let
1085 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1086 region = toRegion row col
1087 in
1088 Report.Report "UNFINISHED EXPOSING" region [] $
1089 Code.toSnippet source surroundings (Just region)
1091 D.reflow $
1092 "I was partway through parsing exposed values, but I got stuck here:"
1094 D.reflow $
1095 "Maybe there is a comma missing before this?"
1098 ExposingTypePrivacy row col ->
1099 let
1100 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1101 region = toRegion row col
1102 in
1103 Report.Report "PROBLEM EXPOSING CUSTOM TYPE VARIANTS" region [] $
1104 Code.toSnippet source surroundings (Just region)
1106 D.reflow $
1107 "It looks like you are trying to expose the variants of a custom type:"
1109 D.stack
1110 [ D.fillSep $
1111 ["You","need","to","write","something","like"
1112 ,D.dullyellow "Status(..)","or",D.dullyellow "Entity(..)"
1113 ,"though.","It","is","all","or","nothing,","otherwise","`case`"
1114 ,"expressions","could","miss","a","variant","and","crash!"
1116 , D.toSimpleNote $
1117 "It is often best to keep the variants hidden! If someone pattern matches on\
1118 \ the variants, it is a MAJOR change if any new variants are added. Suddenly\
1119 \ their `case` expressions do not cover all variants! So if you do not need\
1120 \ people to pattern match, keep the variants hidden and expose functions to\
1121 \ construct values of this type. This way you can add new variants as a MINOR change!"
1125 ExposingIndentEnd row col ->
1126 let
1127 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1128 region = toRegion row col
1129 in
1130 Report.Report "UNFINISHED EXPOSING" region [] $
1131 Code.toSnippet source surroundings (Just region)
1133 D.reflow $
1134 "I was partway through parsing exposed values, but I got stuck here:"
1136 D.stack
1137 [ D.fillSep $
1138 ["I","was","expecting","a","closing","parenthesis."
1139 ,"Try","adding","a",D.green ")","right","here?"
1141 , D.toSimpleNote $
1142 "I can get confused when there is not enough indentation, so if you already\
1143 \ have a closing parenthesis, it probably just needs some spaces in front of it."
1147 ExposingIndentValue row col ->
1148 let
1149 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1150 region = toRegion row col
1151 in
1152 Report.Report "UNFINISHED EXPOSING" region [] $
1153 Code.toSnippet source surroundings (Just region)
1155 D.reflow $
1156 "I was partway through parsing exposed values, but I got stuck here:"
1158 D.reflow $
1159 "I was expecting another value to expose."
1164-- SPACES
1167toSpaceReport :: Code.Source -> Space -> Row -> Col -> Report.Report
1168toSpaceReport source space row col =
1169 case space of
1170 HasTab ->
1171 let
1172 region = toRegion row col
1173 in
1174 Report.Report "NO TABS" region [] $
1175 Code.toSnippet source region Nothing
1177 D.reflow $
1178 "I ran into a tab, but tabs are not allowed in Elm files."
1180 D.reflow $
1181 "Replace the tab with spaces."
1184 EndlessMultiComment ->
1185 let
1186 region = toWiderRegion row col 2
1187 in
1188 Report.Report "ENDLESS COMMENT" region [] $
1189 Code.toSnippet source region Nothing
1191 D.reflow $
1192 "I cannot find the end of this multi-line comment:"
1194 D.stack -- "{-"
1195 [ D.reflow "Add a -} somewhere after this to end the comment."
1196 , D.toSimpleHint
1197 "Multi-line comments can be nested in Elm, so {- {- -} -} is a comment\
1198 \ that happens to contain another comment. Like parentheses and curly braces,\
1199 \ the start and end markers must always be balanced. Maybe that is the problem?"
1205-- DECLARATIONS
1208toRegion :: Row -> Col -> A.Region
1209toRegion row col =
1210 let
1211 pos = A.Position row col
1212 in
1213 A.Region pos pos
1216toWiderRegion :: Row -> Col -> Word16 -> A.Region
1217toWiderRegion row col extra =
1218 A.Region
1219 (A.Position row col)
1220 (A.Position row (col + extra))
1223toKeywordRegion :: Row -> Col -> [Char.Char] -> A.Region
1224toKeywordRegion row col keyword =
1225 A.Region
1226 (A.Position row col)
1227 (A.Position row (col + fromIntegral (length keyword)))
1230toDeclarationsReport :: Code.Source -> Decl -> Report.Report
1231toDeclarationsReport source decl =
1232 case decl of
1233 DeclStart row col ->
1234 case Code.whatIsNext source row col of
1235 Code.Close term bracket ->
1236 let
1237 region = toRegion row col
1238 in
1239 Report.Report ("STRAY " ++ map Char.toUpper term) region [] $
1240 Code.toSnippet source region Nothing
1242 D.reflow $
1243 "I was not expecting to see a " ++ term ++ " here:"
1244 , D.reflow $
1245 "This " ++ bracket : " does not match up with an earlier open " ++ term ++ ". Try deleting it?"
1248 Code.Keyword keyword ->
1249 let
1250 region = toKeywordRegion row col keyword
1251 in
1252 Report.Report "RESERVED WORD" region [] $
1253 Code.toSnippet source region Nothing
1255 D.reflow $
1256 "I was not expecting to run into the `" ++ keyword ++ "` keyword here:"
1258 case keyword of
1259 "import" ->
1260 D.reflow $
1261 "It is reserved for declaring imports at the top of your module. If you want\
1262 \ another import, try moving it up top with the other imports. If you want to\
1263 \ define a value or function, try changing the name to something else!"
1265 "case" ->
1266 D.stack
1267 [ D.reflow $
1268 "It is reserved for writing `case` expressions. Try using a different name?"
1269 , D.toSimpleNote $
1270 "If you are trying to write a `case` expression, it needs to be part of a\
1271 \ definition. So you could write something like this instead:"
1272 , D.vcat $
1273 [ D.indent 0 $ D.fillSep [D.green "getWidth","maybeWidth","="]
1274 , D.indent 2 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
1275 , D.indent 4 $ D.fillSep [D.blue "Just","width","->"]
1276 , D.indent 6 $ D.fillSep ["width","+",D.dullyellow "200"]
1277 , ""
1278 , D.indent 4 $ D.fillSep [D.blue "Nothing","->"]
1279 , D.indent 6 $ D.fillSep [D.dullyellow "400"]
1281 , D.reflow $
1282 "This defines a `getWidth` function that we can use elsewhere in our program."
1285 "if" ->
1286 D.stack
1287 [ D.reflow $
1288 "It is reserved for writing `if` expressions. Try using a different name?"
1289 , D.toSimpleNote $
1290 "If you are trying to write an `if` expression, it needs to be part of a\
1291 \ definition. So you could write something like this instead:"
1292 , D.vcat $
1293 [ D.indent 0 $ D.fillSep [D.green "reviewPowerLevel","powerLevel","="]
1294 , D.indent 2 $ D.fillSep $
1295 [D.cyan "if","powerLevel",">",D.dullyellow "9000"
1296 ,D.cyan "then",D.dullyellow "\"OVER 9000!!!\""
1297 ,D.cyan "else",D.dullyellow "\"not bad\""
1300 , D.reflow $
1301 "This defines a `reviewPowerLevel` function that we can use elsewhere in our program."
1304 _ ->
1305 D.reflow $
1306 "It is a reserved word. Try changing the name to something else?"
1309 _ ->
1310 let
1311 region = toRegion row col
1312 in
1313 Report.Report "SYNTAX PROBLEM" region [] $
1314 Code.toSnippet source region Nothing
1316 D.reflow $
1317 "I was expecting to see a new declaration here:"
1319 D.stack
1320 [ D.reflow $
1321 "I am not sure what is going wrong exactly, but here are a couple valid\
1322 \ declarations for reference:"
1323 , D.vcat
1324 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
1325 , D.fillSep [D.green "add","x","y","="]
1326 , D.fillSep [" ","x","+","y"]
1328 , D.fillSep [D.cyan "type",D.green "User","=","Anonymous","|","LoggedIn String"]
1329 , D.reflow $
1330 "Note that all declarations start with lower-case letters in Elm. Capitalization\
1331 \ makes a difference, so be consious of that if you are working from examples!"
1335 DeclSpace space row col ->
1336 toSpaceReport source space row col
1338 Port port_ row col ->
1339 toPortReport source port_ row col
1341 DeclType declType row col ->
1342 toDeclTypeReport source declType row col
1344 DeclDef name declDef row col ->
1345 toDeclDefReport source name declDef row col
1347 DeclFreshLineAfterDocComment row col ->
1348 let
1349 region = toRegion row col
1350 in
1351 Report.Report "EXPECTING DECLARATION" region [] $
1352 Code.toSnippet source region Nothing
1354 D.reflow $
1355 "I just saw a doc comment, but then I got stuck here:"
1357 D.reflow $
1358 "I was expecting to see the corresponding declaration next, starting on a fresh\
1359 \ line with no indentation."
1364-- PORT
1367toPortReport :: Code.Source -> Port -> Row -> Col -> Report.Report
1368toPortReport source port_ startRow startCol =
1369 case port_ of
1370 PortSpace space row col ->
1371 toSpaceReport source space row col
1373 PortName row col ->
1374 case Code.whatIsNext source row col of
1375 Code.Keyword keyword ->
1376 let
1377 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1378 region = toKeywordRegion row col keyword
1379 in
1380 Report.Report "RESERVED WORD" region [] $
1381 Code.toSnippet source surroundings (Just region)
1383 D.reflow $
1384 "I cannot handle ports with names like this:"
1386 D.reflow $
1387 "You are trying to make a port named `" ++ keyword
1388 ++ "` but that is a reserved word. Try using some other name?"
1391 _ ->
1392 let
1393 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1394 region = toRegion row col
1395 in
1396 Report.Report "PORT PROBLEM" region [] $
1397 Code.toSnippet source surroundings (Just region)
1399 D.reflow $
1400 "I just saw the start of a `port` declaration, but then I got stuck here:"
1402 D.stack
1403 [ D.fillSep
1404 ["I","was","expecting","to","see","a","name","like"
1405 ,D.dullyellow "send","or",D.dullyellow "receive","next."
1406 ,"Something","that","starts","with","a","lower-case","letter."
1408 , portNote
1412 PortColon row col ->
1413 let
1414 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1415 region = toRegion row col
1416 in
1417 Report.Report "PORT PROBLEM" region [] $
1418 Code.toSnippet source surroundings (Just region)
1420 D.reflow $
1421 "I just saw the start of a `port` declaration, but then I got stuck here:"
1423 D.stack
1424 [ D.reflow $
1425 "I was expecting to see a colon next. And then a type that tells me\
1426 \ what type of values are going to flow through."
1427 , portNote
1431 PortType tipe row col ->
1432 toTypeReport source TC_Port tipe row col
1434 PortIndentName row col ->
1435 let
1436 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1437 region = toRegion row col
1438 in
1439 Report.Report "UNFINISHED PORT" region [] $
1440 Code.toSnippet source surroundings (Just region)
1442 D.reflow $
1443 "I just saw the start of a `port` declaration, but then I got stuck here:"
1445 D.stack
1446 [ D.fillSep
1447 ["I","was","expecting","to","see","a","name","like"
1448 ,D.dullyellow "send","or",D.dullyellow "receive","next."
1449 ,"Something","that","starts","with","a","lower-case","letter."
1451 , portNote
1455 PortIndentColon row col ->
1456 let
1457 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1458 region = toRegion row col
1459 in
1460 Report.Report "UNFINISHED PORT" region [] $
1461 Code.toSnippet source surroundings (Just region)
1463 D.reflow $
1464 "I just saw the start of a `port` declaration, but then I got stuck here:"
1466 D.stack
1467 [ D.reflow $
1468 "I was expecting to see a colon next. And then a type that tells me\
1469 \ what type of values are going to flow through."
1470 , portNote
1474 PortIndentType row col ->
1475 let
1476 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1477 region = toRegion row col
1478 in
1479 Report.Report "UNFINISHED PORT" region [] $
1480 Code.toSnippet source surroundings (Just region)
1482 D.reflow $
1483 "I just saw the start of a `port` declaration, but then I got stuck here:"
1485 D.stack
1486 [ D.reflow $
1487 "I was expecting to see a type next. Here are examples of outgoing and\
1488 \ incoming ports for reference:"
1489 , D.vcat
1490 [ D.fillSep [D.cyan "port","send",":","String -> Cmd msg"]
1491 , D.fillSep [D.cyan "port","receive",":","(String -> msg) -> Sub msg"]
1493 , D.reflow $
1494 "The first line defines a `send` port so you can send strings out to JavaScript.\
1495 \ Maybe you send them on a WebSocket or put them into IndexedDB. The second line\
1496 \ defines a `receive` port so you can receive strings from JavaScript. Maybe you\
1497 \ get receive messages when new WebSocket messages come in or when an entry in\
1498 \ IndexedDB changes for some external reason."
1503portNote :: D.Doc
1504portNote =
1505 D.stack
1506 [ D.toSimpleNote $
1507 "Here are some example `port` declarations for reference:"
1508 , D.vcat
1509 [ D.fillSep [D.cyan "port","send",":","String -> Cmd msg"]
1510 , D.fillSep [D.cyan "port","receive",":","(String -> msg) -> Sub msg"]
1512 , D.reflow $
1513 "The first line defines a `send` port so you can send strings out to JavaScript.\
1514 \ Maybe you send them on a WebSocket or put them into IndexedDB. The second line\
1515 \ defines a `receive` port so you can receive strings from JavaScript. Maybe you\
1516 \ get receive messages when new WebSocket messages come in or when the IndexedDB\
1517 \ is changed for some external reason."
1522-- DECL TYPE
1525toDeclTypeReport :: Code.Source -> DeclType -> Row -> Col -> Report.Report
1526toDeclTypeReport source declType startRow startCol =
1527 case declType of
1528 DT_Space space row col ->
1529 toSpaceReport source space row col
1531 DT_Name row col ->
1532 let
1533 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1534 region = toRegion row col
1535 in
1536 Report.Report "EXPECTING TYPE NAME" region [] $
1537 Code.toSnippet source surroundings (Just region)
1539 D.reflow $
1540 "I think I am parsing a type declaration, but I got stuck here:"
1542 D.stack
1543 [ D.fillSep $
1544 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1545 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1547 , customTypeNote
1551 DT_Alias typeAlias row col ->
1552 toTypeAliasReport source typeAlias row col
1554 DT_Union customType row col ->
1555 toCustomTypeReport source customType row col
1557 DT_IndentName row col ->
1558 let
1559 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1560 region = toRegion row col
1561 in
1562 Report.Report "EXPECTING TYPE NAME" region [] $
1563 Code.toSnippet source surroundings (Just region)
1565 D.reflow $
1566 "I think I am parsing a type declaration, but I got stuck here:"
1568 D.stack
1569 [ D.fillSep $
1570 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1571 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1573 , customTypeNote
1578toTypeAliasReport :: Code.Source -> TypeAlias -> Row -> Col -> Report.Report
1579toTypeAliasReport source typeAlias startRow startCol =
1580 case typeAlias of
1581 AliasSpace space row col ->
1582 toSpaceReport source space row col
1584 AliasName row col ->
1585 let
1586 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1587 region = toRegion row col
1588 in
1589 Report.Report "EXPECTING TYPE ALIAS NAME" region [] $
1590 Code.toSnippet source surroundings (Just region)
1592 D.reflow $
1593 "I am partway through parsing a type alias, but I got stuck here:"
1595 D.stack
1596 [ D.fillSep $
1597 ["I","was","expecting","a","name","like",D.dullyellow "Person","or",D.dullyellow "Point"
1598 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1600 , typeAliasNote
1604 AliasEquals row col ->
1605 case Code.whatIsNext source row col of
1606 Code.Keyword keyword ->
1607 let
1608 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1609 region = toKeywordRegion row col keyword
1610 in
1611 Report.Report "RESERVED WORD" region [] $
1612 Code.toSnippet source surroundings (Just region)
1614 D.reflow $
1615 "I ran into a reserved word unexpectedly while parsing this type alias:"
1617 D.stack
1618 [ D.reflow $
1619 "It looks like you are trying use `" ++ keyword
1620 ++ "` as a type variable, but it is a reserved word. Try using a different name?"
1621 , typeAliasNote
1625 _ ->
1626 let
1627 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1628 region = toRegion row col
1629 in
1630 Report.Report "PROBLEM IN TYPE ALIAS" region [] $
1631 Code.toSnippet source surroundings (Just region)
1633 D.reflow $
1634 "I am partway through parsing a type alias, but I got stuck here:"
1636 D.stack
1637 [ D.reflow $
1638 "I was expecting to see a type variable or an an equals sign next."
1639 , typeAliasNote
1643 AliasBody tipe row col ->
1644 toTypeReport source TC_TypeAlias tipe row col
1646 AliasIndentEquals row col ->
1647 let
1648 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1649 region = toRegion row col
1650 in
1651 Report.Report "UNFINISHED TYPE ALIAS" region [] $
1652 Code.toSnippet source surroundings (Just region)
1654 D.reflow $
1655 "I am partway through parsing a type alias, but I got stuck here:"
1657 D.stack
1658 [ D.reflow $
1659 "I was expecting to see a type variable or an an equals sign next."
1660 , typeAliasNote
1664 AliasIndentBody row col ->
1665 let
1666 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1667 region = toRegion row col
1668 in
1669 Report.Report "UNFINISHED TYPE ALIAS" region [] $
1670 Code.toSnippet source surroundings (Just region)
1672 D.reflow $
1673 "I am partway through parsing a type alias, but I got stuck here:"
1675 D.stack
1676 [ D.fillSep $
1677 ["I","was","expecting","to","see","a","type","next.","Something","as","simple"
1678 ,"as",D.dullyellow "Int","or",D.dullyellow "Float","would","work!"
1680 , typeAliasNote
1685typeAliasNote :: D.Doc
1686typeAliasNote =
1687 D.stack
1688 [ D.toSimpleNote $
1689 "Here is an example of a valid `type alias` for reference:"
1690 , D.vcat $
1691 [ D.indent 0 $ D.fillSep [D.cyan "type",D.cyan "alias",D.green "Person","="]
1692 , D.indent 2 $ D.vcat $
1693 ["{ name : String"
1694 ,", age : Int"
1695 ,", height : Float"
1696 ,"}"
1699 , D.reflow $
1700 "This would let us use `Person` as a shorthand for that record type. Using this\
1701 \ shorthand makes type annotations much easier to read, and makes changing code\
1702 \ easier if you decide later that there is more to a person than age and height!"
1706toCustomTypeReport :: Code.Source -> CustomType -> Row -> Col -> Report.Report
1707toCustomTypeReport source customType startRow startCol =
1708 case customType of
1709 CT_Space space row col ->
1710 toSpaceReport source space row col
1712 CT_Name row col ->
1713 let
1714 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1715 region = toRegion row col
1716 in
1717 Report.Report "EXPECTING TYPE NAME" region [] $
1718 Code.toSnippet source surroundings (Just region)
1720 D.reflow $
1721 "I think I am parsing a type declaration, but I got stuck here:"
1723 D.stack
1724 [ D.fillSep $
1725 ["I","was","expecting","a","name","like",D.dullyellow "Status","or",D.dullyellow "Style"
1726 ,"next.","Just","make","sure","it","is","a","name","that","starts","with","a","capital","letter!"
1728 , customTypeNote
1732 CT_Equals row col ->
1733 case Code.whatIsNext source row col of
1734 Code.Keyword keyword ->
1735 let
1736 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1737 region = toKeywordRegion row col keyword
1738 in
1739 Report.Report "RESERVED WORD" region [] $
1740 Code.toSnippet source surroundings (Just region)
1742 D.reflow $
1743 "I ran into a reserved word unexpectedly while parsing this custom type:"
1745 D.stack
1746 [ D.reflow $
1747 "It looks like you are trying use `" ++ keyword
1748 ++ "` as a type variable, but it is a reserved word. Try using a different name?"
1749 , customTypeNote
1753 _ ->
1754 let
1755 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1756 region = toRegion row col
1757 in
1758 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
1759 Code.toSnippet source surroundings (Just region)
1761 D.reflow $
1762 "I am partway through parsing a custom type, but I got stuck here:"
1764 D.stack
1765 [ D.reflow $
1766 "I was expecting to see a type variable or an an equals sign next."
1767 , customTypeNote
1771 CT_Bar row col ->
1772 let
1773 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1774 region = toRegion row col
1775 in
1776 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
1777 Code.toSnippet source surroundings (Just region)
1779 D.reflow $
1780 "I am partway through parsing a custom type, but I got stuck here:"
1782 D.stack
1783 [ D.reflow $
1784 "I was expecting to see a vertical bar like | next."
1785 , customTypeNote
1789 CT_Variant row col ->
1790 let
1791 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1792 region = toRegion row col
1793 in
1794 Report.Report "PROBLEM IN CUSTOM TYPE" region [] $
1795 Code.toSnippet source surroundings (Just region)
1797 D.reflow $
1798 "I am partway through parsing a custom type, but I got stuck here:"
1800 D.stack
1801 [ D.fillSep $
1802 ["I","was","expecting","to","see","a","variant","name","next."
1803 ,"Something","like",D.dullyellow "Success","or",D.dullyellow "Sandwich" <> "."
1804 ,"Any","name","that","starts","with","a","capital","letter","really!"
1806 , customTypeNote
1810 CT_VariantArg tipe row col ->
1811 toTypeReport source TC_CustomType tipe row col
1813 CT_IndentEquals row col ->
1814 let
1815 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1816 region = toRegion row col
1817 in
1818 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1819 Code.toSnippet source surroundings (Just region)
1821 D.reflow $
1822 "I am partway through parsing a custom type, but I got stuck here:"
1824 D.stack
1825 [ D.reflow $
1826 "I was expecting to see a type variable or an an equals sign next."
1827 , customTypeNote
1831 CT_IndentBar row col ->
1832 let
1833 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1834 region = toRegion row col
1835 in
1836 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1837 Code.toSnippet source surroundings (Just region)
1839 D.reflow $
1840 "I am partway through parsing a custom type, but I got stuck here:"
1842 D.stack
1843 [ D.reflow $
1844 "I was expecting to see a vertical bar like | next."
1845 , customTypeNote
1849 CT_IndentAfterBar row col ->
1850 let
1851 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1852 region = toRegion row col
1853 in
1854 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1855 Code.toSnippet source surroundings (Just region)
1857 D.reflow $
1858 "I am partway through parsing a custom type, but I got stuck here:"
1860 D.stack
1861 [ D.reflow $
1862 "I just saw a vertical bar, so I was expecting to see another variant defined next."
1863 , customTypeNote
1867 CT_IndentAfterEquals row col ->
1868 let
1869 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1870 region = toRegion row col
1871 in
1872 Report.Report "UNFINISHED CUSTOM TYPE" region [] $
1873 Code.toSnippet source surroundings (Just region)
1875 D.reflow $
1876 "I am partway through parsing a custom type, but I got stuck here:"
1878 D.stack
1879 [ D.reflow $
1880 "I just saw an equals sign, so I was expecting to see the first variant defined next."
1881 , customTypeNote
1886customTypeNote :: D.Doc
1887customTypeNote =
1888 D.stack
1889 [ D.toSimpleNote $
1890 "Here is an example of a valid `type` declaration for reference:"
1891 , D.vcat $
1892 [ D.indent 0 $ D.fillSep [D.cyan "type",D.green "Status"]
1893 , D.indent 2 $ D.fillSep ["=","Failure"]
1894 , D.indent 2 $ D.fillSep ["|","Waiting"]
1895 , D.indent 2 $ D.fillSep ["|","Success","String"]
1897 , D.reflow $
1898 "This defines a new `Status` type with three variants. This could be useful if\
1899 \ we are waiting for an HTTP request. Maybe we start with `Waiting` and then\
1900 \ switch to `Failure` or `Success \"message from server\"` depending on how\
1901 \ things go. Notice that the Success variant has some associated data, allowing\
1902 \ us to store a String if the request goes well!"
1907-- DECL DEF
1910toDeclDefReport :: Code.Source -> Name.Name -> DeclDef -> Row -> Col -> Report.Report
1911toDeclDefReport source name declDef startRow startCol =
1912 case declDef of
1913 DeclDefSpace space row col ->
1914 toSpaceReport source space row col
1916 DeclDefEquals row col ->
1917 case Code.whatIsNext source row col of
1918 Code.Keyword keyword ->
1919 let
1920 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1921 region = toKeywordRegion row col keyword
1922 in
1923 Report.Report "RESERVED WORD" region [] $
1924 Code.toSnippet source surroundings (Just region)
1926 D.reflow $
1927 "It looks like you are trying to use `" ++ keyword ++ "` as an argument:"
1929 D.reflow $
1930 "This is a reserved word! Try using some other name?"
1933 Code.Operator op ->
1934 let
1935 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1936 region = toKeywordRegion row col op
1937 in
1938 Report.Report "UNEXPECTED SYMBOL" region [] $
1939 Code.toSnippet source surroundings (Just region)
1941 D.reflow $
1942 "I was not expecting to see this symbol here:"
1944 D.stack
1945 [ D.reflow $
1946 "I am not sure what is going wrong exactly, so here is a valid\
1947 \ definition (with an optional type annotation) for reference:"
1948 , D.vcat
1949 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
1950 , D.fillSep [D.green "add","x","y","="]
1951 , D.fillSep [" ","x","+","y"]
1953 , D.reflow $
1954 "Try to use that format with your `" ++ Name.toChars name ++ "` definition!"
1958 _ ->
1959 let
1960 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1961 region = toRegion row col
1962 in
1963 Report.Report "PROBLEM IN DEFINITION" region [] $
1964 Code.toSnippet source surroundings (Just region)
1966 D.reflow $
1967 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
1969 D.stack
1970 [ D.reflow $
1971 "I am not sure what is going wrong exactly, so here is a valid\
1972 \ definition (with an optional type annotation) for reference:"
1973 , D.vcat
1974 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
1975 , D.fillSep [D.green "add","x","y","="]
1976 , D.fillSep [" ","x","+","y"]
1978 , D.reflow $
1979 "Try to use that format!"
1983 DeclDefType tipe row col ->
1984 toTypeReport source (TC_Annotation name) tipe row col
1986 DeclDefArg pattern row col ->
1987 toPatternReport source PArg pattern row col
1989 DeclDefBody expr row col ->
1990 toExprReport source (InDef name startRow startCol) expr row col
1992 DeclDefNameRepeat row col ->
1993 let
1994 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1995 region = toRegion row col
1996 in
1997 Report.Report "EXPECTING DEFINITION" region [] $
1998 Code.toSnippet source surroundings (Just region)
2000 D.reflow $
2001 "I just saw the type annotation for `" ++ Name.toChars name
2002 ++ "` so I was expecting to see its definition here:"
2004 D.stack
2005 [ D.reflow $
2006 "Type annotations always appear directly above the relevant\
2007 \ definition, without anything else in between. (Not even doc comments!)"
2008 , declDefNote
2012 DeclDefNameMatch defName row col ->
2013 let
2014 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2015 region = toRegion row col
2016 in
2017 Report.Report "NAME MISMATCH" region [] $
2018 Code.toSnippet source surroundings (Just region)
2020 D.reflow $
2021 "I just saw a type annotation for `" ++ Name.toChars name ++ "`, but it is followed by a definition for `" ++ Name.toChars defName ++ "`:"
2023 D.stack
2024 [ D.reflow $
2025 "These names do not match! Is there a typo?"
2026 , D.indent 4 $ D.fillSep $
2027 [D.dullyellow (D.fromName defName),"->",D.green (D.fromName name)]
2031 DeclDefIndentType row col ->
2032 let
2033 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2034 region = toRegion row col
2035 in
2036 Report.Report "UNFINISHED DEFINITION" region [] $
2037 Code.toSnippet source surroundings (Just region)
2039 D.reflow $
2040 "I got stuck while parsing the `" ++ Name.toChars name ++ "` type annotation:"
2042 D.stack
2043 [ D.reflow $
2044 "I just saw a colon, so I am expecting to see a type next."
2045 , declDefNote
2049 DeclDefIndentEquals row col ->
2050 let
2051 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2052 region = toRegion row col
2053 in
2054 Report.Report "UNFINISHED DEFINITION" region [] $
2055 Code.toSnippet source surroundings (Just region)
2057 D.reflow $
2058 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
2060 D.stack
2061 [ D.reflow $
2062 "I was expecting to see an argument or an equals sign next."
2063 , declDefNote
2067 DeclDefIndentBody row col ->
2068 let
2069 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2070 region = toRegion row col
2071 in
2072 Report.Report "UNFINISHED DEFINITION" region [] $
2073 Code.toSnippet source surroundings (Just region)
2075 D.reflow $
2076 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
2078 D.stack
2079 [ D.reflow $
2080 "I was expecting to see an expression next. What is it equal to?"
2081 , declDefNote
2086declDefNote :: D.Doc
2087declDefNote =
2088 D.stack
2089 [ D.reflow $
2090 "Here is a valid definition (with a type annotation) for reference:"
2091 , D.vcat
2092 [ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
2093 , D.fillSep [D.green "add","x","y","="]
2094 , D.fillSep [" ","x","+","y"]
2096 , D.reflow $
2097 "The top line (called a \"type annotation\") is optional. You can leave it off\
2098 \ if you want. As you get more comfortable with Elm and as your project grows,\
2099 \ it becomes more and more valuable to add them though! They work great as\
2100 \ compiler-verified documentation, and they often improve error messages!"
2105-- CONTEXT
2108data Context
2109 = InNode Node Row Col Context
2110 | InDef Name.Name Row Col
2111 | InDestruct Row Col
2114data Node
2115 = NRecord
2116 | NParens
2117 | NList
2118 | NFunc
2119 | NCond
2120 | NThen
2121 | NElse
2122 | NCase
2123 | NBranch
2124 deriving (Eq)
2127getDefName :: Context -> Maybe Name.Name
2128getDefName context =
2129 case context of
2130 InDestruct _ _ -> Nothing
2131 InDef name _ _ -> Just name
2132 InNode _ _ _ c -> getDefName c
2135isWithin :: Node -> Context -> Bool
2136isWithin desiredNode context =
2137 case context of
2138 InDestruct _ _ -> False
2139 InDef _ _ _ -> False
2140 InNode actualNode _ _ _ -> desiredNode == actualNode
2144-- EXPR REPORTS
2147toExprReport :: Code.Source -> Context -> Expr -> Row -> Col -> Report.Report
2148toExprReport source context expr startRow startCol =
2149 case expr of
2150 Let let_ row col ->
2151 toLetReport source context let_ row col
2153 Case case_ row col ->
2154 toCaseReport source context case_ row col
2156 If if_ row col ->
2157 toIfReport source context if_ row col
2159 List list row col ->
2160 toListReport source context list row col
2162 Record record row col ->
2163 toRecordReport source context record row col
2165 Tuple tuple row col ->
2166 toTupleReport source context tuple row col
2168 Func func row col ->
2169 toFuncReport source context func row col
2171 Dot row col ->
2172 let region = toRegion row col in
2173 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
2174 Code.toSnippet source region Nothing
2176 D.reflow $
2177 "I was expecting to see a record accessor here:"
2179 D.fillSep
2180 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
2181 ,"that","accesses","a","value","from","a","record."
2185 Access row col ->
2186 let region = toRegion row col in
2187 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
2188 Code.toSnippet source region Nothing
2190 D.reflow $
2191 "I am trying to parse a record accessor here:"
2193 D.stack
2195 D.fillSep
2196 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
2197 ,"that","accesses","a","value","from","a","record."
2200 D.toSimpleNote $
2201 "Record field names must start with a lower case letter!"
2205 OperatorRight op row col ->
2206 let region = toRegion row col in
2207 Report.Report "MISSING EXPRESSION" region [] $
2208 Code.toSnippet source region Nothing
2210 D.reflow $
2211 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
2213 D.stack
2214 [ D.fillSep $
2215 ["You","can","just","put","anything","for","now,","like"
2216 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
2217 ,"Once","there","is","something","there,","I","can","probably"
2218 ,"give","a","more","specific","hint!"
2220 , D.toSimpleNote $
2221 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
2222 \ Or if I run into operators in unexpected spots. Point is, there are a\
2223 \ couple ways I can get confused and give sort of weird advice!"
2227 OperatorReserved operator row col ->
2228 toOperatorReport source context operator row col
2230 Start row col ->
2231 let
2232 (contextRow, contextCol, aThing) =
2233 case context of
2234 InDestruct r c -> (r, c, "a definition")
2235 InDef name r c -> (r, c, "the `" ++ Name.toChars name ++ "` definition")
2236 InNode NRecord r c _ -> (r, c, "a record")
2237 InNode NParens r c _ -> (r, c, "some parentheses")
2238 InNode NList r c _ -> (r, c, "a list")
2239 InNode NFunc r c _ -> (r, c, "an anonymous function")
2240 InNode NCond r c _ -> (r, c, "an `if` expression")
2241 InNode NThen r c _ -> (r, c, "an `if` expression")
2242 InNode NElse r c _ -> (r, c, "an `if` expression")
2243 InNode NCase r c _ -> (r, c, "a `case` expression")
2244 InNode NBranch r c _ -> (r, c, "a `case` expression")
2245 -- TODO check if this is actually the best way to get error messages here
2247 surroundings = A.Region (A.Position contextRow contextCol) (A.Position row col)
2248 region = toRegion row col
2249 in
2250 Report.Report "MISSING EXPRESSION" region [] $
2251 Code.toSnippet source surroundings (Just region)
2253 D.reflow $
2254 "I am partway through parsing " ++ aThing ++ ", but I got stuck here:"
2256 D.stack
2257 [ D.fillSep $
2258 ["I","was","expecting","to","see","an","expression","like"
2259 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
2260 ,"Once","there","is","something","there,","I","can","probably"
2261 ,"give","a","more","specific","hint!"
2263 , D.toSimpleNote $
2264 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
2265 \ Or if I run into operators in unexpected spots. Point is, there are a\
2266 \ couple ways I can get confused and give sort of weird advice!"
2270 Char char row col ->
2271 toCharReport source char row col
2273 String string row col ->
2274 toStringReport source string row col
2276 Number number row col ->
2277 toNumberReport source number row col
2279 Space space row col ->
2280 toSpaceReport source space row col
2282 EndlessShader row col ->
2283 let
2284 region = toWiderRegion row col 6
2285 in
2286 Report.Report "ENDLESS SHADER" region [] $
2287 Code.toSnippet source region Nothing
2289 D.reflow "I cannot find the end of this shader:"
2291 D.reflow "Add a |] somewhere after this to end the shader."
2294 ShaderProblem problem row col ->
2295 let
2296 region = toRegion row col
2297 in
2298 Report.Report "SHADER PROBLEM" region [] $
2299 Code.toSnippet source region Nothing
2301 D.reflow $
2302 "I ran into a problem while parsing this GLSL block."
2304 D.stack
2305 [ D.reflow $
2306 "I use a 3rd party GLSL parser for now, and I did my best to extract their error message:"
2307 , D.indent 4 $ D.vcat $
2308 map D.fromChars (filter (/="") (lines problem))
2312 IndentOperatorRight op row col ->
2313 let
2314 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2315 region = toRegion row col
2316 in
2317 Report.Report "MISSING EXPRESSION" region [] $
2318 Code.toSnippet source surroundings (Just region)
2320 D.reflow $
2321 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
2323 D.stack
2325 D.fillSep $
2326 ["You","can","just","put","anything","for","now,","like"
2327 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
2328 ,"Once","there","is","something","there,","I","can","probably"
2329 ,"give","a","more","specific","hint!"
2332 D.toSimpleNote $
2333 "I may be getting confused by your indentation? The easiest way to make sure\
2334 \ this is not an indentation problem is to put the expression on the right of\
2335 \ the " ++ Name.toChars op ++ " operator on the same line."
2341-- CHAR
2344toCharReport :: Code.Source -> Char -> Row -> Col -> Report.Report
2345toCharReport source char row col =
2346 case char of
2347 CharEndless ->
2348 let
2349 region = toRegion row col
2350 in
2351 Report.Report "MISSING SINGLE QUOTE" region [] $
2352 Code.toSnippet source region Nothing
2354 D.reflow $
2355 "I thought I was parsing a character, but I got to the end of\
2356 \ the line without seeing the closing single quote:"
2358 D.reflow $
2359 "Add a closing single quote here!"
2362 CharEscape escape ->
2363 toEscapeReport source escape row col
2365 CharNotString width ->
2366 let
2367 region = toWiderRegion row col width
2368 in
2369 Report.Report "NEEDS DOUBLE QUOTES" region [] $
2370 Code.toSnippet source region Nothing
2372 "The following string uses single quotes:"
2374 D.stack
2375 [ "Please switch to double quotes instead:"
2376 , D.indent 4 $
2377 D.dullyellow "'this'" <> " => " <> D.green "\"this\""
2378 , D.toSimpleNote $
2379 "Elm uses double quotes for strings like \"hello\", whereas it uses single\
2380 \ quotes for individual characters like 'a' and 'ø'. This distinction helps with\
2381 \ code like (String.any (\\c -> c == 'X') \"90210\") where you are inspecting\
2382 \ individual characters."
2388-- STRING
2391toStringReport :: Code.Source -> String -> Row -> Col -> Report.Report
2392toStringReport source string row col =
2393 case string of
2394 StringEndless_Single ->
2395 let
2396 region = toRegion row col
2397 in
2398 Report.Report "ENDLESS STRING" region [] $
2399 Code.toSnippet source region Nothing
2401 D.reflow $
2402 "I got to the end of the line without seeing the closing double quote:"
2404 D.stack
2405 [ D.fillSep $
2406 ["Strings","look","like",D.green "\"this\"","with","double"
2407 ,"quotes","on","each","end.","Is","the","closing","double"
2408 ,"quote","missing","in","your","code?"
2410 , D.link "Note" "Read" "TODO" "if you want a string that spans multiple lines."
2414 StringEndless_Multi ->
2415 let
2416 region = toWiderRegion row col 3
2417 in
2418 Report.Report "ENDLESS STRING" region [] $
2419 Code.toSnippet source region Nothing
2421 D.reflow $
2422 "I cannot find the end of this multi-line string:"
2424 D.stack
2425 [ D.reflow "Add a \"\"\" somewhere after this to end the string."
2426 , D.link "Hint" "Read" "TODO" "for more information on strings and multi-line strings."
2430 StringEscape escape ->
2431 toEscapeReport source escape row col
2435-- ESCAPES
2438toEscapeReport :: Code.Source -> Escape -> Row -> Col -> Report.Report
2439toEscapeReport source escape row col =
2440 case escape of
2441 EscapeUnknown ->
2442 let
2443 region = toWiderRegion row col 2
2444 in
2445 Report.Report "UNKNOWN ESCAPE" region [] $
2446 Code.toSnippet source region Nothing
2448 D.reflow $
2449 "Backslashes always start escaped characters, but I do not recognize this one:"
2451 D.stack
2452 [ D.reflow $
2453 "Valid escape characters include:"
2454 , D.dullyellow $ D.indent 4 $ D.vcat $
2455 [ "\\n"
2456 , "\\r"
2457 , "\\t"
2458 , "\\\""
2459 , "\\\'"
2460 , "\\\\"
2461 , "\\u{003D}"
2463 , D.reflow $
2464 "Do you want one of those instead? Maybe you need \\\\ to escape a backslash?"
2465 , D.toSimpleNote $
2466 "The last style lets encode ANY character by its Unicode code\
2467 \ point. That means \\u{0009} and \\t are the same. You can use\
2468 \ that style for anything not covered by the other six escapes!"
2472 BadUnicodeFormat width ->
2473 let
2474 region = toWiderRegion row col width
2475 in
2476 Report.Report "BAD UNICODE ESCAPE" region [] $
2477 Code.toSnippet source region Nothing
2479 D.reflow $
2480 "I ran into an invalid Unicode escape:"
2482 D.stack
2483 [ D.reflow $
2484 "Here are some examples of valid Unicode escapes:"
2485 , D.dullyellow $ D.indent 4 $ D.vcat $
2486 [ "\\u{0041}"
2487 , "\\u{03BB}"
2488 , "\\u{6728}"
2489 , "\\u{1F60A}"
2491 , D.reflow $
2492 "Notice that the code point is always surrounded by curly braces.\
2493 \ Maybe you are missing the opening or closing curly brace?"
2496 BadUnicodeCode width ->
2497 let
2498 region = toWiderRegion row col width
2499 in
2500 Report.Report "BAD UNICODE ESCAPE" region [] $
2501 Code.toSnippet source region Nothing
2503 D.reflow $
2504 "This is not a valid code point:"
2506 D.reflow $
2507 "The valid code points are between 0 and 10FFFF inclusive."
2510 BadUnicodeLength width numDigits badCode ->
2511 let
2512 region = toWiderRegion row col width
2513 in
2514 Report.Report "BAD UNICODE ESCAPE" region [] $
2515 Code.toSnippet source region Nothing $
2516 if numDigits < 4 then
2518 D.reflow $
2519 "Every code point needs at least four digits:"
2521 let
2522 goodCode = replicate (4 - numDigits) '0' ++ map Char.toUpper (showHex badCode "")
2523 suggestion = "\\u{" <> D.fromChars goodCode <> "}"
2524 in
2525 D.fillSep ["Try",D.green suggestion,"instead?"]
2528 else
2530 D.reflow $
2531 "This code point has too many digits:"
2533 D.fillSep $
2534 ["Valid","code","points","are","between"
2535 ,D.green "\\u{0000}","and",D.green "\\u{10FFFF}" <> ","
2536 ,"so","try","trimming","any","leading","zeros","until"
2537 ,"you","have","between","four","and","six","digits."
2543-- NUMBERS
2546toNumberReport :: Code.Source -> Number -> Row -> Col -> Report.Report
2547toNumberReport source number row col =
2548 let
2549 region = toRegion row col
2550 in
2551 case number of
2552 NumberEnd ->
2553 Report.Report "WEIRD NUMBER" region [] $
2554 Code.toSnippet source region Nothing
2556 D.reflow $
2557 "I thought I was reading a number, but I ran into some weird stuff here:"
2559 D.stack
2560 [ D.reflow $
2561 "I recognize numbers in the following formats:"
2562 , D.indent 4 $ D.vcat [ "42", "3.14", "6.022e23", "0x002B" ]
2563 , D.reflow $
2564 "So is there a way to write it like one of those?"
2568 NumberDot int ->
2569 Report.Report "WEIRD NUMBER" region [] $
2570 Code.toSnippet source region Nothing
2572 D.reflow $
2573 "Numbers cannot end with a dot like this:"
2575 D.fillSep
2576 ["Switching","to",D.green (D.fromChars (show int))
2577 ,"or",D.green (D.fromChars (show int ++ ".0"))
2578 ,"will","work","though!"
2582 NumberHexDigit ->
2583 Report.Report "WEIRD HEXIDECIMAL" region [] $
2584 Code.toSnippet source region Nothing
2586 D.reflow $
2587 "I thought I was reading a hexidecimal number until I got here:"
2589 D.stack
2590 [ D.reflow $
2591 "Valid hexidecimal digits include 0123456789abcdefABCDEF, so I can\
2592 \ only recognize things like this:"
2593 , D.indent 4 $ D.vcat [ "0x2B", "0x002B", "0x00ffb3" ]
2597 NumberNoLeadingZero ->
2598 Report.Report "LEADING ZEROS" region [] $
2599 Code.toSnippet source region Nothing
2601 D.reflow $
2602 "I do not accept numbers with leading zeros:"
2604 D.stack
2605 [ D.reflow $
2606 "Just delete the leading zeros and it should work!"
2607 , D.toSimpleNote $
2608 "Some languages let you to specify octal numbers by adding a leading zero.\
2609 \ So in C, writing 0111 is the same as writing 73. Some people are used to\
2610 \ that, but others probably want it to equal 111. Either path is going to\
2611 \ surprise people from certain backgrounds, so Elm tries to avoid this whole\
2612 \ situation."
2618-- OPERATORS
2621toOperatorReport :: Code.Source -> Context -> BadOperator -> Row -> Col -> Report.Report
2622toOperatorReport source context operator row col =
2623 case operator of
2624 BadDot ->
2625 let
2626 region = toRegion row col
2627 in
2628 Report.Report "UNEXPECTED SYMBOL" region [] $
2629 Code.toSnippet source region Nothing
2631 "I was not expecting this dot:"
2633 D.reflow $
2634 "Dots are for record access and decimal points, so\
2635 \ they cannot float around on their own. Maybe\
2636 \ there is some extra whitespace?"
2639 BadPipe ->
2640 let
2641 region = toRegion row col
2642 in
2643 Report.Report "UNEXPECTED SYMBOL" region [] $
2644 Code.toSnippet source region Nothing
2646 D.reflow $
2647 "I was not expecting this vertical bar:"
2649 D.reflow $
2650 "Vertical bars should only appear in custom type declarations. Maybe you want || instead?"
2653 BadArrow ->
2654 let
2655 region = toWiderRegion row col 2
2656 in
2657 Report.Report "UNEXPECTED ARROW" region [] $
2658 Code.toSnippet source region Nothing $
2659 if isWithin NBranch context then
2661 D.reflow $
2662 "I was not expecting to see an arrow here:"
2664 D.stack
2666 D.reflow $
2667 "I think I am parsing a `case` expression right now, so it makes sense to\
2668 \ see arrows around here. This one is confusing me though!"
2670 D.toSimpleHint $
2671 "I may be getting confused by the indentation. Every pattern in a `case` must be\
2672 \ exactly aligned (with exactly the same amount of indentation) so maybe this arrow\
2673 \ appears after the next `case` pattern (correctly!) but the pattern itself is\
2674 \ indented too far?"
2678 else
2680 D.reflow $
2681 "I was not expecting an arrow here:"
2683 D.reflow $
2684 "Arrows should only appear in `case` expressions and anonymous functions. Maybe\
2685 \ you want > or >= instead?"
2688 BadEquals ->
2689 let
2690 region = toRegion row col
2691 in
2692 Report.Report "UNEXPECTED EQUALS" region [] $
2693 Code.toSnippet source region Nothing
2695 D.reflow $
2696 "I was not expecting to see this equals sign:"
2698 D.stack
2700 D.reflow "Maybe you want == instead? To check if two values are equal?"
2702 D.toSimpleNote $
2703 if isWithin NRecord context then
2704 "Records look like { x = 3, y = 4 } with the equals sign right\
2705 \ after the field name. So maybe you forgot a comma?"
2706 else
2707 case getDefName context of
2708 Nothing ->
2709 "I may be getting confused by your indentation. I need all definitions to be indented\
2710 \ exactly the same amount, so if this is meant to be a new definition, it may have too\
2711 \ many spaces in front of it."
2713 Just name ->
2714 "I may be getting confused by your indentation. I think I am still parsing the `"
2715 ++ Name.toChars name ++ "` definition. Is this supposed to be part of a definition\
2716 \ after that? If so, the problem may be a bit before the equals sign. I need all\
2717 \ definitions to be indented exactly the same amount, so the problem may be that\
2718 \ this new definition has too many spaces in front of it."
2722 BadHasType ->
2723 let
2724 region = toRegion row col
2725 in
2726 Report.Report "UNEXPECTED SYMBOL" region [] $
2727 Code.toSnippet source region Nothing $
2729 D.reflow $
2730 "I was not expecting to run into the \"has type\" symbol here:"
2732 case getDefName context of
2733 Nothing ->
2734 D.fillSep
2735 ["Maybe","you","want",D.green "::","instead?"
2736 ,"To","put","something","on","the","front","of","a","list?"
2739 Just name ->
2740 D.stack
2742 D.fillSep
2743 ["Maybe","you","want",D.green "::","instead?"
2744 ,"To","put","something","on","the","front","of","a","list?"
2746 , D.toSimpleNote $
2747 "The single colon is reserved for type annotations and record types, but I think\
2748 \ I am parsing the definition of `" ++ Name.toChars name ++ "` right now."
2750 D.toSimpleNote $
2751 "I may be getting confused by your indentation. Is this supposed to be part of\
2752 \ a type annotation AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
2753 \ the problem may be a bit before the \"has type\" symbol. I need all definitions to\
2754 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
2755 \ this new definition is indented a bit too much."
2761-- CASE
2764toLetReport :: Code.Source -> Context -> Let -> Row -> Col -> Report.Report
2765toLetReport source context let_ startRow startCol =
2766 case let_ of
2767 LetSpace space row col ->
2768 toSpaceReport source space row col
2770 LetIn row col ->
2771 let
2772 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2773 region = toRegion row col
2774 in
2775 Report.Report "LET PROBLEM" region [] $
2776 Code.toSnippet source surroundings (Just region)
2778 D.reflow $
2779 "I was partway through parsing a `let` expression, but I got stuck here:"
2781 D.stack
2782 [ D.fillSep $
2783 ["Based","on","the","indentation,","I","was","expecting","to","see","the",D.cyan "in"
2784 ,"keyword","next.","Is","there","a","typo?"
2786 , D.toSimpleNote $
2787 "This can also happen if you are trying to define another value within the `let` but\
2788 \ it is not indented enough. Make sure each definition has exactly the same amount of\
2789 \ spaces before it. They should line up exactly!"
2793 LetDefAlignment _ row col ->
2794 let
2795 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2796 region = toRegion row col
2797 in
2798 Report.Report "LET PROBLEM" region [] $
2799 Code.toSnippet source surroundings (Just region)
2801 D.reflow $
2802 "I was partway through parsing a `let` expression, but I got stuck here:"
2804 D.stack
2805 [ D.fillSep $
2806 ["Based","on","the","indentation,","I","was","expecting","to","see","the",D.cyan "in"
2807 ,"keyword","next.","Is","there","a","typo?"
2809 , D.toSimpleNote $
2810 "This can also happen if you are trying to define another value within the `let` but\
2811 \ it is not indented enough. Make sure each definition has exactly the same amount of\
2812 \ spaces before it. The should line up exactly!"
2816 LetDefName row col ->
2817 case Code.whatIsNext source row col of
2818 Code.Keyword keyword ->
2819 let
2820 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2821 region = toKeywordRegion row col keyword
2822 in
2823 Report.Report "RESERVED WORD" region [] $
2824 Code.toSnippet source surroundings (Just region)
2826 D.reflow $
2827 "I was partway through parsing a `let` expression, but I got stuck here:"
2829 D.reflow $
2830 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name, but\
2831 \ it is a reserved word! Try using a different name instead."
2834 _ ->
2835 toUnfinishLetReport source row col startRow startCol $
2836 D.reflow $
2837 "I was expecting the name of a definition next."
2839 LetDef name def row col ->
2840 toLetDefReport source name def row col
2842 LetDestruct destruct row col ->
2843 toLetDestructReport source destruct row col
2845 LetBody expr row col ->
2846 toExprReport source context expr row col
2848 LetIndentDef row col ->
2849 toUnfinishLetReport source row col startRow startCol $
2850 D.reflow $
2851 "I was expecting a value to be defined here."
2853 LetIndentIn row col ->
2854 toUnfinishLetReport source row col startRow startCol $
2855 D.fillSep $
2856 ["I","was","expecting","to","see","the",D.cyan "in","keyword","next."
2857 ,"Or","maybe","more","of","that","expression?"
2860 LetIndentBody row col ->
2861 toUnfinishLetReport source row col startRow startCol $
2862 D.reflow $
2863 "I was expecting an expression next. Tell me what should happen with the value you just defined!"
2866toUnfinishLetReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
2867toUnfinishLetReport source row col startRow startCol message =
2868 let
2869 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2870 region = toRegion row col
2871 in
2872 Report.Report "UNFINISHED LET" region [] $
2873 Code.toSnippet source surroundings (Just region)
2875 D.reflow $
2876 "I was partway through parsing a `let` expression, but I got stuck here:"
2878 D.stack
2879 [ message
2880 , D.toSimpleNote $
2881 "Here is an example with a valid `let` expression for reference:"
2882 , D.vcat $
2883 [ D.indent 0 $ D.fillSep [D.green "viewPerson","person","="]
2884 , D.indent 2 $ D.fillSep [D.cyan "let"]
2885 , D.indent 4 $ D.fillSep ["fullName","="]
2886 , D.indent 6 $ D.fillSep ["person.firstName","++",D.dullyellow "\" \"","++","person.lastName"]
2887 , D.indent 2 $ D.fillSep [D.cyan "in"]
2888 , D.indent 2 $ D.fillSep ["div","[]","[","text","fullName","]"]
2890 , D.reflow $
2891 "Here we defined a `viewPerson` function that turns a person into some HTML. We use\
2892 \ a `let` expression to define the `fullName` we want to show. Notice the indentation! The\
2893 \ `fullName` is indented more than the `let` keyword, and the actual value of `fullName` is\
2894 \ indented a bit more than that. That is important!"
2899toLetDefReport :: Code.Source -> Name.Name -> Def -> Row -> Col -> Report.Report
2900toLetDefReport source name def startRow startCol =
2901 case def of
2902 DefSpace space row col ->
2903 toSpaceReport source space row col
2905 DefType tipe row col ->
2906 toTypeReport source (TC_Annotation name) tipe row col
2908 DefNameRepeat row col ->
2909 let
2910 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2911 region = toRegion row col
2912 in
2913 Report.Report "EXPECTING DEFINITION" region [] $
2914 Code.toSnippet source surroundings (Just region)
2916 D.reflow $
2917 "I just saw the type annotation for `" ++ Name.toChars name
2918 ++ "` so I was expecting to see its definition here:"
2920 D.stack
2921 [ D.reflow $
2922 "Type annotations always appear directly above the relevant\
2923 \ definition, without anything else in between."
2924 , defNote
2928 DefNameMatch defName row col ->
2929 let
2930 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2931 region = toRegion row col
2932 in
2933 Report.Report "NAME MISMATCH" region [] $
2934 Code.toSnippet source surroundings (Just region)
2936 D.reflow $
2937 "I just saw a type annotation for `" ++ Name.toChars name ++ "`, but it is followed by a definition for `" ++ Name.toChars defName ++ "`:"
2939 D.stack
2940 [ D.reflow $
2941 "These names do not match! Is there a typo?"
2942 , D.indent 4 $ D.fillSep $
2943 [D.dullyellow (D.fromName defName),"->",D.green (D.fromName name)]
2947 DefArg pattern row col ->
2948 toPatternReport source PArg pattern row col
2950 DefEquals row col ->
2951 case Code.whatIsNext source row col of
2952 Code.Keyword keyword ->
2953 let
2954 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2955 region = toKeywordRegion row col keyword
2956 in
2957 Report.Report "RESERVED WORD" region [] $
2958 Code.toSnippet source surroundings (Just region)
2960 D.reflow $
2961 "It looks like you are trying to use `" ++ keyword ++ "` as an argument:"
2963 D.reflow $
2964 "This is a reserved word! Try using some other name?"
2967 Code.Operator op ->
2968 let
2969 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2970 region = toKeywordRegion row col op
2971 in
2972 Report.Report "UNEXPECTED SYMBOL" region [] $
2973 Code.toSnippet source surroundings (Just region)
2975 D.reflow $
2976 "I was not expecting to see this symbol here:"
2978 D.stack
2979 [ D.reflow $
2980 "I am not sure what is going wrong exactly, so here is a valid\
2981 \ definition (with an optional type annotation) for reference:"
2982 , D.vcat
2983 [ D.indent 4 $ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
2984 , D.indent 4 $ D.fillSep [D.green "add","x","y","="]
2985 , D.indent 6 $ D.fillSep ["x","+","y"]
2987 , D.reflow $
2988 "Try to use that format with your `" ++ Name.toChars name ++ "` definition!"
2992 _ ->
2993 let
2994 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2995 region = toRegion row col
2996 in
2997 Report.Report "PROBLEM IN DEFINITION" region [] $
2998 Code.toSnippet source surroundings (Just region)
3000 D.reflow $
3001 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
3003 D.stack
3004 [ D.reflow $
3005 "I am not sure what is going wrong exactly, so here is a valid\
3006 \ definition (with an optional type annotation) for reference:"
3007 , D.vcat
3008 [ D.indent 4 $ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
3009 , D.indent 4 $ D.fillSep [D.green "add","x","y","="]
3010 , D.indent 4 $ D.fillSep ["x","+","y"]
3012 , D.reflow $
3013 "Try to use that format!"
3017 DefBody expr row col ->
3018 toExprReport source (InDef name startRow startCol) expr row col
3020 DefIndentEquals row col ->
3021 let
3022 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3023 region = toRegion row col
3024 in
3025 Report.Report "UNFINISHED DEFINITION" region [] $
3026 Code.toSnippet source surroundings (Just region)
3028 D.reflow $
3029 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
3031 D.stack
3032 [ D.reflow $
3033 "I was expecting to see an argument or an equals sign next."
3034 , defNote
3038 DefIndentType row col ->
3039 let
3040 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3041 region = toRegion row col
3042 in
3043 Report.Report "UNFINISHED DEFINITION" region [] $
3044 Code.toSnippet source surroundings (Just region)
3046 D.reflow $
3047 "I got stuck while parsing the `" ++ Name.toChars name ++ "` type annotation:"
3049 D.stack
3050 [ D.reflow $
3051 "I just saw a colon, so I am expecting to see a type next."
3052 , defNote
3056 DefIndentBody row col ->
3057 let
3058 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3059 region = toRegion row col
3060 in
3061 Report.Report "UNFINISHED DEFINITION" region [] $
3062 Code.toSnippet source surroundings (Just region)
3064 D.reflow $
3065 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
3067 D.stack
3068 [ D.reflow $
3069 "I was expecting to see an expression next. What is it equal to?"
3070 , declDefNote
3074 DefAlignment indent row col ->
3075 let
3076 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3077 region = toRegion row col
3078 offset = indent - col
3079 in
3080 Report.Report "PROBLEM IN DEFINITION" region [] $
3081 Code.toSnippet source surroundings (Just region)
3083 D.reflow $
3084 "I got stuck while parsing the `" ++ Name.toChars name ++ "` definition:"
3086 D.reflow $
3087 "I just saw a type annotation indented " ++ show indent ++ " spaces, so I was\
3088 \ expecting to see the corresponding definition next with the exact same amount\
3089 \ of indentation. It looks like this line needs "
3090 ++ show offset ++ " more " ++ (if offset == 1 then "space" else "spaces") ++ "?"
3095defNote :: D.Doc
3096defNote =
3097 D.stack
3098 [ D.reflow $
3099 "Here is a valid definition (with a type annotation) for reference:"
3100 , D.vcat
3101 [ D.indent 4 $ D.fillSep [D.green "add",":","Int","->","Int","->","Int"]
3102 , D.indent 4 $ D.fillSep [D.green "add","x","y","="]
3103 , D.indent 6 $ D.fillSep ["x","+","y"]
3105 , D.reflow $
3106 "The top line (called a \"type annotation\") is optional. You can leave it off\
3107 \ if you want. As you get more comfortable with Elm and as your project grows,\
3108 \ it becomes more and more valuable to add them though! They work great as\
3109 \ compiler-verified documentation, and they often improve error messages!"
3113toLetDestructReport :: Code.Source -> Destruct -> Row -> Col -> Report.Report
3114toLetDestructReport source destruct startRow startCol =
3115 case destruct of
3116 DestructSpace space row col ->
3117 toSpaceReport source space row col
3119 DestructPattern pattern row col ->
3120 toPatternReport source PLet pattern row col
3122 DestructEquals row col ->
3123 let
3124 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3125 region = toRegion row col
3126 in
3127 Report.Report "PROBLEM IN DEFINITION" region [] $
3128 Code.toSnippet source surroundings (Just region)
3130 D.reflow $
3131 "I got stuck trying to parse this definition:"
3133 case Code.whatIsNext source row col of
3134 Code.Operator ":" ->
3135 D.stack
3136 [ D.reflow $
3137 "I was expecting to see an equals sign next, followed by an expression\
3138 \ telling me what to compute."
3139 , D.toSimpleNote $
3140 "It looks like you may be trying to write a type annotation? It is not\
3141 \ possible to add type annotations on destructuring definitions like this.\
3142 \ You can assign a name to the overall structure, put a type annotation on\
3143 \ that, and then destructure separately though."
3146 _ ->
3147 D.reflow $
3148 "I was expecting to see an equals sign next, followed by an expression\
3149 \ telling me what to compute."
3152 DestructBody expr row col ->
3153 toExprReport source (InDestruct startRow startCol) expr row col
3155 DestructIndentEquals row col ->
3156 let
3157 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3158 region = toRegion row col
3159 in
3160 Report.Report "UNFINISHED DEFINITION" region [] $
3161 Code.toSnippet source surroundings (Just region)
3163 D.reflow $
3164 "I got stuck trying to parse this definition:"
3166 D.reflow $
3167 "I was expecting to see an equals sign next, followed by an expression\
3168 \ telling me what to compute."
3171 DestructIndentBody row col ->
3172 let
3173 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3174 region = toRegion row col
3175 in
3176 Report.Report "UNFINISHED DEFINITION" region [] $
3177 Code.toSnippet source surroundings (Just region)
3179 D.reflow $
3180 "I got stuck while parsing this definition:"
3182 D.reflow $
3183 "I was expecting to see an expression next. What is it equal to?"
3188-- CASE
3191toCaseReport :: Code.Source -> Context -> Case -> Row -> Col -> Report.Report
3192toCaseReport source context case_ startRow startCol =
3193 case case_ of
3194 CaseSpace space row col ->
3195 toSpaceReport source space row col
3197 CaseOf row col ->
3198 toUnfinishCaseReport source row col startRow startCol $
3199 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
3201 CasePattern pattern row col ->
3202 toPatternReport source PCase pattern row col
3204 CaseArrow row col ->
3205 case Code.whatIsNext source row col of
3206 Code.Keyword keyword ->
3207 let
3208 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3209 region = toKeywordRegion row col keyword
3210 in
3211 Report.Report "RESERVED WORD" region [] $
3212 Code.toSnippet source surroundings (Just region)
3214 D.reflow $
3215 "I am partway through parsing a `case` expression, but I got stuck here:"
3217 D.reflow $
3218 "It looks like you are trying to use `" ++ keyword ++ "` in one of your\
3219 \ patterns, but it is a reserved word. Try using a different name?"
3222 Code.Operator ":" ->
3223 let
3224 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3225 region = toRegion row col
3226 in
3227 Report.Report "UNEXPECTED OPERATOR" region [] $
3228 Code.toSnippet source surroundings (Just region)
3230 D.reflow $
3231 "I am partway through parsing a `case` expression, but I got stuck here:"
3233 D.fillSep $
3234 ["I","am","seeing",D.dullyellow ":","but","maybe","you","want",D.green "::","instead?"
3235 ,"For","pattern","matching","on","lists?"
3239 Code.Operator "=" ->
3240 let
3241 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3242 region = toRegion row col
3243 in
3244 Report.Report "UNEXPECTED OPERATOR" region [] $
3245 Code.toSnippet source surroundings (Just region)
3247 D.reflow $
3248 "I am partway through parsing a `case` expression, but I got stuck here:"
3250 D.fillSep $
3251 ["I","am","seeing",D.dullyellow "=","but","maybe","you","want",D.green "->","instead?"
3255 _ ->
3256 let
3257 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3258 region = toRegion row col
3259 in
3260 Report.Report "MISSING ARROW" region [] $
3261 Code.toSnippet source surroundings (Just region)
3263 D.reflow $
3264 "I am partway through parsing a `case` expression, but I got stuck here:"
3266 addNoteForCaseIndentError $
3267 D.reflow $
3268 "I was expecting to see an arrow next."
3271 CaseExpr expr row col ->
3272 toExprReport source (InNode NCase startRow startCol context) expr row col
3274 CaseBranch expr row col ->
3275 toExprReport source (InNode NBranch startRow startCol context) expr row col
3277 CaseIndentOf row col ->
3278 toUnfinishCaseReport source row col startRow startCol $
3279 D.fillSep ["I","was","expecting","to","see","the",D.dullyellow "of","keyword","next."]
3281 CaseIndentExpr row col ->
3282 toUnfinishCaseReport source row col startRow startCol $
3283 D.reflow "I was expecting to see a expression next."
3285 CaseIndentPattern row col ->
3286 toUnfinishCaseReport source row col startRow startCol $
3287 D.reflow "I was expecting to see a pattern next."
3289 CaseIndentArrow row col ->
3290 toUnfinishCaseReport source row col startRow startCol $
3291 D.fillSep
3292 ["I","just","saw","a","pattern,","so","I","was","expecting"
3293 ,"to","see","a",D.dullyellow "->","next."
3296 CaseIndentBranch row col ->
3297 toUnfinishCaseReport source row col startRow startCol $
3298 D.reflow $
3299 "I was expecting to see an expression next. What should I do when\
3300 \ I run into this particular pattern?"
3302 CasePatternAlignment indent row col ->
3303 toUnfinishCaseReport source row col startRow startCol $
3304 D.reflow $
3305 "I suspect this is a pattern that is not indented far enough? (" ++ show indent ++ " spaces)"
3308toUnfinishCaseReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
3309toUnfinishCaseReport source row col startRow startCol message =
3310 let
3311 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3312 region = toRegion row col
3313 in
3314 Report.Report "UNFINISHED CASE" region [] $
3315 Code.toSnippet source surroundings (Just region)
3317 D.reflow $
3318 "I was partway through parsing a `case` expression, but I got stuck here:"
3320 D.stack
3321 [ message
3322 , D.toSimpleNote $
3323 "Here is an example of a valid `case` expression for reference."
3324 , D.vcat $
3325 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
3326 , D.indent 6 $ D.fillSep [D.blue "Just","width","->"]
3327 , D.indent 8 $ D.fillSep ["width","+",D.dullyellow "200"]
3328 , ""
3329 , D.indent 6 $ D.fillSep [D.blue "Nothing","->"]
3330 , D.indent 8 $ D.fillSep [D.dullyellow "400"]
3332 , D.reflow $
3333 "Notice the indentation. Each pattern is aligned, and each branch is indented\
3334 \ a bit more than the corresponding pattern. That is important!"
3339addNoteForCaseIndentError :: D.Doc -> D.Doc
3340addNoteForCaseIndentError message =
3341 D.stack $
3342 message
3344 [ D.toSimpleNote $
3345 "Sometimes I get confused by indentation, so try to make your `case` look\
3346 \ something like this:"
3347 , D.vcat $
3348 [ D.indent 4 $ D.fillSep [D.cyan "case","maybeWidth",D.cyan "of"]
3349 , D.indent 6 $ D.fillSep [D.blue "Just","width","->"]
3350 , D.indent 8 $ D.fillSep ["width","+",D.dullyellow "200"]
3351 , ""
3352 , D.indent 6 $ D.fillSep [D.blue "Nothing","->"]
3353 , D.indent 8 $ D.fillSep [D.dullyellow "400"]
3355 , D.reflow $
3356 "Notice the indentation! Each pattern is aligned, and each branch is indented\
3357 \ a bit more than the corresponding pattern. That is important!"
3362-- IF
3365toIfReport :: Code.Source -> Context -> If -> Row -> Col -> Report.Report
3366toIfReport source context if_ startRow startCol =
3367 case if_ of
3368 IfSpace space row col ->
3369 toSpaceReport source space row col
3371 IfThen row col ->
3372 let
3373 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3374 region = toRegion row col
3375 in
3376 Report.Report "UNFINISHED IF" region [] $
3377 Code.toSnippet source surroundings (Just region)
3379 D.reflow $
3380 "I was expecting to see more of this `if` expression, but I got stuck here:"
3382 D.fillSep $
3383 ["I","was","expecting","to","see","the",D.cyan "then","keyword","next."
3387 IfElse row col ->
3388 let
3389 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3390 region = toRegion row col
3391 in
3392 Report.Report "UNFINISHED IF" region [] $
3393 Code.toSnippet source surroundings (Just region)
3395 D.reflow $
3396 "I was expecting to see more of this `if` expression, but I got stuck here:"
3398 D.fillSep $
3399 ["I","was","expecting","to","see","the",D.cyan "else","keyword","next."
3403 IfElseBranchStart row col ->
3404 let
3405 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3406 region = toRegion row col
3407 in
3408 Report.Report "UNFINISHED IF" region [] $
3409 Code.toSnippet source surroundings (Just region)
3411 D.reflow $
3412 "I just saw the start of an `else` branch, but then I got stuck here:"
3414 D.reflow $
3415 "I was expecting to see an expression next. Maybe it is not filled in yet?"
3418 IfCondition expr row col ->
3419 toExprReport source (InNode NCond startRow startCol context) expr row col
3421 IfThenBranch expr row col ->
3422 toExprReport source (InNode NThen startRow startCol context) expr row col
3424 IfElseBranch expr row col ->
3425 toExprReport source (InNode NElse startRow startCol context) expr row col
3427 IfIndentCondition row col ->
3428 let
3429 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3430 region = toRegion row col
3431 in
3432 Report.Report "UNFINISHED IF" region [] $
3433 Code.toSnippet source surroundings (Just region)
3435 D.reflow $
3436 "I was expecting to see more of this `if` expression, but I got stuck here:"
3438 D.stack
3439 [ D.fillSep $
3440 ["I","was","expecting","to","see","an","expression","like",D.dullyellow "x < 0"
3441 ,"that","evaluates","to","True","or","False."
3443 , D.toSimpleNote $
3444 "I can be confused by indentation. Maybe something is not indented enough?"
3448 IfIndentThen row col ->
3449 let
3450 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3451 region = toRegion row col
3452 in
3453 Report.Report "UNFINISHED IF" region [] $
3454 Code.toSnippet source surroundings (Just region)
3456 D.reflow $
3457 "I was expecting to see more of this `if` expression, but I got stuck here:"
3459 D.stack
3460 [ D.fillSep $
3461 ["I","was","expecting","to","see","the",D.cyan "then","keyword","next."
3463 , D.toSimpleNote $
3464 "I can be confused by indentation. Maybe something is not indented enough?"
3468 IfIndentThenBranch row col ->
3469 let
3470 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3471 region = toRegion row col
3472 in
3473 Report.Report "UNFINISHED IF" region [] $
3474 Code.toSnippet source surroundings (Just region)
3476 D.reflow $
3477 "I got stuck after the start of this `then` branch:"
3479 D.stack
3480 [ D.reflow $
3481 "I was expecting to see an expression next. Maybe it is not filled in yet?"
3482 , D.toSimpleNote $
3483 "I can be confused by indentation, so if the `then` branch is already\
3484 \ present, it may not be indented enough for me to recognize it."
3488 IfIndentElseBranch row col ->
3489 let
3490 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3491 region = toRegion row col
3492 in
3493 Report.Report "UNFINISHED IF" region [] $
3494 Code.toSnippet source surroundings (Just region)
3496 D.reflow $
3497 "I got stuck after the start of this `else` branch:"
3499 D.stack
3500 [ D.reflow $
3501 "I was expecting to see an expression next. Maybe it is not filled in yet?"
3502 , D.toSimpleNote $
3503 "I can be confused by indentation, so if the `else` branch is already\
3504 \ present, it may not be indented enough for me to recognize it."
3508 IfIndentElse row col ->
3509 let
3510 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3511 region = toRegion row col
3512 in
3513 Report.Report "UNFINISHED IF" region [] $
3514 Code.toSnippet source surroundings (Just region)
3516 D.reflow $
3517 "I was expecting to see an `else` branch after this:"
3519 D.stack
3520 [ D.reflow $
3521 "I know what to do when the condition is `True`, but not when it is `False`."
3522 , D.fillSep
3523 ["Add","an",D.cyan "else","branch","to","handle","that","scenario!"]
3529-- RECORD
3532toRecordReport :: Code.Source -> Context -> Record -> Row -> Col -> Report.Report
3533toRecordReport source context record startRow startCol =
3534 case record of
3535 RecordOpen row col ->
3536 case Code.whatIsNext source row col of
3537 Code.Keyword keyword ->
3538 let
3539 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3540 region = toKeywordRegion row col keyword
3541 in
3542 Report.Report "RESERVED WORD" region [] $
3543 Code.toSnippet source surroundings (Just region)
3545 D.reflow $
3546 "I just started parsing a record, but I got stuck on this field name:"
3548 D.reflow $
3549 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
3550 \ that is a reserved word. Try using a different name!"
3553 _ ->
3554 let
3555 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3556 region = toRegion row col
3557 in
3558 Report.Report "UNFINISHED RECORD" region [] $
3559 Code.toSnippet source surroundings (Just region)
3561 D.reflow $
3562 "I just started parsing a record, but I got stuck here:"
3564 D.fillSep
3565 ["Records","look","like",D.dullyellow "{ x = 3, y = 4 },"
3566 ,"so","I","was","expecting","to","see","a","field","name","next."
3570 RecordEnd row col ->
3571 let
3572 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3573 region = toRegion row col
3574 in
3575 Report.Report "UNFINISHED RECORD" region [] $
3576 Code.toSnippet source surroundings (Just region)
3578 D.reflow $
3579 "I am partway through parsing a record, but I got stuck here:"
3581 D.stack
3582 [ D.fillSep
3583 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
3584 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
3586 , D.toSimpleNote $
3587 "When I get stuck like this, it usually means that there is a missing parenthesis\
3588 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
3592 RecordField row col ->
3593 case Code.whatIsNext source row col of
3594 Code.Keyword keyword ->
3595 let
3596 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3597 region = toKeywordRegion row col keyword
3598 in
3599 Report.Report "RESERVED WORD" region [] $
3600 Code.toSnippet source surroundings (Just region)
3602 D.reflow $
3603 "I am partway through parsing a record, but I got stuck on this field name:"
3605 D.reflow $
3606 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
3607 \ that is a reserved word. Try using a different name!"
3610 _ ->
3611 let
3612 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3613 region = toRegion row col
3614 in
3615 Report.Report "UNFINISHED RECORD" region [] $
3616 Code.toSnippet source surroundings (Just region)
3618 D.reflow $
3619 "I am partway through parsing a record, but I got stuck after that last comma:"
3621 addNoteForRecordError $
3622 D.reflow $
3623 "Trailing commas are not allowed in records, so I was expecting to see another\
3624 \ record field defined next. If you are done defining the record, the fix may\
3625 \ be to delete that last comma?"
3628 RecordEquals row col ->
3629 let
3630 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3631 region = toRegion row col
3632 in
3633 Report.Report "UNFINISHED RECORD" region [] $
3634 Code.toSnippet source surroundings (Just region)
3636 D.reflow $
3637 "I am partway through parsing a record, but I got stuck here:"
3639 addNoteForRecordError $
3640 D.fillSep $
3641 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
3642 ,"an","equals","sign","next.","So","try","putting","an",D.green "=","sign","here?"
3646 RecordExpr expr row col ->
3647 toExprReport source (InNode NRecord startRow startCol context) expr row col
3649 RecordSpace space row col ->
3650 toSpaceReport source space row col
3652 RecordIndentOpen row col ->
3653 let
3654 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3655 region = toRegion row col
3656 in
3657 Report.Report "UNFINISHED RECORD" region [] $
3658 Code.toSnippet source surroundings (Just region)
3660 D.reflow $
3661 "I just saw the opening curly brace of a record, but then I got stuck here:"
3663 addNoteForRecordIndentError $
3664 D.fillSep $
3665 ["I","am","expecting","a","record","like",D.dullyellow "{ x = 3, y = 4 }","here."
3666 ,"Try","defining","some","fields","of","your","own?"
3670 RecordIndentEnd row col ->
3671 let
3672 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3673 region = toRegion row col
3674 in
3675 Report.Report "UNFINISHED RECORD" region [] $
3676 Code.toSnippet source surroundings (Just region)
3678 D.reflow $
3679 "I was expecting to see a closing curly brace next:"
3681 addNoteForRecordIndentError $
3682 D.fillSep $
3683 ["Try","putting","an",D.green "}","and","see","if","that","helps?"
3687 RecordIndentField row col ->
3688 let
3689 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3690 region = toRegion row col
3691 in
3692 Report.Report "UNFINISHED RECORD" region [] $
3693 Code.toSnippet source surroundings (Just region)
3695 D.reflow $
3696 "I am partway through parsing a record, but I got stuck after that last comma:"
3698 addNoteForRecordError $
3699 D.reflow $
3700 "Trailing commas are not allowed in records, so the fix may be to\
3701 \ delete that last comma? Or maybe you were in the middle of defining\
3702 \ an additional field?"
3705 RecordIndentEquals row col ->
3706 let
3707 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3708 region = toRegion row col
3709 in
3710 Report.Report "UNFINISHED RECORD" region [] $
3711 Code.toSnippet source surroundings (Just region)
3713 D.reflow $
3714 "I am partway through parsing a record. I just saw a record\
3715 \ field, so I was expecting to see an equals sign next:"
3717 addNoteForRecordIndentError $
3718 D.fillSep $
3719 ["Try","putting","an",D.green "=","followed","by","an","expression?"
3723 RecordIndentExpr row col ->
3724 let
3725 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3726 region = toRegion row col
3727 in
3728 Report.Report "UNFINISHED RECORD" region [] $
3729 Code.toSnippet source surroundings (Just region)
3731 D.reflow $
3732 "I am partway through parsing a record, and I was expecting to run into an expression next:"
3734 addNoteForRecordIndentError $
3735 D.fillSep $
3736 ["Try","putting","something","like"
3737 ,D.dullyellow "42","or",D.dullyellow"\"hello\"","for","now?"
3742addNoteForRecordError :: D.Doc -> D.Doc
3743addNoteForRecordError normalRecommendation =
3744 D.stack $
3745 normalRecommendation
3747 [ D.toSimpleNote
3748 "If you are trying to define a record across multiple lines, I recommend using this format:"
3749 , D.indent 4 $ D.vcat $
3750 [ "{ name = \"Alice\""
3751 , ", age = 42"
3752 , ", height = 1.75"
3753 , "}"
3755 , D.reflow $
3756 "Notice that each line starts with some indentation. Usually two or four spaces. I\
3757 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
3758 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3762addNoteForRecordIndentError :: D.Doc -> D.Doc
3763addNoteForRecordIndentError normalRecommendation =
3764 D.stack $
3765 normalRecommendation
3767 [ D.toSimpleNote
3768 "I may be confused by indentation. For example, if you are trying to define\
3769 \ a record across multiple lines, I recommend using this format:"
3770 , D.indent 4 $ D.vcat $
3771 [ "{ name = \"Alice\""
3772 , ", age = 42"
3773 , ", height = 1.75"
3774 , "}"
3776 , D.reflow $
3777 "Notice that each line starts with some indentation. Usually two or four spaces. I\
3778 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
3779 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3784-- TUPLE
3787toTupleReport :: Code.Source -> Context -> Tuple -> Row -> Col -> Report.Report
3788toTupleReport source context tuple startRow startCol =
3789 case tuple of
3790 TupleExpr expr row col ->
3791 toExprReport source (InNode NParens startRow startCol context) expr row col
3793 TupleSpace space row col ->
3794 toSpaceReport source space row col
3796 TupleEnd 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 PARENTHESES" region [] $
3802 Code.toSnippet source surroundings (Just region)
3804 D.reflow $
3805 "I was expecting to see a closing parentheses next, but I got stuck here:"
3807 D.stack
3808 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
3809 , D.toSimpleNote $
3810 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
3811 \ unexpectedly. So there may be some earlier syntax trouble (like extra parenthesis\
3812 \ or missing brackets) that is confusing me."
3816 TupleOperatorClose row col ->
3817 let
3818 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3819 region = toRegion row col
3820 in
3821 Report.Report "UNFINISHED OPERATOR FUNCTION" region [] $
3822 Code.toSnippet source surroundings (Just region)
3824 D.reflow "I was expecting a closing parenthesis here:"
3826 D.stack
3827 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
3828 , D.toSimpleNote $
3829 "I think I am parsing an operator function right now, so I am expecting to see\
3830 \ something like (+) or (&&) where an operator is surrounded by parentheses with\
3831 \ no extra spaces."
3835 TupleOperatorReserved operator row col ->
3836 let
3837 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3838 region = toRegion row col
3839 in
3840 Report.Report "UNEXPECTED SYMBOL" region [] $
3841 Code.toSnippet source surroundings (Just region)
3843 D.reflow $
3844 "I ran into an unexpected symbol here:"
3846 D.fillSep $
3847 case operator of
3848 BadDot -> ["Maybe","you","wanted","a","record","accessor","like",D.dullyellow ".x","or",D.dullyellow ".name","instead?"]
3849 BadPipe -> ["Try",D.dullyellow "(||)","instead?","To","turn","boolean","OR","into","a","function?"]
3850 BadArrow -> ["Maybe","you","wanted",D.dullyellow "(>)","or",D.dullyellow "(>=)","instead?"]
3851 BadEquals -> ["Try",D.dullyellow "(==)","instead?","To","make","a","function","that","checks","equality?"]
3852 BadHasType -> ["Try",D.dullyellow "(::)","instead?","To","add","values","to","the","front","of","lists?"]
3855 TupleIndentExpr1 row col ->
3856 let
3857 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3858 region = toRegion row col
3859 in
3860 Report.Report "UNFINISHED PARENTHESES" region [] $
3861 Code.toSnippet source surroundings (Just region)
3863 D.reflow $
3864 "I just saw an open parenthesis, so I was expecting to see an expression next."
3866 D.stack
3867 [ D.fillSep $
3868 ["Something","like",D.dullyellow "(4 + 5)","or"
3869 ,D.dullyellow "(String.reverse \"desserts\")" <> "."
3870 ,"Anything","where","you","are","putting","parentheses","around","normal","expressions."
3872 , D.toSimpleNote $
3873 "I can get confused by indentation in cases like this, so\
3874 \ maybe you have an expression but it is not indented enough?"
3878 TupleIndentExprN row col ->
3879 let
3880 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3881 region = toRegion row col
3882 in
3883 Report.Report "UNFINISHED TUPLE" region [] $
3884 Code.toSnippet source surroundings (Just region)
3886 D.reflow $
3887 "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."
3889 D.stack
3890 [ D.fillSep $
3891 ["A","tuple","looks","like",D.dullyellow "(3,4)","or"
3892 ,D.dullyellow "(\"Tom\",42)" <> ","
3893 ,"so","I","think","there","is","an","expression","missing","here?"
3895 , D.toSimpleNote $
3896 "I can get confused by indentation in cases like this, so\
3897 \ maybe you have an expression but it is not indented enough?"
3901 TupleIndentEnd row col ->
3902 let
3903 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3904 region = toRegion row col
3905 in
3906 Report.Report "UNFINISHED PARENTHESES" region [] $
3907 Code.toSnippet source surroundings (Just region)
3909 D.reflow $
3910 "I was expecting to see a closing parenthesis next:"
3912 D.stack
3913 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
3914 , D.toSimpleNote $
3915 "I can get confused by indentation in cases like this, so\
3916 \ maybe you have a closing parenthesis but it is not indented enough?"
3921toListReport :: Code.Source -> Context -> List -> Row -> Col -> Report.Report
3922toListReport source context list startRow startCol =
3923 case list of
3924 ListSpace space row col ->
3925 toSpaceReport source space row col
3927 ListOpen row col ->
3928 let
3929 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3930 region = toRegion row col
3931 in
3932 Report.Report "UNFINISHED LIST" region [] $
3933 Code.toSnippet source surroundings (Just region)
3935 D.reflow $
3936 "I am partway through parsing a list, but I got stuck here:"
3938 D.stack
3939 [ D.fillSep
3940 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
3941 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
3943 , D.toSimpleNote $
3944 "When I get stuck like this, it usually means that there is a missing parenthesis\
3945 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
3949 ListExpr expr row col ->
3950 case expr of
3951 Start r c ->
3952 let
3953 surroundings = A.Region (A.Position startRow startCol) (A.Position r c)
3954 region = toRegion r c
3955 in
3956 Report.Report "UNFINISHED LIST" region [] $
3957 Code.toSnippet source surroundings (Just region)
3959 D.reflow $
3960 "I was expecting to see another list entry after that last comma:"
3962 D.stack
3963 [ D.reflow $
3964 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
3965 , D.toSimpleNote
3966 "I recommend using the following format for lists that span multiple lines:"
3967 , D.indent 4 $ D.vcat $
3968 [ "[ \"Alice\""
3969 , ", \"Bob\""
3970 , ", \"Chuck\""
3971 , "]"
3973 , D.reflow $
3974 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
3975 \ This style can be jarring for people coming from C-like syntax, but folks generally\
3976 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
3980 _ ->
3981 toExprReport source (InNode NList startRow startCol context) expr row col
3983 ListEnd row col ->
3984 let
3985 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
3986 region = toRegion row col
3987 in
3988 Report.Report "UNFINISHED LIST" region [] $
3989 Code.toSnippet source surroundings (Just region)
3991 D.reflow $
3992 "I am partway through parsing a list, but I got stuck here:"
3994 D.stack
3995 [ D.fillSep
3996 ["I","was","expecting","to","see","a","closing","square","bracket","before","this,"
3997 ,"so","try","adding","a",D.dullyellow "]","and","see","if","that","helps?"
3999 , D.toSimpleNote $
4000 "When I get stuck like this, it usually means that there is a missing parenthesis\
4001 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
4005 ListIndentOpen row col ->
4006 let
4007 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4008 region = toRegion row col
4009 in
4010 Report.Report "UNFINISHED LIST" region [] $
4011 Code.toSnippet source surroundings (Just region)
4013 D.reflow $
4014 "I cannot find the end of this list:"
4016 D.stack
4017 [ D.fillSep $
4018 ["You","could","change","it","to","something","like"
4019 ,D.dullyellow "[3,4,5]"
4020 ,"or","even","just"
4021 ,D.dullyellow "[]" <> "."
4022 ,"Anything","where","there","is","an","open","and","close","square","brace,"
4023 ,"and","where","the","elements","of","the","list","are","separated","by","commas."
4025 , D.toSimpleNote
4026 "I may be confused by indentation. For example, if you are trying to define\
4027 \ a list across multiple lines, I recommend using this format:"
4028 , D.indent 4 $ D.vcat $
4029 [ "[ \"Alice\""
4030 , ", \"Bob\""
4031 , ", \"Chuck\""
4032 , "]"
4034 , D.reflow $
4035 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
4036 \ This style can be jarring for people coming from C-like syntax, but folks generally\
4037 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
4041 ListIndentEnd row col ->
4042 let
4043 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4044 region = toRegion row col
4045 in
4046 Report.Report "UNFINISHED LIST" region [] $
4047 Code.toSnippet source surroundings (Just region)
4049 D.reflow $
4050 "I cannot find the end of this list:"
4052 D.stack
4053 [ D.fillSep $
4054 ["You","can","just","add","a","closing",D.dullyellow "]"
4055 ,"right","here,","and","I","will","be","all","set!"
4057 , D.toSimpleNote
4058 "I may be confused by indentation. For example, if you are trying to define\
4059 \ a list across multiple lines, I recommend using this format:"
4060 , D.indent 4 $ D.vcat $
4061 [ "[ \"Alice\""
4062 , ", \"Bob\""
4063 , ", \"Chuck\""
4064 , "]"
4066 , D.reflow $
4067 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
4068 \ This style can be jarring for people coming from C-like syntax, but folks generally\
4069 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
4073 ListIndentExpr row col ->
4074 let
4075 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4076 region = toRegion row col
4077 in
4078 Report.Report "UNFINISHED LIST" region [] $
4079 Code.toSnippet source surroundings (Just region)
4081 D.reflow $
4082 "I was expecting to see another list entry after this comma:"
4084 D.stack
4085 [ D.reflow $
4086 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
4087 , D.toSimpleNote
4088 "I recommend using the following format for lists that span multiple lines:"
4089 , D.indent 4 $ D.vcat $
4090 [ "[ \"Alice\""
4091 , ", \"Bob\""
4092 , ", \"Chuck\""
4093 , "]"
4095 , D.reflow $
4096 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
4097 \ This style can be jarring for people coming from C-like syntax, but folks generally\
4098 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
4103toFuncReport :: Code.Source -> Context -> Func -> Row -> Col -> Report.Report
4104toFuncReport source context func startRow startCol =
4105 case func of
4106 FuncSpace space row col ->
4107 toSpaceReport source space row col
4109 FuncArg pattern row col ->
4110 toPatternReport source PArg pattern row col
4112 FuncBody expr row col ->
4113 toExprReport source (InNode NFunc startRow startCol context) expr row col
4115 FuncArrow row col ->
4116 case Code.whatIsNext source row col of
4117 Code.Keyword keyword ->
4118 let
4119 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4120 region = toKeywordRegion row col keyword
4121 in
4122 Report.Report "RESERVED WORD" region [] $
4123 Code.toSnippet source surroundings (Just region)
4125 D.reflow $
4126 "I was parsing an anonymous function, but I got stuck here:"
4128 D.reflow $
4129 "It looks like you are trying to use `" ++ keyword ++ "` as an argument, but\
4130 \ it is a reserved word in this language. Try using a different argument name!"
4133 _ ->
4134 let
4135 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4136 region = toRegion row col
4137 in
4138 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
4139 Code.toSnippet source surroundings (Just region)
4141 D.reflow $
4142 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
4144 D.fillSep $
4145 ["The","syntax","for","anonymous","functions","is"
4146 ,D.dullyellow "(\\x -> x + 1)"
4147 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
4151 FuncIndentArg row col ->
4152 let
4153 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4154 region = toRegion row col
4155 in
4156 Report.Report "MISSING ARGUMENT" region [] $
4157 Code.toSnippet source surroundings (Just region)
4159 D.reflow $
4160 "I just saw the beginning of an anonymous function, so I was expecting to see an argument next:"
4162 D.stack
4163 [ D.fillSep
4164 ["Something","like",D.dullyellow"x","or",D.dullyellow "name" <> "."
4165 ,"Anything","that","starts","with","a","lower","case","letter!"
4167 , D.toSimpleNote $
4168 "The syntax for anonymous functions is (\\x -> x + 1) where the backslash\
4169 \ is meant to look a bit like a lambda if you squint. This visual pun seemed\
4170 \ like a better idea at the time!"
4174 FuncIndentArrow row col ->
4175 let
4176 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4177 region = toRegion row col
4178 in
4179 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
4180 Code.toSnippet source surroundings (Just region)
4182 D.reflow $
4183 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
4185 D.stack
4186 [ D.fillSep $
4187 ["The","syntax","for","anonymous","functions","is"
4188 ,D.dullyellow "(\\x -> x + 1)"
4189 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
4191 , D.toSimpleNote $
4192 "It is possible that I am confused about indetation! I generally recommend\
4193 \ switching to named functions if the definition cannot fit inline nicely, so\
4194 \ either (1) try to fit the whole anonymous function on one line or (2) break\
4195 \ the whole thing out into a named function. Things tend to be clearer that way!"
4199 FuncIndentBody row col ->
4200 let
4201 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4202 region = toRegion row col
4203 in
4204 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
4205 Code.toSnippet source surroundings (Just region)
4207 D.reflow $
4208 "I was expecting to see the body of your anonymous function next:"
4210 D.stack
4211 [ D.fillSep $
4212 ["The","syntax","for","anonymous","functions","is"
4213 ,D.dullyellow "(\\x -> x + 1)"
4214 ,"so","I","am","missing","all","the","stuff","after","the","arrow!"
4216 , D.toSimpleNote $
4217 "It is possible that I am confused about indetation! I generally recommend\
4218 \ switching to named functions if the definition cannot fit inline nicely, so\
4219 \ either (1) try to fit the whole anonymous function on one line or (2) break\
4220 \ the whole thing out into a named function. Things tend to be clearer that way!"
4226-- PATTERN
4229data PContext
4230 = PCase
4231 | PArg
4232 | PLet
4235toPatternReport :: Code.Source -> PContext -> Pattern -> Row -> Col -> Report.Report
4236toPatternReport source context pattern startRow startCol =
4237 case pattern of
4238 PRecord record row col ->
4239 toPRecordReport source record row col
4241 PTuple tuple row col ->
4242 toPTupleReport source context tuple row col
4244 PList list row col ->
4245 toPListReport source context list row col
4247 PStart row col ->
4248 case Code.whatIsNext source row col of
4249 Code.Keyword keyword ->
4250 let
4251 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4252 region = toKeywordRegion row col keyword
4253 inThisThing =
4254 case context of
4255 PArg -> "as an argument"
4256 PCase -> "in this pattern"
4257 PLet -> "in this pattern"
4258 in
4259 Report.Report "RESERVED WORD" region [] $
4260 Code.toSnippet source surroundings (Just region)
4262 D.reflow $
4263 "It looks like you are trying to use `" ++ keyword ++ "` " ++ inThisThing ++ ":"
4265 D.reflow $
4266 "This is a reserved word! Try using some other name?"
4269 Code.Operator "-" ->
4270 let
4271 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4272 region = toRegion row col
4273 in
4274 Report.Report "UNEXPECTED SYMBOL" region [] $
4275 Code.toSnippet source surroundings (Just region)
4277 D.reflow $
4278 "I ran into a minus sign unexpectedly in this pattern:"
4280 D.reflow $
4281 "It is not possible to pattern match on negative numbers at this\
4282 \ time. Try using an `if` expression for that sort of thing for now."
4285 _ ->
4286 let
4287 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4288 region = toRegion row col
4289 in
4290 Report.Report "PROBLEM IN PATTERN" region [] $
4291 Code.toSnippet source surroundings (Just region)
4293 D.reflow $
4294 "I wanted to parse a pattern next, but I got stuck here:"
4296 D.fillSep $
4297 ["I","am","not","sure","why","I","am","getting","stuck","exactly."
4298 ,"I","just","know","that","I","want","a","pattern","next."
4299 ,"Something","as","simple","as"
4300 ,D.dullyellow "maybeHeight","or",D.dullyellow "result"
4301 ,"would","work!"
4305 PChar char row col ->
4306 toCharReport source char row col
4308 PString string row col ->
4309 toStringReport source string row col
4311 PNumber number row col ->
4312 toNumberReport source number row col
4314 PFloat width row col ->
4315 let
4316 region = toWiderRegion row col width
4317 in
4318 Report.Report "UNEXPECTED PATTERN" region [] $
4319 Code.toSnippet source region Nothing
4321 D.reflow $
4322 "I cannot pattern match with floating point numbers:"
4324 D.fillSep $
4325 ["Equality","on","floats","can","be","unreliable,","so","you","usually","want"
4326 ,"to","check","that","they","are","nearby","with","some","sort","of"
4327 ,D.dullyellow "(abs (actual - expected) < 0.001)","check."
4331 PAlias row col ->
4332 let
4333 region = toRegion row col
4334 in
4335 Report.Report "UNFINISHED PATTERN" region [] $
4336 Code.toSnippet source region Nothing $
4338 D.reflow $
4339 "I was expecting to see a variable name after the `as` keyword:"
4341 D.stack
4342 [ D.fillSep $
4343 ["The","`as`","keyword","lets","you","write","patterns","like"
4344 ,"((" <> D.dullyellow "x" <> "," <> D.dullyellow "y" <> ") " <> D.cyan "as" <> D.dullyellow " point" <> ")"
4345 ,"so","you","can","refer","to","individual","parts","of","the","tuple","with"
4346 ,D.dullyellow "x","and",D.dullyellow "y","or","you","refer","to","the","whole"
4347 ,"thing","with",D.dullyellow "point."
4349 , D.reflow $
4350 "So I was expecting to see a variable name after the `as` keyword here. Sometimes\
4351 \ people just want to use `as` as a variable name though. Try using a different name\
4352 \ in that case!"
4356 PWildcardNotVar name width row col ->
4357 let
4358 region = toWiderRegion row col (fromIntegral width)
4359 examples =
4360 case dropWhile (=='_') (Name.toChars name) of
4361 [] -> [D.dullyellow "x","or",D.dullyellow "age"]
4362 c:cs -> [D.dullyellow (D.fromChars (Char.toLower c : cs))]
4363 in
4364 Report.Report "UNEXPECTED NAME" region [] $
4365 Code.toSnippet source region Nothing $
4367 D.reflow $
4368 "Variable names cannot start with underscores like this:"
4370 D.fillSep $
4371 ["You","can","either","have","an","underscore","like",D.dullyellow "_","to"
4372 ,"ignore","the","value,","or","you","can","have","a","name","like"
4373 ] ++ examples ++ ["to","use","the","matched","value." ]
4376 PSpace space row col ->
4377 toSpaceReport source space row col
4379 PIndentStart row col ->
4380 let
4381 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4382 region = toRegion row col
4383 in
4384 Report.Report "UNFINISHED PATTERN" region [] $
4385 Code.toSnippet source surroundings (Just region)
4387 D.reflow $
4388 "I wanted to parse a pattern next, but I got stuck here:"
4390 D.stack
4391 [ D.fillSep $
4392 ["I","am","not","sure","why","I","am","getting","stuck","exactly."
4393 ,"I","just","know","that","I","want","a","pattern","next."
4394 ,"Something","as","simple","as"
4395 ,D.dullyellow "maybeHeight","or",D.dullyellow "result"
4396 ,"would","work!"
4398 , D.toSimpleNote $
4399 "I can get confused by indentation. If you think there is a pattern next, maybe\
4400 \ it needs to be indented a bit more?"
4404 PIndentAlias row col ->
4405 let
4406 region = toRegion row col
4407 in
4408 Report.Report "UNFINISHED PATTERN" region [] $
4409 Code.toSnippet source region Nothing $
4411 D.reflow $
4412 "I was expecting to see a variable name after the `as` keyword:"
4414 D.stack
4415 [ D.fillSep $
4416 ["The","`as`","keyword","lets","you","write","patterns","like"
4417 ,"((" <> D.dullyellow "x" <> "," <> D.dullyellow "y" <> ") " <> D.cyan "as" <> D.dullyellow " point" <> ")"
4418 ,"so","you","can","refer","to","individual","parts","of","the","tuple","with"
4419 ,D.dullyellow "x","and",D.dullyellow "y","or","you","refer","to","the","whole"
4420 ,"thing","with",D.dullyellow "point."
4422 , D.reflow $
4423 "So I was expecting to see a variable name after the `as` keyword here. Sometimes\
4424 \ people just want to use `as` as a variable name though. Try using a different name\
4425 \ in that case!"
4430toPRecordReport :: Code.Source -> PRecord -> Row -> Col -> Report.Report
4431toPRecordReport source record startRow startCol =
4432 case record of
4433 PRecordOpen row col ->
4434 toUnfinishRecordPatternReport source row col startRow startCol $
4435 D.reflow "I was expecting to see a field name next."
4437 PRecordEnd row col ->
4438 toUnfinishRecordPatternReport source row col startRow startCol $
4439 D.fillSep
4440 ["I","was","expecting","to","see","a","closing","curly","brace","next."
4441 ,"Try","adding","a",D.dullyellow "}","here?"
4444 PRecordField row col ->
4445 case Code.whatIsNext source row col of
4446 Code.Keyword keyword ->
4447 let
4448 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4449 region = toKeywordRegion row col keyword
4450 in
4451 Report.Report "RESERVED WORD" region [] $
4452 Code.toSnippet source surroundings (Just region)
4454 D.reflow $
4455 "I was not expecting to see `" ++ keyword ++ "` as a record field name:"
4457 D.reflow $
4458 "This is a reserved word, not available for variable names. Try another name!"
4461 _ ->
4462 toUnfinishRecordPatternReport source row col startRow startCol $
4463 D.reflow "I was expecting to see a field name next."
4465 PRecordSpace space row col ->
4466 toSpaceReport source space row col
4468 PRecordIndentOpen row col ->
4469 toUnfinishRecordPatternReport source row col startRow startCol $
4470 D.reflow "I was expecting to see a field name next."
4472 PRecordIndentEnd row col ->
4473 toUnfinishRecordPatternReport source row col startRow startCol $
4474 D.fillSep
4475 ["I","was","expecting","to","see","a","closing","curly","brace","next."
4476 ,"Try","adding","a",D.dullyellow "}","here?"
4479 PRecordIndentField row col ->
4480 toUnfinishRecordPatternReport source row col startRow startCol $
4481 D.reflow "I was expecting to see a field name next."
4484toUnfinishRecordPatternReport :: Code.Source -> Row -> Col -> Row -> Col -> D.Doc -> Report.Report
4485toUnfinishRecordPatternReport source row col startRow startCol message =
4486 let
4487 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4488 region = toRegion row col
4489 in
4490 Report.Report "UNFINISHED RECORD PATTERN" region [] $
4491 Code.toSnippet source surroundings (Just region)
4493 D.reflow $
4494 "I was partway through parsing a record pattern, but I got stuck here:"
4496 D.stack
4497 [ message
4498 , D.toFancyHint $
4499 ["A","record","pattern","looks","like",D.dullyellow "{x,y}","or",D.dullyellow "{name,age}"
4500 ,"where","you","list","the","field","names","you","want","to","access."
4507toPTupleReport :: Code.Source -> PContext -> PTuple -> Row -> Col -> Report.Report
4508toPTupleReport source context tuple startRow startCol =
4509 case tuple of
4510 PTupleOpen row col ->
4511 case Code.whatIsNext source row col of
4512 Code.Keyword keyword ->
4513 let
4514 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4515 region = toKeywordRegion row col keyword
4516 in
4517 Report.Report "RESERVED WORD" region [] $
4518 Code.toSnippet source surroundings (Just region)
4520 D.reflow $
4521 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name:"
4523 D.reflow $
4524 "This is a reserved word! Try using some other name?"
4527 _ ->
4528 let
4529 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4530 region = toRegion row col
4531 in
4532 Report.Report "UNFINISHED PARENTHESES" region [] $
4533 Code.toSnippet source surroundings (Just region)
4535 D.reflow $
4536 "I just saw an open parenthesis, but I got stuck here:"
4538 D.fillSep
4539 ["I","was","expecting","so","see","a","pattern","next."
4540 ,"Maybe","it","will","end","up","being","something"
4541 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "?"
4545 PTupleEnd row col ->
4546 case Code.whatIsNext source row col of
4547 Code.Keyword keyword ->
4548 let
4549 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4550 region = toKeywordRegion row col keyword
4551 in
4552 Report.Report "RESERVED WORD" region [] $
4553 Code.toSnippet source surroundings (Just region) $
4555 D.reflow $
4556 "I ran into a reserved word in this pattern:"
4558 D.reflow $
4559 "The `" ++ keyword ++ "` keyword is reserved. Try using a different name instead!"
4562 Code.Operator op ->
4563 let
4564 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4565 region = toKeywordRegion row col op
4566 in
4567 Report.Report "UNEXPECTED SYMBOL" region [] $
4568 Code.toSnippet source surroundings (Just region) $
4570 D.reflow $
4571 "I ran into the " ++ op ++ " symbol unexpectedly in this pattern:"
4573 D.reflow $
4574 "Only the :: symbol that works in patterns. It is useful if you\
4575 \ are pattern matching on lists, trying to get the first element\
4576 \ off the front. Did you want that instead?"
4579 Code.Close term bracket ->
4580 let
4581 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4582 region = toRegion row col
4583 in
4584 Report.Report ("STRAY " ++ map Char.toUpper term) region [] $
4585 Code.toSnippet source surroundings (Just region) $
4587 D.reflow $
4588 "I ran into a an unexpected " ++ term ++ " in this pattern:"
4590 D.reflow $
4591 "This " ++ bracket : " does not match up with an earlier open " ++ term ++ ". Try deleting it?"
4594 _ ->
4595 let
4596 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4597 region = toRegion row col
4598 in
4599 Report.Report "UNFINISHED PARENTHESES" region [] $
4600 Code.toSnippet source surroundings (Just region) $
4602 D.reflow $
4603 "I was partway through parsing a pattern, but I got stuck here:"
4605 D.fillSep
4606 ["I","was","expecting","a","closing","parenthesis","next,","so"
4607 ,"try","adding","a",D.dullyellow ")","to","see","if","that","helps?"
4611 PTupleExpr pattern row col ->
4612 toPatternReport source context pattern row col
4614 PTupleSpace space row col ->
4615 toSpaceReport source space row col
4617 PTupleIndentEnd row col ->
4618 let
4619 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4620 region = toRegion row col
4621 in
4622 Report.Report "UNFINISHED PARENTHESES" region [] $
4623 Code.toSnippet source surroundings (Just region) $
4625 D.reflow $
4626 "I was expecting a closing parenthesis next:"
4628 D.stack
4629 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
4630 , D.toSimpleNote $
4631 "I can get confused by indentation in cases like this, so\
4632 \ maybe you have a closing parenthesis but it is not indented enough?"
4636 PTupleIndentExpr1 row col ->
4637 let
4638 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4639 region = toRegion row col
4640 in
4641 Report.Report "UNFINISHED PARENTHESES" region [] $
4642 Code.toSnippet source surroundings (Just region) $
4644 D.reflow $
4645 "I just saw an open parenthesis, but then I got stuck here:"
4647 D.fillSep
4648 ["I","was","expecting","so","see","a","pattern","next."
4649 ,"Maybe","it","will","end","up","being","something"
4650 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "?"
4654 PTupleIndentExprN row col ->
4655 let
4656 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4657 region = toRegion row col
4658 in
4659 Report.Report "UNFINISHED TUPLE PATTERN" region [] $
4660 Code.toSnippet source surroundings (Just region) $
4662 D.reflow $
4663 "I am partway through parsing a tuple pattern, but I got stuck here:"
4665 D.stack
4666 [ D.fillSep
4667 ["I","was","expecting","so","see","a","pattern","next."
4668 ,"I","am","expecting","the","final","result","to","be","something"
4669 ,"like",D.dullyellow "(x,y)","or",D.dullyellow "(name, _)" <> "."
4671 , D.toSimpleNote $
4672 "I can get confused by indentation in cases like this, so the problem\
4673 \ may be that the next part is not indented enough?"
4678toPListReport :: Code.Source -> PContext -> PList -> Row -> Col -> Report.Report
4679toPListReport source context list startRow startCol =
4680 case list of
4681 PListOpen row col ->
4682 case Code.whatIsNext source row col of
4683 Code.Keyword keyword ->
4684 let
4685 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4686 region = toKeywordRegion row col keyword
4687 in
4688 Report.Report "RESERVED WORD" region [] $
4689 Code.toSnippet source surroundings (Just region)
4691 D.reflow $
4692 "It looks like you are trying to use `" ++ keyword ++ "` to name an element of a list:"
4694 D.reflow $
4695 "This is a reserved word though! Try using some other name?"
4698 _ ->
4699 let
4700 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4701 region = toRegion row col
4702 in
4703 Report.Report "UNFINISHED LIST PATTERN" region [] $
4704 Code.toSnippet source surroundings (Just region) $
4706 D.reflow $
4707 "I just saw an open square bracket, but then I got stuck here:"
4709 D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
4712 PListEnd row col ->
4713 let
4714 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4715 region = toRegion row col
4716 in
4717 Report.Report "UNFINISHED LIST PATTERN" region [] $
4718 Code.toSnippet source surroundings (Just region) $
4720 D.reflow $
4721 "I was expecting a closing square bracket to end this list pattern:"
4723 D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
4726 PListExpr pattern row col ->
4727 toPatternReport source context pattern row col
4729 PListSpace space row col ->
4730 toSpaceReport source space row col
4732 PListIndentOpen row col ->
4733 let
4734 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4735 region = toRegion row col
4736 in
4737 Report.Report "UNFINISHED LIST PATTERN" region [] $
4738 Code.toSnippet source surroundings (Just region) $
4740 D.reflow $
4741 "I just saw an open square bracket, but then I got stuck here:"
4743 D.stack
4744 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
4745 , D.toSimpleNote $
4746 "I can get confused by indentation in cases like this, so\
4747 \ maybe there is something next, but it is not indented enough?"
4751 PListIndentEnd row col ->
4752 let
4753 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4754 region = toRegion row col
4755 in
4756 Report.Report "UNFINISHED LIST PATTERN" region [] $
4757 Code.toSnippet source surroundings (Just region) $
4759 D.reflow $
4760 "I was expecting a closing square bracket to end this list pattern:"
4762 D.stack
4763 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
4764 , D.toSimpleNote $
4765 "I can get confused by indentation in cases like this, so\
4766 \ maybe you have a closing square bracket but it is not indented enough?"
4770 PListIndentExpr row col ->
4771 let
4772 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4773 region = toRegion row col
4774 in
4775 Report.Report "UNFINISHED LIST PATTERN" region [] $
4776 Code.toSnippet source surroundings (Just region) $
4778 D.reflow $
4779 "I am partway through parsing a list pattern, but I got stuck here:"
4781 D.stack
4782 [ D.reflow $
4783 "I was expecting to see another pattern next. Maybe a variable name."
4784 , D.toSimpleNote $
4785 "I can get confused by indentation in cases like this, so\
4786 \ maybe there is more to this pattern but it is not indented enough?"
4792-- TYPES
4795data TContext
4796 = TC_Annotation Name.Name
4797 | TC_CustomType
4798 | TC_TypeAlias
4799 | TC_Port
4802toTypeReport :: Code.Source -> TContext -> Type -> Row -> Col -> Report.Report
4803toTypeReport source context tipe startRow startCol =
4804 case tipe of
4805 TRecord record row col ->
4806 toTRecordReport source context record row col
4808 TTuple tuple row col ->
4809 toTTupleReport source context tuple row col
4811 TStart row col ->
4812 case Code.whatIsNext source row col of
4813 Code.Keyword keyword ->
4814 let
4815 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4816 region = toKeywordRegion row col keyword
4817 in
4818 Report.Report "RESERVED WORD" region [] $
4819 Code.toSnippet source surroundings (Just region)
4821 D.reflow $
4822 "I was expecting to see a type next, but I got stuck on this reserved word:"
4824 D.reflow $
4825 "It looks like you are trying to use `" ++ keyword ++ "` as a type variable, but \
4826 \ it is a reserved word. Try using a different name!"
4829 _ ->
4830 let
4831 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4832 region = toRegion row col
4834 thing =
4835 case context of
4836 TC_Annotation _ -> "type annotation"
4837 TC_CustomType -> "custom type"
4838 TC_TypeAlias -> "type alias"
4839 TC_Port -> "port"
4841 something =
4842 case context of
4843 TC_Annotation name -> "the `" ++ Name.toChars name ++ "` type annotation"
4844 TC_CustomType -> "a custom type"
4845 TC_TypeAlias -> "a type alias"
4846 TC_Port -> "a port"
4847 in
4848 Report.Report ("PROBLEM IN " ++ map Char.toUpper thing) region [] $
4849 Code.toSnippet source surroundings (Just region)
4851 D.reflow $
4852 "I was partway through parsing " ++ something ++ ", but I got stuck here:"
4854 D.fillSep $
4855 ["I","was","expecting","to","see","a","type","next."
4856 ,"Try","putting",D.dullyellow "Int","or",D.dullyellow "String","for","now?"
4860 TSpace space row col ->
4861 toSpaceReport source space row col
4863 TIndentStart row col ->
4864 let
4865 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4866 region = toRegion row col
4868 thing =
4869 case context of
4870 TC_Annotation _ -> "type annotation"
4871 TC_CustomType -> "custom type"
4872 TC_TypeAlias -> "type alias"
4873 TC_Port -> "port"
4874 in
4875 Report.Report ("UNFINISHED " ++ map Char.toUpper thing) region [] $
4876 Code.toSnippet source surroundings (Just region)
4878 D.reflow $
4879 "I was partway through parsing a " ++ thing ++ ", but I got stuck here:"
4881 D.stack
4882 [ D.fillSep $
4883 ["I","was","expecting","to","see","a","type","next."
4884 ,"Try","putting",D.dullyellow "Int","or",D.dullyellow "String","for","now?"
4886 , D.toSimpleNote $
4887 "I can get confused by indentation. If you think there is already a type\
4888 \ next, maybe it is not indented enough?"
4893toTRecordReport :: Code.Source -> TContext -> TRecord -> Row -> Col -> Report.Report
4894toTRecordReport source context record startRow startCol =
4895 case record of
4896 TRecordOpen row col ->
4897 case Code.whatIsNext source row col of
4898 Code.Keyword keyword ->
4899 let
4900 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4901 region = toKeywordRegion row col keyword
4902 in
4903 Report.Report "RESERVED WORD" region [] $
4904 Code.toSnippet source surroundings (Just region)
4906 D.reflow $
4907 "I just started parsing a record type, but I got stuck on this field name:"
4909 D.reflow $
4910 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
4911 \ that is a reserved word. Try using a different name!"
4914 _ ->
4915 let
4916 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4917 region = toRegion row col
4918 in
4919 Report.Report "UNFINISHED RECORD TYPE" region [] $
4920 Code.toSnippet source surroundings (Just region)
4922 D.reflow $
4923 "I just started parsing a record type, but I got stuck here:"
4925 D.fillSep
4926 ["Record","types","look","like",D.dullyellow "{ name : String, age : Int },"
4927 ,"so","I","was","expecting","to","see","a","field","name","next."
4931 TRecordEnd row col ->
4932 let
4933 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4934 region = toRegion row col
4935 in
4936 Report.Report "UNFINISHED RECORD TYPE" region [] $
4937 Code.toSnippet source surroundings (Just region)
4939 D.reflow $
4940 "I am partway through parsing a record type, but I got stuck here:"
4942 D.stack
4943 [ D.fillSep
4944 ["I","was","expecting","to","see","a","closing","curly","brace","before","this,"
4945 ,"so","try","adding","a",D.dullyellow "}","and","see","if","that","helps?"
4947 , D.toSimpleNote $
4948 "When I get stuck like this, it usually means that there is a missing parenthesis\
4949 \ or bracket somewhere earlier. It could also be a stray keyword or operator."
4953 TRecordField row col ->
4954 case Code.whatIsNext source row col of
4955 Code.Keyword keyword ->
4956 let
4957 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4958 region = toKeywordRegion row col keyword
4959 in
4960 Report.Report "RESERVED WORD" region [] $
4961 Code.toSnippet source surroundings (Just region)
4963 D.reflow $
4964 "I am partway through parsing a record type, but I got stuck on this field name:"
4966 D.reflow $
4967 "It looks like you are trying to use `" ++ keyword ++ "` as a field name, but \
4968 \ that is a reserved word. Try using a different name!"
4971 _ ->
4972 let
4973 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4974 region = toRegion row col
4975 in
4976 Report.Report "UNFINISHED RECORD TYPE" region [] $
4977 Code.toSnippet source surroundings (Just region)
4979 D.reflow $
4980 "I am partway through parsing a record type, but I got stuck after that last comma:"
4982 addNoteForRecordTypeError $
4983 D.reflow $
4984 "Trailing commas are not allowed in records, so I was expecting to see another\
4985 \ record field defined next. If you are done defining the record, the fix may\
4986 \ be to delete that last comma?"
4989 TRecordColon row col ->
4990 let
4991 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
4992 region = toRegion row col
4993 in
4994 Report.Report "UNFINISHED RECORD TYPE" region [] $
4995 Code.toSnippet source surroundings (Just region)
4997 D.reflow $
4998 "I am partway through parsing a record type, but I got stuck here:"
5000 addNoteForRecordTypeError $
5001 D.fillSep $
5002 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
5003 ,"a","colon","next.","So","try","putting","an",D.green ":","sign","here?"
5007 TRecordType tipe row col ->
5008 toTypeReport source context tipe row col
5010 TRecordSpace space row col ->
5011 toSpaceReport source space row col
5013 TRecordIndentOpen row col ->
5014 let
5015 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5016 region = toRegion row col
5017 in
5018 Report.Report "UNFINISHED RECORD TYPE" region [] $
5019 Code.toSnippet source surroundings (Just region)
5021 D.reflow $
5022 "I just saw the opening curly brace of a record type, but then I got stuck here:"
5024 addNoteForRecordTypeIndentError $
5025 D.fillSep $
5026 ["I","am","expecting","a","record","like",D.dullyellow "{ name : String, age : Int }","here."
5027 ,"Try","defining","some","fields","of","your","own?"
5031 TRecordIndentEnd row col ->
5032 let
5033 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5034 region = toRegion row col
5035 in
5036 Report.Report "UNFINISHED RECORD TYPE" region [] $
5037 Code.toSnippet source surroundings (Just region)
5039 D.reflow $
5040 "I was expecting to see a closing curly brace next:"
5042 addNoteForRecordTypeIndentError $
5043 D.fillSep $
5044 ["Try","putting","an",D.green "}","and","see","if","that","helps?"
5048 TRecordIndentField row col ->
5049 let
5050 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5051 region = toRegion row col
5052 in
5053 Report.Report "UNFINISHED RECORD TYPE" region [] $
5054 Code.toSnippet source surroundings (Just region)
5056 D.reflow $
5057 "I am partway through parsing a record type, but I got stuck after that last comma:"
5059 addNoteForRecordTypeIndentError $
5060 D.reflow $
5061 "Trailing commas are not allowed in record types, so the fix may be to\
5062 \ delete that last comma? Or maybe you were in the middle of defining\
5063 \ an additional field?"
5066 TRecordIndentColon row col ->
5067 let
5068 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5069 region = toRegion row col
5070 in
5071 Report.Report "UNFINISHED RECORD TYPE" region [] $
5072 Code.toSnippet source surroundings (Just region)
5074 D.reflow $
5075 "I am partway through parsing a record type. I just saw a record\
5076 \ field, so I was expecting to see a colon next:"
5078 addNoteForRecordTypeIndentError $
5079 D.fillSep $
5080 ["Try","putting","an",D.green ":","followed","by","a","type?"
5084 TRecordIndentType row col ->
5085 let
5086 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5087 region = toRegion row col
5088 in
5089 Report.Report "UNFINISHED RECORD TYPE" region [] $
5090 Code.toSnippet source surroundings (Just region)
5092 D.reflow $
5093 "I am partway through parsing a record type, and I was expecting to run into a type next:"
5095 addNoteForRecordTypeIndentError $
5096 D.fillSep $
5097 ["Try","putting","something","like"
5098 ,D.dullyellow "Int","or",D.dullyellow "String","for","now?"
5103addNoteForRecordTypeError :: D.Doc -> D.Doc
5104addNoteForRecordTypeError normalRecommendation =
5105 D.stack $
5106 normalRecommendation
5108 [ D.toSimpleNote
5109 "If you are trying to define a record type across multiple lines, I recommend using this format:"
5110 , D.indent 4 $ D.vcat $
5111 [ "{ name : String"
5112 , ", age : Int"
5113 , ", height : Float"
5114 , "}"
5116 , D.reflow $
5117 "Notice that each line starts with some indentation. Usually two or four spaces. I\
5118 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
5119 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
5123addNoteForRecordTypeIndentError :: D.Doc -> D.Doc
5124addNoteForRecordTypeIndentError normalRecommendation =
5125 D.stack $
5126 normalRecommendation
5128 [ D.toSimpleNote
5129 "I may be confused by indentation. For example, if you are trying to define\
5130 \ a record type across multiple lines, I recommend using this format:"
5131 , D.indent 4 $ D.vcat $
5132 [ "{ name : String"
5133 , ", age : Int"
5134 , ", height : Float"
5135 , "}"
5137 , D.reflow $
5138 "Notice that each line starts with some indentation. Usually two or four spaces. I\
5139 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
5140 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
5144toTTupleReport :: Code.Source -> TContext -> TTuple -> Row -> Col -> Report.Report
5145toTTupleReport source context tuple startRow startCol =
5146 case tuple of
5147 TTupleOpen row col ->
5148 case Code.whatIsNext source row col of
5149 Code.Keyword keyword ->
5150 let
5151 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5152 region = toKeywordRegion row col keyword
5153 in
5154 Report.Report "RESERVED WORD" region [] $
5155 Code.toSnippet source surroundings (Just region)
5157 D.reflow $
5158 "I ran into a reserved word unexpectedly:"
5160 D.reflow $
5161 "It looks like you are trying to use `" ++ keyword ++ "` as a variable name, but \
5162 \ it is a reserved word. Try using a different name!"
5165 _ ->
5166 let
5167 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5168 region = toRegion row col
5169 in
5170 Report.Report "UNFINISHED PARENTHESES" region [] $
5171 Code.toSnippet source surroundings (Just region)
5173 D.reflow $
5174 "I just saw an open parenthesis, so I was expecting to see a type next."
5176 D.fillSep $
5177 ["Something","like",D.dullyellow "(Maybe Int)","or"
5178 ,D.dullyellow "(List Person)" <> "."
5179 ,"Anything","where","you","are","putting","parentheses","around","normal","types."
5183 TTupleEnd row col ->
5184 let
5185 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5186 region = toRegion row col
5187 in
5188 Report.Report "UNFINISHED PARENTHESES" region [] $
5189 Code.toSnippet source surroundings (Just region)
5191 D.reflow $
5192 "I was expecting to see a closing parentheses next, but I got stuck here:"
5194 D.stack
5195 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
5196 , D.toSimpleNote $
5197 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
5198 \ unexpectedly. So there may be some earlier syntax trouble (like extra parenthesis\
5199 \ or missing brackets) that is confusing me."
5203 TTupleType tipe row col ->
5204 toTypeReport source context tipe row col
5206 TTupleSpace space row col ->
5207 toSpaceReport source space row col
5209 TTupleIndentType1 row col ->
5210 let
5211 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5212 region = toRegion row col
5213 in
5214 Report.Report "UNFINISHED PARENTHESES" region [] $
5215 Code.toSnippet source surroundings (Just region)
5217 D.reflow $
5218 "I just saw an open parenthesis, so I was expecting to see a type next."
5220 D.stack
5221 [ D.fillSep $
5222 ["Something","like",D.dullyellow "(Maybe Int)","or"
5223 ,D.dullyellow "(List Person)" <> "."
5224 ,"Anything","where","you","are","putting","parentheses","around","normal","types."
5226 , D.toSimpleNote $
5227 "I can get confused by indentation in cases like this, so\
5228 \ maybe you have a type but it is not indented enough?"
5232 TTupleIndentTypeN row col ->
5233 let
5234 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5235 region = toRegion row col
5236 in
5237 Report.Report "UNFINISHED TUPLE TYPE" region [] $
5238 Code.toSnippet source surroundings (Just region)
5240 D.reflow $
5241 "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."
5243 D.stack
5244 [ D.fillSep $
5245 ["A","tuple","type","looks","like",D.dullyellow "(Float,Float)","or"
5246 ,D.dullyellow "(String,Int)" <> ","
5247 ,"so","I","think","there","is","a","type","missing","here?"
5249 , D.toSimpleNote $
5250 "I can get confused by indentation in cases like this, so\
5251 \ maybe you have an expression but it is not indented enough?"
5255 TTupleIndentEnd row col ->
5256 let
5257 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
5258 region = toRegion row col
5259 in
5260 Report.Report "UNFINISHED PARENTHESES" region [] $
5261 Code.toSnippet source surroundings (Just region)
5263 D.reflow $
5264 "I was expecting to see a closing parenthesis next:"
5266 D.stack
5267 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
5268 , D.toSimpleNote $
5269 "I can get confused by indentation in cases like this, so\
5270 \ maybe you have a closing parenthesis but it is not indented enough?"