From cdee1177ae3e73eb54373da18451ff3dbca300c9 Mon Sep 17 00:00:00 2001 From: koen <koenwermer@gmail.com> Date: Tue, 27 Sep 2016 21:48:57 +0200 Subject: [PATCH] blocks (sequences of statements) are now handled correctly w.r.t. dealing with statements that pass control in different ways --- WLP.hs | 84 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/WLP.hs b/WLP.hs index c3e4624..c13baaa 100644 --- a/WLP.hs +++ b/WLP.hs @@ -3,11 +3,11 @@ module WLP where import Language.Java.Syntax import Language.Java.Lexer import Language.Java.Parser +import Data.Maybe import Verifier - type StmtAlgebra r = (Block -> r, Exp -> r -> r, Exp -> r -> r -> r, @@ -29,6 +29,19 @@ type StmtAlgebra r = (Block -> r, ) +-- Some constants: + +-- Differentiate between different exceptions? +diffExc :: Bool +diffExc = False + +true :: Exp +true = Lit (Boolean True) + +false :: Exp +false = Lit (Boolean False) + + -- Logical operators for expressions: (&*) :: Exp -> Exp -> Exp e1 &* e2 = BinOp e1 And e2 @@ -58,37 +71,43 @@ foldStmt (fStmtBlock, fIfThen, fIfThenElse, fWhile, fBasicFor, fEnhancedFor, fEm -- | A type synonym for the inherited attribute - - -type Inh = (Exp -> Exp, -- The accumulated transformer up till the last loop (this is used when handling break statements etc.) - Exp -> Exp -- The wlp of the current loop statement not including initialization code. It refers to the loop starting from the loop continuation point. +type Inh = (Exp -> Exp, -- The accumulated transformer of the current block up until the current statement + Exp -> Exp, -- The accumulated transformer up until the last loop (this is used when handling break statements etc.) + Exp -> Exp, -- The wlp of the current loop statement not including initialization code. It refers to the loop starting from the loop continuation point. + Maybe ([Catch], Bool) -- The catches when executing a block in a try statement, and a Bool indicating wether there is a finally-block ) + +-- | A type synonym for the synthesized attribute +type Syn = Exp -> Exp -- | The algebra that defines the wlp transformer for statements -- The synthesized attribute is the resulting transformer. -wlpStmtAlgebra :: StmtAlgebra (Inh -> Exp -> Exp) +-- Statements that pass control to the next statement have to explicitly combine their wlp function with the accumulated function, as some statements (e.g. break) ignore the accumulated function. +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 ((.) . wlpBlock inh) id bs - fIfThen e s1 = fIfThenElse e s1 (const id) - fIfThenElse e s1 s2 inh = (\q -> (e &* s1 inh q) |* (neg e &* s2 inh q)) - fWhile e s (acc, _) = let loop = (\q -> if isTrue (((inv &* neg e) `imp` q) &* ((inv &* e) `imp` s (acc, loop) inv)) then inv else (neg e &* q)) in loop - fBasicFor init e incr s inh@(acc, _) = wlp' inh (initToStmt init) . let loop = fWhile (fromMaybeGuard e) (\inh' -> s (acc, loop) . wlp' inh' (incrToStmt incr)) inh in loop - fEnhancedFor = error "TODO: EnhancedFor" - fEmpty inh = id - fExpStmt = error "TODO: ExpStmt" - fAssert e _ inh = (e &*) - fSwitch e bs inh = let (e', s1, s2) = desugarSwitch e bs in fIfThenElse e' (flip wlp' s1) (flip wlp' s2) inh - fDo s e (acc, _) = let loop = s (acc, loop) . fWhile e s (acc, loop) in loop -- 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 _ (acc, _) = acc - fContinue _ (acc, loop) = loop . acc - fReturn = undefined - fSynchronized = undefined - fThrow = undefined - fTry = undefined - fLabeled = undefined + fStmtBlock (Block bs) (acc, br, loop, catch) = foldr (\b r -> wlpBlock (r, br, loop, catch) b) acc bs -- The result of the last block-statement will be the accumulated transformer for the second-last etc. + 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@(acc, _, _, _) = (\q -> (e &* s1 inh q) |* (neg e &* s2 inh q)) . acc + fWhile e s (acc, br, _, catch) = let loop = (\q -> if isTrue (((inv &* neg e) `imp` q) &* ((inv &* e) `imp` s (id, br, loop, catch) inv)) then inv else (neg e &* q)) in loop . acc + fBasicFor init e incr s inh@(acc, br, loop, catch) = let loop' = fWhile (fromMaybeGuard e) (\inh' -> s (wlp' inh' (incrToStmt incr), br, loop', catch)) inh in wlp' (loop', br, loop, catch) (initToStmt init) + fEnhancedFor = error "TODO: EnhancedFor" + fEmpty (acc, _, _, _) = acc -- Empty does nothing, but still passes control to the next statement + fExpStmt = error "TODO: ExpStmt" + fAssert e _ inh@(acc, _, _, _) = (e &*) . acc + fSwitch e bs inh@(acc, _, _, _) = let (e', s1, s2) = desugarSwitch e bs in fIfThenElse e' (flip wlp' s1) (flip wlp' s2) inh . acc + fDo s e (acc, br, _, catch) = let loop = s (fWhile e s (acc, br, loop, catch), br, loop, catch) in loop -- 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 _ (_, br, _, _) = br -- wlp of the breakpoint + fContinue _ (_, _, loop, _) = loop -- wlp of the loop + fReturn = error "TODO: Return" + fSynchronized _ = fStmtBlock + fThrow e inh@(acc, br, loop, catch) = case catch of + Nothing -> (\q -> q &* throwException e) -- acc is ignored, as the rest of the block is not executed + Just (cs, f) -> maybe (if f then id else (\q -> q &* throwException e)) (flip fStmtBlock (id, br, loop, Nothing)) (getCatch e cs) + fTry b cs f inh@(acc, br, loop, catch) = fStmtBlock b (id, br, loop, Just (cs, isJust f)) . maybe acc (flip fStmtBlock inh) f -- The finally-block is always executed + fLabeled _ s = s -- Helper functions - wlpBlock :: Inh -> BlockStmt -> Exp -> Exp + wlpBlock :: Inh -> BlockStmt -> Syn wlpBlock inh b = case b of BlockStmt s -> wlp' inh s LocalClass _ -> id @@ -121,13 +140,20 @@ wlpStmtAlgebra = (fStmtBlock, fIfThen, fIfThenElse, fWhile, fBasicFor, fEnhanced SwitchCase e' -> (BinOp e Equal e', StmtBlock (Block bs), sbscode) Default -> (true, StmtBlock (Block bs), sbscode) where sbscode = let (e, s1, s2) = desugarSwitch e sbs in IfThenElse e s1 s2 - -true :: Exp -true = Lit (Boolean True) + + throwException :: Exp -> Exp + throwException e = if diffExc then MethodInv (MethodCall (Name [Ident "Exception"]) [e]) else false + + getCatch :: Exp -> [Catch] -> Maybe Block + getCatch e [] = Nothing + getCatch e (Catch p b:cs) = if p `catches` e then Just b else getCatch e cs + + catches :: FormalParam -> Exp -> Bool + catches (FormalParam _ t _ _) e = True -- TODO -- | Calculates the weakest liberal pre-condition of a statement and a given post-condition wlp :: Stmt -> Exp -> Exp -wlp = wlp' (id, id) +wlp = wlp' (id, id, id, Nothing) -- wlp' lets you specify the inherited attributes wlp' :: Inh -> Stmt -> Exp -> Exp -- GitLab