module FrontEnd.Desugar (doToExp, listCompToExp, desugarHsModule, desugarHsStmt) where
import Control.Monad.State
import FrontEnd.HsSyn
import FrontEnd.SrcLoc
import FrontEnd.Syn.Traverse
import Name.Name
import Name.Names
type PatState = Int
getUnique = do
n <- get
put (n + 1)
return n
type PatSM = State PatState
instance MonadSrcLoc PatSM where
instance MonadSetSrcLoc PatSM where
withSrcLoc _ a = a
newPatVarName :: HsName
newPatVarName = nameName $ toName Val ("patvar@0"::String)
desugarHsModule :: HsModule -> HsModule
desugarHsModule m = hsModuleDecls_s ds' m where
(ds', _) = runState (dsm (hsModuleDecls m)) (0::Int)
dsm ds = fmap concat $ mapM desugarDecl ds
desugarHsStmt :: Monad m => HsStmt -> m HsStmt
desugarHsStmt s = return $ fst $ runState (desugarStmt s) (0::Int)
desugarDecl :: HsDecl -> PatSM [HsDecl]
desugarDecl (HsFunBind matches) = do
newMatches <- mapM desugarMatch matches
return [HsFunBind newMatches]
desugarDecl pb@(HsPatBind sloc (HsPVar n) rhs wheres) = do
newRhs <- desugarRhs rhs
newWheres <- mapM desugarDecl wheres
return [HsPatBind sloc (HsPVar n) newRhs (concat newWheres)]
desugarDecl pb@(HsPatBind sloc pat rhs wheres) = do
rhs <- desugarRhs rhs
unique <- getUnique
let newRhsName = toName Val ("patrhs@" ++ show unique)
newWheres <- mapM desugarDecl wheres
let newTopDeclForRhs
= HsPatBind sloc (HsPVar newRhsName) rhs (concat newWheres)
let newBinds = genBindsForPat pat sloc newRhsName
newBinds <- mapM desugarDecl newBinds
return (newTopDeclForRhs : concat newBinds)
desugarDecl (HsClassDecl sloc qualtype decls) = do
newDecls <- mapM desugarDecl decls
return [HsClassDecl sloc qualtype (concat newDecls)]
desugarDecl (HsInstDecl sloc qualtype decls) = do
newDecls <- mapM desugarDecl decls
return [HsInstDecl sloc qualtype (concat newDecls)]
desugarDecl HsPragmaSpecialize { hsDeclName = n } | n == u_instance = return []
desugarDecl anyOtherDecl = return [anyOtherDecl]
desugarMatch :: (HsMatch) -> PatSM (HsMatch)
desugarMatch (HsMatch sloc funName pats rhs wheres) = do
newWheres <- mapM desugarDecl wheres
newRhs <- desugarRhs rhs
return (HsMatch sloc funName pats newRhs (concat newWheres))
genBindsForPat :: HsPat -> SrcLoc -> HsName -> [HsDecl]
genBindsForPat pat sloc rhsName
= [HsPatBind sloc (HsPVar patName) (HsUnGuardedRhs (HsApp selector (HsVar rhsName))) [] | (patName, selector) <- selFuns]
where
selFuns = getPatSelFuns sloc pat
getPatSelFuns :: SrcLoc -> HsPat -> [(HsName, (HsExp))]
getPatSelFuns sloc pat = [(varName, HsParen (HsLambda sloc [HsPVar newPatVarName] (kase (replaceVarNamesInPat varName pat)))) | varName <- getNamesFromHsPat pat] where
kase p = HsCase (HsVar newPatVarName) [a1, a2 ] where
a1 = HsAlt sloc p (HsUnGuardedRhs (HsVar newPatVarName)) []
a2 = HsAlt sloc HsPWildCard (HsUnGuardedRhs (HsError { hsExpSrcLoc = sloc, hsExpErrorType = HsErrorPatternFailure, hsExpString = show sloc ++ " failed pattern match" })) []
replaceVarNamesInPat :: HsName -> HsPat -> HsPat
replaceVarNamesInPat name p = f name p where
f name1 (HsPVar (toName Val -> name2))
| name1 == name2 = HsPVar $ newPatVarName
| otherwise = HsPWildCard
f _ p@(HsPLit _) = p
f name (HsPNeg pat) = HsPNeg $ f name pat
f name (HsPInfixApp pat1 conName pat2) = HsPInfixApp (f name pat1) conName (f name pat2)
f name (HsPApp conName pats) = HsPApp conName (map (f name) pats)
f name (HsPTuple pats) = HsPTuple (map (f name) pats)
f name (HsPUnboxedTuple pats) = HsPUnboxedTuple (map (f name) pats)
f name (HsPList pats) = HsPList (map (f name) pats)
f name (HsPParen pat) = HsPParen (f name pat)
f name (HsPRec conName fields) = HsPRec conName [ HsPFieldPat fname (f name pat)
| HsPFieldPat fname pat <- fields ]
f name (HsPAsPat asName pat)
| name == asName = HsPAsPat newPatVarName (f name pat)
| otherwise = f name pat
f name HsPWildCard = HsPWildCard
f name (HsPIrrPat pat) = HsPIrrPat $ fmap (f name) pat
f name (HsPBangPat pat) = HsPBangPat $ fmap (f name) pat
f name p = error $ "f: " ++ show (name,p)
desugarRhs :: (HsRhs) -> PatSM (HsRhs)
desugarRhs = traverseHsRhsHsExp desugarExp
desugarExp :: (HsExp) -> PatSM (HsExp)
desugarExp (HsLambda sloc pats e)
| all isSimplePat pats = do
newE <- desugarExp e
return (HsLambda sloc pats newE)
desugarExp (HsLambda sloc pats e) = z where
z = do
ps <- mapM f pats
let (xs,zs) = unzip ps
e' <- (ne e $ concat zs)
return (HsLambda sloc (map HsPVar xs) e')
ne e [] = desugarExp e
ne e ((n,p):zs) = do
e' <- ne e zs
let a1 = HsAlt sloc p (HsUnGuardedRhs e') []
a2 = HsAlt sloc HsPWildCard (HsUnGuardedRhs (HsError { hsExpSrcLoc = sloc, hsExpErrorType = HsErrorPatternFailure, hsExpString = show sloc ++ " failed pattern match in lambda" })) []
return $ HsCase (HsVar n) [a1, a2 ]
f (HsPVar x) = return (x,[])
f (HsPAsPat n p) = return (n,[(n,p)])
f p = do
unique <- getUnique
let n = nameName $ toName Val ("lambind@" ++ show unique)
return (n,[(n,p)])
desugarExp (HsLet decls e) = do
newDecls <- mapM desugarDecl decls
newE <- desugarExp e
return (HsLet (concat newDecls) newE)
desugarExp (HsCase e alts) = do
newE <- desugarExp e
newAlts <- mapM desugarAlt alts
return (HsCase newE newAlts)
desugarExp (HsDo stmts) = HsDo `liftM` mapM desugarStmt stmts
desugarExp (HsListComp e stmts) = do
e <- desugarExp e
stmts <- mapM desugarStmt stmts
return (HsListComp e stmts)
desugarExp e = traverseHsExp desugarExp e
desugarAlt :: (HsAlt) -> PatSM (HsAlt)
desugarAlt (HsAlt sloc pat gAlts wheres) = do
newGAlts <- desugarRhs gAlts
newWheres <- mapM desugarDecl wheres
return (HsAlt sloc pat newGAlts (concat newWheres))
desugarStmt :: (HsStmt) -> PatSM (HsStmt)
desugarStmt (HsGenerator srcLoc pat e) = do
newE <- desugarExp e
return (HsGenerator srcLoc pat newE)
desugarStmt (HsQualifier e) = do
newE <- desugarExp e
return (HsQualifier newE)
desugarStmt (HsLetStmt decls) = do
newDecls <- mapM desugarDecl decls
return (HsLetStmt $ concat newDecls)
doToExp :: Monad m
=> m HsName
-> HsName
-> HsName
-> HsName
-> [HsStmt]
-> m HsExp
doToExp newName f_bind f_bind_ f_fail ss = hsParen `liftM` f ss where
f [] = fail "doToExp: empty statements in do notation"
f [HsQualifier e] = return e
f [gen@(HsGenerator srcLoc _pat _e)] = fail $ "doToExp: last expression n do notation is a generator (srcLoc):" ++ show srcLoc
f [letst@(HsLetStmt _decls)] = fail $ "doToExp: last expression n do notation is a let statement"
f (HsQualifier e:ss) = do
ss <- f ss
return $ HsInfixApp (hsParen e) (HsVar f_bind_) (hsParen ss)
f ((HsGenerator _srcLoc pat e):ss) | isSimplePat pat = do
ss <- f ss
return $ HsInfixApp (hsParen e) (HsVar f_bind) (HsLambda _srcLoc [pat] ss)
f ((HsGenerator srcLoc pat e):ss) = do
npvar <- newName
ss <- f ss
let kase = HsCase (HsVar npvar) [a1, a2 ]
a1 = HsAlt srcLoc pat (HsUnGuardedRhs ss) []
a2 = HsAlt srcLoc HsPWildCard (HsUnGuardedRhs (HsApp (HsVar f_fail) (HsLit $ HsString $ show srcLoc ++ " failed pattern match in do"))) []
return $ HsInfixApp (hsParen e) (HsVar f_bind) (HsLambda srcLoc [HsPVar npvar] kase) where
f (HsLetStmt decls:ss) = do
ss <- f ss
return $ HsLet decls ss
hsApp e es = hsParen $ foldl HsApp (hsParen e) (map hsParen es)
hsIf e a b = hsParen $ HsIf e a b
listCompToExp :: Monad m => m HsName -> HsExp -> [HsStmt] -> m HsExp
listCompToExp newName exp ss = hsParen `liftM` f ss where
f [] = return $ HsList [exp]
f (gen:HsQualifier q1:HsQualifier q2:ss) = f (gen:HsQualifier (hsApp (HsVar v_and) [q1,q2]):ss)
f ((HsLetStmt ds):ss) = do ss' <- f ss; return $ hsParen (HsLet ds ss')
f (HsQualifier e:ss) = do ss' <- f ss; return $ hsParen (HsIf e ss' (HsList []))
f ((HsGenerator srcLoc pat e):ss) | isLazyPat pat, Just exp' <- g ss = do
return $ hsParen $ HsVar v_map `app` HsLambda srcLoc [pat] exp' `app` e
f ((HsGenerator srcLoc pat e):HsQualifier q:ss) | isLazyPat pat, Just exp' <- g ss = do
npvar <- newName
return $ hsApp (HsVar v_foldr) [HsLambda srcLoc [pat,HsPVar npvar] $ hsIf q (hsApp (HsCon dc_Cons) [exp',HsVar npvar]) (HsVar npvar), HsList [],e]
f ((HsGenerator srcLoc pat e):ss) | isLazyPat pat = do
ss' <- f ss
return $ hsParen $ HsVar v_concatMap `app` HsLambda srcLoc [pat] ss' `app` e
f ((HsGenerator srcLoc pat e):HsQualifier q:ss) | isFailablePat pat || Nothing == g ss = do
npvar <- newName
ss' <- f ss
let kase = HsCase (HsVar npvar) [a1, a2 ]
a1 = HsAlt srcLoc pat (HsGuardedRhss [HsGuardedRhs srcLoc q ss']) []
a2 = HsAlt srcLoc HsPWildCard (HsUnGuardedRhs $ HsList []) []
return $ hsParen $ HsVar v_concatMap `app` HsLambda srcLoc [HsPVar npvar] kase `app` e
f ((HsGenerator srcLoc pat e):ss) | isFailablePat pat || Nothing == g ss = do
npvar <- newName
ss' <- f ss
let kase = HsCase (HsVar npvar) [a1, a2 ]
a1 = HsAlt srcLoc pat (HsUnGuardedRhs ss') []
a2 = HsAlt srcLoc HsPWildCard (HsUnGuardedRhs $ HsList []) []
return $ hsParen $ HsVar v_concatMap `app` HsLambda srcLoc [HsPVar npvar] kase `app` e
f ((HsGenerator srcLoc pat e):ss) = do
npvar <- newName
let Just exp' = g ss
kase = HsCase (HsVar npvar) [a1 ]
a1 = HsAlt srcLoc pat (HsUnGuardedRhs exp') []
return $ hsParen $ HsVar v_map `app` HsLambda srcLoc [HsPVar npvar] kase `app` e
g [] = return exp
g (HsLetStmt ds:ss) = do
e <- g ss
return (hsParen (HsLet ds e))
g _ = Nothing
app x y = HsApp x (hsParen y)
isFailablePat p | isStrictPat p = f (openPat p) where
f (HsPTuple ps) = any isFailablePat ps
f (HsPUnboxedTuple ps) = any isFailablePat ps
f (HsPBangPat (Located _ p)) = isFailablePat p
f _ = True
isFailablePat _ = False
isSimplePat p = f (openPat p) where
f HsPVar {} = True
f HsPWildCard = True
f _ = False
isLazyPat pat = not (isStrictPat pat)
isStrictPat p = f (openPat p) where
f HsPVar {} = False
f HsPWildCard = False
f (HsPIrrPat p) = False
f _ = True
openPat (HsPParen p) = openPat p
openPat (HsPNeg p) = openPat p
openPat (HsPAsPat _ p) = openPat p
openPat (HsPTypeSig _ p _) = openPat p
openPat (HsPInfixApp a n b) = HsPApp n [a,b]
openPat p = p