2012-06-10 04:21:16 +00:00
|
|
|
module 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-04-19 06:32:10 +00:00
|
|
|
import Data.List (foldl',splitAt,elemIndices,group,groupBy,sortBy,find)
|
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)
|
|
|
|
|
2012-06-10 04:21:16 +00:00
|
|
|
import Text.Parsec
|
|
|
|
import ParseLib
|
|
|
|
|
|
|
|
data Assoc = L | N | R deriving (Eq,Show)
|
2012-04-19 06:32:10 +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, "-")
|
|
|
|
, (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-04-19 06:32:10 +00:00
|
|
|
, (3, R, "&&")
|
|
|
|
, (2, R, "||")
|
|
|
|
, (0, R, "$")
|
|
|
|
]
|
|
|
|
|
|
|
|
sortOps = sortBy (\(i,_,_) (j,_,_) -> compare i j)
|
|
|
|
|
|
|
|
binops term anyOp = do
|
|
|
|
e <- term
|
2012-06-10 04:21:16 +00:00
|
|
|
(ops,es) <- liftM unzip $
|
2012-06-12 06:28:45 +00:00
|
|
|
many (commitIf (whitespace >> anyOp) $ do { whitespace ; op <- anyOp
|
|
|
|
; whitespace ; e <- term
|
|
|
|
; return (op,e) })
|
2012-04-28 06:57:11 +00:00
|
|
|
case binopOf Map.empty (sortOps table) ops (e:es) of
|
2012-04-19 06:32:10 +00:00
|
|
|
Right e -> return e
|
2012-06-10 04:21:16 +00:00
|
|
|
Left msg -> fail msg
|
2012-04-19 06:32:10 +00:00
|
|
|
|
|
|
|
binopSplit seen opTable i ops es =
|
|
|
|
case (splitAt i ops, splitAt (i+1) es) of
|
|
|
|
((befores, op:afters), (pres, posts)) ->
|
|
|
|
do e1 <- binopOf seen opTable befores pres
|
|
|
|
e2 <- binopOf seen opTable afters posts
|
|
|
|
return $ Binop op e1 e2
|
|
|
|
|
|
|
|
binopOf _ _ _ [e] = return e
|
2012-06-10 04:21:16 +00:00
|
|
|
binopOf seen [] ops es = binopOf seen [(9,L,head ops)] ops es
|
2012-04-19 06:32:10 +00:00
|
|
|
|
|
|
|
binopOf seen (tbl@((lvl, L, op):rest)) ops es =
|
|
|
|
case elemIndices op ops of
|
|
|
|
[] -> binopOf seen rest ops es
|
|
|
|
is -> case Map.lookup lvl seen of
|
2012-04-27 15:36:57 +00:00
|
|
|
Nothing -> binopSplit (Map.insert lvl (L,op) seen) tbl (last is) ops es
|
2012-04-19 06:32:10 +00:00
|
|
|
Just (L,_) -> binopSplit seen tbl (last is) ops es
|
|
|
|
Just (assoc,op') -> Left $ errorMessage lvl op L op' assoc
|
|
|
|
binopOf seen (tbl@((lvl, assoc, op):rest)) ops es =
|
|
|
|
case elemIndices op ops of
|
|
|
|
[] -> binopOf seen rest ops es
|
|
|
|
i:_ -> case Map.lookup lvl seen of
|
2012-06-10 04:21:16 +00:00
|
|
|
Nothing -> binopSplit (Map.insert lvl (assoc,op) seen) tbl i ops es
|
2012-04-19 06:32:10 +00:00
|
|
|
Just (assoc',op') ->
|
2012-06-10 04:21:16 +00:00
|
|
|
if assoc == assoc' && assoc /= N then
|
2012-04-19 06:32:10 +00:00
|
|
|
binopSplit seen tbl i ops es
|
|
|
|
else Left $ errorMessage lvl op assoc op' assoc'
|
|
|
|
|
|
|
|
errorMessage lvl op1 assoc1 op2 assoc2 =
|
|
|
|
"Cannot have (" ++ op1 ++ ") with [" ++ show assoc1 ++ " " ++
|
|
|
|
show lvl ++ "] and (" ++ op2 ++ ") with [" ++ show assoc2 ++ " " ++
|
|
|
|
show lvl ++ "]"
|