From e50e091f692c4317a93df1187bed0449b9079c55 Mon Sep 17 00:00:00 2001 From: koen <koenwermer@gmail.com> Date: Thu, 29 Dec 2016 00:12:47 +0100 Subject: [PATCH] fixed some shit --- Settings.hs | 2 +- Substitute.hs | 10 ++++- Tests/methods.java | 2 +- Verifier.hs | 2 +- WLP.hs | 106 ++++++++++++++++++++++++--------------------- 5 files changed, 67 insertions(+), 55 deletions(-) diff --git a/Settings.hs b/Settings.hs index 1e509e5..bcb07f1 100644 --- a/Settings.hs +++ b/Settings.hs @@ -5,4 +5,4 @@ testFile = "methods" postCond = "(x == 4)" nrOfUnroll :: Int -nrOfUnroll = 1 \ No newline at end of file +nrOfUnroll = 2 \ No newline at end of file diff --git a/Substitute.hs b/Substitute.hs index 8bd9e23..b8a4daa 100644 --- a/Substitute.hs +++ b/Substitute.hs @@ -52,8 +52,8 @@ substVarExpAlgebra = (fLit, fClassLit, fThis, fThisClass, fInstanceCreation, fQu case lhs inh of NameLhs (Name lhsName) -> case lookupType (decls inh) (env inh) (Name lhsNameInit) of PrimType _ | lhsName == name -> rhs inh - RefType _ | isIntroducedVar (Name lhsName) && lhsName == name -> rhs inh - RefType _ | isIntroducedVar (Name lhsName) && lhsName /= name -> ExpName (Name name) + RefType _ | isIntroducedVar (Name lhsName) && lhsName == name && not (isObjectCreation (rhs inh)) -> rhs inh + RefType _ | isIntroducedVar (Name lhsName) -> ExpName (Name name) RefType t | lookupType (decls inh) (env inh) (Name nameInit) == RefType t -> case rhs inh of ExpName (Name rhsName) | take (length lhsName) name == lhsName -> ExpName (Name (rhsName ++ drop (length lhsName) name)) -- accessing o1.x might affect o2.x if o1 and o2 point to the same object: @@ -92,6 +92,12 @@ substVarExpAlgebra = (fLit, fClassLit, fThis, fThisClass, fInstanceCreation, fQu fLambda lParams lExp _ = Lambda lParams lExp fMethodRef className methodName _ = MethodRef className methodName + -- Checks if an expressions creates a new object or array + isObjectCreation :: Exp -> Bool + isObjectCreation (InstanceCreation _ _ _ _) = True + isObjectCreation (ArrayCreate _ _ _) = True + isObjectCreation _ = False + -- Recursively accesses a field of an expression getFields :: [TypeDecl] -> Exp -> [Ident] -> Exp getFields decls e [] = e diff --git a/Tests/methods.java b/Tests/methods.java index 560104c..d524111 100644 --- a/Tests/methods.java +++ b/Tests/methods.java @@ -5,7 +5,7 @@ public static class Main { C c1, c2; c1 = new C(0); - c2 = new C(1); + c2 = new C(0); c1.method1(1); c2.method1(1); x = c1.c + c2.c; diff --git a/Verifier.hs b/Verifier.hs index 6852a6f..d86c402 100644 --- a/Verifier.hs +++ b/Verifier.hs @@ -62,7 +62,7 @@ expAssertAlgebra = (fLit, fClassLit, fThis, fThisClass, fInstanceCreation, fQual fThisClass = undefined fInstanceCreation = undefined fQualInstanceCreation = undefined - fArrayCreate _ _ _ = mkTrue + fArrayCreate = undefined fArrayCreateInit = undefined fFieldAccess fieldAccess = case fieldAccess of PrimaryFieldAccess e id -> case e of diff --git a/WLP.hs b/WLP.hs index cb2a9b3..b602748 100644 --- a/WLP.hs +++ b/WLP.hs @@ -36,17 +36,16 @@ wlpStmtAlgebra :: StmtAlgebra (Inh -> Syn) wlpStmtAlgebra = (fStmtBlock, fIfThen, fIfThenElse, fWhile, fBasicFor, fEnhancedFor, fEmpty, fExpStmt, fAssert, fSwitch, fDo, fBreak, fContinue, fReturn, fSynchronized, fThrow, fTry, fLabeled) where fStmtBlock (Block bs) inh = foldr (\b r -> wlpBlock (inh {acc = r, env = envBlock bs (env inh)}) b) (acc inh) bs -- The result of the last block-statement will be the accumulated transformer for the second-last etc. The type environment is build from the left, so it has to be done seperately. fIfThen e s1 = fIfThenElse e s1 (const id) -- if-then is just an if-then-else with an empty else-block - fIfThenElse e s1 s2 inh = let e' = getExp (foldExp wlpExpAlgebra e) inh - eTrans = getTrans (foldExp wlpExpAlgebra e) inh {acc = id} -- The guard might also have side effects - in ((\q -> (e' &* eTrans ((s1 inh {acc = id}) q)) |* (neg e' &* eTrans ((s2 inh {acc = id}) q))) . acc inh) - fWhile e s inh = let e' = getExp (foldExp wlpExpAlgebra e) inh - in ((\q -> unrollLoop nrOfUnroll e' (getTrans (foldExp wlpExpAlgebra e) inh {acc = id}) ((s (inh {acc = id, br = const q}))) q) . acc inh) + fIfThenElse e s1 s2 inh = let (e', trans) = foldExp wlpExpAlgebra e inh {acc = id} + in ((\q -> (e' &* trans ((s1 inh {acc = id}) q)) |* (neg e' &* trans ((s2 inh {acc = id}) q))) . acc inh) + fWhile e s inh = let (e', trans) = foldExp wlpExpAlgebra e inh {acc = id} + in ((\q -> unrollLoop nrOfUnroll e' trans ((s (inh {acc = id, br = const q}))) q) . acc inh) fBasicFor init me incr s inh = let loop = (fWhile (fromMaybeGuard me) (\inh' -> s (inh {acc = (wlp' inh {acc = id} (incrToStmt incr))})) inh) in wlp' (inh {acc = loop}) (initToStmt init) fEnhancedFor = error "EnhancedFor" fEmpty inh = (acc inh) -- Empty does nothing, but still passes control to the next statement fExpStmt e inh = snd $ foldExp wlpExpAlgebra e inh - fAssert e _ inh = let e' = getExp (foldExp wlpExpAlgebra e) inh - in ((e' &*) . getTrans (foldExp wlpExpAlgebra e) inh) + fAssert e _ inh = let (e', trans) = foldExp wlpExpAlgebra e inh + in ((e' &*) . trans) fSwitch e bs inh = let (e', s1, s2) = desugarSwitch e bs in fIfThenElse e' (flip wlp' s1) (flip wlp' s2) (inh {acc = id, br = acc inh}) fDo s e inh = s (inh {acc = fWhile e s inh}) -- Do is just a while with the statement block executed one additional time. Break and continue still have to be handled in this additional execution. fBreak _ inh = (br inh) -- wlp of the breakpoint. Control is passed to the statement after the loop @@ -85,7 +84,7 @@ wlpStmtAlgebra = (fStmtBlock, fIfThen, fIfThenElse, fWhile, fBasicFor, fEnhanced PrimType _ -> substVar (env inh) (decls inh) (NameLhs (Name [ident])) (getInitValue t) . acc inh -- We don't initialize ref types to null, because we want to keep pointer information RefType _ -> acc inh - wlpDeclAssignment t inh (VarDecl (VarId ident) (Just (InitExp e))) = getTrans (foldExp wlpExpAlgebra (Assign (NameLhs (Name [ident])) EqualA e)) inh + wlpDeclAssignment t inh (VarDecl (VarId ident) (Just (InitExp e))) = snd (foldExp wlpExpAlgebra (Assign (NameLhs (Name [ident])) EqualA e) inh) -- Unrolls a while-loop a finite amount of times unrollLoop :: Int -> Exp -> (Exp -> Exp) -> (Exp -> Exp) -> Exp -> Exp @@ -148,50 +147,63 @@ wlpExpAlgebra = (fLit, fClassLit, fThis, fThisClass, fInstanceCreation, fQualIns fThis inh = (fromJust' "fThis" (object inh), (acc inh)) fThisClass name inh = (ThisClass name, (acc inh)) fInstanceCreation typeArgs t args mBody inh = case args of - [ExpName (Name [Ident "#"])] -> (InstanceCreation typeArgs t args mBody, (acc inh)) -- '#' indicates we already called the constructor method using the correct arguments + [ExpName (Name [Ident "#"])] -> (InstanceCreation typeArgs t args mBody, acc inh) -- '#' indicates we already called the constructor method using the correct arguments _ -> -- Create a var, assign a new instance to var, then call the constructor method on var - let (var, invocation) = (Name [getReturnVar invocation], MethodCall (Name [getReturnVar invocation, Ident ("#" ++ getClassName t)]) args) - in (ExpName var, (substVar (env inh) (decls inh) (NameLhs var) (InstanceCreation typeArgs t [ExpName (Name [Ident "#"])] mBody) . getTrans (fMethodInv invocation) inh {acc = id, object = Just (ExpName var)} . acc inh)) - fQualInstanceCreation e typeArgs t args mBody inh = (QualInstanceCreation (getExp e inh) typeArgs t args mBody, (getTrans e inh)) - fArrayCreate t dimLengths dim inh = (ArrayCreate t (map (flip getExp inh) dimLengths) dim, (acc inh)) - fArrayCreateInit t dim init inh = (ArrayCreateInit t dim init, (acc inh)) + let varId = getReturnVar invocation + var = Name [varId] + invocation = MethodCall (Name [varId, Ident ("#" ++ getClassName t)]) args + in (ExpName var, (substVar (env inh) (decls inh) (NameLhs var) (InstanceCreation typeArgs t [ExpName (Name [Ident "#"])] mBody) . snd ((fMethodInv invocation) inh {acc = id}) . acc inh)) + fQualInstanceCreation e typeArgs t args mBody inh = error "fQualInstanceCreation" + fArrayCreate t dimLengths dim inh = (ArrayCreate t (map (\e -> fst (e inh)) dimLengths) dim, acc inh) + fArrayCreateInit t dim init inh = (ArrayCreateInit t dim init, acc inh) fFieldAccess fieldAccess inh = (ExpName (foldFieldAccess inh fieldAccess), (acc inh)) fMethodInv invocation inh = case invocation of MethodCall (Name [Ident "*assume"]) [e] -> (false, (if e == false then const true else imp e)) _ -> if getCallCount (calls inh) (invocationToId invocation) >= nrOfUnroll - then (false, (const true)) - else let callWlp = wlp' (inh {acc = id, calls = incrCallCount (calls inh) (invocationToId invocation), ret = Just (getReturnVar invocation), object = getObject inh invocation}) (inlineMethod inh invocation) - in (callWlp (ExpName (Name [getReturnVar invocation])), (callWlp . acc inh)) + then (false, const true) + else let varId = getReturnVar invocation + callWlp = wlp' (inh {acc = id, calls = incrCallCount (calls inh) (invocationToId invocation), ret = Just varId, object = getObject inh invocation}) (inlineMethod inh invocation) + in (callWlp (ExpName (Name [varId])), (callWlp . acc inh)) fArrayAccess (ArrayIndex a i) inh = case catch inh of - Nothing -> (arrayAccess a i, (getTrans (foldExp wlpExpAlgebra a) inh)) - Just (cs, f) -> (arrayAccess a i, (getTrans (foldExp wlpExpAlgebra a) inh {acc = id} . arrayAccessWlp a i inh)) + Nothing -> (arrayAccess a i, snd ((foldExp wlpExpAlgebra a) inh)) + Just (cs, f) -> (arrayAccess a i, snd ((foldExp wlpExpAlgebra a) inh {acc = id}) . arrayAccessWlp a i inh) fExpName name inh = (ExpName name, (acc inh)) -- x++ increments x but evaluates to the original value - fPostIncrement e inh = case getExp e inh of - var@(ExpName name) -> (var, (substVar (env inh) (decls inh) (NameLhs name) (BinOp var Add (Lit (Int 1))) . getTrans e inh)) - exp -> (exp, (getTrans e inh)) - fPostDecrement e inh = case getExp e inh of - var@(ExpName name) -> (var, (substVar (env inh) (decls inh) (NameLhs name) (BinOp var Rem (Lit (Int 1))) . getTrans e inh)) - exp -> (exp, (getTrans e inh)) + fPostIncrement e inh = let (e', trans) = e inh in + case e' of + var@(ExpName name) -> (var, substVar (env inh) (decls inh) (NameLhs name) (BinOp var Add (Lit (Int 1))) . trans) + exp -> (exp, trans) + fPostDecrement e inh = let (e', trans) = e inh in + case e' of + var@(ExpName name) -> (var, substVar (env inh) (decls inh) (NameLhs name) (BinOp var Rem (Lit (Int 1))) . trans) + exp -> (exp, trans) -- ++x increments x and evaluates to the new value of x - fPreIncrement e inh = case getExp e inh of - var@(ExpName name) -> (BinOp var Add (Lit (Int 1)), (substVar (env inh) (decls inh) (NameLhs name) (BinOp var Add (Lit (Int 1))) . getTrans e inh)) - exp -> (BinOp exp Add (Lit (Int 1)), (getTrans e inh)) - fPreDecrement e inh = case getExp e inh of - var@(ExpName name) -> (BinOp var Rem (Lit (Int 1)), (substVar (env inh) (decls inh) (NameLhs name) (BinOp var Rem (Lit (Int 1))) . getTrans e inh)) - exp -> (BinOp exp Rem (Lit (Int 1)), (getTrans e inh)) - fPrePlus e inh = (getExp e inh, (getTrans e inh)) - fPreMinus e inh = (PreMinus $ getExp e inh, (getTrans e inh)) - fPreBitCompl e inh = (PreBitCompl $ getExp e inh, (getTrans e inh)) - fPreNot e inh = (PreNot $ getExp e inh, (getTrans e inh)) - fCast t e inh = (getExp e inh, (getTrans e inh)) - fBinOp e1 op e2 inh = (BinOp (getExp e1 inh) op (getTrans e1 (inh {acc = id}) (getExp e2 inh)), (getTrans e1 (inh {acc = getTrans e2 inh}))) -- Side effects of the first expression are applied before the second is evaluated, so we have to apply the transformer + fPreIncrement e inh = let (e', trans) = e inh in + case e' of + var@(ExpName name) -> (BinOp var Add (Lit (Int 1)), substVar (env inh) (decls inh) (NameLhs name) (BinOp var Add (Lit (Int 1))) . trans) + exp -> (BinOp exp Add (Lit (Int 1)), trans) + fPreDecrement e inh = let (e', trans) = e inh in + case e' of + var@(ExpName name) -> (BinOp var Rem (Lit (Int 1)), substVar (env inh) (decls inh) (NameLhs name) (BinOp var Rem (Lit (Int 1))) . trans) + exp -> (BinOp exp Rem (Lit (Int 1)), trans) + fPrePlus e inh = let (e', trans) = e inh in (e', trans) + fPreMinus e inh = let (e', trans) = e inh in (PreMinus e', trans) + fPreBitCompl e inh = let (e', trans) = e inh in (PreBitCompl e', trans) + fPreNot e inh = let (e', trans) = e inh in (PreNot e', trans) + fCast t e inh = let (e', trans) = e inh in (e', trans) + fBinOp e1 op e2 inh = let (e1', trans1) = e1 inh {acc = id} + (e2', trans2) = e2 inh {acc = id} + in (BinOp e1' op e2', trans1 . trans2 . acc inh) -- Side effects of the first expression are applied before the second is evaluated, so we have to apply the transformer fInstanceOf = error "instanceOf" - fCond g e1 e2 inh = (Cond (getExp g inh) (getExp e1 inh) (getExp e2 inh), (getTrans g (inh {acc = id}) . (\q -> (getExp g inh &* getTrans e1 (inh {acc = id}) q) |* (neg (getExp g inh) &* getTrans e2 (inh {acc = id}) q)) . acc inh)) + fCond g e1 e2 inh = let (e1', trans1) = e1 inh {acc = id} + (e2', trans2) = e2 inh {acc = id} + (g', transg) = g inh {acc = id} + in (Cond g' e1' e2', (transg . (\q -> (g' &* trans1 q) |* (neg g' &* trans2 q)) . acc inh)) fAssign lhs op e inh = let lhs' = foldLhs inh lhs - rhs' = desugarAssign lhs' op (getExp e inh) - in (rhs', (getTrans e inh {acc = id} . substVar (env inh) (decls inh) lhs' rhs' . acc inh)) + rhs' = desugarAssign lhs' op e' + (e', trans) = e inh {acc = id} + in (rhs', trans . substVar (env inh) (decls inh) lhs' rhs' . acc inh) fLambda = error "lambda" fMethodRef = error "method reference" @@ -265,28 +277,22 @@ wlpExpAlgebra = (fLit, fClassLit, fThis, fThisClass, fInstanceCreation, fQualIns -- Folds the expression part of an lhs foldLhs :: Inh -> Lhs -> Lhs foldLhs inh lhs = case lhs of - FieldLhs (PrimaryFieldAccess e id) -> case getExp (foldExp wlpExpAlgebra e) inh of + FieldLhs (PrimaryFieldAccess e id) -> case fst (foldExp wlpExpAlgebra e inh) of ExpName name -> NameLhs (Name (fromName name ++ [id])) _ -> error "foldFieldAccess" - ArrayLhs (ArrayIndex e i) -> ArrayLhs (ArrayIndex (getExp (foldExp wlpExpAlgebra e) inh) (map (\e -> getExp (foldExp wlpExpAlgebra e) inh) i)) + ArrayLhs (ArrayIndex e i) -> let e' = fst (foldExp wlpExpAlgebra e inh) + in ArrayLhs (ArrayIndex e' (map (\e'' -> fst (foldExp wlpExpAlgebra e'' inh)) i)) lhs' -> lhs' -- Folds the expression part of a fieldaccess and simplifies it to a name foldFieldAccess :: Inh -> FieldAccess -> Name foldFieldAccess inh fieldAccess = case fieldAccess of - PrimaryFieldAccess e id -> case getExp (foldExp wlpExpAlgebra e) inh of + PrimaryFieldAccess e id -> case fst (foldExp wlpExpAlgebra e inh) of ExpName name -> Name (fromName name ++ [id]) x -> error ("foldFieldAccess: " ++ show x ++ show id) SuperFieldAccess id -> foldFieldAccess inh (PrimaryFieldAccess (fromJust' "foldFieldAccess" (object inh)) id) ClassFieldAccess name id -> Name (fromName name ++ [id]) --- | Gets the expression attribute -getExp :: (Inh -> (Exp, Syn)) -> Inh -> Exp -getExp f inh = let (e, _) = f inh in e - --- | Gets the transformer attribute -getTrans :: (Inh -> (Exp, Syn)) -> Inh -> Exp -> Exp -getTrans f inh = let (_, trans) = f inh in trans -- | Calculates the weakest liberal pre-condition of a statement and a given post-condition wlp :: [TypeDecl] -> Stmt -> Exp -> Exp -- GitLab