on e43ce3d help sign in
2396 lines 78 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)
52import Numeric (showHex)
54import qualified Elm.ModuleName as ModuleName
55import Parse.Primitives (Row, Col)
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 | ModuleEndOfFile Row Col
81 | Module Row Col
82 | ModuleName Row Col
83 | ModuleExposing Row Col
84 | ModuleExposingList Exposing Row Col
85 --
86 | ModulePortModule Row Col
87 | ModuleEffect Row Col
88 --
89 | ModuleIndentStart Row Col
90 | ModuleIndentName Row Col
91 | ModuleIndentExposing Row Col
92 | ModuleIndentExposingList Row Col
93 | ModuleIndentPortModule Row Col
94 --
95 | FreshLineModuleStart Row Col
96 | FreshLineAfterModuleLine Row Col
97 | FreshLineAfterDocComment Row Col
98 --
99 | ImportStart Row Col
100 | ImportName Row Col
101 | ImportAs Row Col
102 | ImportAlias Row Col
103 | ImportExposing Row Col
104 | ImportExposingList Exposing Row Col
105 | ImportEnd Row Col -- different based on col=1 or if greater
106 --
107 | ImportIndentName Row Col
108 | ImportIndentAlias Row Col
109 | ImportIndentExposingList Row Col
110 --
111 | Infix Row Col
112 --
113 | Declarations Decl Row Col
116data Exposing
117 = ExposingSpace Space Row Col
118 | ExposingStart Row Col
119 | ExposingValue Row Col
120 | ExposingOperator Row Col
121 | ExposingOperatorReserved Operator Row Col
122 | ExposingOperatorRightParen Row Col
123 | ExposingEnd Row Col
124 --
125 | ExposingTypePrivacy Row Col
126 | ExposingTypePrivacyDots Row Col
127 | ExposingTypePrivacyEnd Row Col
128 --
129 | ExposingIndentEnd Row Col
130 | ExposingIndentValue Row Col
131 | ExposingIndentValueEnd Row Col
132 | ExposingIndentTypePrivacy Row Col
133 | ExposingIndentTypePrivacyDots Row Col
134 | ExposingIndentTypePrivacyEnd Row Col
138-- DECLARATIONS
141data Decl
142 = DeclStart Row Col
143 | DeclSpace Space Row Col
144 --
145 | Port Port Row Col
146 | DeclType DeclType Row Col
147 | DeclDef Name.Name DeclDef Row Col
148 --
149 | DeclFreshLineStart Row Col
150 | DeclFreshLineAfterDocComment Row Col
153data DeclDef
154 = DeclDefSpace Space Row Col
155 | DeclDefEquals Row Col
156 | DeclDefType Type Row Col
157 | DeclDefArg Pattern Row Col
158 | DeclDefBody Expr Row Col
159 | DeclDefNameRepeat Row Col
160 | DeclDefNameMatch Name.Name Row Col
161 --
162 | DeclDefIndentType Row Col
163 | DeclDefIndentEquals Row Col
164 | DeclDefIndentBody Row Col
165 --
166 | DeclDefFreshLineAfterType Row Col
169data Port
170 = PortSpace Space Row Col
171 | PortName Row Col
172 | PortColon Row Col
173 | PortType Type Row Col
174 | PortIndentName Row Col
175 | PortIndentColon Row Col
176 | PortIndentType Row Col
180-- TYPE DECLARATIONS
183data DeclType
184 = DT_Space Space Row Col
185 | DT_Name Row Col
186 | DT_Alias TypeAlias Row Col
187 | DT_Union CustomType Row Col
188 --
189 | DT_IndentName Row Col
192data TypeAlias
193 = AliasSpace Space Row Col
194 | AliasName Row Col
195 | AliasEquals Row Col
196 | AliasBody Type Row Col
197 --
198 | AliasIndentEquals Row Col
199 | AliasIndentBody Row Col
202data CustomType
203 = CT_Space Space Row Col
204 | CT_Name Row Col
205 | CT_Equals Row Col
206 | CT_Bar Row Col
207 | CT_Variant Row Col
208 | CT_VariantArg Type Row Col
209 --
210 | CT_IndentEquals Row Col
211 | CT_IndentBar Row Col
212 | CT_IndentAfterBar Row Col
213 | CT_IndentAfterEquals Row Col
217-- EXPRESSIONS
220data Expr
221 = Let Let Row Col
222 | Case Case Row Col
223 | If If Row Col
224 | List List Row Col
225 | Record Record Row Col
226 | Tuple Tuple Row Col
227 | Func Func Row Col
228 --
229 | Dot Row Col
230 | Access Row Col
231 | OperatorRight Name.Name Row Col
232 | OperatorReserved Operator Row Col
233 --
234 | Start Row Col
235 | Char Char Row Col
236 | String String Row Col
237 | Number Number Row Col
238 | Space Space Row Col
239 | EndlessShader Row Col
240 | ShaderProblem [Char.Char] Row Col
241 | IndentOperatorRight Name.Name Row Col
242 | IndentMoreExpr Row Col
245data Record
246 = RecordOpen Row Col
247 | RecordEnd Row Col
248 | RecordField Row Col
249 | RecordEquals Row Col
250 | RecordExpr Expr Row Col
251 | RecordSpace Space Row Col
252 --
253 | RecordIndentOpen Row Col
254 | RecordIndentEnd Row Col
255 | RecordIndentField Row Col
256 | RecordIndentEquals Row Col
257 | RecordIndentExpr Row Col
260data Tuple
261 = TupleExpr Expr Row Col
262 | TupleSpace Space Row Col
263 | TupleEnd Row Col
264 | TupleOperatorClose Row Col
265 | TupleOperatorReserved Operator Row Col
266 --
267 | TupleIndentExpr1 Row Col
268 | TupleIndentExprN Row Col
269 | TupleIndentEnd Row Col
272data List
273 = ListSpace Space Row Col
274 | ListOpen Row Col
275 | ListExpr Expr Row Col
276 | ListEnd Row Col
277 --
278 | ListIndentOpen Row Col
279 | ListIndentEnd Row Col
280 | ListIndentExpr Row Col
283data Func
284 = FuncSpace Space Row Col
285 | FuncArg Pattern Row Col
286 | FuncBody Expr Row Col
287 | FuncArrow Row Col
288 --
289 | FuncIndentArg Row Col
290 | FuncIndentArrow Row Col
291 | FuncIndentBody Row Col
294data Case
295 = CaseSpace Space Row Col
296 | CaseOf Row Col
297 | CasePattern Pattern Row Col
298 | CaseArrow Row Col
299 | CaseExpr Expr Row Col
300 | CaseBranch Expr Row Col
301 --
302 | CaseIndentOf Row Col
303 | CaseIndentExpr Row Col
304 | CaseIndentPattern Row Col
305 | CaseIndentArrow Row Col
306 | CaseIndentBranch Row Col
307 | CasePatternAlignment Word16 Row Col
310data If
311 = IfSpace Space Row Col
312 | IfThen Row Col
313 | IfElse Row Col
314 | IfElseBranchStart Row Col
315 --
316 | IfCondition Expr Row Col
317 | IfThenBranch Expr Row Col
318 | IfElseBranch Expr Row Col
319 --
320 | IfIndentCondition Row Col
321 | IfIndentThen Row Col
322 | IfIndentThenBranch Row Col
323 | IfIndentElseBranch Row Col
324 | IfIndentElse Row Col
327data Let
328 = LetSpace Space Row Col
329 | LetIn Row Col
330 | LetDefAlignment Word16 Row Col
331 | LetDefName Row Col
332 | LetDef Name.Name Def Row Col
333 | LetDestruct Destruct Row Col
334 | LetBody Expr Row Col
335 | LetIndentDef Row Col
336 | LetIndentIn Row Col
337 | LetIndentBody Row Col
340data Def
341 = DefSpace Space Row Col
342 | DefType Type Row Col
343 | DefNameRepeat Name.Name Row Col
344 | DefNameMatch Name.Name Name.Name Row Col
345 | DefArg Pattern Row Col
346 | DefEquals Row Col
347 | DefBody Expr Row Col
348 | DefIndentEquals Row Col
349 | DefIndentType Row Col
350 | DefIndentBody Row Col
351 | DefAlignment Word16 Row Col
354data Destruct
355 = DestructSpace Space Row Col
356 | DestructPattern Pattern Row Col
357 | DestructEquals Row Col
358 | DestructBody Expr Row Col
359 | DestructIndentEquals Row Col
360 | DestructIndentBody Row Col
364-- PATTERNS
367data Pattern
368 = PRecord PRecord Row Col
369 | PTuple PTuple Row Col
370 | PList PList Row Col
371 --
372 | PStart Row Col
373 | PChar Char Row Col
374 | PString String Row Col
375 | PNumber Number Row Col
376 | PFloat Int Row Col
377 | PAlias Row Col
378 | PWildcardNotVar Int Row Col
379 | PSpace Space Row Col
380 --
381 | PIndentStart Row Col
382 | PIndentAlias Row Col
385data PRecord
386 = PRecordOpen Row Col
387 | PRecordEnd Row Col
388 | PRecordField Row Col
389 | PRecordSpace Space Row Col
390 --
391 | PRecordIndentOpen Row Col
392 | PRecordIndentEnd Row Col
393 | PRecordIndentField Row Col
396data PTuple
397 = PTupleOpen Row Col
398 | PTupleEnd Row Col
399 | PTupleExpr Pattern Row Col
400 | PTupleSpace Space Row Col
401 --
402 | PTupleIndentOpen Row Col
403 | PTupleIndentEnd Row Col
404 | PTupleIndentExpr Row Col
407data PList
408 = PListOpen Row Col
409 | PListEnd Row Col
410 | PListExpr Pattern Row Col
411 | PListSpace Space Row Col
412 --
413 | PListIndentOpen Row Col
414 | PListIndentEnd Row Col
415 | PListIndentExpr Row Col
419-- TYPES
422data Type
423 = TRecord TRecord Row Col
424 | TTuple TTuple Row Col
425 | TVariant Row Col
426 | TArrow Row Col
427 --
428 | TStart Row Col
429 | TSpace Space Row Col
430 --
431 | TIndentStart Row Col
434data TRecord
435 = TRecordOpen Row Col
436 | TRecordEnd Row Col
437 --
438 | TRecordField Row Col
439 | TRecordColon Row Col
440 | TRecordType Type Row Col
441 --
442 | TRecordSpace Space Row Col
443 --
444 | TRecordIndentOpen Row Col
445 | TRecordIndentField Row Col
446 | TRecordIndentColon Row Col
447 | TRecordIndentType Row Col
448 | TRecordIndentEnd Row Col
451data TTuple
452 = TTupleOpen Row Col
453 | TTupleEnd Row Col
454 | TTupleType Type Row Col
455 | TTupleSpace Space Row Col
456 --
457 | TTupleIndentOpen Row Col
458 | TTupleIndentType Row Col
459 | TTupleIndentEnd Row Col
463-- LITERALS
466data Char
467 = CharEndless
468 | CharEscape Escape
469 | CharNotString Word16
472data String
473 = StringEndless_Single
474 | StringEndless_Multi
475 | StringEscape Escape
478data Escape
479 = EscapeUnknown
480 | BadUnicodeFormat Word16
481 | BadUnicodeCode Word16
482 | BadUnicodeLength Word16 Int Int
485data Number
486 = NumberEnd
487 | NumberDot Int
488 | NumberHexDigit
489 | NumberNoLeadingZero
493-- MISC
496data Space
497 = HasTab
498 | EndlessMultiComment
501data Operator
502 = OpDot
503 | OpPipe
504 | OpArrow
505 | OpEquals
506 | OpHasType
510-- TO REPORT
513toReport :: Code.Source -> Error -> Report.Report
514toReport source err =
515 case err of
516 ModuleNameUnspecified name ->
517 let
518 region = toRegion 1 1
519 in
520 Report.Report "MODULE NAME MISSING" region [] $
521 D.stack
522 [ D.reflow $
523 "I need the module name to be declared at the top of this file, like this:"
524 , D.indent 4 $ D.green $ D.fromChars $
525 "module " ++ ModuleName.toChars name ++ " exposing (..)"
526 , D.reflow $
527 "Try adding that as the first line of your file!"
528 , D.toSimpleNote $
529 "It is best to replace (..) with an explicit list of types and\
530 \ functions you want to expose. When you know a value is only used\
531 \ within this module, you can refactor without worrying about uses\
532 \ elsewhere. Limiting exposed values can also speed up compilation\
533 \ because I can skip a bunch of work if I see that the exposed API\
534 \ has not changed."
535 ]
537 ModuleNameMismatch expectedName (A.At region actualName) ->
538 Report.Report "MODULE NAME MISMATCH" region [ModuleName.toChars expectedName] $
539 Report.toCodeSnippet source region Nothing
540 (
541 "It looks like this module name is out of sync:"
542 ,
543 D.stack
544 [ D.reflow $
545 "I need it to match the file path, so I was expecting it to see `"
546 ++ ModuleName.toChars expectedName
547 ++ "` here. Make the following change, and you should be all set!"
548 , D.indent 4 $
549 D.dullyellow (D.fromName actualName) <> " -> " <> D.green (D.fromName expectedName)
550 , D.toSimpleNote $
551 "I require that module names correspond to file paths. This makes it much\
552 \ easier to explore unfamiliar codebases! So if you want to keep the current\
553 \ module name, try renaming the file instead."
554 ]
555 )
557 UnexpectedPort region ->
558 error "TODO UnexpectedPort" region
560 NoPorts region ->
561 error "TODO NoPorts" region
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 ModuleEndOfFile row col ->
574 let
575 region = toRegion row col
576 in
577 Report.Report "EXPECTING END OF FILE" region [] $
578 Report.toCodeSnippet source region Nothing
579 (
580 D.reflow $
581 "I was not expecting to see anything more here:"
582 ,
583 D.reflow $
584 "I think I have read all the declarations in the file and that there is nothing\
585 \ left to see, so whatever I am running into is confusing me a lot!"
586 )
588 Module row col ->
589 error "TODO Module" row col
591 ModuleName row col ->
592 error "TODO ModuleName" row col
594 ModuleExposing row col ->
595 error "TODO ModuleExposing" row col
597 ModuleExposingList exposing row col ->
598 error "TODO ModuleExposingList" exposing row col
600 ModulePortModule row col ->
601 error "TODO ModulePortModule" row col
603 ModuleEffect row col ->
604 error "TODO ModuleEffect" row col
606 ModuleIndentStart row col ->
607 error "TODO ModuleIndentStart" row col
609 ModuleIndentName row col ->
610 error "TODO ModuleIndentName" row col
612 ModuleIndentExposing row col ->
613 error "TODO ModuleIndentExposing" row col
615 ModuleIndentExposingList row col ->
616 error "TODO ModuleIndentExposingList" row col
618 ModuleIndentPortModule row col ->
619 error "TODO ModuleIndentPortModule" row col
621 FreshLineModuleStart row col ->
622 error "TODO FreshLineModuleStart" row col
624 FreshLineAfterModuleLine row col ->
625 error "TODO FreshLineAfterModuleLine" row col
627 FreshLineAfterDocComment row col ->
628 error "TODO FreshLineAfterDocComment" row col
630 ImportStart row col ->
631 error "TODO ImportStart" row col
633 ImportName row col ->
634 error "TODO ImportName" row col
636 ImportAs row col ->
637 error "TODO ImportAs" row col
639 ImportAlias row col ->
640 error "TODO ImportAlias" row col
642 ImportExposing row col ->
643 error "TODO ImportExposing" row col
645 ImportExposingList exposing row col ->
646 error "TODO ImportExposingList" exposing row col
648 ImportEnd row col ->
649 error "TODO ImportEnd" row col
651 ImportIndentName row col ->
652 error "TODO ImportIndentName" row col
654 ImportIndentAlias row col ->
655 error "TODO ImportIndentAlias" row col
657 ImportIndentExposingList row col ->
658 let
659 region = toRegion row col
660 in
661 Report.Report "UNFINISHED IMPORT" region [] $
662 Report.toCodeSnippet source region Nothing
663 (
664 D.reflow $
665 "I was parsing an `import` until I got stuck here:"
666 ,
667 D.stack
668 [ D.reflow $
669 "I was expecting to see the list of exposed values next. For example, here\
670 \ are two ways to expose values from the `Html` module:"
671 , D.indent 4 $ D.vcat $
672 [ D.fillSep [D.blue "import","Html",D.blue "exposing",D.green "(..)"]
673 , D.fillSep [D.blue "import","Html",D.blue "exposing",D.green "(Html, div, text)"]
674 ]
675 , D.reflow $
676 "I generally recommend the second style. It is more explicit, making it\
677 \ much easier to figure out where values are coming from in large projects!"
678 ]
679 )
681 Infix row col ->
682 let
683 region = toRegion row col
684 in
685 Report.Report "BAD INFIX" region [] $
686 Report.toCodeSnippet source region Nothing
687 (
688 D.reflow $
689 "Something went wrong in this infix operator declaration:"
690 ,
691 D.reflow $
692 "This feature is used by the @elm organization to define the\
693 \ languages built-in operators."
694 )
696 Declarations decl _ _ ->
697 toDeclarationsReport source decl
700toSpaceReport :: Code.Source -> Space -> Row -> Col -> Report.Report
701toSpaceReport source space row col =
702 case space of
703 HasTab ->
704 let
705 region = toRegion row col
706 in
707 Report.Report "NO TABS" region [] $
708 Report.toCodeSnippet source region Nothing
709 (
710 D.reflow $
711 "I ran into a tab, but tabs are not allowed in Elm files."
712 ,
713 D.reflow $
714 "Replace the tab with spaces."
715 )
717 EndlessMultiComment ->
718 let
719 region = toWiderRegion row col 2
720 in
721 Report.Report "ENDLESS COMMENT" region [] $
722 Report.toCodeSnippet source region Nothing
723 (
724 D.reflow $
725 "I cannot find the end of this multi-line comment:"
726 ,
727 D.stack -- "{-"
728 [ D.reflow "Add a -} somewhere after this to end the comment."
729 , D.toSimpleHint
730 "Multi-line comments can be nested in Elm, so {- {- -} -} is a comment\
731 \ that happens to contain another comment. Like parentheses and curly braces,\
732 \ the start and end markers must always be balanced. Maybe that is the problem?"
733 ]
734 )
737toRegion :: Row -> Col -> A.Region
738toRegion row col =
739 let
740 pos = A.Position row col
741 in
742 A.Region pos pos
745toWiderRegion :: Row -> Col -> Word16 -> A.Region
746toWiderRegion row col extra =
747 A.Region
748 (A.Position row col)
749 (A.Position row (col + extra))
752toDeclarationsReport :: Code.Source -> Decl -> Report.Report
753toDeclarationsReport source decl =
754 case decl of
755 DeclStart row col ->
756 error "TODO DeclStart" row col
758 DeclSpace space row col ->
759 toSpaceReport source space row col
761 Port port row col ->
762 error "TODO Port" port row col
764 DeclType declType row col ->
765 error "TODO DeclType" declType row col
767 DeclDef name declDef row col ->
768 toDeclDefReport source name declDef row col
770 DeclFreshLineStart row col ->
771 error "TODO DeclFreshLineStart" row col
773 DeclFreshLineAfterDocComment row col ->
774 error "TODO DeclFreshLineAfterDocComment" row col
777toDeclDefReport :: Code.Source -> Name.Name -> DeclDef -> Row -> Col -> Report.Report
778toDeclDefReport source name declDef startRow startCol =
779 case declDef of
780 DeclDefSpace space row col ->
781 toSpaceReport source space row col
783 DeclDefEquals row col ->
784 error "TODO DeclDefEquals" row col
786 DeclDefType tipe row col ->
787 error "TODO DeclDefType" tipe row col
789 DeclDefArg pattern row col ->
790 error "TODO DeclDefArg" pattern row col
792 DeclDefBody expr row col ->
793 toExprReport source (InDef name startRow startCol) expr row col
795 DeclDefNameRepeat row col ->
796 error "TODO DeclDefNameRepeat" name row col
798 DeclDefNameMatch defName row col ->
799 error "TODO DeclDefNameMatch" name defName row col
801 DeclDefIndentType row col ->
802 error "TODO DeclDefIndentType" row col
804 DeclDefIndentEquals row col ->
805 error "TODO DeclDefIndentEquals" row col
807 DeclDefIndentBody row col ->
808 error "TODO DeclDefIndentBody" row col
810 DeclDefFreshLineAfterType row col ->
811 error "TODO DeclDefFreshLineAfterType" row col
815-- CONTEXT
818data Context
819 = InNode Node Row Col Context
820 | InDef Name.Name Row Col
823data Node
824 = NRecord
825 | NParens
826 | NList
827 | NFunc
828 | NCond
829 | NThen
830 | NElse
831 deriving (Eq)
834getDefName :: Context -> Name.Name
835getDefName context =
836 case context of
837 InDef name _ _ -> name
838 InNode _ _ _ c -> getDefName c
841isWithin :: Node -> Context -> Bool
842isWithin desiredNode context =
843 case context of
844 InDef _ _ _ -> False
845 InNode actualNode _ _ _ -> desiredNode == actualNode
849-- EXPR REPORTS
852toExprReport :: Code.Source -> Context -> Expr -> Row -> Col -> Report.Report
853toExprReport source context expr startRow startCol =
854 case expr of
855 Let _ _ _ ->
856 error "TODO Let"
858 Case _ _ _ ->
859 error "TODO Case"
861 If if_ row col ->
862 toIfReport source context if_ row col
864 List list row col ->
865 toListReport source context list row col
867 Record record row col ->
868 toRecordReport source context record row col
870 Tuple tuple row col ->
871 toTupleReport source context tuple row col
873 Func func row col ->
874 toFuncReport source context func row col
876 Dot row col ->
877 let region = toRegion row col in
878 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
879 Report.toCodeSnippet source region Nothing
880 (
881 D.reflow $
882 "I was expecting to see a record accessor here:"
883 ,
884 D.fillSep
885 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
886 ,"that","accesses","a","value","from","a","record."
887 ]
888 )
890 Access row col ->
891 let region = toRegion row col in
892 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
893 Report.toCodeSnippet source region Nothing
894 (
895 D.reflow $
896 "I am trying to parse a record accessor here:"
897 ,
898 D.stack
899 [
900 D.fillSep
901 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
902 ,"that","accesses","a","value","from","a","record."
903 ]
904 ,
905 D.toSimpleNote $
906 "Record field names must start with a lower case letter!"
907 ]
908 )
910 OperatorRight op row col ->
911 let region = toRegion row col in
912 Report.Report "MISSING EXPRESSION" region [] $
913 Report.toCodeSnippet source region Nothing
914 (
915 D.reflow $
916 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
917 ,
918 D.stack
919 [ D.fillSep $
920 ["You","can","just","put","anything","for","now,","like"
921 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
922 ,"Once","there","is","something","there,","I","can","probably"
923 ,"give","a","more","specific","hint!"
924 ]
925 , D.toSimpleNote $
926 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
927 \ Or if I run into operators in unexpected spots. Point is, there are a\
928 \ couple ways I can get confused and give sort of weird advice!"
929 ]
930 )
932 OperatorReserved operator row col ->
933 toOperatorReport source context operator row col
935 Start row col ->
936 let
937 (contextRow, contextCol, aThing) =
938 case context of
939 InDef name r c -> (r, c, "the `" ++ Name.toChars name ++ "` definition")
940 InNode NRecord r c _ -> (r, c, "a record")
941 InNode NParens r c _ -> (r, c, "some parentheses")
942 InNode NList r c _ -> (r, c, "a list")
943 InNode NFunc r c _ -> (r, c, "an anonymous function")
944 InNode NCond r c _ -> (r, c, "an `if` expression")
945 InNode NThen r c _ -> (r, c, "an `if` expression")
946 InNode NElse r c _ -> (r, c, "an `if` expression")
947 -- TODO check if this is actually the best way to get error messages here
949 surroundings = A.Region (A.Position contextRow contextCol) (A.Position row col)
950 region = toRegion row col
951 in
952 Report.Report "MISSING EXPRESSION" region [] $
953 Report.toCodeSnippet source surroundings (Just region)
954 (
955 D.reflow $
956 "I am partway through parsing " ++ aThing ++ ", but I got stuck here:"
957 ,
958 D.stack
959 [ D.fillSep $
960 ["I","was","expecting","to","see","an","expression","like"
961 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
962 ,"Once","there","is","something","there,","I","can","probably"
963 ,"give","a","more","specific","hint!"
964 ]
965 , D.toSimpleNote $
966 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
967 \ Or if I run into operators in unexpected spots. Point is, there are a\
968 \ couple ways I can get confused and give sort of weird advice!"
969 ]
970 )
972 Char char row col ->
973 toCharReport source char row col
975 String string row col ->
976 toStringReport source string row col
978 Number number row col ->
979 toNumberReport source number row col
981 Space space row col ->
982 toSpaceReport source space row col
984 EndlessShader row col ->
985 let
986 region = toWiderRegion row col 6
987 in
988 Report.Report "ENDLESS SHADER" region [] $
989 Report.toCodeSnippet source region Nothing
990 (
991 D.reflow "I cannot find the end of this shader:"
992 ,
993 D.reflow "Add a |] somewhere after this to end the shader."
994 )
996 ShaderProblem problem row col ->
997 let
998 region = toRegion row col
999 in
1000 Report.Report "SHADER PROBLEM" region [] $
1001 Report.toCodeSnippet source region Nothing
1003 D.reflow $
1004 "I ran into a problem while parsing this GLSL block."
1006 D.stack
1007 [ D.reflow $
1008 "I use a 3rd party GLSL parser for now, and I did my best to extract their error message:"
1009 , D.indent 4 $ D.vcat $
1010 map D.fromChars (filter (/="") (lines problem))
1014 IndentOperatorRight op row col ->
1015 let
1016 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1017 region = toRegion row col
1018 in
1019 Report.Report "MISSING EXPRESSION" region [] $
1020 Report.toCodeSnippet source surroundings (Just region)
1022 D.reflow $
1023 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
1025 D.stack
1027 D.fillSep $
1028 ["You","can","just","put","anything","for","now,","like"
1029 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1030 ,"Once","there","is","something","there,","I","can","probably"
1031 ,"give","a","more","specific","hint!"
1034 D.toSimpleNote $
1035 "I may be getting confused by your indentation? The easiest way to make sure\
1036 \ this is not an indentation problem is to put the expression on the right of\
1037 \ the " ++ Name.toChars op ++ " operator on the same line."
1041 IndentMoreExpr _ _ ->
1042 error "TODO IndentMoreExpr"
1045toCharReport :: Code.Source -> Char -> Row -> Col -> Report.Report
1046toCharReport source char row col =
1047 case char of
1048 CharEndless ->
1049 let
1050 region = toRegion row col
1051 in
1052 Report.Report "MISSING SINGLE QUOTE" region [] $
1053 Report.toCodeSnippet source region Nothing
1055 D.reflow $
1056 "I thought I was parsing a character, but I got to the end of\
1057 \ the line without seeing the closing single quote:"
1059 D.reflow $
1060 "Add a closing single quote here!"
1063 CharEscape escape ->
1064 toEscapeReport source escape row col
1066 CharNotString width ->
1067 let
1068 region = toWiderRegion row col width
1069 in
1070 Report.Report "NEEDS DOUBLE QUOTES" region [] $
1071 Report.toCodeSnippet source region Nothing
1073 "The following string uses single quotes:"
1075 D.stack
1076 [ "Please switch to double quotes instead:"
1077 , D.indent 4 $
1078 D.dullyellow "'this'" <> " => " <> D.green "\"this\""
1079 , D.toSimpleNote $
1080 "Elm uses double quotes for strings like \"hello\", whereas it uses single\
1081 \ quotes for individual characters like 'a' and 'ø'. This distinction helps with\
1082 \ code like (String.any (\\c -> c == 'X') \"90210\") where you are inspecting\
1083 \ individual characters."
1088toStringReport :: Code.Source -> String -> Row -> Col -> Report.Report
1089toStringReport source string row col =
1090 case string of
1091 StringEndless_Single ->
1092 let
1093 region = toRegion row col
1094 in
1095 Report.Report "ENDLESS STRING" region [] $
1096 Report.toCodeSnippet source region Nothing
1098 D.reflow $
1099 "I got to the end of the line without seeing the closing double quote:"
1101 D.stack
1102 [ D.fillSep $
1103 ["Strings","look","like",D.green "\"this\"","with","double"
1104 ,"quotes","on","each","end.","Is","the","closing","double"
1105 ,"quote","missing","in","your","code?"
1107 , D.link "Note" "Read" "TODO" "if you want a string that spans multiple lines."
1111 StringEndless_Multi ->
1112 let
1113 region = toWiderRegion row col 3
1114 in
1115 Report.Report "ENDLESS STRING" region [] $
1116 Report.toCodeSnippet source region Nothing
1118 D.reflow $
1119 "I cannot find the end of this multi-line string:"
1121 D.stack
1122 [ D.reflow "Add a \"\"\" somewhere after this to end the string."
1123 , D.link "Hint" "Read" "TODO" "for more information on strings and multi-line strings."
1127 StringEscape escape ->
1128 toEscapeReport source escape row col
1131toEscapeReport :: Code.Source -> Escape -> Row -> Col -> Report.Report
1132toEscapeReport source escape row col =
1133 case escape of
1134 EscapeUnknown ->
1135 let
1136 region = toWiderRegion row col 2
1137 in
1138 Report.Report "UNKNOWN ESCAPE" region [] $
1139 Report.toCodeSnippet source region Nothing
1141 D.reflow $
1142 "Backslashes always start escaped characters, but I do not recognize this one:"
1144 D.stack
1145 [ D.reflow $
1146 "Valid escape characters include:"
1147 , D.dullyellow $ D.indent 4 $ D.vcat $
1148 [ "\\n"
1149 , "\\r"
1150 , "\\t"
1151 , "\\\""
1152 , "\\\'"
1153 , "\\\\"
1154 , "\\u{003D}"
1156 , D.reflow $
1157 "Do you want one of those instead? Maybe you need \\\\ to escape a backslash?"
1158 , D.toSimpleNote $
1159 "The last style lets encode ANY character by its Unicode code\
1160 \ point. That means \\u{0009} and \\t are the same. You can use\
1161 \ that style for anything not covered by the other six escapes!"
1165 BadUnicodeFormat width ->
1166 let
1167 region = toWiderRegion row col width
1168 in
1169 Report.Report "BAD UNICODE ESCAPE" region [] $
1170 Report.toCodeSnippet source region Nothing
1172 D.reflow $
1173 "I ran into an invalid Unicode escape:"
1175 D.stack
1176 [ D.reflow $
1177 "Here are some examples of valid Unicode escapes:"
1178 , D.dullyellow $ D.indent 4 $ D.vcat $
1179 [ "\\u{0041}"
1180 , "\\u{03BB}"
1181 , "\\u{6728}"
1182 , "\\u{1F60A}"
1184 , D.reflow $
1185 "Notice that the code point is always surrounded by curly braces.\
1186 \ Maybe you are missing the opening or closing curly brace?"
1189 BadUnicodeCode width ->
1190 let
1191 region = toWiderRegion row col width
1192 in
1193 Report.Report "BAD UNICODE ESCAPE" region [] $
1194 Report.toCodeSnippet source region Nothing
1196 D.reflow $
1197 "This is not a valid code point:"
1199 D.reflow $
1200 "The valid code points are between 0 and 10FFFF inclusive."
1203 BadUnicodeLength width numDigits badCode ->
1204 let
1205 region = toWiderRegion row col width
1206 in
1207 Report.Report "BAD UNICODE ESCAPE" region [] $
1208 Report.toCodeSnippet source region Nothing $
1209 if numDigits < 4 then
1211 D.reflow $
1212 "Every code point needs at least four digits:"
1214 let
1215 goodCode = replicate (4 - numDigits) '0' ++ map Char.toUpper (showHex badCode "")
1216 suggestion = "\\u{" <> D.fromChars goodCode <> "}"
1217 in
1218 D.fillSep ["Try",D.green suggestion,"instead?"]
1221 else
1223 D.reflow $
1224 "This code point has too many digits:"
1226 D.fillSep $
1227 ["Valid","code","points","are","between"
1228 ,D.green "\\u{0000}","and",D.green "\\u{10FFFF}" <> ","
1229 ,"so","try","trimming","any","leading","zeros","until"
1230 ,"you","have","between","four","and","six","digits."
1235toNumberReport :: Code.Source -> Number -> Row -> Col -> Report.Report
1236toNumberReport source number row col =
1237 let
1238 region = toRegion row col
1239 in
1240 case number of
1241 NumberEnd ->
1242 Report.Report "WEIRD NUMBER" region [] $
1243 Report.toCodeSnippet source region Nothing
1245 D.reflow $
1246 "I thought I was reading a number, but I ran into some weird stuff here:"
1248 D.stack
1249 [ D.reflow $
1250 "I recognize numbers in the following formats:"
1251 , D.indent 4 $ D.vcat [ "42", "3.14", "6.022e23", "0x002B" ]
1252 , D.reflow $
1253 "So is there a way to write it like one of those?"
1257 NumberDot int ->
1258 Report.Report "WEIRD NUMBER" region [] $
1259 Report.toCodeSnippet source region Nothing
1261 D.reflow $
1262 "Numbers cannot end with a dot like this:"
1264 D.fillSep
1265 ["Switching","to",D.green (D.fromChars (show int))
1266 ,"or",D.green (D.fromChars (show int ++ ".0"))
1267 ,"will","work","though!"
1271 NumberHexDigit ->
1272 Report.Report "WEIRD HEXIDECIMAL" region [] $
1273 Report.toCodeSnippet source region Nothing
1275 D.reflow $
1276 "I thought I was reading a hexidecimal number until I got here:"
1278 D.stack
1279 [ D.reflow $
1280 "Valid hexidecimal digits include 0123456789abcdefABCDEF, so I can\
1281 \ only recognize things like this:"
1282 , D.indent 4 $ D.vcat [ "0x2B", "0x002B", "0x00ffb3" ]
1286 NumberNoLeadingZero ->
1287 Report.Report "LEADING ZEROS" region [] $
1288 Report.toCodeSnippet source region Nothing
1290 D.reflow $
1291 "I do not accept numbers with leading zeros:"
1293 D.stack
1294 [ D.reflow $
1295 "Just delete the leading zeros and it should work!"
1296 , D.toSimpleNote $
1297 "Some languages let you to specify octal numbers by adding a leading zero.\
1298 \ So in C, writing 0111 is the same as writing 73. Some people are used to\
1299 \ that, but others probably want it to equal 111. Either path is going to\
1300 \ surprise people from certain backgrounds, so Elm tries to avoid this whole\
1301 \ situation."
1306toOperatorReport :: Code.Source -> Context -> Operator -> Row -> Col -> Report.Report
1307toOperatorReport source context operator row col =
1308 case operator of
1309 OpDot ->
1310 let
1311 region = toRegion row col
1312 in
1313 Report.Report "UNEXPECTED SYMBOL" region [] $
1314 Report.toCodeSnippet source region Nothing
1316 "I was not expecting this dot:"
1318 D.reflow $
1319 "Dots are for record access and decimal points, so\
1320 \ they cannot float around on their own. Maybe\
1321 \ there is some extra whitespace?"
1324 OpPipe ->
1325 let
1326 region = toRegion row col
1327 in
1328 Report.Report "UNEXPECTED SYMBOL" region [] $
1329 Report.toCodeSnippet source region Nothing
1331 D.reflow $
1332 "I was not expecting this vertical bar:"
1334 D.reflow $
1335 "Vertical bars should only appear in custom type declarations. Maybe you want || instead?"
1338 OpArrow ->
1339 let
1340 region = toWiderRegion row col 2
1341 in
1342 Report.Report "UNEXPECTED ARROW" region [] $
1343 Report.toCodeSnippet source region Nothing $
1344 if error "TODO inCase" then
1346 D.reflow $
1347 "I was not expecting to see an arrow here:"
1349 D.stack
1351 D.reflow $
1352 "I think I am parsing a `case` expression right now, so it makes sense to\
1353 \ see arrows around here. This one is confusing me though!"
1355 D.toSimpleHint $
1356 "I may be getting confused by the indentation. Every pattern in a `case` must be\
1357 \ exactly aligned (with exactly the same amount of indentation) so maybe this arrow\
1358 \ appears after the next `case` pattern (correctly!) but the pattern itself is\
1359 \ indented too far?"
1363 else
1365 D.reflow $
1366 "I was not expecting an arrow here:"
1368 D.reflow $
1369 "Arrows should only appear in `case` expressions and anonymous functions. Maybe\
1370 \ you want > or >= instead?"
1373 OpEquals ->
1374 let
1375 region = toRegion row col
1376 name = getDefName context
1377 in
1378 Report.Report "UNEXPECTED EQUALS" region [] $
1379 Report.toCodeSnippet source region Nothing
1381 D.reflow $
1382 "I was not expecting to see this equals sign:"
1384 D.stack
1386 D.reflow "Maybe you want == instead? To check if two values are equal?"
1388 D.toSimpleNote $
1389 if isWithin NRecord context then
1390 "Records look like { x = 3, y = 4 } with the equals sign right\
1391 \ after the field name. So maybe you forgot a comma?"
1392 else
1393 "I may be getting confused by your indentation. Is this supposed to be part of\
1394 \ a definition AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
1395 \ the problem may be a bit before the equals sign. I need all definitions to\
1396 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
1397 \ this new definition is indented a bit too much."
1401 OpHasType ->
1402 let
1403 region = toRegion row col
1404 name = getDefName context
1405 in
1406 Report.Report "UNEXPECTED SYMBOL" region [] $
1407 Report.toCodeSnippet source region Nothing $
1409 D.reflow $
1410 "I was not expecting to run into the \"has type\" symbol here:"
1412 D.stack
1414 D.fillSep
1415 ["Maybe","you","want",D.green "::","instead?"
1416 ,"To","put","something","on","the","front","of","a","list?"
1418 , D.toSimpleNote $
1419 "The single colon is reserved for type annotations and record types, but I think\
1420 \ I am parsing the definition of `" ++ Name.toChars name ++ "` right now."
1422 D.toSimpleNote $
1423 "I may be getting confused by your indentation. Is this supposed to be part of\
1424 \ a type annotation AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
1425 \ the problem may be a bit before the \"has type\" symbol. I need all definitions to\
1426 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
1427 \ this new definition is indented a bit too much."
1433-- IF
1436toIfReport :: Code.Source -> Context -> If -> Row -> Col -> Report.Report
1437toIfReport source context if_ startRow startCol =
1438 case if_ of
1439 IfSpace space row col ->
1440 toSpaceReport source space row col
1442 IfThen row col ->
1443 let
1444 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1445 region = toRegion row col
1446 in
1447 Report.Report "UNFINISHED IF" region [] $
1448 Report.toCodeSnippet source surroundings (Just region)
1450 D.reflow $
1451 "I was expecting to see more of this `if` expression, but I got stuck here:"
1453 D.fillSep $
1454 ["I","was","expecting","to","see","the",D.green "then","keyword","next."
1458 IfElse row col ->
1459 let
1460 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1461 region = toRegion row col
1462 in
1463 Report.Report "UNFINISHED IF" region [] $
1464 Report.toCodeSnippet source surroundings (Just region)
1466 D.reflow $
1467 "I was expecting to see more of this `if` expression, but I got stuck here:"
1469 D.fillSep $
1470 ["I","was","expecting","to","see","the",D.green "else","keyword","next."
1474 IfElseBranchStart 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 IF" region [] $
1480 Report.toCodeSnippet source surroundings (Just region)
1482 D.reflow $
1483 "I just saw the start of an `else` branch, but then I got stuck here:"
1485 D.reflow $
1486 "I was expecting to see an expression next. Maybe it is not filled in yet?"
1489 IfCondition expr row col ->
1490 toExprReport source (InNode NCond startRow startCol context) expr row col
1492 IfThenBranch expr row col ->
1493 toExprReport source (InNode NThen startRow startCol context) expr row col
1495 IfElseBranch expr row col ->
1496 toExprReport source (InNode NElse startRow startCol context) expr row col
1498 IfIndentCondition row col ->
1499 let
1500 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1501 region = toRegion row col
1502 in
1503 Report.Report "UNFINISHED IF" region [] $
1504 Report.toCodeSnippet source surroundings (Just region)
1506 D.reflow $
1507 "I was expecting to see more of this `if` expression, but I got stuck here:"
1509 D.stack
1510 [ D.fillSep $
1511 ["I","was","expecting","to","see","an","expression","like",D.dullyellow "x < 0"
1512 ,"that","evaluates","to","True","or","False."
1514 , D.toSimpleNote $
1515 "I can be confused by indentation. Maybe something is not indented enough?"
1519 IfIndentThen row col ->
1520 let
1521 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1522 region = toRegion row col
1523 in
1524 Report.Report "UNFINISHED IF" region [] $
1525 Report.toCodeSnippet source surroundings (Just region)
1527 D.reflow $
1528 "I was expecting to see more of this `if` expression, but I got stuck here:"
1530 D.stack
1531 [ D.fillSep $
1532 ["I","was","expecting","to","see","the",D.green "then","keyword","next."
1534 , D.toSimpleNote $
1535 "I can be confused by indentation. Maybe something is not indented enough?"
1539 IfIndentThenBranch row col ->
1540 let
1541 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1542 region = toRegion row col
1543 in
1544 Report.Report "UNFINISHED IF" region [] $
1545 Report.toCodeSnippet source surroundings (Just region)
1547 D.reflow $
1548 "I got stuck after the start of this `then` branch:"
1550 D.stack
1551 [ D.reflow $
1552 "I was expecting to see an expression next. Maybe it is not filled in yet?"
1553 , D.toSimpleNote $
1554 "I can be confused by indentation, so if the `then` branch is already\
1555 \ present, it may not be indented enough for me to recognize it."
1559 IfIndentElseBranch row col ->
1560 let
1561 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1562 region = toRegion row col
1563 in
1564 Report.Report "UNFINISHED IF" region [] $
1565 Report.toCodeSnippet source surroundings (Just region)
1567 D.reflow $
1568 "I got stuck after the start of this `else` branch:"
1570 D.stack
1571 [ D.reflow $
1572 "I was expecting to see an expression next. Maybe it is not filled in yet?"
1573 , D.toSimpleNote $
1574 "I can be confused by indentation, so if the `else` branch is already\
1575 \ present, it may not be indented enough for me to recognize it."
1579 IfIndentElse row col ->
1580 let
1581 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1582 region = toRegion row col
1583 in
1584 Report.Report "UNFINISHED IF" region [] $
1585 Report.toCodeSnippet source surroundings (Just region)
1587 D.reflow $
1588 "I was expecting to see an `else` branch after this:"
1590 D.stack
1591 [ D.reflow $
1592 "I know what to do when the condition is `True`, but not when it is `False`."
1593 , D.fillSep
1594 ["Add","an",D.green "else","branch","to","handle","that","scenario!"]
1600-- RECORD
1603toRecordReport :: Code.Source -> Context -> Record -> Row -> Col -> Report.Report
1604toRecordReport source context record startRow startCol =
1605 case record of
1606 RecordOpen row col ->
1607 let
1608 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1609 region = toRegion row col
1610 in
1611 Report.Report "UNFINISHED PARENTHESES" region [] $
1612 Report.toCodeSnippet source surroundings (Just region)
1614 D.reflow $
1615 "I was expecting to see a closing curly brace next, but I got stuck here:"
1617 D.stack
1618 [ D.fillSep ["Try","adding","a",D.dullyellow "}","to","see","if","that","helps?"]
1619 , D.toSimpleNote $
1620 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
1621 \ unexpectedly. So there may be some other syntax trouble (like an extra\
1622 \ parenthesis?) that is confusing me."
1626 RecordEnd row col ->
1627 let
1628 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1629 region = toRegion row col
1630 in
1631 Report.Report "UNFINISHED PARENTHESES" region [] $
1632 Report.toCodeSnippet source surroundings (Just region)
1634 D.reflow $
1635 "I was expecting to see a closing curly brace next, but I got stuck here:"
1637 D.stack
1638 [ D.fillSep ["Try","adding","a",D.dullyellow "}","to","see","if","that","helps?"]
1639 , D.toSimpleNote $
1640 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
1641 \ unexpectedly. So there may be some other syntax trouble (like an extra\
1642 \ parenthesis?) that is confusing me."
1646 RecordField 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 RECORD" region [] $
1652 Report.toCodeSnippet source surroundings (Just region)
1654 D.reflow $
1655 "I am partway through parsing a record, but I got stuck after that last comma:"
1657 addNoteForRecordError $
1658 D.reflow $
1659 "Trailing commas are not allowed in records, so I was expecting to see another\
1660 \ record field defined next. If you are done defining the record, the fix may\
1661 \ be to delete that last comma?"
1664 RecordEquals 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 RECORD" region [] $
1670 Report.toCodeSnippet source surroundings (Just region)
1672 D.reflow $
1673 "I am partway through parsing a record, but I got stuck here:"
1675 addNoteForRecordError $
1676 D.fillSep $
1677 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
1678 ,"an","equals","sign","next.","So","try","putting","an",D.green "=","sign","here?"
1682 RecordExpr expr row col ->
1683 toExprReport source (InNode NRecord startRow startCol context) expr row col
1685 RecordSpace space row col ->
1686 toSpaceReport source space row col
1688 RecordIndentOpen row col ->
1689 let
1690 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1691 region = toRegion row col
1692 in
1693 Report.Report "UNFINISHED RECORD" region [] $
1694 Report.toCodeSnippet source surroundings (Just region)
1696 D.reflow $
1697 "I just saw the opening curly brace of a record, but then I got stuck here:"
1699 addNoteForRecordIndentError $
1700 D.fillSep $
1701 ["I","am","expecting","a","record","like",D.dullyellow "{ x = 3, y = 4 }","here."
1702 ,"Try","defining","some","fields","of","your","own?"
1706 RecordIndentEnd row col ->
1707 let
1708 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1709 region = toRegion row col
1710 in
1711 Report.Report "UNFINISHED RECORD" region [] $
1712 Report.toCodeSnippet source surroundings (Just region)
1714 D.reflow $
1715 "I was expecting to see a closing curly brace next:"
1717 addNoteForRecordIndentError $
1718 D.fillSep $
1719 ["Try","putting","an",D.green "}","and","see","if","that","helps?"
1723 RecordIndentField row col ->
1724 let
1725 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1726 region = toRegion row col
1727 in
1728 Report.Report "UNFINISHED RECORD" region [] $
1729 Report.toCodeSnippet source surroundings (Just region)
1731 D.reflow $
1732 "I am partway through parsing a record, but I got stuck after that last comma:"
1734 addNoteForRecordError $
1735 D.reflow $
1736 "Trailing commas are not allowed in records, so the fix may be to\
1737 \ delete that last comma? Or maybe you were in the middle of defining\
1738 \ an additional field?"
1741 RecordIndentEquals row col ->
1742 let
1743 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1744 region = toRegion row col
1745 in
1746 Report.Report "UNFINISHED RECORD" region [] $
1747 Report.toCodeSnippet source surroundings (Just region)
1749 D.reflow $
1750 "I am partway through parsing a record. I just saw a record\
1751 \ field, so I was expecting to see an equals sign next:"
1753 addNoteForRecordIndentError $
1754 D.fillSep $
1755 ["Try","putting","an",D.green "=","followed","by","an","expression?"
1759 RecordIndentExpr row col ->
1760 let
1761 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1762 region = toRegion row col
1763 in
1764 Report.Report "UNFINISHED RECORD" region [] $
1765 Report.toCodeSnippet source surroundings (Just region)
1767 D.reflow $
1768 "I am partway through parsing a record, and I was expecting to run into an expression next:"
1770 addNoteForRecordIndentError $
1771 D.fillSep $
1772 ["Try","putting","something,","like"
1773 ,D.dullyellow "42","or",D.dullyellow"\"hello\"","for","now?"
1778addNoteForRecordError :: D.Doc -> D.Doc
1779addNoteForRecordError normalRecommendation =
1780 D.stack $
1781 normalRecommendation
1783 [ D.toSimpleNote
1784 "If you are trying to define a record across multiple lines, I recommend using this format:"
1785 , D.indent 4 $ D.vcat $
1786 [ "{ name = \"Alice\""
1787 , ", age = 42"
1788 , ", height = 1.75"
1789 , "}"
1791 , D.reflow $
1792 "Notice that nothing comes directly after a newline. Each line starts with some spaces. I\
1793 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
1794 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
1798addNoteForRecordIndentError :: D.Doc -> D.Doc
1799addNoteForRecordIndentError normalRecommendation =
1800 D.stack $
1801 normalRecommendation
1803 [ D.toSimpleNote
1804 "I may be confused by indentation. For example, if you are trying to define\
1805 \ a record across multiple lines, I recommend using this format:"
1806 , D.indent 4 $ D.vcat $
1807 [ "[ \"Alice\""
1808 , ", \"Bob\""
1809 , ", \"Chuck\""
1810 , "]"
1812 , D.reflow $
1813 "Notice that nothing comes directly after a newline. Each line starts with some spaces. I\
1814 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
1815 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
1820-- TUPLE
1823toTupleReport :: Code.Source -> Context -> Tuple -> Row -> Col -> Report.Report
1824toTupleReport source context tuple startRow startCol =
1825 case tuple of
1826 TupleExpr expr row col ->
1827 toExprReport source (InNode NParens startRow startCol context) expr row col
1829 TupleSpace space row col ->
1830 toSpaceReport source space row col
1832 TupleEnd row col ->
1833 let
1834 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1835 region = toRegion row col
1836 in
1837 Report.Report "UNFINISHED PARENTHESES" region [] $
1838 Report.toCodeSnippet source surroundings (Just region)
1840 D.reflow $
1841 "I was expecting to see a closing parentheses next, but I got stuck here:"
1843 D.stack
1844 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
1845 , D.toSimpleNote $
1846 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
1847 \ unexpectedly. So there may be some other syntax trouble (like an extra\
1848 \ square bracket?) that is confusing me."
1852 TupleOperatorClose row col ->
1853 let
1854 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1855 region = toRegion row col
1856 in
1857 Report.Report "UNFINISHED OPERATOR FUNCTION" region [] $
1858 Report.toCodeSnippet source surroundings (Just region)
1860 D.reflow "I was expecting a closing parenthesis here:"
1862 D.stack
1863 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
1864 , D.toSimpleNote $
1865 "I think I am parsing an operator function right now, so I am expecting to see\
1866 \ something like (+) or (&&) where an operator is surrounded by parentheses with\
1867 \ no extra spaces."
1871 TupleOperatorReserved operator row col ->
1872 let
1873 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1874 region = toRegion row col
1875 in
1876 Report.Report "UNEXPECTED SYMBOL" region [] $
1877 Report.toCodeSnippet source surroundings (Just region)
1879 D.reflow $
1880 "I ran into an unexpected symbol here:"
1882 D.fillSep $
1883 case operator of
1884 OpDot -> ["Maybe","you","wanted","a","record","accessor","like",D.dullyellow ".x","or",D.dullyellow ".name","instead?"]
1885 OpPipe -> ["Try",D.dullyellow "(||)","instead?","To","turn","boolean","OR","into","a","function?"]
1886 OpArrow -> ["Maybe","you","wanted",D.dullyellow "(>)","or",D.dullyellow "(>=)","instead?"]
1887 OpEquals -> ["Try",D.dullyellow "(==)","instead?","To","make","a","function","that","checks","equality?"]
1888 OpHasType -> ["Try",D.dullyellow "(::)","instead?","To","add","values","to","the","front","of","lists?"]
1891 TupleIndentExpr1 row col ->
1892 let
1893 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1894 region = toRegion row col
1895 in
1896 Report.Report "UNFINISHED PARENTHESES" region [] $
1897 Report.toCodeSnippet source surroundings (Just region)
1899 D.reflow $
1900 "I just saw an open parenthesis, so I was expecting to see an expression next."
1902 D.stack
1903 [ D.fillSep $
1904 ["Something","like",D.dullyellow "(4 + 5)","or"
1905 ,D.dullyellow "(String.reverse \"desserts\")" <> "."
1906 ,"Anything","where","you","are","putting","parentheses","around","normal","expressions."
1908 , D.toSimpleNote $
1909 "I can get confused by indentation in cases like this, so\
1910 \ maybe you have an expression but it is not indented enough?"
1914 TupleIndentExprN row col ->
1915 let
1916 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1917 region = toRegion row col
1918 in
1919 Report.Report "UNFINISHED TUPLE" region [] $
1920 Report.toCodeSnippet source surroundings (Just region)
1922 D.reflow $
1923 "I think I am in the middle of parsing a tuple. I just saw a comma, so I was expecting to see expression next."
1925 D.stack
1926 [ D.fillSep $
1927 ["A","tuple","looks","like",D.dullyellow "(3,4)","or"
1928 ,D.dullyellow "(\"Tom\",42)" <> ","
1929 ,"so","I","think","there","is","an","expression","missing","here?"
1931 , D.toSimpleNote $
1932 "I can get confused by indentation in cases like this, so\
1933 \ maybe you have an expression but it is not indented enough?"
1937 TupleIndentEnd row col ->
1938 let
1939 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1940 region = toRegion row col
1941 in
1942 Report.Report "UNFINISHED PARENTHESES" region [] $
1943 Report.toCodeSnippet source surroundings (Just region)
1945 D.reflow $
1946 "I was expecting to see a closing parenthesis next:"
1948 D.stack
1949 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
1950 , D.toSimpleNote $
1951 "I can get confused by indentation in cases like this, so\
1952 \ maybe you have a closing parenthesis but it is not indented enough?"
1957toListReport :: Code.Source -> Context -> List -> Row -> Col -> Report.Report
1958toListReport source context list startRow startCol =
1959 case list of
1960 ListSpace space row col ->
1961 toSpaceReport source space row col
1963 ListOpen row col ->
1964 let
1965 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1966 region = toRegion row col
1967 in
1968 Report.Report "UNFINISHED LIST" region [] $
1969 Report.toCodeSnippet source surroundings (Just region)
1971 D.reflow $
1972 "I was expecting to see a closing square bracket next, but I got stuck here:"
1974 D.stack
1975 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
1976 , D.toSimpleNote $
1977 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
1978 \ unexpectedly. So there may be some other syntax trouble (like an extra\
1979 \ parenthesis?) that is confusing me."
1983 ListExpr expr row col ->
1984 case expr of
1985 Start r c ->
1986 let
1987 surroundings = A.Region (A.Position startRow startCol) (A.Position r c)
1988 region = toRegion r c
1989 in
1990 Report.Report "UNFINISHED LIST" region [] $
1991 Report.toCodeSnippet source surroundings (Just region)
1993 D.reflow $
1994 "I was expecting to see another list entry after that last comma:"
1996 D.stack
1997 [ D.reflow $
1998 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
1999 , D.toSimpleNote
2000 "I recommend using the following format for lists that span multiple lines:"
2001 , D.indent 4 $ D.vcat $
2002 [ "[ \"Alice\""
2003 , ", \"Bob\""
2004 , ", \"Chuck\""
2005 , "]"
2007 , D.reflow $
2008 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2009 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2010 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2014 _ ->
2015 toExprReport source (InNode NList startRow startCol context) expr row col
2017 ListEnd row col ->
2018 let
2019 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2020 region = toRegion row col
2021 in
2022 Report.Report "UNFINISHED LIST" region [] $
2023 Report.toCodeSnippet source surroundings (Just region)
2025 D.reflow $
2026 "I was expecting to see a closing square bracket next, but I got stuck here:"
2028 D.stack
2029 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
2030 , D.toSimpleNote $
2031 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
2032 \ unexpectedly. So there may be some other syntax trouble (like an extra\
2033 \ parenthesis?) that is confusing me."
2037 ListIndentOpen row col ->
2038 let
2039 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2040 region = toRegion row col
2041 in
2042 Report.Report "UNFINISHED LIST" region [] $
2043 Report.toCodeSnippet source surroundings (Just region)
2045 D.reflow $
2046 "I cannot find the end of this list:"
2048 D.stack
2049 [ D.fillSep $
2050 ["You","could","change","it","to","something","like"
2051 ,D.dullyellow "[3,4,5]"
2052 ,"or","even","just"
2053 ,D.dullyellow "[]" <> "."
2054 ,"Anything","where","there","is","an","open","and","close","square","brace,"
2055 ,"and","where","the","elements","of","the","list","are","separated","by","commas."
2057 , D.toSimpleNote
2058 "I may be confused by indentation. For example, if you are trying to define\
2059 \ a list across multiple lines, I recommend using this format:"
2060 , D.indent 4 $ D.vcat $
2061 [ "[ \"Alice\""
2062 , ", \"Bob\""
2063 , ", \"Chuck\""
2064 , "]"
2066 , D.reflow $
2067 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2068 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2069 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2073 ListIndentEnd row col ->
2074 let
2075 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2076 region = toRegion row col
2077 in
2078 Report.Report "UNFINISHED LIST" region [] $
2079 Report.toCodeSnippet source surroundings (Just region)
2081 D.reflow $
2082 "I cannot find the end of this list:"
2084 D.stack
2085 [ D.fillSep $
2086 ["You","can","just","add","a","closing",D.dullyellow "]"
2087 ,"right","here,","and","I","will","be","all","set!"
2089 , D.toSimpleNote
2090 "I may be confused by indentation. For example, if you are trying to define\
2091 \ a list across multiple lines, I recommend using this format:"
2092 , D.indent 4 $ D.vcat $
2093 [ "[ \"Alice\""
2094 , ", \"Bob\""
2095 , ", \"Chuck\""
2096 , "]"
2098 , D.reflow $
2099 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2100 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2101 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2105 ListIndentExpr row col ->
2106 let
2107 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2108 region = toRegion row col
2109 in
2110 Report.Report "UNFINISHED LIST" region [] $
2111 Report.toCodeSnippet source surroundings (Just region)
2113 D.reflow $
2114 "I was expecting to see another list entry after this comma:"
2116 D.stack
2117 [ D.reflow $
2118 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
2119 , D.toSimpleNote
2120 "I recommend using the following format for lists that span multiple lines:"
2121 , D.indent 4 $ D.vcat $
2122 [ "[ \"Alice\""
2123 , ", \"Bob\""
2124 , ", \"Chuck\""
2125 , "]"
2127 , D.reflow $
2128 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2129 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2130 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2135toFuncReport :: Code.Source -> Context -> Func -> Row -> Col -> Report.Report
2136toFuncReport source context func startRow startCol =
2137 case func of
2138 FuncSpace space row col ->
2139 toSpaceReport source space row col
2141 FuncArg pattern row col ->
2142 error "TODO FuncArg" pattern row col
2144 FuncBody expr row col ->
2145 toExprReport source (InNode NFunc startRow startCol context) expr row col
2147 FuncArrow row col ->
2148 let
2149 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2150 region = toRegion row col
2151 in
2152 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
2153 Report.toCodeSnippet source surroundings (Just region)
2155 D.reflow $
2156 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
2158 D.fillSep $
2159 ["The","syntax","for","anonymous","functions","is"
2160 ,D.dullyellow "(\\x -> x + 1)"
2161 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
2165 FuncIndentArg row col ->
2166 let
2167 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2168 region = toRegion row col
2169 in
2170 Report.Report "MISSING ARGUMENT" region [] $
2171 Report.toCodeSnippet source surroundings (Just region)
2173 D.reflow $
2174 "I just saw the beginning of an anonymous function, so I was expecting to see an argument next:"
2176 D.stack
2177 [ D.fillSep
2178 ["Something","like",D.dullyellow"x","or",D.dullyellow "name" <> "."
2179 ,"Anything","that","starts","with","a","lower","case","letter!"
2181 , D.toSimpleNote $
2182 "The syntax for anonymous functions is (\\x -> x + 1) where the backslash\
2183 \ is meant to look a bit like a lambda if you squint. This visual pun seemed\
2184 \ like a better idea at the time!"
2188 FuncIndentArrow row col ->
2189 let
2190 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2191 region = toRegion row col
2192 in
2193 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
2194 Report.toCodeSnippet source surroundings (Just region)
2196 D.reflow $
2197 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
2199 D.stack
2200 [ D.fillSep $
2201 ["The","syntax","for","anonymous","functions","is"
2202 ,D.dullyellow "(\\x -> x + 1)"
2203 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
2205 , D.toSimpleNote $
2206 "It is possible that I am confused about indetation! I generally recommend\
2207 \ switching to named functions if the definition cannot fit inline nicely, so\
2208 \ either (1) try to fit the whole anonymous function on one line or (2) break\
2209 \ the whole thing out into a named function. Things tend to be clearer that way!"
2213 FuncIndentBody row col ->
2214 let
2215 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2216 region = toRegion row col
2217 in
2218 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
2219 Report.toCodeSnippet source surroundings (Just region)
2221 D.reflow $
2222 "I was expecting to see the body of your anonymous function next:"
2224 D.stack
2225 [ D.fillSep $
2226 ["The","syntax","for","anonymous","functions","is"
2227 ,D.dullyellow "(\\x -> x + 1)"
2228 ,"so","I","am","missing","all","the","stuff","after","the","arrow!"
2230 , D.toSimpleNote $
2231 "It is possible that I am confused about indetation! I generally recommend\
2232 \ switching to named functions if the definition cannot fit inline nicely, so\
2233 \ either (1) try to fit the whole anonymous function on one line or (2) break\
2234 \ the whole thing out into a named function. Things tend to be clearer that way!"
2242 case err of
2243 CommentOnNothing region ->
2244 Report.Report "STRAY COMMENT" region [] $
2245 Report.toCodeSnippet source region Nothing
2247 "This documentation comment is not followed by anything."
2249 D.reflow $
2250 "All documentation comments need to be right above the declaration they\
2251 \ describe. Maybe some code got deleted or commented out by accident? Or\
2252 \ maybe this comment is here by accident?"
2255 UnexpectedPort region ->
2256 Report.Report "UNEXPECTED PORTS" region [] $
2257 Report.toCodeSnippet source region Nothing
2259 D.reflow $
2260 "You are declaring ports in a normal module."
2262 D.stack
2263 [ D.fillSep
2264 ["Switch","this","to","say",D.green "port module","instead,"
2265 ,"marking","that","this","module","contains","port","declarations."
2267 , D.link "Note"
2268 "Ports are not a traditional FFI for calling JS functions directly. They need a different mindset! Read"
2269 "ports"
2270 "to learn the syntax and how to use it effectively."
2274 NoPorts region ->
2275 Report.Report "NO PORTS" region [] $
2276 Report.toCodeSnippet source region Nothing
2278 D.reflow $
2279 "This module does not declare any ports, but it says it will:"
2281 D.fillSep
2282 ["Switch","this","to",D.green "module"
2283 ,"and","you","should","be","all","set!"
2287 ParseError row col context expectation ->
2288 let
2289 pos = A.Position row col
2290 region = A.Region pos pos
2291 in
2292 case expectation of
2294 DocComment ->
2295 Report.Report "EXPECTING DOC COMMENT" region [] $
2296 Report.toCodeSnippet source region Nothing
2298 D.reflow $
2299 "I was expecting a doc comment here:"
2301 D.reflowLink
2302 "Check out" "TODO" "for examples of doc comments."
2305 -- Parse.Number
2307 Precedence ->
2308 Report.Report "EXPECTING PRECEDENCE" region [] $
2309 Report.toCodeSnippet source region Nothing
2311 D.reflow $
2312 "I was expecting the precedence here:"
2314 D.reflow $
2315 "I need a single digit between 0 and 9 inclusive."
2318 Wildcard ->
2319 Report.Report "EXPECTING A WILDCARD" region [] $
2320 Report.toCodeSnippet source region Nothing
2322 D.reflow $
2323 "I was expecting a _ here:"
2325 D.reflow $
2326 "An underscore indicates that “I do not care about this value” and is\
2327 \ called a wildcard pattern because it will match with any type of values."
2330 WildcardNotVar startCol endCol ->
2331 let
2332 badRegion =
2333 A.Region (A.Position row startCol) (A.Position row endCol)
2334 in
2335 Report.Report "INVALID PATTERN" badRegion [] $
2336 Report.toCodeSnippet source badRegion Nothing
2338 D.reflow $
2339 "I was expecting to see an underscore without any additional characters:"
2341 D.reflow $
2342 "There are two options. Either (1) remove the extra characters and ignore the\
2343 \ value or (2) remove the starting underscore to give the value a normal name."
2346 -- Parse.Pattern
2348 FloatInPattern ->
2349 Report.Report "INVALID PATTERN" region [] $
2350 Report.toCodeSnippet source region Nothing
2352 D.reflow $
2353 "I cannot pattern match with floating point numbers:"
2355 D.reflow $
2356 "Equality on floats can be unreliable, so you usually want to check that they\
2357 \ are nearby with some sort of (abs (actual - expected) < 0.001) check."
2360 -- Parse.Expression
2362 MatchingName name ->
2363 Report.Report "EXPECTING A DEFINITION" region [] $
2364 Report.toCodeSnippet source region Nothing
2366 D.reflow $
2367 "I just saw the type annotation for `" ++ Name.toChars name
2368 ++ "` so I was expecting to see its definition here:"
2370 D.reflow $
2371 "Type annotations always appear directly above the relevant\
2372 \ definition, without anything else (even doc comments) in between."
2378 TypeWithBadDefinition region annName defName ->
2379 Report.Report "ANNOTATION MISMATCH" region [] $
2380 Report.toCodeSnippet source region Nothing
2382 D.reflow $
2383 "I see a `" <> Name.toChars annName
2384 <> "` annotation, but it is followed by a `"
2385 <> Name.toChars defName <> "` definition."
2387 D.fillSep
2388 ["The","annotation","and","definition","names","must","match!"
2389 ,"Is","there","a","typo","between"
2390 , D.dullyellow (D.fromName annName)
2391 ,"and"
2392 , D.dullyellow (D.fromName defName) <> "?"