@@ -1,9 +1,11 @@
1module Parse.Binop (infixOp, binops, OpTable) where
1module Parse.Binop (infixOp, binops, OpTable) where
3−import Control.Monad (guard)
4import qualified Data.List as List
3import qualified Data.List as List
5import qualified Data.Map as Map
4import qualified Data.Map as Map
6−import Text.Parsec ((<|>), choice, getState, lower, many1, notFollowedBy, satisfy, try)
6+ ( (<|>), choice, getState, lookAhead, lower, many1
7+ , notFollowedBy, satisfy, string, try
8import AST.Declaration (Assoc(L, N, R))
10import AST.Declaration (Assoc(L, N, R))
9import AST.Expression.General (Expr'(Binop))
11import AST.Expression.General (Expr'(Binop))
@@ -20,12 +22,34 @@ import qualified Reporting.Annotation as A
21infixOp :: IParser String
23infixOp :: IParser String
25+ infixOpWith notReserved
28+infixOpWith :: IParser String -> IParser String
23 expecting "an infix operator like (+)" $
30 expecting "an infix operator like (+)" $
24− do op <- many1 (satisfy (\c -> Help.isSymbol c))
31+ do op <- checker <|> many1 (satisfy Help.isSymbol)
25− guard (op `notElem` [ "=", "->", "--", "|", ":" ])
26 case op of
32 case op of
27 "." -> notFollowedBy lower >> return op
33 "." -> notFollowedBy lower >> return op
28− _ -> return op
34+ _ -> return op
37+failOn :: String -> String -> IParser a
39+ do try $ lookAhead $ do
41+ notFollowedBy (satisfy Help.isSymbol)
45+notReserved :: IParser a
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?"
@@ -58,7 +82,7 @@ binops term last =
61− [ commitIf (whitespace >> infixOp) $
85+ [ commitIf (whitespace >> infixOpWith (fail "")) $
62 do whitespace
86 do whitespace
63 op <- infixOp
87 op <- infixOp
64 whitespace
88 whitespace