@@ -2,25 +2,55 @@
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Reporting.Error.Syntax
3module Reporting.Error.Syntax
4 ( Error(..)
4 ( Error(..)
6− , Problem(..), Theory(..)
6+ , Decl(..)
7− , EscapeProblem(..)
7+ , Infix(..)
8− , ContextStack, Context(..)
8+ , CustomType(..)
9− , BadOp(..), Next(..)
9+ --
10 , toReport
37 , toReport
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)
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
@@ -28,760 +58,342 @@ import qualified Reporting.Report as Report
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+
42−data ParseError = ParseError !Int !Int !Problem
50− | EndOfFile_MultiString
54− | BadEscape Int EscapeProblem
62− | BadShader Text.Text
64− | BadOp BadOp ContextStack
65− | Theories ContextStack [Theory]
72− | UnicodeLength Int String
75−data BadOp = HasType | Equals | Arrow | Pipe | Dot
93− | AfterOpExpr Name.Name
103−type ContextStack = [(Context, R.Position)]
115− | Definition Name.Name
116− | Annotation Name.Name
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
81+ | EndlessDocComment Row Col
82+ | DeclSpace Space Row Col
83+ | DeclDeadend Row Col
88+ | Associativity Row Col
93+ | CT_Space Space Row Col
94+ | CT_Type Type Row Col
106+ | Record Record Row Col
107+ | Update Expr Row Col
108+ | Tuple Tuple Row Col
113+ | OperatorRHS Row Col
114+ | OperatorRight Row Col
115+ | OperatorReserved Operator 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
129+ = RecordOpen Row Col
131+ | RecordField Row Col
132+ | RecordEquals Row Col
133+ | RecordExpr Expr Row Col
134+ | RecordSpace Space Row Col
136+ | RecordIndentOpen Row Col
137+ | RecordIndentEnd Row Col
138+ | RecordIndentField Row Col
139+ | RecordIndentEquals Row Col
140+ | RecordIndentExpr Row Col
145+ | TupleExpr Expr Row Col
146+ | TupleSpace Space Row Col
148+ | TupleOperatorClose Row Col
149+ | TupleOperatorReserved Operator Row Col
151+ | TupleIndentExpr Row Col
152+ | TupleIndentEnd Row Col
156+ = ListSpace Space Row Col
158+ | ListExpr Expr Row Col
161+ | ListIndentOpen Row Col
162+ | ListIndentEnd Row Col
163+ | ListIndentExpr Row Col
167+ = FuncSpace Space Row Col
168+ | FuncArg Pattern Row Col
169+ | FuncBody Expr Row Col
172+ | FuncIndentArg Row Col
173+ | FuncIndentArrow Row Col
174+ | FuncIndentBody Row Col
178+ = CaseSpace Space Row Col
180+ | CasePattern Pattern Row Col
182+ | CaseExpr Expr Row Col
183+ | CaseBranch Expr Row Col
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
194+ = IfSpace Space Row Col
197+ | IfElseBranchStart Row Col
199+ | IfCondition Expr Row Col
200+ | IfThenBranch Expr Row Col
201+ | IfElseBranch Expr Row Col
203+ | IfIndentCondition Row Col
204+ | IfIndentThen Row Col
205+ | IfIndentThenBranch Row Col
206+ | IfIndentElseBranch Row Col
207+ | IfIndentElse Row Col
211+ = LetSpace Space 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
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
230+ | DefBody Expr Row Col
231+ | DefIndentEquals Row Col
232+ | DefIndentType Row Col
233+ | DefIndentBody Row Col
234+ | DefAlignment Word16 Row Col
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
251+ = PRecord PRecord Row Col
252+ | PTuple PTuple Row Col
253+ | PList PList Row Col
256+ | PChar Char Row Col
257+ | PString String Row Col
258+ | PNumber Number Row Col
259+ | PFloat Int Row Col
261+ | PWildcardNotVar Int Row Col
262+ | PSpace Space Row Col
264+ | PIndentStart Row Col
265+ | PIndentAlias Row Col
269+ = PRecordOpen Row Col
270+ | PRecordEnd Row Col
271+ | PRecordField Row Col
272+ | PRecordSpace Space Row Col
274+ | PRecordIndentOpen Row Col
275+ | PRecordIndentEnd Row Col
276+ | PRecordIndentField Row Col
280+ = PTupleOpen Row Col
282+ | PTupleExpr Pattern Row Col
283+ | PTupleSpace Space Row Col
285+ | PTupleIndentOpen Row Col
286+ | PTupleIndentEnd Row Col
287+ | PTupleIndentExpr Row Col
293+ | PListExpr Pattern Row Col
294+ | PListSpace Space Row Col
296+ | PListIndentOpen Row Col
297+ | PListIndentEnd Row Col
298+ | PListIndentExpr Row Col
306+ = TRecord TRecord Row Col
307+ | TTuple TTuple Row Col
312+ | TSpace Space Row Col
314+ | TIndentStart Row Col
318+ = TRecordOpen Row Col
319+ | TRecordEnd Row Col
321+ | TRecordField Row Col
322+ | TRecordColon Row Col
323+ | TRecordType Type Row Col
325+ | TRecordSpace Space Row Col
327+ | TRecordIndentOpen Row Col
328+ | TRecordIndentField Row Col
329+ | TRecordIndentColon Row Col
330+ | TRecordIndentType Row Col
331+ | TRecordIndentEnd Row Col
335+ = TTupleOpen Row Col
337+ | TTupleType Type Row Col
338+ | TTupleSpace Space Row Col
340+ | TTupleIndentOpen Row Col
341+ | TTupleIndentType Row Col
342+ | TTupleIndentEnd Row Col
356+ = StringEndless_Single
357+ | StringEndless_Multi
358+ | StringEscape Escape
138−toReport :: Code.Source -> Error -> Report.Report
139−toReport source err =
141− CommentOnNothing region ->
142− Report.Report "STRAY COMMENT" region [] $
143− Report.toCodeSnippet source region Nothing
145− "This documentation comment is not followed by anything."
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?"
153− UnexpectedPort region name ->
154− Report.Report "BAD PORT" region [] $
155− Report.toCodeSnippet source region Nothing
158− "You are declaring port `" <> Name.toString name <> "` in a normal module."
161− [ "It needs to be in a `port` module."
163− "Ports are not a traditional FFI for calling JS functions directly. They need a different mindset! Read"
165− "to learn how to use ports effectively."
169− TypeWithBadDefinition region annName defName ->
170− Report.Report "ANNOTATION MISMATCH" region [] $
171− Report.toCodeSnippet source region Nothing
174− "I see a `" <> Name.toString annName
175− <> "` annotation, but it is followed by a `"
176− <> Name.toString defName <> "` definition."
179− ["The","annotation","and","definition","names","must","match!"
180− ,"Is","there","a","typo","between"
181− , D.dullyellow (D.fromName annName)
183− , D.dullyellow (D.fromName defName) <> "?"
187− TypeWithoutDefinition region name ->
188− Report.Report "MISSING DEFINITION" region [] $
189− Report.toCodeSnippet source region Nothing
192− "There is a type annotation for `" <> Name.toString name
193− <> "` but there is no corresponding definition!"
195− "Directly below the type annotation, put a definition like:\n\n"
196− <> " " <> D.fromName name <> " = 42"
199− Parse region subRegion problem ->
200− Report.Report "PARSE ERROR" (maybe region id subRegion) [] $
201− Report.toCodeSnippet source region subRegion $
202− problemToDocs problem
206−-- PARSE ERROR TO DOCS
209−problemToDocs :: Problem -> (D.Doc, D.Doc)
210−problemToDocs problem =
214− "I ran into a tab, but tabs are not allowed in Elm files."
216− "Replace the tab with spaces."
219− EndOfFile_Comment ->
221− "I got to the end of the file while parsing a multi-line comment."
225− "Multi-line comments look like {- comment -}, and it looks like\
226− \ you are missing the closing marker."
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?"
236− "I got to the end of the file while parsing a GLSL block."
239− "A shader should be defined in a block like this: [glsl| ... |]"
244− "I got to the end of the file while parsing a string."
247− "Strings look like \"this\" with double quotes on each end.\
248− \ Is the closing double quote missing in your code?"
251− EndOfFile_MultiString ->
253− "I got to the end of the file while parsing a multi-line string."
256− "Multi-line strings look like \"\"\"this\"\"\" with three double quotes on each\
257− \ end. Is the closing triple quote missing in your code?"
262− "I got to the end of the file while parsing a character."
265− "Characters look like 'c' with single quotes on each end.\
266− \ Is the closing single quote missing in your code?"
271− "This string is missing the closing quote."
275− "Elm strings like \"this\" cannot contain newlines."
277− "For strings that CAN contain newlines, say \"\"\"this\"\"\" for Elm’s\
278− \ multi-line string syntax. It allows unescaped newlines and double quotes."
284− "This character is missing the closing quote."
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."
290− BadEscape _ escapeProblem ->
291− case escapeProblem of
294− "Backslashes always start escaped characters, but I do not recognize this one:"
296− [ "Maybe there is some typo?"
297− , D.toSimpleHint "Valid escape characters include:"
298− , D.indent 4 $ D.vcat $
308− "The last one lets encode ANY character by its Unicode code\
309− \ point, so use that for anything outside the ordinary six."
315− "I ran into an invalid Unicode escape character:"
318− [ "Here are some examples of valid Unicode escape characters:"
319− , D.indent 4 $ D.vcat $
326− "Notice that the code point is always surrounded by curly\
327− \ braces. They are required!"
333− "This is not a real Unicode code point:"
335− "All valid Unicode code points are between 0 and 10FFFF."
338− UnicodeLength numDigits badCode ->
339− if numDigits < 4 then
341− "Every Unicode code point needs at least four digits:"
344− goodCode = replicate (4 - numDigits) '0' ++ badCode
345− escape = "\\u{" <> D.fromString goodCode <> "}"
347− D.hsep [ "Try", D.dullyellow escape, "instead?" ]
352− "This Unicode code point has too many digits:"
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."
363− "Ran into a bad use of single quotes."
367− "If you want to create a string, switch to double quotes:"
369− D.dullyellow "'this'" <> " => " <> D.green "\"this\""
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."
378− BadNumberDot numberBeforeDot ->
380− "Numbers cannot end with a decimal points."
384− D.fromString (show numberBeforeDot)
386− "Saying " <> D.green number <> " or " <> D.green (number <> ".0") <> " will work though!"
391− "Numbers cannot have letters or underscores in them."
394− "Maybe a space is missing between a number and a variable?"
399− "If you put the letter E in a number, it should followed by more digits."
402− "If you want to say 1000, you can also say 1e3.\
403− \ You cannot just end it with an E though!"
408− "I see the start of a hex number, but not the end."
411− "A hex number looks like 0x123ABC, where the 0x is followed by hexidecimal\
412− \ digits. Valid hexidecimal digits include: 0123456789abcdefABCDEF"
417− "Normal numbers cannot start with zeros. Take the zeros off the front."
420− "Only numbers like 0x0040 or 0.25 can start with a zero."
425− "I cannot pattern match with floating point numbers:"
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."
434− "I ran into a problem while parsing this GLSL block."
436− D.reflow (Text.unpack msg)
441− "A variable name cannot start with an underscore:"
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!"
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?"
458− "I was not expecting this equals sign"
459− <> contextToString " here" " while parsing " stack <> "."
461− toBadEqualsHint stack
465− if isCaseRelated stack then
467− "I ran into a stray arrow while parsing this `case` expression."
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?"
476− badOp stack "An" "arrow"
477− "cases expressions and anonymous functions"
478− "Maybe you want > or >= instead?"
481− badOp stack "A" "vertical bar"
483− "Maybe you want || instead?"
487− "I was not expecting this dot."
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?"
495− Theories stack allTheories ->
498− "Something went wrong while parsing " <> contextToString "your code" "" stack <> "."
500− case Set.toList (Set.fromList allTheories) of
504− "I do not have any suggestions though!"
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!"
513− "I was expecting to see "
514− <> addPeriod (theoryToString stack theory)
518− [ "I was expecting:"
521− ++ map (bullet . theoryToString stack) theories
529−badOp :: ContextStack -> String -> String -> String -> String -> ( D.Doc, D.Doc )
530−badOp stack article opName setting hint =
533− "I was not expecting this " <> opName
534− <> contextToString " here" " while parsing " stack <> "."
537− article <> " " <> opName <> " should only appear in "
538− <> setting <> ". " <> hint
362+ = EscapeUnknown Word16 Word16
363+ | BadUnicodeFormat Word16 Word16
364+ | BadUnicodeCode Word16 Word16
365+ | BadUnicodeLength Word16 Word16 Int Int
542−toBadEqualsHint :: ContextStack -> D.Doc
543−toBadEqualsHint stack =
547− "Maybe you want == instead? Or maybe something is indented too much?"
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
554− (Definition _, _) : rest ->
374+
556− "Maybe this is supposed to be a separate definition? If so, it\
376+-- MISC
557− \ is indented too far. "
377+
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
565− toBadEqualsHint rest
385+data Operator
569−isCaseRelated :: ContextStack -> Bool
389+ | OpEquals
570−isCaseRelated stack =
390+ | OpHasType
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
583−contextToString :: String -> String -> ContextStack -> String
584−contextToString defaultString prefixString stack =
589− (context, _) : rest ->
590− let anchor = getAnchor rest in
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"
615−getAnchor :: ContextStack -> String
621− (context, _) : rest ->
624− " in " <> Name.toString name <> "'s definition"
627− " in " <> Name.toString name <> "'s type annotation"
637−bullet :: String -> D.Doc
639− D.hang 4 (" - " <> D.fillSep (map D.fromString (words point)))
642−addPeriod :: String -> String
644− if last msg `elem` ['`', ')', '.', '!', '?'] then
650−theoryToString :: ContextStack -> Theory -> String
651−theoryToString context theory =
654− "the `" <> keyword <> "` keyword"
658− "=" -> equalsTheory context
659− "->" -> "an arrow (->) followed by an expression"
660− ":" -> "the \"has type\" symbol (:) followed by a type"
662− "|" -> barTheory context
663− "::" -> "the cons operator (::) followed by more list elements"
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"
677− "a lower-case variable, like `x` or `user`"
680− "an upper-case variable, like `Maybe` or `Just`"
683− "an infix operator, like (+) or (==)"
686− "a digit from 0 to 9"
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 (..)`"
704−equalsTheory :: ContextStack -> String
708− "an equals sign (=)"
710− (context, _) : rest ->
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
719−barTheory :: ContextStack -> String
723− "a vertical bar (|)"
725− (context, _) : rest ->
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"
733−badSpace :: ContextStack -> String
737− "more indentation? I was not done with that last thing yet."
739− (context, _) : rest ->
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
763−badSpaceEnd :: String
765− ". Maybe you forgot some code? Or you need more indentation?"
768−badSpaceExprEnd :: ContextStack -> String
769−badSpaceExprEnd stack =
774− (Definition name, R.Position _ column) : _ ->
780− "more indentation? (Try " <> show (column + 1) <> "+ spaces.)"
782− ". Maybe you forgot some code? Or maybe the body of `"
783− <> Name.toString name
784− <> "` needs " <> ending
787− badSpaceExprEnd rest