on 46abd86 help sign in
2452 lines 79 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 | ImportIndentAs Row Col
109 | ImportIndentAlias Row Col
110 | ImportIndentExposing Row Col
111 | ImportIndentExposingList Row Col
112 --
113 | Infix Row Col
114 --
115 | Declarations Decl Row Col
118data Exposing
119 = ExposingSpace Space Row Col
120 | ExposingStart Row Col
121 | ExposingValue Row Col
122 | ExposingOperator Row Col
123 | ExposingOperatorReserved Operator Row Col
124 | ExposingOperatorRightParen Row Col
125 | ExposingEnd Row Col
126 --
127 | ExposingTypePrivacy Row Col
128 | ExposingTypePrivacyDots Row Col
129 | ExposingTypePrivacyEnd Row Col
130 --
131 | ExposingIndentEnd Row Col
132 | ExposingIndentValue Row Col
133 | ExposingIndentValueEnd Row Col
134 | ExposingIndentTypePrivacy Row Col
135 | ExposingIndentTypePrivacyDots Row Col
136 | ExposingIndentTypePrivacyEnd Row Col
140-- DECLARATIONS
143data Decl
144 = DeclStart Row Col
145 | DeclSpace Space Row Col
146 --
147 | Port Port Row Col
148 | DeclType DeclType Row Col
149 | DeclDef Name.Name DeclDef Row Col
150 --
151 | DeclFreshLineStart Row Col
152 | DeclFreshLineAfterDocComment Row Col
155data DeclDef
156 = DeclDefSpace Space Row Col
157 | DeclDefEquals Row Col
158 | DeclDefType Type Row Col
159 | DeclDefArg Pattern Row Col
160 | DeclDefBody Expr Row Col
161 | DeclDefNameRepeat Row Col
162 | DeclDefNameMatch Name.Name Row Col
163 --
164 | DeclDefIndentType Row Col
165 | DeclDefIndentEquals Row Col
166 | DeclDefIndentBody Row Col
167 --
168 | DeclDefFreshLineAfterType Row Col
171data Port
172 = PortSpace Space Row Col
173 | PortName Row Col
174 | PortColon Row Col
175 | PortType Type Row Col
176 | PortIndentName Row Col
177 | PortIndentColon Row Col
178 | PortIndentType Row Col
182-- TYPE DECLARATIONS
185data DeclType
186 = DT_Space Space Row Col
187 | DT_Name Row Col
188 | DT_Alias TypeAlias Row Col
189 | DT_Union CustomType Row Col
190 --
191 | DT_IndentName Row Col
194data TypeAlias
195 = AliasSpace Space Row Col
196 | AliasName Row Col
197 | AliasEquals Row Col
198 | AliasBody Type Row Col
199 --
200 | AliasIndentEquals Row Col
201 | AliasIndentBody Row Col
204data CustomType
205 = CT_Space Space Row Col
206 | CT_Name Row Col
207 | CT_Equals Row Col
208 | CT_Bar Row Col
209 | CT_Variant Row Col
210 | CT_VariantArg Type Row Col
211 --
212 | CT_IndentEquals Row Col
213 | CT_IndentBar Row Col
214 | CT_IndentAfterBar Row Col
215 | CT_IndentAfterEquals Row Col
219-- EXPRESSIONS
222data Expr
223 = Let Let Row Col
224 | Case Case Row Col
225 | If If Row Col
226 | List List Row Col
227 | Record Record Row Col
228 | Tuple Tuple Row Col
229 | Func Func Row Col
230 --
231 | Dot Row Col
232 | Access Row Col
233 | OperatorRight Name.Name Row Col
234 | OperatorReserved Operator Row Col
235 --
236 | Start Row Col
237 | Char Char Row Col
238 | String String Row Col
239 | Number Number Row Col
240 | Space Space Row Col
241 | EndlessShader Row Col
242 | ShaderProblem [Char.Char] Row Col
243 | IndentOperatorRight Name.Name Row Col
244 | IndentMoreExpr Row Col
247data Record
248 = RecordOpen Row Col
249 | RecordEnd Row Col
250 | RecordField Row Col
251 | RecordEquals Row Col
252 | RecordExpr Expr Row Col
253 | RecordSpace Space Row Col
254 --
255 | RecordIndentOpen Row Col
256 | RecordIndentEnd Row Col
257 | RecordIndentField Row Col
258 | RecordIndentEquals Row Col
259 | RecordIndentExpr Row Col
262data Tuple
263 = TupleExpr Expr Row Col
264 | TupleSpace Space Row Col
265 | TupleEnd Row Col
266 | TupleOperatorClose Row Col
267 | TupleOperatorReserved Operator Row Col
268 --
269 | TupleIndentExpr1 Row Col
270 | TupleIndentExprN Row Col
271 | TupleIndentEnd Row Col
274data List
275 = ListSpace Space Row Col
276 | ListOpen Row Col
277 | ListExpr Expr Row Col
278 | ListEnd Row Col
279 --
280 | ListIndentOpen Row Col
281 | ListIndentEnd Row Col
282 | ListIndentExpr Row Col
285data Func
286 = FuncSpace Space Row Col
287 | FuncArg Pattern Row Col
288 | FuncBody Expr Row Col
289 | FuncArrow Row Col
290 --
291 | FuncIndentArg Row Col
292 | FuncIndentArrow Row Col
293 | FuncIndentBody Row Col
296data Case
297 = CaseSpace Space Row Col
298 | CaseOf Row Col
299 | CasePattern Pattern Row Col
300 | CaseArrow Row Col
301 | CaseExpr Expr Row Col
302 | CaseBranch Expr Row Col
303 --
304 | CaseIndentOf Row Col
305 | CaseIndentExpr Row Col
306 | CaseIndentPattern Row Col
307 | CaseIndentArrow Row Col
308 | CaseIndentBranch Row Col
309 | CasePatternAlignment Word16 Row Col
312data If
313 = IfSpace Space Row Col
314 | IfThen Row Col
315 | IfElse Row Col
316 | IfElseBranchStart Row Col
317 --
318 | IfCondition Expr Row Col
319 | IfThenBranch Expr Row Col
320 | IfElseBranch Expr Row Col
321 --
322 | IfIndentCondition Row Col
323 | IfIndentThen Row Col
324 | IfIndentThenBranch Row Col
325 | IfIndentElseBranch Row Col
326 | IfIndentElse Row Col
329data Let
330 = LetSpace Space Row Col
331 | LetIn Row Col
332 | LetDefAlignment Word16 Row Col
333 | LetDefName Row Col
334 | LetDef Name.Name Def Row Col
335 | LetDestruct Destruct Row Col
336 | LetBody Expr Row Col
337 | LetIndentDef Row Col
338 | LetIndentIn Row Col
339 | LetIndentBody Row Col
342data Def
343 = DefSpace Space Row Col
344 | DefType Type Row Col
345 | DefNameRepeat Name.Name Row Col
346 | DefNameMatch Name.Name Name.Name Row Col
347 | DefArg Pattern Row Col
348 | DefEquals Row Col
349 | DefBody Expr Row Col
350 | DefIndentEquals Row Col
351 | DefIndentType Row Col
352 | DefIndentBody Row Col
353 | DefAlignment Word16 Row Col
356data Destruct
357 = DestructSpace Space Row Col
358 | DestructPattern Pattern Row Col
359 | DestructEquals Row Col
360 | DestructBody Expr Row Col
361 | DestructIndentEquals Row Col
362 | DestructIndentBody Row Col
366-- PATTERNS
369data Pattern
370 = PRecord PRecord Row Col
371 | PTuple PTuple Row Col
372 | PList PList Row Col
373 --
374 | PStart Row Col
375 | PChar Char Row Col
376 | PString String Row Col
377 | PNumber Number Row Col
378 | PFloat Int Row Col
379 | PAlias Row Col
380 | PWildcardNotVar Int Row Col
381 | PSpace Space Row Col
382 --
383 | PIndentStart Row Col
384 | PIndentAlias Row Col
387data PRecord
388 = PRecordOpen Row Col
389 | PRecordEnd Row Col
390 | PRecordField Row Col
391 | PRecordSpace Space Row Col
392 --
393 | PRecordIndentOpen Row Col
394 | PRecordIndentEnd Row Col
395 | PRecordIndentField Row Col
398data PTuple
399 = PTupleOpen Row Col
400 | PTupleEnd Row Col
401 | PTupleExpr Pattern Row Col
402 | PTupleSpace Space Row Col
403 --
404 | PTupleIndentOpen Row Col
405 | PTupleIndentEnd Row Col
406 | PTupleIndentExpr Row Col
409data PList
410 = PListOpen Row Col
411 | PListEnd Row Col
412 | PListExpr Pattern Row Col
413 | PListSpace Space Row Col
414 --
415 | PListIndentOpen Row Col
416 | PListIndentEnd Row Col
417 | PListIndentExpr Row Col
421-- TYPES
424data Type
425 = TRecord TRecord Row Col
426 | TTuple TTuple Row Col
427 | TVariant Row Col
428 | TArrow Row Col
429 --
430 | TStart Row Col
431 | TSpace Space Row Col
432 --
433 | TIndentStart Row Col
436data TRecord
437 = TRecordOpen Row Col
438 | TRecordEnd Row Col
439 --
440 | TRecordField Row Col
441 | TRecordColon Row Col
442 | TRecordType Type Row Col
443 --
444 | TRecordSpace Space Row Col
445 --
446 | TRecordIndentOpen Row Col
447 | TRecordIndentField Row Col
448 | TRecordIndentColon Row Col
449 | TRecordIndentType Row Col
450 | TRecordIndentEnd Row Col
453data TTuple
454 = TTupleOpen Row Col
455 | TTupleEnd Row Col
456 | TTupleType Type Row Col
457 | TTupleSpace Space Row Col
458 --
459 | TTupleIndentOpen Row Col
460 | TTupleIndentType Row Col
461 | TTupleIndentEnd Row Col
465-- LITERALS
468data Char
469 = CharEndless
470 | CharEscape Escape
471 | CharNotString Word16
474data String
475 = StringEndless_Single
476 | StringEndless_Multi
477 | StringEscape Escape
480data Escape
481 = EscapeUnknown
482 | BadUnicodeFormat Word16
483 | BadUnicodeCode Word16
484 | BadUnicodeLength Word16 Int Int
487data Number
488 = NumberEnd
489 | NumberDot Int
490 | NumberHexDigit
491 | NumberNoLeadingZero
495-- MISC
498data Space
499 = HasTab
500 | EndlessMultiComment
503data Operator
504 = OpDot
505 | OpPipe
506 | OpArrow
507 | OpEquals
508 | OpHasType
512-- TO REPORT
515toReport :: Code.Source -> Error -> Report.Report
516toReport source err =
517 case err of
518 ModuleNameUnspecified name ->
519 let
520 region = toRegion 1 1
521 in
522 Report.Report "MODULE NAME MISSING" region [] $
523 D.stack
524 [ D.reflow $
525 "I need the module name to be declared at the top of this file, like this:"
526 , D.indent 4 $ D.green $ D.fromChars $
527 "module " ++ ModuleName.toChars name ++ " exposing (..)"
528 , D.reflow $
529 "Try adding that as the first line of your file!"
530 , D.toSimpleNote $
531 "It is best to replace (..) with an explicit list of types and\
532 \ functions you want to expose. When you know a value is only used\
533 \ within this module, you can refactor without worrying about uses\
534 \ elsewhere. Limiting exposed values can also speed up compilation\
535 \ because I can skip a bunch of work if I see that the exposed API\
536 \ has not changed."
537 ]
539 ModuleNameMismatch expectedName (A.At region actualName) ->
540 Report.Report "MODULE NAME MISMATCH" region [ModuleName.toChars expectedName] $
541 Report.toCodeSnippet source region Nothing
542 (
543 "It looks like this module name is out of sync:"
544 ,
545 D.stack
546 [ D.reflow $
547 "I need it to match the file path, so I was expecting it to see `"
548 ++ ModuleName.toChars expectedName
549 ++ "` here. Make the following change, and you should be all set!"
550 , D.indent 4 $
551 D.dullyellow (D.fromName actualName) <> " -> " <> D.green (D.fromName expectedName)
552 , D.toSimpleNote $
553 "I require that module names correspond to file paths. This makes it much\
554 \ easier to explore unfamiliar codebases! So if you want to keep the current\
555 \ module name, try renaming the file instead."
556 ]
557 )
559 UnexpectedPort region ->
560 error "TODO UnexpectedPort" region
562 NoPorts region ->
563 error "TODO NoPorts" region
565 ParseError modul ->
566 toParseErrorReport source modul
569toParseErrorReport :: Code.Source -> Module -> Report.Report
570toParseErrorReport source modul =
571 case modul of
572 ModuleSpace space row col ->
573 toSpaceReport source space row col
575 ModuleEndOfFile row col ->
576 let
577 region = toRegion row col
578 in
579 Report.Report "EXPECTING END OF FILE" region [] $
580 Report.toCodeSnippet source region Nothing
581 (
582 D.reflow $
583 "I was not expecting to see anything more here:"
584 ,
585 D.reflow $
586 "I think I have read all the declarations in the file and that there is nothing\
587 \ left to see, so whatever I am running into is confusing me a lot!"
588 )
590 Module row col ->
591 error "TODO Module" row col
593 ModuleName row col ->
594 error "TODO ModuleName" row col
596 ModuleExposing row col ->
597 error "TODO ModuleExposing" row col
599 ModuleExposingList exposing row col ->
600 error "TODO ModuleExposingList" exposing row col
602 --
603 ModulePortModule row col ->
604 error "TODO ModulePortModule" row col
606 ModuleEffect row col ->
607 error "TODO ModuleEffect" row col
609 ModuleIndentStart row col ->
610 error "TODO ModuleIndentStart" row col
612 ModuleIndentName row col ->
613 error "TODO ModuleIndentName" row col
615 ModuleIndentExposing row col ->
616 error "TODO ModuleIndentExposing" row col
618 ModuleIndentExposingList row col ->
619 error "TODO ModuleIndentExposingList" row col
621 ModuleIndentPortModule row col ->
622 error "TODO ModuleIndentPortModule" row col
624 FreshLineModuleStart row col ->
625 error "TODO FreshLineModuleStart" row col
627 FreshLineAfterModuleLine row col ->
628 error "TODO FreshLineAfterModuleLine" row col
630 FreshLineAfterDocComment row col ->
631 error "TODO FreshLineAfterDocComment" row col
633 ImportStart row col ->
634 error "TODO ImportStart" row col
636 ImportName row col ->
637 error "TODO ImportName" row col
639 ImportAs row col ->
640 error "TODO ImportAs" row col
642 ImportAlias row col ->
643 error "TODO ImportAlias" row col
645 ImportExposing row col ->
646 error "TODO ImportExposing" row col
648 ImportExposingList exposing row col ->
649 error "TODO ImportExposingList" exposing row col
651 ImportEnd row col ->
652 error "TODO ImportEnd" row col
654 ImportIndentName row col ->
655 error "TODO ImportIndentName" row col
657 ImportIndentAs row col ->
658 error "TODO ImportIndentAs" row col
660 ImportIndentAlias row col ->
661 error "TODO ImportIndentAlias" row col
663 ImportIndentExposing row col ->
664 error "TODO ImportIndentExposing" row col
666 ImportIndentExposingList row col ->
667 error "TODO ImportIndentExposingList" row col
669 Infix row col ->
670 error "TODO Infix" row col
672 Declarations decl _ _ ->
673 toDeclarationsReport source decl
676toSpaceReport :: Code.Source -> Space -> Row -> Col -> Report.Report
677toSpaceReport source space row col =
678 case space of
679 HasTab ->
680 let
681 region = toRegion row col
682 in
683 Report.Report "NO TABS" region [] $
684 Report.toCodeSnippet source region Nothing
685 (
686 D.reflow $
687 "I ran into a tab, but tabs are not allowed in Elm files."
688 ,
689 D.reflow $
690 "Replace the tab with spaces."
691 )
693 EndlessMultiComment ->
694 let
695 region = toWiderRegion row col 2
696 in
697 Report.Report "ENDLESS COMMENT" region [] $
698 Report.toCodeSnippet source region Nothing
699 (
700 D.reflow $
701 "I cannot find the end of this multi-line comment:"
702 ,
703 D.stack -- "{-"
704 [ D.reflow "Add a -} somewhere after this to end the comment."
705 , D.toSimpleHint
706 "Multi-line comments can be nested in Elm, so {- {- -} -} is a comment\
707 \ that happens to contain another comment. Like parentheses and curly braces,\
708 \ the start and end markers must always be balanced. Maybe that is the problem?"
709 ]
710 )
713toRegion :: Row -> Col -> A.Region
714toRegion row col =
715 let
716 pos = A.Position row col
717 in
718 A.Region pos pos
721toWiderRegion :: Row -> Col -> Word16 -> A.Region
722toWiderRegion row col extra =
723 A.Region
724 (A.Position row col)
725 (A.Position row (col + extra))
728toDeclarationsReport :: Code.Source -> Decl -> Report.Report
729toDeclarationsReport source decl =
730 case decl of
731 DeclStart row col ->
732 error "TODO DeclStart" row col
734 DeclSpace space row col ->
735 toSpaceReport source space row col
737 Port port row col ->
738 error "TODO Port" port row col
740 DeclType declType row col ->
741 error "TODO DeclType" declType row col
743 DeclDef name declDef row col ->
744 toDeclDefReport source name declDef row col
746 DeclFreshLineStart row col ->
747 error "TODO DeclFreshLineStart" row col
749 DeclFreshLineAfterDocComment row col ->
750 error "TODO DeclFreshLineAfterDocComment" row col
753toDeclDefReport :: Code.Source -> Name.Name -> DeclDef -> Row -> Col -> Report.Report
754toDeclDefReport source name declDef startRow startCol =
755 case declDef of
756 DeclDefSpace space row col ->
757 toSpaceReport source space row col
759 DeclDefEquals row col ->
760 error "TODO DeclDefEquals" row col
762 DeclDefType tipe row col ->
763 error "TODO DeclDefType" tipe row col
765 DeclDefArg pattern row col ->
766 error "TODO DeclDefArg" pattern row col
768 DeclDefBody expr row col ->
769 toExprReport source (InDef name startRow startCol) expr row col
771 DeclDefNameRepeat row col ->
772 error "TODO DeclDefNameRepeat" name row col
774 DeclDefNameMatch defName row col ->
775 error "TODO DeclDefNameMatch" name defName row col
777 DeclDefIndentType row col ->
778 error "TODO DeclDefIndentType" row col
780 DeclDefIndentEquals row col ->
781 error "TODO DeclDefIndentEquals" row col
783 DeclDefIndentBody row col ->
784 error "TODO DeclDefIndentBody" row col
786 DeclDefFreshLineAfterType row col ->
787 error "TODO DeclDefFreshLineAfterType" row col
791-- CONTEXT
794data Context
795 = InNode Node Row Col Context
796 | InDef Name.Name Row Col
799data Node
800 = NRecord
801 | NParens
802 | NList
803 | NFunc
804 | NCond
805 | NThen
806 | NElse
807 deriving (Eq)
810getDefName :: Context -> Name.Name
811getDefName context =
812 case context of
813 InDef name _ _ -> name
814 InNode _ _ _ c -> getDefName c
817isWithin :: Node -> Context -> Bool
818isWithin desiredNode context =
819 case context of
820 InDef _ _ _ -> False
821 InNode actualNode _ _ _ -> desiredNode == actualNode
825-- EXPR REPORTS
828toExprReport :: Code.Source -> Context -> Expr -> Row -> Col -> Report.Report
829toExprReport source context expr startRow startCol =
830 case expr of
831 Let _ _ _ ->
832 error "TODO Let"
834 Case _ _ _ ->
835 error "TODO Case"
837 If if_ row col ->
838 toIfReport source context if_ row col
840 List list row col ->
841 toListReport source context list row col
843 Record record row col ->
844 toRecordReport source context record row col
846 Tuple tuple row col ->
847 toTupleReport source context tuple row col
849 Func func row col ->
850 toFuncReport source context func row col
852 Dot row col ->
853 let region = toRegion row col in
854 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
855 Report.toCodeSnippet source region Nothing
856 (
857 D.reflow $
858 "I was expecting to see a record accessor here:"
859 ,
860 D.fillSep
861 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
862 ,"that","accesses","a","value","from","a","record."
863 ]
864 )
866 Access row col ->
867 let region = toRegion row col in
868 Report.Report "EXPECTING RECORD ACCESSOR" region [] $
869 Report.toCodeSnippet source region Nothing
870 (
871 D.reflow $
872 "I am trying to parse a record accessor here:"
873 ,
874 D.stack
875 [
876 D.fillSep
877 ["Something","like",D.dullyellow".name","or",D.dullyellow".price"
878 ,"that","accesses","a","value","from","a","record."
879 ]
880 ,
881 D.toSimpleNote $
882 "Record field names must start with a lower case letter!"
883 ]
884 )
886 OperatorRight op row col ->
887 let region = toRegion row col in
888 Report.Report "MISSING EXPRESSION" region [] $
889 Report.toCodeSnippet source region Nothing
890 (
891 D.reflow $
892 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
893 ,
894 D.stack
895 [ D.fillSep $
896 ["You","can","just","put","anything","for","now,","like"
897 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
898 ,"Once","there","is","something","there,","I","can","probably"
899 ,"give","a","more","specific","hint!"
900 ]
901 , D.toSimpleNote $
902 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
903 \ Or if I run into operators in unexpected spots. Point is, there are a\
904 \ couple ways I can get confused and give sort of weird advice!"
905 ]
906 )
908 OperatorReserved operator row col ->
909 toOperatorReport source context operator row col
911 Start row col ->
912 let
913 (contextRow, contextCol, aThing) =
914 case context of
915 InDef name r c -> (r, c, "the `" ++ Name.toChars name ++ "` definition")
916 InNode NRecord r c _ -> (r, c, "a record")
917 InNode NParens r c _ -> (r, c, "some parentheses")
918 InNode NList r c _ -> (r, c, "a list")
919 InNode NFunc r c _ -> (r, c, "an anonymous function")
920 InNode NCond r c _ -> (r, c, "an `if` expression")
921 InNode NThen r c _ -> (r, c, "an `if` expression")
922 InNode NElse r c _ -> (r, c, "an `if` expression")
923 -- TODO check if this is actually the best way to get error messages here
925 surroundings = A.Region (A.Position contextRow contextCol) (A.Position row col)
926 region = toRegion row col
927 in
928 Report.Report "MISSING EXPRESSION" region [] $
929 Report.toCodeSnippet source surroundings (Just region)
930 (
931 D.reflow $
932 "I am partway through parsing " ++ aThing ++ ", but I got stuck here:"
933 ,
934 D.stack
935 [ D.fillSep $
936 ["I","was","expecting","to","see","an","expression","like"
937 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
938 ,"Once","there","is","something","there,","I","can","probably"
939 ,"give","a","more","specific","hint!"
940 ]
941 , D.toSimpleNote $
942 "This can also happen if run into reserved words like `let` or `as` unexpectedly.\
943 \ Or if I run into operators in unexpected spots. Point is, there are a\
944 \ couple ways I can get confused and give sort of weird advice!"
945 ]
946 )
948 Char char row col ->
949 toCharReport source char row col
951 String string row col ->
952 toStringReport source string row col
954 Number number row col ->
955 toNumberReport source number row col
957 Space space row col ->
958 toSpaceReport source space row col
960 EndlessShader row col ->
961 let
962 region = toWiderRegion row col 6
963 in
964 Report.Report "ENDLESS SHADER" region [] $
965 Report.toCodeSnippet source region Nothing
966 (
967 D.reflow "I cannot find the end of this shader:"
968 ,
969 D.reflow "Add a |] somewhere after this to end the shader."
970 )
972 ShaderProblem problem row col ->
973 let
974 region = toRegion row col
975 in
976 Report.Report "SHADER PROBLEM" region [] $
977 Report.toCodeSnippet source region Nothing
978 (
979 D.reflow $
980 "I ran into a problem while parsing this GLSL block."
981 ,
982 D.stack
983 [ D.reflow $
984 "I use a 3rd party GLSL parser for now, and I did my best to extract their error message:"
985 , D.indent 4 $ D.vcat $
986 map D.fromChars (filter (/="") (lines problem))
987 ]
988 )
990 IndentOperatorRight op row col ->
991 let
992 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
993 region = toRegion row col
994 in
995 Report.Report "MISSING EXPRESSION" region [] $
996 Report.toCodeSnippet source surroundings (Just region)
997 (
998 D.reflow $
999 "I was expecting to see an expression after this " ++ Name.toChars op ++ " operator:"
1001 D.stack
1003 D.fillSep $
1004 ["You","can","just","put","anything","for","now,","like"
1005 ,D.dullyellow "42","or",D.dullyellow"\"hello\"" <> "."
1006 ,"Once","there","is","something","there,","I","can","probably"
1007 ,"give","a","more","specific","hint!"
1010 D.toSimpleNote $
1011 "I may be getting confused by your indentation? The easiest way to make sure\
1012 \ this is not an indentation problem is to put the expression on the right of\
1013 \ the " ++ Name.toChars op ++ " operator on the same line."
1017 IndentMoreExpr _ _ ->
1018 error "TODO IndentMoreExpr"
1021toCharReport :: Code.Source -> Char -> Row -> Col -> Report.Report
1022toCharReport source char row col =
1023 case char of
1024 CharEndless ->
1025 let
1026 region = toRegion row col
1027 in
1028 Report.Report "MISSING SINGLE QUOTE" region [] $
1029 Report.toCodeSnippet source region Nothing
1031 D.reflow $
1032 "I thought I was parsing a character, but I got to the end of\
1033 \ the line without seeing the closing single quote:"
1035 D.reflow $
1036 "Add a closing single quote here!"
1039 CharEscape escape ->
1040 toEscapeReport source escape row col
1042 CharNotString width ->
1043 let
1044 region = toWiderRegion row col width
1045 in
1046 Report.Report "NEEDS DOUBLE QUOTES" region [] $
1047 Report.toCodeSnippet source region Nothing
1049 "The following string uses single quotes:"
1051 D.stack
1052 [ "Please switch to double quotes instead:"
1053 , D.indent 4 $
1054 D.dullyellow "'this'" <> " => " <> D.green "\"this\""
1055 , D.toSimpleNote $
1056 "Elm uses double quotes for strings like \"hello\", whereas it uses single\
1057 \ quotes for individual characters like 'a' and 'ø'. This distinction helps with\
1058 \ code like (String.any (\\c -> c == 'X') \"90210\") where you are inspecting\
1059 \ individual characters."
1064toStringReport :: Code.Source -> String -> Row -> Col -> Report.Report
1065toStringReport source string row col =
1066 case string of
1067 StringEndless_Single ->
1068 let
1069 region = toRegion row col
1070 in
1071 Report.Report "ENDLESS STRING" region [] $
1072 Report.toCodeSnippet source region Nothing
1074 D.reflow $
1075 "I got to the end of the line without seeing the closing double quote:"
1077 D.stack
1078 [ D.fillSep $
1079 ["Strings","look","like",D.green "\"this\"","with","double"
1080 ,"quotes","on","each","end.","Is","the","closing","double"
1081 ,"quote","missing","in","your","code?"
1083 , D.link "Note" "Read" "TODO" "if you want a string that spans multiple lines."
1087 StringEndless_Multi ->
1088 let
1089 region = toWiderRegion row col 3
1090 in
1091 Report.Report "ENDLESS STRING" region [] $
1092 Report.toCodeSnippet source region Nothing
1094 D.reflow $
1095 "I cannot find the end of this multi-line string:"
1097 D.stack
1098 [ D.reflow "Add a \"\"\" somewhere after this to end the string."
1099 , D.link "Hint" "Read" "TODO" "for more information on strings and multi-line strings."
1103 StringEscape escape ->
1104 toEscapeReport source escape row col
1107toEscapeReport :: Code.Source -> Escape -> Row -> Col -> Report.Report
1108toEscapeReport source escape row col =
1109 case escape of
1110 EscapeUnknown ->
1111 let
1112 region = toWiderRegion row col 2
1113 in
1114 Report.Report "UNKNOWN ESCAPE" region [] $
1115 Report.toCodeSnippet source region Nothing
1117 D.reflow $
1118 "Backslashes always start escaped characters, but I do not recognize this one:"
1120 D.stack
1121 [ D.reflow $
1122 "Valid escape characters include:"
1123 , D.dullyellow $ D.indent 4 $ D.vcat $
1124 [ "\\n"
1125 , "\\r"
1126 , "\\t"
1127 , "\\\""
1128 , "\\\'"
1129 , "\\\\"
1130 , "\\u{003D}"
1132 , D.reflow $
1133 "Do you want one of those instead? Maybe you need \\\\ to escape a backslash?"
1134 , D.toSimpleNote $
1135 "The last style lets encode ANY character by its Unicode code\
1136 \ point. That means \\u{0009} and \\t are the same. You can use\
1137 \ that style for anything not covered by the other six escapes!"
1141 BadUnicodeFormat width ->
1142 let
1143 region = toWiderRegion row col width
1144 in
1145 Report.Report "BAD UNICODE ESCAPE" region [] $
1146 Report.toCodeSnippet source region Nothing
1148 D.reflow $
1149 "I ran into an invalid Unicode escape:"
1151 D.stack
1152 [ D.reflow $
1153 "Here are some examples of valid Unicode escapes:"
1154 , D.dullyellow $ D.indent 4 $ D.vcat $
1155 [ "\\u{0041}"
1156 , "\\u{03BB}"
1157 , "\\u{6728}"
1158 , "\\u{1F60A}"
1160 , D.reflow $
1161 "Notice that the code point is always surrounded by curly braces.\
1162 \ Maybe you are missing the opening or closing curly brace?"
1165 BadUnicodeCode 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 "This is not a valid code point:"
1175 D.reflow $
1176 "The valid code points are between 0 and 10FFFF inclusive."
1179 BadUnicodeLength width numDigits badCode ->
1180 let
1181 region = toWiderRegion row col width
1182 in
1183 Report.Report "BAD UNICODE ESCAPE" region [] $
1184 Report.toCodeSnippet source region Nothing $
1185 if numDigits < 4 then
1187 D.reflow $
1188 "Every code point needs at least four digits:"
1190 let
1191 goodCode = replicate (4 - numDigits) '0' ++ map Char.toUpper (showHex badCode "")
1192 suggestion = "\\u{" <> D.fromChars goodCode <> "}"
1193 in
1194 D.fillSep ["Try",D.green suggestion,"instead?"]
1197 else
1199 D.reflow $
1200 "This code point has too many digits:"
1202 D.fillSep $
1203 ["Valid","code","points","are","between"
1204 ,D.green "\\u{0000}","and",D.green "\\u{10FFFF}" <> ","
1205 ,"so","try","trimming","any","leading","zeros","until"
1206 ,"you","have","between","four","and","six","digits."
1211toNumberReport :: Code.Source -> Number -> Row -> Col -> Report.Report
1212toNumberReport source number row col =
1213 let
1214 region = toRegion row col
1215 in
1216 case number of
1217 NumberEnd ->
1218 Report.Report "WEIRD NUMBER" region [] $
1219 Report.toCodeSnippet source region Nothing
1221 D.reflow $
1222 "I thought I was reading a number, but I ran into some weird stuff here:"
1224 D.stack
1225 [ D.reflow $
1226 "I recognize numbers in the following formats:"
1227 , D.indent 4 $ D.vcat [ "42", "3.14", "6.022e23", "0x002B" ]
1228 , D.reflow $
1229 "So is there a way to write it like one of those?"
1233 NumberDot int ->
1234 Report.Report "WEIRD NUMBER" region [] $
1235 Report.toCodeSnippet source region Nothing
1237 D.reflow $
1238 "Numbers cannot end with a dot like this:"
1240 D.fillSep
1241 ["Switching","to",D.green (D.fromChars (show int))
1242 ,"or",D.green (D.fromChars (show int ++ ".0"))
1243 ,"will","work","though!"
1247 NumberHexDigit ->
1248 Report.Report "WEIRD HEXIDECIMAL" region [] $
1249 Report.toCodeSnippet source region Nothing
1251 D.reflow $
1252 "I thought I was reading a hexidecimal number until I got here:"
1254 D.stack
1255 [ D.reflow $
1256 "Valid hexidecimal digits include 0123456789abcdefABCDEF, so I can\
1257 \ only recognize things like this:"
1258 , D.indent 4 $ D.vcat [ "0x2B", "0x002B", "0x00ffb3" ]
1262 NumberNoLeadingZero ->
1263 Report.Report "LEADING ZEROS" region [] $
1264 Report.toCodeSnippet source region Nothing
1266 D.reflow $
1267 "I do not accept numbers with leading zeros:"
1269 D.stack
1270 [ D.reflow $
1271 "Just delete the leading zeros and it should work!"
1272 , D.toSimpleNote $
1273 "Some languages let you to specify octal numbers by adding a leading zero.\
1274 \ So in C, writing 0111 is the same as writing 73. Some people are used to\
1275 \ that, but others probably want it to equal 111. Either path is going to\
1276 \ surprise people from certain backgrounds, so Elm tries to avoid this whole\
1277 \ situation."
1282toOperatorReport :: Code.Source -> Context -> Operator -> Row -> Col -> Report.Report
1283toOperatorReport source context operator row col =
1284 case operator of
1285 OpDot ->
1286 let
1287 region = toRegion row col
1288 in
1289 Report.Report "UNEXPECTED SYMBOL" region [] $
1290 Report.toCodeSnippet source region Nothing
1292 "I was not expecting this dot:"
1294 D.reflow $
1295 "Dots are for record access and decimal points, so\
1296 \ they cannot float around on their own. Maybe\
1297 \ there is some extra whitespace?"
1300 OpPipe ->
1301 let
1302 region = toRegion row col
1303 in
1304 Report.Report "UNEXPECTED SYMBOL" region [] $
1305 Report.toCodeSnippet source region Nothing
1307 D.reflow $
1308 "I was not expecting this vertical bar:"
1310 D.reflow $
1311 "Vertical bars should only appear in custom type declarations. Maybe you want || instead?"
1314 OpArrow ->
1315 let
1316 region = toWiderRegion row col 2
1317 in
1318 Report.Report "UNEXPECTED ARROW" region [] $
1319 Report.toCodeSnippet source region Nothing $
1320 if error "TODO inCase" then
1322 D.reflow $
1323 "I was not expecting to see an arrow here:"
1325 D.stack
1327 D.reflow $
1328 "I think I am parsing a `case` expression right now, so it makes sense to\
1329 \ see arrows around here. This one is confusing me though!"
1331 D.toSimpleHint $
1332 "I may be getting confused by the indentation. Every pattern in a `case` must be\
1333 \ exactly aligned (with exactly the same amount of indentation) so maybe this arrow\
1334 \ appears after the next `case` pattern (correctly!) but the pattern itself is\
1335 \ indented too far?"
1339 else
1341 D.reflow $
1342 "I was not expecting an arrow here:"
1344 D.reflow $
1345 "Arrows should only appear in `case` expressions and anonymous functions. Maybe\
1346 \ you want > or >= instead?"
1349 OpEquals ->
1350 let
1351 region = toRegion row col
1352 name = getDefName context
1353 in
1354 Report.Report "UNEXPECTED EQUALS" region [] $
1355 Report.toCodeSnippet source region Nothing
1357 D.reflow $
1358 "I was not expecting to see this equals sign:"
1360 D.stack
1362 D.reflow "Maybe you want == instead? To check if two values are equal?"
1364 D.toSimpleNote $
1365 if isWithin NRecord context then
1366 "Records look like { x = 3, y = 4 } with the equals sign right\
1367 \ after the field name. So maybe you forgot a comma?"
1368 else
1369 "I may be getting confused by your indentation. Is this supposed to be part of\
1370 \ a definition AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
1371 \ the problem may be a bit before the equals sign. I need all definitions to\
1372 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
1373 \ this new definition is indented a bit too much."
1377 OpHasType ->
1378 let
1379 region = toRegion row col
1380 name = getDefName context
1381 in
1382 Report.Report "UNEXPECTED SYMBOL" region [] $
1383 Report.toCodeSnippet source region Nothing $
1385 D.reflow $
1386 "I was not expecting to run into the \"has type\" symbol here:"
1388 D.stack
1390 D.fillSep
1391 ["Maybe","you","want",D.green "::","instead?"
1392 ,"To","put","something","on","the","front","of","a","list?"
1394 , D.toSimpleNote $
1395 "The single colon is reserved for type annotations and record types, but I think\
1396 \ I am parsing the definition of `" ++ Name.toChars name ++ "` right now."
1398 D.toSimpleNote $
1399 "I may be getting confused by your indentation. Is this supposed to be part of\
1400 \ a type annotation AFTER the `" ++ Name.toChars name ++ "` definition? If so,\
1401 \ the problem may be a bit before the \"has type\" symbol. I need all definitions to\
1402 \ be exactly aligned (with exactly the same indentation) so the problem may be that\
1403 \ this new definition is indented a bit too much."
1409-- IF
1412toIfReport :: Code.Source -> Context -> If -> Row -> Col -> Report.Report
1413toIfReport source context if_ startRow startCol =
1414 case if_ of
1415 IfSpace space row col ->
1416 toSpaceReport source space row col
1418 IfThen row col ->
1419 let
1420 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1421 region = toRegion row col
1422 in
1423 Report.Report "UNFINISHED IF" region [] $
1424 Report.toCodeSnippet source surroundings (Just region)
1426 D.reflow $
1427 "I was expecting to see more of this `if` expression, but I got stuck here:"
1429 D.fillSep $
1430 ["I","was","expecting","to","see","the",D.green "then","keyword","next."
1434 IfElse row col ->
1435 let
1436 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1437 region = toRegion row col
1438 in
1439 Report.Report "UNFINISHED IF" region [] $
1440 Report.toCodeSnippet source surroundings (Just region)
1442 D.reflow $
1443 "I was expecting to see more of this `if` expression, but I got stuck here:"
1445 D.fillSep $
1446 ["I","was","expecting","to","see","the",D.green "else","keyword","next."
1450 IfElseBranchStart row col ->
1451 let
1452 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1453 region = toRegion row col
1454 in
1455 Report.Report "UNFINISHED IF" region [] $
1456 Report.toCodeSnippet source surroundings (Just region)
1458 D.reflow $
1459 "I just saw the start of an `else` branch, but then I got stuck here:"
1461 D.reflow $
1462 "I was expecting to see an expression next. Maybe it is not filled in yet?"
1465 IfCondition expr row col ->
1466 toExprReport source (InNode NCond startRow startCol context) expr row col
1468 IfThenBranch expr row col ->
1469 toExprReport source (InNode NThen startRow startCol context) expr row col
1471 IfElseBranch expr row col ->
1472 toExprReport source (InNode NElse startRow startCol context) expr row col
1474 IfIndentCondition 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 was expecting to see more of this `if` expression, but I got stuck here:"
1485 D.stack
1486 [ D.fillSep $
1487 ["I","was","expecting","to","see","an","expression","like",D.dullyellow "x < 0"
1488 ,"that","evaluates","to","True","or","False."
1490 , D.toSimpleNote $
1491 "I can be confused by indentation. Maybe something is not indented enough?"
1495 IfIndentThen row col ->
1496 let
1497 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1498 region = toRegion row col
1499 in
1500 Report.Report "UNFINISHED IF" region [] $
1501 Report.toCodeSnippet source surroundings (Just region)
1503 D.reflow $
1504 "I was expecting to see more of this `if` expression, but I got stuck here:"
1506 D.stack
1507 [ D.fillSep $
1508 ["I","was","expecting","to","see","the",D.green "then","keyword","next."
1510 , D.toSimpleNote $
1511 "I can be confused by indentation. Maybe something is not indented enough?"
1515 IfIndentThenBranch row col ->
1516 let
1517 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1518 region = toRegion row col
1519 in
1520 Report.Report "UNFINISHED IF" region [] $
1521 Report.toCodeSnippet source surroundings (Just region)
1523 D.reflow $
1524 "I got stuck after the start of this `then` branch:"
1526 D.stack
1527 [ D.reflow $
1528 "I was expecting to see an expression next. Maybe it is not filled in yet?"
1529 , D.toSimpleNote $
1530 "I can be confused by indentation, so if the `then` branch is already\
1531 \ present, it may not be indented enough for me to recognize it."
1535 IfIndentElseBranch row col ->
1536 let
1537 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1538 region = toRegion row col
1539 in
1540 Report.Report "UNFINISHED IF" region [] $
1541 Report.toCodeSnippet source surroundings (Just region)
1543 D.reflow $
1544 "I got stuck after the start of this `else` branch:"
1546 D.stack
1547 [ D.reflow $
1548 "I was expecting to see an expression next. Maybe it is not filled in yet?"
1549 , D.toSimpleNote $
1550 "I can be confused by indentation, so if the `else` branch is already\
1551 \ present, it may not be indented enough for me to recognize it."
1555 IfIndentElse row col ->
1556 let
1557 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1558 region = toRegion row col
1559 in
1560 Report.Report "UNFINISHED IF" region [] $
1561 Report.toCodeSnippet source surroundings (Just region)
1563 D.reflow $
1564 "I was expecting to see an `else` branch after this:"
1566 D.stack
1567 [ D.reflow $
1568 "I know what to do when the condition is `True`, but not when it is `False`."
1569 , D.fillSep
1570 ["Add","an",D.green "else","branch","to","handle","that","scenario!"]
1576-- RECORD
1579toRecordReport :: Code.Source -> Context -> Record -> Row -> Col -> Report.Report
1580toRecordReport source context record startRow startCol =
1581 case record of
1582 RecordOpen row col ->
1583 let
1584 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1585 region = toRegion row col
1586 in
1587 Report.Report "UNFINISHED PARENTHESES" region [] $
1588 Report.toCodeSnippet source surroundings (Just region)
1590 D.reflow $
1591 "I was expecting to see a closing curly brace next, but I got stuck here:"
1593 D.stack
1594 [ D.fillSep ["Try","adding","a",D.dullyellow "}","to","see","if","that","helps?"]
1595 , D.toSimpleNote $
1596 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
1597 \ unexpectedly. So there may be some other syntax trouble (like an extra\
1598 \ parenthesis?) that is confusing me."
1602 RecordEnd row col ->
1603 let
1604 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1605 region = toRegion row col
1606 in
1607 Report.Report "UNFINISHED PARENTHESES" region [] $
1608 Report.toCodeSnippet source surroundings (Just region)
1610 D.reflow $
1611 "I was expecting to see a closing curly brace next, but I got stuck here:"
1613 D.stack
1614 [ D.fillSep ["Try","adding","a",D.dullyellow "}","to","see","if","that","helps?"]
1615 , D.toSimpleNote $
1616 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
1617 \ unexpectedly. So there may be some other syntax trouble (like an extra\
1618 \ parenthesis?) that is confusing me."
1622 RecordField row col ->
1623 let
1624 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1625 region = toRegion row col
1626 in
1627 Report.Report "UNFINISHED RECORD" region [] $
1628 Report.toCodeSnippet source surroundings (Just region)
1630 D.reflow $
1631 "I am partway through parsing a record, but I got stuck after that last comma:"
1633 addNoteForRecordError $
1634 D.reflow $
1635 "Trailing commas are not allowed in records, so I was expecting to see another\
1636 \ record field defined next. If you are done defining the record, the fix may\
1637 \ be to delete that last comma?"
1640 RecordEquals row col ->
1641 let
1642 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1643 region = toRegion row col
1644 in
1645 Report.Report "UNFINISHED RECORD" region [] $
1646 Report.toCodeSnippet source surroundings (Just region)
1648 D.reflow $
1649 "I am partway through parsing a record, but I got stuck here:"
1651 addNoteForRecordError $
1652 D.fillSep $
1653 ["I","just","saw","a","field","name,","so","I","was","expecting","to","see"
1654 ,"an","equals","sign","next.","So","try","putting","an",D.green "=","sign","here?"
1658 RecordExpr expr row col ->
1659 toExprReport source (InNode NRecord startRow startCol context) expr row col
1661 RecordSpace space row col ->
1662 toSpaceReport source space row col
1664 RecordIndentOpen 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 just saw the opening curly brace of a record, but then I got stuck here:"
1675 addNoteForRecordIndentError $
1676 D.fillSep $
1677 ["I","am","expecting","a","record","like",D.dullyellow "{ x = 3, y = 4 }","here."
1678 ,"Try","defining","some","fields","of","your","own?"
1682 RecordIndentEnd row col ->
1683 let
1684 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1685 region = toRegion row col
1686 in
1687 Report.Report "UNFINISHED RECORD" region [] $
1688 Report.toCodeSnippet source surroundings (Just region)
1690 D.reflow $
1691 "I was expecting to see a closing curly brace next:"
1693 addNoteForRecordIndentError $
1694 D.fillSep $
1695 ["Try","putting","an",D.green "}","and","see","if","that","helps?"
1699 RecordIndentField row col ->
1700 let
1701 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1702 region = toRegion row col
1703 in
1704 Report.Report "UNFINISHED RECORD" region [] $
1705 Report.toCodeSnippet source surroundings (Just region)
1707 D.reflow $
1708 "I am partway through parsing a record, but I got stuck after that last comma:"
1710 addNoteForRecordError $
1711 D.reflow $
1712 "Trailing commas are not allowed in records, so the fix may be to\
1713 \ delete that last comma? Or maybe you were in the middle of defining\
1714 \ an additional field?"
1717 RecordIndentEquals row col ->
1718 let
1719 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1720 region = toRegion row col
1721 in
1722 Report.Report "UNFINISHED RECORD" region [] $
1723 Report.toCodeSnippet source surroundings (Just region)
1725 D.reflow $
1726 "I am partway through parsing a record. I just saw a record\
1727 \ field, so I was expecting to see an equals sign next:"
1729 addNoteForRecordIndentError $
1730 D.fillSep $
1731 ["Try","putting","an",D.green "=","followed","by","an","expression?"
1735 RecordIndentExpr row col ->
1736 let
1737 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1738 region = toRegion row col
1739 in
1740 Report.Report "UNFINISHED RECORD" region [] $
1741 Report.toCodeSnippet source surroundings (Just region)
1743 D.reflow $
1744 "I am partway through parsing a record, and I was expecting to run into an expression next:"
1746 addNoteForRecordIndentError $
1747 D.fillSep $
1748 ["Try","putting","something,","like"
1749 ,D.dullyellow "42","or",D.dullyellow"\"hello\"","for","now?"
1754addNoteForRecordError :: D.Doc -> D.Doc
1755addNoteForRecordError normalRecommendation =
1756 D.stack $
1757 normalRecommendation
1759 [ D.toSimpleNote
1760 "If you are trying to define a record across multiple lines, I recommend using this format:"
1761 , D.indent 4 $ D.vcat $
1762 [ "{ name = \"Alice\""
1763 , ", age = 42"
1764 , ", height = 1.75"
1765 , "}"
1767 , D.reflow $
1768 "Notice that nothing comes directly after a newline. Each line starts with some spaces. I\
1769 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
1770 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
1774addNoteForRecordIndentError :: D.Doc -> D.Doc
1775addNoteForRecordIndentError normalRecommendation =
1776 D.stack $
1777 normalRecommendation
1779 [ D.toSimpleNote
1780 "I may be confused by indentation. For example, if you are trying to define\
1781 \ a record across multiple lines, I recommend using this format:"
1782 , D.indent 4 $ D.vcat $
1783 [ "[ \"Alice\""
1784 , ", \"Bob\""
1785 , ", \"Chuck\""
1786 , "]"
1788 , D.reflow $
1789 "Notice that nothing comes directly after a newline. Each line starts with some spaces. I\
1790 \ know this style can be jarring for people coming from C-like syntax, but folks generally\
1791 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
1796-- TUPLE
1799toTupleReport :: Code.Source -> Context -> Tuple -> Row -> Col -> Report.Report
1800toTupleReport source context tuple startRow startCol =
1801 case tuple of
1802 TupleExpr expr row col ->
1803 toExprReport source (InNode NParens startRow startCol context) expr row col
1805 TupleSpace space row col ->
1806 toSpaceReport source space row col
1808 TupleEnd row col ->
1809 let
1810 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1811 region = toRegion row col
1812 in
1813 Report.Report "UNFINISHED PARENTHESES" region [] $
1814 Report.toCodeSnippet source surroundings (Just region)
1816 D.reflow $
1817 "I was expecting to see a closing parentheses next, but I got stuck here:"
1819 D.stack
1820 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps?"]
1821 , D.toSimpleNote $
1822 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
1823 \ unexpectedly. So there may be some other syntax trouble (like an extra\
1824 \ square bracket?) that is confusing me."
1828 TupleOperatorClose row col ->
1829 let
1830 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1831 region = toRegion row col
1832 in
1833 Report.Report "UNFINISHED OPERATOR FUNCTION" region [] $
1834 Report.toCodeSnippet source surroundings (Just region)
1836 D.reflow "I was expecting a closing parenthesis here:"
1838 D.stack
1839 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
1840 , D.toSimpleNote $
1841 "I think I am parsing an operator function right now, so I am expecting to see\
1842 \ something like (+) or (&&) where an operator is surrounded by parentheses with\
1843 \ no extra spaces."
1847 TupleOperatorReserved operator row col ->
1848 let
1849 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1850 region = toRegion row col
1851 in
1852 Report.Report "UNEXPECTED SYMBOL" region [] $
1853 Report.toCodeSnippet source surroundings (Just region)
1855 D.reflow $
1856 "I ran into an unexpected symbol here:"
1858 D.fillSep $
1859 case operator of
1860 OpDot -> ["Maybe","you","wanted","a","record","accessor","like",D.dullyellow ".x","or",D.dullyellow ".name","instead?"]
1861 OpPipe -> ["Try",D.dullyellow "(||)","instead?","To","turn","boolean","OR","into","a","function?"]
1862 OpArrow -> ["Maybe","you","wanted",D.dullyellow "(>)","or",D.dullyellow "(>=)","instead?"]
1863 OpEquals -> ["Try",D.dullyellow "(==)","instead?","To","make","a","function","that","checks","equality?"]
1864 OpHasType -> ["Try",D.dullyellow "(::)","instead?","To","add","values","to","the","front","of","lists?"]
1867 TupleIndentExpr1 row col ->
1868 let
1869 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1870 region = toRegion row col
1871 in
1872 Report.Report "UNFINISHED PARENTHESES" region [] $
1873 Report.toCodeSnippet source surroundings (Just region)
1875 D.reflow $
1876 "I just saw an open parenthesis, so I was expecting to see an expression next."
1878 D.stack
1879 [ D.fillSep $
1880 ["Something","like",D.dullyellow "(4 + 5)","or"
1881 ,D.dullyellow "(String.reverse \"desserts\")" <> "."
1882 ,"Anything","where","you","are","putting","parentheses","around","normal","expressions."
1884 , D.toSimpleNote $
1885 "I can get confused by indentation in cases like this, so\
1886 \ maybe you have an expression but it is not indented enough?"
1890 TupleIndentExprN row col ->
1891 let
1892 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1893 region = toRegion row col
1894 in
1895 Report.Report "UNFINISHED TUPLE" region [] $
1896 Report.toCodeSnippet source surroundings (Just region)
1898 D.reflow $
1899 "I think I am in the middle of parsing a tuple. I just saw a comma, so I was expecting to see expression next."
1901 D.stack
1902 [ D.fillSep $
1903 ["A","tuple","looks","like",D.dullyellow "(3,4)","or"
1904 ,D.dullyellow "(\"Tom\",42)" <> ","
1905 ,"so","I","think","there","is","an","expression","missing","here?"
1907 , D.toSimpleNote $
1908 "I can get confused by indentation in cases like this, so\
1909 \ maybe you have an expression but it is not indented enough?"
1913 TupleIndentEnd row col ->
1914 let
1915 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1916 region = toRegion row col
1917 in
1918 Report.Report "UNFINISHED PARENTHESES" region [] $
1919 Report.toCodeSnippet source surroundings (Just region)
1921 D.reflow $
1922 "I was expecting to see a closing parenthesis next:"
1924 D.stack
1925 [ D.fillSep ["Try","adding","a",D.dullyellow ")","to","see","if","that","helps!"]
1926 , D.toSimpleNote $
1927 "I can get confused by indentation in cases like this, so\
1928 \ maybe you have a closing parenthesis but it is not indented enough?"
1933toListReport :: Code.Source -> Context -> List -> Row -> Col -> Report.Report
1934toListReport source context list startRow startCol =
1935 case list of
1936 ListSpace space row col ->
1937 toSpaceReport source space row col
1939 ListOpen row col ->
1940 let
1941 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1942 region = toRegion row col
1943 in
1944 Report.Report "UNFINISHED LIST" region [] $
1945 Report.toCodeSnippet source surroundings (Just region)
1947 D.reflow $
1948 "I was expecting to see a closing square bracket next, but I got stuck here:"
1950 D.stack
1951 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
1952 , D.toSimpleNote $
1953 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
1954 \ unexpectedly. So there may be some other syntax trouble (like an extra\
1955 \ parenthesis?) that is confusing me."
1959 ListExpr expr row col ->
1960 case expr of
1961 Start r c ->
1962 let
1963 surroundings = A.Region (A.Position startRow startCol) (A.Position r c)
1964 region = toRegion r c
1965 in
1966 Report.Report "UNFINISHED LIST" region [] $
1967 Report.toCodeSnippet source surroundings (Just region)
1969 D.reflow $
1970 "I was expecting to see another list entry after that last comma:"
1972 D.stack
1973 [ D.reflow $
1974 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
1975 , D.toSimpleNote
1976 "I recommend using the following format for lists that span multiple lines:"
1977 , D.indent 4 $ D.vcat $
1978 [ "[ \"Alice\""
1979 , ", \"Bob\""
1980 , ", \"Chuck\""
1981 , "]"
1983 , D.reflow $
1984 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
1985 \ This style can be jarring for people coming from C-like syntax, but folks generally\
1986 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
1990 _ ->
1991 toExprReport source (InNode NList startRow startCol context) expr row col
1993 ListEnd row col ->
1994 let
1995 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
1996 region = toRegion row col
1997 in
1998 Report.Report "UNFINISHED LIST" region [] $
1999 Report.toCodeSnippet source surroundings (Just region)
2001 D.reflow $
2002 "I was expecting to see a closing square bracket next, but I got stuck here:"
2004 D.stack
2005 [ D.fillSep ["Try","adding","a",D.dullyellow "]","to","see","if","that","helps?"]
2006 , D.toSimpleNote $
2007 "I can get stuck when I run into keywords, operators, parentheses, or brackets\
2008 \ unexpectedly. So there may be some other syntax trouble (like an extra\
2009 \ parenthesis?) that is confusing me."
2013 ListIndentOpen row col ->
2014 let
2015 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2016 region = toRegion row col
2017 in
2018 Report.Report "UNFINISHED LIST" region [] $
2019 Report.toCodeSnippet source surroundings (Just region)
2021 D.reflow $
2022 "I cannot find the end of this list:"
2024 D.stack
2025 [ D.fillSep $
2026 ["You","could","change","it","to","something","like"
2027 ,D.dullyellow "[3,4,5]"
2028 ,"or","even","just"
2029 ,D.dullyellow "[]" <> "."
2030 ,"Anything","where","there","is","an","open","and","close","square","brace,"
2031 ,"and","where","the","elements","of","the","list","are","separated","by","commas."
2033 , D.toSimpleNote
2034 "I may be confused by indentation. For example, if you are trying to define\
2035 \ a list across multiple lines, I recommend using this format:"
2036 , D.indent 4 $ D.vcat $
2037 [ "[ \"Alice\""
2038 , ", \"Bob\""
2039 , ", \"Chuck\""
2040 , "]"
2042 , D.reflow $
2043 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2044 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2045 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2049 ListIndentEnd row col ->
2050 let
2051 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2052 region = toRegion row col
2053 in
2054 Report.Report "UNFINISHED LIST" region [] $
2055 Report.toCodeSnippet source surroundings (Just region)
2057 D.reflow $
2058 "I cannot find the end of this list:"
2060 D.stack
2061 [ D.fillSep $
2062 ["You","can","just","add","a","closing",D.dullyellow "]"
2063 ,"right","here,","and","I","will","be","all","set!"
2065 , D.toSimpleNote
2066 "I may be confused by indentation. For example, if you are trying to define\
2067 \ a list across multiple lines, I recommend using this format:"
2068 , D.indent 4 $ D.vcat $
2069 [ "[ \"Alice\""
2070 , ", \"Bob\""
2071 , ", \"Chuck\""
2072 , "]"
2074 , D.reflow $
2075 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2076 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2077 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2081 ListIndentExpr row col ->
2082 let
2083 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2084 region = toRegion row col
2085 in
2086 Report.Report "UNFINISHED LIST" region [] $
2087 Report.toCodeSnippet source surroundings (Just region)
2089 D.reflow $
2090 "I was expecting to see another list entry after this comma:"
2092 D.stack
2093 [ D.reflow $
2094 "Trailing commas are not allowed in lists, so the fix may be to delete the comma?"
2095 , D.toSimpleNote
2096 "I recommend using the following format for lists that span multiple lines:"
2097 , D.indent 4 $ D.vcat $
2098 [ "[ \"Alice\""
2099 , ", \"Bob\""
2100 , ", \"Chuck\""
2101 , "]"
2103 , D.reflow $
2104 "Notice that nothing comes directly after a newline. Each line starts with some spaces.\
2105 \ This style can be jarring for people coming from C-like syntax, but folks generally\
2106 \ report that they are used to it (and often prefer it!) after a week or two of using Elm."
2111toFuncReport :: Code.Source -> Context -> Func -> Row -> Col -> Report.Report
2112toFuncReport source context func startRow startCol =
2113 case func of
2114 FuncSpace space row col ->
2115 toSpaceReport source space row col
2117 FuncArg pattern row col ->
2118 error "TODO FuncArg" pattern row col
2120 FuncBody expr row col ->
2121 toExprReport source (InNode NFunc startRow startCol context) expr row col
2123 FuncArrow row col ->
2124 let
2125 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2126 region = toRegion row col
2127 in
2128 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
2129 Report.toCodeSnippet source surroundings (Just region)
2131 D.reflow $
2132 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
2134 D.fillSep $
2135 ["The","syntax","for","anonymous","functions","is"
2136 ,D.dullyellow "(\\x -> x + 1)"
2137 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
2141 FuncIndentArg row col ->
2142 let
2143 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2144 region = toRegion row col
2145 in
2146 Report.Report "MISSING ARGUMENT" region [] $
2147 Report.toCodeSnippet source surroundings (Just region)
2149 D.reflow $
2150 "I just saw the beginning of an anonymous function, so I was expecting to see an argument next:"
2152 D.stack
2153 [ D.fillSep
2154 ["Something","like",D.dullyellow"x","or",D.dullyellow "name" <> "."
2155 ,"Anything","that","starts","with","a","lower","case","letter!"
2157 , D.toSimpleNote $
2158 "The syntax for anonymous functions is (\\x -> x + 1) where the backslash\
2159 \ is meant to look a bit like a lambda if you squint. This visual pun seemed\
2160 \ like a better idea at the time!"
2164 FuncIndentArrow row col ->
2165 let
2166 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2167 region = toRegion row col
2168 in
2169 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
2170 Report.toCodeSnippet source surroundings (Just region)
2172 D.reflow $
2173 "I just saw the beginning of an anonymous function, so I was expecting to see an arrow next:"
2175 D.stack
2176 [ D.fillSep $
2177 ["The","syntax","for","anonymous","functions","is"
2178 ,D.dullyellow "(\\x -> x + 1)"
2179 ,"so","I","am","missing","the","arrow","and","the","body","of","the","function."
2181 , D.toSimpleNote $
2182 "It is possible that I am confused about indetation! I generally recommend\
2183 \ switching to named functions if the definition cannot fit inline nicely, so\
2184 \ either (1) try to fit the whole anonymous function on one line or (2) break\
2185 \ the whole thing out into a named function. Things tend to be clearer that way!"
2189 FuncIndentBody row col ->
2190 let
2191 surroundings = A.Region (A.Position startRow startCol) (A.Position row col)
2192 region = toRegion row col
2193 in
2194 Report.Report "UNFINISHED ANONYMOUS FUNCTION" region [] $
2195 Report.toCodeSnippet source surroundings (Just region)
2197 D.reflow $
2198 "I was expecting to see the body of your anonymous function next:"
2200 D.stack
2201 [ D.fillSep $
2202 ["The","syntax","for","anonymous","functions","is"
2203 ,D.dullyellow "(\\x -> x + 1)"
2204 ,"so","I","am","missing","all","the","stuff","after","the","arrow!"
2206 , D.toSimpleNote $
2207 "It is possible that I am confused about indetation! I generally recommend\
2208 \ switching to named functions if the definition cannot fit inline nicely, so\
2209 \ either (1) try to fit the whole anonymous function on one line or (2) break\
2210 \ the whole thing out into a named function. Things tend to be clearer that way!"
2218 case err of
2219 CommentOnNothing region ->
2220 Report.Report "STRAY COMMENT" region [] $
2221 Report.toCodeSnippet source region Nothing
2223 "This documentation comment is not followed by anything."
2225 D.reflow $
2226 "All documentation comments need to be right above the declaration they\
2227 \ describe. Maybe some code got deleted or commented out by accident? Or\
2228 \ maybe this comment is here by accident?"
2231 UnexpectedPort region ->
2232 Report.Report "UNEXPECTED PORTS" region [] $
2233 Report.toCodeSnippet source region Nothing
2235 D.reflow $
2236 "You are declaring ports in a normal module."
2238 D.stack
2239 [ D.fillSep
2240 ["Switch","this","to","say",D.green "port module","instead,"
2241 ,"marking","that","this","module","contains","port","declarations."
2243 , D.link "Note"
2244 "Ports are not a traditional FFI for calling JS functions directly. They need a different mindset! Read"
2245 "ports"
2246 "to learn the syntax and how to use it effectively."
2250 NoPorts region ->
2251 Report.Report "NO PORTS" region [] $
2252 Report.toCodeSnippet source region Nothing
2254 D.reflow $
2255 "This module does not declare any ports, but it says it will:"
2257 D.fillSep
2258 ["Switch","this","to",D.green "module"
2259 ,"and","you","should","be","all","set!"
2263 ParseError row col context expectation ->
2264 let
2265 pos = A.Position row col
2266 region = A.Region pos pos
2267 in
2268 case expectation of
2270 DocComment ->
2271 Report.Report "EXPECTING DOC COMMENT" region [] $
2272 Report.toCodeSnippet source region Nothing
2274 D.reflow $
2275 "I was expecting a doc comment here:"
2277 D.reflowLink
2278 "Check out" "TODO" "for examples of doc comments."
2281 -- Parse.Number
2283 Precedence ->
2284 Report.Report "EXPECTING PRECEDENCE" region [] $
2285 Report.toCodeSnippet source region Nothing
2287 D.reflow $
2288 "I was expecting the precedence here:"
2290 D.reflow $
2291 "I need a single digit between 0 and 9 inclusive."
2294 Operator ->
2295 Report.Report "EXPECTING AN OPERATOR" region [] $
2296 Report.toCodeSnippet source region Nothing
2298 D.reflow $
2299 "I was expecting an operator here:"
2301 D.stack
2302 [ D.reflow "Some of the most common operators are:"
2303 , D.indent 4 $ D.vcat ["+","-","*","&&","||"]
2304 , D.reflow "Something like that!"
2308 Wildcard ->
2309 Report.Report "EXPECTING A WILDCARD" region [] $
2310 Report.toCodeSnippet source region Nothing
2312 D.reflow $
2313 "I was expecting a _ here:"
2315 D.reflow $
2316 "An underscore indicates that “I do not care about this value” and is\
2317 \ called a wildcard pattern because it will match with any type of values."
2320 WildcardNotVar startCol endCol ->
2321 let
2322 badRegion =
2323 A.Region (A.Position row startCol) (A.Position row endCol)
2324 in
2325 Report.Report "INVALID PATTERN" badRegion [] $
2326 Report.toCodeSnippet source badRegion Nothing
2328 D.reflow $
2329 "I was expecting to see an underscore without any additional characters:"
2331 D.reflow $
2332 "There are two options. Either (1) remove the extra characters and ignore the\
2333 \ value or (2) remove the starting underscore to give the value a normal name."
2336 -- Parse.Pattern
2338 FloatInPattern ->
2339 Report.Report "INVALID PATTERN" region [] $
2340 Report.toCodeSnippet source region Nothing
2342 D.reflow $
2343 "I cannot pattern match with floating point numbers:"
2345 D.reflow $
2346 "Equality on floats can be unreliable, so you usually want to check that they\
2347 \ are nearby with some sort of (abs (actual - expected) < 0.001) check."
2350 FieldNamePattern ->
2351 Report.Report "EXPECTING A FIELD NAME" region [] $
2352 Report.toCodeSnippet source region Nothing
2354 D.reflow $
2355 "I was expecting a field name here:"
2357 D.fillSep $
2358 ["A","name","like",D.dullyellow "id" <> ",",D.dullyellow "status" <> ","
2359 ,"or","whatever","field","you","want","to","access."
2363 -- Parse.Expression
2365 MatchingName name ->
2366 Report.Report "EXPECTING A DEFINITION" region [] $
2367 Report.toCodeSnippet source region Nothing
2369 D.reflow $
2370 "I just saw the type annotation for `" ++ Name.toChars name
2371 ++ "` so I was expecting to see its definition here:"
2373 D.reflow $
2374 "Type annotations always appear directly above the relevant\
2375 \ definition, without anything else (even doc comments) in between."
2381 TypeWithBadDefinition region annName defName ->
2382 Report.Report "ANNOTATION MISMATCH" region [] $
2383 Report.toCodeSnippet source region Nothing
2385 D.reflow $
2386 "I see a `" <> Name.toChars annName
2387 <> "` annotation, but it is followed by a `"
2388 <> Name.toChars defName <> "` definition."
2390 D.fillSep
2391 ["The","annotation","and","definition","names","must","match!"
2392 ,"Is","there","a","typo","between"
2393 , D.dullyellow (D.fromName annName)
2394 ,"and"
2395 , D.dullyellow (D.fromName defName) <> "?"
2400-- CONTEXT
2403contextToString :: String -> String -> ContextStack -> String
2404contextToString defaultString prefixString stack =
2405 case stack of
2406 [] ->
2407 defaultString
2409 (context, _) : rest ->
2410 let anchor = getAnchor rest in
2411 prefixString <>
2412 case context of
2413 ExprIf -> "an `if` expression" <> anchor
2414 ExprLet -> "a `let` expression" <> anchor
2415 ExprFunc -> "an anonymous function" <> anchor
2416 ExprCase -> "a `case` expression" <> anchor
2417 ExprList -> "a list" <> anchor
2418 ExprTuple -> "an expression (in parentheses)" <> anchor
2419 ExprRecord -> "a record" <> anchor
2420 Definition name -> Name.toChars name <> "'s definition"
2421 Annotation name -> Name.toChars name <> "'s type annotation"
2422 TypeTuple -> "a type (in parentheses)" <> anchor
2423 TypeRecord -> "a record type" <> anchor
2424 PatternList -> "a list pattern" <> anchor
2425 PatternTuple -> "a pattern (in parentheses)" <> anchor
2426 PatternRecord -> "a record pattern" <> anchor
2427 Module -> "a module declaration"
2428 Import -> "an import"
2429 TypeUnion -> "a union type"
2430 TypeAlias -> "a type alias"
2431 Infix -> "an infix declaration"
2432 Port -> "a port declaration"
2435getAnchor :: ContextStack -> String
2436getAnchor stack =
2437 case stack of
2438 [] ->
2439 ""
2441 (context, _) : rest ->
2442 case context of
2443 Definition name ->
2444 " in " <> Name.toChars name <> "'s definition"
2446 Annotation name ->
2447 " in " <> Name.toChars name <> "'s type annotation"
2449 _ ->
2450 getAnchor rest