on master help sign in
Introduce nestable types for tracking parse errors
aa10604Evan Czaplicki
compiler/src/Reporting/Error/Syntax.hs+371−759
@@ -2,25 +2,55 @@
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Reporting.Error.Syntax
3module Reporting.Error.Syntax
4 ( Error(..)
4 ( Error(..)
5− , ParseError(..)
5+ --
6− , Problem(..), Theory(..)
6+ , Decl(..)
7− , EscapeProblem(..)
7+ , Infix(..)
8− , ContextStack, Context(..)
8+ , CustomType(..)
9− , BadOp(..), Next(..)
9+ --
10+ , Expr(..)
11+ , Record(..)
12+ , Tuple(..)
13+ , List(..)
14+ , Func(..)
15+ , Case(..)
16+ , If(..)
17+ , Let(..)
18+ , Def(..)
19+ , Destruct(..)
20+ --
21+ , Pattern(..)
22+ , PRecord(..)
23+ , PTuple(..)
24+ , PList(..)
25+ --
26+ , Type(..)
27+ , TRecord(..)
28+ , TTuple(..)
29+ --
30+ , Char(..)
31+ , String(..)
32+ , Escape(..)
33+ , Number(..)
34+ --
35+ , Space(..)
36+ , Operator(..)
10 , toReport
37 , toReport
11 )
38 )
12 where
39 where
13
40
14
41
15−import Data.Monoid ((<>))
42+import Prelude hiding (Char, String)
43+import qualified Data.Char as Char
16import qualified Data.Name as Name
44import qualified Data.Name as Name
17−import qualified Data.Set as Set
45+import Data.Word (Word16)
18−import qualified Data.Text as Text
46+--import Numeric (showHex)
19
47
48+import Parse.Primitives (Row, Col)
49+--import qualified Parse.Primitives as P
50+import qualified Reporting.Annotation as A
20−import qualified Reporting.Doc as D
51+--import qualified Reporting.Doc as D
21−import qualified Reporting.Region as R
22−import qualified Reporting.Render.Code as Code
23import qualified Reporting.Report as Report
52import qualified Reporting.Report as Report
53+import qualified Reporting.Render.Code as Code
24
54
25
55
26
56
@@ -28,760 +58,342 @@ import qualified Reporting.Report as Report
28
58
29
59
30data Error
60data Error
31− = CommentOnNothing R.Region
61+ = CommentOnNothing A.Region
32− | UnexpectedPort R.Region Name.Name
62+ | UnexpectedPort A.Region
33− | TypeWithBadDefinition R.Region Name.Name Name.Name
63+ | NoPorts A.Region
34− | TypeWithoutDefinition R.Region Name.Name
64+ | ParseError Decl
35− | Parse R.Region (Maybe R.Region) Problem
65+
36−
66+
37−
67+
38−
68+-- DECLARATIONS
39−-- PARSE ERRORS
69+
40−
70+
41−
42−data ParseError = ParseError !Int !Int !Problem
43−
44−
45−data Problem
46− = Tab
47− | EndOfFile_Comment
48− | EndOfFile_Shader
49− | EndOfFile_String
50− | EndOfFile_MultiString
51− | EndOfFile_Char
52− | NewLineInString
53− | NewLineInChar
54− | BadEscape Int EscapeProblem
55− | BadChar Int
56− | BadNumberDot Int
57− | BadNumberEnd
58− | BadNumberExp
59− | BadNumberHex
60− | BadNumberZero
61− | FloatInPattern
62− | BadShader Text.Text
63− | BadUnderscore Int
64− | BadOp BadOp ContextStack
65− | Theories ContextStack [Theory]
66−
67−
68−data EscapeProblem
69− = UnknownEscape
70− | UnicodeSyntax
71− | UnicodeRange
72− | UnicodeLength Int String
73−
74−
75−data BadOp = HasType | Equals | Arrow | Pipe | Dot
76−
77−
78−data Theory
79− = Expecting Next
80− | Keyword String
81− | Symbol String
82− | LowVar
83− | CapVar
84− | InfixOp
85− | Digit
86− | BadSpace
87− deriving (Eq, Ord)
88−
89−
90−data Next
91− = Decl
71+data Decl
92− | Expr
93− | AfterOpExpr Name.Name
94− | ElseBranch
95− | Arg
96− | Pattern
97− | Type
98− | Listing
99− | Exposing
100− deriving (Eq, Ord)
101−
102−
103−type ContextStack = [(Context, R.Position)]
104−
105−
106−data Context
107− = ExprIf
108− | ExprLet
109− | ExprFunc
110− | ExprCase
111− | ExprList
112− | ExprTuple
113− | ExprRecord
114− ----------------
115− | Definition Name.Name
116− | Annotation Name.Name
117− ----------------
118− | TypeTuple
119− | TypeRecord
120− ----------------
121− | PatternList
122− | PatternTuple
123− | PatternRecord
124− ----------------
125− | Module
72+ = Module Row Col
126− | Import
73+ | Import Row Col
127− | TypeUnion
74+ | Annotation Name.Name Type Row Col
75+ | Definition Name.Name Def Row Col
128− | TypeAlias
76+ | TypeAlias Name.Name Row Col
129− | Infix
77+ | CustomType Name.Name CustomType Row Col
130− | Port
78+ | Port Name.Name Row Col
131− deriving (Eq, Ord)
79+ | Infix Infix Row Col
80+ ----
81+ | EndlessDocComment Row Col
82+ | DeclSpace Space Row Col
83+ | DeclDeadend Row Col
84+
85+
86+data Infix
87+ = Precedence Row Col
88+ | Associativity Row Col
89+
90+
91+data CustomType
92+ = CT_Variant Row Col
93+ | CT_Space Space Row Col
94+ | CT_Type Type Row Col
95+
96+
97+
98+-- EXPRESSIONS
99+
100+
101+data Expr
102+ = Let Let Row Col
103+ | Case Case Row Col
104+ | If If Row Col
105+ | List List Row Col
106+ | Record Record Row Col
107+ | Update Expr Row Col
108+ | Tuple Tuple Row Col
109+ | Func Func Row Col
110+ --
111+ | Dot Row Col
112+ | Access Row Col
113+ | OperatorRHS Row Col
114+ | OperatorRight Row Col
115+ | OperatorReserved Operator Row Col
116+ --
117+ | Start Row Col
118+ | Char Char Row Col
119+ | String String Row Col
120+ | Number Number Row Col
121+ | Space Space Row Col
122+ | EndlessShader Row Col
123+ | ShaderProblem [Char.Char] Row Col
124+ | IndentOperatorRight Row Col
125+ | IndentMoreExpr Row Col
126+
127+
128+data Record
129+ = RecordOpen Row Col
130+ | RecordEnd Row Col
131+ | RecordField Row Col
132+ | RecordEquals Row Col
133+ | RecordExpr Expr Row Col
134+ | RecordSpace Space Row Col
135+ --
136+ | RecordIndentOpen Row Col
137+ | RecordIndentEnd Row Col
138+ | RecordIndentField Row Col
139+ | RecordIndentEquals Row Col
140+ | RecordIndentExpr Row Col
141+
142+
143+data Tuple
144+ = TupleOpen Row Col
145+ | TupleExpr Expr Row Col
146+ | TupleSpace Space Row Col
147+ | TupleEnd Row Col
148+ | TupleOperatorClose Row Col
149+ | TupleOperatorReserved Operator Row Col
150+ --
151+ | TupleIndentExpr Row Col
152+ | TupleIndentEnd Row Col
153+
154+
155+data List
156+ = ListSpace Space Row Col
157+ | ListOpen Row Col
158+ | ListExpr Expr Row Col
159+ | ListEnd Row Col
160+ --
161+ | ListIndentOpen Row Col
162+ | ListIndentEnd Row Col
163+ | ListIndentExpr Row Col
164+
165+
166+data Func
167+ = FuncSpace Space Row Col
168+ | FuncArg Pattern Row Col
169+ | FuncBody Expr Row Col
170+ | FuncArrow Row Col
171+ --
172+ | FuncIndentArg Row Col
173+ | FuncIndentArrow Row Col
174+ | FuncIndentBody Row Col
175+
176+
177+data Case
178+ = CaseSpace Space Row Col
179+ | CaseOf Row Col
180+ | CasePattern Pattern Row Col
181+ | CaseArrow Row Col
182+ | CaseExpr Expr Row Col
183+ | CaseBranch Expr Row Col
184+ --
185+ | CaseIndentOf Row Col
186+ | CaseIndentExpr Row Col
187+ | CaseIndentPattern Row Col
188+ | CaseIndentArrow Row Col
189+ | CaseIndentBranch Row Col
190+ | CasePatternAlignment Word16 Row Col
191+
192+
193+data If
194+ = IfSpace Space Row Col
195+ | IfThen Row Col
196+ | IfElse Row Col
197+ | IfElseBranchStart Row Col
198+ --
199+ | IfCondition Expr Row Col
200+ | IfThenBranch Expr Row Col
201+ | IfElseBranch Expr Row Col
202+ --
203+ | IfIndentCondition Row Col
204+ | IfIndentThen Row Col
205+ | IfIndentThenBranch Row Col
206+ | IfIndentElseBranch Row Col
207+ | IfIndentElse Row Col
208+
209+
210+data Let
211+ = LetSpace Space Row Col
212+ | LetIn Row Col
213+ | LetDefAlignment Word16 Row Col
214+ | LetDefName Row Col
215+ | LetDef Name.Name Def Row Col
216+ | LetDestruct Destruct Row Col
217+ | LetBody Expr Row Col
218+ | LetIndentDef Row Col
219+ | LetIndentIn Row Col
220+ | LetIndentBody Row Col
221+
222+
223+data Def
224+ = DefSpace Space Row Col
225+ | DefType Type Row Col
226+ | DefNameRepeat Name.Name Row Col
227+ | DefNameMatch Name.Name Name.Name Row Col
228+ | DefArg Pattern Row Col
229+ | DefEquals Row Col
230+ | DefBody Expr Row Col
231+ | DefIndentEquals Row Col
232+ | DefIndentType Row Col
233+ | DefIndentBody Row Col
234+ | DefAlignment Word16 Row Col
235+
236+
237+data Destruct
238+ = DestructSpace Space Row Col
239+ | DestructPattern Pattern Row Col
240+ | DestructEquals Row Col
241+ | DestructBody Expr Row Col
242+ | DestructIndentEquals Row Col
243+ | DestructIndentBody Row Col
244+
245+
246+
247+-- PATTERNS
248+
249+
250+data Pattern
251+ = PRecord PRecord Row Col
252+ | PTuple PTuple Row Col
253+ | PList PList Row Col
254+ --
255+ | PStart Row Col
256+ | PChar Char Row Col
257+ | PString String Row Col
258+ | PNumber Number Row Col
259+ | PFloat Int Row Col
260+ | PAlias Row Col
261+ | PWildcardNotVar Int Row Col
262+ | PSpace Space Row Col
263+ --
264+ | PIndentStart Row Col
265+ | PIndentAlias Row Col
266+
267+
268+data PRecord
269+ = PRecordOpen Row Col
270+ | PRecordEnd Row Col
271+ | PRecordField Row Col
272+ | PRecordSpace Space Row Col
273+ --
274+ | PRecordIndentOpen Row Col
275+ | PRecordIndentEnd Row Col
276+ | PRecordIndentField Row Col
277+
278+
279+data PTuple
280+ = PTupleOpen Row Col
281+ | PTupleEnd Row Col
282+ | PTupleExpr Pattern Row Col
283+ | PTupleSpace Space Row Col
284+ --
285+ | PTupleIndentOpen Row Col
286+ | PTupleIndentEnd Row Col
287+ | PTupleIndentExpr Row Col
288+
289+
290+data PList
291+ = PListOpen Row Col
292+ | PListEnd Row Col
293+ | PListExpr Pattern Row Col
294+ | PListSpace Space Row Col
295+ --
296+ | PListIndentOpen Row Col
297+ | PListIndentEnd Row Col
298+ | PListIndentExpr Row Col
299+
300+
301+
302+-- TYPES
132
303
133
304
305+data Type
306+ = TRecord TRecord Row Col
307+ | TTuple TTuple Row Col
308+ | TVariant Row Col
309+ | TArrow Row Col
310+ --
311+ | TStart Row Col
312+ | TSpace Space Row Col
313+ --
314+ | TIndentStart Row Col
134
315
135−-- TO REPORT
136
316
317+data TRecord
318+ = TRecordOpen Row Col
319+ | TRecordEnd Row Col
320+ --
321+ | TRecordField Row Col
322+ | TRecordColon Row Col
323+ | TRecordType Type Row Col
324+ --
325+ | TRecordSpace Space Row Col
326+ --
327+ | TRecordIndentOpen Row Col
328+ | TRecordIndentField Row Col
329+ | TRecordIndentColon Row Col
330+ | TRecordIndentType Row Col
331+ | TRecordIndentEnd Row Col
332+
333+
334+data TTuple
335+ = TTupleOpen Row Col
336+ | TTupleEnd Row Col
337+ | TTupleType Type Row Col
338+ | TTupleSpace Space Row Col
339+ --
340+ | TTupleIndentOpen Row Col
341+ | TTupleIndentType Row Col
342+ | TTupleIndentEnd Row Col
343+
344+
345+
346+-- LITERALS
347+
348+
349+data Char
350+ = CharEndless
351+ | CharEscape Escape
352+ | CharNotString Int
353+
354+
355+data String
356+ = StringEndless_Single
357+ | StringEndless_Multi
358+ | StringEscape Escape
137
359
138−toReport :: Code.Source -> Error -> Report.Report
139−toReport source err =
140− case err of
141− CommentOnNothing region ->
142− Report.Report "STRAY COMMENT" region [] $
143− Report.toCodeSnippet source region Nothing
144− (
145− "This documentation comment is not followed by anything."
146− ,
147− D.reflow $
148− "All documentation comments need to be right above the declaration they\
149− \ describe. Maybe some code got deleted or commented out by accident? Or\
150− \ maybe this comment is here by accident?"
151− )
152−
153− UnexpectedPort region name ->
154− Report.Report "BAD PORT" region [] $
155− Report.toCodeSnippet source region Nothing
156− (
157− D.reflow $
158− "You are declaring port `" <> Name.toString name <> "` in a normal module."
159− ,
160− D.stack
161− [ "It needs to be in a `port` module."
162− , D.link "Hint"
163− "Ports are not a traditional FFI for calling JS functions directly. They need a different mindset! Read"
164− "ports"
165− "to learn how to use ports effectively."
166− ]
167− )
168−
169− TypeWithBadDefinition region annName defName ->
170− Report.Report "ANNOTATION MISMATCH" region [] $
171− Report.toCodeSnippet source region Nothing
172− (
173− D.reflow $
174− "I see a `" <> Name.toString annName
175− <> "` annotation, but it is followed by a `"
176− <> Name.toString defName <> "` definition."
177− ,
178− D.fillSep
179− ["The","annotation","and","definition","names","must","match!"
180− ,"Is","there","a","typo","between"
181− , D.dullyellow (D.fromName annName)
182− ,"and"
183− , D.dullyellow (D.fromName defName) <> "?"
184− ]
185− )
186−
187− TypeWithoutDefinition region name ->
188− Report.Report "MISSING DEFINITION" region [] $
189− Report.toCodeSnippet source region Nothing
190− (
191− D.reflow $
192− "There is a type annotation for `" <> Name.toString name
193− <> "` but there is no corresponding definition!"
194− ,
195− "Directly below the type annotation, put a definition like:\n\n"
196− <> " " <> D.fromName name <> " = 42"
197− )
198−
199− Parse region subRegion problem ->
200− Report.Report "PARSE ERROR" (maybe region id subRegion) [] $
201− Report.toCodeSnippet source region subRegion $
202− problemToDocs problem
203−
204−
205−
206−-- PARSE ERROR TO DOCS
207−
208−
209−problemToDocs :: Problem -> (D.Doc, D.Doc)
210−problemToDocs problem =
211− case problem of
212− Tab ->
213− (
214− "I ran into a tab, but tabs are not allowed in Elm files."
215− ,
216− "Replace the tab with spaces."
217− )
218−
219− EndOfFile_Comment ->
220− (
221− "I got to the end of the file while parsing a multi-line comment."
222− ,
223− D.stack
224− [ D.reflow $
225− "Multi-line comments look like {- comment -}, and it looks like\
226− \ you are missing the closing marker."
227− , D.toSimpleHint $
228− "Nested multi-line comments like {- this {- and this -} -} are allowed.\
229− \ The opening and closing markers must be balanced though, just\
230− \ like parentheses in normal code. Maybe that is the problem?"
231− ]
232− )
233−
234− EndOfFile_Shader ->
235− (
236− "I got to the end of the file while parsing a GLSL block."
237− ,
238− D.reflow $
239− "A shader should be defined in a block like this: [glsl| ... |]"
240− )
241−
242− EndOfFile_String ->
243− (
244− "I got to the end of the file while parsing a string."
245− ,
246− D.reflow $
247− "Strings look like \"this\" with double quotes on each end.\
248− \ Is the closing double quote missing in your code?"
249− )
250−
251− EndOfFile_MultiString ->
252− (
253− "I got to the end of the file while parsing a multi-line string."
254− ,
255− D.reflow $
256− "Multi-line strings look like \"\"\"this\"\"\" with three double quotes on each\
257− \ end. Is the closing triple quote missing in your code?"
258− )
259−
260− EndOfFile_Char ->
261− (
262− "I got to the end of the file while parsing a character."
263− ,
264− D.reflow $
265− "Characters look like 'c' with single quotes on each end.\
266− \ Is the closing single quote missing in your code?"
267− )
268−
269− NewLineInString ->
270− (
271− "This string is missing the closing quote."
272− ,
273− D.stack
274− [ D.reflow $
275− "Elm strings like \"this\" cannot contain newlines."
276− , D.toSimpleHint $
277− "For strings that CAN contain newlines, say \"\"\"this\"\"\" for Elm’s\
278− \ multi-line string syntax. It allows unescaped newlines and double quotes."
279− ]
280− )
281−
282− NewLineInChar ->
283− (
284− "This character is missing the closing quote."
285− ,
286− "Elm characters must start and end with a single quote. Valid examples\n\
287− \ include 'a', 'b', '\n', 'ø', and '\\u{00F8}' for unicode code points."
288− )
289−
290− BadEscape _ escapeProblem ->
291− case escapeProblem of
292− UnknownEscape ->
293− (
294− "Backslashes always start escaped characters, but I do not recognize this one:"
295− , D.stack
296− [ "Maybe there is some typo?"
297− , D.toSimpleHint "Valid escape characters include:"
298− , D.indent 4 $ D.vcat $
299− [ "\\n"
300− , "\\r"
301− , "\\t"
302− , "\\\""
303− , "\\\'"
304− , "\\\\"
305− , "\\u{03BB}"
306− ]
307− , D.reflow $
308− "The last one lets encode ANY character by its Unicode code\
309− \ point, so use that for anything outside the ordinary six."
310− ]
311− )
312−
313− UnicodeSyntax ->
314− (
315− "I ran into an invalid Unicode escape character:"
316− ,
317− D.stack
318− [ "Here are some examples of valid Unicode escape characters:"
319− , D.indent 4 $ D.vcat $
320− [ "\\u{0041}"
321− , "\\u{03BB}"
322− , "\\u{6728}"
323− , "\\u{1F60A}"
324− ]
325− , D.reflow $
326− "Notice that the code point is always surrounded by curly\
327− \ braces. They are required!"
328− ]
329− )
330−
331− UnicodeRange ->
332− (
333− "This is not a real Unicode code point:"
334− ,
335− "All valid Unicode code points are between 0 and 10FFFF."
336− )
337−
338− UnicodeLength numDigits badCode ->
339− if numDigits < 4 then
340− (
341− "Every Unicode code point needs at least four digits:"
342− ,
343− let
344− goodCode = replicate (4 - numDigits) '0' ++ badCode
345− escape = "\\u{" <> D.fromString goodCode <> "}"
346− in
347− D.hsep [ "Try", D.dullyellow escape, "instead?" ]
348− )
349−
350− else
351− (
352− "This Unicode code point has too many digits:"
353− ,
354− D.fillSep
355− ["Valid","code","points","are","between"
356− , D.dullyellow "\\u{0000}", "and", D.dullyellow "\\u{10FFFF}"
357− ,"so","it","must","have","between","four","and","six","digits."
358− ]
359− )
360−
361− BadChar _ ->
362− (
363− "Ran into a bad use of single quotes."
364− ,
365− D.stack
366− [ D.reflow $
367− "If you want to create a string, switch to double quotes:"
368− , D.indent 4 $
369− D.dullyellow "'this'" <> " => " <> D.green "\"this\""
370− , D.toSimpleHint $
371− "Unlike JavaScript, Elm distinguishes between strings like \"hello\"\
372− \ and individual characters like 'A' and '3'. If you really do want\
373− \ a character though, something went wrong and I did not find the\
374− \ closing single quote."
375− ]
376− )
377−
378− BadNumberDot numberBeforeDot ->
379− (
380− "Numbers cannot end with a decimal points."
381− ,
382− let
383− number =
384− D.fromString (show numberBeforeDot)
385− in
386− "Saying " <> D.green number <> " or " <> D.green (number <> ".0") <> " will work though!"
387− )
388−
389− BadNumberEnd ->
390− (
391− "Numbers cannot have letters or underscores in them."
392− ,
393− D.reflow $
394− "Maybe a space is missing between a number and a variable?"
395− )
396−
397− BadNumberExp ->
398− (
399− "If you put the letter E in a number, it should followed by more digits."
400− ,
401− D.reflow $
402− "If you want to say 1000, you can also say 1e3.\
403− \ You cannot just end it with an E though!"
404− )
405−
406− BadNumberHex ->
407− (
408− "I see the start of a hex number, but not the end."
409− ,
410− D.reflow $
411− "A hex number looks like 0x123ABC, where the 0x is followed by hexidecimal\
412− \ digits. Valid hexidecimal digits include: 0123456789abcdefABCDEF"
413− )
414−
415− BadNumberZero ->
416− (
417− "Normal numbers cannot start with zeros. Take the zeros off the front."
418− ,
419− D.reflow $
420− "Only numbers like 0x0040 or 0.25 can start with a zero."
421− )
422−
423− FloatInPattern ->
424− (
425− "I cannot pattern match with floating point numbers:"
426− ,
427− D.reflow $
428− "Equality on floats can be unreliable, so you usually want to check that they\
429− \ are nearby with some sort of (abs (actual - expected) < 0.001) check."
430− )
431−
432− BadShader msg ->
433− (
434− "I ran into a problem while parsing this GLSL block."
435− ,
436− D.reflow (Text.unpack msg)
437− )
438−
439− BadUnderscore _ ->
440− (
441− "A variable name cannot start with an underscore:"
442− ,
443− D.reflow $
444− "You can (1) use a wildcard like _ to ignore the value or you can (2) use\
445− \ a name that starts with a letter to access the value later. Pick one!"
446− )
447−
448− BadOp op stack ->
449− case op of
450− HasType ->
451− badOp stack "A" "\"has type\" operator"
452− "type annotations and record types"
453− "Maybe you want :: instead? Or maybe something is indented too much?"
454−
455− Equals ->
456− (
457− D.reflow $
458− "I was not expecting this equals sign"
459− <> contextToString " here" " while parsing " stack <> "."
460− ,
461− toBadEqualsHint stack
462− )
463−
464− Arrow ->
465− if isCaseRelated stack then
466− (
467− "I ran into a stray arrow while parsing this `case` expression."
468− ,
469− D.reflow $
470− "All branches in a `case` must be indented the exact\
471− \ same amount, so the patterns are vertically\
472− \ aligned. Maybe this branch is indented too much?"
473− )
474−
475− else
476− badOp stack "An" "arrow"
477− "cases expressions and anonymous functions"
478− "Maybe you want > or >= instead?"
479−
480− Pipe ->
481− badOp stack "A" "vertical bar"
482− "type declarations"
483− "Maybe you want || instead?"
484−
485− Dot ->
486− (
487− "I was not expecting this dot."
488− ,
489− D.reflow $
490− "Dots are for record access and decimal points, so\
491− \ they cannot float around on their own. Maybe\
492− \ there is some extra whitespace?"
493− )
494−
495− Theories stack allTheories ->
496− (
497− D.reflow $
498− "Something went wrong while parsing " <> contextToString "your code" "" stack <> "."
499− ,
500− case Set.toList (Set.fromList allTheories) of
501− [] ->
502− D.stack
503− [ D.reflow $
504− "I do not have any suggestions though!"
505− , D.reflow $
506− "Can you get it down to a <http://sscce.org> and share it at\
507− \ <https://github.com/elm/error-message-catalog/issues>?\
508− \ That way we can figure out how to give better advice!"
509− ]
510−
511− [theory] ->
512− D.reflow $
513− "I was expecting to see "
514− <> addPeriod (theoryToString stack theory)
515−
516− theories ->
517− D.vcat $
518− [ "I was expecting:"
519− , ""
520− ]
521− ++ map (bullet . theoryToString stack) theories
522− )
523−
524−
525−
526−-- BAD OP HELPERS
527−
528−
529−badOp :: ContextStack -> String -> String -> String -> String -> ( D.Doc, D.Doc )
530−badOp stack article opName setting hint =
531− (
532− D.reflow $
533− "I was not expecting this " <> opName
534− <> contextToString " here" " while parsing " stack <> "."
535− ,
536− D.reflow $
537− article <> " " <> opName <> " should only appear in "
538− <> setting <> ". " <> hint
539− )
540
360
361+data Escape
362+ = EscapeUnknown Word16 Word16
363+ | BadUnicodeFormat Word16 Word16
364+ | BadUnicodeCode Word16 Word16
365+ | BadUnicodeLength Word16 Word16 Int Int
541
366
542−toBadEqualsHint :: ContextStack -> D.Doc
543−toBadEqualsHint stack =
544− case stack of
545− [] ->
546− D.reflow $
547− "Maybe you want == instead? Or maybe something is indented too much?"
548
367
549− (ExprRecord, _) : _ ->
368+data Number
550− D.reflow $
369+ = NumberEnd
551− "Records look like { x = 3, y = 4 } with the equals sign right\
370+ | NumberDot Int
552− \ after the field name. Maybe you forgot a comma?"
371+ | NumberHexDigit
372+ | NumberNoLeadingZero
553
373
554− (Definition _, _) : rest ->
374+
555− D.reflow $
375+
556− "Maybe this is supposed to be a separate definition? If so, it\
376+-- MISC
557− \ is indented too far. "
377+
558− <>
378+
559− if any ((==) ExprLet . fst) rest then
379+data Space
560− "All definitions in a `let` expression must be vertically aligned."
380+ = HasTab
561− else
381+ | EndlessMultiComment
562− "Spaces are not allowed before top-level definitions."
382+ | UnexpectedDocComment
563−
383+
564− _ : rest ->
384+
565− toBadEqualsHint rest
385+data Operator
566−
386+ = OpDot
567−
387+ | OpPipe
568−
388+ | OpArrow
569−isCaseRelated :: ContextStack -> Bool
389+ | OpEquals
570−isCaseRelated stack =
390+ | OpHasType
571− case stack of
391+
572− [] ->
392+
573− False
393+
574−
394+-- TO REPORT
575− (context, _) : rest ->
395+
576− context == ExprCase || isCaseRelated rest
396+
577−
397+toReport :: Code.Source -> Error -> Report.Report
578−
398+toReport source err =
579−
399+ error "TODO" source err
580−-- CONTEXT
581−
582−
583−contextToString :: String -> String -> ContextStack -> String
584−contextToString defaultString prefixString stack =
585− case stack of
586− [] ->
587− defaultString
588−
589− (context, _) : rest ->
590− let anchor = getAnchor rest in
591− prefixString <>
592− case context of
593− ExprIf -> "an `if` expression" <> anchor
594− ExprLet -> "a `let` expression" <> anchor
595− ExprFunc -> "an anonymous function" <> anchor
596− ExprCase -> "a `case` expression" <> anchor
597− ExprList -> "a list" <> anchor
598− ExprTuple -> "an expression (in parentheses)" <> anchor
599− ExprRecord -> "a record" <> anchor
600− Definition name -> Name.toString name <> "'s definition"
601− Annotation name -> Name.toString name <> "'s type annotation"
602− TypeTuple -> "a type (in parentheses)" <> anchor
603− TypeRecord -> "a record type" <> anchor
604− PatternList -> "a list pattern" <> anchor
605− PatternTuple -> "a pattern (in parentheses)" <> anchor
606− PatternRecord -> "a record pattern" <> anchor
607− Module -> "a module declaration"
608− Import -> "an import"
609− TypeUnion -> "a union type"
610− TypeAlias -> "a type alias"
611− Infix -> "an infix declaration"
612− Port -> "a port declaration"
613−
614−
615−getAnchor :: ContextStack -> String
616−getAnchor stack =
617− case stack of
618− [] ->
619− ""
620−
621− (context, _) : rest ->
622− case context of
623− Definition name ->
624− " in " <> Name.toString name <> "'s definition"
625−
626− Annotation name ->
627− " in " <> Name.toString name <> "'s type annotation"
628−
629− _ ->
630− getAnchor rest
631−
632−
633−
634−-- THEORY HELPERS
635−
636−
637−bullet :: String -> D.Doc
638−bullet point =
639− D.hang 4 (" - " <> D.fillSep (map D.fromString (words point)))
640−
641−
642−addPeriod :: String -> String
643−addPeriod msg =
644− if last msg `elem` ['`', ')', '.', '!', '?'] then
645− msg
646− else
647− msg <> "."
648−
649−
650−theoryToString :: ContextStack -> Theory -> String
651−theoryToString context theory =
652− case theory of
653− Keyword keyword ->
654− "the `" <> keyword <> "` keyword"
655−
656− Symbol symbol ->
657− case symbol of
658− "=" -> equalsTheory context
659− "->" -> "an arrow (->) followed by an expression"
660− ":" -> "the \"has type\" symbol (:) followed by a type"
661− "," -> "a comma"
662− "|" -> barTheory context
663− "::" -> "the cons operator (::) followed by more list elements"
664− "." -> "a dot (.)"
665− "-" -> "a minus sign (-)"
666− "_" -> "an underscore"
667− "(" -> "a left paren, for grouping or starting tuples"
668− ")" -> "a closing paren"
669− "[" -> "a left square bracket, for starting lists"
670− "]" -> "a right square bracket, to end a list"
671− "{" -> "a left curly brace, for starting records"
672− "}" -> "a right curly brace, to end a record"
673− "{-|" -> "a doc comment, like {-| this -}"
674− _ -> "the (" <> symbol <> ") symbol"
675−
676− LowVar ->
677− "a lower-case variable, like `x` or `user`"
678−
679− CapVar ->
680− "an upper-case variable, like `Maybe` or `Just`"
681−
682− InfixOp ->
683− "an infix operator, like (+) or (==)"
684−
685− Digit ->
686− "a digit from 0 to 9"
687−
688− BadSpace ->
689− badSpace context
690−
691− Expecting next ->
692− case next of
693− Decl -> "a declaration, like `x = 5` or `type alias Model = { ... }`"
694− Expr -> "an expression, like x or 42"
695− AfterOpExpr op -> "an expression after that (" <> Name.toString op <> ") operator, like x or 42"
696− ElseBranch -> "an `else` branch. An `if` must handle both possibilities."
697− Arg -> "an argument, like `name` or `total`"
698− Pattern -> "a pattern, like `name` or (Just x)"
699− Type -> "a type, like Int or (List String)"
700− Listing -> "a list of exposed values and types, like (..) or (x,y,z)"
701− Exposing -> "something like `exposing (..)`"
702−
703−
704−equalsTheory :: ContextStack -> String
705−equalsTheory stack =
706− case stack of
707− [] ->
708− "an equals sign (=)"
709−
710− (context, _) : rest ->
711− case context of
712− ExprRecord -> "an equals sign (=) followed by an expression"
713− Definition name -> "an equals sign (=) followed by " <> Name.toString name <> "'s definition"
714− TypeUnion -> "an equals sign (=) followed by the first union type constructor"
715− TypeAlias -> "an equals sign (=) followed by the aliased type"
716− _ -> equalsTheory rest
717−
718−
719−barTheory :: ContextStack -> String
720−barTheory stack =
721− case stack of
722− [] ->
723− "a vertical bar (|)"
724−
725− (context, _) : rest ->
726− case context of
727− ExprRecord -> "a vertical bar (|) followed by the record fields you want to update"
728− TypeRecord -> "a vertical bar (|) followed by some record field types"
729− TypeUnion -> "a vertical bar (|) followed by more union type constructors"
730− _ -> barTheory rest
731−
732−
733−badSpace :: ContextStack -> String
734−badSpace stack =
735− case stack of
736− [] ->
737− "more indentation? I was not done with that last thing yet."
738−
739− (context, _) : rest ->
740− case context of
741− ExprIf -> "the end of that `if`" <> badSpaceExprEnd rest
742− ExprLet -> "the end of that `let`" <> badSpaceExprEnd rest
743− ExprFunc -> badSpace rest
744− ExprCase -> "more of that `case`" <> badSpaceExprEnd rest
745− ExprList -> "the end of that list" <> badSpaceExprEnd rest
746− ExprTuple -> "a closing paren" <> badSpaceExprEnd rest
747− ExprRecord -> "the end of that record" <> badSpaceExprEnd rest
748− Definition name -> "the rest of " <> Name.toString name <> "'s definition" <> badSpaceExprEnd stack
749− Annotation name -> "the rest of " <> Name.toString name <> "'s type annotation" <> badSpaceEnd
750− TypeTuple -> "a closing paren" <> badSpaceEnd
751− TypeRecord -> "the end of that record" <> badSpaceEnd
752− PatternList -> "the end of that list" <> badSpaceEnd
753− PatternTuple -> "a closing paren" <> badSpaceEnd
754− PatternRecord -> "the end of that record" <> badSpaceEnd
755− Module -> "something like `module Main exposing (..)`"
756− Import -> "something like `import Html exposing (..)`"
757− TypeUnion -> "more of that union type" <> badSpaceEnd
758− TypeAlias -> "more of that type alias" <> badSpaceEnd
759− Infix -> "more of that infix declaration" <> badSpaceEnd
760− Port -> "more of that port declaration" <> badSpaceEnd
761−
762−
763−badSpaceEnd :: String
764−badSpaceEnd =
765− ". Maybe you forgot some code? Or you need more indentation?"
766−
767−
768−badSpaceExprEnd :: ContextStack -> String
769−badSpaceExprEnd stack =
770− case stack of
771− [] ->
772− badSpaceEnd
773−
774− (Definition name, R.Position _ column) : _ ->
775− let
776− ending =
777− if column <= 1 then
778− "to be indented?"
779− else
780− "more indentation? (Try " <> show (column + 1) <> "+ spaces.)"
781− in
782− ". Maybe you forgot some code? Or maybe the body of `"
783− <> Name.toString name
784− <> "` needs " <> ending
785−
786− _ : rest ->
787− badSpaceExprEnd rest