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