From 304a8d3bf2c7b037769c36f3465c1dbe7a645c0d Mon Sep 17 00:00:00 2001
From: Orestis Melkonian <melkon.or@gmail.com>
Date: Mon, 5 Feb 2018 16:18:08 +0100
Subject: [PATCH] Rebased Z3 onto QuickCheck.

---
 javawlp.cabal                                 | 23 ++++++-----
 .../{ => QuickCheck}/ModelGenerator.hs        | 15 +++----
 src/LogicIR/Backend/{ => QuickCheck}/Test.hs  | 13 +++---
 src/LogicIR/Backend/{ => Z3}/API.hs           |  8 ++--
 src/LogicIR/Backend/{ => Z3}/Model.hs         |  4 +-
 src/LogicIR/Backend/{ => Z3}/Pretty.hs        |  5 ++-
 src/LogicIR/Backend/{ => Z3}/Z3.hs            |  2 +-
 src/LogicIR/Eval.hs                           | 22 +++-------
 src/LogicIR/Pretty.hs                         |  1 -
 src/SimpleFormulaChecker.hs                   | 41 +++++++++++++++----
 test/Spec.hs                                  |  1 +
 test/TIRTest.hs                               |  2 +-
 test/TZ3Model.hs                              |  3 +-
 13 files changed, 76 insertions(+), 64 deletions(-)
 rename src/LogicIR/Backend/{ => QuickCheck}/ModelGenerator.hs (87%)
 rename src/LogicIR/Backend/{ => QuickCheck}/Test.hs (97%)
 rename src/LogicIR/Backend/{ => Z3}/API.hs (94%)
 rename src/LogicIR/Backend/{ => Z3}/Model.hs (98%)
 rename src/LogicIR/Backend/{ => Z3}/Pretty.hs (97%)
 rename src/LogicIR/Backend/{ => Z3}/Z3.hs (98%)

diff --git a/javawlp.cabal b/javawlp.cabal
index a4f01e0..eb917c3 100644
--- a/javawlp.cabal
+++ b/javawlp.cabal
@@ -20,28 +20,31 @@ library
   exposed-modules:     Javawlp.Engine.Types
                      , Javawlp.Engine.HelperFunctions
                      , Javawlp.Engine.Folds
+                     -- LIR
                      , LogicIR.Expr
                      , LogicIR.Fold
                      , LogicIR.Parser
                      , LogicIR.Null
                      , LogicIR.Pretty
                      , LogicIR.Frontend.Java
-                     , LogicIR.Backend.Z3
-                     , LogicIR.Backend.Test
-                     , LogicIR.Backend.ModelGenerator
-                     , LogicIR.Backend.Pretty
-                     , LogicIR.Backend.Null
-                     , LogicIR.Fold
                      , LogicIR.Eval
-                     , LogicIR.Backend.API
-                     , LogicIR.Backend.Model
+                     -- Checker
+                     , SimpleFormulaChecker
+                     -- Z3
+                     , LogicIR.Backend.Z3.Z3
+                     , LogicIR.Backend.Z3.API
+                     , LogicIR.Backend.Z3.Model
+                     , LogicIR.Backend.Z3.Pretty
+                     -- QuickCheck
+                     , LogicIR.Backend.QuickCheck.Test
+                     , LogicIR.Backend.QuickCheck.ModelGenerator
+                     -- Java EDSL
                      , Language.Java.Lexer
                      , Language.Java.Parser
                      , Language.Java.Pretty
                      , Language.Java.Syntax
                      , Language.Java.Syntax.Exp
                      , Language.Java.Syntax.Types
-                     , SimpleFormulaChecker
   build-depends:       base >= 4.7 && < 5
                      , random
                      , parsec
@@ -52,8 +55,6 @@ library
                      , mtl
                      , containers
   default-language:    Haskell2010
-  -- build-tools:         alex, happy
-  -- other-modules:       ModelParser.Lexer, ModelParser.Parser
 
 test-suite javawlp-tests
   type:                exitcode-stdio-1.0
diff --git a/src/LogicIR/Backend/ModelGenerator.hs b/src/LogicIR/Backend/QuickCheck/ModelGenerator.hs
similarity index 87%
rename from src/LogicIR/Backend/ModelGenerator.hs
rename to src/LogicIR/Backend/QuickCheck/ModelGenerator.hs
index 425cf6e..ac57a56 100644
--- a/src/LogicIR/Backend/ModelGenerator.hs
+++ b/src/LogicIR/Backend/QuickCheck/ModelGenerator.hs
@@ -1,18 +1,19 @@
-module LogicIR.Backend.ModelGenerator (generateModel, generateArrayModel, Model, ArrayModel) where
+module LogicIR.Backend.QuickCheck.ModelGenerator (generateModel, generateArrayModel, Model, ArrayModel) where
 
-import LogicIR.Expr
 import Data.List (find, nub, (\\))
 import System.Random
 import Data.Maybe (isNothing, fromJust)
 import Data.Map (Map)
 import qualified Data.Map.Lazy as M
 
+import LogicIR.Expr
+
 type Model = [(LExpr, LExpr)]
 type ArrayModel = Map Var [LConst]
 
 -- Generates a constant value for all vars vars in the given list.
 generateModel :: [LExpr] -> IO Model
-generateModel exprs = mapM generateModelEntry exprs
+generateModel = mapM generateModelEntry
 
 generateArrayModel :: [LExpr] -> IO ArrayModel
 generateArrayModel es = mapM generateArray es >>= \l -> return (M.fromList l)
@@ -31,9 +32,9 @@ generateArrayModel es = mapM generateArray es >>= \l -> return (M.fromList l)
                        This is because otherwise, the evaluation of an LExpr should be changed drastically.
                        After all, How do you evaluate a[0] or a.length if a == null... -}
 generateModelEntry :: LExpr -> IO (LExpr, LExpr)
-generateModelEntry e@(LVar (Var (TPrim t) _)) = do
+generateModelEntry e@(LVar (Var (TPrim t) _)) =
     generatePrimitive t >>= \v -> return (e, v)
-generateModelEntry e@(LIsnull (Var (TArray _) _)) = do
+generateModelEntry e@(LIsnull (Var (TArray _) _)) =
     generatePrimitive PBool >>= \v -> return (e, v)
 generateModelEntry e =
     error $ "Cannot generate model entry for " ++ show e
@@ -54,9 +55,9 @@ generateIntWithBounds b = getStdRandom (randomR b)
 -- some type primitive type.
 bounds :: Primitive -> (Int, Int)
 bounds PBool  = (0, 1)
-bounds PInt32 = (-10, 10)
+bounds PInt = (-10, 10)
 
 -- Generates an LExpr given a Primitive type and a value.
 toLExpr :: Primitive -> Int -> LExpr
 toLExpr PBool  v = LConst $ CBool $ v == 1
-toLExpr PInt32 v = LConst $ CInt  $ v
\ No newline at end of file
+toLExpr PInt v = LConst $ CInt v
diff --git a/src/LogicIR/Backend/Test.hs b/src/LogicIR/Backend/QuickCheck/Test.hs
similarity index 97%
rename from src/LogicIR/Backend/Test.hs
rename to src/LogicIR/Backend/QuickCheck/Test.hs
index 902110c..9184458 100644
--- a/src/LogicIR/Backend/Test.hs
+++ b/src/LogicIR/Backend/QuickCheck/Test.hs
@@ -1,12 +1,11 @@
-module LogicIR.Backend.Test (testEquality) where
+module LogicIR.Backend.QuickCheck.Test (testEquality) where
 
 import LogicIR.Expr
 import LogicIR.Fold
 import LogicIR.Eval
-import LogicIR.Backend.ModelGenerator
-import Data.Maybe (fromMaybe)
+import LogicIR.Backend.QuickCheck.ModelGenerator
+import Data.Maybe (fromMaybe, isNothing, fromJust)
 import Data.List (find, nub, (\\))
-import Data.Maybe (isNothing, fromJust)
 import Data.Map (Map)
 import qualified Data.Map.Lazy as M
 
@@ -26,7 +25,7 @@ testEquality 0 e1 e2 = do
     return (True, ([], M.empty))
 testEquality n e1 e2 = do
     (r,m1,m2) <- test e1 e2
-    if not r then do 
+    if not r then do
         return (False, (m1, m2))
     else do
         (rs, model) <- testEquality (n-1) e1 e2
@@ -37,7 +36,7 @@ testEquality n e1 e2 = do
 -- is used, and the model itself. If the formula, after substitution, cannot
 -- be evaluated - i.e. there's still a variable in the LExpr - an error will be thrown.
 testLExpr :: LExpr -> IO (LConst, EvalInfo)
-testLExpr e = do 
+testLExpr e = do
     let vs@(regularVs, (arrayVs, arrayOpVs), quantVs) = findVariables e
     let isNullExprs   = filter sIsnullExpr arrayOpVs
     primitivesModel  <- generateModel (regularVs ++ isNullExprs)
@@ -74,7 +73,7 @@ applyModel e evalInfo = foldLExpr algebra e
 
 get arr model = do
     let res = (M.lookup) arr model
-    if res == Nothing then do 
+    if res == Nothing then do
         error $ "Bug in Test.hs made substitution of Array expression impossible. This should never happen. Array: " ++ show arr ++ ", ArrayModel: " ++ show model
         []
     else do
diff --git a/src/LogicIR/Backend/API.hs b/src/LogicIR/Backend/Z3/API.hs
similarity index 94%
rename from src/LogicIR/Backend/API.hs
rename to src/LogicIR/Backend/Z3/API.hs
index 67fdae9..d6c8347 100644
--- a/src/LogicIR/Backend/API.hs
+++ b/src/LogicIR/Backend/Z3/API.hs
@@ -1,4 +1,4 @@
-module LogicIR.Backend.API where
+module LogicIR.Backend.Z3.API where
 
 import Z3.Monad
 import Z3.Opts
@@ -9,10 +9,10 @@ import Control.Monad.Trans (liftIO)
 import Data.Maybe (fromJust)
 import Data.Monoid ((<>))
 
-import LogicIR.Backend.Model
+import LogicIR.Backend.Z3.Model
 
-import LogicIR.Backend.Pretty (showRelevantModel)
-import LogicIR.Backend.Z3
+import LogicIR.Backend.Z3.Pretty (showRelevantModel)
+import LogicIR.Backend.Z3.Z3
 import LogicIR.Expr (LExpr)
 
 -- | Z3 Response type.
diff --git a/src/LogicIR/Backend/Model.hs b/src/LogicIR/Backend/Z3/Model.hs
similarity index 98%
rename from src/LogicIR/Backend/Model.hs
rename to src/LogicIR/Backend/Z3/Model.hs
index 78bcd68..cfa8ec6 100644
--- a/src/LogicIR/Backend/Model.hs
+++ b/src/LogicIR/Backend/Z3/Model.hs
@@ -1,6 +1,6 @@
 {-# LANGUAGE FlexibleContexts  #-}
 {-# LANGUAGE OverloadedStrings #-}
-module LogicIR.Backend.Model where
+module LogicIR.Backend.Z3.Model where
 
 import Data.String
 import System.IO.Unsafe (unsafePerformIO)
@@ -11,8 +11,6 @@ import Text.Parsec.Language
 import Text.Parsec.String
 import qualified Text.Parsec.Token as Tokens
 
-import Debug.Trace
-
 data FuncInst = InstVal Integer ModelVal
               | InstElse ModelVal
               deriving (Show, Read, Eq, Ord)
diff --git a/src/LogicIR/Backend/Pretty.hs b/src/LogicIR/Backend/Z3/Pretty.hs
similarity index 97%
rename from src/LogicIR/Backend/Pretty.hs
rename to src/LogicIR/Backend/Z3/Pretty.hs
index 4d96c8f..7868b41 100644
--- a/src/LogicIR/Backend/Pretty.hs
+++ b/src/LogicIR/Backend/Z3/Pretty.hs
@@ -1,11 +1,12 @@
-module LogicIR.Backend.Pretty (showRelevantModel) where
+module LogicIR.Backend.Z3.Pretty (showRelevantModel) where
+
 import Data.List
 import Data.Maybe
 import qualified Data.Map as M
 import Z3.Monad
 import Z3.Opts
 
-import LogicIR.Backend.Model
+import LogicIR.Backend.Z3.Model
 
 -- | Function that shows a human-readable model and also highlights potential inconsistencies.
 showRelevantModel :: Z3Model -> IO ()
diff --git a/src/LogicIR/Backend/Z3.hs b/src/LogicIR/Backend/Z3/Z3.hs
similarity index 98%
rename from src/LogicIR/Backend/Z3.hs
rename to src/LogicIR/Backend/Z3/Z3.hs
index e30794d..f03babc 100644
--- a/src/LogicIR/Backend/Z3.hs
+++ b/src/LogicIR/Backend/Z3/Z3.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE OverloadedStrings #-}
-module LogicIR.Backend.Z3 where
+module LogicIR.Backend.Z3.Z3 where
 
 import Z3.Monad
 import Control.Monad.Trans (liftIO)
diff --git a/src/LogicIR/Eval.hs b/src/LogicIR/Eval.hs
index 939e89b..5fc82fc 100644
--- a/src/LogicIR/Eval.hs
+++ b/src/LogicIR/Eval.hs
@@ -10,7 +10,7 @@ eval :: LExpr -> LConst
 eval = foldLExpr evalAlgebra
 
 evalIfPossible :: LExpr -> LExpr
-evalIfPossible e = if evalPossible e then (LConst (eval e)) else e
+evalIfPossible e = if evalPossible e then LConst (eval e) else e
 
 -- Returns True if an LExpr only contains constants and no variables whatsoever.
 evalPossible :: LExpr -> Bool
@@ -33,21 +33,14 @@ evalAlgebra :: LExprAlgebra LConst
 evalAlgebra = (cnst, var, uni, bin, iff, quant, arr, snull, len)
     where cnst b@(CBool _) = b
           cnst i@(CInt  _) = i
-
           uni NNeg (CInt i)  = CInt (-i)
-          uni NNot (CInt i)  = CInt (-i - 1)
           uni LNot (CBool b) = CBool (not b)
-
-          bin le o re     = evalBin le o re
-
-          iff ge e1 e2    = if ge == (CBool True) then e1 else e2
-          
+          bin = evalBin
+          iff ge e1 e2    = if ge == CBool True then e1 else e2
           -- This possibly needs to be changed.
           len v           = CInt  10 -- error "Array length cannot yet be evaluated."
-
           snull (Var (TPrim _) _)  = CBool False -- Primitive type is never null.
           snull (Var (TArray _) _) = error "You can't call eval on an LExpr that has an (LIsnull someArrayVar) that wasn't converted to a boolean first."
-
           -- Things that should never happen.
           quant _ _ e1 e2 = error "Quantifiers cannot be evaluated and should be replaced using LogicIR.Rewrite.replaceQuantifiers."
           arr v a         = error "You can't call eval on an LExpr that contains uninstantiated arrays."
@@ -61,9 +54,9 @@ evalBin (CInt l) CGreater (CInt r) = CBool (l > r)
 -- Logical operators
 evalBin (CBool l) LAnd  (CBool r) = CBool (l && r)
 evalBin (CBool l) LOr   (CBool r) = CBool (l || r)
-evalBin (CBool l) LImpl (CBool r) = CBool ((not l) || (l && r))
+evalBin (CBool l) LImpl (CBool r) = CBool (not l || (l && r))
 -- Numerical operators
-evalBin (CInt l) o (CInt r) = CInt ((convert o) l r)
+evalBin (CInt l) o (CInt r) = CInt (convert o l r)
      -- Both NShr and NShl are evaluated using the Data.Bits.shift function,
      -- where a right shift is achieved by inverting the r integer.
      where convert NAdd = (+)
@@ -71,8 +64,3 @@ evalBin (CInt l) o (CInt r) = CInt ((convert o) l r)
            convert NMul = (*)
            convert NDiv = div
            convert NRem = mod
-           convert NShl = shiftL
-           convert NShr = shiftR
-           convert NAnd = (.&.)
-           convert NOr  = (.|.)
-           convert NXor = xor
diff --git a/src/LogicIR/Pretty.hs b/src/LogicIR/Pretty.hs
index c24fb1f..10df1c7 100644
--- a/src/LogicIR/Pretty.hs
+++ b/src/LogicIR/Pretty.hs
@@ -7,7 +7,6 @@ import qualified Data.Map as M
 import Z3.Monad
 import Z3.Opts
 
-import LogicIR.Backend.Model
 import LogicIR.Expr
 import LogicIR.Fold
 
diff --git a/src/SimpleFormulaChecker.hs b/src/SimpleFormulaChecker.hs
index 518329c..db2c459 100644
--- a/src/SimpleFormulaChecker.hs
+++ b/src/SimpleFormulaChecker.hs
@@ -12,14 +12,12 @@ import Language.Java.Parser
 import Language.Java.Pretty
 import Language.Java.Syntax
 
-import qualified LogicIR.Backend.API as Z3
+import qualified LogicIR.Backend.Z3.API as Z3
 import LogicIR.Expr
 import LogicIR.Eval
-import LogicIR.Frontend.Java
-import LogicIR.Backend.Z3
-import LogicIR.Backend.Test
-import LogicIR.Backend.Pretty
-import LogicIR.Backend.Null
+import LogicIR.Backend.Z3.Z3
+import LogicIR.Backend.QuickCheck.Test
+import LogicIR.Backend.Z3.Pretty
 
 import LogicIR.Frontend.Java (javaExpToLExpr)
 import LogicIR.Null (lExprPreprocessNull)
@@ -98,5 +96,32 @@ extractExpr call = combineExprs $ map (\(MethodCall (Name [Ident _]) [a]) -> a)
           combineExprs [e]    = e
           combineExprs (e:es) = e &* combineExprs es
 
-test9 = testSpec (edslSrc, "swap_spec1") (edslSrc, "swap_spec4") 1000
-    where edslSrc = "examples/javawlp_edsl/src/nl/uu/javawlp_edsl/Main.java"
+parse :: (FilePath, String) -> (FilePath, String) -> IO (MethodDef, MethodDef)
+parse method1@(_, name1) method2@(_, name2) = do
+    -- load the methods
+    m1@(decls1, mbody1, env1) <- parseMethod method1
+    m2@(decls2, mbody2, env2) <- parseMethod method2
+    when (env1 /= env2) $ fail "inconsistent method parameters"
+    when (decls1 /= decls2) $ fail "inconsistent class declarations (TODO)"
+    return (m1, m2)
+
+methodDefToLExpr :: MethodDef -> MethodDef -> String -> (LExpr, LExpr)
+methodDefToLExpr m1@(decls1, _, env1) m2@(decls2, _, env2) name = do
+    -- get pre/post condition
+    let (e1, e2) = (extractCond m1 name, extractCond m2 name)
+    let (lExpr1', lExpr2') = (javaExpToLExpr e1 env1 decls1, javaExpToLExpr e2 env2 decls2)
+    -- preprocess "a == null" to "isNull(a)"
+    let (lExpr1, lExpr2) = (lExprPreprocessNull lExpr1', lExprPreprocessNull lExpr2')
+    (lExpr1, lExpr2)
+        where extractCond m n = extractExpr $ getMethodCalls m n
+
+testSpec :: (FilePath, String) -> (FilePath, String) -> Int -> IO Bool
+testSpec method1@(_, name1) method2@(_, name2) n = do
+    (m1, m2) <- parse method1 method2
+    putStrLn $ "----PRE---- (" ++ name1 ++ " vs " ++ name2 ++ ")"
+    let (lExpr1, lExpr2) = methodDefToLExpr m1 m2 "pre"
+    (preAns, counterModel) <- testEquality n lExpr1 lExpr2
+    putStrLn "\n----POST---"
+    let (lExpr1, lExpr2) = methodDefToLExpr m1 m2 "post"
+    (postAns, counterModel) <- testEquality n lExpr1 lExpr2
+    return $ preAns && postAns
diff --git a/test/Spec.hs b/test/Spec.hs
index 4b11dcc..d7ec9c8 100644
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -13,6 +13,7 @@ main = defaultMain
         ("LIR_PARSER", parserTests)
       , ("Z3_MODEL", modelTests)
       , ("EXAMPLES", examples)
+      , ("AUTOMATED_TESTING_CHECK", testingModuleTests)
       , ("EQUIV_REAL", genEquivTests "examples/test_equiv/Reals.java")
       , ("EQUIV_ARRAY", genEquivTests "examples/test_equiv/Arrays.java")
       ]
diff --git a/test/TIRTest.hs b/test/TIRTest.hs
index 448e892..2270962 100644
--- a/test/TIRTest.hs
+++ b/test/TIRTest.hs
@@ -31,4 +31,4 @@ testingModuleTests =
   , (neq "sorted3" "test2" 100)
   , (neq "sorted3" "sorted4" 500)
   , (neq  "sorted1" "sorted4" 100)
-  ]
\ No newline at end of file
+  ]
diff --git a/test/TZ3Model.hs b/test/TZ3Model.hs
index 7fb1298..9246154 100644
--- a/test/TZ3Model.hs
+++ b/test/TZ3Model.hs
@@ -3,8 +3,7 @@ import System.IO.Unsafe (unsafePerformIO)
 import System.IO.Silently (silence)
 import Test.HUnit
 
-import LogicIR.Backend.Model
-import Debug.Trace
+import LogicIR.Backend.Z3.Model
 
 (~~) model ast = runP modelP model @?= ast
 
-- 
GitLab