diff options
-rw-r--r-- | Jennisys.sln | 56 | ||||
-rw-r--r-- | Jennisys/Analyzer.fs | 83 | ||||
-rw-r--r-- | Jennisys/Ast.fs | 17 | ||||
-rw-r--r-- | Jennisys/AstUtils.fs | 40 | ||||
-rw-r--r-- | Jennisys/DafnyModelUtils.fs | 192 | ||||
-rw-r--r-- | Jennisys/DafnyPrinter.fs | 13 | ||||
-rw-r--r-- | Jennisys/Jennisys.fs | 5 | ||||
-rw-r--r-- | Jennisys/Jennisys.fsproj | 17 | ||||
-rw-r--r-- | Jennisys/Lexer.fsl | 5 | ||||
-rw-r--r-- | Jennisys/Parser.fsy | 13 | ||||
-rw-r--r-- | Jennisys/PipelineUtils.fs | 14 | ||||
-rw-r--r-- | Jennisys/Printer.fs | 17 | ||||
-rw-r--r-- | Jennisys/TypeChecker.fs | 1 | ||||
-rw-r--r-- | Jennisys/Utils.fs | 71 | ||||
-rw-r--r-- | Jennisys/examples/List.jen | 10 |
15 files changed, 501 insertions, 53 deletions
diff --git a/Jennisys.sln b/Jennisys.sln index 77ebb8e2..bb45d27c 100644 --- a/Jennisys.sln +++ b/Jennisys.sln @@ -2,17 +2,73 @@ Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Jennisys", "Jennisys\Jennisys.fsproj", "{F2FF4B3A-2FE8-474A-88DF-6950F7D78908}"
+ ProjectSection(ProjectDependencies) = postProject
+ {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83} = {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}
+ {A678C6EB-B329-46A9-BBFC-7585F01ACD7C} = {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "..\Source\Model\Model.csproj", "{ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModelViewer", "..\Source\ModelViewer\ModelViewer.csproj", "{A678C6EB-B329-46A9-BBFC-7585F01ACD7C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Checked|Any CPU = Checked|Any CPU
+ Checked|Mixed Platforms = Checked|Mixed Platforms
+ Checked|x86 = Checked|x86
+ Debug|Any CPU = Debug|Any CPU
+ Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|Mixed Platforms = Release|Mixed Platforms
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {F2FF4B3A-2FE8-474A-88DF-6950F7D78908}.Checked|Any CPU.ActiveCfg = Release|x86
+ {F2FF4B3A-2FE8-474A-88DF-6950F7D78908}.Checked|Mixed Platforms.ActiveCfg = Release|x86
+ {F2FF4B3A-2FE8-474A-88DF-6950F7D78908}.Checked|Mixed Platforms.Build.0 = Release|x86
+ {F2FF4B3A-2FE8-474A-88DF-6950F7D78908}.Checked|x86.ActiveCfg = Release|x86
+ {F2FF4B3A-2FE8-474A-88DF-6950F7D78908}.Checked|x86.Build.0 = Release|x86
+ {F2FF4B3A-2FE8-474A-88DF-6950F7D78908}.Debug|Any CPU.ActiveCfg = Debug|x86
+ {F2FF4B3A-2FE8-474A-88DF-6950F7D78908}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+ {F2FF4B3A-2FE8-474A-88DF-6950F7D78908}.Debug|Mixed Platforms.Build.0 = Debug|x86
{F2FF4B3A-2FE8-474A-88DF-6950F7D78908}.Debug|x86.ActiveCfg = Debug|x86
{F2FF4B3A-2FE8-474A-88DF-6950F7D78908}.Debug|x86.Build.0 = Debug|x86
+ {F2FF4B3A-2FE8-474A-88DF-6950F7D78908}.Release|Any CPU.ActiveCfg = Release|x86
+ {F2FF4B3A-2FE8-474A-88DF-6950F7D78908}.Release|Mixed Platforms.ActiveCfg = Release|x86
+ {F2FF4B3A-2FE8-474A-88DF-6950F7D78908}.Release|Mixed Platforms.Build.0 = Release|x86
{F2FF4B3A-2FE8-474A-88DF-6950F7D78908}.Release|x86.ActiveCfg = Release|x86
{F2FF4B3A-2FE8-474A-88DF-6950F7D78908}.Release|x86.Build.0 = Release|x86
+ {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Any CPU.ActiveCfg = Checked|Any CPU
+ {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Any CPU.Build.0 = Checked|Any CPU
+ {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU
+ {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU
+ {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|x86.ActiveCfg = Checked|Any CPU
+ {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Any CPU.Build.0 = Release|Any CPU
+ {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|x86.ActiveCfg = Release|Any CPU
+ {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|Any CPU.ActiveCfg = Checked|x86
+ {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|Mixed Platforms.ActiveCfg = Checked|x86
+ {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|Mixed Platforms.Build.0 = Checked|x86
+ {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|x86.ActiveCfg = Checked|x86
+ {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|x86.Build.0 = Checked|x86
+ {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|Any CPU.ActiveCfg = Debug|x86
+ {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+ {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|Mixed Platforms.Build.0 = Debug|x86
+ {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|x86.ActiveCfg = Debug|x86
+ {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|x86.Build.0 = Debug|x86
+ {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|Any CPU.ActiveCfg = Release|x86
+ {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|Mixed Platforms.ActiveCfg = Release|x86
+ {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|Mixed Platforms.Build.0 = Release|x86
+ {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|x86.ActiveCfg = Release|x86
+ {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Jennisys/Analyzer.fs b/Jennisys/Analyzer.fs index 806a6ab5..9a57ae64 100644 --- a/Jennisys/Analyzer.fs +++ b/Jennisys/Analyzer.fs @@ -2,25 +2,18 @@ open Ast open AstUtils +open DafnyModelUtils +open PipelineUtils open Printer open DafnyPrinter open TypeChecker +open Microsoft.Boogie + let VarsAreDifferent aa bb = printf "false" List.iter2 (fun (_,Var(a,_)) (_,Var(b,_)) -> printf " || %s != %s" a b) aa bb -let Fields members = - members |> List.choose (function Field(vd) -> Some(vd) | _ -> None) - -let Methods prog = - match prog with - | Program(components) -> - components |> List.fold (fun acc comp -> - match comp with - | Component(Class(_,_,members), Model(_,_,_,_,_), _) -> List.concat [acc ; members] - | _ -> acc) [] - let Rename suffix vars = vars |> List.map (function Var(nm,tp) -> nm, Var(nm + suffix, tp)) @@ -79,18 +72,31 @@ let GenValidFunctionCode clsMembers modelInv vars prog : string = let allInvs = modelInv :: clsInvs let fieldsValid = GetFieldsValidExprList vars prog let idt = " " - let invsStr = List.concat [fieldsValid ; allInvs] |> List.fold (fun acc (e: Expr) -> - if acc = "" then - sprintf "%s%s" idt (PrintExpr 0 e) - else - acc + " &&" + newline + sprintf "%s%s" idt (PrintExpr 0 e)) "" + let invsStr = List.concat [allInvs ; fieldsValid] |> List.fold (fun acc e -> List.concat [acc ; SplitIntoConjunts e]) [] + |> List.fold (fun acc (e: Expr) -> + if acc = "" then + sprintf "%s(%s)" idt (PrintExpr 0 e) + else + acc + " &&" + newline + sprintf "%s(%s)" idt (PrintExpr 0 e)) "" + // TODO: don't hardcode decr vars!!! + let decrVars = if List.choose (function Var(n,_) -> Some(n)) vars |> List.exists (fun n -> n = "next") then + ["list"] + else + [] " function Valid(): bool" + newline + " reads *;" + newline + + (if List.isEmpty decrVars then "" else sprintf " decreases %s;%s" (PrintSep ", " (fun a -> a) decrVars) newline) + " {" + newline + invsStr + newline + " }" + newline -let AnalyzeMethod prog mthd : string = +let GetAnalyzeConstrCode mthd = + match mthd with + | Constructor(methodName,signature,pre,post) -> (GenerateMethodCode methodName signature pre post false) + newline + | Method(methodName,signature,pre,post) -> (GenerateMethodCode methodName signature pre post true) + newline + | _ -> "" + +let AnalyzeMethod prog mthd mthdCodeFunc: string = match prog with | Program(components) -> components |> List.fold (fun acc comp -> match comp with @@ -101,35 +107,52 @@ let AnalyzeMethod prog mthd : string = acc + (sprintf "class %s%s {" name (PrintTypeParams typeParams)) + newline + // the fields: original abstract fields plus concrete fields - (sprintf "%s" (PrintFields allVars 2)) + newline + + (sprintf "%s" (PrintFields aVars 2 true)) + newline + + (sprintf "%s" (PrintFields cVars 2 false)) + newline + // generate the Valid function (sprintf "%s" (GenValidFunctionCode members inv allVars prog)) + newline + // generate code for the given method (if List.exists (fun a -> a = mthd) members then - match mthd with - | Constructor(methodName,signature,pre,post) -> (GenerateMethodCode methodName signature pre post false) + newline - | Method(methodName,signature,pre,post) -> (GenerateMethodCode methodName signature pre post true) + newline - | _ -> "" + mthdCodeFunc mthd else "") + // the end of the class "}" + newline + newline | _ -> assert false; "") "" -let scratchFileName = "scratch.dfy" +let PrintImplCode (heap, env, ctx) = + + () let Analyze prog = - let methods = Methods prog - + let models = ref null + let methods = Methods prog // synthesize constructors - methods |> List.iter (fun m -> + methods |> List.iter (fun (comp, m) -> match m with | Constructor(methodName,signature,pre,post) -> - use file = System.IO.File.CreateText(scratchFileName) - let code = AnalyzeMethod prog m - printfn "printing code for method %s:\r\n%s" methodName code - printfn "-------------------------" + use file = System.IO.File.CreateText(dafnyScratchFile) + file.AutoFlush <- true + let code = AnalyzeMethod prog m GetAnalyzeConstrCode + printfn "analyzing constructor %s" methodName +// printfn "%s" code +// printfn "-------------------------" fprintf file "%s" code + file.Close() + RunDafny dafnyScratchFile dafnyModelFile + use modelFile = System.IO.File.OpenText(dafnyModelFile) + + let models = Microsoft.Boogie.Model.ParseModels modelFile + if models.Count = 0 then + printfn "spec for method %s.%s is inconsistent (no valid solution exists)" (GetClassName comp) methodName + else + assert (models.Count = 1) // TODO + let model = models.[0] + + let (heap,env,ctx) = ReadFieldValuesFromModel model prog comp m + PrintImplCode (heap, env, ctx) |> ignore + printfn "done with %s" methodName + System.Environment.Exit(1) | _ -> ()) diff --git a/Jennisys/Ast.fs b/Jennisys/Ast.fs index b6e04d3f..eeb2f753 100644 --- a/Jennisys/Ast.fs +++ b/Jennisys/Ast.fs @@ -3,10 +3,22 @@ open System
open System.Numerics
-
type Type =
+ | IntType
+ | BoolType
+ | SetType of Type (* type parameter *)
+ | SeqType of Type (* type parameter *)
| NamedType of string
- | InstantiatedType of string * Type
+ | InstantiatedType of string * Type (* type parameter *)
+
+type Const =
+ | IntConst of int
+ | BoolConst of bool
+ | SetConst of Set<Const>
+ | SeqConst of (Const option) list
+ | ThisConst of (* loc id *) string * Type option
+ | NewObj of (* loc id *) string * Type option
+ | Unresolved of (* loc id *) string
type VarDecl =
| Var of string * Type option
@@ -50,3 +62,4 @@ type Component = type Program =
| Program of Component list
+
diff --git a/Jennisys/AstUtils.fs b/Jennisys/AstUtils.fs index 83104f5d..794a89dc 100644 --- a/Jennisys/AstUtils.fs +++ b/Jennisys/AstUtils.fs @@ -23,4 +23,42 @@ let BinaryImplies lhs rhs = BinaryExpr(20, "==>", lhs, rhs) let BinaryNeq lhs rhs = BinaryExpr(40, "!=", lhs, rhs)
let TrueLiteral = IdLiteral("true")
-let FalseLiteral = IdLiteral("false")
\ No newline at end of file +let FalseLiteral = IdLiteral("false")
+
+// --- search functions ---
+
+let Fields members = + members |> List.choose (function Field(vd) -> Some(vd) | _ -> None) + +let Methods prog = + match prog with + | Program(components) -> + components |> List.fold (fun acc comp -> + match comp with + | Component(Class(_,_,members),_,_) -> List.concat [acc ; members |> List.choose (fun m -> Some(comp, m))] + | _ -> acc) []
+
+let AllFields c =
+ match c with + | Component(Class(_,_,members), Model(_,_,cVars,_,_), _) -> + let aVars = Fields members + List.concat [aVars ; cVars]
+ | _ -> []
+
+let GetClassName comp =
+ match comp with
+ | Component(Class(name,_,_),_,_) -> name
+ | _ -> failwith ("unrecognized component: " + comp.ToString())
+
+let FindComponent (prog: Program) clsName =
+ match prog with
+ | Program(comps) -> comps |> List.filter (function Component(Class(name,_,_),_,_) when name = clsName -> true | _ -> false)
+ |> Utils.ListToOption
+
+let FindVar (prog: Program) clsName fldName =
+ let copt = FindComponent prog clsName
+ match copt with
+ | Some(comp) ->
+ AllFields comp |> List.filter (function Var(name,_) when name = fldName -> true | _ -> false)
+ |> Utils.ListToOption
+ | None -> None
\ No newline at end of file diff --git a/Jennisys/DafnyModelUtils.fs b/Jennisys/DafnyModelUtils.fs new file mode 100644 index 00000000..c3db8e83 --- /dev/null +++ b/Jennisys/DafnyModelUtils.fs @@ -0,0 +1,192 @@ +module DafnyModelUtils
+
+(*
+ The heap maps objects and fields to locations.
+ heap: Const * VarDecl option |--> Const
+
+ The environment maps locations to values (except that it can also
+ be locations to locations, because not all values are explicitly
+ present in the model.
+ envMap: Const |--> Const
+
+ The context is just a list of equality constraints collected on the way
+ ctx: Set<Set<Const>>, where the inner set contains exactly two constants
+*)
+
+open Ast
+open AstUtils
+open Utils
+
+open Microsoft.Boogie
+
+let GetElemFullName (elem: Model.Element) =
+ elem.Names |> Seq.filter (fun ft -> ft.Func.Arity = 0) + |> Seq.choose (fun ft -> Some(ft.Func.Name)) + |> Utils.SeqToOption
+
+let GetElemName (elem: Model.Element) =
+ let fullNameOpt = GetElemFullName elem + match fullNameOpt with + | Some(fullName) -> + let dotIdx = fullName.LastIndexOf(".") + let fldName = fullName.Substring(dotIdx + 1) + let clsName = if dotIdx = -1 then "" else fullName.Substring(0, dotIdx)
+ Some(clsName, fldName)
+ | None -> None
+
+let GetRefName (ref: Model.Element) =
+ match ref with
+ | :? Model.Uninterpreted as uref -> uref.Name
+ | _ -> failwith ("not a ref (Uninterpreted) but: " + ref.GetType().Name)
+
+let ConvertValue (model: Model) (refVal: Model.Element) =
+ match refVal with
+ | :? Model.Number as ival -> IntConst(ival.AsInt())
+ | :? Model.Boolean as bval -> BoolConst(bval.Value)
+ | :? Model.Array as aval -> failwith "reading array values from model not implemented"
+ | :? Model.Uninterpreted as uval -> Unresolved(uval.Name) (* just a symbolic name for now, which we'll hopefully resolve later*)
+ | _ -> failwith ("unexpected model element kind: " + refVal.ToString())
+
+let GetInt (elem: Model.Element) =
+ match elem with
+ | :? Model.Number as ival -> ival.AsInt()
+ | _ -> failwith ("not an int element: " + elem.ToString())
+
+let GetBool (elem: Model.Element) =
+ match elem with
+ | :? Model.Boolean as bval -> bval.Value
+ | _ -> failwith ("not a bool element: " + elem.ToString())
+
+let GetType (e: Model.Element) =
+ let fNameOpt = GetElemFullName e
+ match fNameOpt with
+ | Some(fname) -> match fname with
+ | Exact "intType" _ -> Some(IntType)
+ | Prefix "class." clsName -> Some(NamedType(clsName))
+ | _ -> None
+ | None -> None
+
+let GetLoc (e: Model.Element) =
+ Unresolved(GetRefName e)
+
+let GetSeqFromEnv env key =
+ match Map.find key env with
+ | SeqConst(lst) -> lst
+ | _ as x-> failwith ("not a SeqConst but: " + x.ToString())
+
+let AddConstr c1 c2 ctx =
+ if c1 = c2 then
+ ctx
+ else
+ match c1, c2 with
+ | Unresolved(_), _ | _, Unresolved(_) -> Set.add (Set.ofList [c1; c2]) ctx
+ | _ -> failwith ("trying to add an equality constraint between two constants: " + c1.ToString() + ", and " + c2.ToString())
+
+let rec UpdateContext lst1 lst2 ctx =
+ match lst1, lst2 with
+ | fs1 :: rest1, fs2 :: rest2 ->
+ match fs1, fs2 with
+ | Some(c1), Some(c2) -> UpdateContext rest1 rest2 (AddConstr c1 c2 ctx)
+ | _ -> UpdateContext rest1 rest2 ctx
+ | [], [] -> ctx
+ | _ -> failwith "lists are not of the same length"
+
+let UnboxIfNeeded (model: Microsoft.Boogie.Model) (e: Model.Element) =
+ let f_unbox = model.MkFunc("$Unbox", 2)
+ let unboxed = f_unbox.Apps |> Seq.filter (fun ft -> if (GetLoc ft.Args.[1]) = (GetLoc e) then true else false)
+ |> Seq.choose (fun ft -> Some(ft.Result))
+ |> Utils.SeqToOption
+ match unboxed with
+ | Some(e) -> ConvertValue model e
+ | None -> GetLoc e
+
+let ReadHeap (model: Microsoft.Boogie.Model) prog =
+ let f_heap_select = model.MkFunc("[3]", 3) + let values = f_heap_select.Apps + values |> Seq.fold (fun acc ft -> + assert (ft.Args.Length = 3) + let ref = ft.Args.[1] + let fld = ft.Args.[2] + assert (Seq.length fld.Names = 1) + let fldFullName = (Seq.nth 0 fld.Names).Func.Name + let dotIdx = fldFullName.LastIndexOf(".") + let fldName = fldFullName.Substring(dotIdx + 1) + let clsName = if dotIdx = -1 then "" else fldFullName.Substring(0, dotIdx) + let refVal = ft.Result + let refObj = Unresolved(GetRefName ref) + let fldVar = FindVar prog clsName fldName + let fldType = match fldVar with + | Some(Var(_,t)) -> t + | _ -> None + let fldVal = ConvertValue model refVal + acc |> Map.add (refObj, fldVar) fldVal + ) Map.empty
+
+let rec ReadSeqLen (model: Microsoft.Boogie.Model) (len_tuples: Model.FuncTuple list) (envMap,ctx) =
+ match len_tuples with
+ | ft :: rest ->
+ let len = GetInt ft.Result
+ let emptyList = Utils.GenList len
+ let newMap = envMap |> Map.add (GetLoc ft.Args.[0]) (SeqConst(emptyList))
+ ReadSeqLen model rest (newMap,ctx)
+ | _ -> (envMap,ctx)
+
+let rec ReadSeqIndex (model: Microsoft.Boogie.Model) (idx_tuples: Model.FuncTuple list) (envMap,ctx) =
+ match idx_tuples with
+ | ft :: rest ->
+ let srcLstKey = GetLoc ft.Args.[0]
+ let oldLst = GetSeqFromEnv envMap srcLstKey
+ let idx = GetInt ft.Args.[1]
+ let lstElem = UnboxIfNeeded model ft.Result
+ let newLst = Utils.ListSet idx (Some(lstElem)) oldLst
+ let newCtx = UpdateContext oldLst newLst ctx
+ let newEnv = envMap |> Map.add srcLstKey (SeqConst(newLst))
+ ReadSeqIndex model rest (newEnv,newCtx)
+ | _ -> (envMap,ctx)
+
+let rec ReadSeqBuild (model: Microsoft.Boogie.Model) (bld_tuples: Model.FuncTuple list) (envMap,ctx) =
+ match bld_tuples with
+ | ft :: rest ->
+ let srcLstKey = GetLoc ft.Args.[0]
+ let dstLstKey = GetLoc ft.Result
+ let oldLst = GetSeqFromEnv envMap srcLstKey
+ let idx = GetInt ft.Args.[1]
+ let lstElemVal = UnboxIfNeeded model ft.Args.[2]
+ let dstLst = GetSeqFromEnv envMap dstLstKey
+ let newLst = Utils.ListBuild oldLst idx (Some(lstElemVal)) dstLst
+ let newCtx = UpdateContext dstLst newLst ctx
+ let newEnv = envMap |> Map.add dstLstKey (SeqConst(newLst))
+ ReadSeqBuild model rest (newEnv,newCtx)
+ | _ -> (envMap,ctx)
+
+let ReadSeq (model: Microsoft.Boogie.Model) (envMap,ctx) =
+ let f_seq_len = model.MkFunc("Seq#Length", 1)
+ let f_seq_bld = model.MkFunc("Seq#Build", 4)
+ let f_seq_idx = model.MkFunc("Seq#Index", 2)
+ (envMap,ctx) |> ReadSeqLen model (List.ofSeq f_seq_len.Apps)
+ |> ReadSeqIndex model (List.ofSeq f_seq_idx.Apps)
+ |> ReadSeqBuild model (List.ofSeq f_seq_bld.Apps)
+
+let ReadSet (model: Microsoft.Boogie.Model) envMap =
+ envMap
+
+let ReadEnv (model: Microsoft.Boogie.Model) =
+ let f_dtype = model.MkFunc("dtype", 1) + let refs = f_dtype.Apps |> Seq.choose (fun ft -> Some(ft.Args.[0]))
+ let envMap = f_dtype.Apps |> Seq.fold (fun acc ft ->
+ let locName = GetRefName ft.Args.[0]
+ let elemName = GetElemFullName ft.Args.[0]
+ let loc = Unresolved(locName)
+ let locType = GetType ft.Result
+ let value = match elemName with
+ | Some(n) when n.StartsWith("this") -> ThisConst(locName, locType)
+ | _ -> NewObj(locName, locType)
+ acc |> Map.add loc value
+ ) Map.empty
+ (envMap, Set.ofList([])) |> ReadSeq model
+ |> ReadSet model
+
+let ReadFieldValuesFromModel (model: Microsoft.Boogie.Model) prog comp meth = + let heap = ReadHeap model prog + let env,ctx = ReadEnv model + heap,env,ctx
\ No newline at end of file diff --git a/Jennisys/DafnyPrinter.fs b/Jennisys/DafnyPrinter.fs index d5fa6086..87937850 100644 --- a/Jennisys/DafnyPrinter.fs +++ b/Jennisys/DafnyPrinter.fs @@ -5,7 +5,11 @@ open Printer let rec PrintType ty = match ty with - | NamedType(id) -> id + | IntType -> "int" + | BoolType -> "bool" + | NamedType(id) -> id + | SeqType(t) -> sprintf "seq<%s>" (PrintType t) + | SetType(t) -> sprintf "set<%s>" (PrintType t) | InstantiatedType(id,arg) -> sprintf "%s<%s>" id (PrintType arg) let rec PrintExpr ctx expr = @@ -41,7 +45,8 @@ let PrintTypeParams typeParams = | [] -> "" | _ -> sprintf "<%s>" (typeParams |> PrintSep ", " (fun tp -> tp)) -let PrintFields vars indent = +let PrintFields vars indent ghost = + let ghostStr = if ghost then "ghost " else "" vars |> List.fold (fun acc v -> match v with - | Var(nm,None) -> acc + (sprintf "%svar %s;%s" (Indent indent) nm newline) - | Var(nm,Some(tp)) -> acc + (sprintf "%svar %s: %s;%s" (Indent indent) nm (PrintType tp) newline)) ""
\ No newline at end of file + | Var(nm,None) -> acc + (sprintf "%s%svar %s;%s" (Indent indent) ghostStr nm newline) + | Var(nm,Some(tp)) -> acc + (sprintf "%s%svar %s: %s;%s" (Indent indent) ghostStr nm (PrintType tp) newline)) ""
\ No newline at end of file diff --git a/Jennisys/Jennisys.fs b/Jennisys/Jennisys.fs index d58af665..0c69f797 100644 --- a/Jennisys/Jennisys.fs +++ b/Jennisys/Jennisys.fs @@ -61,4 +61,7 @@ let rec start n (args: string []) tracing analyzing filename = readAndProcess tracing analyzing filename let args = Environment.GetCommandLineArgs() -start 1 args false true null +try + start 1 args false true null +with +| _ as e -> printfn "%s" e.StackTrace
\ No newline at end of file diff --git a/Jennisys/Jennisys.fsproj b/Jennisys/Jennisys.fsproj index 68369571..1ec66a98 100644 --- a/Jennisys/Jennisys.fsproj +++ b/Jennisys/Jennisys.fsproj @@ -23,7 +23,7 @@ <WarningLevel>3</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
<DocumentationFile>bin\Debug\Language.XML</DocumentationFile>
- <StartArguments>C:\boogie\Jennisys\Jennisys\examples\List.jen</StartArguments>
+ <StartArguments>C:\boogie\Jennisys\Jennisys\examples\List2.jen</StartArguments>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<DebugType>pdbonly</DebugType>
@@ -42,6 +42,8 @@ <FsYaccOutputFolder>$(IntermediateOutputPath)</FsYaccOutputFolder>
</PropertyGroup>
<ItemGroup>
+ <Compile Include="Utils.fs" />
+ <Compile Include="PipelineUtils.fs" />
<Compile Include="Ast.fs" />
<Compile Include="AstUtils.fs" />
<Compile Include="$(IntermediateOutputPath)\Parser.fs">
@@ -52,6 +54,7 @@ <Visible>false</Visible>
<Link>Lexer.fs</Link>
</Compile>
+ <Compile Include="DafnyModelUtils.fs" />
<FsYacc Include="Parser.fsy">
<OtherFlags>--module Parser</OtherFlags>
</FsYacc>
@@ -74,6 +77,18 @@ <Reference Include="System.Core" />
<Reference Include="System.Numerics" />
</ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\Source\ModelViewer\ModelViewer.csproj">
+ <Name>ModelViewer</Name>
+ <Project>{a678c6eb-b329-46a9-bbfc-7585f01acd7c}</Project>
+ <Private>True</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Source\Model\Model.csproj">
+ <Name>Model</Name>
+ <Project>{acef88d5-dadd-46da-bae1-2144d63f4c83}</Project>
+ <Private>True</Private>
+ </ProjectReference>
+ </ItemGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
diff --git a/Jennisys/Lexer.fsl b/Jennisys/Lexer.fsl index 26195484..a0e62109 100644 --- a/Jennisys/Lexer.fsl +++ b/Jennisys/Lexer.fsl @@ -32,6 +32,11 @@ rule tokenize = parse | "requires" { REQUIRES }
| "ensures" { ENSURES }
| "forall" { FORALL }
+// Types
+| "int" { INTTYPE }
+| "bool" { BOOLTYPE }
+| "seq" { SEQTYPE }
+| "set" { SETTYPE }
// Operators
| "." { DOT }
| "+" { PLUS }
diff --git a/Jennisys/Parser.fsy b/Jennisys/Parser.fsy index 0b5c2fc8..71ca4de0 100644 --- a/Jennisys/Parser.fsy +++ b/Jennisys/Parser.fsy @@ -29,6 +29,7 @@ let rec MyFold ee acc = %token GETS COLON COLONCOLON COMMA
%token CLASS MODEL CODE
%token VAR CONSTRUCTOR METHOD FRAME INVARIANT RETURNS REQUIRES ENSURES FORALL
+%token INTTYPE BOOLTYPE SEQTYPE SETTYPE
%token EOF
// This is the type of the data produced by a successful reduction of the 'start'
@@ -89,8 +90,8 @@ BlockStmt: Member:
| VAR VarDecl { Field($2) }
| CONSTRUCTOR ID Signature Pre Post { Constructor($2, $3, $4, $5) }
- | METHOD ID Signature Pre Post { Method($2, $3, $4, $5) }
- | INVARIANT ExprList { Invariant($2) }
+ | METHOD ID Signature Pre Post { Method($2, $3, $4, $5) }
+ | INVARIANT ExprList { Invariant($2) }
FrameMembers:
| { [], [], IdLiteral("true") }
@@ -113,8 +114,12 @@ VarDecl: | ID COLON Type { Var($1,Some($3)) }
Type:
- | ID { NamedType($1) }
- | ID LBRACKET Type RBRACKET { InstantiatedType($1, $3) }
+ | INTTYPE { IntType }
+ | BOOLTYPE { BoolType }
+ | ID { NamedType($1) }
+ | SEQTYPE LBRACKET Type RBRACKET { SeqType($3) }
+ | SETTYPE LBRACKET Type RBRACKET { SetType($3) }
+ | ID LBRACKET Type RBRACKET { InstantiatedType($1, $3) }
ExprList:
| { [] }
diff --git a/Jennisys/PipelineUtils.fs b/Jennisys/PipelineUtils.fs new file mode 100644 index 00000000..0f7eb847 --- /dev/null +++ b/Jennisys/PipelineUtils.fs @@ -0,0 +1,14 @@ +module PipelineUtils
+ +let dafnyScratchFile = @"c:\tmp\jennisys-scratch.dfy" +let dafnyModelFile = @"c:\tmp\jennisys-scratch.model" +let dafnyOutFile = @"c:\tmp\jennisys-scratch.out" + +let RunDafny inputFile modelFile =
+ async {
+ use proc = new System.Diagnostics.Process()
+ proc.StartInfo.FileName <- @"c:\tmp\StartDafny-jen.bat"
+ proc.StartInfo.Arguments <- "/mv:" + modelFile + " " + inputFile
+ assert proc.Start()
+ proc.WaitForExit()
+ } |> Async.RunSynchronously
diff --git a/Jennisys/Printer.fs b/Jennisys/Printer.fs index 77e462f3..2c6315a3 100644 --- a/Jennisys/Printer.fs +++ b/Jennisys/Printer.fs @@ -12,7 +12,11 @@ let rec PrintSep sep f list = let rec PrintType ty = match ty with - | NamedType(id) -> id + | IntType -> "int" + | BoolType -> "bool" + | NamedType(id) -> id + | SeqType(t) -> sprintf "seq[%s]" (PrintType t) + | SetType(t) -> sprintf "set[%s]" (PrintType t) | InstantiatedType(id,arg) -> sprintf "%s[%s]" id (PrintType arg) let PrintVarDecl vd = @@ -50,11 +54,14 @@ let PrintSig signature = else "" sprintf "(%s)%s" (ins |> PrintSep ", " PrintVarDecl) returnClause -let rec ForeachConjunct f expr = +let rec SplitIntoConjunts expr = match expr with - | IdLiteral("true") -> "" - | BinaryExpr(_,"&&",e0,e1) -> (ForeachConjunct f e0) + (ForeachConjunct f e1) - | _ -> f expr + | IdLiteral("true") -> [] + | BinaryExpr(_,"&&",e0,e1) -> List.concat [SplitIntoConjunts e0 ; SplitIntoConjunts e1] + | _ -> [expr] + +let rec ForeachConjunct f expr = + SplitIntoConjunts expr |> List.fold (fun acc e -> acc + (f e)) "" let rec Indent i = if i = 0 then "" else " " + (Indent (i-1)) diff --git a/Jennisys/TypeChecker.fs b/Jennisys/TypeChecker.fs index 41ffbb5d..6ca13453 100644 --- a/Jennisys/TypeChecker.fs +++ b/Jennisys/TypeChecker.fs @@ -24,6 +24,7 @@ let IsUserType prog tpo = let tpname = match tp with
| NamedType(tname) -> tname
| InstantiatedType(tname, _) -> tname
+ | _ -> ""
match prog with
| Program(components) -> components |> List.filter (function Component(Class(name,_,_),_,_) when name = tpname -> true
| _ -> false) |> List.isEmpty |> not
diff --git a/Jennisys/Utils.fs b/Jennisys/Utils.fs new file mode 100644 index 00000000..8a2e107e --- /dev/null +++ b/Jennisys/Utils.fs @@ -0,0 +1,71 @@ +module Utils
+
+// -------------------------------------------
+// ----------- collection util funcs ---------
+// -------------------------------------------
+
+let ListToOption lst =
+ assert (List.length lst <= 1)
+ if List.isEmpty lst then
+ None
+ else
+ Some(lst.[0])
+
+let SeqToOption seq =
+ assert (Seq.length seq <= 1)
+ if Seq.isEmpty seq then
+ None
+ else
+ Some(Seq.nth 0 seq)
+
+let rec GenList n =
+ if n = 0 then
+ []
+ else
+ None :: (GenList (n-1))
+
+let rec ListSkip cnt lst =
+ if cnt = 0 then
+ lst
+ else
+ match lst with
+ | fs :: rest -> ListSkip (cnt-1) rest
+ | [] -> []
+
+let rec ListBuild srcList idx v dstList =
+ match srcList, dstList with
+ | fs1 :: rest1, fs2 :: rest2 -> if idx = 0 then
+ v :: List.concat [rest1 ; ListSkip (List.length rest1) rest2]
+ else
+ fs1 :: ListBuild rest1 (idx-1) v rest2
+ | [], fs2 :: rest2 -> if idx = 0 then
+ v :: rest2
+ else
+ fs2 :: ListBuild [] (idx-1) v rest2
+ | _, [] -> failwith "index out of range"
+
+
+let rec ListSet idx v lst =
+ match lst with
+ | fs :: rest -> if idx = 0 then
+ v :: rest
+ else
+ fs :: ListSet (idx-1) v rest
+ | [] -> failwith "index out of range"
+
+// -------------------------------------------
+// ------ string active patterns -------------
+// -------------------------------------------
+
+let (|Prefix|_|) (p:string) (s:string) =
+ if s.StartsWith(p) then
+ Some(s.Substring(p.Length))
+ else
+ None
+
+let (|Exact|_|) (p:string) (s:string) =
+ if s = p then
+ Some(s)
+ else
+ None
+
diff --git a/Jennisys/examples/List.jen b/Jennisys/examples/List.jen index 89716f8b..184f4947 100644 --- a/Jennisys/examples/List.jen +++ b/Jennisys/examples/List.jen @@ -1,10 +1,10 @@ class List[T] { var list: seq[T] - constructor Init() + constructor Empty() ensures list = [] - constructor Singleton(t) + constructor Singleton(t: T) ensures list = [t] } @@ -25,7 +25,7 @@ class Node[T] { invariant |list| > 0 - constructor Init(t) + constructor Init(t: T) ensures list = [t] } @@ -37,6 +37,6 @@ model Node[T] { data * next invariant - next = null ==> list = [data] - next != null ==> list = [data] + next.list + next = null <==> list = [data] + next != null ==> list = [data] + next.list } |