g2-0.2.0.0: src/G2/Language/Simplification.hs
-- Semantics-preserving syntactic transformations
{-# LANGUAGE FlexibleContexts #-}
module G2.Language.Simplification ( simplifyExprs
, simplifyAppLambdas
, inlineFunc
, inlineFuncInCase) where
import G2.Language.AST
import G2.Language.Expr
import qualified G2.Language.ExprEnv as E
import G2.Language.Syntax
import G2.Language.Typing
import Data.List
simplifyExprs :: ASTContainer t Expr => E.ExprEnv -> E.ExprEnv -> t -> t
simplifyExprs eenv c_eenv = modifyContainedASTs (simplifyExpr eenv c_eenv)
simplifyExpr :: E.ExprEnv -> E.ExprEnv -> Expr -> Expr
simplifyExpr eenv c_eenv e =
let
e' = simplifyAppLambdas $ e
-- e' = caseOfKnownCons
-- . inlineFuncInCase c_eenv
-- . inlineFunc eenv
-- . simplifyAppLambdas $ e
in
if e == e' then e else simplifyExpr eenv c_eenv e'
-- | Reduce Lambdas that are being passed variables or values in SWHNF.
-- This AVOIDS reducing a lamba if it could cause us to miss an opportunity for sharing.
simplifyAppLambdas :: Expr -> Expr
simplifyAppLambdas (App (Lam TermL i e) e')
| safeToInline e' = simplifyAppLambdas $ replaceVar (idName i) e' e
simplifyAppLambdas (App (Lam TypeL i e) (Var i')) =
simplifyAppLambdas $ retype i (TyVar i') e
simplifyAppLambdas (App (Lam TypeL i e) (Type t)) =
simplifyAppLambdas $ retype i t e
simplifyAppLambdas e@(App (App _ _) _) =
let
e' = modifyChildren simplifyAppLambdas e
in
if e == e' then e else simplifyAppLambdas e'
simplifyAppLambdas e = modifyChildren simplifyAppLambdas e
safeToInline :: Expr -> Bool
safeToInline (Var _) = True
safeToInline (Lit _) = True
safeToInline e@(App _ _) | Data _:_ <- unApp e = True
safeToInline e@(App _ _) | Prim _ _:_ <- unApp e = True
safeToInline _ = False
-- | Inline the functions in the ExprEnv
inlineFunc :: E.ExprEnv -> Expr -> Expr
inlineFunc eenv v@(Var (Id n _))
| Just e <- E.lookup n eenv = inlineFunc eenv e
| otherwise = v
inlineFunc eenv e =
modifyChildren (inlineFunc eenv) e
-- | Inline the functions in the ExprEnv, if they are the bindee in a Case expression
inlineFuncInCase :: E.ExprEnv -> Expr -> Expr
inlineFuncInCase eenv c@(Case (Var (Id n _)) i t as)
| Just e <- E.lookup n eenv =
inlineFuncInCase eenv $ Case e i t as
| otherwise = c
inlineFuncInCase eenv e =
modifyChildren (inlineFuncInCase eenv) e
caseOfKnownCons :: Expr -> Expr
caseOfKnownCons (Case e i _ as)
| Data (DataCon n t):es <- unApp e
, Just (Alt (DataAlt _ is) ae) <- find (matchingDataAlt n) as =
let
tfa_count = length (leadingTyForAllBindings $ PresType t)
es' = drop tfa_count es
in
foldr (uncurry replaceVar) (replaceVar (idName i) e ae) (zip (map idName is) es')
| Lit l:_ <- unApp e
, Just (Alt (LitAlt _) ae) <- find (matchingLitAlt l) as = replaceVar (idName i) e ae
| Data _:_ <- unApp e
, Just (Alt Default ae) <- find (\(Alt am _) -> am == Default) as = replaceVar (idName i) e ae
| Lit l:_ <- unApp e
, Just (Alt Default ae) <- find (\(Alt am _) -> am == Default) as = replaceVar (idName i) e ae
caseOfKnownCons e = modifyChildren caseOfKnownCons e
matchingDataAlt :: Name -> Alt -> Bool
matchingDataAlt n (Alt (DataAlt (DataCon n' _) _) _) = n == n'
matchingDataAlt _ _ = False
matchingLitAlt :: Lit -> Alt -> Bool
matchingLitAlt l (Alt (LitAlt l') _) = l == l'
matchingLitAlt _ _ = False