on 7b60982 help sign in
1574 lines 46 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 , Operator(..)
43 , toReport
44 )
45 where
48import Prelude hiding (Char, String)
49import qualified Data.Char as Char
50import qualified Data.Name as Name
51import Data.Word (Word16)
52--import Numeric (showHex)
54import qualified Elm.ModuleName as ModuleName
55import Parse.Primitives (Row, Col)
56--import qualified Parse.Primitives as P
57import qualified Reporting.Annotation as A
58--import qualified Reporting.Doc as D
59import qualified Reporting.Report as Report
60import qualified Reporting.Render.Code as Code
64-- ALL SYNTAX ERRORS
67data Error
68 = ModuleNameUnspecified ModuleName.Raw
69 | ModuleNameMismatch ModuleName.Raw (A.Located ModuleName.Raw)
70 | UnexpectedPort A.Region
71 | NoPorts A.Region
72 | ParseError Module
76-- MODULE
79data Module
80 = ModuleSpace Space Row Col
81 | ModuleEndOfFile Row Col
82 | Module Row Col
83 | ModuleName Row Col
84 | ModuleExposing Row Col
85 | ModuleExposingList Exposing Row Col
86 --
87 | ModulePortModule Row Col
88 | ModuleEffect Row Col
89 --
90 | ModuleIndentStart Row Col
91 | ModuleIndentName Row Col
92 | ModuleIndentExposing Row Col
93 | ModuleIndentExposingList Row Col
94 | ModuleIndentPortModule Row Col
95 --
96 | FreshLineModuleStart Row Col
97 | FreshLineAfterModuleLine Row Col
98 | FreshLineAfterDocComment Row Col
99 --
100 | ImportStart Row Col
101 | ImportName Row Col
102 | ImportAs Row Col
103 | ImportAlias Row Col
104 | ImportExposing Row Col
105 | ImportExposingList Exposing Row Col
106 | ImportEnd Row Col -- different based on col=1 or if greater
107 --
108 | ImportIndentName Row Col
109 | ImportIndentAs Row Col
110 | ImportIndentAlias Row Col
111 | ImportIndentExposing Row Col
112 | ImportIndentExposingList Row Col
113 --
114 | Infix Row Col
115 --
116 | Declarations Decl Row Col
119data Exposing
120 = ExposingSpace Space Row Col
121 | ExposingStart Row Col
122 | ExposingValue Row Col
123 | ExposingOperator Row Col
124 | ExposingOperatorReserved Operator Row Col
125 | ExposingOperatorRightParen Row Col
126 | ExposingEnd Row Col
127 --
128 | ExposingTypePrivacy Row Col
129 | ExposingTypePrivacyDots Row Col
130 | ExposingTypePrivacyEnd Row Col
131 --
132 | ExposingIndentEnd Row Col
133 | ExposingIndentValue Row Col
134 | ExposingIndentValueEnd Row Col
135 | ExposingIndentTypePrivacy Row Col
136 | ExposingIndentTypePrivacyDots Row Col
137 | ExposingIndentTypePrivacyEnd Row Col
141-- DECLARATIONS
144data Decl
145 = DeclStart Row Col
146 | DeclSpace Space Row Col
147 --
148 | Port Port Row Col
149 | DeclType DeclType Row Col
150 | DeclDef Name.Name DeclDef Row Col
151 --
152 | DeclFreshLineStart Row Col
153 | DeclFreshLineAfterDocComment Row Col
156data DeclDef
157 = DeclDefSpace Space Row Col
158 | DeclDefEquals Row Col
159 | DeclDefType Type Row Col
160 | DeclDefArg Pattern Row Col
161 | DeclDefBody Expr Row Col
162 | DeclDefNameRepeat Name.Name Row Col
163 | DeclDefNameMatch Name.Name Name.Name Row Col
164 --
165 | DeclDefIndentType Row Col
166 | DeclDefIndentEquals Row Col
167 | DeclDefIndentBody Row Col
168 --
169 | DeclDefFreshLineAfterType Row Col
172data Port
173 = PortSpace Space Row Col
174 | PortName Row Col
175 | PortColon Row Col
176 | PortType Type Row Col
177 | PortIndentName Row Col
178 | PortIndentColon Row Col
179 | PortIndentType Row Col
183-- TYPE DECLARATIONS
186data DeclType
187 = DT_Space Space Row Col
188 | DT_Name Row Col
189 | DT_Alias TypeAlias Row Col
190 | DT_Union CustomType Row Col
191 --
192 | DT_IndentName Row Col
195data TypeAlias
196 = AliasSpace Space Row Col
197 | AliasName Row Col
198 | AliasEquals Row Col
199 | AliasBody Type Row Col
200 --
201 | AliasIndentEquals Row Col
202 | AliasIndentBody Row Col
205data CustomType
206 = CT_Space Space Row Col
207 | CT_Name Row Col
208 | CT_Equals Row Col
209 | CT_Bar Row Col
210 | CT_Variant Row Col
211 | CT_VariantArg Type Row Col
212 --
213 | CT_IndentEquals Row Col
214 | CT_IndentBar Row Col
215 | CT_IndentAfterBar Row Col
216 | CT_IndentAfterEquals Row Col
220-- EXPRESSIONS
223data Expr
224 = Let Let Row Col
225 | Case Case Row Col
226 | If If Row Col
227 | List List Row Col
228 | Record Record Row Col
229 | Update Expr Row Col
230 | Tuple Tuple Row Col
231 | Func Func Row Col
232 --
233 | Dot Row Col
234 | Access Row Col
235 | OperatorRHS Row Col
236 | OperatorRight Row Col
237 | OperatorReserved Operator Row Col
238 --
239 | Start Row Col
240 | Char Char Row Col
241 | String String Row Col
242 | Number Number Row Col
243 | Space Space Row Col
244 | EndlessShader Row Col
245 | ShaderProblem [Char.Char] Row Col
246 | IndentOperatorRight Row Col
247 | IndentMoreExpr Row Col
250data Record
251 = RecordOpen Row Col
252 | RecordEnd Row Col
253 | RecordField Row Col
254 | RecordEquals Row Col
255 | RecordExpr Expr Row Col
256 | RecordSpace Space Row Col
257 --
258 | RecordIndentOpen Row Col
259 | RecordIndentEnd Row Col
260 | RecordIndentField Row Col
261 | RecordIndentEquals Row Col
262 | RecordIndentExpr Row Col
265data Tuple
266 = TupleOpen Row Col
267 | TupleExpr Expr Row Col
268 | TupleSpace Space Row Col
269 | TupleEnd Row Col
270 | TupleOperatorClose Row Col
271 | TupleOperatorReserved Operator Row Col
272 --
273 | TupleIndentExpr Row Col
274 | TupleIndentEnd Row Col
277data List
278 = ListSpace Space Row Col
279 | ListOpen Row Col
280 | ListExpr Expr Row Col
281 | ListEnd Row Col
282 --
283 | ListIndentOpen Row Col
284 | ListIndentEnd Row Col
285 | ListIndentExpr Row Col
288data Func
289 = FuncSpace Space Row Col
290 | FuncArg Pattern Row Col
291 | FuncBody Expr Row Col
292 | FuncArrow Row Col
293 --
294 | FuncIndentArg Row Col
295 | FuncIndentArrow Row Col
296 | FuncIndentBody Row Col
299data Case
300 = CaseSpace Space Row Col
301 | CaseOf Row Col
302 | CasePattern Pattern Row Col
303 | CaseArrow Row Col
304 | CaseExpr Expr Row Col
305 | CaseBranch Expr Row Col
306 --
307 | CaseIndentOf Row Col
308 | CaseIndentExpr Row Col
309 | CaseIndentPattern Row Col
310 | CaseIndentArrow Row Col
311 | CaseIndentBranch Row Col
312 | CasePatternAlignment Word16 Row Col
315data If
316 = IfSpace Space Row Col
317 | IfThen Row Col
318 | IfElse Row Col
319 | IfElseBranchStart Row Col
320 --
321 | IfCondition Expr Row Col
322 | IfThenBranch Expr Row Col
323 | IfElseBranch Expr Row Col
324 --
325 | IfIndentCondition Row Col
326 | IfIndentThen Row Col
327 | IfIndentThenBranch Row Col
328 | IfIndentElseBranch Row Col
329 | IfIndentElse Row Col
332data Let
333 = LetSpace Space Row Col
334 | LetIn Row Col
335 | LetDefAlignment Word16 Row Col
336 | LetDefName Row Col
337 | LetDef Name.Name Def Row Col
338 | LetDestruct Destruct Row Col
339 | LetBody Expr Row Col
340 | LetIndentDef Row Col
341 | LetIndentIn Row Col
342 | LetIndentBody Row Col
345data Def
346 = DefSpace Space Row Col
347 | DefType Type Row Col
348 | DefNameRepeat Name.Name Row Col
349 | DefNameMatch Name.Name Name.Name Row Col
350 | DefArg Pattern Row Col
351 | DefEquals Row Col
352 | DefBody Expr Row Col
353 | DefIndentEquals Row Col
354 | DefIndentType Row Col
355 | DefIndentBody Row Col
356 | DefAlignment Word16 Row Col
359data Destruct
360 = DestructSpace Space Row Col
361 | DestructPattern Pattern Row Col
362 | DestructEquals Row Col
363 | DestructBody Expr Row Col
364 | DestructIndentEquals Row Col
365 | DestructIndentBody Row Col
369-- PATTERNS
372data Pattern
373 = PRecord PRecord Row Col
374 | PTuple PTuple Row Col
375 | PList PList Row Col
376 --
377 | PStart Row Col
378 | PChar Char Row Col
379 | PString String Row Col
380 | PNumber Number Row Col
381 | PFloat Int Row Col
382 | PAlias Row Col
383 | PWildcardNotVar Int Row Col
384 | PSpace Space Row Col
385 --
386 | PIndentStart Row Col
387 | PIndentAlias Row Col
390data PRecord
391 = PRecordOpen Row Col
392 | PRecordEnd Row Col
393 | PRecordField Row Col
394 | PRecordSpace Space Row Col
395 --
396 | PRecordIndentOpen Row Col
397 | PRecordIndentEnd Row Col
398 | PRecordIndentField Row Col
401data PTuple
402 = PTupleOpen Row Col
403 | PTupleEnd Row Col
404 | PTupleExpr Pattern Row Col
405 | PTupleSpace Space Row Col
406 --
407 | PTupleIndentOpen Row Col
408 | PTupleIndentEnd Row Col
409 | PTupleIndentExpr Row Col
412data PList
413 = PListOpen Row Col
414 | PListEnd Row Col
415 | PListExpr Pattern Row Col
416 | PListSpace Space Row Col
417 --
418 | PListIndentOpen Row Col
419 | PListIndentEnd Row Col
420 | PListIndentExpr Row Col
424-- TYPES
427data Type
428 = TRecord TRecord Row Col
429 | TTuple TTuple Row Col
430 | TVariant Row Col
431 | TArrow Row Col
432 --
433 | TStart Row Col
434 | TSpace Space Row Col
435 --
436 | TIndentStart Row Col
439data TRecord
440 = TRecordOpen Row Col
441 | TRecordEnd Row Col
442 --
443 | TRecordField Row Col
444 | TRecordColon Row Col
445 | TRecordType Type Row Col
446 --
447 | TRecordSpace Space Row Col
448 --
449 | TRecordIndentOpen Row Col
450 | TRecordIndentField Row Col
451 | TRecordIndentColon Row Col
452 | TRecordIndentType Row Col
453 | TRecordIndentEnd Row Col
456data TTuple
457 = TTupleOpen Row Col
458 | TTupleEnd Row Col
459 | TTupleType Type Row Col
460 | TTupleSpace Space Row Col
461 --
462 | TTupleIndentOpen Row Col
463 | TTupleIndentType Row Col
464 | TTupleIndentEnd Row Col
468-- LITERALS
471data Char
472 = CharEndless
473 | CharEscape Escape
474 | CharNotString Int
477data String
478 = StringEndless_Single
479 | StringEndless_Multi
480 | StringEscape Escape
483data Escape
484 = EscapeUnknown Word16 Word16
485 | BadUnicodeFormat Word16 Word16
486 | BadUnicodeCode Word16 Word16
487 | BadUnicodeLength Word16 Word16 Int Int
490data Number
491 = NumberEnd
492 | NumberDot Int
493 | NumberHexDigit
494 | NumberNoLeadingZero
498-- MISC
501data Space
502 = HasTab
503 | EndlessMultiComment
504 | UnexpectedDocComment
507data Operator
508 = OpDot
509 | OpPipe
510 | OpArrow
511 | OpEquals
512 | OpHasType
516-- TO REPORT
519toReport :: Code.Source -> Error -> Report.Report
520toReport source err =
521 error "TODO" source err
522{-
523 case err of
524 CommentOnNothing region ->
525 Report.Report "STRAY COMMENT" region [] $
526 Report.toCodeSnippet source region Nothing
527 (
528 "This documentation comment is not followed by anything."
529 ,
530 D.reflow $
531 "All documentation comments need to be right above the declaration they\
532 \ describe. Maybe some code got deleted or commented out by accident? Or\
533 \ maybe this comment is here by accident?"
534 )
536 UnexpectedPort region ->
537 Report.Report "UNEXPECTED PORTS" region [] $
538 Report.toCodeSnippet source region Nothing
539 (
540 D.reflow $
541 "You are declaring ports in a normal module."
542 ,
543 D.stack
544 [ D.fillSep
545 ["Switch","this","to","say",D.green "port module","instead,"
546 ,"marking","that","this","module","contains","port","declarations."
547 ]
548 , D.link "Note"
549 "Ports are not a traditional FFI for calling JS functions directly. They need a different mindset! Read"
550 "ports"
551 "to learn the syntax and how to use it effectively."
552 ]
553 )
555 NoPorts region ->
556 Report.Report "NO PORTS" region [] $
557 Report.toCodeSnippet source region Nothing
558 (
559 D.reflow $
560 "This module does not declare any ports, but it says it will:"
561 ,
562 D.fillSep
563 ["Switch","this","to",D.green "module"
564 ,"and","you","should","be","all","set!"
565 ]
566 )
568 ParseError row col context expectation ->
569 let
570 pos = A.Position row col
571 region = A.Region pos pos
572 in
573 case expectation of
574 TODO ->
575 error "TODO no parse error yet"
577 XXX ->
578 error "TODO no parse error yet"
580 -- Parse.Utils
582 HasTab ->
583 Report.Report "NO TABS" region [] $
584 Report.toCodeSnippet source region Nothing
585 (
586 D.reflow $
587 "I ran into a tab, but tabs are not allowed in Elm files."
588 ,
589 D.reflow $
590 "Replace the tab with spaces."
591 )
593 DocComment ->
594 Report.Report "EXPECTING DOC COMMENT" region [] $
595 Report.toCodeSnippet source region Nothing
596 (
597 D.reflow $
598 "I was expecting a doc comment here:"
599 ,
600 D.reflowLink
601 "Check out" "TODO" "for examples of doc comments."
602 )
604 MultiCommentEnd startRow startCol ->
605 let
606 startRegion =
607 A.Region
608 (A.Position startRow startCol)
609 (A.Position startRow (startCol + 3))
610 in
611 Report.Report "ENDLESS COMMENT" startRegion [] $
612 Report.toCodeSnippet source startRegion Nothing
613 (
614 D.reflow $
615 "I cannot find the end of this multi-line comment:"
616 ,
617 D.stack -- "{-"
618 [ D.reflow "Add a -} somewhere after this to end the comment."
619 , D.toSimpleHint
620 "Multi-line comments can be nested in Elm, so {- {- -} -} is a comment\
621 \ that happens to contain another comment. Like parentheses and curly braces,\
622 \ the start and end markers must always be balanced. Maybe that is the problem?"
623 ]
624 )
626 -- Parse.Number
628 Number_Start ->
629 Report.Report "EXPECTING NUMBER" region [] $
630 Report.toCodeSnippet source region Nothing
631 (
632 D.reflow $
633 "I was expecting to see a number here:"
634 ,
635 D.stack
636 [ D.reflow $
637 "I recognize numbers in the following formats:"
638 , D.indent 4 $ D.vcat [ "42", "3.14", "6.022e23", "0x002B" ]
639 , D.reflow $
640 "So is there a way to write it like one of those?"
641 ]
642 )
644 Number_End ->
645 Report.Report "WEIRD NUMBER" region [] $
646 Report.toCodeSnippet source region Nothing
647 (
648 D.reflow $
649 "I thought I was reading a number, but I ran into some weird stuff here:"
650 ,
651 D.stack
652 [ D.reflow $
653 "I recognize numbers in the following formats:"
654 , D.indent 4 $ D.vcat [ "42", "3.14", "6.022e23", "0x002B" ]
655 , D.reflow $
656 "So is there a way to write it like one of those?"
657 ]
658 )
660 Number_Dot int ->
661 Report.Report "WEIRD NUMBER" region [] $
662 Report.toCodeSnippet source region Nothing
663 (
664 D.reflow $
665 "Numbers cannot end with a dot like this:"
666 ,
667 D.fillSep
668 ["Switching","to",D.green (D.fromChars (show int))
669 ,"or",D.green (D.fromChars (show int ++ ".0"))
670 ,"will","work","though!"
671 ]
672 )
674 Number_HexDigit ->
675 Report.Report "WEIRD HEXIDECIMAL" region [] $
676 Report.toCodeSnippet source region Nothing
677 (
678 D.reflow $
679 "I thought I was reading a hexidecimal number until I got here:"
680 ,
681 D.stack
682 [ D.reflow $
683 "Valid hexidecimal digits include 0123456789abcdefABCDEF, so I can\
684 \ only recognize things like this:"
685 , D.indent 4 $ D.vcat [ "0x2B", "0x002B", "0x00ffb3" ]
686 ]
687 )
689 Number_NoLeadingZero ->
690 Report.Report "LEADING ZEROS" region [] $
691 Report.toCodeSnippet source region Nothing
692 (
693 D.reflow $
694 "I do not accept numbers with leading zeros:"
695 ,
696 D.stack
697 [ D.reflow $
698 "Just delete the leading zeros and it should work!"
699 , D.toSimpleNote $
700 "Some languages let you to specify octal numbers by adding a leading zero.\
701 \ So in C, writing 0111 is the same as writing 73. Some people are used to\
702 \ that, but others probably want it to equal 111. Either path is going to\
703 \ surprise people from certain backgrounds, so Elm tries to avoid this whole\
704 \ situation."
705 ]
706 )
708 Precedence ->
709 Report.Report "EXPECTING PRECEDENCE" region [] $
710 Report.toCodeSnippet source region Nothing
711 (
712 D.reflow $
713 "I was expecting the precedence here:"
714 ,
715 D.reflow $
716 "I need a single digit between 0 and 9 inclusive."
717 )
719 -- Parse.Utf8
721 CharStart ->
722 Report.Report "EXPECTING A CHARACTER" region [] $
723 Report.toCodeSnippet source region Nothing
724 (
725 D.reflow $
726 "I was expecting a character here:"
727 ,
728 D.stack
729 [ D.reflow $
730 "Characters start and end with single quotes, like this:"
731 , D.indent 4 $ D.vcat $
732 [ "'a'"
733 , "'b'"
734 , "'ø'"
735 , "'\\n'"
736 , "'\\u{00F8}'"
737 ]
738 , D.reflow $
739 "That last style lets you encode characters by their unicode\
740 \ code point, so 'a' is equivalent to '\\u{0061}', 'ø' is\
741 \ equivalent to '\\u{00F8}', and so on for all code points."
742 ]
743 )
745 CharEnd ->
746 Report.Report "MISSING SINGLE QUOTE" region [] $
747 Report.toCodeSnippet source region Nothing
748 (
749 D.reflow $
750 "I thought I was parsing a character, but I got to the end of\
751 \ the line without seeing the closing single quote:"
752 ,
753 D.stack
754 [ D.reflow $
755 "Characters start and end with single quotes, like this:"
756 , D.indent 4 $ D.vcat $
757 [ "'a'"
758 , "'b'"
759 , "'ø'"
760 , "'\\n'"
761 , "'\\u{00F8}'"
762 ]
763 , D.reflow $
764 "That last style lets you encode characters by their unicode\
765 \ code point, so 'a' is equivalent to '\\u{0061}', 'ø' is\
766 \ equivalent to '\\u{00F8}', and so on for all code points."
767 ]
768 )
770 CharNotString startRow startCol ->
771 let
772 stringRegion =
773 A.Region (A.Position startRow startCol) pos
774 in
775 Report.Report "NEEDS DOUBLE QUOTES" stringRegion [] $
776 Report.toCodeSnippet source stringRegion Nothing
777 (
778 "The following string uses single quotes:"
779 ,
780 D.stack
781 [ "Please switch to double quotes instead:"
782 , D.indent 4 $
783 D.dullyellow "'this'" <> " => " <> D.green "\"this\""
784 , D.toSimpleNote $
785 "Elm uses double quotes for strings like \"hello\", whereas it uses single\
786 \ quotes for individual characters like 'a' and 'ø'. This distinction helps with\
787 \ code like (String.any (\\c -> c == 'X') \"90210\") where you are inspecting\
788 \ individual characters."
789 ]
790 )
792 StringStart ->
793 Report.Report "EXPECTING A STRING" region [] $
794 Report.toCodeSnippet source region Nothing
795 (
796 D.reflow $
797 "I was expecting a string here:"
798 ,
799 D.fillSep
800 ["Something","like"
801 ,D.green "\"this\""
802 ,"or"
803 ,D.green "\"that\""
804 ,"with","double","quotes."
805 ]
806 )
808 StringEnd_Single ->
809 Report.Report "ENDLESS STRING" region [] $
810 Report.toCodeSnippet source region Nothing
811 (
812 D.reflow $
813 "I got to the end of the line without seeing the closing double quote:"
814 ,
815 D.stack
816 [ D.fillSep $
817 ["Strings","look","like",D.green "\"this\"","with","double"
818 ,"quotes","on","each","end.","Is","the","closing","double"
819 ,"quote","missing","in","your","code?"
820 ]
821 , D.link "Note" "Read" "TODO" "if you want a string that spans multiple lines."
822 ]
823 )
825 StringEnd_Multi startRow startCol ->
826 let
827 startRegion =
828 A.Region
829 (A.Position startRow startCol)
830 (A.Position startRow (startCol + 3))
831 in
832 Report.Report "ENDLESS STRING" startRegion [] $
833 Report.toCodeSnippet source startRegion Nothing
834 (
835 D.reflow $
836 "I cannot find the end of this multi-line string:"
837 ,
838 D.stack
839 [ D.reflow "Add a \"\"\" somewhere after this to end the string."
840 , D.link "Hint" "Read" "TODO" "for more information on strings and multi-line strings."
841 ]
842 )
844 EscapeUnknown startCol endCol ->
845 let
846 escapeRegion =
847 A.Region (A.Position row startCol) (A.Position row endCol)
848 in
849 Report.Report "UNKNOWN ESCAPE" escapeRegion [] $
850 Report.toCodeSnippet source escapeRegion Nothing
851 (
852 D.reflow $
853 "Backslashes always start escaped characters, but I do not recognize this one:"
854 ,
855 D.stack
856 [ D.reflow $
857 "Valid escape characters include:"
858 , D.indent 4 $ D.vcat $
859 [ "\\n"
860 , "\\r"
861 , "\\t"
862 , "\\\""
863 , "\\\'"
864 , "\\\\"
865 , "\\u{03BB}"
866 ]
867 , D.reflow $
868 "The last one lets encode ANY character by its Unicode code\
869 \ point, so use that for anything outside the ordinary six."
870 ]
871 )
873 BadUnicodeFormat startCol endCol ->
874 let
875 escapeRegion =
876 A.Region (A.Position row startCol) (A.Position row endCol)
877 in
878 Report.Report "BAD UNICODE ESCAPE" escapeRegion [] $
879 Report.toCodeSnippet source escapeRegion Nothing
880 (
881 D.reflow $
882 "I ran into an invalid Unicode escape:"
883 ,
884 D.stack
885 [ D.reflow $
886 "Here are some examples of valid Unicode escapes:"
887 , D.green $ D.indent 4 $ D.vcat $
888 [ "\\u{0041}"
889 , "\\u{03BB}"
890 , "\\u{6728}"
891 , "\\u{1F60A}"
892 ]
893 , D.reflow $
894 "Notice that the code point is always surrounded by curly\
895 \ braces. They are required!"
896 ]
897 )
899 BadUnicodeCode startCol endCol ->
900 let
901 escapeRegion =
902 A.Region (A.Position row startCol) (A.Position row endCol)
903 in
904 Report.Report "BAD UNICODE ESCAPE" escapeRegion [] $
905 Report.toCodeSnippet source escapeRegion Nothing
906 (
907 D.reflow $
908 "This is not a valid code point:"
909 ,
910 D.reflow $
911 "The valid code points are between 0 and 10FFFF inclusive."
912 )
914 BadUnicodeLength startCol endCol numDigits badCode ->
915 let
916 escapeRegion =
917 A.Region (A.Position row startCol) (A.Position row endCol)
918 in
919 Report.Report "BAD UNICODE ESCAPE" escapeRegion [] $
920 Report.toCodeSnippet source escapeRegion Nothing $
921 if numDigits < 4 then
922 (
923 D.reflow $
924 "Every code point needs at least four digits:"
925 ,
926 let
927 goodCode = replicate (4 - numDigits) '0' ++ showHex badCode ""
928 escape = "\\u{" <> D.fromChars goodCode <> "}"
929 in
930 D.fillSep ["Try",D.green escape,"instead?"]
931 )
933 else
934 (
935 D.reflow $
936 "This code point has too many digits:"
937 ,
938 D.fillSep $
939 ["Valid","code","points","are","between"
940 ,D.green "\\u{0000}","and",D.green "\\u{10FFFF}" <> ","
941 ,"so","try","trimming","any","leading","zeros","until"
942 ,"you","have","between","four","and","six","digits."
943 ]
944 )
946 -- Parse.Shader
948 ShaderStart ->
949 Report.Report "EXPECTING A SHADER" region [] $
950 Report.toCodeSnippet source region Nothing $
951 (
952 D.reflow $
953 "I was expecting a GLSL shader block here:"
954 ,
955 D.reflow $
956 "These blocks start with [glsl| and end with |] and should be\
957 \ filled with GLSL code."
958 )
960 ShaderEnd startCol endCol ->
961 let
962 shaderRegion =
963 A.Region (A.Position row startCol) (A.Position row endCol)
964 in
965 Report.Report "ENDLESS SHADER" shaderRegion [] $
966 Report.toCodeSnippet source shaderRegion Nothing
967 (
968 D.reflow "I cannot find the end of this shader:"
969 ,
970 D.reflow "Add a |] somewhere after this to end the shader."
971 )
973 ShaderProblem problem ->
974 Report.Report "SHADER PROBLEM" region [] $
975 Report.toCodeSnippet source region Nothing
976 (
977 D.reflow $
978 "I ran into a problem while parsing this GLSL block."
979 ,
980 D.fromChars problem
981 )
983 Operator ->
984 Report.Report "EXPECTING AN OPERATOR" region [] $
985 Report.toCodeSnippet source region Nothing
986 (
987 D.reflow $
988 "I was expecting an operator here:"
989 ,
990 D.stack
991 [ D.reflow "Some of the most common operators are:"
992 , D.indent 4 $ D.vcat ["+","-","*","&&","||"]
993 , D.reflow "Something like that!"
994 ]
995 )
997 ReservedOperator op ->
998 error "TODO ReservedOperator" op
1000 Wildcard ->
1001 Report.Report "EXPECTING A WILDCARD" region [] $
1002 Report.toCodeSnippet source region Nothing
1004 D.reflow $
1005 "I was expecting a _ here:"
1007 D.reflow $
1008 "An underscore indicates that “I do not care about this value” and is\
1009 \ called a wildcard pattern because it will match with any type of values."
1012 WildcardNotVar startCol endCol ->
1013 let
1014 badRegion =
1015 A.Region (A.Position row startCol) (A.Position row endCol)
1016 in
1017 Report.Report "INVALID PATTERN" badRegion [] $
1018 Report.toCodeSnippet source badRegion Nothing
1020 D.reflow $
1021 "I was expecting to see an underscore without any additional characters:"
1023 D.reflow $
1024 "There are two options. Either (1) remove the extra characters and ignore the\
1025 \ value or (2) remove the starting underscore to give the value a normal name."
1028 -- Parse.Pattern
1030 Pattern ->
1031 error "TODO" context
1033 case context of
1034 P.Frame r c
1035 P.NoContext ->
1038 FloatInPattern ->
1039 Report.Report "INVALID PATTERN" region [] $
1040 Report.toCodeSnippet source region Nothing
1042 D.reflow $
1043 "I cannot pattern match with floating point numbers:"
1045 D.reflow $
1046 "Equality on floats can be unreliable, so you usually want to check that they\
1047 \ are nearby with some sort of (abs (actual - expected) < 0.001) check."
1050 FieldNamePattern ->
1051 Report.Report "EXPECTING A FIELD NAME" region [] $
1052 Report.toCodeSnippet source region Nothing
1054 D.reflow $
1055 "I was expecting a field name here:"
1057 D.fillSep $
1058 ["A","name","like",D.dullyellow "id" <> ",",D.dullyellow "status" <> ","
1059 ,"or","whatever","field","you","want","to","access."
1063 -- Parse.Expression
1065 MatchingName name ->
1066 Report.Report "EXPECTING A DEFINITION" region [] $
1067 Report.toCodeSnippet source region Nothing
1069 D.reflow $
1070 "I just saw the type annotation for `" ++ Name.toChars name
1071 ++ "` so I was expecting to see its definition here:"
1073 D.reflow $
1074 "Type annotations always appear directly above the relevant\
1075 \ definition, without anything else (even doc comments) in between."
1080 EndOfFile ->
1081 Report.Report "EXPECTING END OF FILE" region [] $
1082 Report.toCodeSnippet source region Nothing
1084 D.reflow $
1085 "I was not expecting to see anything more here:"
1087 D.reflow $
1088 "I think I have read all the declarations in the file and that there is nothing\
1089 \ left to see, so whatever I am running into is confusing me a lot!"
1095 TypeWithBadDefinition region annName defName ->
1096 Report.Report "ANNOTATION MISMATCH" region [] $
1097 Report.toCodeSnippet source region Nothing
1099 D.reflow $
1100 "I see a `" <> Name.toChars annName
1101 <> "` annotation, but it is followed by a `"
1102 <> Name.toChars defName <> "` definition."
1104 D.fillSep
1105 ["The","annotation","and","definition","names","must","match!"
1106 ,"Is","there","a","typo","between"
1107 , D.dullyellow (D.fromName annName)
1108 ,"and"
1109 , D.dullyellow (D.fromName defName) <> "?"
1114-- PARSE ERROR TO DOCS
1117problemToDocs :: Problem -> (D.Doc, D.Doc)
1118problemToDocs problem =
1119 case problem of
1120 Tab ->
1122 "I ran into a tab, but tabs are not allowed in Elm files."
1124 "Replace the tab with spaces."
1127 EndOfFile_Comment ->
1129 "I got to the end of the file while parsing a multi-line comment."
1132 "Multi-line comments look like {- comment -}, and it looks like\
1133 \ you are missing the closing marker."
1135 D.toSimpleHint $
1136 "Nested multi-line comments like {- this {- and this -} -} are allowed.\
1137 \ The opening and closing markers must be balanced though, just\
1138 \ like parentheses in normal code. Maybe that is the problem?"
1142 EndOfFile_String ->
1144 "I got to the end of the file while parsing a string."
1146 "Strings look like \"this\" with double quotes on each end.\
1147 \ Is the closing double quote missing in your code?"
1150 EndOfFile_MultiString ->
1152 "I got to the end of the file while parsing a multi-line string."
1154 "Multi-line strings look like \"\"\"this\"\"\" with three double quotes\
1155 \ on each end. Is the closing triple quote missing in your code?"
1158 EndOfFile_Char ->
1160 "I got to the end of the file while parsing a character."
1162 "Characters look like 'c' with single quotes on each end.\
1163 \ Is the closing single quote missing in your code?"
1166 NewLineInString ->
1168 "This string is missing the closing quote."
1171 "Elm strings like \"this\" cannot contain newlines."
1173 D.toSimpleHint $
1174 "For strings that CAN contain newlines, say \"\"\"this\"\"\" for Elm’s\
1175 \ multi-line string syntax. It allows unescaped newlines and double quotes."
1179 NewLineInChar ->
1181 "This character is missing the closing quote."
1183 "Elm characters must start and end with a single quote. Valid examples\n\
1184 \ include 'a', 'b', '\n', 'ø', and '\\u{00F8}' for unicode code points."
1187 BadNumberDot numberBeforeDot ->
1189 "Numbers cannot end with a decimal points."
1191 let
1192 number =
1193 D.fromString (show numberBeforeDot)
1194 in
1195 "Saying " <> D.green number <> " or " <> D.green (number <> ".0") <> " will work though!"
1198 BadNumberEnd ->
1200 "Numbers cannot have letters or underscores in them."
1202 "Maybe a space is missing between a number and a variable?"
1205 BadNumberExp ->
1207 "If you put the letter E in a number, it should followed by more digits."
1209 "If you want to say 1000, you can also say 1e3.\
1210 \ You cannot just end it with an E though!"
1213 BadNumberHex ->
1215 "I see the start of a hex number, but not the end."
1217 "A hex number looks like 0x123ABC, where the 0x is followed by hexidecimal\
1218 \ digits. Valid hexidecimal digits include: 0123456789abcdefABCDEF"
1221 BadNumberZero ->
1223 "Normal numbers cannot start with zeros. Take the zeros off the front."
1225 "Only numbers like 0x0040 or 0.25 can start with a zero."
1228 BadUnderscore _ ->
1230 "Variable names cannot start with an underscore like this:"
1232 "Delete the underscore and it shoulld be fine!"
1235 BadOp op stack ->
1236 case op of
1237 HasType ->
1238 badOp stack "A" "\"has type\" operator"
1239 "type annotations and record types"
1240 "Maybe you want :: instead? Or maybe something is indented too much?"
1242 Equals ->
1244 "I was not expecting this equals sign"
1245 <> contextToString " here" " while parsing " stack <> "."
1247 toBadEqualsHint stack
1250 Arrow ->
1251 if isCaseRelated stack then
1253 "I ran into a stray arrow while parsing this `case` expression."
1255 D.reflow $
1256 "All branches in a `case` must be indented the exact\
1257 \ same amount, so the patterns are vertically\
1258 \ aligned. Maybe this branch is indented too much?"
1261 else
1262 badOp stack "An" "arrow"
1263 "cases expressions and anonymous functions"
1264 "Maybe you want > or >= instead?"
1266 Pipe ->
1267 badOp stack "A" "vertical bar"
1268 "type declarations"
1269 "Maybe you want || instead?"
1271 Dot ->
1273 "I was not expecting this dot."
1275 D.reflow $
1276 "Dots are for record access and decimal points, so\
1277 \ they cannot float around on their own. Maybe\
1278 \ there is some extra whitespace?"
1281 Theories stack allTheories ->
1283 D.reflow $
1284 "Something went wrong while parsing " <> contextToString "your code" "" stack <> "."
1286 case Set.toList (Set.fromList allTheories) of
1287 [] ->
1288 D.stack
1289 [ D.reflow $
1290 "I do not have any suggestions though!"
1291 , D.reflow $
1292 "Can you get it down to a <http://sscce.org> and share it at\
1293 \ <https://github.com/elm/error-message-catalog/issues>?\
1294 \ That way we can figure out how to give better advice!"
1297 [theory] ->
1298 D.reflow $
1299 "I was expecting to see "
1300 <> addPeriod (theoryToString stack theory)
1302 theories ->
1303 D.vcat $
1304 [ "I was expecting:"
1305 , ""
1307 ++ map (bullet . theoryToString stack) theories
1312-- BAD OP HELPERS
1315badOp :: ContextStack -> String -> String -> String -> String -> ( D.Doc, D.Doc )
1316badOp stack article opName setting hint =
1318 D.reflow $
1319 "I was not expecting this " <> opName
1320 <> contextToString " here" " while parsing " stack <> "."
1322 D.reflow $
1323 article <> " " <> opName <> " should only appear in "
1324 <> setting <> ". " <> hint
1328toBadEqualsHint :: ContextStack -> D.Doc
1329toBadEqualsHint stack =
1330 case stack of
1331 [] ->
1332 D.reflow $
1333 "Maybe you want == instead? Or maybe something is indented too much?"
1335 (ExprRecord, _) : _ ->
1336 D.reflow $
1337 "Records look like { x = 3, y = 4 } with the equals sign right\
1338 \ after the field name. Maybe you forgot a comma?"
1340 (Definition _, _) : rest ->
1341 D.reflow $
1342 "Maybe this is supposed to be a separate definition? If so, it\
1343 \ is indented too far. "
1344 <>
1345 if any ((==) ExprLet . fst) rest then
1346 "All definitions in a `let` expression must be vertically aligned."
1347 else
1348 "Spaces are not allowed before top-level definitions."
1350 _ : rest ->
1351 toBadEqualsHint rest
1355isCaseRelated :: ContextStack -> Bool
1356isCaseRelated stack =
1357 case stack of
1358 [] ->
1359 False
1361 (context, _) : rest ->
1362 context == ExprCase || isCaseRelated rest
1366-- CONTEXT
1369contextToString :: String -> String -> ContextStack -> String
1370contextToString defaultString prefixString stack =
1371 case stack of
1372 [] ->
1373 defaultString
1375 (context, _) : rest ->
1376 let anchor = getAnchor rest in
1377 prefixString <>
1378 case context of
1379 ExprIf -> "an `if` expression" <> anchor
1380 ExprLet -> "a `let` expression" <> anchor
1381 ExprFunc -> "an anonymous function" <> anchor
1382 ExprCase -> "a `case` expression" <> anchor
1383 ExprList -> "a list" <> anchor
1384 ExprTuple -> "an expression (in parentheses)" <> anchor
1385 ExprRecord -> "a record" <> anchor
1386 Definition name -> Name.toChars name <> "'s definition"
1387 Annotation name -> Name.toChars name <> "'s type annotation"
1388 TypeTuple -> "a type (in parentheses)" <> anchor
1389 TypeRecord -> "a record type" <> anchor
1390 PatternList -> "a list pattern" <> anchor
1391 PatternTuple -> "a pattern (in parentheses)" <> anchor
1392 PatternRecord -> "a record pattern" <> anchor
1393 Module -> "a module declaration"
1394 Import -> "an import"
1395 TypeUnion -> "a union type"
1396 TypeAlias -> "a type alias"
1397 Infix -> "an infix declaration"
1398 Port -> "a port declaration"
1401getAnchor :: ContextStack -> String
1402getAnchor stack =
1403 case stack of
1404 [] ->
1405 ""
1407 (context, _) : rest ->
1408 case context of
1409 Definition name ->
1410 " in " <> Name.toChars name <> "'s definition"
1412 Annotation name ->
1413 " in " <> Name.toChars name <> "'s type annotation"
1415 _ ->
1416 getAnchor rest
1420-- THEORY HELPERS
1423bullet :: String -> D.Doc
1424bullet point =
1425 D.hang 4 (" - " <> D.fillSep (map D.fromString (words point)))
1428addPeriod :: String -> String
1429addPeriod msg =
1430 if last msg `elem` ['`', ')', '.', '!', '?'] then
1431 msg
1432 else
1433 msg <> "."
1436theoryToString :: ContextStack -> Theory -> String
1437theoryToString context theory =
1438 case theory of
1439 Keyword keyword ->
1440 "the `" <> keyword <> "` keyword"
1442 Symbol symbol ->
1443 case symbol of
1444 "=" -> equalsTheory context
1445 "->" -> "an arrow (->) followed by an expression"
1446 ":" -> "the \"has type\" symbol (:) followed by a type"
1447 "," -> "a comma"
1448 "|" -> barTheory context
1449 "::" -> "the cons operator (::) followed by more list elements"
1450 "." -> "a dot (.)"
1451 "-" -> "a minus sign (-)"
1452 "_" -> "an underscore"
1453 "(" -> "a left paren, for grouping or starting tuples"
1454 ")" -> "a closing paren"
1455 "[" -> "a left square bracket, for starting lists"
1456 "]" -> "a right square bracket, to end a list"
1457 "{" -> "a left curly brace, for starting records"
1458 "}" -> "a right curly brace, to end a record"
1459 "{-|" -> "a doc comment, like {-| this -}" --}
1460 _ -> "the (" <> symbol <> ") symbol"
1462 LowVar ->
1463 "a lower-case variable, like `x` or `user`"
1465 CapVar ->
1466 "an upper-case variable, like `Maybe` or `Just`"
1468 InfixOp ->
1469 "an infix operator, like (+) or (==)"
1471 Digit ->
1472 "a digit from 0 to 9"
1474 BadSpace ->
1475 badSpace context
1477 Expecting next ->
1478 case next of
1479 Decl -> "a declaration, like `x = 5` or `type alias Model = { ... }`"
1480 Expr -> "an expression, like x or 42"
1481 AfterOpExpr op -> "an expression after that (" <> Name.toChars op <> ") operator, like x or 42"
1482 ElseBranch -> "an `else` branch. An `if` must handle both possibilities."
1483 Arg -> "an argument, like `name` or `total`"
1484 Pattern -> "a pattern, like `name` or (Just x)"
1485 Type -> "a type, like Int or (List String)"
1486 Listing -> "a list of exposed values and types, like (..) or (x,y,z)"
1487 Exposing -> "something like `exposing (..)`"
1490equalsTheory :: ContextStack -> String
1491equalsTheory stack =
1492 case stack of
1493 [] ->
1494 "an equals sign (=)"
1496 (context, _) : rest ->
1497 case context of
1498 ExprRecord -> "an equals sign (=) followed by an expression"
1499 Definition name -> "an equals sign (=) followed by " <> Name.toChars name <> "'s definition"
1500 TypeUnion -> "an equals sign (=) followed by the first union type constructor"
1501 TypeAlias -> "an equals sign (=) followed by the aliased type"
1502 _ -> equalsTheory rest
1505barTheory :: ContextStack -> String
1506barTheory stack =
1507 case stack of
1508 [] ->
1509 "a vertical bar (|)"
1511 (context, _) : rest ->
1512 case context of
1513 ExprRecord -> "a vertical bar (|) followed by the record fields you want to update"
1514 TypeRecord -> "a vertical bar (|) followed by some record field types"
1515 TypeUnion -> "a vertical bar (|) followed by more union type constructors"
1516 _ -> barTheory rest
1519badSpace :: ContextStack -> String
1520badSpace stack =
1521 case stack of
1522 [] ->
1523 "more indentation? I was not done with that last thing yet."
1525 (context, _) : rest ->
1526 case context of
1527 ExprIf -> "the end of that `if`" <> badSpaceExprEnd rest
1528 ExprLet -> "the end of that `let`" <> badSpaceExprEnd rest
1529 ExprFunc -> badSpace rest
1530 ExprCase -> "more of that `case`" <> badSpaceExprEnd rest
1531 ExprList -> "the end of that list" <> badSpaceExprEnd rest
1532 ExprTuple -> "a closing paren" <> badSpaceExprEnd rest
1533 ExprRecord -> "the end of that record" <> badSpaceExprEnd rest
1534 Definition name -> "the rest of " <> Name.toChars name <> "'s definition" <> badSpaceExprEnd stack
1535 Annotation name -> "the rest of " <> Name.toChars name <> "'s type annotation" <> badSpaceEnd
1536 TypeTuple -> "a closing paren" <> badSpaceEnd
1537 TypeRecord -> "the end of that record" <> badSpaceEnd
1538 PatternList -> "the end of that list" <> badSpaceEnd
1539 PatternTuple -> "a closing paren" <> badSpaceEnd
1540 PatternRecord -> "the end of that record" <> badSpaceEnd
1541 Module -> "something like `module Main exposing (..)`"
1542 Import -> "something like `import Html exposing (..)`"
1543 TypeUnion -> "more of that union type" <> badSpaceEnd
1544 TypeAlias -> "more of that type alias" <> badSpaceEnd
1545 Infix -> "more of that infix declaration" <> badSpaceEnd
1546 Port -> "more of that port declaration" <> badSpaceEnd
1549badSpaceEnd :: String
1550badSpaceEnd =
1551 ". Maybe you forgot some code? Or you need more indentation?"
1554badSpaceExprEnd :: ContextStack -> String
1555badSpaceExprEnd stack =
1556 case stack of
1557 [] ->
1558 badSpaceEnd
1560 (Definition name, A.Position _ column) : _ ->
1561 let
1562 ending =
1563 if column <= 1 then
1564 "to be indented?"
1565 else
1566 "more indentation? (Try " <> show (column + 1) <> "+ spaces.)"
1567 in
1568 ". Maybe you forgot some code? Or maybe the body of `"
1569 <> Name.toChars name
1570 <> "` needs " <> ending
1572 _ : rest ->
1573 badSpaceExprEnd rest