diff options
-rw-r--r-- | Jennisys/AstUtils.fs | 10 | ||||
-rw-r--r-- | Jennisys/DafnyModelUtils.fs | 88 | ||||
-rw-r--r-- | Jennisys/Jennisys.fsproj | 2 | ||||
-rw-r--r-- | Jennisys/README.txt | 24 | ||||
-rw-r--r-- | Jennisys/examples/BHeap.jen | 33 |
5 files changed, 121 insertions, 36 deletions
diff --git a/Jennisys/AstUtils.fs b/Jennisys/AstUtils.fs index 11189ebb..6aac59e2 100644 --- a/Jennisys/AstUtils.fs +++ b/Jennisys/AstUtils.fs @@ -290,11 +290,17 @@ let rec DescendExpr2BU visitorFunc expr acc = | SequenceExpr(exs)
| SetExpr(exs) -> __Pipe exs
+//TODO: if names in dafny models contain funky characters,
+// these gensym variables might not be valid identifiers
let PrintGenSym (name: string) =
if name.StartsWith("gensym") then
name
- else
- sprintf "gensym%s" name
+ else
+ let idx = name.LastIndexOf("!")
+ if idx <> -1 then
+ sprintf "gensym%s" (name.Substring(idx+1))
+ else
+ sprintf "gensym%s" name
// =====================
/// Returns TRUE literal
diff --git a/Jennisys/DafnyModelUtils.fs b/Jennisys/DafnyModelUtils.fs index 50d5f2c5..e734f3bb 100644 --- a/Jennisys/DafnyModelUtils.fs +++ b/Jennisys/DafnyModelUtils.fs @@ -26,6 +26,21 @@ open Utils open Microsoft.Boogie
+let HEAP_SELECT_FNAME = "MapType1Select"
+let SEQ_BUILD_FNAME = "Seq#Build"
+let SEQ_APPEND_FNAME = "Seq#Append"
+let SEQ_LENGTH_FNAME = "Seq#Length"
+let SEQ_INDEX_FNAME = "Seq#Index"
+let SET_EMPTY_FNAME = "Set#Empty"
+let SET_SELECT_FNAME = "MapType0Select"
+let UNBOX_FNAME = "$Unbox"
+let BOOL_2_U_FNAME = "bool_2_U"
+let U_2_BOOL_FNAME = "U_2_bool"
+let INT_2_U_FNAME = "int_2_U"
+let U_2_INT_FNAME = "U_2_int"
+let DTYPE_FNAME = "dtype"
+let NULL_FNAME = "null"
+
type HeapModel = {
heap : Map<Const * VarDecl, Const>;
env : Map<Const, Const>;
@@ -44,25 +59,46 @@ 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) =
+
+let GetInt (elem: Model.Element) =
+ let __NotIntFail e = failwith ("not an int element: " + elem.ToString())
+ let rec __GetIntStrict (e: Model.Element) cont =
+ match e with
+ | :? Model.Number as ival -> ival.AsInt()
+ | _ -> cont e
+ __GetIntStrict elem (fun e ->
+ let f = e.Model.MkFunc(U_2_INT_FNAME, 1)
+ let matches = f.Apps |> Seq.filter (fun ft -> ft.Args.[0] = e) |> Seq.map (fun ft -> ft.Result)
+ if matches |> Seq.isEmpty then
+ __NotIntFail e
+ else
+ __GetIntStrict (matches |> Seq.nth 0) __NotIntFail)
+
+let GetBool (elem: Model.Element) =
+ let __NotBoolFail e = failwith ("not a bool element: " + elem.ToString())
+ let rec __GetBoolStrict (e: Model.Element) cont =
+ match e with
+ | :? Model.Boolean as bval -> bval.Value
+ | _ -> cont e
+ __GetBoolStrict elem (fun e ->
+ let f = e.Model.MkFunc(U_2_BOOL_FNAME, 1)
+ let matches = f.Apps |> Seq.filter (fun ft -> ft.Args.[0] = e) |> Seq.map (fun ft -> ft.Result)
+ if matches |> Seq.isEmpty then
+ __NotBoolFail e
+ else
+ __GetBoolStrict (matches |> Seq.nth 0) __NotBoolFail)
+
+let ConvertValue (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*)
+ | :? Model.Uninterpreted as uval ->
+ try BoolConst(GetBool refVal)
+ with _ -> try IntConst(GetInt refVal)
+ with _ -> 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 LastDotSplit (str: string) =
let dotIdx = str.LastIndexOf(".")
let s1 = if dotIdx = -1 then "" else str.Substring(0, dotIdx)
@@ -135,16 +171,16 @@ let rec UpdateContext lst1 lst2 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 f_unbox = model.MkFunc(UNBOX_FNAME, 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
+ | Some(e) -> ConvertValue e
| None -> GetLoc e
let ReadHeap (model: Microsoft.Boogie.Model) prog =
- let f_heap_select = model.MkFunc("[3]", 3)
+ let f_heap_select = model.MkFunc(HEAP_SELECT_FNAME, 3)
let values = f_heap_select.Apps
values |> Seq.fold (fun acc ft ->
assert (ft.Args.Length = 3)
@@ -169,7 +205,7 @@ let ReadHeap (model: Microsoft.Boogie.Model) prog = match fldVarOpt with
| Some(fldVar) ->
let fldType = GetVarType fldVar
- let fldVal = ConvertValue model refVal
+ let fldVal = ConvertValue refVal
acc |> Map.add (refObj, fldVar) fldVal
| None -> acc
) Map.empty
@@ -189,7 +225,7 @@ let rec ReadArgValues (model: Microsoft.Boogie.Model) args = let fldVar = v
assert (Seq.length func.Apps = 1)
let ft = Seq.head func.Apps
- let fldVal = ConvertValue model (ft.Result)
+ let fldVal = ConvertValue (ft.Result)
ReadArgValues model rest |> Map.add (VarConst(name)) fldVal
| None -> failwith ("cannot find corresponding function for parameter " + name)
| [] -> Map.empty
@@ -258,8 +294,8 @@ let ReadSeq (model: Microsoft.Boogie.Model) (envMap,ctx) = // keeps reading from Seq#Build and Seq#Append until fixpoint
let rec __ReadUntilFixpoint hmodel =
- let f_seq_bld = model.MkFunc("Seq#Build", 2)
- let f_seq_app = model.MkFunc("Seq#Append", 2)
+ let f_seq_bld = model.MkFunc(SEQ_BUILD_FNAME, 2)
+ let f_seq_app = model.MkFunc(SEQ_APPEND_FNAME, 2)
let hmodel' = hmodel |> __ReadSeqBuild model (List.ofSeq f_seq_bld.Apps)
|> __ReadSeqAppend model (List.ofSeq f_seq_app.Apps)
if hmodel' = hmodel then
@@ -267,8 +303,8 @@ let ReadSeq (model: Microsoft.Boogie.Model) (envMap,ctx) = else
__ReadUntilFixpoint hmodel'
- let f_seq_len = model.MkFunc("Seq#Length", 1)
- let f_seq_idx = model.MkFunc("Seq#Index", 2)
+ let f_seq_len = model.MkFunc(SEQ_LENGTH_FNAME, 1)
+ let f_seq_idx = model.MkFunc(SEQ_INDEX_FNAME, 2)
let hmodel = (envMap,ctx)
let hmodel' = hmodel |> __ReadSeqLen model (List.ofSeq f_seq_len.Apps)
|> __ReadSeqIndex model (List.ofSeq f_seq_idx.Apps)
@@ -305,8 +341,8 @@ let ReadSet (model: Microsoft.Boogie.Model) (envMap,ctx) = __ReadSetMembership rest (env,ctx)
| [] -> (env,ctx)
- let t_set_empty = Seq.toList (model.MkFunc("Set#Empty", 1).Apps)
- let t_set = Seq.toList (model.MkFunc("[2]", 2).Apps)
+ let t_set_empty = Seq.toList (model.MkFunc(SET_EMPTY_FNAME, 1).Apps)
+ let t_set = Seq.toList (model.MkFunc(SET_SELECT_FNAME, 2).Apps)
(envMap,ctx) |> __ReadSetEmpty t_set_empty
|> __ReadSetMembership t_set
@@ -383,7 +419,7 @@ let ReadSet (model: Microsoft.Boogie.Model) (envMap,ctx) = /// and adds it to the given "envMap" map and "ctx" set.
// ======================================================
let ReadNull (model: Microsoft.Boogie.Model) (envMap,ctx) =
- let f_null = model.MkFunc("null", 0)
+ let f_null = model.MkFunc(NULL_FNAME, 0)
assert (f_null.AppCount = 1)
let e = (f_null.Apps |> Seq.nth 0).Result
let newEnv = envMap |> Map.add (GetLoc e) NullConst
@@ -396,7 +432,7 @@ let ReadNull (model: Microsoft.Boogie.Model) (envMap,ctx) = /// and then proceeds by reading stuff about the null constant, about sequences, and about sets.
// ============================================================================================
let ReadEnv (model: Microsoft.Boogie.Model) prog =
- let f_dtype = model.MkFunc("dtype", 1)
+ let f_dtype = model.MkFunc(DTYPE_FNAME, 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]
diff --git a/Jennisys/Jennisys.fsproj b/Jennisys/Jennisys.fsproj index f9bbc289..d3493749 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>examples/DList.jen /method:DNode.Init /noGenMod</StartArguments>
+ <StartArguments>examples/oopsla12/IntSet.jen /method:IntSet.Singleton</StartArguments>
<StartWorkingDirectory>C:\boogie\Jennisys\Jennisys\</StartWorkingDirectory>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
diff --git a/Jennisys/README.txt b/Jennisys/README.txt index 41bb9964..30f91b2e 100644 --- a/Jennisys/README.txt +++ b/Jennisys/README.txt @@ -1,18 +1,28 @@ 1. Installation instructions ---------------------------- + - download the entire boogie source distribution and place it in c:\boogie - create c:\tmp folder - copy the Jennisys\scripts\StartDafny-jen.bat script into c:\tmp 2. Running the examples ---------------------------- - $ cd Jennisys - $ bin/Debug/Jennisys.exe examples/<name>.jen /genRepr /genMod + $ cd Jennisys + $ bin/Debug/Jennisys.exe examples/<name>.jen - /genRepr - generate Repr field - /genMod - generate modular code (delegate to methods) + The most current and complete set of examples is in the + "examples/oopsla12" folder. No additional Jennisys switches need be + passed for either of them. - Currenty, in the List.jen example, methods SkipFew and Index cannot - be synthesized. All other methods in List.jen, List2.jen, List3.jen, - Set.jen, Number.jen, and NumberMethods.jen should be synthesizable. + Synthesized programs will be generated in "c:\tmp", and their file + names will follow the following pattern: + + "jennisys-synth_<example-name>.dfy" + + To verify the correctness of the synthesized programs, run + + $ Dafny /compile:0 jennisys-synth_<example-name>.dfy + + Expected outputs (i.e., synthesized Dafny programs) for the examples + in "examples/oopsla12" can be found in the same folder. diff --git a/Jennisys/examples/BHeap.jen b/Jennisys/examples/BHeap.jen new file mode 100644 index 00000000..55258bde --- /dev/null +++ b/Jennisys/examples/BHeap.jen @@ -0,0 +1,33 @@ +interface BHeap { + var elems: set[int] + + constructor Singleton(x: int) + ensures elems = {x} + + constructor Dupleton(a: int, b: int) + requires a != b + ensures elems = {a b} + + constructor Tripleton(x: int, y: int, z: int) + requires x != y && y != z && z != x + ensures elems = {x y z} + + method Find(n: int) returns (ret: bool) + ensures ret = (n in elems) +} + +datamodel BHeap { + var data: int + var left: BHeap + var right: BHeap + + frame + left * right + + invariant + elems = {data} + (left != null ? left.elems : {}) + (right != null ? right.elems : {}) + left != null ==> forall e :: e in left.elems ==> e < data + right != null ==> forall e :: e in right.elems ==> e < data + left = null ==> right = null + (left != null && right = null) ==> left.elems = {left.data} +} |