summaryrefslogtreecommitdiff
path: root/Jennisys/Analyzer.fs
diff options
context:
space:
mode:
Diffstat (limited to 'Jennisys/Analyzer.fs')
-rw-r--r--Jennisys/Analyzer.fs644
1 files changed, 353 insertions, 291 deletions
diff --git a/Jennisys/Analyzer.fs b/Jennisys/Analyzer.fs
index 244b50b4..7bee9194 100644
--- a/Jennisys/Analyzer.fs
+++ b/Jennisys/Analyzer.fs
@@ -1,295 +1,357 @@
-module Analyzer
-
-open Ast
-open AstUtils
-open CodeGen
-open DafnyModelUtils
-open PipelineUtils
-open Options
-open Printer
-open Resolver
-open DafnyPrinter
-open Utils
-
-open Microsoft.Boogie
-
-let VarsAreDifferent aa bb =
- printf "false"
- List.iter2 (fun (_,Var(a,_)) (_,Var(b,_)) -> printf " || %s != %s" a b) aa bb
-
-let Rename suffix vars =
- vars |> List.map (function Var(nm,tp) -> nm, Var(nm + suffix, tp))
-
-let ReplaceName substMap nm =
- match Map.tryFind nm substMap with
- | Some(Var(name, tp)) -> name
- | None -> nm
-
-let rec Substitute substMap = function
- | IdLiteral(s) -> IdLiteral(ReplaceName substMap s)
- | Dot(e,f) -> Dot(Substitute substMap e, ReplaceName substMap f)
- | UnaryExpr(op,e) -> UnaryExpr(op, Substitute substMap e)
- | BinaryExpr(n,op,e0,e1) -> BinaryExpr(n, op, Substitute substMap e0, Substitute substMap e1)
- | SelectExpr(e0,e1) -> SelectExpr(Substitute substMap e0, Substitute substMap e1)
- | UpdateExpr(e0,e1,e2) -> UpdateExpr(Substitute substMap e0, Substitute substMap e1, Substitute substMap e2)
- | SequenceExpr(ee) -> SequenceExpr(List.map (Substitute substMap) ee)
- | SeqLength(e) -> SeqLength(Substitute substMap e)
- | ForallExpr(vv,e) -> ForallExpr(vv, Substitute substMap e)
- | expr -> expr
-
-let GenMethodAnalysisCode comp methodName signature pre post assertion =
- " method " + methodName + "()" + newline +
- " modifies this;" + newline +
- " {" + newline +
- // print signature as local variables
- (match signature with
- | Sig(ins,outs) ->
- List.concat [ins; outs] |> List.fold (fun acc vd -> acc + (sprintf " var %s;" (PrintVarDecl vd)) + newline) "") +
- " // assume precondition" + newline +
- " assume " + (PrintExpr 0 pre) + ";" + newline +
- " // assume invariant and postcondition" + newline +
- " assume Valid();" + newline +
- " assume " + (PrintExpr 0 post) + ";" + newline +
- " // assume user defined invariant again because assuming Valid() doesn't always work" + newline +
- (GetInvariantsAsList comp |> PrintSep newline (fun e -> " assume " + (PrintExpr 0 e) + ";")) + newline +
- // if the following assert fails, the model hints at what code to generate; if the verification succeeds, an implementation would be infeasible
- " // assert false to search for a model satisfying the assumed constraints" + newline +
- " assert " + (PrintExpr 0 assertion) + ";" + newline +
- " }" + newline
-
-let MethodAnalysisPrinter onlyForThisCompMethod assertion comp mthd =
- match onlyForThisCompMethod with
- | (c,m) when c = comp && m = mthd ->
- match m with
- | Method(methodName, sign, pre, post, true) -> (GenMethodAnalysisCode comp methodName sign pre post assertion) + newline
- | _ -> ""
- | _ -> ""
-
-let rec IsArgsOnly args expr =
- match expr with
- | IdLiteral(id) -> args |> List.exists (function Var(varName,_) when varName = id -> true | _ -> false)
- | UnaryExpr(_,e) -> IsArgsOnly args e
- | BinaryExpr(_,_,e1,e2) -> (IsArgsOnly args e1) && (IsArgsOnly args e2)
- | Dot(e,_) -> IsArgsOnly args e
- | SelectExpr(e1, e2) -> (IsArgsOnly args e1) && (IsArgsOnly args e2)
- | UpdateExpr(e1, e2, e3) -> (IsArgsOnly args e1) && (IsArgsOnly args e2) && (IsArgsOnly args e3)
- | SequenceExpr(exprs) -> exprs |> List.fold (fun acc e -> acc && (IsArgsOnly args e)) true
- | SeqLength(e) -> IsArgsOnly args e
- | ForallExpr(vars,e) -> IsArgsOnly (List.concat [args; vars]) e
- | IntLiteral(_) -> true
- | Star -> true
-
-let rec GetUnifications expr args (heap,env,ctx) =
- match expr with
- | IntLiteral(_)
- | IdLiteral(_)
- | Star
- | Dot(_)
- | SelectExpr(_) // TODO: handle select expr
- | UpdateExpr(_) // TODO: handle update expr
- | SequenceExpr(_)
- | SeqLength(_)
- | ForallExpr(_) // TODO: handle forall expr
- | UnaryExpr(_) -> Set.empty
- | BinaryExpr(strength,op,e0,e1) ->
- if op = "=" then
- let v0 = Eval e0 (heap,env,ctx)
- let v1 = Eval e1 (heap,env,ctx)
- let argsOnly0 = IsArgsOnly args e0
- let argsOnly1 = IsArgsOnly args e1
- match v0,argsOnly1,argsOnly0,v1 with
- | Some(c0),true,_,_ ->
- Logger.DebugLine (" - adding unification " + (PrintConst c0) + " <--> " + (PrintExpr 0 e1));
- Set.ofList [c0, e1]
- | _,_,true,Some(c1) ->
- Logger.DebugLine (" - adding unification " + (PrintConst c1) + " <--> " + (PrintExpr 0 e0));
- Set.ofList [c1, e0]
- | _ -> Logger.TraceLine (" - couldn't unify anything from " + (PrintExpr 0 expr));
- Set.empty
- else
- GetUnifications e0 args (heap,env,ctx) |> Set.union (GetUnifications e1 args (heap,env,ctx))
-
-let rec GetArgValueUnifications args env =
- match args with
- | Var(name,_) :: rest ->
- match Map.tryFind (VarConst(name)) env with
- | Some(c) ->
- Logger.DebugLine (" - adding unification " + (PrintConst c) + " <--> " + name);
- Set.ofList [c, IdLiteral(name)] |> Set.union (GetArgValueUnifications rest env)
- | None -> failwith ("couldn't find value for argument " + name)
- | [] -> Set.empty
-
-let rec _GetObjRefExpr o (heap,env,ctx) visited =
- if Set.contains o visited then
- None
- else
- let newVisited = Set.add o visited
- let refName = PrintObjRefName o (env,ctx)
- match refName with
- | Exact "this" _ -> Some(IdLiteral(refName))
- | _ ->
- let rec __fff lst =
- match lst with
- | ((o,Var(fldName,_)),l) :: rest ->
- match _GetObjRefExpr o (heap,env,ctx) newVisited with
- | Some(expr) -> Some(Dot(expr, fldName))
- | None -> __fff rest
- | [] -> None
- let backPointers = heap |> Map.filter (fun (_,_) l -> l = o) |> Map.toList
- __fff backPointers
-
-let GetObjRefExpr o (heap,env,ctx) =
- _GetObjRefExpr o (heap,env,ctx) (Set.empty)
-
-let rec UpdateHeapEnv prog comp mthd unifs (heap,env,ctx) =
- match unifs with
- | (c,e) :: rest ->
- let restHeap,env,ctx = UpdateHeapEnv prog comp mthd rest (heap,env,ctx)
- let newHeap = restHeap |> Map.fold (fun acc (o,f) l ->
- let value = Resolve l (env,ctx)
- if value = c then
- let objRefExpr = GetObjRefExpr o (heap,env,ctx) |> Utils.ExtractOptionMsg ("Couldn't find a path from this to " + (PrintObjRefName o (env,ctx)))
- let fldName = PrintVarName f
- let assertionExpr = BinaryEq (Dot(objRefExpr, fldName)) e
- // check if the assertion follows and if so update the env
- let code = PrintDafnyCodeSkeleton prog (MethodAnalysisPrinter (comp,mthd) assertionExpr)
- Logger.Debug(" - checking assertion: " + (PrintExpr 0 assertionExpr) + " ... ")
- let ok = CheckDafnyProgram code ("unif_" + (GetMethodFullName comp mthd))
- if ok then
- Logger.DebugLine " HOLDS"
- // change the value to expression
- acc |> Map.add (o,f) (ExprConst(e))
- else
- Logger.DebugLine " DOESN'T HOLDS"
- // don't change the value
- acc |> Map.add (o,f) l
- else
- // see if it's a list, then try to match its elements
- match value with
- | SeqConst(clist) -> acc |> Map.add (o,f) l //TODO!!
- | _ ->
- // leave it as is
- acc |> Map.add (o,f) l
- ) restHeap
- (newHeap,env,ctx)
- | [] -> (heap,env,ctx)
-
-let GeneralizeSolution prog comp mthd (heap,env,ctx) =
- match mthd with
- | Method(mName,Sig(ins, outs),pre,post,_) ->
- let args = List.concat [ins; outs]
- match args with
- | [] -> (heap,env,ctx)
- | _ ->
- let unifs = GetUnifications (BinaryAnd pre post) args (heap,env,ctx)
- |> Set.union (GetArgValueUnifications args env)
- UpdateHeapEnv prog comp mthd (Set.toList unifs) (heap,env,ctx)
- | _ -> failwith ("not a method: " + mthd.ToString())
-
-// ====================================================================================
-/// Returns whether the code synthesized for the given method can be verified with Dafny
-// ====================================================================================
-let VerifySolution prog comp mthd (heap,env,ctx) =
- // print the solution to file and try to verify it with Dafny
- let solution = Map.empty |> Map.add (comp,mthd) (heap,env,ctx)
- let code = PrintImplCode prog solution (fun p -> [comp,mthd])
- CheckDafnyProgram code dafnyVerifySuffix
-
-// ============================================================================
+module Analyzer
+
+open Ast
+open AstUtils
+open CodeGen
+open DafnyModelUtils
+open PipelineUtils
+open Options
+open Printer
+open Resolver
+open DafnyPrinter
+open Utils
+
+open Microsoft.Boogie
+
+let VarsAreDifferent aa bb =
+ printf "false"
+ List.iter2 (fun (_,Var(a,_)) (_,Var(b,_)) -> printf " || %s != %s" a b) aa bb
+
+let Rename suffix vars =
+ vars |> List.map (function Var(nm,tp) -> nm, Var(nm + suffix, tp))
+
+let ReplaceName substMap nm =
+ match Map.tryFind nm substMap with
+ | Some(Var(name, tp)) -> name
+ | None -> nm
+
+let rec Substitute substMap = function
+ | IdLiteral(s) -> IdLiteral(ReplaceName substMap s)
+ | Dot(e,f) -> Dot(Substitute substMap e, ReplaceName substMap f)
+ | UnaryExpr(op,e) -> UnaryExpr(op, Substitute substMap e)
+ | BinaryExpr(n,op,e0,e1) -> BinaryExpr(n, op, Substitute substMap e0, Substitute substMap e1)
+ | SelectExpr(e0,e1) -> SelectExpr(Substitute substMap e0, Substitute substMap e1)
+ | UpdateExpr(e0,e1,e2) -> UpdateExpr(Substitute substMap e0, Substitute substMap e1, Substitute substMap e2)
+ | SequenceExpr(ee) -> SequenceExpr(List.map (Substitute substMap) ee)
+ | SeqLength(e) -> SeqLength(Substitute substMap e)
+ | ForallExpr(vv,e) -> ForallExpr(vv, Substitute substMap e)
+ | expr -> expr
+
+let GenMethodAnalysisCode comp m assertion =
+ let methodName = GetMethodName m
+ let signature = GetMethodSig m
+ let ppre,ppost = GetMethodPrePost m
+ let pre = Desugar ppre
+ let post = Desugar ppost
+ " method " + methodName + "()" + newline +
+ " modifies this;" + newline +
+ " {" + newline +
+ // print signature as local variables
+ (match signature with
+ | Sig(ins,outs) ->
+ List.concat [ins; outs] |> List.fold (fun acc vd -> acc + (sprintf " var %s;" (PrintVarDecl vd)) + newline) "") +
+ " // assume precondition" + newline +
+ " assume " + (PrintExpr 0 pre) + ";" + newline +
+ " // assume invariant and postcondition" + newline +
+ " assume Valid();" + newline +
+ " assume " + (PrintExpr 0 post) + ";" + newline +
+ " // assume user defined invariant again because assuming Valid() doesn't always work" + newline +
+ (GetInvariantsAsList comp |> PrintSep newline (fun e -> " assume " + (PrintExpr 0 e) + ";")) + newline +
+ // if the following assert fails, the model hints at what code to generate; if the verification succeeds, an implementation would be infeasible
+ " // assert false to search for a model satisfying the assumed constraints" + newline +
+ " assert " + (PrintExpr 0 assertion) + ";" + newline +
+ " }" + newline
+
+let MethodAnalysisPrinter onlyForThisCompMethod assertion comp mthd =
+ match onlyForThisCompMethod with
+ | (c,m) when c = comp && m = mthd ->
+ match m with
+ | Method(methodName, sign, pre, post, true) -> (GenMethodAnalysisCode comp m assertion) + newline
+ | _ -> ""
+ | _ -> ""
+
+let rec IsArgsOnly args expr =
+ match expr with
+ | IntLiteral(_) -> true
+ | BoolLiteral(_) -> true
+ | Star -> true
+ | IdLiteral(id) -> args |> List.exists (function Var(varName,_) when varName = id -> true | _ -> false)
+ | UnaryExpr(_,e) -> IsArgsOnly args e
+ | BinaryExpr(_,_,e1,e2) -> (IsArgsOnly args e1) && (IsArgsOnly args e2)
+ | IteExpr(c,e1,e2) -> (IsArgsOnly args c) && (IsArgsOnly args e1) && (IsArgsOnly args e2)
+ | Dot(e,_) -> IsArgsOnly args e
+ | SelectExpr(e1, e2) -> (IsArgsOnly args e1) && (IsArgsOnly args e2)
+ | UpdateExpr(e1, e2, e3) -> (IsArgsOnly args e1) && (IsArgsOnly args e2) && (IsArgsOnly args e3)
+ | SequenceExpr(exprs) | SetExpr(exprs) -> exprs |> List.fold (fun acc e -> acc && (IsArgsOnly args e)) true
+ | SeqLength(e) -> IsArgsOnly args e
+ | ForallExpr(vars,e) -> IsArgsOnly (List.concat [args; vars]) e
+
+let GetUnifications expr args (heap,env,ctx) =
+ // - first looks if the give expression talks only about method arguments (args)
+ // - then checks if it doesn't already exist in the unification map
+ // - then it tries to evaluate it to a constant
+ // - if all of these succeed, it adds a unification rule e <--> val(e) to the given unifMap map
+ let __AddUnif e unifMap =
+ let builder = new CascadingBuilder<_>(unifMap)
+ builder {
+ let! argsOnly = IsArgsOnly args e |> Utils.BoolToOption
+ let! notAlreadyAdded = Map.tryFind e unifMap |> Utils.IsNoneOption |> Utils.BoolToOption
+ let! v = Eval (heap,env,ctx) e
+ Logger.DebugLine (" - adding unification " + (PrintExpr 0 e) + " <--> " + (PrintConst v));
+ return Map.add e v unifMap
+ }
+ // just recurses on all expressions
+ let rec __GetUnifications expr args unifs =
+ let unifs = __AddUnif expr unifs
+ match expr with
+ | IntLiteral(_)
+ | BoolLiteral(_)
+ | IdLiteral(_)
+ | Star -> unifs
+ | Dot(e, _)
+ | SeqLength(e)
+ | ForallExpr(_,e)
+ | UnaryExpr(_,e) -> unifs |> __GetUnifications e args
+ | SelectExpr(e1, e2)
+ | BinaryExpr(_,_,e1,e2) -> unifs |> __GetUnifications e1 args |> __GetUnifications e2 args
+ | IteExpr(e1,e2,e3)
+ | UpdateExpr(e1, e2, e3) -> unifs |> __GetUnifications e1 args |> __GetUnifications e2 args |> __GetUnifications e3 args
+ | SetExpr(elst)
+ | SequenceExpr(elst) -> elst |> List.fold (fun acc e -> acc |> __GetUnifications e args) unifs
+ (* --- function body starts here --- *)
+ __GetUnifications expr args Map.empty
+
+// =======================================================
+/// Returns a map (Expr |--> Const) containing unifications
+/// found for the given method and heap/env/ctx
+// =======================================================
+let GetUnificationsForMethod comp m (heap,env,ctx) =
+ let rec GetArgValueUnifications args env =
+ match args with
+ | Var(name,_) :: rest ->
+ match Map.tryFind (Unresolved(name)) env with
+ | Some(c) ->
+ Logger.DebugLine (" - adding unification " + (PrintConst c) + " <--> " + name);
+ Map.ofList [IdLiteral(name), c] |> Utils.MapAddAll (GetArgValueUnifications rest env)
+ | None -> failwith ("couldn't find value for argument " + name)
+ | [] -> Map.empty
+ (* --- function body starts here --- *)
+ match m with
+ | Method(mName,Sig(ins, outs),pre,post,_) ->
+ let args = List.concat [ins; outs]
+ match args with
+ | [] -> Map.empty
+ | _ -> GetUnifications (BinaryAnd pre post) args (heap,env,ctx)
+ |> Utils.MapAddAll (GetArgValueUnifications args env)
+ | _ -> failwith ("not a method: " + m.ToString())
+
+// =========================================================================
+/// For a given constant "o" (which is an object, something like "gensym32"),
+/// finds a path of field references from "this".
+///
+/// Implements a backtracking search over the heap entries to find that
+/// path. It starts from the given object, and follows the backpointers
+/// until it reaches the root ("this")
+// =========================================================================
+let GetObjRefExpr o (heap,env,ctx) =
+ let rec __GetObjRefExpr o (heap,env,ctx) visited =
+ if Set.contains o visited then
+ None
+ else
+ let newVisited = Set.add o visited
+ let refName = PrintObjRefName o (env,ctx)
+ match refName with
+ | "this" -> Some(IdLiteral(refName))
+ | _ ->
+ let rec __fff lst =
+ match lst with
+ | ((o,Var(fldName,_)),l) :: rest ->
+ match __GetObjRefExpr o (heap,env,ctx) newVisited with
+ | Some(expr) -> Some(Dot(expr, fldName))
+ | None -> __fff rest
+ | [] -> None
+ let backPointers = heap |> Map.filter (fun (_,_) l -> l = o) |> Map.toList
+ __fff backPointers
+ (* --- function body starts here --- *)
+ __GetObjRefExpr o (heap,env,ctx) (Set.empty)
+
+// =======================================================
+/// Applies given unifications onto the given heap/env/ctx
+///
+/// If "conservative" is true, applies only those that
+/// can be verified to hold, otherwise applies all of them
+// =======================================================
+let rec ApplyUnifications prog comp mthd unifs (heap,env,ctx) conservative =
+ let __CheckUnif o f e idx =
+ if not conservative then
+ true
+ else
+ let objRefExpr = GetObjRefExpr o (heap,env,ctx) |> Utils.ExtractOptionMsg ("Couldn't find a path from 'this' to " + (PrintObjRefName o (env,ctx)))
+ let fldName = PrintVarName f
+ let lhs = Dot(objRefExpr, fldName)
+ let assertionExpr = match f with
+ | Var(_, Some(SeqType(_))) when not (idx = -1) -> BinaryEq (SelectExpr(lhs, IntLiteral(idx))) e
+ | Var(_, Some(SetType(_))) when not (idx = -1) -> BinaryIn e lhs
+ | _ -> BinaryEq lhs e
+ // check if the assertion follows and if so update the env
+ let code = PrintDafnyCodeSkeleton prog (MethodAnalysisPrinter (comp,mthd) assertionExpr)
+ Logger.Debug (" - checking assertion: " + (PrintExpr 0 assertionExpr) + " ... ")
+ let ok = CheckDafnyProgram code ("unif_" + (GetMethodFullName comp mthd))
+ if ok then
+ Logger.DebugLine " HOLDS"
+ else
+ Logger.DebugLine " DOESN'T HOLD"
+ ok
+ (* --- function body starts here --- *)
+ match unifs with
+ | (e,c) :: rest ->
+ let restHeap,env,ctx = ApplyUnifications prog comp mthd rest (heap,env,ctx) conservative
+ let newHeap = restHeap |> Map.fold (fun acc (o,f) l ->
+ let value = TryResolve (env,ctx) l
+ if value = c then
+ if __CheckUnif o f e -1 then
+ // change the value to expression
+ Logger.TraceLine (sprintf " - applied: %s.%s --> %s" (PrintConst o) (GetVarName f) (PrintExpr 0 e) )
+ acc |> Map.add (o,f) (ExprConst(e))
+ else
+ // don't change the value unless "conservative = false"
+ acc |> Map.add (o,f) l
+ else
+ let rec __UnifyOverLst lst cnt =
+ match lst with
+ | lstElem :: rest when lstElem = c ->
+ if __CheckUnif o f e cnt then
+ Logger.TraceLine (sprintf " - applied: %s.%s[%d] --> %s" (PrintConst o) (GetVarName f) cnt (PrintExpr 0 e) )
+ ExprConst(e) :: __UnifyOverLst rest (cnt+1)
+ else
+ lstElem :: __UnifyOverLst rest (cnt+1)
+ | lstElem :: rest ->
+ lstElem :: __UnifyOverLst rest (cnt+1)
+ | [] -> []
+ // see if it's a list, then try to match its elements, otherwise leave it as is
+ match value with
+ | SeqConst(clist) ->
+ let newLstConst = __UnifyOverLst clist 0
+ acc |> Map.add (o,f) (SeqConst(newLstConst))
+ | SetConst(cset) ->
+ let newLstConst = __UnifyOverLst (Set.toList cset) 0
+ acc |> Map.add (o,f) (SetConst(newLstConst |> Set.ofList))
+ | _ ->
+ acc |> Map.add (o,f) l
+ ) restHeap
+ (newHeap,env,ctx)
+ | [] -> (heap,env,ctx)
+
+// ====================================================================================
+/// Returns whether the code synthesized for the given method can be verified with Dafny
+// ====================================================================================
+let VerifySolution prog comp mthd (heap,env,ctx) =
+ // print the solution to file and try to verify it with Dafny
+ let solution = Map.empty |> Map.add (comp,mthd) (heap,env,ctx)
+ let code = PrintImplCode prog solution (fun p -> [comp,mthd])
+ CheckDafnyProgram code dafnyVerifySuffix
+
+let TryInferConditionals prog comp m unifs (heap,env,ctx) =
+ let heap2,env2,ctx2 = ApplyUnifications prog comp m unifs (heap,env,ctx) false
+ Some(heap2,env2,ctx2)
+
+// ============================================================================
/// Attempts to synthesize the initialization code for the given constructor "m"
///
-/// Returns a (heap,env,ctx) tuple
-// ============================================================================
-let AnalyzeConstructor prog comp m =
- let methodName = GetMethodName m
- // generate Dafny code for analysis first
- let code = PrintDafnyCodeSkeleton prog (MethodAnalysisPrinter (comp,m) FalseLiteral)
+/// Returns a (heap,env,ctx) tuple
+// ============================================================================
+let AnalyzeConstructor prog comp m =
+ let methodName = GetMethodName m
+ // generate Dafny code for analysis first
+ let code = PrintDafnyCodeSkeleton prog (MethodAnalysisPrinter (comp,m) FalseLiteral)
Logger.InfoLine (" [*] analyzing constructor " + methodName + (PrintSig (GetMethodSig m)))
- Logger.Info " - searching for a solution ..."
- let models = RunDafnyProgram code (dafnyScratchSuffix + "_" + (GetMethodFullName comp m))
- if models.Count = 0 then
- // no models means that the "assert false" was verified, which means that the spec is inconsistent
- Logger.WarnLine " !!! SPEC IS INCONSISTENT !!!"
- None
- else
- if models.Count > 1 then
- Logger.WarnLine " FAILED "
- failwith "internal error (more than one model for a single constructor analysis)"
- Logger.InfoLine " OK "
- let model = models.[0]
- let heap,env,ctx = ReadFieldValuesFromModel model prog comp m
- |> GeneralizeSolution prog comp m
- if _opt_verifySolutions then
- Logger.InfoLine " - verifying synthesized solution ... "
- let verified = VerifySolution prog comp m (heap,env,ctx)
- Logger.Info " "
- if verified then
- Logger.InfoLine "~~~ VERIFIED ~~~"
- Some(heap,env,ctx)
- else
- Logger.InfoLine "!!! NOT VERIFIED !!!"
- Some(heap,env,ctx)
- else
- Some(heap,env,ctx)
-
-
-// ============================================================================
-/// Goes through a given list of methods of the given program and attempts to
-/// synthesize code for each one of them.
-///
-/// Returns a map from (component * method) |--> (heap,env,ctx)
-// ============================================================================
-let rec AnalyzeMethods prog members =
- match members with
- | (comp,m) :: rest ->
- match m with
- | Method(_,_,_,_,true) ->
- let solOpt = AnalyzeConstructor prog comp m
- Logger.InfoLine ""
- match solOpt with
- | Some(heap,env,ctx) -> AnalyzeMethods prog rest |> Map.add (comp,m) (heap,env,ctx)
- | None -> AnalyzeMethods prog rest
- | _ -> AnalyzeMethods prog rest
- | [] -> Map.empty
-
-let Analyze prog =
- let solutions = AnalyzeMethods prog (GetMethodsToAnalyze prog)
- use file = System.IO.File.CreateText(dafnySynthFile)
- file.AutoFlush <- true
- Logger.InfoLine "Printing synthesized code"
- let synthCode = PrintImplCode prog solutions GetMethodsToAnalyze
- fprintfn file "%s" synthCode
- ()
-
-//let AnalyzeComponent_rustan c =
-// match c with
-// | Component(Class(name,typeParams,members), Model(_,_,cVars,frame,inv), code) ->
-// let aVars = Fields members
-// let aVars0 = Rename "0" aVars
-// let aVars1 = Rename "1" aVars
-// let allVars = List.concat [aVars; List.map (fun (a,b) -> b) aVars0; List.map (fun (a,b) -> b) aVars1; cVars]
-// let inv0 = Substitute (Map.ofList aVars0) inv
-// let inv1 = Substitute (Map.ofList aVars1) inv
-// // Now print it as a Dafny program
-// printf "class %s" name
-// match typeParams with
-// | [] -> ()
-// | _ -> printf "<%s>" (typeParams |> PrintSep ", " (fun tp -> tp))
-// printfn " {"
-// // the fields: original abstract fields plus two more copies thereof, plus and concrete fields
-// allVars |> List.iter (function Var(nm,None) -> printfn " var %s;" nm | Var(nm,Some(tp)) -> printfn " var %s: %s;" nm (PrintType tp))
-// // the method
-// printfn " method %s_checkInjective() {" name
-// printf " assume " ; (VarsAreDifferent aVars0 aVars1) ; printfn ";"
-// printfn " assume %s;" (PrintExpr 0 inv0)
-// printfn " assume %s;" (PrintExpr 0 inv1)
-// printfn " assert false;" // {:msg "Two abstract states map to the same concrete state"}
-// printfn " }"
-// // generate code
-// members |> List.iter (function
-// | Constructor(methodName,signature,pre,stmts) -> printf "%s" (GenerateCode methodName signature pre stmts inv false)
-// | Method(methodName,signature,pre,stmts) -> printf "%s" (GenerateCode methodName signature pre stmts inv true)
-// | _ -> ())
-// // the end of the class
-// printfn "}"
+ Logger.Info " - searching for an instance ..."
+ let models = RunDafnyProgram code (dafnyScratchSuffix + "_" + (GetMethodFullName comp m))
+ if models.Count = 0 then
+ // no models means that the "assert false" was verified, which means that the spec is inconsistent
+ Logger.WarnLine " !!! SPEC IS INCONSISTENT !!!"
+ None
+ else
+ if models.Count > 1 then
+ Logger.WarnLine " FAILED "
+ failwith "internal error (more than one model for a single constructor analysis)"
+ Logger.InfoLine " OK "
+ let model = models.[0]
+ let heap,env,ctx = ReadFieldValuesFromModel model prog comp m
+ let unifs = GetUnificationsForMethod comp m (heap,env,ctx) |> Map.toList
+ let heap,env,ctx = ApplyUnifications prog comp m unifs (heap,env,ctx) true
+ if Options.CONFIG.verifySolutions then
+ Logger.InfoLine " - verifying synthesized solution ... "
+ let verified = VerifySolution prog comp m (heap,env,ctx)
+ Logger.Info " "
+ if verified then
+ Logger.InfoLine "~~~ VERIFIED ~~~"
+ Some(heap,env,ctx)
+ else
+ Logger.InfoLine "!!! NOT VERIFIED !!!"
+ TryInferConditionals prog comp m unifs (heap,env,ctx)
+ else
+ Some(heap,env,ctx)
+
+
+// ============================================================================
+/// Goes through a given list of methods of the given program and attempts to
+/// synthesize code for each one of them.
+///
+/// Returns a map from (component * method) |--> (heap,env,ctx)
+// ============================================================================
+let rec AnalyzeMethods prog members =
+ match members with
+ | (comp,m) :: rest ->
+ match m with
+ | Method(_,_,_,_,true) ->
+ let solOpt = AnalyzeConstructor prog comp m
+ Logger.InfoLine ""
+ match solOpt with
+ | Some(heap,env,ctx) -> AnalyzeMethods prog rest |> Map.add (comp,m) (heap,env,ctx)
+ | None -> AnalyzeMethods prog rest
+ | _ -> AnalyzeMethods prog rest
+ | [] -> Map.empty
+
+let Analyze prog filename =
+ let solutions = AnalyzeMethods prog (GetMethodsToAnalyze prog)
+ let progName = System.IO.Path.GetFileNameWithoutExtension(filename)
+ use file = System.IO.File.CreateText(dafnySynthFileNameTemplate.Replace("###", progName))
+ file.AutoFlush <- true
+ Logger.InfoLine "Printing synthesized code"
+ let synthCode = PrintImplCode prog solutions GetMethodsToAnalyze
+ fprintfn file "%s" synthCode
+ ()
+
+//let AnalyzeComponent_rustan c =
+// match c with
+// | Component(Class(name,typeParams,members), Model(_,_,cVars,frame,inv), code) ->
+// let aVars = Fields members
+// let aVars0 = Rename "0" aVars
+// let aVars1 = Rename "1" aVars
+// let allVars = List.concat [aVars; List.map (fun (a,b) -> b) aVars0; List.map (fun (a,b) -> b) aVars1; cVars]
+// let inv0 = Substitute (Map.ofList aVars0) inv
+// let inv1 = Substitute (Map.ofList aVars1) inv
+// // Now print it as a Dafny program
+// printf "class %s" name
+// match typeParams with
+// | [] -> ()
+// | _ -> printf "<%s>" (typeParams |> PrintSep ", " (fun tp -> tp))
+// printfn " {"
+// // the fields: original abstract fields plus two more copies thereof, plus and concrete fields
+// allVars |> List.iter (function Var(nm,None) -> printfn " var %s;" nm | Var(nm,Some(tp)) -> printfn " var %s: %s;" nm (PrintType tp))
+// // the method
+// printfn " method %s_checkInjective() {" name
+// printf " assume " ; (VarsAreDifferent aVars0 aVars1) ; printfn ";"
+// printfn " assume %s;" (PrintExpr 0 inv0)
+// printfn " assume %s;" (PrintExpr 0 inv1)
+// printfn " assert false;" // {:msg "Two abstract states map to the same concrete state"}
+// printfn " }"
+// // generate code
+// members |> List.iter (function
+// | Constructor(methodName,signature,pre,stmts) -> printf "%s" (GenerateCode methodName signature pre stmts inv false)
+// | Method(methodName,signature,pre,stmts) -> printf "%s" (GenerateCode methodName signature pre stmts inv true)
+// | _ -> ())
+// // the end of the class
+// printfn "}"
// | _ -> assert false // unexpected case \ No newline at end of file