2013-06-14 05:45:08 +00:00
|
|
|
module Generate.Cases (caseToMatch, Match (..), Clause (..), matchSubst) where
|
2012-08-25 21:02:34 +00:00
|
|
|
|
2013-08-31 10:07:19 +00:00
|
|
|
import Control.Applicative ((<$>),(<*>))
|
2012-08-25 21:02:34 +00:00
|
|
|
import Control.Arrow (first)
|
2013-08-31 10:07:19 +00:00
|
|
|
import Control.Monad.State
|
2012-10-10 21:41:40 +00:00
|
|
|
import Data.List (groupBy,sortBy,lookup)
|
|
|
|
import Data.Maybe (fromMaybe)
|
2012-08-25 21:02:34 +00:00
|
|
|
|
2013-06-14 05:45:08 +00:00
|
|
|
import SourceSyntax.Location
|
2013-06-23 08:36:23 +00:00
|
|
|
import SourceSyntax.Literal
|
2013-06-14 05:45:08 +00:00
|
|
|
import SourceSyntax.Pattern
|
|
|
|
import SourceSyntax.Expression
|
|
|
|
import Transform.Substitute
|
2012-08-25 21:02:34 +00:00
|
|
|
|
2013-08-31 10:07:19 +00:00
|
|
|
|
2012-08-25 21:02:34 +00:00
|
|
|
caseToMatch patterns = do
|
|
|
|
v <- newVar
|
2013-08-31 10:07:19 +00:00
|
|
|
(,) v <$> match [v] (map (first (:[])) patterns) Fail
|
2012-08-25 21:02:34 +00:00
|
|
|
|
2013-08-31 10:07:19 +00:00
|
|
|
newVar = do n <- get
|
|
|
|
modify (+1)
|
2012-08-25 21:02:34 +00:00
|
|
|
return $ "case" ++ show n
|
|
|
|
|
2013-06-14 05:45:08 +00:00
|
|
|
data Match t v
|
|
|
|
= Match String [Clause t v] (Match t v)
|
|
|
|
| Break
|
|
|
|
| Fail
|
|
|
|
| Other (LExpr t v)
|
|
|
|
| Seq [Match t v]
|
|
|
|
deriving Show
|
2012-08-25 21:02:34 +00:00
|
|
|
|
2013-06-14 05:45:08 +00:00
|
|
|
data Clause t v =
|
2013-06-23 08:36:23 +00:00
|
|
|
Clause (Either String Literal) [String] (Match t v)
|
2013-06-14 05:45:08 +00:00
|
|
|
deriving Show
|
2012-08-25 21:02:34 +00:00
|
|
|
|
2013-06-14 05:45:08 +00:00
|
|
|
matchSubst :: [(String,String)] -> Match t v -> Match t v
|
2012-10-10 21:41:40 +00:00
|
|
|
matchSubst _ Break = Break
|
|
|
|
matchSubst _ Fail = Fail
|
|
|
|
matchSubst pairs (Seq ms) = Seq (map (matchSubst pairs) ms)
|
2013-07-30 18:43:42 +00:00
|
|
|
matchSubst pairs (Other (L s e)) =
|
|
|
|
Other . L s $ foldr ($) e $ map (\(x,y) -> subst x (Var y)) pairs
|
2012-12-25 08:39:18 +00:00
|
|
|
matchSubst pairs (Match n cs m) =
|
|
|
|
Match (varSubst n) (map clauseSubst cs) (matchSubst pairs m)
|
|
|
|
where varSubst v = fromMaybe v (lookup v pairs)
|
|
|
|
clauseSubst (Clause c vs m) =
|
|
|
|
Clause c (map varSubst vs) (matchSubst pairs m)
|
2012-10-10 21:41:40 +00:00
|
|
|
|
2013-06-23 11:18:27 +00:00
|
|
|
isCon (p:ps, e) =
|
2013-06-23 08:36:23 +00:00
|
|
|
case p of
|
|
|
|
PData _ _ -> True
|
|
|
|
PLiteral _ -> True
|
|
|
|
_ -> False
|
2012-08-25 21:02:34 +00:00
|
|
|
|
|
|
|
isVar p = not (isCon p)
|
|
|
|
|
2013-08-31 10:07:19 +00:00
|
|
|
match :: [String] -> [([Pattern],LExpr t v)] -> Match t v -> State Int (Match t v)
|
2012-08-25 21:02:34 +00:00
|
|
|
match [] [] def = return def
|
|
|
|
match [] [([],e)] Fail = return $ Other e
|
|
|
|
match [] [([],e)] Break = return $ Other e
|
|
|
|
match [] cs def = return $ Seq (map (Other . snd) cs ++ [def])
|
2013-06-23 11:18:27 +00:00
|
|
|
match vs@(v:_) cs def
|
|
|
|
| all isVar cs' = matchVar vs cs' def
|
|
|
|
| all isCon cs' = matchCon vs cs' def
|
|
|
|
| otherwise = matchMix vs cs' def
|
|
|
|
where
|
|
|
|
cs' = map (dealias v) cs
|
|
|
|
|
2013-07-30 18:43:42 +00:00
|
|
|
dealias v c@(p:ps, L s e) =
|
2013-06-23 11:18:27 +00:00
|
|
|
case p of
|
2013-07-30 18:43:42 +00:00
|
|
|
PAlias x pattern -> (pattern:ps, L s $ subst x (Var v) e)
|
2013-06-23 11:18:27 +00:00
|
|
|
_ -> c
|
2012-08-25 21:02:34 +00:00
|
|
|
|
2013-08-31 10:07:19 +00:00
|
|
|
matchVar :: [String] -> [([Pattern],LExpr t v)] -> Match t v -> State Int (Match t v)
|
2012-08-25 21:02:34 +00:00
|
|
|
matchVar (v:vs) cs def = match vs (map subVar cs) def
|
2013-04-07 13:46:46 +00:00
|
|
|
where
|
2013-07-30 18:43:42 +00:00
|
|
|
subVar (p:ps, ce@(L s e)) = (ps, L s $ subOnePattern p e)
|
2013-06-23 08:36:23 +00:00
|
|
|
where
|
2013-06-23 11:18:27 +00:00
|
|
|
subOnePattern pattern e =
|
2013-06-23 08:36:23 +00:00
|
|
|
case pattern of
|
|
|
|
PVar x -> subst x (Var v) e
|
|
|
|
PAnything -> e
|
|
|
|
PRecord fs ->
|
2013-07-30 18:43:42 +00:00
|
|
|
foldr (\x -> subst x (Access (L s (Var v)) x)) e fs
|
2013-06-23 08:36:23 +00:00
|
|
|
|
|
|
|
matchCon :: [String] -> [([Pattern],LExpr t v)] -> Match t v
|
2013-08-31 10:07:19 +00:00
|
|
|
-> State Int (Match t v)
|
|
|
|
matchCon (v:vs) cs def = (flip (Match v) def) <$> mapM toClause css
|
2013-06-23 08:36:23 +00:00
|
|
|
where
|
|
|
|
css = groupBy eq (sortBy cmp cs)
|
|
|
|
|
|
|
|
cmp (p1:_,_) (p2:_,_) =
|
|
|
|
case (p1,p2) of
|
|
|
|
(PData n1 _, PData n2 _) -> compare n1 n2
|
|
|
|
_ -> compare p1 p2
|
|
|
|
|
|
|
|
eq (p1:_,_) (p2:_,_) =
|
|
|
|
case (p1,p2) of
|
|
|
|
(PData n1 _, PData n2 _) -> n1 == n2
|
|
|
|
_ -> p1 == p2
|
2012-08-25 21:02:34 +00:00
|
|
|
|
2013-06-23 08:36:23 +00:00
|
|
|
toClause cs =
|
|
|
|
case head cs of
|
|
|
|
(PData name _ : _, _) -> matchClause (Left name) (v:vs) cs Break
|
|
|
|
(PLiteral lit : _, _) -> matchClause (Right lit) (v:vs) cs Break
|
|
|
|
|
|
|
|
matchClause :: Either String Literal
|
|
|
|
-> [String]
|
|
|
|
-> [([Pattern],LExpr t v)]
|
|
|
|
-> Match t v
|
2013-08-31 10:07:19 +00:00
|
|
|
-> State Int (Clause t v)
|
2012-08-25 21:02:34 +00:00
|
|
|
matchClause c (v:vs) cs def =
|
|
|
|
do vs' <- getVars
|
2013-08-31 10:07:19 +00:00
|
|
|
Clause c vs' <$> match (vs' ++ vs) (map flatten cs) def
|
2013-06-23 08:36:23 +00:00
|
|
|
where
|
|
|
|
|
|
|
|
flatten (p:ps, e) =
|
|
|
|
case p of
|
|
|
|
PData _ ps' -> (ps' ++ ps, e)
|
|
|
|
PLiteral _ -> (ps, e)
|
|
|
|
|
|
|
|
getVars =
|
|
|
|
case head cs of
|
|
|
|
(PData _ ps : _, _) -> mapM (\_ -> newVar) ps
|
|
|
|
(PLiteral _ : _, _) -> return []
|
2012-08-25 21:02:34 +00:00
|
|
|
|
2013-08-31 10:07:19 +00:00
|
|
|
matchMix :: [String] -> [([Pattern],LExpr t v)] -> Match t v -> State Int (Match t v)
|
2012-08-25 21:02:34 +00:00
|
|
|
matchMix vs cs def = foldM (flip $ match vs) def (reverse css)
|
|
|
|
where css = groupBy (\p1 p2 -> isCon p1 == isCon p2) cs
|