@@ -1,9 +1,11 @@
11module Parse.Binop (infixOp, binops, OpTable) where
22
3−import Control.Monad (guard)
43import qualified Data.List as List
54import qualified Data.Map as Map
6−import Text.Parsec ((<|>), choice, getState, lower, many1, notFollowedBy, satisfy, try)
5+import Text.Parsec
6+ ( (<|>), choice, getState, lookAhead, lower, many1
7+ , notFollowedBy, satisfy, string, try
8+ )
79
810import AST.Declaration (Assoc(L, N, R))
911import AST.Expression.General (Expr'(Binop))
@@ -20,12 +22,34 @@ import qualified Reporting.Annotation as A
2022
2123infixOp :: IParser String
2224infixOp =
25+ infixOpWith notReserved
26+
27+
28+infixOpWith :: IParser String -> IParser String
29+infixOpWith checker =
2330 expecting "an infix operator like (+)" $
24− do op <- many1 (satisfy (\c -> Help.isSymbol c))
25− guard (op `notElem` [ "=", "->", "--", "|", ":" ])
31+ do op <- checker <|> many1 (satisfy Help.isSymbol)
2632 case op of
2733 "." -> notFollowedBy lower >> return op
28− _ -> return op
34+ _ -> return op
35+
36+
37+failOn :: String -> String -> IParser a
38+failOn op msg =
39+ do try $ lookAhead $ do
40+ string op
41+ notFollowedBy (satisfy Help.isSymbol)
42+ failure msg
43+
44+
45+notReserved :: IParser a
46+notReserved =
47+ choice
48+ [ failOn "=" "The = operator is reserved for defining variables. Maybe you want == instead?"
49+ , failOn "->" "Arrows are reserved for cases and anonymous functions. Maybe you want > or >= instead?"
50+ , failOn "|" "Vertical bars are reserved for use in union type declarations. Maybe you want || instead?"
51+ , failOn ":" "A singe colon is for type annotations. Maybe you want :: instead?"
52+ ]
2953
3054
3155
@@ -58,7 +82,7 @@ binops term last =
5882 where
5983 nextOps =
6084 choice
61− [ commitIf (whitespace >> infixOp) $
85+ [ commitIf (whitespace >> infixOpWith (fail "")) $
6286 do whitespace
6387 op <- infixOp
6488 whitespace