Elm-0.4.0: src/Gen/Cases.hs
module Cases (caseToMatch, Match (..), Clause (..)) where
import Control.Arrow (first)
import Control.Monad (liftM,foldM)
import Data.List (groupBy,sortBy)
import Ast
import Guid
import Substitute
import System.IO.Unsafe
caseToMatch patterns = do
v <- newVar
match [v] (map (first (:[])) patterns) Fail
newVar = do n <- guid
return $ "case" ++ show n
data Match = Match String [Clause] Match
| Break
| Fail
| Other Expr
| Seq [Match]
deriving Show
data Clause = Clause String [String] Match
deriving Show
isCon (PData _ _ : _, _) = True
isCon _ = False
isVar p = not (isCon p)
match :: [String] -> [([Pattern],Expr)] -> Match -> GuidCounter Match
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])
match vs cs def
| all isVar cs = matchVar vs cs def
| all isCon cs = matchCon vs cs def
| otherwise = matchMix vs cs def
matchVar :: [String] -> [([Pattern],Expr)] -> Match -> GuidCounter Match
matchVar (v:vs) cs def = match vs (map subVar cs) def
where subVar (PVar x : ps, e) = (ps, subst x (Var v) e)
subVar (PAnything : ps, e) = (ps, e)
matchCon :: [String] -> [([Pattern],Expr)] -> Match -> GuidCounter Match
matchCon (v:vs) cs def = (flip (Match v) def) `liftM` mapM toClause css
where css = groupBy (withName (==)) $ sortBy (withName compare) cs
withName f (PData n1 _:_,_) (PData n2 _:_,_) = f n1 n2
toClause cs = let (PData name _ : _ , _) = head cs in
matchClause name (v:vs) cs Break
matchClause :: String -> [String] -> [([Pattern],Expr)] -> Match -> GuidCounter Clause
matchClause c (v:vs) cs def =
do vs' <- getVars
Clause c vs' `liftM` match (vs' ++ vs) (map flatten cs) def
where flatten (PData _ ps' : ps, e) = (ps' ++ ps, e)
getVars = let (PData _ ps : _, _) = head cs in
mapM (\_ -> newVar) ps
matchMix :: [String] -> [([Pattern],Expr)] -> Match -> GuidCounter Match
matchMix vs cs def = foldM (flip $ match vs) def (reverse css)
where css = groupBy (\p1 p2 -> isCon p1 == isCon p2) cs