2012-11-23 04:15:59 +00:00
|
|
|
module Parse.Binops (binops) where
|
2012-04-19 06:32:10 +00:00
|
|
|
|
|
|
|
import Ast
|
|
|
|
import Control.Monad (liftM,guard)
|
2012-04-21 06:15:30 +00:00
|
|
|
import Control.Monad.Error
|
2012-12-25 08:39:18 +00:00
|
|
|
import Data.List (foldl',splitAt,elemIndices
|
|
|
|
,group,groupBy,sortBy,find,intercalate)
|
2012-04-27 15:36:57 +00:00
|
|
|
import qualified Data.Map as Map
|
2012-04-19 06:32:10 +00:00
|
|
|
import Data.Maybe (mapMaybe)
|
|
|
|
|
2013-05-29 23:20:38 +00:00
|
|
|
import Located (epos)
|
2012-06-10 04:21:16 +00:00
|
|
|
import Text.Parsec
|
2012-11-23 04:15:59 +00:00
|
|
|
import Parse.Library
|
2012-06-10 04:21:16 +00:00
|
|
|
|
|
|
|
data Assoc = L | N | R deriving (Eq,Show)
|
2012-04-19 06:32:10 +00:00
|
|
|
|
2012-12-25 08:39:18 +00:00
|
|
|
type OpTable = [(Int, Assoc, String)]
|
|
|
|
|
|
|
|
table :: OpTable
|
2013-04-22 17:24:37 +00:00
|
|
|
table = [ (9, R, ".")
|
2012-08-07 11:39:03 +00:00
|
|
|
, (8, R, "^")
|
|
|
|
, (7, L, "*"), (7, L, "/"), (7, L, "mod"), (7, L, "div"), (7, L, "rem")
|
2012-04-19 06:32:10 +00:00
|
|
|
, (6, L, "+"), (6, L, "-")
|
2013-02-06 06:26:22 +00:00
|
|
|
, (5, R, "::"), (5, R, "++")
|
2012-06-10 04:21:16 +00:00
|
|
|
, (4, N, "<="), (4, N, ">="), (4, N, "<")
|
|
|
|
, (4, N, "=="), (4, N, "/="), (4, N, ">")
|
2012-12-25 08:39:18 +00:00
|
|
|
, (4, L, "~"), (4, L, "<~")
|
2012-04-19 06:32:10 +00:00
|
|
|
, (3, R, "&&")
|
|
|
|
, (2, R, "||")
|
|
|
|
, (0, R, "$")
|
2013-04-21 20:59:12 +00:00
|
|
|
, (0, R, "<|"), (0, L, "|>")
|
2012-04-19 06:32:10 +00:00
|
|
|
]
|
|
|
|
|
2012-12-25 08:39:18 +00:00
|
|
|
opLevel op = Map.findWithDefault 9 op dict
|
|
|
|
where dict = Map.fromList (map (\(lvl,_,op) -> (op,lvl)) table)
|
|
|
|
|
|
|
|
opAssoc op = Map.findWithDefault R op dict
|
|
|
|
where dict = Map.fromList (map (\(_,assoc,op) -> (op,assoc)) table)
|
|
|
|
|
|
|
|
hasLevel n (op,e) = opLevel op == n
|
|
|
|
|
|
|
|
sortOps :: OpTable -> OpTable
|
2012-04-19 06:32:10 +00:00
|
|
|
sortOps = sortBy (\(i,_,_) (j,_,_) -> compare i j)
|
|
|
|
|
2012-12-25 08:39:18 +00:00
|
|
|
binops :: IParser CExpr -> IParser String -> IParser CExpr
|
2012-04-19 06:32:10 +00:00
|
|
|
binops term anyOp = do
|
|
|
|
e <- term
|
2012-12-25 08:39:18 +00:00
|
|
|
split 0 e =<< many (commitIf (whitespace >> anyOp) $ do
|
|
|
|
whitespace ; op <- anyOp
|
|
|
|
whitespace ; e <- term
|
|
|
|
return (op,e))
|
|
|
|
|
|
|
|
split :: Int -> CExpr -> [(String, CExpr)] -> IParser CExpr
|
|
|
|
split _ e [] = return e
|
|
|
|
split n e eops = do
|
|
|
|
assoc <- getAssoc n eops
|
|
|
|
es <- sequence (splitLevel n e eops)
|
|
|
|
let ops = map fst (filter (hasLevel n) eops)
|
|
|
|
case assoc of R -> joinR es ops
|
|
|
|
_ -> joinL es ops
|
|
|
|
|
|
|
|
splitLevel :: Int -> CExpr -> [(String, CExpr)] -> [IParser CExpr]
|
|
|
|
splitLevel n e eops =
|
|
|
|
case break (hasLevel n) eops of
|
|
|
|
(lops, (op,e'):rops) -> split (n+1) e lops : splitLevel n e' rops
|
|
|
|
(lops, []) -> [ split (n+1) e lops ]
|
|
|
|
|
|
|
|
joinL :: [CExpr] -> [String] -> IParser CExpr
|
|
|
|
joinL [e] [] = return e
|
|
|
|
joinL (a:b:es) (op:ops) = joinL (epos a b (Binop op a b) : es) ops
|
|
|
|
joinL _ _ = fail "Ill-formed binary expression. Report a compiler bug."
|
|
|
|
|
|
|
|
joinR :: [CExpr] -> [String] -> IParser CExpr
|
|
|
|
joinR [e] [] = return e
|
|
|
|
joinR (a:b:es) (op:ops) = do e <- joinR (b:es) ops
|
|
|
|
return (epos a e (Binop op a e))
|
|
|
|
joinR _ _ = fail "Ill-formed binary expression. Report a compiler bug."
|
|
|
|
|
|
|
|
getAssoc :: Int -> [(String,CExpr)] -> IParser Assoc
|
|
|
|
getAssoc n eops | all (==L) assocs = return L
|
|
|
|
| all (==R) assocs = return R
|
|
|
|
| all (==N) assocs = case assocs of [_] -> return N
|
|
|
|
_ -> fail msg
|
|
|
|
where levelOps = filter (hasLevel n) eops
|
|
|
|
assocs = map (opAssoc . fst) levelOps
|
|
|
|
msg = concat [ "Conflicting precedence for binary operators ("
|
|
|
|
, intercalate ", " (map fst eops), "). "
|
|
|
|
, "Consider adding parentheses to disambiguate." ]
|
|
|
|
|