1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
--- ---------------------------------------------------------------------------- --- This module provides transforms FlatCurry programs for concolic evaluation: --- - For every case expression a fresh identifier is introduced for the --- scrutinized expression. For instance the expression --- --- case e of p1 -> e1; ... ; pn -> en --- --- is transformed to --- --- let cid = e in case cid of p1 -> e1; ... ; pn -> en --- --- where cid is a fresh identifier --- --- - Furthermore, cases with boolean expressions as arguments are normalized --- in the following form: --- --- case c1 && c2 of case c1 of --- True -> e1 is transformed to True -> case c2 of --- False -> e2 True -> e1 --- False -> e2 --- False -> e2 --- --- Disjunctions are transformed in a similar way. --- --- @author Jan Tikovsky --- @version August 2017 --- ---------------------------------------------------------------------------- module IdentifyCases where import FCYFunctorInstances import FlatCurry.Annotated.Types -- import FlatCurry.Annotated.Goodies (annExpr, combArgs, updCombs) import FlatCurryGoodies (IDAnn, extendAnn) import Utils ((<$>), (<*>)) --- Identify Cases Monad data ICM a = IC { runICM :: VarIndex -> (a, VarIndex) } instance Monad ICM where return x = IC $ \s -> (x, s) f >>= g = IC $ \s -> let (x, s') = runICM f s in (runICM (g x)) s' get :: ICM VarIndex get = IC $ \s -> (s, s) put :: VarIndex -> ICM () put s = IC $ \_ -> ((), s) --- Generate a fresh identifier freshID :: ICM VarIndex freshID = do v <- get put (v - 1) return v --- Annotate case expressions with fresh identifiers and mark literals idCases :: [AFuncDecl a] -> ([AFuncDecl (IDAnn a)], VarIndex) idCases fs = runICM (mapM (idFunc . fmap extendAnn) fs) (-1) idFunc :: AFuncDecl (IDAnn a) -> ICM (AFuncDecl (IDAnn a)) idFunc (AFunc qn a vis ty r) = AFunc qn a vis ty <$> idRule r idRule :: ARule (IDAnn a) -> ICM (ARule (IDAnn a)) idRule (ARule ann vs e) = ARule ann vs <$> idExpr e idRule e@(AExternal _ _) = return e idExpr :: AExpr (IDAnn a) -> ICM (AExpr (IDAnn a)) idExpr v@(AVar _ _) = return v idExpr (ALit (ann, mid, _) l) = return $ ALit (ann, mid, True) l idExpr (AComb ann ct qn es) = AComb ann ct qn <$> mapM idExpr es idExpr (ALet ann bs e) = ALet ann <$> mapM idBinding bs <*> idExpr e where idBinding (v, ve) = idExpr ve >>= \ve' -> return (v, ve') idExpr (AFree ann vs e) = AFree ann vs <$> idExpr e idExpr (AOr ann e1 e2) = AOr ann <$> idExpr e1 <*> idExpr e2 idExpr (ACase (ann, _, lf) ct e bs) = do v <- freshID e' <- idExpr e bs' <- mapM idBranch bs return $ ACase (ann, Just v, lf) ct e' bs' where idBranch (ABranch p be) = ABranch p <$> idExpr be idExpr (ATyped ann e ty) = flip (ATyped ann) ty <$> idExpr e -- --- Add a unique identifier to all expressions which are scrutinized in cases -- idCases :: [AFuncDecl TypeExpr] -> ([AFuncDecl TypeExpr], VarIndex) -- idCases fs = (runICM (mapM icFunc fs)) (-1) -- -- icFunc :: AFuncDecl TypeExpr -> ICM (AFuncDecl TypeExpr) -- icFunc (AFunc qn a vis ty r) = AFunc qn a vis ty <$> icRule r -- -- icRule :: ARule TypeExpr -> ICM (ARule TypeExpr) -- icRule (ARule ann vs e) = ARule ann vs <$> splitCases e -- icExpr e -- icRule e@(AExternal _ _) = return e -- -- icExpr :: AExpr TypeExpr -> ICM (AExpr TypeExpr) -- icExpr v@(AVar _ _) = return v -- icExpr l@(ALit _ _) = return l -- icExpr (AComb ann ct qn es) = AComb ann ct qn <$> mapM icExpr es -- icExpr (ALet ann bs e) = ALet ann <$> mapM icBinding bs <*> icExpr e -- where icBinding (v, ve) = icExpr ve >>= \ve' -> return (v, ve') -- icExpr (AFree ann vs e) = AFree ann vs <$> icExpr e -- icExpr (AOr ann e1 e2) = AOr ann <$> icExpr e1 <*> icExpr e2 -- icExpr (ACase ann ct e bs) = do -- v <- freshID -- bs' <- mapM icBranch bs -- return $ ALet ann [((v, annE), e)] (ACase ann ct (AVar annE v) bs') -- where annE = annExpr e -- icBranch (ABranch p be) = ABranch p <$> icExpr be -- icExpr (ATyped ann e ty) = flip (ATyped ann) ty <$> icExpr e -- -- splitCases :: AExpr TypeExpr -> ICM (AExpr TypeExpr) -- splitCases v@(AVar _ _) = return v -- splitCases l@(ALit _ _) = return l -- splitCases (AComb ty ct qn es) = AComb ty ct qn <$> mapM splitCases es -- splitCases (ALet ty bs e) = ALet ty <$> mapM splitBinding bs -- <*> splitCases e -- where splitBinding (v, ve) = splitCases ve >>= \ve' -> return (v, ve') -- splitCases (AFree ty vs e) = AFree ty vs <$> splitCases e -- splitCases (AOr ty e1 e2) = AOr ty <$> splitCases e1 <*> splitCases e2 -- splitCases c@(ACase ty ct e bs) -- -- | isBoolType (annExpr e) = idCase (splitCase ty ct e bs) -- | otherwise = idCase c -- splitCases (ATyped ty e ty') = flip (ATyped ty) ty' <$> splitCases e -- -- --- Split up case expressions over conditionals (i.e. sequences of simple -- --- boolean expressions connected with `&&` or `||`) -- splitCase :: TypeExpr -> CaseType -> AExpr TypeExpr -> [ABranchExpr TypeExpr] -- -> AExpr TypeExpr -- splitCase ty ct e bs -- | isConj e = splitCase ty ct c1 (branch truePat : selBranch falsePat bs) -- | isDisj e = splitCase ty ct c1 (branch falsePat : selBranch truePat bs) -- | otherwise = ACase ty ct (rnmCmpOps e) bs -- where [c1,c2] = combArgs e -- innerCase = splitCase ty ct c2 bs -- branch p = ABranch p innerCase -- -- --- Add a unique identifier to a case expression -- idCase :: AExpr TypeExpr -> ICM (AExpr TypeExpr) -- idCase exp = case exp of -- ACase ty ct e bs -> do -- v <- freshID -- bs' <- mapM splitBranch bs -- return $ ALet ty [((v, tyE), e)] (ACase ty ct (AVar tyE v) bs') -- where tyE = annExpr e -- splitBranch (ABranch p be) = ABranch p <$> splitCases be -- _ -> splitCases exp -- -- --- Rename all operators for comparisons on literals -- rnmCmpOps :: AExpr a -> AExpr a -- rnmCmpOps = updCombs rplCmp -- where rplCmp ann ct f@(qn, qna) args = case lookup qn builtinCmpOps of -- Nothing -> AComb ann ct f args -- Just qn' -> let n = 2 - length args -- ct' = if n == 0 then FuncCall else FuncPartCall n -- in AComb ann ct' (qn', qna) args -- -- -- helper -- -- -- select the branch expression matching the given pattern -- selBranch :: APattern a -> [ABranchExpr a] -> [ABranchExpr a] -- selBranch _ [] = [] -- selBranch p (b@(ABranch q _) : bs) -- | eqPattern p q = [b] -- | otherwise = selBranch p bs -- -- --- Logical operations on integers and floats which are builtin -- builtinCmpOps :: [(QName, QName)] -- builtinCmpOps = map (\(a, b) -> (prel a, prel b)) -- -- integers -- [ ("_impl#==#Prelude.Eq#Prelude.Int" , "_==") -- , ("_impl#/=#Prelude.Eq#Prelude.Int" , "_/=") -- , ("_impl#<#Prelude.Ord#Prelude.Int" , "_<") -- , ("_impl#<=#Prelude.Ord#Prelude.Int", "_<=") -- , ("_impl#>#Prelude.Ord#Prelude.Int" , "_>") -- , ("_impl#>=#Prelude.Ord#Prelude.Int", "_>=") -- -- floats -- , ("_impl#==#Prelude.Eq#Prelude.Float" , "_==") -- , ("_impl#/=#Prelude.Eq#Prelude.Float" , "_/=") -- , ("_impl#<#Prelude.Ord#Prelude.Float" , "_<") -- , ("_impl#<=#Prelude.Ord#Prelude.Float", "_<=") -- , ("_impl#>#Prelude.Ord#Prelude.Float" , "_>") -- , ("_impl#>=#Prelude.Ord#Prelude.Float", "_>=") -- ] |