summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Rustan Leino <leino@microsoft.com>2011-07-21 13:48:13 -0700
committerGravatar Rustan Leino <leino@microsoft.com>2011-07-21 13:48:13 -0700
commit5e4a59d51efca7030672b83f06dccbc01f4f012e (patch)
treebe875b00a057b985c9e68447abf3ec7d16c58d47
parentd38660974a1fd289770b70024ca4cc9f2e60bdfc (diff)
parent4d47d89fd942fdf7ffffe5a59a60913a772b6943 (diff)
Merge
-rw-r--r--BCT/BytecodeTranslator/BytecodeTranslator.csproj2
-rw-r--r--BCT/BytecodeTranslator/ExpressionTraverser.cs211
-rw-r--r--BCT/BytecodeTranslator/HeapFactory.cs72
-rw-r--r--BCT/BytecodeTranslator/MetadataTraverser.cs48
-rw-r--r--BCT/BytecodeTranslator/Phone/PhoneCodeHelper.cs121
-rw-r--r--BCT/BytecodeTranslator/Phone/PhoneCodeWrapperWriter.cs38
-rw-r--r--BCT/BytecodeTranslator/Phone/PhoneInitializationTraverser.cs46
-rw-r--r--BCT/BytecodeTranslator/Phone/PhoneNavigationTraverser.cs95
-rw-r--r--BCT/BytecodeTranslator/Phone/PhoneURIDeclarationsTraverser.cs9
-rw-r--r--BCT/BytecodeTranslator/Program.cs33
-rw-r--r--BCT/BytecodeTranslator/Sink.cs70
-rw-r--r--BCT/BytecodeTranslator/StatementTraverser.cs4
-rw-r--r--BCT/BytecodeTranslator/TraverserFactory.cs5
-rw-r--r--BCT/PhoneControlsExtractor/PhoneBoogieCodeGenerator.py218
-rw-r--r--BCT/PhoneControlsExtractor/PhoneControlsExtractor.py9
-rw-r--r--BCT/RegressionTests/TranslationTest/GeneralHeapInput.txt175
-rw-r--r--BCT/RegressionTests/TranslationTest/SplitFieldsHeapInput.txt175
-rw-r--r--BCT/TranslationPlugins/PhoneControlsPlugin.cs145
-rw-r--r--Binaries/DafnyPrelude.bpl191
-rw-r--r--Binaries/DafnyRuntime.cs148
-rw-r--r--Chalice/chalice.bat2
-rw-r--r--Chalice/src/Ast.scala9
-rw-r--r--Chalice/src/Boogie.scala4
-rw-r--r--Chalice/src/Chalice.scala169
-rw-r--r--Chalice/src/Prelude.scala6
-rw-r--r--Chalice/src/SmokeTest.scala239
-rw-r--r--Chalice/src/Translator.scala208
-rw-r--r--Chalice/tests/examples/AssociationList.output.txt12
-rw-r--r--Chalice/tests/examples/BackgroundComputation.output.txt4
-rw-r--r--Chalice/tests/examples/CopyLessMessagePassing-with-ack.chalice14
-rw-r--r--Chalice/tests/examples/CopyLessMessagePassing-with-ack.output.txt8
-rw-r--r--Chalice/tests/examples/CopyLessMessagePassing-with-ack2.chalice21
-rw-r--r--Chalice/tests/examples/CopyLessMessagePassing-with-ack2.output.txt7
-rw-r--r--Chalice/tests/examples/CopyLessMessagePassing.chalice14
-rw-r--r--Chalice/tests/examples/CopyLessMessagePassing.output.txt4
-rw-r--r--Chalice/tests/examples/FictionallyDisjointCells.output.txt4
-rw-r--r--Chalice/tests/examples/ForkJoin.output.txt4
-rw-r--r--Chalice/tests/examples/HandOverHand.output.txt4
-rw-r--r--Chalice/tests/examples/ImplicitLocals.output.txt4
-rw-r--r--Chalice/tests/examples/LoopLockChange.output.txt15
-rw-r--r--Chalice/tests/examples/OwickiGries.output.txt4
-rw-r--r--Chalice/tests/examples/PetersonsAlgorithm.output.txt8
-rw-r--r--Chalice/tests/examples/ProdConsChannel.output.txt15
-rw-r--r--Chalice/tests/examples/RockBand-automagic.output.txt8
-rw-r--r--Chalice/tests/examples/RockBand.output.txt4
-rw-r--r--Chalice/tests/examples/Sieve.output.txt4
-rw-r--r--Chalice/tests/examples/SmokeTestTest.chalice112
-rw-r--r--Chalice/tests/examples/SmokeTestTest.output.txt19
-rw-r--r--Chalice/tests/examples/Solver.output.txt4
-rw-r--r--Chalice/tests/examples/TreeOfWorker.output.txt4
-rw-r--r--Chalice/tests/examples/UnboundedThreads.output.txt7
-rw-r--r--Chalice/tests/examples/cell-defaults.output.txt13
-rw-r--r--Chalice/tests/examples/cell.output.txt9
-rw-r--r--Chalice/tests/examples/counter.output.txt23
-rw-r--r--Chalice/tests/examples/dining-philosophers.output.txt6
-rw-r--r--Chalice/tests/examples/iterator.output.txt4
-rw-r--r--Chalice/tests/examples/iterator2.output.txt4
-rw-r--r--Chalice/tests/examples/linkedlist.output.txt7
-rw-r--r--Chalice/tests/examples/producer-consumer.output.txt7
-rw-r--r--Chalice/tests/examples/prog1.output.txt26
-rw-r--r--Chalice/tests/examples/prog2.output.txt17
-rw-r--r--Chalice/tests/examples/prog3.output.txt15
-rw-r--r--Chalice/tests/examples/prog4.output.txt21
-rw-r--r--Chalice/tests/examples/quantifiers.output.txt7
-rw-r--r--Chalice/tests/examples/swap.output.txt4
-rw-r--r--Chalice/tests/permission-model/basic.output.txt13
-rw-r--r--Chalice/tests/permission-model/channels.output.txt9
-rw-r--r--Chalice/tests/permission-model/locks.output.txt30
-rw-r--r--Chalice/tests/permission-model/peculiar.output.txt9
-rw-r--r--Chalice/tests/permission-model/permission_arithmetic.chalice53
-rw-r--r--Chalice/tests/permission-model/permission_arithmetic.output.txt31
-rw-r--r--Chalice/tests/permission-model/predicates.output.txt14
-rw-r--r--Chalice/tests/permission-model/scaling.chalice58
-rw-r--r--Chalice/tests/permission-model/scaling.output.txt11
-rw-r--r--Chalice/tests/permission-model/sequences.output.txt9
-rw-r--r--Chalice/tests/test-scripts/getboogieoutput.bat2
-rw-r--r--Chalice/tests/test-scripts/reg_test.bat2
-rw-r--r--Chalice/tests/test-scripts/test.bat2
-rw-r--r--Jennisys/Jennisys/Analyzer.fs200
-rw-r--r--Jennisys/Jennisys/Ast.fs1
-rw-r--r--Jennisys/Jennisys/AstUtils.fs110
-rw-r--r--Jennisys/Jennisys/CodeGen.fs234
-rw-r--r--Jennisys/Jennisys/DafnyModelUtils.fs23
-rw-r--r--Jennisys/Jennisys/DafnyPrinter.fs15
-rw-r--r--Jennisys/Jennisys/Jennisys.fsproj2
-rw-r--r--Jennisys/Jennisys/Options.fs32
-rw-r--r--Jennisys/Jennisys/Printer.fs284
-rw-r--r--Jennisys/Jennisys/Resolver.fs108
-rw-r--r--Jennisys/Jennisys/Utils.fs40
-rw-r--r--Jennisys/Jennisys/examples/List.jen6
-rw-r--r--Jennisys/Jennisys/examples/List2.jen4
-rw-r--r--Jennisys/Jennisys/examples/List3.jen4
-rw-r--r--Jennisys/Jennisys/examples/Set.jen12
-rw-r--r--Jennisys/Jennisys/examples/jennisys-synth_List.dfy147
-rw-r--r--Jennisys/Jennisys/examples/jennisys-synth_List2.dfy207
-rw-r--r--Jennisys/Jennisys/examples/jennisys-synth_List3.dfy255
-rw-r--r--Jennisys/Jennisys/examples/jennisys-synth_Number.dfy202
-rw-r--r--Jennisys/Jennisys/examples/jennisys-synth_Set.dfy344
-rw-r--r--Source/Dafny/Compiler.cs62
-rw-r--r--Source/Dafny/Dafny.atg32
-rw-r--r--Source/Dafny/DafnyAst.cs65
-rw-r--r--Source/Dafny/Parser.cs898
-rw-r--r--Source/Dafny/Printer.cs10
-rw-r--r--Source/Dafny/Resolver.cs132
-rw-r--r--Source/Dafny/Scanner.cs152
-rw-r--r--Source/Dafny/Translator.cs278
-rw-r--r--Test/VSI-Benchmarks/Answer12
-rw-r--r--Test/VSI-Benchmarks/runtest.bat4
-rw-r--r--Test/dafny0/AdvancedLHS.dfy1
-rw-r--r--Test/dafny0/Answer225
-rw-r--r--Test/dafny0/Array.dfy32
-rw-r--r--Test/dafny0/Definedness.dfy16
-rw-r--r--Test/dafny0/MultiSets.dfy103
-rw-r--r--Test/dafny0/NatTypes.dfy3
-rw-r--r--Test/dafny0/Termination.dfy5
-rw-r--r--Test/dafny0/TypeAntecedents.dfy4
-rw-r--r--Test/dafny0/TypeParameters.dfy23
-rw-r--r--Test/dafny0/runtest.bat2
-rw-r--r--Test/dafny1/Answer6
-rw-r--r--Test/dafny1/Celebrity.dfy26
-rw-r--r--Test/dafny1/Rippling.dfy18
-rw-r--r--Test/dafny1/UltraFilter.dfy3
-rw-r--r--Test/sanity/Answer2
-rw-r--r--Util/VS2010/Dafny/DafnyLanguageService/Grammar.cs3
124 files changed, 5742 insertions, 1767 deletions
diff --git a/BCT/BytecodeTranslator/BytecodeTranslator.csproj b/BCT/BytecodeTranslator/BytecodeTranslator.csproj
index e9b8be83..8f72e62f 100644
--- a/BCT/BytecodeTranslator/BytecodeTranslator.csproj
+++ b/BCT/BytecodeTranslator/BytecodeTranslator.csproj
@@ -128,7 +128,7 @@
<Compile Include="Phone\PhoneCodeHelper.cs" />
<Compile Include="Phone\PhoneInitializationTraverser.cs" />
<Compile Include="Phone\PhoneNavigationTraverser.cs" />
- <Compile Include="Phone\PhoneURIDeclarationsTraverser.cs" />
+ <Compile Include="Phone\PhoneCodeWrapperWriter.cs" />
<Compile Include="Prelude.cs" />
<Compile Include="ExpressionTraverser.cs" />
<Compile Include="Sink.cs" />
diff --git a/BCT/BytecodeTranslator/ExpressionTraverser.cs b/BCT/BytecodeTranslator/ExpressionTraverser.cs
index 7e7de866..5e195300 100644
--- a/BCT/BytecodeTranslator/ExpressionTraverser.cs
+++ b/BCT/BytecodeTranslator/ExpressionTraverser.cs
@@ -17,6 +17,8 @@ using Microsoft.Cci.ILToCodeModel;
using Bpl = Microsoft.Boogie;
using System.Diagnostics.Contracts;
+using TranslationPlugins;
+using BytecodeTranslator.Phone;
namespace BytecodeTranslator
@@ -447,7 +449,6 @@ namespace BytecodeTranslator
/// <remarks>Stub, This one really needs comments!</remarks>
public override void Visit(IMethodCall methodCall) {
var resolvedMethod = Sink.Unspecialize(methodCall.MethodToCall).ResolvedMethod;
-
if (resolvedMethod == Dummy.Method) {
throw new TranslationException(
ExceptionType.UnresolvedMethod,
@@ -455,108 +456,131 @@ namespace BytecodeTranslator
}
Bpl.IToken methodCallToken = methodCall.Token();
-
List<Bpl.Expr> inexpr;
List<Bpl.IdentifierExpr> outvars;
Bpl.IdentifierExpr thisExpr;
Dictionary<Bpl.IdentifierExpr, Bpl.IdentifierExpr> toBoxed;
var proc = TranslateArgumentsAndReturnProcedure(methodCallToken, methodCall.MethodToCall, resolvedMethod, methodCall.IsStaticCall ? null : methodCall.ThisArgument, methodCall.Arguments, out inexpr, out outvars, out thisExpr, out toBoxed);
-
string methodname = proc.Name;
var translateAsFunctionCall = proc is Bpl.Function;
Bpl.QKeyValue attrib = null;
- if (!translateAsFunctionCall) {
- foreach (var a in resolvedMethod.Attributes) {
- if (TypeHelper.GetTypeName(a.Type).EndsWith("AsyncAttribute")) {
- attrib = new Bpl.QKeyValue(methodCallToken, "async", new List<object>(), null);
+
+ // TODO this code structure is quite chaotic, and some code needs to be evaluated regardless, hence the try-finally
+ try {
+ if (!translateAsFunctionCall) {
+ foreach (var a in resolvedMethod.Attributes) {
+ if (TypeHelper.GetTypeName(a.Type).EndsWith("AsyncAttribute")) {
+ attrib = new Bpl.QKeyValue(methodCallToken, "async", new List<object>(), null);
+ }
}
}
- }
-
- #region Special case: ctor call for a struct type
- if (resolvedMethod.IsConstructor && resolvedMethod.ContainingTypeDefinition.IsStruct) {
- // then the method call looks like "&s.S.ctor(...)" for some variable s of struct type S
- // treat it as if it was "s := new S(...)"
- // So this code is the same as Visit(ICreateObjectInstance)
- // TODO: factor the code into a single method?
- // First generate an Alloc() call
- this.StmtTraverser.StmtBuilder.Add(new Bpl.CallCmd(methodCallToken, this.sink.AllocationMethodName, new Bpl.ExprSeq(), new Bpl.IdentifierExprSeq(thisExpr)));
+ if (resolvedMethod.IsConstructor && resolvedMethod.ContainingTypeDefinition.IsStruct) {
+ handleStructConstructorCall(methodCall, methodCallToken, inexpr, outvars, thisExpr, proc);
+ return;
+ }
- // Second, generate the call to the appropriate ctor
- this.StmtTraverser.StmtBuilder.Add(new Bpl.CallCmd(methodCallToken, proc.Name, inexpr, outvars));
+ Bpl.CallCmd call;
+ bool isEventAdd = resolvedMethod.IsSpecialName && resolvedMethod.Name.Value.StartsWith("add_");
+ bool isEventRemove = resolvedMethod.IsSpecialName && resolvedMethod.Name.Value.StartsWith("remove_");
+ if (isEventAdd || isEventRemove) {
+ call = translateAddRemoveCall(methodCall, resolvedMethod, methodCallToken, inexpr, outvars, thisExpr, isEventAdd);
+ } else {
+ if (translateAsFunctionCall) {
+ var func = proc as Bpl.Function;
+ var exprSeq = new Bpl.ExprSeq();
+ foreach (var e in inexpr) {
+ exprSeq.Add(e);
+ }
+ var callFunction = new Bpl.NAryExpr(methodCallToken, new Bpl.FunctionCall(func), exprSeq);
+ this.TranslatedExpressions.Push(callFunction);
+ return;
+ } else {
+ if (attrib != null)
+ call = new Bpl.CallCmd(methodCallToken, methodname, inexpr, outvars, attrib);
+ else
+ call = new Bpl.CallCmd(methodCallToken, methodname, inexpr, outvars);
+ this.StmtTraverser.StmtBuilder.Add(call);
+ }
+ }
- // Generate an assumption about the dynamic type of the just allocated object
- this.StmtTraverser.StmtBuilder.Add(
- new Bpl.AssumeCmd(methodCallToken,
- Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Eq,
- this.sink.Heap.DynamicType(thisExpr),
- this.sink.FindOrCreateType(methodCall.MethodToCall.ResolvedMethod.ContainingTypeDefinition)
- )
- )
- );
+ foreach (KeyValuePair<Bpl.IdentifierExpr, Bpl.IdentifierExpr> kv in toBoxed) {
+ this.StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(kv.Key, this.sink.Heap.Unbox(Bpl.Token.NoToken, kv.Key.Type, kv.Value)));
+ }
- return;
+ Bpl.Expr expr = Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Neq, Bpl.Expr.Ident(this.sink.Heap.ExceptionVariable), Bpl.Expr.Ident(this.sink.Heap.NullRef));
+ this.StmtTraverser.RaiseException(expr);
+ } finally {
+ if (PhoneCodeHelper.PhonePlugin != null) {
+ if (PhoneCodeHelper.isNavigationCall(methodCall, sink.host)) {
+ // the block is a potential page changer
+ List<Bpl.AssignLhs> lhs = new List<Bpl.AssignLhs>();
+ List<Bpl.Expr> rhs = new List<Bpl.Expr>();
+ Bpl.Expr value = new Bpl.LiteralExpr(Bpl.Token.NoToken, false);
+ rhs.Add(value);
+ Bpl.SimpleAssignLhs assignee=
+ new Bpl.SimpleAssignLhs(Bpl.Token.NoToken,
+ new Bpl.IdentifierExpr(Bpl.Token.NoToken,
+ sink.FindOrCreateGlobalVariable(PhoneCodeHelper.BOOGIE_CONTINUE_ON_PAGE_VARIABLE, Bpl.Type.Bool)));
+ lhs.Add(assignee);
+ Bpl.AssignCmd assignCmd = new Bpl.AssignCmd(Bpl.Token.NoToken, lhs, rhs);
+ this.StmtTraverser.StmtBuilder.Add(assignCmd);
+ }
+ }
}
- #endregion
+ }
+ private Bpl.CallCmd translateAddRemoveCall(IMethodCall methodCall, IMethodDefinition resolvedMethod, Bpl.IToken methodCallToken, List<Bpl.Expr> inexpr, List<Bpl.IdentifierExpr> outvars, Bpl.IdentifierExpr thisExpr, bool isEventAdd) {
Bpl.CallCmd call;
- bool isEventAdd = resolvedMethod.IsSpecialName && resolvedMethod.Name.Value.StartsWith("add_");
- bool isEventRemove = resolvedMethod.IsSpecialName && resolvedMethod.Name.Value.StartsWith("remove_");
- if (isEventAdd || isEventRemove) {
- var mName = resolvedMethod.Name.Value;
- var eventName = mName.Substring(mName.IndexOf('_') + 1);
- var eventDef = TypeHelper.GetEvent(resolvedMethod.ContainingTypeDefinition, this.sink.host.NameTable.GetNameFor(eventName));
- Contract.Assert(eventDef != Dummy.Event);
- Bpl.Variable eventVar = this.sink.FindOrCreateEventVariable(eventDef);
- Bpl.Variable local = this.sink.CreateFreshLocal(eventDef.Type);
-
- if (methodCall.IsStaticCall) {
- this.StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(Bpl.Expr.Ident(local), Bpl.Expr.Ident(eventVar)));
- inexpr.Insert(0, Bpl.Expr.Ident(local));
- }
- else {
- this.StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(Bpl.Expr.Ident(local), this.sink.Heap.ReadHeap(thisExpr, Bpl.Expr.Ident(eventVar), resolvedMethod.ContainingType.ResolvedType.IsStruct ? AccessType.Struct : AccessType.Heap, local.TypedIdent.Type)));
- inexpr[0] = Bpl.Expr.Ident(local);
- }
-
- System.Diagnostics.Debug.Assert(outvars.Count == 0);
- outvars.Insert(0, Bpl.Expr.Ident(local));
- string methodName = isEventAdd ? this.sink.DelegateAddName : this.sink.DelegateRemoveName;
- call = new Bpl.CallCmd(methodCallToken, methodName, inexpr, outvars);
- this.StmtTraverser.StmtBuilder.Add(call);
- if (methodCall.IsStaticCall) {
- this.StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(Bpl.Expr.Ident(eventVar), Bpl.Expr.Ident(local)));
- }
- else {
- this.StmtTraverser.StmtBuilder.Add(this.sink.Heap.WriteHeap(methodCallToken, thisExpr, Bpl.Expr.Ident(eventVar), Bpl.Expr.Ident(local), resolvedMethod.ContainingType.ResolvedType.IsStruct ? AccessType.Struct : AccessType.Heap, local.TypedIdent.Type));
- }
+ var mName = resolvedMethod.Name.Value;
+ var eventName = mName.Substring(mName.IndexOf('_') + 1);
+ var eventDef = TypeHelper.GetEvent(resolvedMethod.ContainingTypeDefinition, this.sink.host.NameTable.GetNameFor(eventName));
+ Contract.Assert(eventDef != Dummy.Event);
+ Bpl.Variable eventVar = this.sink.FindOrCreateEventVariable(eventDef);
+ Bpl.Variable local = this.sink.CreateFreshLocal(eventDef.Type);
+
+ if (methodCall.IsStaticCall) {
+ this.StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(Bpl.Expr.Ident(local), Bpl.Expr.Ident(eventVar)));
+ inexpr.Insert(0, Bpl.Expr.Ident(local));
} else {
- if (translateAsFunctionCall) {
- var func = proc as Bpl.Function;
- var exprSeq = new Bpl.ExprSeq();
- foreach (var e in inexpr) {
- exprSeq.Add(e);
- }
- var callFunction = new Bpl.NAryExpr(methodCallToken, new Bpl.FunctionCall(func), exprSeq);
- this.TranslatedExpressions.Push(callFunction);
- return;
-
- } else {
- if (attrib != null)
- call = new Bpl.CallCmd(methodCallToken, methodname, inexpr, outvars, attrib);
- else
- call = new Bpl.CallCmd(methodCallToken, methodname, inexpr, outvars);
- this.StmtTraverser.StmtBuilder.Add(call);
- }
+ this.StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(Bpl.Expr.Ident(local), this.sink.Heap.ReadHeap(thisExpr, Bpl.Expr.Ident(eventVar), resolvedMethod.ContainingType.ResolvedType.IsStruct ? AccessType.Struct : AccessType.Heap, local.TypedIdent.Type)));
+ inexpr[0] = Bpl.Expr.Ident(local);
}
- foreach (KeyValuePair<Bpl.IdentifierExpr, Bpl.IdentifierExpr> kv in toBoxed) {
- this.StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(kv.Key, this.sink.Heap.Unbox(Bpl.Token.NoToken, kv.Key.Type, kv.Value)));
+ System.Diagnostics.Debug.Assert(outvars.Count == 0);
+ outvars.Insert(0, Bpl.Expr.Ident(local));
+ string methodName = isEventAdd ? this.sink.DelegateAddName : this.sink.DelegateRemoveName;
+ call = new Bpl.CallCmd(methodCallToken, methodName, inexpr, outvars);
+ this.StmtTraverser.StmtBuilder.Add(call);
+ if (methodCall.IsStaticCall) {
+ this.StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(Bpl.Expr.Ident(eventVar), Bpl.Expr.Ident(local)));
+ } else {
+ this.StmtTraverser.StmtBuilder.Add(this.sink.Heap.WriteHeap(methodCallToken, thisExpr, Bpl.Expr.Ident(eventVar), Bpl.Expr.Ident(local), resolvedMethod.ContainingType.ResolvedType.IsStruct ? AccessType.Struct : AccessType.Heap, local.TypedIdent.Type));
}
+ return call;
+ }
- Bpl.Expr expr = Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Neq, Bpl.Expr.Ident(this.sink.Heap.ExceptionVariable), Bpl.Expr.Ident(this.sink.Heap.NullRef));
- this.StmtTraverser.RaiseException(expr);
+ private void handleStructConstructorCall(IMethodCall methodCall, Bpl.IToken methodCallToken, List<Bpl.Expr> inexpr, List<Bpl.IdentifierExpr> outvars, Bpl.IdentifierExpr thisExpr, Bpl.DeclWithFormals proc) {
+ // then the method call looks like "&s.S.ctor(...)" for some variable s of struct type S
+ // treat it as if it was "s := new S(...)"
+ // So this code is the same as Visit(ICreateObjectInstance)
+ // TODO: factor the code into a single method?
+
+ // First generate an Alloc() call
+ this.StmtTraverser.StmtBuilder.Add(new Bpl.CallCmd(methodCallToken, this.sink.AllocationMethodName, new Bpl.ExprSeq(), new Bpl.IdentifierExprSeq(thisExpr)));
+
+ // Second, generate the call to the appropriate ctor
+ this.StmtTraverser.StmtBuilder.Add(new Bpl.CallCmd(methodCallToken, proc.Name, inexpr, outvars));
+
+ // Generate an assumption about the dynamic type of the just allocated object
+ this.StmtTraverser.StmtBuilder.Add(
+ new Bpl.AssumeCmd(methodCallToken,
+ Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Eq,
+ this.sink.Heap.DynamicType(thisExpr),
+ this.sink.FindOrCreateType(methodCall.MethodToCall.ResolvedMethod.ContainingTypeDefinition)
+ )
+ )
+ );
}
// REVIEW: Does "thisExpr" really need to come back as an identifier? Can't it be a general expression?
@@ -657,9 +681,21 @@ namespace BytecodeTranslator
public override void Visit(IAssignment assignment) {
Contract.Assert(TranslatedExpressions.Count == 0);
var tok = assignment.Token();
- TranslateAssignment(tok, assignment.Target.Definition, assignment.Target.Instance, assignment.Source);
- return;
+ ICompileTimeConstant constant= assignment.Source as ICompileTimeConstant;
+ if (PhoneCodeHelper.PhonePlugin != null && constant != null && constant.Value.Equals(PhoneCodeHelper.BOOGIE_DO_HAVOC_CURRENTURI)) {
+ TranslateHavocCurrentURI();
+ } else {
+ TranslateAssignment(tok, assignment.Target.Definition, assignment.Target.Instance, assignment.Source);
+ }
+ }
+
+ /// <summary>
+ /// Patch, to account for URIs that cannot be tracked because of current dataflow restrictions
+ /// </summary>
+ private void TranslateHavocCurrentURI() {
+ Bpl.CallCmd havocCall = new Bpl.CallCmd(Bpl.Token.NoToken, PhoneCodeHelper.BOOGIE_DO_HAVOC_CURRENTURI, new List<Bpl.Expr>(), new List<Bpl.IdentifierExpr>());
+ StmtTraverser.StmtBuilder.Add(havocCall);
}
/// <summary>
@@ -1223,8 +1259,8 @@ namespace BytecodeTranslator
*/
StatementTraverser thenStmtTraverser = this.StmtTraverser.factory.MakeStatementTraverser(this.sink, this.StmtTraverser.PdbReader, this.contractContext);
- ExpressionTraverser thenExprTraverser = this.StmtTraverser.factory.MakeExpressionTraverser(this.sink, thenStmtTraverser, this.contractContext);
StatementTraverser elseStmtTraverser = this.StmtTraverser.factory.MakeStatementTraverser(this.sink, this.StmtTraverser.PdbReader, this.contractContext);
+ ExpressionTraverser thenExprTraverser = this.StmtTraverser.factory.MakeExpressionTraverser(this.sink, thenStmtTraverser, this.contractContext);
ExpressionTraverser elseExprTraverser = this.StmtTraverser.factory.MakeExpressionTraverser(this.sink, elseStmtTraverser, this.contractContext);
thenExprTraverser.Visit(conditional.ResultIfTrue);
elseExprTraverser.Visit(conditional.ResultIfFalse);
@@ -1294,7 +1330,12 @@ namespace BytecodeTranslator
base.Visit(checkIfInstance.Operand);
var exp = TranslatedExpressions.Pop();
var dynTypeOfOperand = this.sink.Heap.DynamicType(exp);
- var subtype = Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Subtype, dynTypeOfOperand, e);
+ //var subtype = Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Subtype, dynTypeOfOperand, e);
+ var subtype = new Bpl.NAryExpr(
+ Bpl.Token.NoToken,
+ new Bpl.FunctionCall(this.sink.Heap.Subtype),
+ new Bpl.ExprSeq(dynTypeOfOperand, e)
+ );
var notnull = Bpl.Expr.Neq(exp, Bpl.Expr.Ident(this.sink.Heap.NullRef));
var and = Bpl.Expr.And(notnull, subtype);
TranslatedExpressions.Push(and);
diff --git a/BCT/BytecodeTranslator/HeapFactory.cs b/BCT/BytecodeTranslator/HeapFactory.cs
index fa46fe34..a2a3e806 100644
--- a/BCT/BytecodeTranslator/HeapFactory.cs
+++ b/BCT/BytecodeTranslator/HeapFactory.cs
@@ -284,6 +284,15 @@ namespace BytecodeTranslator {
[RepresentationFor("$As", "function $As(Ref, Type): Ref;")]
public Bpl.Function AsFunction = null;
+ [RepresentationFor("$Subtype", "function $Subtype(Type, Type): bool;")]
+ public Bpl.Function Subtype = null;
+
+ [RepresentationFor("$DirectSubtype", "function $DirectSubtype(Type, Type): bool;")]
+ public Bpl.Function DirectSubtype = null;
+
+ [RepresentationFor("$DisjointSubtree", "function $DisjointSubtree(Type, Type): bool;")]
+ public Bpl.Function DisjointSubtree = null;
+
protected readonly string CommonText =
@"var $Alloc: [Ref] bool;
@@ -294,6 +303,27 @@ procedure {:inline 1} Alloc() returns (x: Ref)
$Alloc[x] := true;
}
+// Subtype is reflexive
+axiom (forall t: Type :: $Subtype(t, t) );
+
+// Subtype is anti-symmetric
+axiom (forall t0 : Type, t1 : Type :: { $Subtype(t0, t1), $Subtype(t1, t0) }
+ $Subtype(t0, t1) && $Subtype(t1, t0) ==> (t0 == t1) );
+
+// Subtype is transitive
+axiom (forall t0 : Type, t1 : Type, t2 : Type :: { $Subtype(t0, t1), $Subtype(t1, t2) }
+ $Subtype(t0, t1) && $Subtype(t1, t2) ==> $Subtype(t0, t2) );
+
+// Direct subtype definition
+axiom (forall C : Type, D : Type :: { $DirectSubtype(D, C) }
+ $DirectSubtype(D, C) <==> $Subtype(D, C) && (forall z : Type :: $Subtype(D, z) && $Subtype(z, C) ==> z == C || z == D )
+ );
+
+// Incomparable subtypes: the subtrees are disjoint for (some) subtypes (those that imply single inheritance)
+function oneDown(t0 : Type, t1 : Type) : Type; // uninterpreted function with no axioms
+axiom (forall C : Type, D : Type :: { $DisjointSubtree(D, C) }
+ $DisjointSubtree(D, C) <==> (forall z : Type :: $Subtype(z, D) ==> oneDown(C,z) == D) );
+
function $TypeOfInv(Ref): Type;
axiom (forall t: Type :: {$TypeOf(t)} $TypeOfInv($TypeOf(t)) == t);
@@ -451,6 +481,48 @@ procedure DelegateRemoveHelper(oldi: Ref, m: int, o: Ref) returns (i: Ref)
}
}
+procedure System.String.op_Equality$System.String$System.String(a$in: Ref, b$in: Ref) returns ($result: bool);
+procedure System.String.op_Inequality$System.String$System.String(a$in: Ref, b$in: Ref) returns ($result: bool);
+
+implementation System.String.op_Equality$System.String$System.String(a$in: Ref, b$in: Ref) returns ($result: bool) {
+ $result := (a$in == b$in);
+}
+
+implementation System.String.op_Inequality$System.String$System.String(a$in: Ref, b$in: Ref) returns ($result: bool) {
+ $result := (a$in != b$in);
+}
+
+// SILVERLIGHT CONTROL SPECIFIC CODE
+function isControlEnabled(Ref) : bool;
+function isControlChecked(Ref) : bool;
+
+procedure System.Windows.Controls.Control.set_IsEnabled$System.Boolean($this: Ref, value$in: bool);
+implementation System.Windows.Controls.Control.set_IsEnabled$System.Boolean($this: Ref, value$in: bool) {
+ assume isControlEnabled($this) == value$in;
+}
+
+procedure System.Windows.Controls.Control.get_IsEnabled($this: Ref) returns ($result: Ref);
+implementation System.Windows.Controls.Control.get_IsEnabled($this: Ref) returns ($result: Ref) {
+ var enabledness: bool;
+ enabledness := isControlEnabled($this);
+ $result := Box2Ref(Bool2Box(enabledness));
+}
+
+procedure System.Windows.Controls.Primitives.ToggleButton.set_IsChecked$System.Nullable$System.Boolean$($this: Ref, value$in: Ref);
+implementation System.Windows.Controls.Primitives.ToggleButton.set_IsChecked$System.Nullable$System.Boolean$($this: Ref, value$in: Ref) {
+ var check: bool;
+
+ check := Box2Bool(Ref2Box(value$in));
+ assume isControlChecked($this) == check;
+}
+
+procedure System.Windows.Controls.Primitives.ToggleButton.get_IsChecked($this: Ref) returns ($result: Ref);
+implementation System.Windows.Controls.Primitives.ToggleButton.get_IsChecked($this: Ref) returns ($result: Ref) {
+ var isChecked: bool;
+ isChecked := isControlChecked($this);
+ $result := Box2Ref(Bool2Box(isChecked));
+}
+
";
[RepresentationFor("$Head", "var $Head: [Ref]Ref;")]
diff --git a/BCT/BytecodeTranslator/MetadataTraverser.cs b/BCT/BytecodeTranslator/MetadataTraverser.cs
index d4a125e1..02ae0c9f 100644
--- a/BCT/BytecodeTranslator/MetadataTraverser.cs
+++ b/BCT/BytecodeTranslator/MetadataTraverser.cs
@@ -16,6 +16,8 @@ using Microsoft.Cci.ILToCodeModel;
using Bpl = Microsoft.Boogie;
using System.Diagnostics.Contracts;
+using TranslationPlugins;
+using BytecodeTranslator.Phone;
namespace BytecodeTranslator {
@@ -65,6 +67,8 @@ namespace BytecodeTranslator {
var savedPrivateTypes = this.privateTypes;
this.privateTypes = new List<ITypeDefinition>();
+ trackPageNameVariableName(typeDefinition);
+
if (typeDefinition.IsClass) {
bool savedSawCctor = this.sawCctor;
this.sawCctor = false;
@@ -98,6 +102,16 @@ namespace BytecodeTranslator {
}
List<ITypeDefinition> privateTypes = new List<ITypeDefinition>();
+ private void trackPageNameVariableName(ITypeDefinition typeDef) {
+ if (typeDef.isPhoneApplicationPageClass(sink.host)) {
+ INamespaceTypeDefinition namedTypeDef = typeDef as INamespaceTypeDefinition;
+ string fullyQualifiedName = namedTypeDef.ContainingNamespace.Name.Value + "." + namedTypeDef.Name.Value;
+ string uriName = PhoneCodeHelper.getURIBase(PhoneCodeHelper.getXAMLForPage(fullyQualifiedName));
+ Bpl.Constant uriConstant= sink.FindOrCreateConstant(uriName);
+ PhoneCodeHelper.setBoogieStringPageNameForPageClass(fullyQualifiedName, uriConstant.Name);
+ }
+ }
+
private void CreateDefaultStructConstructor(ITypeDefinition typeDefinition) {
Contract.Requires(typeDefinition.IsStruct);
@@ -476,13 +490,45 @@ namespace BytecodeTranslator {
}
public override void Visit(IFieldDefinition fieldDefinition) {
- this.sink.FindOrCreateFieldVariable(fieldDefinition);
+ Bpl.Variable fieldVar= this.sink.FindOrCreateFieldVariable(fieldDefinition);
+
+ // if tracked by the phone plugin, we need to find out the bpl assigned name for future use
+ if (PhoneCodeHelper.PhonePlugin != null) {
+ trackControlVariableName(fieldDefinition, fieldVar);
+ trackNavigationVariableName(fieldDefinition, fieldVar);
+ }
}
+ private static void trackNavigationVariableName(IFieldDefinition fieldDefinition, Bpl.Variable fieldVar) {
+ if (fieldDefinition.Name.Value.Equals(PhoneCodeHelper.IL_CURRENT_NAVIGATION_URI_VARIABLE)) {
+ PhoneCodeHelper.setBoogieNavigationVariable(fieldVar.Name);
+ }
+ }
+
+ private static void trackControlVariableName(IFieldDefinition fieldDefinition, Bpl.Variable fieldVar) {
+ INamespaceTypeReference namedContainerRef = fieldDefinition.ContainingType as INamespaceTypeReference;
+ if (namedContainerRef != null) {
+ string containerName = namedContainerRef.ContainingUnitNamespace.Unit.Name.Value + "." + namedContainerRef.Name.Value;
+ IEnumerable<ControlInfoStructure> controls = PhoneCodeHelper.PhonePlugin.getControlsForPage(containerName);
+ if (controls != null) {
+ ControlInfoStructure ctrlInfo = controls.FirstOrDefault(ctrl => ctrl.Name == fieldDefinition.Name.Value);
+ if (ctrlInfo != null)
+ ctrlInfo.BplName = fieldVar.Name;
+ }
+ }
+ }
#endregion
+ private void addPhoneTopLevelDeclarations() {
+ Bpl.Variable continueOnPageVar = sink.FindOrCreateGlobalVariable(PhoneCodeHelper.BOOGIE_CONTINUE_ON_PAGE_VARIABLE, Bpl.Type.Bool);
+ sink.TranslatedProgram.TopLevelDeclarations.Add(continueOnPageVar);
+ }
+
#region Public API
public virtual void TranslateAssemblies(IEnumerable<IUnit> assemblies) {
+ if (PhoneCodeHelper.PhonePlugin != null)
+ addPhoneTopLevelDeclarations();
+
foreach (var a in assemblies) {
a.Dispatch(this);
}
diff --git a/BCT/BytecodeTranslator/Phone/PhoneCodeHelper.cs b/BCT/BytecodeTranslator/Phone/PhoneCodeHelper.cs
index 74ad2140..e9cc208b 100644
--- a/BCT/BytecodeTranslator/Phone/PhoneCodeHelper.cs
+++ b/BCT/BytecodeTranslator/Phone/PhoneCodeHelper.cs
@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Cci;
+using Bpl=Microsoft.Boogie;
+using TranslationPlugins;
namespace BytecodeTranslator.Phone {
public enum StaticURIMode {
@@ -11,8 +13,46 @@ namespace BytecodeTranslator.Phone {
public static class PhoneCodeHelper {
// TODO ensure this name is unique in the program code, although it is esoteric enough
+ // TODO externalize strings
private const string IL_BOOGIE_VAR_PREFIX = "@__BOOGIE_";
+ private const string BOOGIE_VAR_PREFIX = "__BOOGIE_";
public const string IL_CURRENT_NAVIGATION_URI_VARIABLE = IL_BOOGIE_VAR_PREFIX + "CurrentNavigationURI__";
+ public const string BOOGIE_CONTINUE_ON_PAGE_VARIABLE = BOOGIE_VAR_PREFIX + "ContinueOnPage__";
+ public static readonly string[] NAV_CALLS = { /*"GoBack", "GoForward", "Navigate", "StopLoading"*/ "Navigate", "GoBack" };
+
+ // awful hack. want to insert a nonexisting method call while traversing CCI AST, deferring it to Boogie translation
+ public const string BOOGIE_DO_HAVOC_CURRENTURI = BOOGIE_VAR_PREFIX + "Havoc_CurrentURI__";
+
+ public static PhoneControlsPlugin PhonePlugin { get; set; }
+ private static IDictionary<string, Bpl.NamedDeclaration> boogieObjects = new Dictionary<string, Bpl.NamedDeclaration>();
+
+ public static Bpl.Variable getBoogieVariableForName(string varName) {
+ Bpl.Variable boogieVar = null;
+ try {
+ boogieVar = boogieObjects[varName] as Bpl.Variable;
+ } catch (KeyNotFoundException) {
+ }
+
+ if (boogieVar == null)
+ throw new ArgumentException("The boogie variable " + varName + " is not defined.");
+
+ return boogieVar;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="name"></param>
+ /// <param name="bplObject"></param>
+ /// <returns>true if defining a new name, false if replacing</returns>
+ public static bool setBoogieObjectForName(string name, Bpl.NamedDeclaration bplObject) {
+ bool ret = true;
+ if (boogieObjects.ContainsKey(name))
+ ret = false;
+
+ boogieObjects[name] = bplObject;
+ return ret;
+ }
public static bool isCreateObjectInstance(this IExpression expr) {
ICreateObjectInstance createObjExpr = expr as ICreateObjectInstance;
@@ -30,12 +70,12 @@ namespace BytecodeTranslator.Phone {
return false;
}
- public static bool isStringClass(this ITypeReference typeRef, MetadataReaderHost host) {
+ public static bool isStringClass(this ITypeReference typeRef, IMetadataHost host) {
ITypeReference targetType = host.PlatformType.SystemString;
return typeRef.isClass(targetType);
}
- public static bool isURIClass (this ITypeReference typeRef, MetadataReaderHost host) {
+ public static bool isURIClass(this ITypeReference typeRef, IMetadataHost host) {
Microsoft.Cci.Immutable.PlatformType platformType = host.PlatformType as Microsoft.Cci.Immutable.PlatformType;
if (platformType == null)
return false;
@@ -44,12 +84,31 @@ namespace BytecodeTranslator.Phone {
AssemblyIdentity systemAssemblyId = new AssemblyIdentity(host.NameTable.GetNameFor("System"), "", coreRef.Version, coreRef.PublicKeyToken, "");
IAssemblyReference systemAssembly = host.FindAssembly(systemAssemblyId);
- ITypeReference uriTypeRef= platformType.CreateReference(systemAssembly, "System", "Uri");
+ ITypeReference uriTypeRef = platformType.CreateReference(systemAssembly, "System", "Uri");
return typeRef.isClass(uriTypeRef);
}
+ public static bool isNavigationServiceClass(this ITypeReference typeRef, IMetadataHost host) {
+ Microsoft.Cci.Immutable.PlatformType platform = host.PlatformType as Microsoft.Cci.Immutable.PlatformType;
+ AssemblyIdentity MSPhoneAssemblyId =
+ new AssemblyIdentity(host.NameTable.GetNameFor("Microsoft.Phone"), "", new Version("7.0.0.0"),
+ new byte[] { 0x24, 0xEE, 0xC0, 0xD8, 0xC8, 0x6C, 0xDA, 0x1E }, "");
- public static bool isPhoneApplicationClass(this ITypeReference typeRef, MetadataReaderHost host) {
+ IAssemblyReference phoneAssembly = host.FindAssembly(MSPhoneAssemblyId);
+ ITypeReference phoneApplicationPageTypeRef = platform.CreateReference(phoneAssembly, "System", "Windows", "Navigation", "NavigationService");
+
+ ITypeReference baseClass = typeRef.ResolvedType.BaseClasses.FirstOrDefault();
+ while (baseClass != null) {
+ if (baseClass.ResolvedType.Equals(phoneApplicationPageTypeRef.ResolvedType)) {
+ return true;
+ }
+ baseClass = baseClass.ResolvedType.BaseClasses.FirstOrDefault();
+ }
+
+ return false;
+ }
+
+ public static bool isPhoneApplicationClass(this ITypeReference typeRef, IMetadataHost host) {
Microsoft.Cci.Immutable.PlatformType platform = host.PlatformType as Microsoft.Cci.Immutable.PlatformType;
IAssemblyReference coreAssemblyRef = platform.CoreAssemblyRef;
AssemblyIdentity MSPhoneSystemWindowsAssemblyId =
@@ -58,11 +117,10 @@ namespace BytecodeTranslator.Phone {
IAssemblyReference systemAssembly = host.FindAssembly(MSPhoneSystemWindowsAssemblyId);
ITypeReference applicationClass = platform.CreateReference(systemAssembly, "System", "Windows", "Application");
-
return typeRef.isClass(applicationClass);
}
- public static bool isPhoneApplicationPageClass(ITypeReference typeDefinition, MetadataReaderHost host) {
+ public static bool isPhoneApplicationPageClass(this ITypeReference typeRef, IMetadataHost host) {
Microsoft.Cci.Immutable.PlatformType platform = host.PlatformType as Microsoft.Cci.Immutable.PlatformType;
AssemblyIdentity MSPhoneAssemblyId =
new AssemblyIdentity(host.NameTable.GetNameFor("Microsoft.Phone"), "", new Version("7.0.0.0"),
@@ -71,7 +129,7 @@ namespace BytecodeTranslator.Phone {
IAssemblyReference phoneAssembly = host.FindAssembly(MSPhoneAssemblyId);
ITypeReference phoneApplicationPageTypeRef = platform.CreateReference(phoneAssembly, "Microsoft", "Phone", "Controls", "PhoneApplicationPage");
- ITypeReference baseClass = typeDefinition.ResolvedType.BaseClasses.FirstOrDefault();
+ ITypeReference baseClass = typeRef.ResolvedType.BaseClasses.FirstOrDefault();
while (baseClass != null) {
if (baseClass.ResolvedType.Equals(phoneApplicationPageTypeRef.ResolvedType)) {
return true;
@@ -100,9 +158,9 @@ namespace BytecodeTranslator.Phone {
IList<string> constantStrings = new List<string>();
// TODO this misses so many static strings, but let's start with this for now
- IExpression leftOp= stringConcatExpr.Arguments.FirstOrDefault();
+ IExpression leftOp = stringConcatExpr.Arguments.FirstOrDefault();
while (leftOp != null && leftOp is ICompileTimeConstant) {
- ICompileTimeConstant strConst= leftOp as ICompileTimeConstant;
+ ICompileTimeConstant strConst = leftOp as ICompileTimeConstant;
constantStrings.Add(strConst.Value as string);
if (stringConcatExpr.Arguments.ToList()[1] is IMethodCall) {
stringConcatExpr = stringConcatExpr.Arguments.ToList()[1] as IMethodCall;
@@ -115,10 +173,18 @@ namespace BytecodeTranslator.Phone {
}
}
- uri= constantStrings.Aggregate((aggr, elem) => aggr + elem);
+ uri = constantStrings.Aggregate((aggr, elem) => aggr + elem);
return Uri.IsWellFormedUriString(uri, UriKind.RelativeOrAbsolute);
}
+ public static bool isNavigationCall(IMethodCall call, IMetadataHost host) {
+ ITypeReference callType = call.MethodToCall.ContainingType;
+ if (!callType.isNavigationServiceClass(host))
+ return false;
+
+ return PhoneCodeHelper.NAV_CALLS.Contains(call.MethodToCall.Name.Value);
+ }
+
/// <summary>
/// uri is a valid URI but possibly partial (incomplete ?arg= values) and overspecified (complete ?arg=values)
/// This method returns a base URI
@@ -128,11 +194,42 @@ namespace BytecodeTranslator.Phone {
public static string getURIBase(string uri) {
// I need to build an absolute URI just to call getComponents() ...
Uri mockBaseUri = new Uri("mock://mock/", UriKind.RelativeOrAbsolute);
- Uri realUri = new Uri(mockBaseUri, uri);
+ Uri realUri;
+ try {
+ realUri = new Uri(uri, UriKind.Absolute);
+ } catch (UriFormatException) {
+ // uri string is relative
+ realUri = new Uri(mockBaseUri, uri);
+ }
- string str= realUri.GetComponents(UriComponents.Path|UriComponents.StrongAuthority|UriComponents.Scheme, UriFormat.UriEscaped);
+ string str = realUri.GetComponents(UriComponents.Path | UriComponents.StrongAuthority | UriComponents.Scheme, UriFormat.UriEscaped);
Uri mockStrippedUri = new Uri(str);
return mockBaseUri.MakeRelativeUri(mockStrippedUri).ToString();
}
+
+ private static ITypeReference mainAppTypeRef;
+ public static void setMainAppTypeReference(ITypeReference appType) {
+ mainAppTypeRef = appType;
+ }
+
+ public static ITypeReference getMainAppTypeReference() {
+ return mainAppTypeRef;
+ }
+
+ public static void setBoogieNavigationVariable(string var) {
+ PhonePlugin.setBoogieNavigationVariable(var);
+ }
+
+ public static string getBoogieNavigationVariable() {
+ return PhonePlugin.getBoogieNavigationVariable();
+ }
+
+ public static string getXAMLForPage(string pageClass) {
+ return PhonePlugin.getXAMLForPage(pageClass);
+ }
+
+ public static void setBoogieStringPageNameForPageClass(string pageClass, string boogieStringName) {
+ PhonePlugin.setBoogieStringPageNameForPageClass(pageClass, boogieStringName);
+ }
}
}
diff --git a/BCT/BytecodeTranslator/Phone/PhoneCodeWrapperWriter.cs b/BCT/BytecodeTranslator/Phone/PhoneCodeWrapperWriter.cs
new file mode 100644
index 00000000..3a779dcd
--- /dev/null
+++ b/BCT/BytecodeTranslator/Phone/PhoneCodeWrapperWriter.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using TranslationPlugins;
+
+namespace BytecodeTranslator.Phone {
+ class PhoneCodeWrapperWriter {
+ private static Sink sink;
+ public static void createCodeWrapper(Sink sink) {
+ PhoneCodeWrapperWriter.sink = sink;
+ /*
+ * create Main procedure
+ * - creates page instances, one per page -- this overapproximates as there may be more instances
+ * - havoc'd loop drives controls via calls to driver
+ *
+ * create Driver procedure
+ * - determine current page; for each page check if it is current or not
+ * - call page driver accordingly
+ *
+ * create Page drivers
+ * - one for each page
+ * - havoc-ly determine control to stimulate
+ * - check enabledness of control, stimulate by calling handler of chosen event if yes, nothing ig not
+ * - possibly many events to handle
+ * - might be slightly more efficient to nto return control until we know page navigation may have changed,
+ * but this requires a lot of knowledge (ie, will the called method call NavigationService or not)
+ */
+ createMainProcedure();
+ }
+
+ private static void createMainProcedure() {
+ // TODO
+ // for now I'm trying to create this code as an outside step of the flow
+ }
+ }
+}
diff --git a/BCT/BytecodeTranslator/Phone/PhoneInitializationTraverser.cs b/BCT/BytecodeTranslator/Phone/PhoneInitializationTraverser.cs
index fd24ff65..fec6e870 100644
--- a/BCT/BytecodeTranslator/Phone/PhoneInitializationTraverser.cs
+++ b/BCT/BytecodeTranslator/Phone/PhoneInitializationTraverser.cs
@@ -26,7 +26,6 @@ namespace BytecodeTranslator.Phone {
public class PhoneInitializationCodeTraverser : BaseCodeTraverser {
private readonly IMethodDefinition methodBeingTraversed;
private static bool initializationFound= false;
- private PhoneControlsPlugin phonePlugin;
private MetadataReaderHost host;
private IAssemblyReference coreAssemblyRef;
@@ -69,9 +68,8 @@ namespace BytecodeTranslator.Phone {
}
}
- public PhoneInitializationCodeTraverser(MetadataReaderHost host, IMethodDefinition traversedMethod, PhoneControlsPlugin phonePlugin) : base() {
+ public PhoneInitializationCodeTraverser(MetadataReaderHost host, IMethodDefinition traversedMethod) : base() {
this.methodBeingTraversed = traversedMethod;
- this.phonePlugin = phonePlugin;
this.host = host;
InitializeTraverser();
}
@@ -142,15 +140,12 @@ namespace BytecodeTranslator.Phone {
private void injectPhoneInitializationCode(BlockStatement block, Statement statementAfter) {
// TODO check page name against container name
- IEnumerable<ControlInfoStructure> controls= phonePlugin.getControlsForPage(methodBeingTraversed.Container.ToString());
+ IEnumerable<ControlInfoStructure> controls= PhoneCodeHelper.PhonePlugin.getControlsForPage(methodBeingTraversed.Container.ToString());
IEnumerable<IStatement> injectedStatements = new List<IStatement>();
foreach (ControlInfoStructure controlInfo in controls) {
injectedStatements = injectedStatements.Concat(getCodeForSettingEnabledness(controlInfo));
injectedStatements = injectedStatements.Concat(getCodeForSettingCheckedState(controlInfo));
injectedStatements = injectedStatements.Concat(getCodeForSettingVisibility(controlInfo));
- injectedStatements = injectedStatements.Concat(getCodeForSettingEventHandlers(controlInfo, "Click"));
- injectedStatements = injectedStatements.Concat(getCodeForSettingEventHandlers(controlInfo, "Checked"));
- injectedStatements = injectedStatements.Concat(getCodeForSettingEventHandlers(controlInfo, "Unchecked"));
}
int stmtPos= block.Statements.IndexOf(statementAfter);
@@ -166,6 +161,7 @@ namespace BytecodeTranslator.Phone {
IsStatic = false,
},
Instance = new ThisReference() { Type = methodBeingTraversed.Container },
+ Type=getTypeForClassname(controlInfo.ClassName),
};
}
@@ -222,7 +218,7 @@ namespace BytecodeTranslator.Phone {
MethodToCall = isEnabledSetter,
ThisArgument = boundControl,
};
-
+
setEnablednessCall.Arguments.Add(controlInfo.IsEnabled ? trueConstant : falseConstant);
ExpressionStatement callStmt = new ExpressionStatement() {
Expression = setEnablednessCall,
@@ -232,13 +228,23 @@ namespace BytecodeTranslator.Phone {
}
private IEnumerable<IStatement> getCodeForSettingCheckedState(ControlInfoStructure controlInfo) {
- // TODO not implemented yet
- return new List<IStatement>();
- }
-
- // TODO should stop propagating the string event name
- private IEnumerable<IStatement> getCodeForSettingEventHandlers(ControlInfoStructure controlInfo, string eventName) {
- // TODO not implemented yet
+ // IList<IStatement> code = new List<IStatement>();
+ // BoundExpression boundControl = makeBoundControlFromControlInfo(controlInfo);
+ // MethodCall setCheckStateCall= new MethodCall() {
+ // IsStaticCall = false,
+ // IsVirtualCall = true,
+ // IsTailCall = false,
+ // Type = ((Microsoft.Cci.Immutable.PlatformType) host.PlatformType).SystemVoid,
+ // MethodToCall = isCheckedSetter,
+ // ThisArgument = boundControl,
+ // };
+
+ // setCheckStateCall.Arguments.Add(controlInfo.IsChecked ? trueConstant : falseConstant);
+ // ExpressionStatement callStmt = new ExpressionStatement() {
+ // Expression = setCheckStateCall,
+ // };
+ // code.Add(callStmt);
+ // return code;
return new List<IStatement>();
}
@@ -268,12 +274,10 @@ namespace BytecodeTranslator.Phone {
/// Traverse metadata looking only for PhoneApplicationPage's constructors
/// </summary>
public class PhoneInitializationMetadataTraverser : BaseMetadataTraverser {
- private PhoneControlsPlugin phoneControlsInfo;
private MetadataReaderHost host;
- public PhoneInitializationMetadataTraverser(PhoneControlsPlugin phonePlugin, MetadataReaderHost host)
+ public PhoneInitializationMetadataTraverser(MetadataReaderHost host)
: base() {
- this.phoneControlsInfo = phonePlugin;
this.host = host;
}
@@ -290,7 +294,9 @@ namespace BytecodeTranslator.Phone {
/// </summary>
///
public override void Visit(ITypeDefinition typeDefinition) {
- if (typeDefinition.IsClass && PhoneCodeHelper.isPhoneApplicationPageClass(typeDefinition, host)) {
+ if (typeDefinition.isPhoneApplicationClass(host)) {
+ PhoneCodeHelper.setMainAppTypeReference(typeDefinition);
+ } else if (typeDefinition.isPhoneApplicationPageClass(host)) {
base.Visit(typeDefinition);
}
}
@@ -302,7 +308,7 @@ namespace BytecodeTranslator.Phone {
if (!method.IsConstructor)
return;
- PhoneInitializationCodeTraverser codeTraverser = new PhoneInitializationCodeTraverser(host, method, phoneControlsInfo);
+ PhoneInitializationCodeTraverser codeTraverser = new PhoneInitializationCodeTraverser(host, method);
var methodBody = method.Body as SourceMethodBody;
if (methodBody == null)
return;
diff --git a/BCT/BytecodeTranslator/Phone/PhoneNavigationTraverser.cs b/BCT/BytecodeTranslator/Phone/PhoneNavigationTraverser.cs
index b702e78b..b0387221 100644
--- a/BCT/BytecodeTranslator/Phone/PhoneNavigationTraverser.cs
+++ b/BCT/BytecodeTranslator/Phone/PhoneNavigationTraverser.cs
@@ -11,14 +11,10 @@ namespace BytecodeTranslator.Phone {
private MetadataReaderHost host;
private ITypeReference navigationSvcType;
private ITypeReference typeTraversed;
- private PhoneControlsPlugin phonePlugin;
- private static readonly string[] NAV_CALLS = { "GoBack", "GoForward", "Navigate", "StopLoading" };
-
- public PhoneNavigationCodeTraverser(PhoneControlsPlugin plugin, MetadataReaderHost host, ITypeReference typeTraversed) : base() {
+ public PhoneNavigationCodeTraverser(MetadataReaderHost host, ITypeReference typeTraversed) : base() {
this.host = host;
this.typeTraversed = typeTraversed;
- this.phonePlugin = plugin;
Microsoft.Cci.Immutable.PlatformType platform = host.PlatformType as Microsoft.Cci.Immutable.PlatformType;
// TODO obtain version, culture and signature data dynamically
@@ -36,7 +32,7 @@ namespace BytecodeTranslator.Phone {
if (method.IsConstructor && PhoneCodeHelper.isPhoneApplicationClass(typeTraversed, host)) {
// TODO initialize current navigation URI to mainpage, using a placeholder for now.
// TODO BUG doing this is generating a fresh variable definition somewhere that the BCT then translates into two different (identical) declarations
- string mainPageUri = phonePlugin.getMainPageXAML();
+ string mainPageUri = PhoneCodeHelper.PhonePlugin.getMainPageXAML();
SourceMethodBody sourceBody = method.Body as SourceMethodBody;
if (sourceBody != null) {
BlockStatement bodyBlock = sourceBody.Block as BlockStatement;
@@ -44,13 +40,14 @@ namespace BytecodeTranslator.Phone {
Assignment uriInitAssign = new Assignment() {
Source = new CompileTimeConstant() {
Type = host.PlatformType.SystemString,
- Value = mainPageUri,
+ Value = PhoneCodeHelper.getURIBase(mainPageUri),
},
Type = host.PlatformType.SystemString,
Target = new TargetExpression() {
Type = host.PlatformType.SystemString,
Definition = new FieldReference() {
- ContainingType= typeTraversed,
+ // ContainingType= typeTraversed,
+ ContainingType= PhoneCodeHelper.getMainAppTypeReference(),
IsStatic=true,
Type=host.PlatformType.SystemString,
Name=host.NameTable.GetNameFor(PhoneCodeHelper.IL_CURRENT_NAVIGATION_URI_VARIABLE),
@@ -69,20 +66,25 @@ namespace BytecodeTranslator.Phone {
private bool navCallFound=false;
+ private bool navCallIsStatic = false;
private StaticURIMode currentStaticMode= StaticURIMode.NOT_STATIC;
private string unpurifiedFoundURI="";
public override void Visit(IBlockStatement block) {
- IList<Tuple<IStatement,StaticURIMode,string>> navStmts = new List<Tuple<IStatement,StaticURIMode,string>>();
+ IList<Tuple<IStatement,StaticURIMode,string>> staticNavStmts = new List<Tuple<IStatement,StaticURIMode,string>>();
+ IList<IStatement> nonStaticNavStmts = new List<IStatement>();
foreach (IStatement statement in block.Statements) {
navCallFound = false;
+ navCallIsStatic = false;
this.Visit(statement);
- if (navCallFound) {
- navStmts.Add(new Tuple<IStatement, StaticURIMode, string>(statement, currentStaticMode, unpurifiedFoundURI));
+ if (navCallFound && navCallIsStatic) {
+ staticNavStmts.Add(new Tuple<IStatement, StaticURIMode, string>(statement, currentStaticMode, unpurifiedFoundURI));
+ } else if (navCallFound) {
+ nonStaticNavStmts.Add(statement);
}
}
- injectNavigationUpdateCode(block, navStmts);
+ injectNavigationUpdateCode(block, staticNavStmts, nonStaticNavStmts);
}
public override void Visit(IMethodCall methodCall) {
@@ -93,9 +95,10 @@ namespace BytecodeTranslator.Phone {
return;
string methodToCallName= methodToCall.Name.Value;
- if (!NAV_CALLS.Contains(methodToCallName))
+ if (!PhoneCodeHelper.NAV_CALLS.Contains(methodToCallName))
return;
+ navCallFound = true;
// TODO check what to do with these
if (methodToCallName == "GoForward" || methodToCallName == "StopLoading") {
// TODO forward navigation is not supported by the phone
@@ -103,19 +106,18 @@ namespace BytecodeTranslator.Phone {
// TODO possibly log
return;
} else {
- bool isStatic=false;
currentStaticMode = StaticURIMode.NOT_STATIC;
- if (methodToCallName == "GoBack")
- isStatic= true;
- else { // Navigate()
+ if (methodToCallName == "GoBack") {
+ navCallIsStatic = false;
+ } else { // Navigate()
// check for different static patterns that we may be able to verify
- IExpression uriArg= methodCall.Arguments.First();
+ IExpression uriArg = methodCall.Arguments.First();
if (isArgumentURILocallyCreatedStatic(uriArg, out unpurifiedFoundURI)) {
- isStatic = true;
+ navCallIsStatic = true;
currentStaticMode = StaticURIMode.STATIC_URI_CREATION_ONSITE;
} else if (isArgumentURILocallyCreatedStaticRoot(uriArg, out unpurifiedFoundURI)) {
- isStatic = true;
+ navCallIsStatic = true;
currentStaticMode = StaticURIMode.STATIC_URI_ROOT_CREATION_ONSITE;
} else {
// get reason
@@ -127,9 +129,6 @@ namespace BytecodeTranslator.Phone {
}
}
- if (isStatic)
- navCallFound = true;
-
//Console.Write("Page navigation event found. Target is static? " + (isStatic ? "YES" : "NO"));
//if (!isStatic) {
// Console.WriteLine(" -- Reason: " + notStaticReason);
@@ -192,12 +191,44 @@ namespace BytecodeTranslator.Phone {
return true;
}
- private void injectNavigationUpdateCode(IBlockStatement block, IEnumerable<Tuple<IStatement,StaticURIMode, string>> stmts) {
+ private void injectNavigationUpdateCode(IBlockStatement block, IEnumerable<Tuple<IStatement,StaticURIMode, string>> staticStmts, IEnumerable<IStatement> nonStaticStmts) {
// TODO Here there is the STRONG assumption that a given method will only navigate at most once per method call
// TODO (or at most will re-navigate to the same page). Quick "page flipping" on the same method
// TODO would not be captured correctly
- foreach (Tuple<IStatement, StaticURIMode, string> entry in stmts) {
- int ndx= block.Statements.ToList().IndexOf(entry.Item1, 0);
+ Microsoft.Cci.MutableCodeModel.BlockStatement mutableBlock = block as Microsoft.Cci.MutableCodeModel.BlockStatement;
+
+ foreach (IStatement stmt in nonStaticStmts) {
+ int ndx = mutableBlock.Statements.ToList().IndexOf(stmt);
+ if (ndx == -1) {
+ // can't be
+ throw new IndexOutOfRangeException("Statement must exist in original block");
+ }
+
+ Assignment currentURIAssign = new Assignment() {
+ Source = new CompileTimeConstant() {
+ Type = host.PlatformType.SystemString,
+ Value = PhoneCodeHelper.BOOGIE_DO_HAVOC_CURRENTURI,
+ },
+ Type = host.PlatformType.SystemString,
+ Target = new TargetExpression() {
+ Type = host.PlatformType.SystemString,
+ Definition = new FieldReference() {
+ ContainingType=PhoneCodeHelper.getMainAppTypeReference(),
+ IsStatic= true,
+ Type = host.PlatformType.SystemString,
+ Name = host.NameTable.GetNameFor(PhoneCodeHelper.IL_CURRENT_NAVIGATION_URI_VARIABLE),
+ },
+ },
+ };
+ Statement uriInitStmt = new ExpressionStatement() {
+ Expression = currentURIAssign,
+ };
+ mutableBlock.Statements.Insert(ndx + 1, uriInitStmt);
+ }
+
+
+ foreach (Tuple<IStatement, StaticURIMode, string> entry in staticStmts) {
+ int ndx= mutableBlock.Statements.ToList().IndexOf(entry.Item1);
if (ndx == -1) {
// can't be
throw new IndexOutOfRangeException("Statement must exist in original block");
@@ -212,8 +243,8 @@ namespace BytecodeTranslator.Phone {
Target = new TargetExpression() {
Type = host.PlatformType.SystemString,
Definition = new FieldReference() {
- ContainingType = typeTraversed,
- IsStatic = true,
+ ContainingType = PhoneCodeHelper.getMainAppTypeReference(),
+ IsStatic= true,
Type = host.PlatformType.SystemString,
Name = host.NameTable.GetNameFor(PhoneCodeHelper.IL_CURRENT_NAVIGATION_URI_VARIABLE),
},
@@ -222,7 +253,7 @@ namespace BytecodeTranslator.Phone {
Statement uriInitStmt = new ExpressionStatement() {
Expression = currentURIAssign,
};
- block.Statements.ToList().Insert(ndx+1, uriInitStmt);
+ mutableBlock.Statements.Insert(ndx+1, uriInitStmt);
}
}
}
@@ -233,12 +264,10 @@ namespace BytecodeTranslator.Phone {
public class PhoneNavigationMetadataTraverser : BaseMetadataTraverser {
private MetadataReaderHost host;
private ITypeDefinition typeBeingTraversed;
- private PhoneControlsPlugin phonePlugin;
- public PhoneNavigationMetadataTraverser(PhoneControlsPlugin plugin, MetadataReaderHost host)
+ public PhoneNavigationMetadataTraverser(MetadataReaderHost host)
: base() {
this.host = host;
- this.phonePlugin = plugin;
}
public override void Visit(IModule module) {
@@ -272,7 +301,7 @@ namespace BytecodeTranslator.Phone {
// TODO same here. Are there specific methods (and ways to identfy those) that can perform navigation?
public override void Visit(IMethodDefinition method) {
- PhoneNavigationCodeTraverser codeTraverser = new PhoneNavigationCodeTraverser(phonePlugin, host, typeBeingTraversed);
+ PhoneNavigationCodeTraverser codeTraverser = new PhoneNavigationCodeTraverser(host, typeBeingTraversed);
codeTraverser.Visit(method);
}
diff --git a/BCT/BytecodeTranslator/Phone/PhoneURIDeclarationsTraverser.cs b/BCT/BytecodeTranslator/Phone/PhoneURIDeclarationsTraverser.cs
deleted file mode 100644
index fa330439..00000000
--- a/BCT/BytecodeTranslator/Phone/PhoneURIDeclarationsTraverser.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace BytecodeTranslator.Phone {
- class PhoneURIDeclarationsTraverser {
- }
-}
diff --git a/BCT/BytecodeTranslator/Program.cs b/BCT/BytecodeTranslator/Program.cs
index 14d0a466..8745ee9e 100644
--- a/BCT/BytecodeTranslator/Program.cs
+++ b/BCT/BytecodeTranslator/Program.cs
@@ -100,7 +100,7 @@ namespace BytecodeTranslator {
} catch (Exception e) { // swallow everything and just return an error code
Console.WriteLine("The byte-code translator failed: {0}", e.Message);
- //Console.WriteLine("Stack trace: {0}", e.StackTrace);
+ // Console.WriteLine("Stack trace: {0}", e.StackTrace);
return -1;
}
return result;
@@ -176,14 +176,6 @@ namespace BytecodeTranslator {
var primaryModule = modules[0];
- if (phoneControlsConfigFile != null && phoneControlsConfigFile != "") {
- PhoneControlsPlugin phonePlugin = new PhoneControlsPlugin(phoneControlsConfigFile);
- PhoneInitializationMetadataTraverser initTr = new PhoneInitializationMetadataTraverser(phonePlugin, host);
- initTr.InjectPhoneCodeAssemblies(modules);
- PhoneNavigationMetadataTraverser navTr = new PhoneNavigationMetadataTraverser(phonePlugin, host);
- navTr.InjectPhoneCodeAssemblies(modules);
- }
-
TraverserFactory traverserFactory;
if (wholeProgram)
traverserFactory = new WholeProgram();
@@ -192,13 +184,34 @@ namespace BytecodeTranslator {
Sink sink= new Sink(host, traverserFactory, heapFactory);
TranslationHelper.tmpVarCounter = 0;
- MetadataTraverser translator = traverserFactory.MakeMetadataTraverser(sink, contractExtractors, pdbReaders);
+ MetadataTraverser translator;
+ translator= traverserFactory.MakeMetadataTraverser(sink, contractExtractors, pdbReaders);
+
+ PhoneControlsPlugin phonePlugin = null;
+ if (phoneControlsConfigFile != null && phoneControlsConfigFile != "") {
+ phonePlugin = new PhoneControlsPlugin(phoneControlsConfigFile);
+ PhoneCodeHelper.PhonePlugin = phonePlugin;
+ PhoneInitializationMetadataTraverser initTr = new PhoneInitializationMetadataTraverser(host);
+ initTr.InjectPhoneCodeAssemblies(modules);
+ PhoneNavigationMetadataTraverser navTr = new PhoneNavigationMetadataTraverser(host);
+ navTr.InjectPhoneCodeAssemblies(modules);
+ }
+
translator.TranslateAssemblies(modules);
foreach (var pair in sink.delegateTypeToDelegates.Values) {
CreateDispatchMethod(sink, pair.Item1, pair.Item2);
}
+ // TODO based on phone plugin information, create the main Boogie program, control drivers and assume/assert scheme
+ if (phonePlugin != null) {
+ string outputConfigFile = Path.ChangeExtension(phoneControlsConfigFile, "bplout");
+ StreamWriter outputStream = new StreamWriter(outputConfigFile);
+ phonePlugin.DumpControlStructure(outputStream);
+ outputStream.Close();
+ PhoneCodeWrapperWriter.createCodeWrapper(sink);
+ }
+
Microsoft.Boogie.TokenTextWriter writer = new Microsoft.Boogie.TokenTextWriter(primaryModule.Name + ".bpl");
Prelude.Emit(writer);
sink.TranslatedProgram.Emit(writer);
diff --git a/BCT/BytecodeTranslator/Sink.cs b/BCT/BytecodeTranslator/Sink.cs
index c14505ee..f1e46ef1 100644
--- a/BCT/BytecodeTranslator/Sink.cs
+++ b/BCT/BytecodeTranslator/Sink.cs
@@ -150,6 +150,24 @@ namespace BytecodeTranslator {
}
/// <summary>
+ /// There are no global variables in code, but it may be useful to have global Boogie vars in the translation
+ ///
+ /// This should be just the same as the encoding for a static field, but I'm being
+ /// IL-unaware here...not sure if this is 100% right
+ /// </summary>
+ private IDictionary<string, Bpl.Variable> globalVariables = new Dictionary<string, Bpl.Variable>();
+ public Bpl.Variable FindOrCreateGlobalVariable(string globalVarName, Bpl.Type type) {
+ Bpl.Variable globalVar;
+ // assuming globalVarName is a valid identifier. Possible name clashing issues too
+ if (!globalVariables.TryGetValue(globalVarName, out globalVar)) {
+ globalVar= new Bpl.GlobalVariable(null, new Bpl.TypedIdent(null, globalVarName, type));
+ }
+
+ return globalVar;
+ }
+
+
+ /// <summary>
/// State that gets re-initialized per method
/// </summary>
private Dictionary<ILocalDefinition, Bpl.LocalVariable> localVarMap = null;
@@ -869,16 +887,23 @@ namespace BytecodeTranslator {
var key = type.InternedKey;
if (!this.declaredTypeConstants.TryGetValue(key, out t)) {
List<ITypeReference> structuralParents;
- var parents = GetParents(type.ResolvedType, out structuralParents);
- t = this.Heap.CreateTypeVariable(type, parents);
+ //var parents = GetParents(type.ResolvedType, out structuralParents);
+ //t = this.Heap.CreateTypeVariable(type, parents);
+ t = this.Heap.CreateTypeVariable(type, null);
this.declaredTypeConstants.Add(key, t);
- foreach (var p in structuralParents) {
- var p_prime = FindOrCreateType(p);
- var e = Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Subtype, Bpl.Expr.Ident(t), p_prime);
- var a = new Bpl.Axiom(Bpl.Token.NoToken, e);
- this.TranslatedProgram.TopLevelDeclarations.Add(a);
- }
+ //foreach (var p in structuralParents) {
+ // var p_prime = FindOrCreateType(p);
+ // //var e = Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Subtype, Bpl.Expr.Ident(t), p_prime);
+ // var e = new Bpl.NAryExpr(
+ // Bpl.Token.NoToken,
+ // new Bpl.FunctionCall(this.Heap.Subtype),
+ // new Bpl.ExprSeq(Bpl.Expr.Ident(t), p_prime)
+ // );
+ // var a = new Bpl.Axiom(Bpl.Token.NoToken, e);
+ // this.TranslatedProgram.TopLevelDeclarations.Add(a);
+ //}
this.TranslatedProgram.TopLevelDeclarations.Add(t);
+ DeclareParents(type.ResolvedType, t);
if (isExtern) {
var attrib = new Bpl.QKeyValue(Bpl.Token.NoToken, "extern", new List<object>(1), null);
t.Attributes = attrib;
@@ -888,6 +913,35 @@ namespace BytecodeTranslator {
}
}
+ private void DeclareSuperType(Bpl.Variable typeDefinitionAsBplConstant, ITypeReference superType) {
+ var superType_prime = FindOrCreateType(superType);
+ var e = new Bpl.NAryExpr(
+ Bpl.Token.NoToken,
+ new Bpl.FunctionCall(this.Heap.Subtype),
+ new Bpl.ExprSeq(Bpl.Expr.Ident(typeDefinitionAsBplConstant), superType_prime)
+ );
+ var a = new Bpl.Axiom(Bpl.Token.NoToken, e);
+ this.TranslatedProgram.TopLevelDeclarations.Add(a);
+ if (!superType.ResolvedType.IsInterface) {
+ var e2 = new Bpl.NAryExpr(
+ Bpl.Token.NoToken,
+ new Bpl.FunctionCall(this.Heap.DisjointSubtree),
+ new Bpl.ExprSeq(Bpl.Expr.Ident(typeDefinitionAsBplConstant), superType_prime)
+ );
+ var a2 = new Bpl.Axiom(Bpl.Token.NoToken, e2);
+ this.TranslatedProgram.TopLevelDeclarations.Add(a2);
+ }
+ }
+ private void DeclareParents(ITypeDefinition typeDefinition, Bpl.Variable typeDefinitionAsBplConstant) {
+ foreach (var p in typeDefinition.BaseClasses) {
+ DeclareSuperType(typeDefinitionAsBplConstant, p);
+ }
+ foreach (var j in typeDefinition.Interfaces) {
+ DeclareSuperType(typeDefinitionAsBplConstant, j);
+ }
+ return;
+ }
+
private List<Bpl.ConstantParent> GetParents(ITypeDefinition typeDefinition, out List<ITypeReference> structuralParents) {
var parents = new List<Bpl.ConstantParent>();
structuralParents = new List<ITypeReference>();
diff --git a/BCT/BytecodeTranslator/StatementTraverser.cs b/BCT/BytecodeTranslator/StatementTraverser.cs
index 89a258ea..7f087a86 100644
--- a/BCT/BytecodeTranslator/StatementTraverser.cs
+++ b/BCT/BytecodeTranslator/StatementTraverser.cs
@@ -16,6 +16,7 @@ using Microsoft.Cci.ILToCodeModel;
using Bpl = Microsoft.Boogie;
using System.Diagnostics.Contracts;
+using TranslationPlugins;
namespace BytecodeTranslator
@@ -171,7 +172,6 @@ namespace BytecodeTranslator
public override void Visit(IConditionalStatement conditionalStatement) {
StatementTraverser thenTraverser = this.factory.MakeStatementTraverser(this.sink, this.PdbReader, this.contractContext);
StatementTraverser elseTraverser = this.factory.MakeStatementTraverser(this.sink, this.PdbReader, this.contractContext);
-
ExpressionTraverser condTraverser = this.factory.MakeExpressionTraverser(this.sink, this, this.contractContext);
condTraverser.Visit(conditionalStatement.Condition);
thenTraverser.Visit(conditionalStatement.TrueBranch);
@@ -469,7 +469,7 @@ namespace BytecodeTranslator
Bpl.IfCmd elseIfCmd = new Bpl.IfCmd(Bpl.Token.NoToken, Bpl.Expr.Literal(false), TranslationHelper.BuildStmtList(new Bpl.ReturnCmd(Bpl.Token.NoToken)), null, null);
Bpl.Expr dynTypeOfOperand = this.sink.Heap.DynamicType(Bpl.Expr.Ident(this.sink.LocalExcVariable));
for (int i = 0; i < catchStatements.Count; i++) {
- Bpl.Expr expr = Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Eq, dynTypeOfOperand, typeReferences[i]);
+ Bpl.Expr expr = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Subtype), new Bpl.ExprSeq(dynTypeOfOperand, typeReferences[i]));
elseIfCmd = new Bpl.IfCmd(Bpl.Token.NoToken, expr, catchStatements[i], elseIfCmd, null);
}
this.StmtBuilder.Add(elseIfCmd);
diff --git a/BCT/BytecodeTranslator/TraverserFactory.cs b/BCT/BytecodeTranslator/TraverserFactory.cs
index 78c818bd..765c7e34 100644
--- a/BCT/BytecodeTranslator/TraverserFactory.cs
+++ b/BCT/BytecodeTranslator/TraverserFactory.cs
@@ -14,10 +14,14 @@ using Microsoft.Cci.MutableCodeModel;
using Microsoft.Cci.Contracts;
using Microsoft.Cci.ILToCodeModel;
+using TranslationPlugins;
+
using Bpl = Microsoft.Boogie;
namespace BytecodeTranslator {
public abstract class TraverserFactory {
+ // TODO this one factory method will have to go away and find the way to get the phone info into the traverser
+ // TODO in some other (better) way
public virtual MetadataTraverser MakeMetadataTraverser(Sink sink,
IDictionary<IUnit, IContractProvider> contractProviders, // TODO: remove this parameter?
IDictionary<IUnit, PdbReader> sourceLocationProviders)
@@ -27,6 +31,7 @@ namespace BytecodeTranslator {
public virtual StatementTraverser MakeStatementTraverser(Sink sink, PdbReader/*?*/ pdbReader, bool contractContext) {
return new StatementTraverser(sink, pdbReader, contractContext);
}
+
public virtual ExpressionTraverser MakeExpressionTraverser(Sink sink, StatementTraverser/*?*/ statementTraverser, bool contractContext) {
return new ExpressionTraverser(sink, statementTraverser, contractContext);
}
diff --git a/BCT/PhoneControlsExtractor/PhoneBoogieCodeGenerator.py b/BCT/PhoneControlsExtractor/PhoneBoogieCodeGenerator.py
new file mode 100644
index 00000000..092acc5b
--- /dev/null
+++ b/BCT/PhoneControlsExtractor/PhoneBoogieCodeGenerator.py
@@ -0,0 +1,218 @@
+import sys
+import getopt
+import os
+from xml.dom import minidom
+import xml.dom
+
+CONTROL_NAMES= ["Button", "CheckBox", "RadioButton"]
+CONTAINER_CONTROL_NAMES= ["Canvas", "Grid", "StackPanel"]
+
+# TODO externalize strings, share with C# code
+CONTINUEONPAGE_VAR= "__BOOGIE_ContinueOnPage__"
+
+staticControlsMap= {}
+mainPageXAML= None
+currentNavigationVariable= None
+originalPageVars= []
+boogiePageVars= []
+boogiePageClasses= []
+
+def showUsage():
+ print "PhoneBoogieCodeGenerator -- create boilerplate code for Boogie verification of Phone apps"
+ print "Usage:"
+ print "\tPhoneBoogieCodeGenerator --controls <app_control_info_file> --output <code_output_file>\n"
+ print "Options:"
+ print "\t--controls <app_control_info_file>: Phone app control info. See PhoneControlsExtractor. Short form: -c"
+ print "\t--output <code_output_file>: file to write with boilerplate code. Short form: -o\n"
+
+def loadControlInfo(infoMap, controlClass, controlName, enabled, visible, clickHandler, checkedHandler, uncheckedHandler, bplName):
+ newControl={}
+ newControl["class"]= controlClass
+ newControl["enabled"]= enabled
+ newControl["visible"]= visible
+ newControl["clickHandler"]= clickHandler
+ newControl["checkedHandler"]= checkedHandler
+ newControl["uncheckedHandler"]= uncheckedHandler
+ newControl["bplName"]=bplName
+ infoMap[controlName]= newControl
+
+def outputPageVariables(file):
+ global originalPageVars
+ global boogiePageVars
+ global boogiePageClasses
+ for entry in staticControlsMap.keys():
+ pageVarName= "__BOOGIE_PAGE_VAR_" + entry
+ originalPageVars.append(entry)
+ pageInfo={}
+ pageInfo["name"]=pageVarName
+ pageInfo["boogieStringName"]= staticControlsMap[entry]["boogieStringName"]
+ boogiePageVars.append(pageInfo)
+ boogiePageClasses.append(staticControlsMap[entry]["class"])
+ pageVar= "var " + pageVarName + ": Ref;\n"
+ file.write(pageVar)
+
+def outputMainProcedure(file):
+ file.write("procedure __BOOGIE_VERIFICATION_PROCEDURE();\n")
+ file.write("implementation __BOOGIE_VERIFICATION_PROCEDURE() {\n")
+ file.write("\tvar $doWork: bool;\n")
+ file.write("\tvar $activeControl: int;\n")
+ file.write("\tvar $isEnabledRef: Ref;\n")
+ file.write("\tvar $isEnabled: bool;\n")
+ file.write("\tvar $control: Ref;\n\n")
+
+ for i in range(0,len(boogiePageVars)):
+ file.write("\tcall " + boogiePageClasses[i] + ".#ctor(" + boogiePageVars[i]["name"] + ");\n")
+
+ file.write("\t//TODO still need to call Loaded handler on main page and the App ctor.\n")
+ file.write("\thavoc $doWork;\n")
+ file.write("\twhile ($doWork) {\n")
+ file.write("\t\tcall DriveControls();\n")
+ file.write("\t\thavoc $doWork;\n")
+ file.write("\t}\n")
+ file.write("}\n")
+
+def outputPageControlDriver(file, originalPageName, boogiePageName):
+ file.write("procedure drive" + boogiePageName + "Controls();\n")
+ file.write("implementation drive" + boogiePageName + "Controls() {\n")
+ file.write("\tvar $activeControl: int;\n")
+ file.write("\tvar $control: Ref;\n")
+ file.write("\tvar $isEnabledRef: Ref;\n")
+ file.write("\tvar $isEnabled: bool;\n")
+ file.write("\tvar $handlerToActivate: int;\n")
+
+ file.write("\t" + CONTINUEONPAGE_VAR +":=true;\n")
+ file.write("\thavoc $activeControl;\n")
+ file.write("\twhile (" + CONTINUEONPAGE_VAR + ") {\n")
+ activeControl=0
+ for entry in staticControlsMap[originalPageName]["controls"].keys():
+ controlInfo= staticControlsMap[originalPageName]["controls"][entry]
+ if activeControl==0:
+ file.write("\t\tif ($activeControl == 0) {\n")
+ else:
+ file.write("\t\telse if ($activeControl == " + str(activeControl) + ") {\n")
+
+ file.write("\t\t\t$control := " + controlInfo["bplName"] + "[" + boogiePageName + "];\n")
+ file.write("\t\t\tcall $isEnabledRef := System.Windows.Controls.Control.get_IsEnabled($control);\n")
+ file.write("\t\t\t$isEnabled := Box2Bool(Ref2Box($isEnabledRef));\n")
+ file.write("\t\t\tif ($isEnabled) {\n")
+ file.write("\t\t\t\thavoc $handlerToActivate;\n")
+ if not controlInfo["clickHandler"] == "":
+ file.write("\t\t\t\tif ($handlerToActivate == 0) {\n")
+ file.write("\t\t\t\t\tcall " + staticControlsMap[originalPageName]["class"] + "." + controlInfo["clickHandler"] + "$System.Object$System.Windows.RoutedEventArgs(" + controlInfo["bplName"] + "[" + boogiePageName + "],null,null);\n")
+ file.write("\t\t\t\t}\n")
+ if not controlInfo["checkedHandler"] == "":
+ file.write("\t\t\t\tif ($handlerToActivate == 1) {\n")
+ file.write("\t\t\t\t\tcall " + staticControlsMap[originalPageName]["class"] + "." + controlInfo["checkedHandler"] + "$System.Object$System.Windows.RoutedEventArgs(" + controlInfo["bplName"] + "[" + boogiePageName + "],null,null);\n")
+ file.write("\t\t\t\t}\n")
+ if not controlInfo["uncheckedHandler"] == "":
+ file.write("\t\t\t\tif ($handlerToActivate == 2) {\n")
+ file.write("\t\t\t\t\tcall " + staticControlsMap[originalPageName]["class"] + "." + controlInfo["uncheckedHandler"] + "$System.Object$System.Windows.RoutedEventArgs(" + controlInfo["bplName"] + "[" + boogiePageName + "],null,null);\n")
+ file.write("\t\t\t\t}\n")
+
+ file.write("\t\t\t}\n")
+ file.write("\t\t}\n")
+ activeControl= activeControl+1
+ file.write("\t}\n")
+ file.write("}\n")
+
+
+def outputControlDrivers(file):
+ for i in range(0,len(boogiePageVars)):
+ outputPageControlDriver(file, originalPageVars[i],boogiePageVars[i]["name"])
+
+ file.write("procedure DriveControls();\n")
+ file.write("implementation DriveControls() {\n")
+ for i in range(0,len(boogiePageVars)):
+ file.write("\tvar isCurrent" + boogiePageVars[i]["name"] + ": bool;\n")
+ file.write("\n")
+
+ for i in range(0,len(boogiePageVars)):
+ file.write("\tcall isCurrent" + boogiePageVars[i]["name"] + " := System.String.op_Equality$System.String$System.String(" + currentNavigationVariable + "," + boogiePageVars[i]["boogieStringName"] + ");\n")
+
+ firstTime= True
+ for i in range(0,len(boogiePageVars)):
+ if firstTime:
+ file.write("\tif")
+ firstTime= False
+ else:
+ file.write("\telse if")
+
+ file.write(" (isCurrent" + boogiePageVars[i]["name"] + ") {\n")
+ file.write("\t\t call drive" + boogiePageVars[i]["name"] + "Controls();\n\t}\n")
+ file.write("}\n")
+
+def outputURIHavocProcedure(file):
+ file.write("procedure __BOOGIE_Havoc_CurrentURI__();\n")
+ file.write("implementation __BOOGIE_Havoc_CurrentURI__() {\n")
+ file.write("\thavoc " + currentNavigationVariable + ";\n")
+ file.write("// TODO write assume statements to filter havoc'd variable to either of all pages\n")
+ # file.write("\tassume )
+ file.write("}\n")
+
+def outputBoilerplate(outputFile):
+ file= open(outputFile,"w")
+ outputPageVariables(file)
+ outputURIHavocProcedure(file)
+ outputControlDrivers(file)
+ outputMainProcedure(file)
+ file.close()
+
+def buildControlInfo(controlInfoFileName):
+ global mainPageXAML
+ global currentNavigationVariable
+ global staticControlsMap
+
+ file = open(controlInfoFileName, "r")
+ # Info file format is first line containing only the main page, another line with boogie's current navigation variable and then one line per
+ # <pageClassName>,<page.xaml file>,<xaml boogie string representation>,<controlClassName>,<controlName (as in field name)>,<IsEnabledValue>,<VisibilityValue>,<ClickValue>,<CheckedValue>,<UncheckedValue>,<BoogieName>
+ mainPageXAML= file.readline().strip()
+ currentNavigationVariable= file.readline().strip()
+ infoLine= file.readline().strip()
+ while not infoLine == "":
+ pageClass, pageName, pageBoogieStringName, controlClass, controlName, enabled, visible, clickHandler, checkedHandler, uncheckedHandler, bplName= infoLine.split(",")
+ pageInfo={}
+ pageInfo["class"]=pageClass
+ try:
+ pageInfo= staticControlsMap[pageName]
+ except KeyError:
+ staticControlsMap[pageName]=pageInfo
+
+ pageInfo["boogieStringName"]= pageBoogieStringName
+ pageControlInfo={}
+ try:
+ pageControlInfo= pageInfo["controls"]
+ except KeyError:
+ pageInfo["controls"]=pageControlInfo
+ loadControlInfo(pageControlInfo, controlClass, controlName, enabled, visible, clickHandler, checkedHandler, uncheckedHandler, bplName)
+ pageInfo["controls"]= pageControlInfo
+ staticControlsMap[pageName]=pageInfo
+
+ infoLine=file.readline().strip()
+ file.close()
+
+def main():
+ controlFile= ""
+ outputFile= ""
+ try:
+ opts, args= getopt.getopt(sys.argv[1:], "c:o:", ["controls=","output="])
+ except geopt.error, msg:
+ print msg
+ showUsage()
+ sys.exit(2)
+
+ if not len(opts) == 2:
+ print "Missing options"
+ showUsage()
+ sys.exit(2)
+
+ for o, a in opts:
+ if o in ["-c","--controls"]:
+ controlFile= a
+ if o in ["-o", "--output"]:
+ outputFile= a
+
+ buildControlInfo(controlFile)
+ outputBoilerplate(outputFile)
+
+if __name__ == "__main__":
+ main() \ No newline at end of file
diff --git a/BCT/PhoneControlsExtractor/PhoneControlsExtractor.py b/BCT/PhoneControlsExtractor/PhoneControlsExtractor.py
index 89cc0c31..4fe4e18f 100644
--- a/BCT/PhoneControlsExtractor/PhoneControlsExtractor.py
+++ b/BCT/PhoneControlsExtractor/PhoneControlsExtractor.py
@@ -103,9 +103,10 @@ def extractPhoneControlsFromPage(pageXAML):
def outputPhoneControls(outputFileName):
outputFile= open(outputFileName, "w")
- # Output format is first line containing only the main page, and then one line per
- # <pageClassName>,<page.xaml file>,<controlClassName>,<controlName (as in field name)>,<IsEnabledValue>,<VisibilityValue>,<ClickValue>,<CheckedValue>,<UncheckedValue>
+ # Output format is first line containing only the main page, then line containing boogie navigation variable, and then one line per
+ # <pageClassName>,<page.xaml file>,<boogie string page name>,<controlClassName>,<controlName (as in field name)>,<IsEnabledValue>,<VisibilityValue>,<ClickValue>,<CheckedValue>,<UncheckedValue>
outputFile.write(mainPageXAML + "\n")
+ outputFile.write("dummyNavigationVariable_unknown\n")
for page in staticControlsMap.keys():
for control in staticControlsMap[page]:
isEnabled= control["IsEnabled"]
@@ -114,7 +115,9 @@ def outputPhoneControls(outputFileName):
checked= control["Checked"]
unchecked= control["Unchecked"]
pageXAML= control["XAML"]
- outputFile.write(page + "," + os.path.basename(pageXAML) + "," + control["Type"] + "," + control["Name"] + "," + isEnabled + "," + visibility + "," + click + "," + checked + "," + unchecked + "\n")
+ # last comma is to account for bpl translation name, that is unknown for now
+ # boogie string page name is unknown for now
+ outputFile.write(page + "," + os.path.basename(pageXAML) + ",dummyBoogieStringPageName," + control["Type"] + "," + control["Name"] + "," + isEnabled + "," + visibility + "," + click + "," + checked + "," + unchecked + ",\n")
outputFile.close()
diff --git a/BCT/RegressionTests/TranslationTest/GeneralHeapInput.txt b/BCT/RegressionTests/TranslationTest/GeneralHeapInput.txt
index 32242dcd..e4fd8eae 100644
--- a/BCT/RegressionTests/TranslationTest/GeneralHeapInput.txt
+++ b/BCT/RegressionTests/TranslationTest/GeneralHeapInput.txt
@@ -18,6 +18,18 @@ implementation Alloc() returns (x: Ref)
+axiom (forall t: Type :: $Subtype(t, t));
+
+axiom (forall t0: Type, t1: Type :: { $Subtype(t0, t1), $Subtype(t1, t0) } $Subtype(t0, t1) && $Subtype(t1, t0) ==> t0 == t1);
+
+axiom (forall t0: Type, t1: Type, t2: Type :: { $Subtype(t0, t1), $Subtype(t1, t2) } $Subtype(t0, t1) && $Subtype(t1, t2) ==> $Subtype(t0, t2));
+
+axiom (forall C: Type, D: Type :: { $DirectSubtype(D, C) } $DirectSubtype(D, C) <==> $Subtype(D, C) && (forall z: Type :: $Subtype(D, z) && $Subtype(z, C) ==> z == C || z == D));
+
+function oneDown(t0: Type, t1: Type) : Type;
+
+axiom (forall C: Type, D: Type :: { $DisjointSubtree(D, C) } $DisjointSubtree(D, C) <==> (forall z: Type :: $Subtype(z, D) ==> oneDown(C, z) == D));
+
function $TypeOfInv(Ref) : Type;
axiom (forall t: Type :: { $TypeOf(t) } $TypeOfInv($TypeOf(t)) == t);
@@ -280,6 +292,85 @@ implementation DelegateRemoveHelper(oldi: Ref, m: int, o: Ref) returns (i: Ref)
+procedure System.String.op_Equality$System.String$System.String(a$in: Ref, b$in: Ref) returns ($result: bool);
+
+
+
+procedure System.String.op_Inequality$System.String$System.String(a$in: Ref, b$in: Ref) returns ($result: bool);
+
+
+
+implementation System.String.op_Equality$System.String$System.String(a$in: Ref, b$in: Ref) returns ($result: bool)
+{
+ $result := a$in == b$in;
+}
+
+
+
+implementation System.String.op_Inequality$System.String$System.String(a$in: Ref, b$in: Ref) returns ($result: bool)
+{
+ $result := a$in != b$in;
+}
+
+
+
+function isControlEnabled(Ref) : bool;
+
+function isControlChecked(Ref) : bool;
+
+procedure System.Windows.Controls.Control.set_IsEnabled$System.Boolean($this: Ref, value$in: bool);
+
+
+
+implementation System.Windows.Controls.Control.set_IsEnabled$System.Boolean($this: Ref, value$in: bool)
+{
+ assume isControlEnabled($this) == value$in;
+}
+
+
+
+procedure System.Windows.Controls.Control.get_IsEnabled($this: Ref) returns ($result: Ref);
+
+
+
+implementation System.Windows.Controls.Control.get_IsEnabled($this: Ref) returns ($result: Ref)
+{
+ var enabledness: bool;
+
+ enabledness := isControlEnabled($this);
+ $result := Box2Ref(Bool2Box(enabledness));
+}
+
+
+
+procedure System.Windows.Controls.Primitives.ToggleButton.set_IsChecked$System.Nullable$System.Boolean$($this: Ref, value$in: Ref);
+
+
+
+implementation System.Windows.Controls.Primitives.ToggleButton.set_IsChecked$System.Nullable$System.Boolean$($this: Ref, value$in: Ref)
+{
+ var check: bool;
+
+ check := Box2Bool(Ref2Box(value$in));
+ assume isControlChecked($this) == check;
+}
+
+
+
+procedure System.Windows.Controls.Primitives.ToggleButton.get_IsChecked($this: Ref) returns ($result: Ref);
+
+
+
+implementation System.Windows.Controls.Primitives.ToggleButton.get_IsChecked($this: Ref) returns ($result: Ref)
+{
+ var isChecked: bool;
+
+ isChecked := isControlChecked($this);
+ $result := Box2Ref(Bool2Box(isChecked));
+}
+
+
+
const unique $BoxField: Field;
var $Heap: HeapType;
@@ -369,6 +460,12 @@ function $TypeOf(Type) : Ref;
function $As(Ref, Type) : Ref;
+function $Subtype(Type, Type) : bool;
+
+function $DirectSubtype(Type, Type) : bool;
+
+function $DisjointSubtree(Type, Type) : bool;
+
var $Head: [Ref]Ref;
var $Next: [Ref][Ref]Ref;
@@ -379,9 +476,13 @@ var $Receiver: [Ref][Ref]Ref;
var {:thread_local} $Exception: Ref;
-const {:extern} unique System.Object: Type extends;
+const unique RegressionTestInput.RealNumbers: Type;
+
+const {:extern} unique System.Object: Type;
+
+axiom $Subtype(RegressionTestInput.RealNumbers, System.Object);
-const unique RegressionTestInput.RealNumbers: Type extends unique System.Object;
+axiom $DisjointSubtree(RegressionTestInput.RealNumbers, System.Object);
procedure RegressionTestInput.RealNumbers.WriteDouble$System.Double($this: Ref, d$in: Real);
@@ -522,7 +623,11 @@ implementation RegressionTestInput.RealNumbers.#cctor()
-const unique RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap: Type extends unique System.Object;
+const unique RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap: Type;
+
+axiom $Subtype(RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap, System.Object);
+
+axiom $DisjointSubtree(RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap, System.Object);
const unique RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.x: Field;
@@ -577,7 +682,11 @@ implementation RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.#cctor()
-const unique RegressionTestInput.CreateStruct: Type extends unique System.Object;
+const unique RegressionTestInput.CreateStruct: Type;
+
+axiom $Subtype(RegressionTestInput.CreateStruct, System.Object);
+
+axiom $DisjointSubtree(RegressionTestInput.CreateStruct, System.Object);
procedure RegressionTestInput.CreateStruct.Create($this: Ref) returns ($result: Ref);
@@ -587,9 +696,17 @@ procedure RegressionTestInput.S.#default_ctor(this: Ref);
-const {:extern} unique System.ValueType: Type extends unique System.Object;
+const unique RegressionTestInput.S: Type;
+
+const {:extern} unique System.ValueType: Type;
+
+axiom $Subtype(System.ValueType, System.Object);
+
+axiom $DisjointSubtree(System.ValueType, System.Object);
+
+axiom $Subtype(RegressionTestInput.S, System.ValueType);
-const unique RegressionTestInput.S: Type extends unique System.ValueType;
+axiom $DisjointSubtree(RegressionTestInput.S, System.ValueType);
const unique RegressionTestInput.S.x: Field;
@@ -670,7 +787,11 @@ implementation RegressionTestInput.CreateStruct.#cctor()
-const unique RegressionTestInput.ClassWithArrayTypes: Type extends unique System.Object;
+const unique RegressionTestInput.ClassWithArrayTypes: Type;
+
+axiom $Subtype(RegressionTestInput.ClassWithArrayTypes, System.Object);
+
+axiom $DisjointSubtree(RegressionTestInput.ClassWithArrayTypes, System.Object);
var RegressionTestInput.ClassWithArrayTypes.s: Ref;
@@ -841,7 +962,11 @@ implementation RegressionTestInput.ClassWithArrayTypes.#cctor()
-const unique RegressionTestInput.BitwiseOperations: Type extends unique System.Object;
+const unique RegressionTestInput.BitwiseOperations: Type;
+
+axiom $Subtype(RegressionTestInput.BitwiseOperations, System.Object);
+
+axiom $DisjointSubtree(RegressionTestInput.BitwiseOperations, System.Object);
procedure RegressionTestInput.BitwiseOperations.BitwiseAnd$System.Int32$System.Int32($this: Ref, x$in: int, y$in: int) returns ($result: int);
@@ -951,11 +1076,21 @@ implementation RegressionTestInput.BitwiseOperations.#cctor()
-const {:extern} unique System.Runtime.InteropServices._Attribute: Type extends;
+const unique RegressionTestInput.AsyncAttribute: Type;
+
+const {:extern} unique System.Attribute: Type;
-const {:extern} unique System.Attribute: Type extends unique System.Object, System.Runtime.InteropServices._Attribute;
+axiom $Subtype(System.Attribute, System.Object);
-const unique RegressionTestInput.AsyncAttribute: Type extends unique System.Attribute;
+axiom $DisjointSubtree(System.Attribute, System.Object);
+
+const {:extern} unique System.Runtime.InteropServices._Attribute: Type;
+
+axiom $Subtype(System.Attribute, System.Runtime.InteropServices._Attribute);
+
+axiom $Subtype(RegressionTestInput.AsyncAttribute, System.Attribute);
+
+axiom $DisjointSubtree(RegressionTestInput.AsyncAttribute, System.Attribute);
procedure RegressionTestInput.AsyncAttribute.#ctor($this: Ref);
@@ -991,7 +1126,11 @@ implementation RegressionTestInput.AsyncAttribute.#cctor()
-const unique RegressionTestInput.RefParameters: Type extends unique System.Object;
+const unique RegressionTestInput.RefParameters: Type;
+
+axiom $Subtype(RegressionTestInput.RefParameters, System.Object);
+
+axiom $DisjointSubtree(RegressionTestInput.RefParameters, System.Object);
procedure RegressionTestInput.RefParameters.M$System.Int32$(x$in: int) returns (x$out: int);
@@ -1061,7 +1200,11 @@ implementation {:inline 1} RegressionTestInput.S.#copy_ctor(this: Ref, other: Re
-const unique RegressionTestInput.Class0: Type extends unique System.Object;
+const unique RegressionTestInput.Class0: Type;
+
+axiom $Subtype(RegressionTestInput.Class0, System.Object);
+
+axiom $DisjointSubtree(RegressionTestInput.Class0, System.Object);
var RegressionTestInput.Class0.StaticInt: int;
@@ -1330,7 +1473,11 @@ implementation RegressionTestInput.Class0.#cctor()
-const unique RegressionTestInput.ClassWithBoolTypes: Type extends unique System.Object;
+const unique RegressionTestInput.ClassWithBoolTypes: Type;
+
+axiom $Subtype(RegressionTestInput.ClassWithBoolTypes, System.Object);
+
+axiom $DisjointSubtree(RegressionTestInput.ClassWithBoolTypes, System.Object);
var RegressionTestInput.ClassWithBoolTypes.staticB: bool;
diff --git a/BCT/RegressionTests/TranslationTest/SplitFieldsHeapInput.txt b/BCT/RegressionTests/TranslationTest/SplitFieldsHeapInput.txt
index 19d98a28..8d329f79 100644
--- a/BCT/RegressionTests/TranslationTest/SplitFieldsHeapInput.txt
+++ b/BCT/RegressionTests/TranslationTest/SplitFieldsHeapInput.txt
@@ -16,6 +16,18 @@ implementation Alloc() returns (x: Ref)
+axiom (forall t: Type :: $Subtype(t, t));
+
+axiom (forall t0: Type, t1: Type :: { $Subtype(t0, t1), $Subtype(t1, t0) } $Subtype(t0, t1) && $Subtype(t1, t0) ==> t0 == t1);
+
+axiom (forall t0: Type, t1: Type, t2: Type :: { $Subtype(t0, t1), $Subtype(t1, t2) } $Subtype(t0, t1) && $Subtype(t1, t2) ==> $Subtype(t0, t2));
+
+axiom (forall C: Type, D: Type :: { $DirectSubtype(D, C) } $DirectSubtype(D, C) <==> $Subtype(D, C) && (forall z: Type :: $Subtype(D, z) && $Subtype(z, C) ==> z == C || z == D));
+
+function oneDown(t0: Type, t1: Type) : Type;
+
+axiom (forall C: Type, D: Type :: { $DisjointSubtree(D, C) } $DisjointSubtree(D, C) <==> (forall z: Type :: $Subtype(z, D) ==> oneDown(C, z) == D));
+
function $TypeOfInv(Ref) : Type;
axiom (forall t: Type :: { $TypeOf(t) } $TypeOfInv($TypeOf(t)) == t);
@@ -278,6 +290,85 @@ implementation DelegateRemoveHelper(oldi: Ref, m: int, o: Ref) returns (i: Ref)
+procedure System.String.op_Equality$System.String$System.String(a$in: Ref, b$in: Ref) returns ($result: bool);
+
+
+
+procedure System.String.op_Inequality$System.String$System.String(a$in: Ref, b$in: Ref) returns ($result: bool);
+
+
+
+implementation System.String.op_Equality$System.String$System.String(a$in: Ref, b$in: Ref) returns ($result: bool)
+{
+ $result := a$in == b$in;
+}
+
+
+
+implementation System.String.op_Inequality$System.String$System.String(a$in: Ref, b$in: Ref) returns ($result: bool)
+{
+ $result := a$in != b$in;
+}
+
+
+
+function isControlEnabled(Ref) : bool;
+
+function isControlChecked(Ref) : bool;
+
+procedure System.Windows.Controls.Control.set_IsEnabled$System.Boolean($this: Ref, value$in: bool);
+
+
+
+implementation System.Windows.Controls.Control.set_IsEnabled$System.Boolean($this: Ref, value$in: bool)
+{
+ assume isControlEnabled($this) == value$in;
+}
+
+
+
+procedure System.Windows.Controls.Control.get_IsEnabled($this: Ref) returns ($result: Ref);
+
+
+
+implementation System.Windows.Controls.Control.get_IsEnabled($this: Ref) returns ($result: Ref)
+{
+ var enabledness: bool;
+
+ enabledness := isControlEnabled($this);
+ $result := Box2Ref(Bool2Box(enabledness));
+}
+
+
+
+procedure System.Windows.Controls.Primitives.ToggleButton.set_IsChecked$System.Nullable$System.Boolean$($this: Ref, value$in: Ref);
+
+
+
+implementation System.Windows.Controls.Primitives.ToggleButton.set_IsChecked$System.Nullable$System.Boolean$($this: Ref, value$in: Ref)
+{
+ var check: bool;
+
+ check := Box2Bool(Ref2Box(value$in));
+ assume isControlChecked($this) == check;
+}
+
+
+
+procedure System.Windows.Controls.Primitives.ToggleButton.get_IsChecked($this: Ref) returns ($result: Ref);
+
+
+
+implementation System.Windows.Controls.Primitives.ToggleButton.get_IsChecked($this: Ref) returns ($result: Ref)
+{
+ var isChecked: bool;
+
+ isChecked := isControlChecked($this);
+ $result := Box2Ref(Bool2Box(isChecked));
+}
+
+
+
var $BoxField: [Ref]Box;
var $ArrayContents: [Ref][int]Box;
@@ -355,6 +446,12 @@ function $TypeOf(Type) : Ref;
function $As(Ref, Type) : Ref;
+function $Subtype(Type, Type) : bool;
+
+function $DirectSubtype(Type, Type) : bool;
+
+function $DisjointSubtree(Type, Type) : bool;
+
var $Head: [Ref]Ref;
var $Next: [Ref][Ref]Ref;
@@ -365,9 +462,13 @@ var $Receiver: [Ref][Ref]Ref;
var {:thread_local} $Exception: Ref;
-const {:extern} unique System.Object: Type extends;
+const unique RegressionTestInput.RealNumbers: Type;
+
+const {:extern} unique System.Object: Type;
+
+axiom $Subtype(RegressionTestInput.RealNumbers, System.Object);
-const unique RegressionTestInput.RealNumbers: Type extends unique System.Object;
+axiom $DisjointSubtree(RegressionTestInput.RealNumbers, System.Object);
procedure RegressionTestInput.RealNumbers.WriteDouble$System.Double($this: Ref, d$in: Real);
@@ -508,7 +609,11 @@ implementation RegressionTestInput.RealNumbers.#cctor()
-const unique RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap: Type extends unique System.Object;
+const unique RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap: Type;
+
+axiom $Subtype(RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap, System.Object);
+
+axiom $DisjointSubtree(RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap, System.Object);
var RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.x: [Ref]int;
@@ -563,7 +668,11 @@ implementation RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.#cctor()
-const unique RegressionTestInput.CreateStruct: Type extends unique System.Object;
+const unique RegressionTestInput.CreateStruct: Type;
+
+axiom $Subtype(RegressionTestInput.CreateStruct, System.Object);
+
+axiom $DisjointSubtree(RegressionTestInput.CreateStruct, System.Object);
procedure RegressionTestInput.CreateStruct.Create($this: Ref) returns ($result: Ref);
@@ -573,9 +682,17 @@ procedure RegressionTestInput.S.#default_ctor(this: Ref);
-const {:extern} unique System.ValueType: Type extends unique System.Object;
+const unique RegressionTestInput.S: Type;
+
+const {:extern} unique System.ValueType: Type;
+
+axiom $Subtype(System.ValueType, System.Object);
+
+axiom $DisjointSubtree(System.ValueType, System.Object);
+
+axiom $Subtype(RegressionTestInput.S, System.ValueType);
-const unique RegressionTestInput.S: Type extends unique System.ValueType;
+axiom $DisjointSubtree(RegressionTestInput.S, System.ValueType);
var RegressionTestInput.S.x: [Ref]int;
@@ -656,7 +773,11 @@ implementation RegressionTestInput.CreateStruct.#cctor()
-const unique RegressionTestInput.ClassWithArrayTypes: Type extends unique System.Object;
+const unique RegressionTestInput.ClassWithArrayTypes: Type;
+
+axiom $Subtype(RegressionTestInput.ClassWithArrayTypes, System.Object);
+
+axiom $DisjointSubtree(RegressionTestInput.ClassWithArrayTypes, System.Object);
var RegressionTestInput.ClassWithArrayTypes.s: Ref;
@@ -827,7 +948,11 @@ implementation RegressionTestInput.ClassWithArrayTypes.#cctor()
-const unique RegressionTestInput.BitwiseOperations: Type extends unique System.Object;
+const unique RegressionTestInput.BitwiseOperations: Type;
+
+axiom $Subtype(RegressionTestInput.BitwiseOperations, System.Object);
+
+axiom $DisjointSubtree(RegressionTestInput.BitwiseOperations, System.Object);
procedure RegressionTestInput.BitwiseOperations.BitwiseAnd$System.Int32$System.Int32($this: Ref, x$in: int, y$in: int) returns ($result: int);
@@ -937,11 +1062,21 @@ implementation RegressionTestInput.BitwiseOperations.#cctor()
-const {:extern} unique System.Runtime.InteropServices._Attribute: Type extends;
+const unique RegressionTestInput.AsyncAttribute: Type;
+
+const {:extern} unique System.Attribute: Type;
-const {:extern} unique System.Attribute: Type extends unique System.Object, System.Runtime.InteropServices._Attribute;
+axiom $Subtype(System.Attribute, System.Object);
-const unique RegressionTestInput.AsyncAttribute: Type extends unique System.Attribute;
+axiom $DisjointSubtree(System.Attribute, System.Object);
+
+const {:extern} unique System.Runtime.InteropServices._Attribute: Type;
+
+axiom $Subtype(System.Attribute, System.Runtime.InteropServices._Attribute);
+
+axiom $Subtype(RegressionTestInput.AsyncAttribute, System.Attribute);
+
+axiom $DisjointSubtree(RegressionTestInput.AsyncAttribute, System.Attribute);
procedure RegressionTestInput.AsyncAttribute.#ctor($this: Ref);
@@ -977,7 +1112,11 @@ implementation RegressionTestInput.AsyncAttribute.#cctor()
-const unique RegressionTestInput.RefParameters: Type extends unique System.Object;
+const unique RegressionTestInput.RefParameters: Type;
+
+axiom $Subtype(RegressionTestInput.RefParameters, System.Object);
+
+axiom $DisjointSubtree(RegressionTestInput.RefParameters, System.Object);
procedure RegressionTestInput.RefParameters.M$System.Int32$(x$in: int) returns (x$out: int);
@@ -1047,7 +1186,11 @@ implementation {:inline 1} RegressionTestInput.S.#copy_ctor(this: Ref, other: Re
-const unique RegressionTestInput.Class0: Type extends unique System.Object;
+const unique RegressionTestInput.Class0: Type;
+
+axiom $Subtype(RegressionTestInput.Class0, System.Object);
+
+axiom $DisjointSubtree(RegressionTestInput.Class0, System.Object);
var RegressionTestInput.Class0.StaticInt: int;
@@ -1316,7 +1459,11 @@ implementation RegressionTestInput.Class0.#cctor()
-const unique RegressionTestInput.ClassWithBoolTypes: Type extends unique System.Object;
+const unique RegressionTestInput.ClassWithBoolTypes: Type;
+
+axiom $Subtype(RegressionTestInput.ClassWithBoolTypes, System.Object);
+
+axiom $DisjointSubtree(RegressionTestInput.ClassWithBoolTypes, System.Object);
var RegressionTestInput.ClassWithBoolTypes.staticB: bool;
diff --git a/BCT/TranslationPlugins/PhoneControlsPlugin.cs b/BCT/TranslationPlugins/PhoneControlsPlugin.cs
index 8c7294ec..3d5b81c3 100644
--- a/BCT/TranslationPlugins/PhoneControlsPlugin.cs
+++ b/BCT/TranslationPlugins/PhoneControlsPlugin.cs
@@ -27,10 +27,12 @@ namespace TranslationPlugins {
}
public class ControlInfoStructure {
- public string Name;
- public string ClassName;
- public bool IsEnabled;
- public Visibility Visible;
+ public string Name { get; set; }
+ public string ClassName { get; set; }
+ public bool IsEnabled { get; set; }
+ public Visibility Visible { get; set; }
+ public string BplName { get; set; }
+
private IDictionary<Event, IList<HandlerSignature>> handlers;
public ControlInfoStructure() {
@@ -43,6 +45,7 @@ namespace TranslationPlugins {
eventHandlers = handlers[p];
} catch (KeyNotFoundException) {
eventHandlers= new List<HandlerSignature>();
+ handlers[p] = eventHandlers;
}
HandlerSignature newHandler= new HandlerSignature();
@@ -65,6 +68,7 @@ namespace TranslationPlugins {
controlsInfo = new Dictionary<string, ControlInfoStructure>();
}
+ public string PageBoogieName { get; set; }
public string PageClassName { get; set; }
public string PageXAML { get; set; }
public bool IsMainPage { get; set; }
@@ -90,16 +94,18 @@ namespace TranslationPlugins {
public class PhoneControlsPlugin : TranslationPlugin {
// TODO this will probably need a complete rewrite once it is event based, and make it more push than pull
// TODO but it doesn't make sense right now to make it BCT or CCI aware
- private static int CONFIG_LINE_FIELDS= 9;
+ private static int CONFIG_LINE_FIELDS= 11;
private static int PAGE_CLASS_FIELD= 0;
private static int PAGE_XAML_FIELD= 1;
- private static int CONTROL_CLASS_FIELD= 2;
- private static int CONTROL_NAME_FIELD= 3;
- private static int ENABLED_FIELD= 4;
- private static int VISIBILITY_FIELD= 5;
- private static int CLICK_HANDLER_FIELD= 6;
- private static int CHECKED_HANDLER_FIELD= 7;
- private static int UNCHECKED_HANDLER_FIELD = 8;
+ private static int PAGE_BOOGIE_STRING_FIELD = 2;
+ private static int CONTROL_CLASS_FIELD= 3;
+ private static int CONTROL_NAME_FIELD= 4;
+ private static int ENABLED_FIELD= 5;
+ private static int VISIBILITY_FIELD= 6;
+ private static int CLICK_HANDLER_FIELD= 7;
+ private static int CHECKED_HANDLER_FIELD= 8;
+ private static int UNCHECKED_HANDLER_FIELD = 9;
+ private static int BPL_NAME_FIELD = 10;
private IDictionary<string, PageStructure> pageStructureInfo;
@@ -134,6 +140,15 @@ namespace TranslationPlugins {
return entry.Value.PageXAML;
}
+ private string boogieCurrentNavigationVariable;
+ public string getBoogieNavigationVariable() {
+ return boogieCurrentNavigationVariable;
+ }
+
+ public void setBoogieNavigationVariable(string var) {
+ boogieCurrentNavigationVariable = var;
+ }
+
private void setPageAsMainPage(string pageXAML) {
KeyValuePair<string,PageStructure> mainPageClass= pageStructureInfo.FirstOrDefault(keyValue => keyValue.Value.PageXAML == pageXAML);
if (mainPageClass.Equals(default(KeyValuePair<string, PageStructure>))) {
@@ -143,27 +158,87 @@ namespace TranslationPlugins {
}
}
+ public void DumpControlStructure(StreamWriter outputStream) {
+ // maintain same format as input format
+ string pageClass, pageXAML, pageBoogieStringName, controlClass, controlName, enabled, visibility, clickHandler, checkedHandler, uncheckedHandler, bplName;
+ outputStream.WriteLine(getMainPageXAML());
+ outputStream.WriteLine(getBoogieNavigationVariable());
+ foreach (KeyValuePair<string, PageStructure> entry in this.pageStructureInfo) {
+ pageClass = entry.Key;
+ pageXAML = entry.Value.PageXAML;
+ pageBoogieStringName = entry.Value.PageBoogieName;
+ foreach (ControlInfoStructure controlInfo in entry.Value.getAllControlsInfo()) {
+ controlClass= controlInfo.ClassName;
+ controlName = controlInfo.Name;
+ enabled= controlInfo.IsEnabled ? "true" : "false";
+ switch (controlInfo.Visible) {
+ case Visibility.Collapsed:
+ visibility = "Collapsed";
+ break;
+ default:
+ visibility = "Visible";
+ break;
+ }
+ IEnumerable<HandlerSignature> handlers= controlInfo.getHandlers(Event.Click);
+ if (handlers.Any()) {
+ clickHandler = handlers.First().Name;
+ } else {
+ clickHandler = "";
+ }
+
+ handlers = controlInfo.getHandlers(Event.Checked);
+ if (handlers.Any()) {
+ checkedHandler = handlers.First().Name;
+ } else {
+ checkedHandler = "";
+ }
+
+ handlers = controlInfo.getHandlers(Event.Unchecked);
+ if (handlers.Any()) {
+ uncheckedHandler = handlers.First().Name;
+ } else {
+ uncheckedHandler = "";
+ }
+ bplName = controlInfo.BplName;
+ outputStream.WriteLine(pageClass + "," + pageXAML + "," + pageBoogieStringName + "," + controlClass + "," + controlName + "," + enabled + "," + visibility + "," + clickHandler + "," + checkedHandler + "," + uncheckedHandler + "," + bplName);
+ }
+ }
+ }
+
+ public void setBoogieStringPageNameForPageClass(string pageClass, string boogieStringPageName) {
+ pageStructureInfo[pageClass].PageBoogieName = boogieStringPageName;
+ }
+
private void LoadControlStructure(StreamReader configStream) {
// TODO it would be nice to have some kind of dynamic definition of config format
// TODO for now remember that config format is CSV
- // TODO each line is <pageClassName>,<pageXAMLPath>,<controlClassName>,<controlName>,<IsEnabledValue>,<VisibilityValue>,<ClickValue>,<CheckedValue>,<UncheckedValue>
+ // TODO each line is <pageClassName>,<pageXAMLPath>,<pageBoogieStringName>,<controlClassName>,<controlName>,<IsEnabledValue>,<VisibilityValue>,<ClickValue>,<CheckedValue>,<UncheckedValue>,<BPL control name>
+ // TODO BPL control name will most probably be empty, but it is useful to be able to dump it
// TODO check PhoneControlsExtractor.py
// TODO the page.xaml value is saved with no directory information: if two pages exist with same name but different directories it will treat them as the same
// TODO I'm not handling this for now, and I won't be handling relative/absolute URI either for now
try {
- string pageClass, pageXAML, controlClass, controlName, enabled, visibility, clickHandler, checkedHandler, uncheckedHandler;
+ string pageClass, pageXAML, pageBoogieStringName, controlClass, controlName, enabled, visibility, clickHandler, checkedHandler, uncheckedHandler, bplName;
string configLine = configStream.ReadLine();
string[] inputLine;
PageStructure pageStr;
ControlInfoStructure controlInfoStr;
// first line just states the main page xaml
- string mainPage = configLine.Trim();
+ string mainPageXAML= configLine.Trim();
configLine = configStream.ReadLine();
+ // second line states boogie current nav variable, possibly dummy value
+ setBoogieNavigationVariable(configLine.Trim());
+ configLine= configStream.ReadLine();
+
while (configLine != null) {
+ if (configLine.Trim().Equals(string.Empty)) {
+ configLine = configStream.ReadLine();
+ continue;
+ }
inputLine = configLine.Split(',');
if (inputLine.Length != CONFIG_LINE_FIELDS)
@@ -171,6 +246,7 @@ namespace TranslationPlugins {
pageClass = inputLine[PAGE_CLASS_FIELD];
pageXAML = inputLine[PAGE_XAML_FIELD];
+ pageBoogieStringName = inputLine[PAGE_BOOGIE_STRING_FIELD];
controlClass = inputLine[CONTROL_CLASS_FIELD];
controlName = inputLine[CONTROL_NAME_FIELD];
enabled = inputLine[ENABLED_FIELD];
@@ -178,6 +254,7 @@ namespace TranslationPlugins {
clickHandler = inputLine[CLICK_HANDLER_FIELD];
checkedHandler = inputLine[CHECKED_HANDLER_FIELD];
uncheckedHandler = inputLine[UNCHECKED_HANDLER_FIELD];
+ bplName = inputLine[BPL_NAME_FIELD];
try {
pageStr = pageStructureInfo[pageClass];
@@ -185,6 +262,7 @@ namespace TranslationPlugins {
pageStr = new PageStructure();
pageStr.PageClassName = pageClass;
pageStr.PageXAML = pageXAML;
+ pageStr.PageBoogieName = pageBoogieStringName;
pageStr.IsMainPage = false;
}
@@ -193,6 +271,7 @@ namespace TranslationPlugins {
controlInfoStr = new ControlInfoStructure();
controlInfoStr.Name = controlName;
controlInfoStr.ClassName = controlClass;
+ controlInfoStr.BplName = bplName;
}
controlInfoStr.IsEnabled = Boolean.Parse(enabled);
controlInfoStr.Visible = visibility == "Collapsed" ? Visibility.Collapsed : Visibility.Visible;
@@ -203,35 +282,57 @@ namespace TranslationPlugins {
pageStr.setControlInfo(controlName, controlInfoStr);
pageStructureInfo[pageClass] = pageStr;
configLine = configStream.ReadLine();
-
- setPageAsMainPage(mainPage);
}
+
+ setPageAsMainPage(mainPageXAML);
} catch (Exception) {
// TODO log, I don't want to terminate BCT because of this
}
}
public IEnumerable<ControlInfoStructure> getControlsForPage(string pageClass) {
- return pageStructureInfo[pageClass].getAllControlsInfo();
+ try {
+ return pageStructureInfo[pageClass].getAllControlsInfo();
+ } catch (KeyNotFoundException) {
+ return null;
+ }
}
public string getXAMLForPage(string pageClass) {
- return pageStructureInfo[pageClass].PageXAML;
+ try {
+ return pageStructureInfo[pageClass].PageXAML;
+ } catch (KeyNotFoundException) {
+ return null;
+ }
}
public bool getIsEnabled(string pageClass, string controlName) {
- return pageStructureInfo[pageClass].getControlInfo(controlName).IsEnabled;
+ try {
+ return pageStructureInfo[pageClass].getControlInfo(controlName).IsEnabled;
+ } catch (KeyNotFoundException) {
+ // TODO not really correct
+ return false;
+ }
}
public Visibility getVisibility(string pageClass, string controlName) {
- return pageStructureInfo[pageClass].getControlInfo(controlName).Visible;
+ try {
+ return pageStructureInfo[pageClass].getControlInfo(controlName).Visible;
+ } catch (KeyNotFoundException) {
+ // TODO not really correct
+ return default(Visibility);
+ }
}
public IList<HandlerSignature> getHandlers(string pageClass, string controlName, string eventName) {
if (eventName != "Checked" && eventName != "Unchecked" && eventName != "Click")
throw new NotImplementedException("Event " + eventName + " is not translated or defined for control " + controlName + " in page " + pageClass);
- return pageStructureInfo[pageClass].getControlInfo(controlName).getHandlers((Event) Event.Parse(typeof(Event), eventName));
+ try {
+ return pageStructureInfo[pageClass].getControlInfo(controlName).getHandlers((Event) Event.Parse(typeof(Event), eventName));
+ } catch (KeyNotFoundException) {
+ return null;
+ }
}
}
}
diff --git a/Binaries/DafnyPrelude.bpl b/Binaries/DafnyPrelude.bpl
index dc152185..32430fd3 100644
--- a/Binaries/DafnyPrelude.bpl
+++ b/Binaries/DafnyPrelude.bpl
@@ -84,6 +84,130 @@ function Set#Choose<T>(Set T, TickType): T;
axiom (forall<T> a: Set T, tick: TickType :: { Set#Choose(a, tick) }
a != Set#Empty() ==> a[Set#Choose(a, tick)]);
+
+// ---------------------------------------------------------------
+// -- Axiomatization of multisets --------------------------------
+// ---------------------------------------------------------------
+
+function Math#min(a: int, b: int): int;
+axiom (forall a: int, b: int :: { Math#min(a, b) } a <= b <==> Math#min(a, b) == a);
+axiom (forall a: int, b: int :: { Math#min(a, b) } b <= a <==> Math#min(a, b) == b);
+axiom (forall a: int, b: int :: { Math#min(a, b) } Math#min(a, b) == a || Math#min(a, b) == b);
+
+function Math#clip(a: int): int;
+axiom (forall a: int :: { Math#clip(a) } 0 <= a ==> Math#clip(a) == a);
+axiom (forall a: int :: { Math#clip(a) } a < 0 ==> Math#clip(a) == 0);
+
+type MultiSet T = [T]int;
+
+function $IsGoodMultiSet<T>(ms: MultiSet T): bool;
+// ints are non-negative, used after havocing, and for conversion from sequences to multisets.
+axiom (forall<T> ms: MultiSet T :: { $IsGoodMultiSet(ms) }
+ $IsGoodMultiSet(ms) <==> (forall o: T :: { ms[o] } 0 <= ms[o]));
+
+function MultiSet#Empty<T>(): MultiSet T;
+axiom (forall<T> o: T :: { MultiSet#Empty()[o] } MultiSet#Empty()[o] == 0);
+
+function MultiSet#Singleton<T>(T): MultiSet T;
+axiom (forall<T> r: T, o: T :: { MultiSet#Singleton(r)[o] } (MultiSet#Singleton(r)[o] == 1 <==> r == o) &&
+ (MultiSet#Singleton(r)[o] == 0 <==> r != o));
+axiom (forall<T> r: T :: { MultiSet#Singleton(r) } MultiSet#Singleton(r) == MultiSet#UnionOne(MultiSet#Empty(), r));
+
+function MultiSet#UnionOne<T>(MultiSet T, T): MultiSet T;
+// pure containment axiom (in the original multiset or is the added element)
+axiom (forall<T> a: MultiSet T, x: T, o: T :: { MultiSet#UnionOne(a,x)[o] }
+ 0 < MultiSet#UnionOne(a,x)[o] <==> o == x || 0 < a[o]);
+// union-ing increases count by one
+axiom (forall<T> a: MultiSet T, x: T :: { MultiSet#UnionOne(a, x) }
+ MultiSet#UnionOne(a, x)[x] == a[x] + 1);
+// non-decreasing
+axiom (forall<T> a: MultiSet T, x: T, y: T :: { MultiSet#UnionOne(a, x), a[y] }
+ 0 < a[y] ==> 0 < MultiSet#UnionOne(a, x)[y]);
+// other elements unchanged
+axiom (forall<T> a: MultiSet T, x: T, y: T :: { MultiSet#UnionOne(a, x), a[y] }
+ x != y ==> a[y] == MultiSet#UnionOne(a, x)[y]);
+
+function MultiSet#Union<T>(MultiSet T, MultiSet T): MultiSet T;
+// union-ing is the sum of the contents
+axiom (forall<T> a: MultiSet T, b: MultiSet T, o: T :: { MultiSet#Union(a,b)[o] }
+ MultiSet#Union(a,b)[o] == a[o] + b[o]);
+
+// two containment axioms
+axiom (forall<T> a, b: MultiSet T, y: T :: { MultiSet#Union(a, b), a[y] }
+ 0 < a[y] ==> 0 < MultiSet#Union(a, b)[y]);
+axiom (forall<T> a, b: MultiSet T, y: T :: { MultiSet#Union(a, b), b[y] }
+ 0 < b[y] ==> 0 < MultiSet#Union(a, b)[y]);
+
+// symmetry axiom
+axiom (forall<T> a, b: MultiSet T :: { MultiSet#Union(a, b) }
+ MultiSet#Difference(MultiSet#Union(a, b), a) == b &&
+ MultiSet#Difference(MultiSet#Union(a, b), b) == a);
+
+function MultiSet#Intersection<T>(MultiSet T, MultiSet T): MultiSet T;
+axiom (forall<T> a: MultiSet T, b: MultiSet T, o: T :: { MultiSet#Intersection(a,b)[o] }
+ MultiSet#Intersection(a,b)[o] == Math#min(a[o], b[o]));
+
+// left and right pseudo-idempotence
+axiom (forall<T> a, b: MultiSet T :: { MultiSet#Intersection(MultiSet#Intersection(a, b), b) }
+ MultiSet#Intersection(MultiSet#Intersection(a, b), b) == MultiSet#Intersection(a, b));
+axiom (forall<T> a, b: MultiSet T :: { MultiSet#Intersection(a, MultiSet#Intersection(a, b)) }
+ MultiSet#Intersection(a, MultiSet#Intersection(a, b)) == MultiSet#Intersection(a, b));
+
+// multiset difference, a - b. clip() makes it positive.
+function MultiSet#Difference<T>(MultiSet T, MultiSet T): MultiSet T;
+axiom (forall<T> a: MultiSet T, b: MultiSet T, o: T :: { MultiSet#Difference(a,b)[o] }
+ MultiSet#Difference(a,b)[o] == Math#clip(a[o] - b[o]));
+axiom (forall<T> a, b: MultiSet T, y: T :: { MultiSet#Difference(a, b), b[y], a[y] }
+ a[y] <= b[y] ==> MultiSet#Difference(a, b)[y] == 0 );
+
+// multiset subset means a must have at most as many of each element as b
+function MultiSet#Subset<T>(MultiSet T, MultiSet T): bool;
+axiom(forall<T> a: MultiSet T, b: MultiSet T :: { MultiSet#Subset(a,b) }
+ MultiSet#Subset(a,b) <==> (forall o: T :: {a[o]} {b[o]} a[o] <= b[o]));
+
+function MultiSet#Equal<T>(MultiSet T, MultiSet T): bool;
+axiom(forall<T> a: MultiSet T, b: MultiSet T :: { MultiSet#Equal(a,b) }
+ MultiSet#Equal(a,b) <==> (forall o: T :: {a[o]} {b[o]} a[o] == b[o]));
+// extensionality axiom for multisets
+axiom(forall<T> a: MultiSet T, b: MultiSet T :: { MultiSet#Equal(a,b) }
+ MultiSet#Equal(a,b) ==> a == b);
+
+function MultiSet#Disjoint<T>(MultiSet T, MultiSet T): bool;
+axiom (forall<T> a: MultiSet T, b: MultiSet T :: { MultiSet#Disjoint(a,b) }
+ MultiSet#Disjoint(a,b) <==> (forall o: T :: {a[o]} {b[o]} a[o] == 0 || b[o] == 0));
+
+// conversion to a multiset. each element in the original set has duplicity 1.
+function MultiSet#FromSet<T>(Set T): MultiSet T;
+axiom (forall<T> s: Set T, a: T :: { MultiSet#FromSet(s)[a] }
+ (MultiSet#FromSet(s)[a] == 0 <==> !s[a]) &&
+ (MultiSet#FromSet(s)[a] == 1 <==> s[a]));
+
+// conversion to a multiset, from a sequence.
+function MultiSet#FromSeq<T>(Seq T): MultiSet T;
+// conversion produces a good map.
+axiom (forall<T> s: Seq T :: { MultiSet#FromSeq(s) } $IsGoodMultiSet(MultiSet#FromSeq(s)) );
+// building axiom
+axiom (forall<T> s: Seq T, v: T ::
+ { MultiSet#FromSeq(Seq#Build(s, v)) }
+ MultiSet#FromSeq(Seq#Build(s, v)) == MultiSet#UnionOne(MultiSet#FromSeq(s), v)
+ );
+axiom (forall<T> :: MultiSet#FromSeq(Seq#Empty(): Seq T) == MultiSet#Empty(): MultiSet T);
+
+// concatenation axiom
+axiom (forall<T> a: Seq T, b: Seq T ::
+ { MultiSet#FromSeq(Seq#Append(a, b)) }
+ MultiSet#FromSeq(Seq#Append(a, b)) == MultiSet#Union(MultiSet#FromSeq(a), MultiSet#FromSeq(b)) );
+
+// update axiom
+axiom (forall<T> s: Seq T, i: int, v: T, x: T ::
+ { MultiSet#FromSeq(Seq#Update(s, i, v))[x] }
+ 0 <= i && i < Seq#Length(s) ==>
+ MultiSet#FromSeq(Seq#Update(s, i, v))[x] ==
+ MultiSet#Union(MultiSet#Difference(MultiSet#FromSeq(s), MultiSet#Singleton(Seq#Index(s,i))), MultiSet#Singleton(v))[x] );
+ // i.e. MS(Update(s, i, v)) == MS(s) - {{s[i]}} + {{v}}
+axiom (forall<T> s: Seq T, x: T :: { MultiSet#FromSeq(s)[x] }
+ (exists i : int :: { Seq#Index(s,i) } 0 <= i && i < Seq#Length(s) && x == Seq#Index(s,i)) <==> 0 < MultiSet#FromSeq(s)[x] );
+
// ---------------------------------------------------------------
// -- Axiomatization of sequences --------------------------------
// ---------------------------------------------------------------
@@ -100,9 +224,12 @@ axiom (forall<T> s: Seq T :: { Seq#Length(s) } Seq#Length(s) == 0 ==> s == Seq#E
function Seq#Singleton<T>(T): Seq T;
axiom (forall<T> t: T :: { Seq#Length(Seq#Singleton(t)) } Seq#Length(Seq#Singleton(t)) == 1);
-function Seq#Build<T>(s: Seq T, index: int, val: T, newLength: int): Seq T;
-axiom (forall<T> s: Seq T, i: int, v: T, len: int :: { Seq#Length(Seq#Build(s,i,v,len)) }
- 0 <= len ==> Seq#Length(Seq#Build(s,i,v,len)) == len);
+function Seq#Build<T>(s: Seq T, val: T): Seq T;
+axiom (forall<T> s: Seq T, v: T :: { Seq#Length(Seq#Build(s,v)) }
+ Seq#Length(Seq#Build(s,v)) == 1 + Seq#Length(s));
+axiom (forall<T> s: Seq T, i: int, v: T :: { Seq#Index(Seq#Build(s,v), i) }
+ (i == Seq#Length(s) ==> Seq#Index(Seq#Build(s,v), i) == v) &&
+ (i != Seq#Length(s) ==> Seq#Index(Seq#Build(s,v), i) == Seq#Index(s, i)));
function Seq#Append<T>(Seq T, Seq T): Seq T;
axiom (forall<T> s0: Seq T, s1: Seq T :: { Seq#Length(Seq#Append(s0,s1)) }
@@ -113,10 +240,6 @@ axiom (forall<T> t: T :: { Seq#Index(Seq#Singleton(t), 0) } Seq#Index(Seq#Single
axiom (forall<T> s0: Seq T, s1: Seq T, n: int :: { Seq#Index(Seq#Append(s0,s1), n) }
(n < Seq#Length(s0) ==> Seq#Index(Seq#Append(s0,s1), n) == Seq#Index(s0, n)) &&
(Seq#Length(s0) <= n ==> Seq#Index(Seq#Append(s0,s1), n) == Seq#Index(s1, n - Seq#Length(s0))));
-axiom (forall<T> s: Seq T, i: int, v: T, len: int, n: int :: { Seq#Index(Seq#Build(s,i,v,len),n) }
- 0 <= n && n < len ==>
- (i == n ==> Seq#Index(Seq#Build(s,i,v,len),n) == v) &&
- (i != n ==> Seq#Index(Seq#Build(s,i,v,len),n) == Seq#Index(s,n)));
function Seq#Update<T>(Seq T, int, T): Seq T;
axiom (forall<T> s: Seq T, i: int, v: T :: { Seq#Length(Seq#Update(s,i,v)) }
@@ -137,16 +260,11 @@ axiom (forall<T> s0: Seq T, s1: Seq T, x: T ::
{ Seq#Contains(Seq#Append(s0, s1), x) }
Seq#Contains(Seq#Append(s0, s1), x) <==>
Seq#Contains(s0, x) || Seq#Contains(s1, x));
-axiom (forall<T> i: int, v: T, len: int, x: T ::
- { Seq#Contains(Seq#Build(Seq#Empty(), i, v, len), x) }
- 0 <= i && i < len ==>
- (Seq#Contains(Seq#Build(Seq#Empty(), i, v, len), x) <==> x == v));
-axiom (forall<T> s: Seq T, i0: int, v0: T, len0: int, i1: int, v1: T, len1: int, x: T ::
- { Seq#Contains(Seq#Build(Seq#Build(s, i0, v0, len0), i1, v1, len1), x) }
- 0 <= i0 && i0 < len0 && len0 <= i1 && i1 < len1 ==>
- (Seq#Contains(Seq#Build(Seq#Build(s, i0, v0, len0), i1, v1, len1), x) <==>
- v1 == x ||
- Seq#Contains(Seq#Build(s, i0, v0, len0), x)));
+
+axiom (forall<T> s: Seq T, v: T, x: T ::
+ { Seq#Contains(Seq#Build(s, v), x) }
+ Seq#Contains(Seq#Build(s, v), x) <==> (v == x || Seq#Contains(s, x)));
+
axiom (forall<T> s: Seq T, n: int, x: T ::
{ Seq#Contains(Seq#Take(s, n), x) }
Seq#Contains(Seq#Take(s, n), x) <==>
@@ -196,6 +314,41 @@ axiom (forall<T> s, t: Seq T ::
Seq#Take(Seq#Append(s, t), Seq#Length(s)) == s &&
Seq#Drop(Seq#Append(s, t), Seq#Length(s)) == t);
+function Seq#FromArray(h: HeapType, a: ref): Seq BoxType;
+axiom (forall h: HeapType, a: ref ::
+ { Seq#Length(Seq#FromArray(h,a)) }
+ Seq#Length(Seq#FromArray(h, a)) == array.Length(a));
+axiom (forall h: HeapType, a: ref :: { Seq#FromArray(h,a): Seq BoxType }
+ (forall i: int :: 0 <= i && i < Seq#Length(Seq#FromArray(h, a)) ==> Seq#Index(Seq#FromArray(h, a), i) == read(h, a, IndexField(i))));
+axiom (forall<alpha> h: HeapType, o: ref, f: Field alpha, v: alpha, a: ref ::
+ { Seq#FromArray(update(h, o, f, v), a) }
+ o != a ==> Seq#FromArray(update(h, o, f, v), a) == Seq#FromArray(h, a) );
+axiom (forall h: HeapType, i: int, v: BoxType, a: ref ::
+ { Seq#FromArray(update(h, a, IndexField(i), v), a) }
+ 0 <= i && i < array.Length(a) ==> Seq#FromArray(update(h, a, IndexField(i), v), a) == Seq#Update(Seq#FromArray(h, a), i, v) );
+
+// Commutability of Take and Drop with Update.
+axiom (forall<T> s: Seq T, i: int, v: T, n: int ::
+ { Seq#Take(Seq#Update(s, i, v), n) }
+ 0 <= i && i < n && n <= Seq#Length(s) ==> Seq#Take(Seq#Update(s, i, v), n) == Seq#Update(Seq#Take(s, n), i, v) );
+axiom (forall<T> s: Seq T, i: int, v: T, n: int ::
+ { Seq#Take(Seq#Update(s, i, v), n) }
+ n <= i && i < Seq#Length(s) ==> Seq#Take(Seq#Update(s, i, v), n) == Seq#Take(s, n));
+axiom (forall<T> s: Seq T, i: int, v: T, n: int ::
+ { Seq#Drop(Seq#Update(s, i, v), n) }
+ 0 <= n && n <= i && i < Seq#Length(s) ==> Seq#Drop(Seq#Update(s, i, v), n) == Seq#Update(Seq#Drop(s, n), i-n, v) );
+axiom (forall<T> s: Seq T, i: int, v: T, n: int ::
+ { Seq#Drop(Seq#Update(s, i, v), n) }
+ 0 <= i && i < n && n < Seq#Length(s) ==> Seq#Drop(Seq#Update(s, i, v), n) == Seq#Drop(s, n));
+// Extension axiom, triggers only on Takes from arrays.
+axiom (forall h: HeapType, a: ref, n0, n1: int ::
+ { Seq#Take(Seq#FromArray(h, a), n0), Seq#Take(Seq#FromArray(h, a), n1) }
+ n0 + 1 == n1 && 0 <= n0 && n1 <= array.Length(a) ==> Seq#Take(Seq#FromArray(h, a), n1) == Seq#Build(Seq#Take(Seq#FromArray(h, a), n0), read(h, a, IndexField(n0): Field BoxType)) );
+// drop commutes with build.
+axiom (forall<T> s: Seq T, v: T, n: int ::
+ { Seq#Drop(Seq#Build(s, v), n) }
+ 0 <= n && n <= Seq#Length(s) ==> Seq#Drop(Seq#Build(s, v), n) == Seq#Build(Seq#Drop(s, n), v) );
+
// ---------------------------------------------------------------
// -- Boxing and unboxing ----------------------------------------
// ---------------------------------------------------------------
@@ -225,6 +378,7 @@ const unique class.int: ClassName;
const unique class.bool: ClassName;
const unique class.set: ClassName;
const unique class.seq: ClassName;
+const unique class.multiset: ClassName;
function /*{:never_pattern true}*/ dtype(ref): ClassName;
function /*{:never_pattern true}*/ TypeParams(ref, int): ClassName;
@@ -332,6 +486,9 @@ axiom (forall r: ref, h: HeapType ::
// -- Arrays -----------------------------------------------------
// ---------------------------------------------------------------
+function array.Length(a: ref): int;
+axiom (forall o: ref :: 0 <= array.Length(o));
+
procedure UpdateArrayRange(arr: ref, low: int, high: int, rhs: BoxType);
modifies $Heap;
ensures $HeapSucc(old($Heap), $Heap);
diff --git a/Binaries/DafnyRuntime.cs b/Binaries/DafnyRuntime.cs
index c03ac643..82de380d 100644
--- a/Binaries/DafnyRuntime.cs
+++ b/Binaries/DafnyRuntime.cs
@@ -132,11 +132,154 @@ namespace Dafny
return default(T);
}
}
+ public class MultiSet<T>
+ {
+ Dictionary<T, int> dict;
+ public MultiSet() { }
+ MultiSet(Dictionary<T, int> d) {
+ dict = d;
+ }
+ public static MultiSet<T> Empty {
+ get {
+ return new MultiSet<T>(new Dictionary<T, int>(0));
+ }
+ }
+ public static MultiSet<T> FromElements(params T[] values) {
+ Dictionary<T, int> d = new Dictionary<T, int>(values.Length);
+ foreach (T t in values) {
+ var i = 0;
+ if (!d.TryGetValue(t, out i)) {
+ i = 0;
+ }
+ d[t] = i + 1;
+ }
+ return new MultiSet<T>(d);
+ }
+ public static MultiSet<T> FromCollection(ICollection<T> values) {
+ Dictionary<T, int> d = new Dictionary<T, int>();
+ foreach (T t in values) {
+ var i = 0;
+ if (!d.TryGetValue(t, out i)) {
+ i = 0;
+ }
+ d[t] = i + 1;
+ }
+ return new MultiSet<T>(d);
+ }
+ public static MultiSet<T> FromSeq(Sequence<T> values) {
+ Dictionary<T, int> d = new Dictionary<T, int>();
+ foreach (T t in values.Elements) {
+ var i = 0;
+ if (!d.TryGetValue(t, out i)) {
+ i = 0;
+ }
+ d[t] = i + 1;
+ }
+ return new MultiSet<T>(d);
+ }
+ public static MultiSet<T> FromSet(Set<T> values) {
+ Dictionary<T, int> d = new Dictionary<T, int>();
+ foreach (T t in values.Elements) {
+ d[t] = 1;
+ }
+ return new MultiSet<T>(d);
+ }
+
+ public bool Equals(MultiSet<T> other) {
+ return other.IsSubsetOf(this) && this.IsSubsetOf(other);
+ }
+ public override bool Equals(object other) {
+ return other is MultiSet<T> && Equals((MultiSet<T>)other);
+ }
+ public override int GetHashCode() {
+ return dict.GetHashCode();
+ }
+ public bool IsProperSubsetOf(MultiSet<T> other) {
+ return !Equals(other) && IsSubsetOf(other);
+ }
+ public bool IsSubsetOf(MultiSet<T> other) {
+ foreach (T t in dict.Keys) {
+ if (!other.dict.ContainsKey(t) || other.dict[t] < dict[t])
+ return false;
+ }
+ return true;
+ }
+ public bool IsSupersetOf(MultiSet<T> other) {
+ return other.IsSubsetOf(this);
+ }
+ public bool IsProperSupersetOf(MultiSet<T> other) {
+ return other.IsProperSubsetOf(this);
+ }
+ public bool IsDisjointFrom(MultiSet<T> other) {
+ foreach (T t in dict.Keys) {
+ if (other.dict.ContainsKey(t))
+ return false;
+ }
+ foreach (T t in other.dict.Keys) {
+ if (dict.ContainsKey(t))
+ return false;
+ }
+ return true;
+ }
+ public bool Contains(T t) {
+ return dict.ContainsKey(t);
+ }
+ public MultiSet<T> Union(MultiSet<T> other) {
+ if (dict.Count == 0)
+ return other;
+ else if (other.dict.Count == 0)
+ return this;
+ var r = new Dictionary<T, int>();
+ foreach (T t in dict.Keys) {
+ var i = 0;
+ if (!r.TryGetValue(t, out i)) {
+ i = 0;
+ }
+ r[t] = i + dict[t];
+ }
+ foreach (T t in other.dict.Keys) {
+ var i = 0;
+ if (!r.TryGetValue(t, out i)) {
+ i = 0;
+ }
+ r[t] = i + other.dict[t];
+ }
+ return new MultiSet<T>(r);
+ }
+ public MultiSet<T> Intersect(MultiSet<T> other) {
+ if (dict.Count == 0)
+ return this;
+ else if (other.dict.Count == 0)
+ return other;
+ var r = new Dictionary<T, int>();
+ foreach (T t in dict.Keys) {
+ if (other.dict.ContainsKey(t)) {
+ r.Add(t, other.dict[t] < dict[t] ? other.dict[t] : dict[t]);
+ }
+ }
+ return new MultiSet<T>(r);
+ }
+ public MultiSet<T> Difference(MultiSet<T> other) { // \result == this - other
+ if (dict.Count == 0)
+ return this;
+ else if (other.dict.Count == 0)
+ return this;
+ var r = new Dictionary<T, int>();
+ foreach (T t in dict.Keys) {
+ if (!other.dict.ContainsKey(t)) {
+ r.Add(t, dict[t]);
+ } else if (other.dict[t] < dict[t]) {
+ r.Add(t, dict[t] - other.dict[t]);
+ }
+ }
+ return new MultiSet<T>(r);
+ }
+ }
public class Sequence<T>
{
T[] elmts;
public Sequence() { }
- Sequence(T[] ee) {
+ public Sequence(T[] ee) {
elmts = ee;
}
public static Sequence<T> Empty {
@@ -303,5 +446,8 @@ namespace Dafny
return c.IsZero ? c : BigInteger.Subtract(bp, c);
}
}
+ public static Sequence<T> SeqFromArray<T>(T[] array) {
+ return new Sequence<T>(array);
+ }
}
}
diff --git a/Chalice/chalice.bat b/Chalice/chalice.bat
index a81e4d5d..1fbc3466 100644
--- a/Chalice/chalice.bat
+++ b/Chalice/chalice.bat
@@ -1,5 +1,5 @@
@echo off
-call scala -cp "%~dp0\bin" chalice.Chalice -nologo %1 %2 %3 %4
+call scala -cp "%~dp0\bin" chalice.Chalice -nologo %*
exit /B 0
diff --git a/Chalice/src/Ast.scala b/Chalice/src/Ast.scala
index 8c59882f..af9fc81b 100644
--- a/Chalice/src/Ast.scala
+++ b/Chalice/src/Ast.scala
@@ -303,7 +303,9 @@ sealed abstract class Statement extends ASTNode {
def Declares: List[Variable] = Nil // call after resolution
def Targets: Set[Variable] = Set() // assigned local variables
}
-case class Assert(e: Expression) extends Statement
+case class Assert(e: Expression) extends Statement {
+ var smokeErrorNr: Option[Int] = None
+}
case class Assume(e: Expression) extends Statement
case class BlockStmt(ss: List[Statement]) extends Statement {
override def Targets = (ss :\ Set[Variable]()) { (s, vars) => vars ++ s.Targets}
@@ -344,7 +346,9 @@ case class Release(obj: Expression) extends Statement
case class RdAcquire(obj: Expression) extends Statement
case class RdRelease(obj: Expression) extends Statement
case class Downgrade(obj: Expression) extends Statement
-case class Lock(obj: Expression, b: BlockStmt, rdLock: Boolean) extends Statement
+case class Lock(obj: Expression, b: BlockStmt, rdLock: Boolean) extends Statement {
+ override def Targets = b.Targets
+}
case class Free(obj: Expression) extends Statement
case class CallAsync(declaresLocal: Boolean, lhs: VariableExpr, obj: Expression, id: String, args: List[Expression]) extends Statement {
var local: Variable = null
@@ -366,6 +370,7 @@ case class Send(ch: Expression, args: List[Expression]) extends Statement {
case class Receive(declaresLocal: List[Boolean], ch: Expression, outs: List[VariableExpr]) extends Statement {
var locals = List[Variable]()
override def Declares = locals
+ override def Targets = (outs :\ Set[Variable]()) { (ve, vars) => if (ve.v != null) vars + ve.v else vars }
}
case class Fold(pred: Access) extends Statement
case class Unfold(pred: Access) extends Statement
diff --git a/Chalice/src/Boogie.scala b/Chalice/src/Boogie.scala
index afaff452..6f18694d 100644
--- a/Chalice/src/Boogie.scala
+++ b/Chalice/src/Boogie.scala
@@ -29,8 +29,10 @@ object Boogie {
case class Comment(comment: String) extends Stmt
case class Assert(e: Expr) extends Stmt {
def this(e: Expr, p: Position, txt: String) = { this(e); this.pos = p; this.message = txt; this }
+ def this(e: Expr, p: Position, txt: String, subsumption: Int) = { this(e, p, txt); this.subsumption = Some(subsumption); this }
var pos = NoPosition : Position
var message = "" : String
+ var subsumption = None: Option[Int]
}
case class Assume(e: Expr) extends Stmt
case class Assign(lhs: Expr, rhs: Expr) extends Stmt
@@ -214,7 +216,7 @@ object Boogie {
} else {
" " + assert.pos + ": "
}
- indent + "assert " + "{:msg \"" + pos + assert.message + "\"}" + " " + PrintExpr(e) + ";" + nl
+ indent + "assert " + "{:msg \"" + pos + assert.message + "\"}" + (assert.subsumption match {case Some(n) => "{:subsumption " + n + "}"; case None => ""}) + " " + PrintExpr(e) + ";" + nl
case Assume(e) => indent + "assume " + PrintExpr(e) + ";" + nl
case If(guard, thn, els) =>
indent + "if (" +
diff --git a/Chalice/src/Chalice.scala b/Chalice/src/Chalice.scala
index 973d6b94..524ab5f6 100644
--- a/Chalice/src/Chalice.scala
+++ b/Chalice/src/Chalice.scala
@@ -37,6 +37,7 @@ object Chalice {
// percentageSupport 2: use function and provide some (redundant) axioms
// percentageSupport 3: use an uninterpreted function and axiomatize the properties of multiplication
private[chalice] var percentageSupport = 2;
+ private[chalice] var smoke = false;
def main(args: Array[String]): Unit = {
var boogiePath = "C:\\boogie\\Binaries\\Boogie.exe"
@@ -47,48 +48,102 @@ object Chalice {
var boogieArgs = " ";
var gen = false;
var showFullStackTrace = false
-
+
+ // help texts and closures for boolean command line options
// closures should be idempotent
- val options = Map(
- "-print" -> {() => printProgram = true},
- "-noTranslate" -> {() => doTranslate = false},
- "-noTypecheck"-> {() => doTypecheck = false},
- "-vs" -> {() => vsMode = true},
- "-checkLeaks" -> {() => checkLeaks = true},
- "-noDeadlockChecks" -> {() => skipDeadlockChecks = true},
- "-noTermination" -> {() => skipTermination = true},
- "-defaults" -> {() => defaults = 3},
- "-gen" -> {() => gen = true},
- "-autoFold" -> {() => autoFold = true},
- "-autoMagic"-> {() => autoMagic = true},
- "-noFreeAssume" -> {() => noFreeAssume = true},
- "-showFullStackTrace" -> {() => showFullStackTrace = true}
+ import scala.collection.immutable.ListMap
+ val options = ListMap[String,(() => Unit, String)](
+ "help" -> (
+ {() => },
+ "print this message"),
+ "print" -> (
+ {() => printProgram = true},
+ "print intermediate versions of the Chalice program"),
+ "noTranslate" -> (
+ {() => doTranslate = false},
+ "do not translate the program to Boogie (only parse and typecheck)"),
+ "noTypecheck"-> (
+ {() => doTypecheck = false},
+ "do not typecheck the program (only parse). Implies /noTranslate."),
+ "vs" -> (
+ {() => vsMode = true},
+ "Microsoft Visual Studio mode (special error reporting for Visual Studio; requires an existing, writable directory at C:\\tmp)"),
+ "checkLeaks" -> (
+ {() => checkLeaks = true},
+ "(no description available)"),
+ "noDeadlockChecks" -> (
+ {() => skipDeadlockChecks = true},
+ "skip all lock ordering checks"),
+ "noTermination" -> (
+ {() => skipTermination = true},
+ "skip the termination checks for functions"),
+ "defaults" -> (
+ {() => defaults = 3},
+ null),
+ "gen" -> (
+ {() => gen = true},
+ "generate C# code from the Chalice program"),
+ "autoFold" -> (
+ {() => autoFold = true},
+ "automatically fold predicates whenever necessary"),
+ "autoMagic" -> (
+ {() => autoMagic = true},
+ "automatically try to infer accessibility predicates and non-nullness checks in specifications"),
+ "noFreeAssume" -> (
+ {() => noFreeAssume = true},
+ "(no description available)"),
+ "showFullStackTrace" -> (
+ {() => showFullStackTrace = true},
+ "show the full stack trace if an exception is encountered"),
+ "smoke" -> (
+ {() => smoke = true},
+ "smoke testing; try to find unreachable code, preconditions/invariants/predicates that are equivalent to false and assumptions that introduce contradictions, by trying to prove 'false' at various positions.")
+ )
+ // help text for options with arguments
+ val nonBooleanOptions = ListMap(
+ "boogie:<file>" -> "use the executable of Boogie at <file>",
+ "defaults:<level>" -> ("defaults to reduce specification overhead\n"+
+ "level 0 or below: no defaults\n"+
+ "level 1: unfold predicates with receiver this in pre and postconditions\n"+
+ "level 2: unfold predicates and functions with receiver this in pre and postconditions\n"+
+ "level 3 or above: level 2 + autoMagic"),
+ "percentageSupport:<n>" -> ("determin how percentage permissions are translated to Boogie\n"+
+ "0: use multiplication directly (can cause performance problems)\n"+
+ "1: fix Permission$denominator as constant (possibly unsound)\n"+
+ "2: use a function and provide some (redundant) axioms\n"+
+ "3: use an uninterpreted function and axiomatize the properties of multiplication")/*,
+ "boogieOpt:<arg>, /bo:<arg>" -> "specify additional Boogie options"*/
)
- lazy val help = options.keys.foldLeft("syntax: chalice")((s, o) => s + " [" + o + "]") +
- " [-boogie:path]" +
- " [-defaults:int]" +
- " <boogie option>*" +
- " <file.chalice>*";
+ lazy val help = {
+ val maxLength = math.min((nonBooleanOptions.keys++options.keys).map(s => s.length+1).max,14)
+ val printOptionHelp = (param: String, help: String) => "\n /" + param + (" "*(maxLength-param.length-1)) +
+ ": " + help.split("\n").map(h => " "*(maxLength+2+2)+wordWrap(h, 80-2-2-math.max(maxLength,param.length+1)," "*(maxLength+2+2))).mkString("\n").substring(maxLength+2+2)
+ "Chalice concurrent program verifier.\nUsage: chalice [option] <filename>+\n"+
+ " where <option> is one of"+
+ options.foldLeft("")((acc, v) => acc + (if (v._2._2 == null) "" else printOptionHelp(v._1, v._2._2)))+
+ nonBooleanOptions.foldLeft("")((acc, v) => acc + printOptionHelp(v._1, v._2))
+ }
+
for (a <- args) {
- if (options contains a) options(a)()
- else if (a == "-help") {Console.out.println(help); return}
- else if (a.startsWith("-boogie:")) boogiePath = a.substring(8)
- else if (a.startsWith("-defaults:")) {
+ if (a == "/help" || a == "-help") {Console.out.println(help); return}
+ else if ((a.startsWith("-") || a.startsWith("/")) && (options contains a.substring(1))) options(a.substring(1))._1()
+ else if (a.startsWith("/boogie:") || a.startsWith("-boogie:")) boogiePath = a.substring(8)
+ else if (a.startsWith("/defaults:") || a.startsWith("-defaults:")) {
try {
defaults = Integer.parseInt(a.substring(10));
if (3<=defaults) { autoMagic = true; }
} catch { case _ => CommandLineError("-defaults takes integer argument", help); }
}
- else if (a.startsWith("-percentageSupport:")) {
+ else if (a.startsWith("/percentageSupport:") || a.startsWith("-percentageSupport:")) {
try {
- val in = Integer.parseInt(a.substring("-percentageSupport:".length));
- if (in < 0 || in > 3) CommandLineError("-percentageSupport takes only values 0,1,2 or 3", help)
+ val in = Integer.parseInt(a.substring(19));
+ if (in < 0 || in > 3) CommandLineError("/percentageSupport takes only values 0,1,2 or 3", help)
else percentageSupport = in
- } catch { case _ => CommandLineError("-percentageSupport takes integer argument", help); }
+ } catch { case _ => CommandLineError("/percentageSupport takes integer argument", help); }
}
else if (a.startsWith("-") || a.startsWith("/"))
- boogieArgs += ('"' + a + '"' + " ")
+ boogieArgs += ("\"" + a + "\"" + " ")
// other arguments starting with "-" or "/" are sent to Boogie.exe
/* [MHS] Quote whole argument to not confuse Boogie with arguments that
* contain spaces, e.g. if Chalice is invoked as
@@ -97,6 +152,12 @@ object Chalice {
else inputs += a
}
+ // for smoke testing, we want to see all failing assertions, so we use no
+ // error limit (or a very high one), and turn the subsumption option off
+ if (smoke) {
+ boogieArgs += ("\"-errorLimit:10000\" ")
+ }
+
percentageSupport match {
case 0 => TranslatorPrelude.addComponent(PercentageStandardPL)
case 1 => TranslatorPrelude.addComponent(PercentageStandardPL, PercentageFixedDenominatorPL)
@@ -134,8 +195,9 @@ object Chalice {
Console.err.println("Error: " + e);
Nil
case parser.Success(prog, _) =>
- if (printProgram) PrintProgram.P(prog)
- prog
+ val pprog = if (smoke) SmokeTest.smokeProgram(prog) else prog
+ if (printProgram) PrintProgram.P(pprog)
+ pprog
}).flatten;
if (parseErrors) return;
@@ -209,14 +271,25 @@ object Chalice {
val input = new BufferedReader(new InputStreamReader(boogie.getInputStream));
var line = input.readLine();
var previous_line = null: String;
- while(line!=null){
- Console.out.println(line);
- Console.out.flush;
+ val boogieOutput: ListBuffer[String] = new ListBuffer()
+ while (line!=null){
+ if (!smoke) {
+ Console.out.println(line);
+ Console.out.flush;
+ }
+ boogieOutput += line
previous_line = line;
line = input.readLine();
}
boogie.waitFor;
input.close;
+
+ // smoke test output
+ if (smoke) {
+ val output = SmokeTest.processBoogieOutput(boogieOutput.toList)
+ Console.out.println(output);
+ Console.out.flush;
+ }
// generate code
if(gen && (previous_line != null) && previous_line.endsWith(" 0 errors")) { // hack
@@ -230,14 +303,14 @@ object Chalice {
}
def writeFile(filename: String, text: String) {
- val writer = new FileWriter(new File(filename));
- writer.write(text);
- writer.flush();
- writer.close();
+ val writer = new FileWriter(new File(filename));
+ writer.write(text);
+ writer.flush();
+ writer.close();
}
def CommandLineError(msg: String, help: String) = {
- Console.err.println("Error: " + msg)
+ Console.err.println("Error: " + msg)
}
def ReportError(pos: Position, msg: String) = {
@@ -247,8 +320,24 @@ object Chalice {
} else {
Console.err.println(pos + ": " + msg)
}
- }
+ }
+
+ def wordWrap(s: String, l: Int, indent: String): String = {
+ var prefix = s.takeWhile(c => c == ' ').length
+ if (prefix == 0) prefix = if (s.indexOf(": ") > 0) s.indexOf(": ")+2 else 0;
+ val words = s.split(" ")
+ var c = 0
+ var result = ""
+ var first = 0
+ for (word <- words) {
+ c += word.length + 1
+ if (c-1 > l-first*prefix) { result += "\n"; c = word.length + 1; first = 1}
+ result += word + " "
+ }
+ result.substring(0, result.length-1).replace("\n", "\n" + (" "*prefix) + indent).replace(" \n","\n")
+ }
}
class InternalErrorException(val msg: String) extends Throwable
class NotSupportedException(val msg: String) extends Throwable
+
diff --git a/Chalice/src/Prelude.scala b/Chalice/src/Prelude.scala
index f4a99796..62597e8e 100644
--- a/Chalice/src/Prelude.scala
+++ b/Chalice/src/Prelude.scala
@@ -106,7 +106,7 @@ axiom Permission$denominator == 100000000000;"""
}
object PercentageFunctionPL extends PreludeComponent {
val text = """
-function Fractions(n: int): int
+function Fractions(n: int) returns (int)
{
n * Permission$denominator
}
@@ -120,8 +120,8 @@ axiom predicateK == channelK && channelK == monitorK;"""
}
object PercentageUninterpretedFunctionPL extends PreludeComponent {
val text = """
-function Fractions(n: int): int;
-function Fractions'(n: int): int;
+function Fractions(n: int) returns (int);
+function Fractions'(n: int) returns (int);
axiom (forall x: int :: { Fractions(x) } Fractions(x) == Fractions'(x));
axiom (forall x,y: int :: 0 <= x && x <= y ==> Fractions'(x) <= Fractions'(y));
axiom (forall x,y: int :: { Fractions(x), Fractions(y) } Fractions(x) + Fractions(y) == Fractions'(x+y));
diff --git a/Chalice/src/SmokeTest.scala b/Chalice/src/SmokeTest.scala
new file mode 100644
index 00000000..bf2622ce
--- /dev/null
+++ b/Chalice/src/SmokeTest.scala
@@ -0,0 +1,239 @@
+
+package chalice;
+
+import scala.util.parsing.input.Position
+import scala.util.parsing.input.NoPosition
+
+/** SmokeTest allows to perform 'smoke testing' on any given Chalice program.
+ * The prover is instructed to try proving 'false' at various places in the
+ * program to find unreachable code, precondition that are equivalent to false
+ * or assumptions that introduce a contradiction.
+ *
+ * @author Stefan Heule
+ */
+object SmokeTest {
+
+ /** SmokeAssert is used to keep track of the position and real error message
+ * associated with a certain assert statement. Also, we build a DAG of
+ * SmokeAssert that essentially corresponds to the control flow graph (the
+ * member prev is used to record the in-edges of every SmokeAssert). This
+ * graph is then used to omit certain warnings (e.g., if the precondition is
+ * already false, we do not need to report that the method end cannot be
+ * reached, too).
+ */
+ case class SmokeAssert(id: Int, pos: Position, msg: String, prev: Set[SmokeAssert], chaliceAssert: Assert) {
+ var warning: Boolean = false // did this "assert false" generate a warning? (i.e. did it not generate a Boogie error?)
+ }
+ /** Serves as a sentinel for the first assert (which should always cause a
+ * warning, thus SmokeAssertSentinel.warning = false
+ */
+ object SmokeAssertSentinel extends SmokeAssert(-1, NoPosition, "", Set(), null)
+
+ /** Map from error message ID's to their SmokeAssert object */
+ private var smokeAssertions: Map[Int,SmokeAssert] = Map()
+ private var count: Int = 0 // current error message id
+
+ /** Process the output of Boogie and generate the correct warnings from smoke testing */
+ def processBoogieOutput(out: List[String]): String = {
+ var errorCount: Map[String, Int] = Map()
+ val SmokePattern = ".*: SMOKE-TEST-([0-9]+).".r
+ val SummaryPattern = "Boogie program verifier finished with ([0-9]+) verified, ([0-9]+) errors".r
+ var verificationResult = "";
+ var smokeErrors: Set[Int] = Set()
+ var outcome: Option[(Int,Int)] = None
+ for (s <- out) s match {
+ case SmokePattern(id) => smokeErrors += id.toInt
+ case SummaryPattern(verified, errors) => outcome = Some((verified.toInt,errors.toInt))
+ case _ => verificationResult += s + "\n"
+ }
+
+ // check which smoke assertions failed
+ for ((errNr, s@SmokeAssert(_, pos, msg, prev, _)) <- smokeAssertions) yield {
+ s.warning = !smokeErrors.contains(errNr)
+ }
+
+ var smokeTestWarnings = 0
+ val smokeResult = {
+ var t = "";
+ for (s@SmokeAssert(_, pos, msg, prev, _) <- smokeAssertions.values.toList.sortWith((a,b) => a.pos < b.pos)) yield {
+ if (s.warning) {
+ if (s.prev.exists(a => !a.warning)) { // omit warning if all ancestors created a warning
+ t += " " + pos + ": " + msg + "\n"
+ smokeTestWarnings += 1
+ }
+ }
+ }
+ t
+ }
+
+ var realErrors = -1
+ val status = (outcome match {
+ case None => ""
+ case Some((verified,errors)) =>
+ realErrors = errors-smokeErrors.size
+ "Boogie program verifier finished with " + realErrors + " errors and " + smokeTestWarnings + " smoke test warnings."
+ })
+
+ verificationResult +
+ (if (realErrors > 0) "The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.\n" else "") +
+ smokeResult + (if (smokeResult != "") "\n" else "") +
+ status
+ }
+
+ /** Add smoke assertions for to a program. */
+ def smokeProgram(prog: List[TopLevelDecl]): List[TopLevelDecl] = {
+ for (decl <- prog) yield decl match {
+ case cl: Class =>
+ val newmembers = for (m <- cl.members) yield m match {
+ case MonitorInvariant(e) => m
+ case f@ Field(id, t, ghost) => m
+ case method: Method =>
+ copyPosition(method, smokeMethod(method))
+ case Condition(id, optE) => m
+ case Predicate(id, definition) => m
+ case Function(id, ins, out, specs, e) => m
+ case m: MethodTransform => m
+ case CouplingInvariant(ids, e) => m
+ }
+ copyPosition(cl, Class(cl.classId, cl.parameters, cl.module, newmembers))
+ case ch: Channel => ch
+ }
+ }
+
+ /** Add smoke assertions for a method (if necessary). */
+ private def smokeMethod(method: Method) = {
+ val preassert = initSmokeAssert(method.pos, "Precondition of method " + method.Id + " is equivalent to false.")
+ var (newbody, bodyout) = smokeStmt(method.body, Set(preassert))
+ val postassert = initSmokeAssert(method.pos, "The end of method " + method.Id + " is unreachable.", bodyout)
+ newbody = preassert.chaliceAssert :: newbody ::: postassert.chaliceAssert :: Nil
+ Method(method.id, method.ins, method.outs, method.spec, newbody)
+ }
+
+ /** Add smoke assertions for multiple statements (if necessary). */
+ private def smokeStmt(stmts: List[Statement], in: Set[SmokeAssert]): (List[Statement], Set[SmokeAssert]) = {
+ var tmp = in
+ val newstmts = (for (s <- stmts) yield {
+ val (sstmts, sout) = smokeStmt(s, tmp)
+ tmp = sout
+ copyPosition(s, sstmts)
+ }).flatten
+ (newstmts, tmp)
+ }
+
+ /** Add smoke assertions for a statement (if necessary). */
+ private def smokeStmt(stmt: Statement, in: Set[SmokeAssert]): (List[Statement], Set[SmokeAssert]) = {
+ var out = in
+ val result = stmt match {
+ // composite statements
+ case BlockStmt(ss) =>
+ val (smokestmts, blocksmoke) = smokeStmt(ss, in)
+ out = blocksmoke
+ smokestmts
+ case ifs@IfStmt(guard, BlockStmt(then), els) =>
+ val thensmoke = initSmokeAssert(ifs.pos, "The begging of the if-branch is unreachable.", in)
+ val (thensmokestmts, thenout) = smokeStmt(then, Set(thensmoke))
+ out = thenout
+ val newthen = thensmoke.chaliceAssert :: thensmokestmts
+ val newelse = els match {
+ case None =>
+ out ++= in
+ None
+ case Some(s) =>
+ val elsesmoke = initSmokeAssert(ifs.pos, "The begging of the else-branch is unreachable.", in)
+ val (blocksmokestmts, blockout) = smokeStmt(s, Set(elsesmoke))
+ out ++= blockout
+ Some(BlockStmt(elsesmoke.chaliceAssert :: blocksmokestmts))
+ }
+ IfStmt(guard, BlockStmt(newthen), newelse) :: Nil
+ case WhileStmt(guard, oldInvs, newInvs, lkch, BlockStmt(body)) =>
+ val whilesmoke = initSmokeAssert(stmt.pos, "The begging of the while-body is unreachable.", in)
+ val (whilesmokestmts, whileout) = smokeStmt(body, Set(whilesmoke))
+ val whileaftersmoke = initSmokeAssert(stmt.pos, "The statements after the while-loop are unreachable.", in)
+ val whileendsmoke = initSmokeAssert(stmt.pos, "The end of the while-loop is unreachable.", whileout)
+ out = Set(whileaftersmoke)
+ val newbody = whilesmoke.chaliceAssert :: whilesmokestmts ::: whileendsmoke.chaliceAssert :: Nil
+ WhileStmt(guard, oldInvs, newInvs, lkch, BlockStmt(newbody)) :: whileaftersmoke.chaliceAssert :: Nil
+ case Lock(obj, BlockStmt(body), rdLock) =>
+ val locksmoke = initSmokeAssert(stmt.pos, "The begging of the lock-block is unreachable.", in)
+ val (blocksmokestmts, blockout) = smokeStmt(body, Set(locksmoke))
+ out = blockout
+ Lock(obj, BlockStmt(locksmoke.chaliceAssert :: blocksmokestmts), rdLock) :: Nil
+ case _: RefinementBlock =>
+ // TODO
+ stmt :: Nil
+
+ // assumption
+ case Assume(_) =>
+ val assumeSmoke = initSmokeAssert(stmt.pos, "Assumption introduces a contradiction.", in)
+ out = Set(assumeSmoke)
+ stmt :: assumeSmoke.chaliceAssert :: Nil
+
+ // simple statements that inhale something
+ case Unfold(_) => val (stmts, sout) = smokeSimpleStmt(stmt, in, "unfold"); out = sout; stmts
+ case JoinAsync(_, _) => val (stmts, sout) = smokeSimpleStmt(stmt, in, "join"); out = sout; stmts
+ case _: Call => val (stmts, sout) = smokeSimpleStmt(stmt, in, "method call"); out = sout; stmts
+ case _: SpecStmt => val (stmts, sout) = smokeSimpleStmt(stmt, in, "specification"); out = sout; stmts
+ case Receive(_, _, _) => val (stmts, sout) = smokeSimpleStmt(stmt, in, "receive"); out = sout; stmts
+ case Acquire(_) => val (stmts, sout) = smokeSimpleStmt(stmt, in, "acquire"); out = sout; stmts
+ case RdAcquire(_) => val (stmts, sout) = smokeSimpleStmt(stmt, in, "rd acquire"); out = sout; stmts
+
+ // any other simple statements
+ case Assert(_) => stmt :: Nil
+ case Assign(_, _) => stmt :: Nil
+ case FieldUpdate(_, _) => stmt :: Nil
+ case _: LocalVar => stmt :: Nil
+ case Install(_, _, _) => stmt :: Nil
+ case Share(_, _, _) => stmt :: Nil
+ case Unshare(_) => stmt :: Nil
+ case Release(_) => stmt :: Nil
+ case RdRelease(_) => stmt :: Nil
+ case Downgrade(_) => stmt :: Nil
+ case Free(_) => stmt :: Nil
+ case Fold(_) => stmt :: Nil
+ case CallAsync(_, _, _, _, _) => stmt :: Nil
+ case Send(_, _) => stmt :: Nil
+ case _: Signal => stmt :: Nil
+ case _: Wait => stmt :: Nil
+ }
+ (result, out)
+ }
+
+ /** Helper method to add a smoke assertion after a simple (non-compound)
+ * statement.
+ */
+ def smokeSimpleStmt(stmt: Statement, in: Set[SmokeAssert], msg: String): (List[Statement], Set[SmokeAssert]) = {
+ val smoke = initSmokeAssert(stmt.pos, "The statements after the " + msg + " statement are unreachable.", in)
+ (stmt :: smoke.chaliceAssert :: Nil, Set(smoke))
+ }
+
+ /** Generate an "assert false" with a certain position and a certain error
+ * message. Note: We generate "assert 1!=1" instead of "assert false", as
+ * Boogie seems to perform some weird optimization for false, which does
+ * not generate warnings for all failing assertions (even if the command
+ * line switch /subsumption:0 is used).
+ */
+ def initSmokeAssert(pos: Position, error: String): SmokeAssert = initSmokeAssert(pos, error, Set(SmokeAssertSentinel))
+ def initSmokeAssert(pos: Position, error: String, prev: Set[SmokeAssert]): SmokeAssert = {
+ count += 1
+ val i = IntLiteral(1); i.typ = IntClass
+ val n = Neq(i, i); n.typ = BoolClass
+ val assert = Assert(n)
+ assert.smokeErrorNr = Some(count)
+ assert.pos = pos
+ val sm = SmokeAssert(count, pos, error, prev, assert)
+ smokeAssertions += count -> sm
+ sm
+ }
+
+ /** Copy the position of an old AST node to a new node (if not already
+ * present).
+ */
+ private def copyPosition[A <: ASTNode](oldNode: A, newNode: A): A = {
+ if (newNode.pos == NoPosition) newNode.pos = oldNode.pos
+ newNode
+ }
+ /** Copy the position from one old AST node to multiple new nodes. */
+ private def copyPosition[A <: ASTNode](oldNode: A, newNodes: List[A]): List[A] = {
+ for (newNode <- newNodes) yield copyPosition(oldNode, newNode)
+ }
+} \ No newline at end of file
diff --git a/Chalice/src/Translator.scala b/Chalice/src/Translator.scala
index 6e8a4c4b..99fb6fb4 100644
--- a/Chalice/src/Translator.scala
+++ b/Chalice/src/Translator.scala
@@ -431,18 +431,23 @@ class Translator {
def translateStatement(s: Statement, methodK: Expr): List[Stmt] = {
s match {
- case Assert(e) =>
- val newGlobals = etran.FreshGlobals("assert");
- val tmpHeap = Boogie.NewBVar(HeapName, theap, true);
- val tmpMask = Boogie.NewBVar(MaskName, tmask, true);
- val tmpCredits = Boogie.NewBVar(CreditsName, tcredits, true);
- val tmpTranslator = new ExpressionTranslator(List(tmpHeap._1.id, tmpMask._1.id, tmpCredits._1.id), List(etran.ChooseEtran(true).Heap, etran.ChooseEtran(true).Mask, etran.ChooseEtran(true).Credits), currentClass);
- Comment("assert") ::
- // exhale e in a copy of the heap/mask/credits
- BLocal(tmpHeap._1) :: (tmpHeap._2 := etran.Heap) ::
- BLocal(tmpMask._1) :: (tmpMask._2 := etran.Mask) ::
- BLocal(tmpCredits._1) :: (tmpCredits._2 := etran.Credits) ::
- tmpTranslator.Exhale(List((e, ErrorMessage(s.pos, "Assertion might not hold."))), "assert", true, methodK, true)
+ case a@Assert(e) =>
+ a.smokeErrorNr match {
+ case None =>
+ val newGlobals = etran.FreshGlobals("assert");
+ val tmpHeap = Boogie.NewBVar(HeapName, theap, true);
+ val tmpMask = Boogie.NewBVar(MaskName, tmask, true);
+ val tmpCredits = Boogie.NewBVar(CreditsName, tcredits, true);
+ val tmpTranslator = new ExpressionTranslator(List(tmpHeap._1.id, tmpMask._1.id, tmpCredits._1.id), List(etran.ChooseEtran(true).Heap, etran.ChooseEtran(true).Mask, etran.ChooseEtran(true).Credits), currentClass);
+ Comment("assert") ::
+ // exhale e in a copy of the heap/mask/credits
+ BLocal(tmpHeap._1) :: (tmpHeap._2 := etran.Heap) ::
+ BLocal(tmpMask._1) :: (tmpMask._2 := etran.Mask) ::
+ BLocal(tmpCredits._1) :: (tmpCredits._2 := etran.Credits) ::
+ tmpTranslator.Exhale(List((e, ErrorMessage(s.pos, "Assertion might not hold."))), "assert", true, methodK, true)
+ case Some(err) =>
+ bassert(e, a.pos, "SMOKE-TEST-" + err + ".", 0) :: Nil
+ }
case Assume(e) =>
Comment("assume") ::
isDefined(e) :::
@@ -693,7 +698,8 @@ class Translator {
bassume(CallCredits(asyncState) ==@ preCallCredits) ::
bassume(CallArgs(asyncState) ==@ argsSeq) :::
// assign the returned token to the variable
- { if (token != null) List(token := tokenId) else List() }
+ { if (token != null) List(token := tokenId) else List() } :::
+ bassume(wf(VarExpr(HeapName), VarExpr(MaskName))) :: Nil
case jn@JoinAsync(lhs, token) =>
val formalThisV = new Variable("this", new Type(jn.m.Parent))
val formalThis = new VariableExpr(formalThisV)
@@ -1111,7 +1117,8 @@ class Translator {
(for ((v, w) <- duringA zip duringC) yield (new VariableExpr(v) := new VariableExpr(w))) :::
BLocal(m) ::
(me := absTran.Mask) ::
- absTran.Exhale(s.post, me, absTran.Heap, ErrorMessage(r.pos, "Refinement may fail to satisfy specification statement post-condition."), false, todoiparam, todobparam) :::
+ absTran.Exhale(s.post, me, absTran.Heap, ErrorMessage(r.pos, "Refinement may fail to satisfy specification statement post-condition."), false, todoiparam, todobparam, false) :::
+ absTran.Exhale(s.post, me, absTran.Heap, ErrorMessage(r.pos, "Refinement may fail to satisfy specification statement post-condition."), false, todoiparam, todobparam, true) :::
(for ((v, w) <- beforeV zip before; if (! s.lhs.exists(ve => ve.v == w))) yield
bassert(new VariableExpr(v) ==@ new VariableExpr(w), r.pos, "Refinement may change a variable not in frame of the specification statement: " + v.id)),
keepTag)
@@ -1668,7 +1675,12 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
createAppendSeq(Tr(e0), Tr(e1))
case at@At(e0, e1) =>SeqIndex(Tr(e0), Tr(e1))
case Drop(e0, e1) =>
- Boogie.FunctionApp("Seq#Drop", List(Tr(e0), Tr(e1)))
+ e1 match {
+ case IntLiteral(0) =>
+ Tr(e0)
+ case _ =>
+ Boogie.FunctionApp("Seq#Drop", List(Tr(e0), Tr(e1)))
+ }
case Take(e0, e1) =>
Boogie.FunctionApp("Seq#Take", List(Tr(e0), Tr(e1)))
case Length(e) => SeqLength(Tr(e))
@@ -1883,15 +1895,14 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
val (emV, em) = NewBVar("exhaleMask", tmask, true)
Comment("begin exhale (" + occasion + ")") ::
BLocal(emV) :: (em := Mask) ::
- (for (p <- predicates) yield Exhale(p._1, em, null, p._2, check, currentK, exactchecking)).flatten :::
+ (for (p <- predicates) yield Exhale(p._1, em, null, p._2, check, currentK, exactchecking, false)).flatten :::
+ (for (p <- predicates) yield Exhale(p._1, em, null, p._2, check, currentK, exactchecking, true)).flatten :::
(Mask := em) ::
bassume(wf(Heap, Mask)) ::
Comment("end exhale")
}
def ExhalePermission(perm: Permission, obj: Expr, memberName: String, currentK: Expr, pos: Position, error: ErrorMessage, em: Boogie.Expr, exactchecking: Boolean): List[Boogie.Stmt] = {
- val ec = needExactChecking(perm, exactchecking);
-
val (f, stmts) = extractKFromPermission(perm, currentK)
val n = extractEpsilonsFromPermission(perm);
@@ -1899,13 +1910,13 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
(perm.permissionType match {
case PermissionType.Mixed =>
bassert(f > 0 || (f == 0 && n > 0), error.pos, error.message + " The permission at " + pos + " might not be positive.") ::
- DecPermissionBoth(obj, memberName, f, n, em, error, pos, ec)
+ DecPermissionBoth(obj, memberName, f, n, em, error, pos, exactchecking)
case PermissionType.Epsilons =>
bassert(n > 0, error.pos, error.message + " The permission at " + pos + " might not be positive.") ::
DecPermissionEpsilon(obj, memberName, n, em, error, pos)
case PermissionType.Fraction =>
bassert(f > 0, error.pos, error.message + " The permission at " + pos + " might not be positive.") ::
- DecPermission(obj, memberName, f, em, error, pos, ec)
+ DecPermission(obj, memberName, f, em, error, pos, exactchecking)
})
}
@@ -1938,79 +1949,94 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
}
}
- def Exhale(p: Expression, em: Boogie.Expr, eh: Boogie.Expr, error: ErrorMessage, check: Boolean, currentK: Expr, exactchecking: Boolean): List[Boogie.Stmt] = desugar(p) match {
+ // Exhale is done in two passes: In the first run, everything except permissions
+ // which need exact checking are exhaled. Then, in the second run, those
+ // permissions are exhaled. The behaviour is controlled with the parameter
+ // onlyExactCheckingPermissions.
+ // The reason for this behaviour is that we want to support preconditions like
+ // "acc(o.f,100-rd) && acc(o.f,rd)", which should be equivalent to a full
+ // permission to o.f. However, when we exhale in the given order, we cannot
+ // use inexact checking for the abstract read permission ("acc(o.f,rd)"), as
+ // this would introduce the (unsound) assumption that "methodcallk < mask[o.f]".
+ // To avoid detecting this, we exhale all abstract read permissions first (or,
+ // more precisely, we exhale all permissions with exact checking later).
+ def Exhale(p: Expression, em: Boogie.Expr, eh: Boogie.Expr, error: ErrorMessage, check: Boolean, currentK: Expr, exactchecking: Boolean, onlyExactCheckingPermissions: Boolean): List[Boogie.Stmt] = desugar(p) match {
case pred@MemberAccess(e, p) if pred.isPredicate =>
val tmp = Access(pred, Full);
tmp.pos = pred.pos;
- Exhale(tmp, em , eh, error, check, currentK, exactchecking)
+ Exhale(tmp, em , eh, error, check, currentK, exactchecking, onlyExactCheckingPermissions)
case AccessAll(obj, perm) => throw new InternalErrorException("should be desugared")
case AccessSeq(s, None, perm) => throw new InternalErrorException("should be desugared")
case acc@Access(e,perm) =>
- val memberName = if(e.isPredicate) e.predicate.FullName else e.f.FullName;
- val (starKV, starK) = NewBVar("starK", tint, true);
-
- // check definedness
- (if(check) isDefined(e.e)(true) :::
- bassert(nonNull(Tr(e.e)), error.pos, error.message + " The target of the acc predicate at " + acc.pos + " might be null.") else Nil) :::
- // if the mask does not contain sufficient permissions, try folding acc(e, fraction)
- // TODO: include automagic again
- // check that the necessary permissions are there and remove them from the mask
- ExhalePermission(perm, Tr(e.e), memberName, currentK, acc.pos, error, em, exactchecking) :::
- bassume(IsGoodMask(Mask)) ::
- bassume(wf(Heap, Mask)) ::
- bassume(wf(Heap, em))
+ val ec = needExactChecking(perm, exactchecking)
+ if (ec != onlyExactCheckingPermissions) Nil else {
+ val memberName = if(e.isPredicate) e.predicate.FullName else e.f.FullName;
+ val (starKV, starK) = NewBVar("starK", tint, true);
+
+ // check definedness
+ (if(check) isDefined(e.e)(true) :::
+ bassert(nonNull(Tr(e.e)), error.pos, error.message + " The target of the acc predicate at " + acc.pos + " might be null.") else Nil) :::
+ // if the mask does not contain sufficient permissions, try folding acc(e, fraction)
+ // TODO: include automagic again
+ // check that the necessary permissions are there and remove them from the mask
+ ExhalePermission(perm, Tr(e.e), memberName, currentK, acc.pos, error, em, ec) :::
+ bassume(IsGoodMask(Mask)) ::
+ bassume(wf(Heap, Mask)) ::
+ bassume(wf(Heap, em))
+ }
case acc @ AccessSeq(s, Some(member), perm) =>
if (member.isPredicate) throw new NotSupportedException("not yet implemented");
- val e = Tr(s);
- val memberName = member.f.FullName;
-
- val (r, stmts) = extractKFromPermission(perm, currentK)
- val n = extractEpsilonsFromPermission(perm);
val ec = needExactChecking(perm, exactchecking);
-
- stmts :::
- (if (check) isDefined(s)(true) ::: isDefined(perm)(true) else Nil) :::
- {
- val (aV,a) = Boogie.NewTVar("alpha");
- val (refV, ref) = Boogie.NewBVar("ref", tref, true);
- val (fV, f) = Boogie.NewBVar("f", FieldType(a), true);
- val (pcV,pc) = Boogie.NewBVar("p", tperm, true);
- val mr = em(ref, memberName)("perm$R");
- val mn = em(ref, memberName)("perm$N");
+
+ if (ec != onlyExactCheckingPermissions) Nil else {
+ val e = Tr(s);
+ val memberName = member.f.FullName;
+ val (r, stmts) = extractKFromPermission(perm, currentK)
+ val n = extractEpsilonsFromPermission(perm);
- // assert that the permission is positive
- bassert((SeqContains(e, ref) ==>
- (perm.permissionType match {
- case PermissionType.Fraction => r > 0
- case PermissionType.Mixed => r > 0 || (r == 0 && n > 0)
- case PermissionType.Epsilons => n > 0
- })).forall(refV), error.pos, error.message + " The permission at " + acc.pos + " might not be positive.") ::
- // make sure enough permission is available
- bassert((SeqContains(e, ref) ==>
- ((perm,perm.permissionType) match {
- case _ if !ec => mr > 0
- case (Star,_) => mr > 0
- case (_,PermissionType.Fraction) => r <= mr && (r ==@ mr ==> 0 <= mn)
- case (_,PermissionType.Mixed) => r <= mr && (r ==@ mr ==> n <= mn)
- case (_,PermissionType.Epsilons) => mr ==@ 0 ==> n <= mn
- })).forall(refV), error.pos, error.message + " Insufficient permission at " + acc.pos + " for " + member.f.FullName) ::
- // additional assumption on k if we have a star permission or use inexact checking
- ( perm match {
- case _ if !ec => bassume((SeqContains(e, ref) ==> (r < mr)).forall(refV)) :: Nil
- case Star => bassume((SeqContains(e, ref) ==> (r < mr)).forall(refV)) :: Nil
- case _ => Nil
- }) :::
- // update the map
- (em := Lambda(List(aV), List(refV, fV),
- (SeqContains(e, ref) && f ==@ memberName).thenElse(
- Lambda(List(), List(pcV), (pc ==@ "perm$R").thenElse(mr - r, mn - n)),
- em(ref, f))))
- } :::
- bassume(IsGoodMask(Mask)) ::
- bassume(wf(Heap, Mask)) ::
- bassume(wf(Heap, em))
-
- case cr@Credit(ch, n) =>
+ stmts :::
+ (if (check) isDefined(s)(true) ::: isDefined(perm)(true) else Nil) :::
+ {
+ val (aV,a) = Boogie.NewTVar("alpha");
+ val (refV, ref) = Boogie.NewBVar("ref", tref, true);
+ val (fV, f) = Boogie.NewBVar("f", FieldType(a), true);
+ val (pcV,pc) = Boogie.NewBVar("p", tperm, true);
+ val mr = em(ref, memberName)("perm$R");
+ val mn = em(ref, memberName)("perm$N");
+
+ // assert that the permission is positive
+ bassert((SeqContains(e, ref) ==>
+ (perm.permissionType match {
+ case PermissionType.Fraction => r > 0
+ case PermissionType.Mixed => r > 0 || (r == 0 && n > 0)
+ case PermissionType.Epsilons => n > 0
+ })).forall(refV), error.pos, error.message + " The permission at " + acc.pos + " might not be positive.") ::
+ // make sure enough permission is available
+ bassert((SeqContains(e, ref) ==>
+ ((perm,perm.permissionType) match {
+ case _ if !ec => mr > 0
+ case (Star,_) => mr > 0
+ case (_,PermissionType.Fraction) => r <= mr && (r ==@ mr ==> 0 <= mn)
+ case (_,PermissionType.Mixed) => r <= mr && (r ==@ mr ==> n <= mn)
+ case (_,PermissionType.Epsilons) => mr ==@ 0 ==> n <= mn
+ })).forall(refV), error.pos, error.message + " Insufficient permission at " + acc.pos + " for " + member.f.FullName) ::
+ // additional assumption on k if we have a star permission or use inexact checking
+ ( perm match {
+ case _ if !ec => bassume((SeqContains(e, ref) ==> (r < mr)).forall(refV)) :: Nil
+ case Star => bassume((SeqContains(e, ref) ==> (r < mr)).forall(refV)) :: Nil
+ case _ => Nil
+ }) :::
+ // update the map
+ (em := Lambda(List(aV), List(refV, fV),
+ (SeqContains(e, ref) && f ==@ memberName).thenElse(
+ Lambda(List(), List(pcV), (pc ==@ "perm$R").thenElse(mr - r, mn - n)),
+ em(ref, f))))
+ } :::
+ bassume(IsGoodMask(Mask)) ::
+ bassume(wf(Heap, Mask)) ::
+ bassume(wf(Heap, em))
+ }
+ case cr@Credit(ch, n) if !onlyExactCheckingPermissions =>
val trCh = Tr(ch)
(if (check)
isDefined(ch)(true) :::
@@ -2020,14 +2046,14 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
Nil) :::
new Boogie.MapUpdate(Credits, trCh, new Boogie.MapSelect(Credits, trCh) - Tr(cr.N))
case Implies(e0,e1) =>
- (if(check) isDefined(e0)(true) else Nil) :::
- Boogie.If(Tr(e0), Exhale(e1, em, eh, error, check, currentK, exactchecking), Nil)
+ (if(check && !onlyExactCheckingPermissions) isDefined(e0)(true) else Nil) :::
+ Boogie.If(Tr(e0), Exhale(e1, em, eh, error, check, currentK, exactchecking, onlyExactCheckingPermissions), Nil)
case IfThenElse(con, then, els) =>
(if(check) isDefined(con)(true) else Nil) :::
- Boogie.If(Tr(con), Exhale(then, em, eh, error, check, currentK, exactchecking), Exhale(els, em, eh, error, check, currentK, exactchecking))
+ Boogie.If(Tr(con), Exhale(then, em, eh, error, check, currentK, exactchecking, onlyExactCheckingPermissions), Exhale(els, em, eh, error, check, currentK, exactchecking, onlyExactCheckingPermissions))
case And(e0,e1) =>
- Exhale(e0, em, eh, error, check, currentK, exactchecking) ::: Exhale(e1, em, eh, error, check, currentK, exactchecking)
- case holds@Holds(e) =>
+ Exhale(e0, em, eh, error, check, currentK, exactchecking, onlyExactCheckingPermissions) ::: Exhale(e1, em, eh, error, check, currentK, exactchecking, onlyExactCheckingPermissions)
+ case holds@Holds(e) if !onlyExactCheckingPermissions =>
(if(check) isDefined(e)(true) :::
bassert(nonNull(Tr(e)), error.pos, error.message + " The target of the holds predicate at " + holds.pos + " might be null.") :: Nil else Nil) :::
bassert(0 < new Boogie.MapSelect(Heap, Tr(e), "held"), error.pos, error.message + " The current thread might not hold lock at " + holds.pos + ".") ::
@@ -2035,7 +2061,7 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
bassume(IsGoodMask(Mask)) ::
bassume(wf(Heap, Mask)) ::
bassume(wf(Heap, em))
- case Eval(h, e) =>
+ case Eval(h, e) if !onlyExactCheckingPermissions =>
val (evalHeap, evalMask, evalCredits, checks, proofOrAssume) = fromEvalState(h);
val preGlobals = etran.FreshGlobals("eval")
val preEtran = new ExpressionTranslator(List(Boogie.VarExpr(preGlobals(0).id), Boogie.VarExpr(preGlobals(1).id), Boogie.VarExpr(preGlobals(2).id)), currentClass);
@@ -2047,7 +2073,8 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
bassume(wf(preEtran.Heap, preEtran.Mask)) ::
bassert(proofOrAssume, p.pos, "Arguments for joinable might not match up.") ::
preEtran.Exhale(List((e, error)), "eval", check, currentK, exactchecking)
- case e => (if(check) isDefined(e)(true) else Nil) ::: List(bassert(Tr(e), error.pos, error.message + " The expression at " + e.pos + " might not evaluate to true."))
+ case e if !onlyExactCheckingPermissions => (if(check) isDefined(e)(true) else Nil) ::: List(bassert(Tr(e), error.pos, error.message + " The expression at " + e.pos + " might not evaluate to true."))
+ case _ => Nil
}
def extractKFromPermission(expr: Permission, currentK: Expr): (Expr, List[Boogie.Stmt]) = expr match {
@@ -2321,6 +2348,7 @@ object TranslationHelper {
def TypeName = NamedType("TypeName");
def FieldType(tp: BType) = IndexedType("Field", tp);
def bassert(e: Expr, pos: Position, msg: String) = new Boogie.Assert(e, pos, msg)
+ def bassert(e: Expr, pos: Position, msg: String, subsumption: Int) = new Boogie.Assert(e, pos, msg, subsumption)
def bassume(e: Expr) = Boogie.Assume(e)
def BLocal(id: String, tp: BType) = new Boogie.LocalVar(id, tp)
def BLocal(x: Boogie.BVar) = Boogie.LocalVar(x)
diff --git a/Chalice/tests/examples/AssociationList.output.txt b/Chalice/tests/examples/AssociationList.output.txt
index 618d878a..bfff3c60 100644
--- a/Chalice/tests/examples/AssociationList.output.txt
+++ b/Chalice/tests/examples/AssociationList.output.txt
@@ -1,6 +1,10 @@
Verification of AssociationList.chalice using parameters=""
- 19.3: The postcondition at 21.13 might not hold. Insufficient fraction at 21.13 for mu.
- 64.9: Method execution before loop might lock/unlock more than allowed by lockchange clause of loop.
-
-Boogie program verifier finished with 10 verified, 2 errors
+ 19.3: The postcondition at 21.13 might not hold. Insufficient fraction at 21.13 for mu.
+ 64.9: Method execution before loop might lock/unlock more than allowed by lockchange clause of loop.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+ 64.9: The begging of the while-body is unreachable.
+ 64.9: The statements after the while-loop are unreachable.
+
+Boogie program verifier finished with 2 errors and 2 smoke test warnings.
diff --git a/Chalice/tests/examples/BackgroundComputation.output.txt b/Chalice/tests/examples/BackgroundComputation.output.txt
index c139677a..dc1bafc1 100644
--- a/Chalice/tests/examples/BackgroundComputation.output.txt
+++ b/Chalice/tests/examples/BackgroundComputation.output.txt
@@ -1,4 +1,4 @@
Verification of BackgroundComputation.chalice using parameters=""
-
-Boogie program verifier finished with 7 verified, 0 errors
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/examples/CopyLessMessagePassing-with-ack.chalice b/Chalice/tests/examples/CopyLessMessagePassing-with-ack.chalice
index 2646f96a..9ed9f0a9 100644
--- a/Chalice/tests/examples/CopyLessMessagePassing-with-ack.chalice
+++ b/Chalice/tests/examples/CopyLessMessagePassing-with-ack.chalice
@@ -8,6 +8,7 @@
// Why: Suppose a channel that allows self-debt is involved in a deadlock. The either that channel is empty, which means there's no difference between the situation with or with self-debt. Or the channel is non-empty. This means that we can make progress by receiving the message stored in the channel! Does this make any sense?
channel C(msg: int, n: Node) where
+ (msg == 0 || msg == 1 || msg == 2) &&
(msg == 0 ==> credit(this, -1)) && // ack
(msg == 1 ==> n != null && acc(n.next) && acc(n.mu) && credit(this, -1)) && // cell
(msg == 2 ==> acc(this.mu, 50)); // done
@@ -55,17 +56,20 @@ class Program {
var x: Node := null;
var msg := 1;
while(msg != 0)
- invariant acc(f.mu, 50) && waitlevel << f.mu && (msg == 1 ==> credit(f, 1)) && (msg == 0 ==> acc(f.mu, 50));
+ invariant msg == 0 || msg == 1;
+ invariant acc(f.mu, 50) && waitlevel << f.mu && (credit(f, 1));
{
+ assert msg == 1
receive msg, x := f;
- if(msg == 0) {
- }
+
if(msg == 1) {
free x;
- send f(2, null);
}
- if(msg != 0 || msg != 1) { assume false; /* abort */ }
+ send f(0, null);
+ if(msg == 2) { assume false; /* abort */ }
}
+ receive msg, x := f;
+ if (msg != 2) { assume false; /* abort */ }
free f; // close the channel
}
diff --git a/Chalice/tests/examples/CopyLessMessagePassing-with-ack.output.txt b/Chalice/tests/examples/CopyLessMessagePassing-with-ack.output.txt
index 4099f78a..b47290ea 100644
--- a/Chalice/tests/examples/CopyLessMessagePassing-with-ack.output.txt
+++ b/Chalice/tests/examples/CopyLessMessagePassing-with-ack.output.txt
@@ -1,4 +1,8 @@
Verification of CopyLessMessagePassing-with-ack.chalice using parameters=""
-
-Boogie program verifier finished with 11 verified, 0 errors
+
+ 48.22: Assumption introduces a contradiction.
+ 69.22: Assumption introduces a contradiction.
+ 72.21: Assumption introduces a contradiction.
+
+Boogie program verifier finished with 0 errors and 3 smoke test warnings.
diff --git a/Chalice/tests/examples/CopyLessMessagePassing-with-ack2.chalice b/Chalice/tests/examples/CopyLessMessagePassing-with-ack2.chalice
index 7744d291..77e0018d 100644
--- a/Chalice/tests/examples/CopyLessMessagePassing-with-ack2.chalice
+++ b/Chalice/tests/examples/CopyLessMessagePassing-with-ack2.chalice
@@ -11,10 +11,9 @@
channel AckChannel(ch: C) where ch != null && credit(ch, -1); // ack
-channel C(msg: int, n: Node, ackC: AckChannel) where
- (msg == 0 || msg == 1) &&
- (msg == 0 ==> acc(this.mu, 50) && acc(ackC.mu, 50)) &&
- (msg == 1 ==> n != null && acc(n.next) && acc(n.mu) && credit(ackC, -1)); // cell
+channel C(msg: bool, n: Node, ackC: AckChannel) where
+ (!msg ==> acc(this.mu, 50) && acc(ackC.mu, 50)) &&
+ (msg ==> n != null && acc(n.next) && acc(n.mu) && credit(ackC, -1)); // cell
class Node {
var next: Node;
@@ -42,7 +41,7 @@ class Program {
{
unfold x.list;
t := x.next;
- send e(1, x, ackC);
+ send e(true, x, ackC);
x := t;
var ack;
assume waitlevel << ackC.mu; // Chalice should be able to figure this out itself?
@@ -50,23 +49,21 @@ class Program {
receive ctmp := ackC;
if(ctmp != e) { assume false; /* abort */ }
}
- send e(0, null, ackC);
+ send e(false, null, ackC);
}
method Getter(f: C, ackC: AckChannel)
requires f!= null && credit(f, 1) && acc(f.mu, 50) && waitlevel << f.mu && ackC != null && acc(ackC.mu, 50) && f.mu << ackC.mu;
{
var x: Node := null;
- var msg := 1;
- while(msg != 0)
- invariant acc(f.mu, 50) && waitlevel << f.mu && (msg == 1 ==> credit(f, 1)) && (msg == 0 ==> acc(f.mu, 50) && acc(ackC.mu, 50));
+ var msg: bool := true;
+ while(msg)
+ invariant acc(f.mu, 50) && waitlevel << f.mu && (msg ==> credit(f, 1)) && (!msg ==> acc(f.mu, 50) && acc(ackC.mu, 50));
{
var ackC2: AckChannel;
receive msg, x, ackC2 := f;
if(ackC2 != ackC) { assume false; /* abort */ }
- if(msg == 0) {
- }
- if(msg == 1) {
+ if(msg) {
free x;
send ackC(f);
}
diff --git a/Chalice/tests/examples/CopyLessMessagePassing-with-ack2.output.txt b/Chalice/tests/examples/CopyLessMessagePassing-with-ack2.output.txt
index 6ba69de5..42a63bf1 100644
--- a/Chalice/tests/examples/CopyLessMessagePassing-with-ack2.output.txt
+++ b/Chalice/tests/examples/CopyLessMessagePassing-with-ack2.output.txt
@@ -1,4 +1,7 @@
Verification of CopyLessMessagePassing-with-ack2.chalice using parameters=""
-
-Boogie program verifier finished with 12 verified, 0 errors
+
+ 50.23: Assumption introduces a contradiction.
+ 65.27: Assumption introduces a contradiction.
+
+Boogie program verifier finished with 0 errors and 2 smoke test warnings.
diff --git a/Chalice/tests/examples/CopyLessMessagePassing.chalice b/Chalice/tests/examples/CopyLessMessagePassing.chalice
index 4b8a9389..3a9b80e0 100644
--- a/Chalice/tests/examples/CopyLessMessagePassing.chalice
+++ b/Chalice/tests/examples/CopyLessMessagePassing.chalice
@@ -5,7 +5,7 @@
// todo: accept ack message before sending the next one (requires sending negative credit!)
-channel C(msg: int, n: Node) where n!= null && acc(n.next) && acc(n.mu) && (msg == 1 ==> credit(this, 1)) && (msg == 0 ==> acc(this.mu, 50));
+channel C(msg: bool, n: Node) where n!= null && acc(n.next) && acc(n.mu) && (msg ==> credit(this, 1)) && (!msg ==> acc(this.mu, 50));
class Node {
var next: Node;
@@ -34,9 +34,9 @@ class Program {
unfold x.list;
t := x.next;
if(t != null) {
- send e(1, x);
+ send e(true, x);
} else {
- send e(0, x);
+ send e(false, x);
}
x := t;
}
@@ -46,12 +46,12 @@ class Program {
requires f!= null && credit(f, 1) && acc(f.mu, 50) && waitlevel << f.mu;
{
var x: Node := null;
- var msg := 1;
- while(msg != 0)
- invariant acc(f.mu, 50) && waitlevel << f.mu && (msg == 1 ==> credit(f, 1)) && (msg == 0 ==> acc(f.mu, 50));
+ var msg: bool := true;
+ while(msg)
+ invariant acc(f.mu, 50) && waitlevel << f.mu && (msg ==> credit(f, 1)) && (!msg ==> acc(f.mu, 50));
{
receive msg, x := f;
- if(msg == 1) {
+ if(msg) {
free x;
}
}
diff --git a/Chalice/tests/examples/CopyLessMessagePassing.output.txt b/Chalice/tests/examples/CopyLessMessagePassing.output.txt
index 859c9998..26784a86 100644
--- a/Chalice/tests/examples/CopyLessMessagePassing.output.txt
+++ b/Chalice/tests/examples/CopyLessMessagePassing.output.txt
@@ -1,4 +1,4 @@
Verification of CopyLessMessagePassing.chalice using parameters=""
-
-Boogie program verifier finished with 11 verified, 0 errors
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/examples/FictionallyDisjointCells.output.txt b/Chalice/tests/examples/FictionallyDisjointCells.output.txt
index 1dc7a7b1..9bc4fb68 100644
--- a/Chalice/tests/examples/FictionallyDisjointCells.output.txt
+++ b/Chalice/tests/examples/FictionallyDisjointCells.output.txt
@@ -1,4 +1,4 @@
Verification of FictionallyDisjointCells.chalice using parameters=""
-
-Boogie program verifier finished with 12 verified, 0 errors
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/examples/ForkJoin.output.txt b/Chalice/tests/examples/ForkJoin.output.txt
index ed2abbda..b1371da7 100644
--- a/Chalice/tests/examples/ForkJoin.output.txt
+++ b/Chalice/tests/examples/ForkJoin.output.txt
@@ -1,4 +1,4 @@
Verification of ForkJoin.chalice using parameters=""
-
-Boogie program verifier finished with 18 verified, 0 errors
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/examples/HandOverHand.output.txt b/Chalice/tests/examples/HandOverHand.output.txt
index de7ab98c..5d32ad2e 100644
--- a/Chalice/tests/examples/HandOverHand.output.txt
+++ b/Chalice/tests/examples/HandOverHand.output.txt
@@ -1,4 +1,4 @@
Verification of HandOverHand.chalice using parameters=""
-
-Boogie program verifier finished with 10 verified, 0 errors
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/examples/ImplicitLocals.output.txt b/Chalice/tests/examples/ImplicitLocals.output.txt
index 4d7b08b1..db26bba6 100644
--- a/Chalice/tests/examples/ImplicitLocals.output.txt
+++ b/Chalice/tests/examples/ImplicitLocals.output.txt
@@ -1,4 +1,4 @@
Verification of ImplicitLocals.chalice using parameters=""
-
-Boogie program verifier finished with 8 verified, 0 errors
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/examples/LoopLockChange.output.txt b/Chalice/tests/examples/LoopLockChange.output.txt
index 7a03627f..19e84f93 100644
--- a/Chalice/tests/examples/LoopLockChange.output.txt
+++ b/Chalice/tests/examples/LoopLockChange.output.txt
@@ -1,7 +1,12 @@
Verification of LoopLockChange.chalice using parameters=""
- 10.5: Method execution before loop might lock/unlock more than allowed by lockchange clause of loop.
- 35.5: The loop might lock/unlock more than the lockchange clause allows.
- 65.5: The loop might lock/unlock more than the lockchange clause allows.
-
-Boogie program verifier finished with 14 verified, 3 errors
+ 10.5: Method execution before loop might lock/unlock more than allowed by lockchange clause of loop.
+ 35.5: The loop might lock/unlock more than the lockchange clause allows.
+ 65.5: The loop might lock/unlock more than the lockchange clause allows.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+ 10.5: The begging of the while-body is unreachable.
+ 10.5: The statements after the while-loop are unreachable.
+ 75.5: Assumption introduces a contradiction.
+
+Boogie program verifier finished with 3 errors and 3 smoke test warnings.
diff --git a/Chalice/tests/examples/OwickiGries.output.txt b/Chalice/tests/examples/OwickiGries.output.txt
index a56e7442..3a9a215b 100644
--- a/Chalice/tests/examples/OwickiGries.output.txt
+++ b/Chalice/tests/examples/OwickiGries.output.txt
@@ -1,4 +1,4 @@
Verification of OwickiGries.chalice using parameters=""
-
-Boogie program verifier finished with 5 verified, 0 errors
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/examples/PetersonsAlgorithm.output.txt b/Chalice/tests/examples/PetersonsAlgorithm.output.txt
index 5bc49aaa..eddb4927 100644
--- a/Chalice/tests/examples/PetersonsAlgorithm.output.txt
+++ b/Chalice/tests/examples/PetersonsAlgorithm.output.txt
@@ -1,4 +1,8 @@
Verification of PetersonsAlgorithm.chalice using parameters=""
-
-Boogie program verifier finished with 7 verified, 0 errors
+
+ 23.5: The statements after the while-loop are unreachable.
+ 34.5: The statements after the while-loop are unreachable.
+ 59.5: The statements after the while-loop are unreachable.
+
+Boogie program verifier finished with 0 errors and 3 smoke test warnings.
diff --git a/Chalice/tests/examples/ProdConsChannel.output.txt b/Chalice/tests/examples/ProdConsChannel.output.txt
index de5e8467..167898fb 100644
--- a/Chalice/tests/examples/ProdConsChannel.output.txt
+++ b/Chalice/tests/examples/ProdConsChannel.output.txt
@@ -1,8 +1,11 @@
Verification of ProdConsChannel.chalice using parameters=""
- 47.3: Method body is not allowed to leave any debt.
- 61.3: Method body is not allowed to leave any debt.
- 85.20: Location might not be readable.
- 123.7: Assertion might not hold. The expression at 123.14 might not evaluate to true.
-
-Boogie program verifier finished with 19 verified, 4 errors
+ 47.3: Method body is not allowed to leave any debt.
+ 61.3: Method body is not allowed to leave any debt.
+ 85.20: Location might not be readable.
+ 123.7: Assertion might not hold. The expression at 123.14 might not evaluate to true.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+ 80.5: The end of the while-loop is unreachable.
+
+Boogie program verifier finished with 4 errors and 1 smoke test warnings.
diff --git a/Chalice/tests/examples/RockBand-automagic.output.txt b/Chalice/tests/examples/RockBand-automagic.output.txt
index 9ce4b436..2e62b457 100644
--- a/Chalice/tests/examples/RockBand-automagic.output.txt
+++ b/Chalice/tests/examples/RockBand-automagic.output.txt
@@ -1,8 +1,4 @@
Verification of RockBand-automagic.chalice using parameters="-checkLeaks -defaults -autoFold -autoMagic"
- 20.27: Location might not be readable.
- 28.3: Method RockBand.Init might leak references.
- 42.10: Location might not be readable.
- 51.5: Location might not be writable
-
-Boogie program verifier finished with 31 verified, 4 errors
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/examples/RockBand.output.txt b/Chalice/tests/examples/RockBand.output.txt
index a52b021b..94f92a6e 100644
--- a/Chalice/tests/examples/RockBand.output.txt
+++ b/Chalice/tests/examples/RockBand.output.txt
@@ -1,4 +1,4 @@
Verification of RockBand.chalice using parameters="-checkLeaks -defaults -autoFold"
-
-Boogie program verifier finished with 35 verified, 0 errors
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/examples/Sieve.output.txt b/Chalice/tests/examples/Sieve.output.txt
index 93271d87..3e5117d3 100644
--- a/Chalice/tests/examples/Sieve.output.txt
+++ b/Chalice/tests/examples/Sieve.output.txt
@@ -1,4 +1,4 @@
Verification of Sieve.chalice using parameters=""
-
-Boogie program verifier finished with 11 verified, 0 errors
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/examples/SmokeTestTest.chalice b/Chalice/tests/examples/SmokeTestTest.chalice
new file mode 100644
index 00000000..2f32625e
--- /dev/null
+++ b/Chalice/tests/examples/SmokeTestTest.chalice
@@ -0,0 +1,112 @@
+// This file is meant as a test for Chalice's smoke testing feature (command line switch -smoke)
+class Cell {
+ var f: int;
+
+ method a1()
+ requires false // SMOKE: precondition is false
+ {}
+
+ method a2()
+ requires acc(this.f,-2) // SMOKE: precondition is equivalent to false
+ {}
+
+ method a3()
+ requires acc(this.f)
+ {
+ if (this.f > 0) {
+ this.f := 0;
+ }
+ }
+
+ method a4()
+ requires acc(this.f)
+ {
+ if (false) {
+ this.f := 0; // SMOKE: unreachable
+ }
+ }
+
+ method a5()
+ requires acc(this.f)
+ {
+ if (true) {
+ this.f := 0;
+ }
+ }
+
+ method a6()
+ requires acc(this.f)
+ {
+ if (false) {
+ this.f := 0; // SMOKE: unreachable
+ } else {
+ this.f := 1;
+ }
+ }
+
+ method a7(i: int, j: int)
+ requires i != j;
+ {
+ assume i == j; // SMOKE: introduces contradiction
+ }
+
+ method a8()
+ requires acc(this.f)
+ {
+ while (true)
+ invariant acc(this.f)
+ {
+ this.f := this.f + 1
+ }
+ // SMOKE: unreachable, loop does not terminate
+ }
+
+ method a9()
+ requires acc(this.f)
+ {
+ call a8()
+ }
+
+ method a10()
+ requires acc(this.f)
+ {
+ if (true) {
+ this.f := 0;
+ } else {
+ this.f := 1; // SMOKE: unreachable
+ }
+ }
+
+ function f1(): int
+ requires false // SMOKE: precondition is false
+ { 1 }
+
+ method a11()
+ {
+ var i: int := 0
+ if (false) {
+ // SMOKE: unreachable
+ } else {
+ if (true) { assume false } // SMOKE: introduces contradiction
+ else { assume i == 1 } // SMOKE: introduces contradiction
+ }
+ }
+
+ method a12()
+ {
+ assume false // SMOKE: introduces contradiction
+ while (false) {
+
+ }
+ }
+
+ method a13()
+ ensures false // ERROR: cannot prove false
+ {
+ }
+
+ method a14()
+ {
+ call a13(); // SMOKE: statements afterwards not reachable anymore
+ }
+}
diff --git a/Chalice/tests/examples/SmokeTestTest.output.txt b/Chalice/tests/examples/SmokeTestTest.output.txt
new file mode 100644
index 00000000..0d7985d6
--- /dev/null
+++ b/Chalice/tests/examples/SmokeTestTest.output.txt
@@ -0,0 +1,19 @@
+Verification of SmokeTestTest.chalice using parameters=""
+
+ 103.3: The postcondition at 104.13 might not hold. The expression at 104.13 might not evaluate to true.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+ 5.3: Precondition of method a1 is equivalent to false.
+ 9.3: Precondition of method a2 is equivalent to false.
+ 24.5: The begging of the if-branch is unreachable.
+ 40.5: The begging of the if-branch is unreachable.
+ 50.5: Assumption introduces a contradiction.
+ 56.5: The statements after the while-loop are unreachable.
+ 73.5: The begging of the else-branch is unreachable.
+ 87.5: The begging of the if-branch is unreachable.
+ 90.7: The begging of the else-branch is unreachable.
+ 90.19: Assumption introduces a contradiction.
+ 97.5: Assumption introduces a contradiction.
+ 110.5: The statements after the method call statement are unreachable.
+
+Boogie program verifier finished with 1 errors and 12 smoke test warnings.
diff --git a/Chalice/tests/examples/Solver.output.txt b/Chalice/tests/examples/Solver.output.txt
index e88f63d9..1ec04d27 100644
--- a/Chalice/tests/examples/Solver.output.txt
+++ b/Chalice/tests/examples/Solver.output.txt
@@ -1,4 +1,4 @@
Verification of Solver.chalice using parameters=""
-
-Boogie program verifier finished with 10 verified, 0 errors
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/examples/TreeOfWorker.output.txt b/Chalice/tests/examples/TreeOfWorker.output.txt
index 4dc67e3c..13932da9 100644
--- a/Chalice/tests/examples/TreeOfWorker.output.txt
+++ b/Chalice/tests/examples/TreeOfWorker.output.txt
@@ -1,4 +1,4 @@
Verification of TreeOfWorker.chalice using parameters=""
-
-Boogie program verifier finished with 5 verified, 0 errors
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/examples/UnboundedThreads.output.txt b/Chalice/tests/examples/UnboundedThreads.output.txt
index efd70a6d..bd34d380 100644
--- a/Chalice/tests/examples/UnboundedThreads.output.txt
+++ b/Chalice/tests/examples/UnboundedThreads.output.txt
@@ -1,5 +1,6 @@
Verification of UnboundedThreads.chalice using parameters=""
- 40.17: The loop invariant at 40.17 might not be preserved by the loop. Insufficient epsilons at 40.27 for C.f.
-
-Boogie program verifier finished with 6 verified, 1 error
+ 40.17: The loop invariant at 40.17 might not be preserved by the loop. Insufficient epsilons at 40.27 for C.f.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+Boogie program verifier finished with 1 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/examples/cell-defaults.output.txt b/Chalice/tests/examples/cell-defaults.output.txt
index 0f7a3b80..138a5717 100644
--- a/Chalice/tests/examples/cell-defaults.output.txt
+++ b/Chalice/tests/examples/cell-defaults.output.txt
@@ -1,7 +1,10 @@
Verification of cell-defaults.chalice using parameters="-defaults -autoFold -autoMagic"
- 97.5: The heap of the callee might not be strictly smaller than the heap of the caller.
- 103.5: The heap of the callee might not be strictly smaller than the heap of the caller.
- 132.5: Assertion might not hold. Insufficient fraction at 132.12 for Cell.valid.
-
-Boogie program verifier finished with 29 verified, 3 errors
+ 97.5: The heap of the callee might not be strictly smaller than the heap of the caller.
+ 103.5: The heap of the callee might not be strictly smaller than the heap of the caller.
+ 132.5: Assertion might not hold. Insufficient fraction at 132.12 for Cell.valid.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+ 125.3: The end of method main2 is unreachable.
+
+Boogie program verifier finished with 3 errors and 1 smoke test warnings.
diff --git a/Chalice/tests/examples/cell.output.txt b/Chalice/tests/examples/cell.output.txt
index 2c6c617d..b5ba1586 100644
--- a/Chalice/tests/examples/cell.output.txt
+++ b/Chalice/tests/examples/cell.output.txt
@@ -1,5 +1,8 @@
Verification of cell.chalice using parameters=""
- 142.5: Assertion might not hold. Insufficient fraction at 142.12 for Cell.valid.
-
-Boogie program verifier finished with 31 verified, 1 error
+ 142.5: Assertion might not hold. Insufficient fraction at 142.12 for Cell.valid.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+ 135.3: The end of method main2 is unreachable.
+
+Boogie program verifier finished with 1 errors and 1 smoke test warnings.
diff --git a/Chalice/tests/examples/counter.output.txt b/Chalice/tests/examples/counter.output.txt
index 961b1413..1d5be0ea 100644
--- a/Chalice/tests/examples/counter.output.txt
+++ b/Chalice/tests/examples/counter.output.txt
@@ -1,10 +1,17 @@
Verification of counter.chalice using parameters=""
- 69.5: Monitor invariant might hot hold. The expression at 4.27 might not evaluate to true.
- 80.5: Assertion might not hold. The expression at 80.12 might not evaluate to true.
- 119.5: The target of the release statement might not be locked by the current thread.
- 128.7: The mu field of the target of the acquire statement might not be above waitlevel.
- 136.7: The mu field of the target of the acquire statement might not be above waitlevel.
- 145.5: The target of the release statement might not be locked by the current thread.
-
-Boogie program verifier finished with 24 verified, 6 errors
+ 69.5: Monitor invariant might hot hold. The expression at 4.27 might not evaluate to true.
+ 80.5: Assertion might not hold. The expression at 80.12 might not evaluate to true.
+ 119.5: The target of the release statement might not be locked by the current thread.
+ 128.7: The mu field of the target of the acquire statement might not be above waitlevel.
+ 136.7: The mu field of the target of the acquire statement might not be above waitlevel.
+ 145.5: The target of the release statement might not be locked by the current thread.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+ 62.3: The end of method main4 is unreachable.
+ 116.3: The end of method nestedBad0 is unreachable.
+ 128.7: The statements after the acquire statement are unreachable.
+ 136.7: The begging of the lock-block is unreachable.
+ 141.3: The end of method nestedBad3 is unreachable.
+
+Boogie program verifier finished with 6 errors and 5 smoke test warnings.
diff --git a/Chalice/tests/examples/dining-philosophers.output.txt b/Chalice/tests/examples/dining-philosophers.output.txt
index 651bd638..bd1bd4a0 100644
--- a/Chalice/tests/examples/dining-philosophers.output.txt
+++ b/Chalice/tests/examples/dining-philosophers.output.txt
@@ -1,4 +1,6 @@
Verification of dining-philosophers.chalice using parameters=""
-
-Boogie program verifier finished with 12 verified, 0 errors
+
+ 24.5: The statements after the while-loop are unreachable.
+
+Boogie program verifier finished with 0 errors and 1 smoke test warnings.
diff --git a/Chalice/tests/examples/iterator.output.txt b/Chalice/tests/examples/iterator.output.txt
index de361b94..a33f44db 100644
--- a/Chalice/tests/examples/iterator.output.txt
+++ b/Chalice/tests/examples/iterator.output.txt
@@ -1,4 +1,4 @@
Verification of iterator.chalice using parameters=""
-
-Boogie program verifier finished with 22 verified, 0 errors
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/examples/iterator2.output.txt b/Chalice/tests/examples/iterator2.output.txt
index af837e6f..02a7f02d 100644
--- a/Chalice/tests/examples/iterator2.output.txt
+++ b/Chalice/tests/examples/iterator2.output.txt
@@ -1,4 +1,4 @@
Verification of iterator2.chalice using parameters=""
-
-Boogie program verifier finished with 21 verified, 0 errors
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/examples/linkedlist.output.txt b/Chalice/tests/examples/linkedlist.output.txt
index 65f03446..468e5921 100644
--- a/Chalice/tests/examples/linkedlist.output.txt
+++ b/Chalice/tests/examples/linkedlist.output.txt
@@ -1,5 +1,6 @@
Verification of linkedlist.chalice using parameters=""
- 49.39: Precondition at 47.14 might not hold. The expression at 47.31 might not evaluate to true.
-
-Boogie program verifier finished with 9 verified, 1 error
+ 49.39: Precondition at 47.14 might not hold. The expression at 47.31 might not evaluate to true.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+Boogie program verifier finished with 1 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/examples/producer-consumer.output.txt b/Chalice/tests/examples/producer-consumer.output.txt
index b21044bb..55f4bf3c 100644
--- a/Chalice/tests/examples/producer-consumer.output.txt
+++ b/Chalice/tests/examples/producer-consumer.output.txt
@@ -1,4 +1,7 @@
Verification of producer-consumer.chalice using parameters=""
-
-Boogie program verifier finished with 36 verified, 0 errors
+
+ 42.5: The statements after the while-loop are unreachable.
+ 81.5: The statements after the while-loop are unreachable.
+
+Boogie program verifier finished with 0 errors and 2 smoke test warnings.
diff --git a/Chalice/tests/examples/prog1.output.txt b/Chalice/tests/examples/prog1.output.txt
index 61938bf7..630ecdfa 100644
--- a/Chalice/tests/examples/prog1.output.txt
+++ b/Chalice/tests/examples/prog1.output.txt
@@ -1,11 +1,19 @@
Verification of prog1.chalice using parameters=""
- 9.10: Location might not be readable.
- 25.5: Location might not be writable
- 33.14: Location might not be readable.
- 42.5: Monitor invariant might hot hold. The expression at 5.23 might not evaluate to true.
- 60.5: Location might not be writable
- 76.5: The target of the unshare statement might not be shared.
- 84.5: The target of the unshare statement might not be shared.
-
-Boogie program verifier finished with 16 verified, 7 errors
+ 9.10: Location might not be readable.
+ 25.5: Location might not be writable
+ 33.14: Location might not be readable.
+ 42.5: Monitor invariant might hot hold. The expression at 5.23 might not evaluate to true.
+ 60.5: Location might not be writable
+ 76.5: The target of the unshare statement might not be shared.
+ 84.5: The target of the unshare statement might not be shared.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+ 7.3: The end of method seq0 is unreachable.
+ 21.3: The end of method seq3 is unreachable.
+ 28.3: The end of method main0 is unreachable.
+ 53.3: The end of method main3 is unreachable.
+ 73.3: The end of method main5 is unreachable.
+ 78.3: The end of method main6 is unreachable.
+
+Boogie program verifier finished with 7 errors and 6 smoke test warnings.
diff --git a/Chalice/tests/examples/prog2.output.txt b/Chalice/tests/examples/prog2.output.txt
index b3ea3e93..b9d88bbe 100644
--- a/Chalice/tests/examples/prog2.output.txt
+++ b/Chalice/tests/examples/prog2.output.txt
@@ -1,8 +1,13 @@
Verification of prog2.chalice using parameters=""
- 24.5: Assertion might not hold. The expression at 24.12 might not evaluate to true.
- 31.13: Location might not be readable.
- 73.5: Const variable can be assigned to only once.
- 78.5: Assertion might not hold. The expression at 78.12 might not evaluate to true.
-
-Boogie program verifier finished with 24 verified, 4 errors
+ 24.5: Assertion might not hold. The expression at 24.12 might not evaluate to true.
+ 31.13: Location might not be readable.
+ 73.5: Const variable can be assigned to only once.
+ 78.5: Assertion might not hold. The expression at 78.12 might not evaluate to true.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+ 20.3: The end of method Caller1 is unreachable.
+ 39.5: The statements after the method call statement are unreachable.
+ 70.3: The end of method M2 is unreachable.
+
+Boogie program verifier finished with 4 errors and 3 smoke test warnings.
diff --git a/Chalice/tests/examples/prog3.output.txt b/Chalice/tests/examples/prog3.output.txt
index 82eeab18..18d05658 100644
--- a/Chalice/tests/examples/prog3.output.txt
+++ b/Chalice/tests/examples/prog3.output.txt
@@ -1,8 +1,11 @@
Verification of prog3.chalice using parameters=""
- 76.3: The postcondition at 77.13 might not hold. The expression at 77.13 might not evaluate to true.
- 76.3: Method might lock/unlock more than allowed.
- 191.5: The precondition at 182.14 might not hold. Insufficient epsilons at 182.14 for ReadSharing.x.
- 202.3: The postcondition at 204.13 might not hold. Insufficient epsilons at 204.13 for ReadSharing.x.
-
-Boogie program verifier finished with 51 verified, 4 errors
+ 76.3: The postcondition at 77.13 might not hold. The expression at 77.13 might not evaluate to true.
+ 76.3: Method might lock/unlock more than allowed.
+ 191.5: The precondition at 182.14 might not hold. Insufficient epsilons at 182.14 for ReadSharing.x.
+ 202.3: The postcondition at 204.13 might not hold. Insufficient epsilons at 204.13 for ReadSharing.x.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+ 191.5: The statements after the method call statement are unreachable.
+
+Boogie program verifier finished with 4 errors and 1 smoke test warnings.
diff --git a/Chalice/tests/examples/prog4.output.txt b/Chalice/tests/examples/prog4.output.txt
index 62197afb..9415df7c 100644
--- a/Chalice/tests/examples/prog4.output.txt
+++ b/Chalice/tests/examples/prog4.output.txt
@@ -1,11 +1,14 @@
Verification of prog4.chalice using parameters=""
- 5.5: Assertion might not hold. The expression at 5.12 might not evaluate to true.
- 17.7: The target of the release statement might not be locked by the current thread.
- 17.7: Release might fail because the current thread might hold the read lock.
- 30.7: The target of the release statement might not be locked by the current thread.
- 30.7: Release might fail because the current thread might hold the read lock.
- 34.5: The target of the release statement might not be locked by the current thread.
- 34.5: Release might fail because the current thread might hold the read lock.
-
-Boogie program verifier finished with 6 verified, 7 errors
+ 5.5: Assertion might not hold. The expression at 5.12 might not evaluate to true.
+ 17.7: The target of the release statement might not be locked by the current thread.
+ 17.7: Release might fail because the current thread might hold the read lock.
+ 30.7: The target of the release statement might not be locked by the current thread.
+ 30.7: Release might fail because the current thread might hold the read lock.
+ 34.5: The target of the release statement might not be locked by the current thread.
+ 34.5: Release might fail because the current thread might hold the read lock.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+ 2.3: The end of method M is unreachable.
+
+Boogie program verifier finished with 7 errors and 1 smoke test warnings.
diff --git a/Chalice/tests/examples/quantifiers.output.txt b/Chalice/tests/examples/quantifiers.output.txt
index efae2ed6..4abb22e1 100644
--- a/Chalice/tests/examples/quantifiers.output.txt
+++ b/Chalice/tests/examples/quantifiers.output.txt
@@ -1,5 +1,6 @@
Verification of quantifiers.chalice using parameters=""
- 57.29: The heap of the callee might not be strictly smaller than the heap of the caller.
-
-Boogie program verifier finished with 11 verified, 1 error
+ 57.29: The heap of the callee might not be strictly smaller than the heap of the caller.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+Boogie program verifier finished with 1 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/examples/swap.output.txt b/Chalice/tests/examples/swap.output.txt
index 70bac3a2..8cd3bb7c 100644
--- a/Chalice/tests/examples/swap.output.txt
+++ b/Chalice/tests/examples/swap.output.txt
@@ -1,4 +1,4 @@
Verification of swap.chalice using parameters=""
-
-Boogie program verifier finished with 5 verified, 0 errors
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/permission-model/basic.output.txt b/Chalice/tests/permission-model/basic.output.txt
index 9d92923a..acbef565 100644
--- a/Chalice/tests/permission-model/basic.output.txt
+++ b/Chalice/tests/permission-model/basic.output.txt
@@ -1,8 +1,9 @@
Verification of basic.chalice using parameters=""
- 28.3: The postcondition at 30.13 might not hold. Insufficient fraction at 30.13 for Cell.x.
- 48.3: The postcondition at 50.13 might not hold. Insufficient fraction at 50.13 for Cell.x.
- 97.3: The postcondition at 99.13 might not hold. Insufficient fraction at 99.13 for Cell.x.
- 148.3: The postcondition at 150.13 might not hold. Insufficient fraction at 150.13 for Cell.x.
-
-Boogie program verifier finished with 41 verified, 4 errors
+ 28.3: The postcondition at 30.13 might not hold. Insufficient fraction at 30.13 for Cell.x.
+ 48.3: The postcondition at 50.13 might not hold. Insufficient fraction at 50.13 for Cell.x.
+ 97.3: The postcondition at 99.13 might not hold. Insufficient fraction at 99.13 for Cell.x.
+ 148.3: The postcondition at 150.13 might not hold. Insufficient fraction at 150.13 for Cell.x.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+Boogie program verifier finished with 4 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/permission-model/channels.output.txt b/Chalice/tests/permission-model/channels.output.txt
index a79b5fb1..f588bc0a 100644
--- a/Chalice/tests/permission-model/channels.output.txt
+++ b/Chalice/tests/permission-model/channels.output.txt
@@ -1,6 +1,7 @@
Verification of channels.chalice using parameters=""
- 8.5: The where clause at 44.24 might not hold. Insufficient fraction at 44.24 for C.f.
- 18.3: The postcondition at 20.13 might not hold. Insufficient fraction at 20.13 for C.f.
-
-Boogie program verifier finished with 11 verified, 2 errors
+ 8.5: The where clause at 44.24 might not hold. Insufficient fraction at 44.24 for C.f.
+ 18.3: The postcondition at 20.13 might not hold. Insufficient fraction at 20.13 for C.f.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+Boogie program verifier finished with 2 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/permission-model/locks.output.txt b/Chalice/tests/permission-model/locks.output.txt
index 98cd0d4e..b6ea8f80 100644
--- a/Chalice/tests/permission-model/locks.output.txt
+++ b/Chalice/tests/permission-model/locks.output.txt
@@ -1,14 +1,20 @@
Verification of locks.chalice using parameters=""
- 21.5: Assertion might not hold. Insufficient fraction at 21.12 for Cell.x.
- 24.5: Assertion might not hold. Insufficient fraction at 24.12 for Cell.x.
- 44.5: Assertion might not hold. Insufficient fraction at 44.12 for Cell.x.
- 54.5: Assertion might not hold. Insufficient fraction at 54.12 for Cell.x.
- 73.5: Assertion might not hold. Insufficient fraction at 73.12 for Cell2.x.
- 80.5: Assertion might not hold. Insufficient fraction at 80.12 for Cell2.x.
- 83.5: Assertion might not hold. Insufficient fraction at 83.12 for Cell2.x.
- 103.5: Assertion might not hold. Insufficient fraction at 103.12 for Cell2.x.
- 111.5: Monitor invariant might hot hold. Insufficient fraction at 64.13 for Cell2.x.
- 136.10: Location might not be readable.
-
-Boogie program verifier finished with 20 verified, 10 errors
+ 21.5: Assertion might not hold. Insufficient fraction at 21.12 for Cell.x.
+ 24.5: Assertion might not hold. Insufficient fraction at 24.12 for Cell.x.
+ 44.5: Assertion might not hold. Insufficient fraction at 44.12 for Cell.x.
+ 54.5: Assertion might not hold. Insufficient fraction at 54.12 for Cell.x.
+ 73.5: Assertion might not hold. Insufficient fraction at 73.12 for Cell2.x.
+ 80.5: Assertion might not hold. Insufficient fraction at 80.12 for Cell2.x.
+ 83.5: Assertion might not hold. Insufficient fraction at 83.12 for Cell2.x.
+ 103.5: Assertion might not hold. Insufficient fraction at 103.12 for Cell2.x.
+ 111.5: Monitor invariant might hot hold. Insufficient fraction at 64.13 for Cell2.x.
+ 136.10: Location might not be readable.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+ 66.3: The end of method a1 is unreachable.
+ 76.3: The end of method a2 is unreachable.
+ 86.3: The end of method a3 is unreachable.
+ 138.5: The statements after the acquire statement are unreachable.
+
+Boogie program verifier finished with 10 errors and 4 smoke test warnings.
diff --git a/Chalice/tests/permission-model/peculiar.output.txt b/Chalice/tests/permission-model/peculiar.output.txt
index 6754cf7f..e2e6ec90 100644
--- a/Chalice/tests/permission-model/peculiar.output.txt
+++ b/Chalice/tests/permission-model/peculiar.output.txt
@@ -1,5 +1,8 @@
Verification of peculiar.chalice using parameters=""
- 35.5: Assertion might not hold. Insufficient fraction at 35.12 for Cell.x.
-
-Boogie program verifier finished with 18 verified, 1 error
+ 35.5: Assertion might not hold. Insufficient fraction at 35.12 for Cell.x.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+ 30.3: The end of method t4 is unreachable.
+
+Boogie program verifier finished with 1 errors and 1 smoke test warnings.
diff --git a/Chalice/tests/permission-model/permission_arithmetic.chalice b/Chalice/tests/permission-model/permission_arithmetic.chalice
index 94cf30a3..0cdf8aae 100644
--- a/Chalice/tests/permission-model/permission_arithmetic.chalice
+++ b/Chalice/tests/permission-model/permission_arithmetic.chalice
@@ -2,6 +2,8 @@ class Cell {
var x: int;
var i: int;
var y: Cell;
+ var f: int;
+ var g: int;
invariant rd(x);
@@ -189,5 +191,56 @@ class Cell {
fold valid
}
+ method a27()
+ requires acc(f,100-rd) && acc(f,rd)
+ {
+ assert acc(f) // ok, we have full access
+ }
+
+ method a28()
+ requires acc(f)
+ {
+ call a27();
+ var x: int
+ x := f // ERROR: no permission left
+ }
+
+ method a27b()
+ requires acc(f,100-rd)
+ requires acc(f,rd)
+ {
+ assert acc(f) // ok, we have full access
+ }
+
+ method a28b()
+ requires acc(f)
+ {
+ call a27b();
+ var x: int
+ x := f // ERROR: no permission left
+ }
+
+ method a29()
+ requires acc(f, 100-rd) && acc(g, rd)
+ { }
+
+ method a30()
+ requires acc(f, 100) && acc(g, rd)
+ {
+ call a29();
+ var tmp: int := this.g;
+ }
+
+ method a31(c: Cell)
+ requires acc(f, 100-rd) && acc(c.f, rd)
+ { }
+
+ method a32(c: Cell)
+ requires acc(f, 100) && acc(c.f, rd)
+ {
+ call a31(c);
+ var tmp: int := this.f;
+ }
+
method void() requires rd(x); ensures rd(x); {}
}
diff --git a/Chalice/tests/permission-model/permission_arithmetic.output.txt b/Chalice/tests/permission-model/permission_arithmetic.output.txt
index 0b2b5335..f5c02b3d 100644
--- a/Chalice/tests/permission-model/permission_arithmetic.output.txt
+++ b/Chalice/tests/permission-model/permission_arithmetic.output.txt
@@ -1,13 +1,22 @@
Verification of permission_arithmetic.chalice using parameters=""
- 24.5: Assertion might not hold. The permission at 24.12 might not be positive.
- 40.5: The precondition at 33.14 might not hold. The permission at 33.14 might not be positive.
- 73.3: The postcondition at 75.13 might not hold. Insufficient fraction at 75.13 for Cell.x.
- 86.3: The postcondition at 88.13 might not hold. Insufficient epsilons at 88.22 for Cell.x.
- 103.20: Location might not be readable.
- 109.20: Location might not be readable.
- 145.5: Monitor invariant might not hold. Insufficient fraction at 6.13 for Cell.x.
- 162.3: The postcondition at 164.13 might not hold. The permission at 164.13 might not be positive.
- 174.3: The postcondition at 176.13 might not hold. Insufficient fraction at 176.13 for Cell.x.
-
-Boogie program verifier finished with 47 verified, 9 errors
+ 26.5: Assertion might not hold. The permission at 26.12 might not be positive.
+ 42.5: The precondition at 35.14 might not hold. The permission at 35.14 might not be positive.
+ 75.3: The postcondition at 77.13 might not hold. Insufficient fraction at 77.13 for Cell.x.
+ 88.3: The postcondition at 90.13 might not hold. Insufficient epsilons at 90.22 for Cell.x.
+ 105.20: Location might not be readable.
+ 111.20: Location might not be readable.
+ 147.5: Monitor invariant might not hold. Insufficient fraction at 8.13 for Cell.x.
+ 164.3: The postcondition at 166.13 might not hold. The permission at 166.13 might not be positive.
+ 176.3: The postcondition at 178.13 might not hold. Insufficient fraction at 178.13 for Cell.x.
+ 205.10: Location might not be readable.
+ 220.10: Location might not be readable.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+ 18.3: Precondition of method a2 is equivalent to false.
+ 24.3: The end of method a3 is unreachable.
+ 42.5: The statements after the method call statement are unreachable.
+ 200.3: The end of method a28 is unreachable.
+ 215.3: The end of method a28b is unreachable.
+
+Boogie program verifier finished with 11 errors and 5 smoke test warnings.
diff --git a/Chalice/tests/permission-model/predicates.output.txt b/Chalice/tests/permission-model/predicates.output.txt
index 30c08a1a..5c0d0455 100644
--- a/Chalice/tests/permission-model/predicates.output.txt
+++ b/Chalice/tests/permission-model/predicates.output.txt
@@ -1,7 +1,11 @@
Verification of predicates.chalice using parameters=""
- 37.5: Fold might fail because the definition of Cell.write1 does not hold. Insufficient fraction at 6.22 for Cell.x.
- 55.5: Fold might fail because the definition of Cell.read1 does not hold. Insufficient fraction at 8.21 for Cell.x.
- 66.3: The postcondition at 68.13 might not hold. Insufficient fraction at 68.13 for Cell.x.
-
-Boogie program verifier finished with 27 verified, 3 errors
+ 37.5: Fold might fail because the definition of Cell.write1 does not hold. Insufficient fraction at 6.22 for Cell.x.
+ 55.5: Fold might fail because the definition of Cell.read1 does not hold. Insufficient fraction at 8.21 for Cell.x.
+ 66.3: The postcondition at 68.13 might not hold. Insufficient fraction at 68.13 for Cell.x.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+ 28.3: The end of method b3 is unreachable.
+ 49.3: The end of method b5 is unreachable.
+
+Boogie program verifier finished with 3 errors and 2 smoke test warnings.
diff --git a/Chalice/tests/permission-model/scaling.chalice b/Chalice/tests/permission-model/scaling.chalice
index 29930346..91c73f6d 100644
--- a/Chalice/tests/permission-model/scaling.chalice
+++ b/Chalice/tests/permission-model/scaling.chalice
@@ -8,6 +8,8 @@ are multiplied. This introduces non-linear arithmetic in Boogie, which can be
very hard and unpredicable for the theorem prover. For this reason, this test is
taking a very long time to complete.
+Note 2: For the moment, this test is (mostly) disabled.
+
-- Stefan Heule, June 2011
*/
@@ -26,59 +28,59 @@ class Cell {
// --- permission scaling ---
method s1()
- requires rd(read1);
+ // requires rd(read1);
{
- unfold rd(read1);
- assert(rd*(x));
- assert(rd(x)); // ERROR: should fail
+ // unfold rd(read1);
+ // assert(rd*(x));
+ // assert(rd(x)); // ERROR: should fail
}
method s2() // INCOMPLETNESS: postcondition should hold, but fails at the moment
- requires rd(read1);
- ensures rd(read1);
+ // requires rd(read1);
+ // ensures rd(read1);
{
- unfold rd(read1);
- fold rd(read1);
+ // unfold rd(read1);
+ // fold rd(read1);
}
method s3()
- requires acc(x);
- ensures rd(read1);
+ // requires acc(x);
+ // ensures rd(read1);
{
- fold rd(read1);
- assert(rd*(x));
- assert(acc(x)); // ERROR: should fail
+ // fold rd(read1);
+ // assert(rd*(x));
+ // assert(acc(x)); // ERROR: should fail
}
method s4() // ERROR: postcondition does not hold
- requires acc(x);
- ensures read1;
+ // requires acc(x);
+ // ensures read1;
{
- fold rd(read1);
+ // fold rd(read1);
}
method s5()
- requires rd(read2);
+ // requires rd(read2);
{
- unfold rd(read2);
- assert(rd*(x));
- assert(rd(x)); // ERROR: should fail
+ // unfold rd(read2);
+ // assert(rd*(x));
+ // assert(rd(x)); // ERROR: should fail
}
method s6()
- requires acc(x);
- ensures rd(read2);
+ // requires acc(x);
+ // ensures rd(read2);
{
- fold rd(read2);
- assert(rd*(x));
- assert(acc(x)); // ERROR: should fail
+ // fold rd(read2);
+ // assert(rd*(x));
+ // assert(acc(x)); // ERROR: should fail
}
method s7() // ERROR: postcondition does not hold
- requires acc(x);
- ensures read2;
+ // requires acc(x);
+ // ensures read2;
{
- fold rd(read2);
+ // fold rd(read2);
}
// --- helper functions ---
diff --git a/Chalice/tests/permission-model/scaling.output.txt b/Chalice/tests/permission-model/scaling.output.txt
index 863e79d8..d57ab458 100644
--- a/Chalice/tests/permission-model/scaling.output.txt
+++ b/Chalice/tests/permission-model/scaling.output.txt
@@ -1,11 +1,4 @@
Verification of scaling.chalice using parameters=""
- 33.5: Assertion might not hold. Insufficient fraction at 33.12 for Cell.x.
- 36.3: The postcondition at 38.13 might not hold. Insufficient fraction at 38.13 for Cell.read1.
- 50.5: Assertion might not hold. Insufficient fraction at 50.12 for Cell.x.
- 53.3: The postcondition at 55.13 might not hold. Insufficient fraction at 55.13 for Cell.read1.
- 65.5: Assertion might not hold. Insufficient fraction at 65.12 for Cell.x.
- 74.5: Assertion might not hold. Insufficient fraction at 74.12 for Cell.x.
- 77.3: The postcondition at 79.13 might not hold. Insufficient fraction at 79.13 for Cell.read2.
-
-Boogie program verifier finished with 17 verified, 7 errors
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/permission-model/sequences.output.txt b/Chalice/tests/permission-model/sequences.output.txt
index c7099103..2cb8d25d 100644
--- a/Chalice/tests/permission-model/sequences.output.txt
+++ b/Chalice/tests/permission-model/sequences.output.txt
@@ -1,6 +1,7 @@
Verification of sequences.chalice using parameters=""
- 36.3: The postcondition at 41.13 might not hold. Insufficient permission at 41.13 for A.f
- 60.3: The postcondition at 65.13 might not hold. Insufficient permission at 65.13 for A.f
-
-Boogie program verifier finished with 20 verified, 2 errors
+ 36.3: The postcondition at 41.13 might not hold. Insufficient permission at 41.13 for A.f
+ 60.3: The postcondition at 65.13 might not hold. Insufficient permission at 65.13 for A.f
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+Boogie program verifier finished with 2 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/test-scripts/getboogieoutput.bat b/Chalice/tests/test-scripts/getboogieoutput.bat
index 40590120..f7b729fe 100644
--- a/Chalice/tests/test-scripts/getboogieoutput.bat
+++ b/Chalice/tests/test-scripts/getboogieoutput.bat
@@ -25,7 +25,7 @@ if "!key!"=="!str!" (
echo Verification of %1.chalice using parameters="%chaliceparameters%" > %output%
echo.>> %output%
-call %chalice% "%1.chalice" %chaliceparameters% %2 %3 %4 %5 %6 %7 >> %output% 2>&1
+call %chalice% "%1.chalice" -smoke %chaliceparameters% %2 %3 %4 %5 %6 %7 >> %output% 2>&1
set o=%~dp1%out.bpl
if exist "%o%" copy "%o%" "%1.bpl">nul
diff --git a/Chalice/tests/test-scripts/reg_test.bat b/Chalice/tests/test-scripts/reg_test.bat
index 530d1d19..c6ab8424 100644
--- a/Chalice/tests/test-scripts/reg_test.bat
+++ b/Chalice/tests/test-scripts/reg_test.bat
@@ -35,7 +35,7 @@ if "!key!"=="!str!" (
set output=output.txt
echo Verification of %1.chalice using parameters="%chaliceparameters%" > %output%
echo.>> %output%
-call %chalice% "%1.chalice" %chaliceparameters% %2 %3 %4 %5 %6 %7 >> %output% 2>&1
+call %chalice% "%1.chalice" -smoke %chaliceparameters% %2 %3 %4 %5 %6 %7 >> %output% 2>&1
fc "%1.output.txt" output.txt > nul
if not errorlevel 1 goto passTest
diff --git a/Chalice/tests/test-scripts/test.bat b/Chalice/tests/test-scripts/test.bat
index ca66d3b6..30e135bd 100644
--- a/Chalice/tests/test-scripts/test.bat
+++ b/Chalice/tests/test-scripts/test.bat
@@ -27,7 +27,7 @@ if "!key!"=="!str!" (
set output=output.txt
echo Verification of %1.chalice using parameters="%chaliceparameters%" > %output%
echo.>> %output%
-call %chalice% "%1.chalice" %chaliceparameters% %2 %3 %4 %5 %6 %7 >> %output% 2>&1
+call %chalice% "%1.chalice" -smoke %chaliceparameters% %2 %3 %4 %5 %6 %7 >> %output% 2>&1
type %output%
exit /B 0
diff --git a/Jennisys/Jennisys/Analyzer.fs b/Jennisys/Jennisys/Analyzer.fs
index 9603dd6e..2bbd43cf 100644
--- a/Jennisys/Jennisys/Analyzer.fs
+++ b/Jennisys/Jennisys/Analyzer.fs
@@ -13,13 +13,7 @@ open Utils
open Microsoft.Boogie
-type MethodSolution = {
- pathCond: Expr;
- heap : Map<Const * VarDecl, Const>;
- env : Map<Const, Const>;
- ctx : Set<Set<Const>>;
-}
-
+
let Rename suffix vars =
vars |> List.map (function Var(nm,tp) -> nm, Var(nm + suffix, tp))
@@ -92,7 +86,7 @@ let rec IsArgsOnly args expr =
| ForallExpr(vars,e) -> IsArgsOnly (List.concat [args; vars]) e
//TODO: unifications should probably by "Expr <--> Expr" instead of "Expr <--> Const"
-let GetUnifications indent expr args (heap,env,ctx) =
+let GetUnifications indent expr args heapInst =
let idt = Indent indent
// - first looks if the give expression talks only about method arguments (args)
// - then checks if it doesn't already exist in the unification map
@@ -103,8 +97,8 @@ let GetUnifications indent expr args (heap,env,ctx) =
builder {
let! argsOnly = IsArgsOnly args e |> Utils.BoolToOption
let! notAlreadyAdded = Map.tryFind e unifMap |> Utils.IsNoneOption |> Utils.BoolToOption
- let! v = try Some(Eval (heap,env,ctx) true e |> Expr2Const) with ex -> None
- Logger.DebugLine (idt + " - adding unification " + (PrintExpr 0 e) + " <--> " + (PrintConst v));
+ let! v = try Some(Eval heapInst true e |> Expr2Const) with ex -> None
+ Logger.DebugLine (idt + " - adding unification " + (PrintExpr 0 e) + " <--> " + (PrintConst v))
return Map.add e v unifMap
}
// just recurses on all expressions
@@ -134,15 +128,15 @@ let GetUnifications indent expr args (heap,env,ctx) =
/// Returns a map (Expr |--> Const) containing unifications
/// found for the given method and heap/env/ctx
// =======================================================
-let GetUnificationsForMethod indent comp m (heap,env,ctx) =
+let GetUnificationsForMethod indent comp m heapInst =
let idt = Indent indent
- let rec GetArgValueUnifications args env =
+ let rec GetArgValueUnifications args =
match args with
| Var(name,_) :: rest ->
- match Map.tryFind (Unresolved(name)) env with
+ match Map.tryFind name heapInst.methodArgs with
| Some(c) ->
- Logger.DebugLine (idt + " - adding unification " + (PrintConst c) + " <--> " + name);
- Map.ofList [VarLiteral(name), c] |> Utils.MapAddAll (GetArgValueUnifications rest env)
+ Logger.DebugLine (idt + " - adding unification " + name + " <--> " + (PrintConst c));
+ Map.ofList [VarLiteral(name), c] |> Utils.MapAddAll (GetArgValueUnifications rest)
| None -> failwith ("couldn't find value for argument " + name)
| [] -> Map.empty
(* --- function body starts here --- *)
@@ -151,8 +145,8 @@ let GetUnificationsForMethod indent comp m (heap,env,ctx) =
let args = List.concat [ins; outs]
match args with
| [] -> Map.empty
- | _ -> GetUnifications indent (BinaryAnd pre post) args (heap,env,ctx)
- |> Utils.MapAddAll (GetArgValueUnifications args env)
+ | _ -> GetUnifications indent (BinaryAnd pre post) args heapInst
+ |> Utils.MapAddAll (GetArgValueUnifications args)
| _ -> failwith ("not a method: " + m.ToString())
// =========================================================================
@@ -163,33 +157,32 @@ let GetUnificationsForMethod indent comp m (heap,env,ctx) =
/// path. It starts from the given object, and follows the backpointers
/// until it reaches the root ("this")
// =========================================================================
-let objRef2ExprCache = new System.Collections.Generic.Dictionary<Const, Expr>()
-let GetObjRefExpr o (heap,env,ctx) =
- let rec __GetObjRefExpr o (heap,env,ctx) visited =
- if Set.contains o visited then
+let objRef2ExprCache = new System.Collections.Generic.Dictionary<string, Expr>()
+let GetObjRefExpr objRefName (heapInst: HeapInstance) =
+ let rec __GetObjRefExpr objRefName visited =
+ if Set.contains objRefName visited then
None
else
- let newVisited = Set.add o visited
- let refName = PrintObjRefName o (env,ctx)
- match refName with
+ let newVisited = Set.add objRefName visited
+ match objRefName with
| "this" -> Some(ObjLiteral("this"))
| _ ->
let rec __fff lst =
match lst with
- | ((o,Var(fldName,_)),l) :: rest ->
- match __GetObjRefExpr o (heap,env,ctx) newVisited with
+ | ((o,Var(fldName,_)),_) :: rest ->
+ match __GetObjRefExpr o.name newVisited with
| Some(expr) -> Some(Dot(expr, fldName))
| None -> __fff rest
| [] -> None
- let backPointers = heap |> Map.filter (fun (_,_) l -> l = o) |> Map.toList
+ let backPointers = heapInst.assignments |> Map.filter (fun (_,_) l -> l = ObjLiteral(objRefName)) |> Map.toList
__fff backPointers
(* --- function body starts here --- *)
- if objRef2ExprCache.ContainsKey(o) then
- Some(objRef2ExprCache.[o])
+ if objRef2ExprCache.ContainsKey(objRefName) then
+ Some(objRef2ExprCache.[objRefName])
else
- let res = __GetObjRefExpr o (heap,env,ctx) (Set.empty)
+ let res = __GetObjRefExpr objRefName (Set.empty)
match res with
- | Some(e) -> objRef2ExprCache.Add(o, e)
+ | Some(e) -> objRef2ExprCache.Add(objRefName, e)
| None -> ()
res
@@ -199,13 +192,13 @@ let GetObjRefExpr o (heap,env,ctx) =
/// If "conservative" is true, applies only those that
/// can be verified to hold, otherwise applies all of them
// =======================================================
-let rec ApplyUnifications indent prog comp mthd unifs (heap,env,ctx) conservative =
+let rec ApplyUnifications indent prog comp mthd unifs heapInst conservative =
let idt = Indent indent
let __CheckUnif o f e idx =
if not conservative || not Options.CONFIG.checkUnifications 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 objRefExpr = GetObjRefExpr o heapInst |> Utils.ExtractOptionMsg ("Couldn't find a path from 'this' to " + o)
let fldName = PrintVarName f
let lhs = Dot(objRefExpr, fldName)
let assertionExpr = match f with
@@ -213,7 +206,7 @@ let rec ApplyUnifications indent prog comp mthd unifs (heap,env,ctx) conservativ
| 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)
+ let code = PrintDafnyCodeSkeleton prog (MethodAnalysisPrinter (comp,mthd) assertionExpr) false
Logger.Debug (idt + " - checking assertion: " + (PrintExpr 0 assertionExpr) + " ... ")
let ok = CheckDafnyProgram code ("unif_" + (GetMethodFullName comp mthd))
if ok then
@@ -224,50 +217,49 @@ let rec ApplyUnifications indent prog comp mthd unifs (heap,env,ctx) conservativ
(* --- function body starts here --- *)
match unifs with
| (e,c) :: rest ->
- let restHeap,env,ctx = ApplyUnifications indent 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 "%s - applied: %s.%s --> %s" idt (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 "%s - applied: %s.%s[%d] --> %s" idt (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)
+ let heapInst = ApplyUnifications indent prog comp mthd rest heapInst conservative
+ let newHeap = heapInst.assignments|> Map.fold (fun acc (o,f) value ->
+ if value = Const2Expr c then
+ if __CheckUnif o.name f e -1 then
+ // change the value to expression
+ //Logger.TraceLine (sprintf "%s - applied: %s.%s --> %s" idt (PrintConst o) (GetVarName f) (PrintExpr 0 e) )
+ acc |> Map.add (o,f) e
+ else
+ // don't change the value unless "conservative = false"
+ acc |> Map.add (o,f) value
+ else
+ let rec __UnifyOverLst lst cnt =
+ match lst with
+ | lstElem :: rest when lstElem = Const2Expr c ->
+ if __CheckUnif o.name f e cnt then
+ //Logger.TraceLine (sprintf "%s - applied: %s.%s[%d] --> %s" idt (PrintConst o) (GetVarName f) cnt (PrintExpr 0 e) )
+ 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
+ | SequenceExpr(elist) ->
+ let newExprList = __UnifyOverLst elist 0
+ acc |> Map.add (o,f) (SequenceExpr(newExprList))
+ | SetExpr(elist) ->
+ let newExprList = __UnifyOverLst elist 0
+ acc |> Map.add (o,f) (SetExpr(newExprList))
+ | _ ->
+ acc |> Map.add (o,f) value
+ ) heapInst.assignments
+ {heapInst with assignments = newHeap }
+ | [] -> heapInst
// ====================================================================================
/// Returns whether the code synthesized for the given method can be verified with Dafny
// ====================================================================================
-let VerifySolution prog comp mthd sol =
+let VerifySolution prog comp mthd sol genRepr =
// print the solution to file and try to verify it with Dafny
let solutions = Map.empty |> Map.add (comp,mthd) sol
- let code = PrintImplCode prog solutions (fun p -> [comp,mthd])
+ let code = PrintImplCode prog solutions (fun p -> [comp,mthd]) genRepr
CheckDafnyProgram code dafnyVerifySuffix
// ============================================================================
@@ -280,7 +272,7 @@ let rec AnalyzeConstructor indent prog comp m =
let methodName = GetMethodName m
let pre,post = GetMethodPrePost m
// generate Dafny code for analysis first
- let code = PrintDafnyCodeSkeleton prog (MethodAnalysisPrinter (comp,m) FalseLiteral)
+ let code = PrintDafnyCodeSkeleton prog (MethodAnalysisPrinter (comp,m) FalseLiteral) false
Logger.InfoLine (idt + "[*] Analyzing constructor")
Logger.InfoLine (idt + "------------------------------------------")
Logger.InfoLine (PrintMethodSignFull (indent + 4) m)
@@ -297,13 +289,14 @@ let rec AnalyzeConstructor indent prog comp m =
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 indent comp m (heap,env,ctx) |> Map.toList
- let heap,env,ctx = ApplyUnifications indent prog comp m unifs (heap,env,ctx) true
+ let hModel = ReadFieldValuesFromModel model prog comp m
+ let heapInst = ResolveModel hModel
+ let unifs = GetUnificationsForMethod indent comp m heapInst |> Map.toList
+ let heapInst = ApplyUnifications indent prog comp m unifs heapInst true
if Options.CONFIG.verifySolutions then
Logger.InfoLine (idt + " - verifying synthesized solution ... ")
- let sol = [TrueLiteral, (heap,env,ctx)]
- let verified = VerifySolution prog comp m sol
+ let sol = [TrueLiteral, heapInst]
+ let verified = VerifySolution prog comp m sol Options.CONFIG.genRepr
Logger.Info (idt + " ")
if verified then
Logger.InfoLine "~~~ VERIFIED ~~~"
@@ -311,50 +304,53 @@ let rec AnalyzeConstructor indent prog comp m =
else
Logger.InfoLine "!!! NOT VERIFIED !!!"
Logger.InfoLine (idt + " Strengthening the pre-condition")
- TryInferConditionals (indent + 4) prog comp m unifs (heap,env,ctx)
+ TryInferConditionals (indent + 4) prog comp m unifs heapInst
else
- [TrueLiteral, (heap,env,ctx)]
-and TryInferConditionals indent prog comp m unifs (heap,env,ctx) =
+ [TrueLiteral, heapInst]
+and TryInferConditionals indent prog comp m unifs heapInst =
let idt = Indent indent
- let heap2,env2,ctx2 = ApplyUnifications indent prog comp m unifs (heap,env,ctx) false
+ let wrongSol = [TrueLiteral, heapInst]
+ let heapInst2 = ApplyUnifications indent prog comp m unifs heapInst false
// get expressions to evaluate:
- // - add pre and post conditions
- // - go through all objects on the heap and assert its invariant
+ // - add post (and pre?) conditions
+ // - go through all objects on the heap and assert their invariants
let pre,post = GetMethodPrePost m
let prepostExpr = post //TODO: do we need the "pre" here as well?
- let heapObjs = heap |> Map.fold (fun acc (o,_) _ -> acc |> Set.add o) Set.empty
+ let heapObjs = heapInst2.assignments |> Map.fold (fun acc (o,_) _ -> acc |> Set.add o) Set.empty
let expr = heapObjs |> Set.fold (fun acc o ->
- let receiverOpt = GetObjRefExpr o (heap,env,ctx)
+ let receiverOpt = GetObjRefExpr o.name heapInst2
let receiver = Utils.ExtractOption receiverOpt
- match Resolve (env,ctx) o with
- | NewObj(_,tOpt) | ThisConst(_,tOpt) ->
- let t = Utils.ExtractOptionMsg "Type missing for heap object" tOpt
- let objComp = FindComponent prog (GetTypeShortName t) |> Utils.ExtractOption
- let objInvs = GetInvariantsAsList objComp
- let objInvsUpdated = objInvs |> List.map (ChangeThisReceiver receiver)
- objInvsUpdated |> List.fold (fun a e -> BinaryAnd a e) acc
- | _ -> failwith "not supposed to happen"
+ let objComp = FindComponent prog (GetTypeShortName o.objType) |> Utils.ExtractOption
+ let objInvs = GetInvariantsAsList objComp
+ let objInvsUpdated = objInvs |> List.map (ChangeThisReceiver receiver)
+ objInvsUpdated |> List.fold (fun a e -> BinaryAnd a e) acc
) prepostExpr
- //expr |> SplitIntoConjunts |> List.iter (fun e -> printfn "%s" (PrintExpr 0 e); printfn "")
// now evaluate and see what's left
- let newCond = Eval (heap2,env2,ctx2) false expr
+ let newCond = Eval heapInst2 false expr
try
if newCond = TrueLiteral then
Logger.InfoLine (sprintf "%s - no more interesting pre-conditions" idt)
- []
+ wrongSol
else
Logger.InfoLine (sprintf "%s - candidate pre-condition: %s" idt (PrintExpr 0 newCond))
let p2,c2,m2 = AddPrecondition prog comp m newCond
Logger.Info (idt + " - verifying partial solution ... ")
- let sol = [newCond, (heap2,env2,ctx2)]
- let verified = VerifySolution p2 c2 m2 sol
+ let sol = [newCond, heapInst2]
+ let verified =
+ if Options.CONFIG.verifyPartialSolutions then
+ VerifySolution p2 c2 m2 sol Options.CONFIG.genRepr
+ else
+ true
if verified then
- Logger.InfoLine "VERIFIED"
+ if Options.CONFIG.verifyPartialSolutions then
+ Logger.InfoLine "VERIFIED"
+ else
+ Logger.InfoLine "SKIPPED"
let p3,c3,m3 = AddPrecondition prog comp m (UnaryNot(newCond))
sol.[0] :: AnalyzeConstructor (indent + 2) p3 c3 m3
else
Logger.InfoLine "NOT VERIFIED"
- []
+ wrongSol
with
ex -> raise ex
@@ -410,7 +406,7 @@ let Analyze prog filename =
use file = System.IO.File.CreateText(dafnySynthFileNameTemplate.Replace("###", progName))
file.AutoFlush <- true
Logger.InfoLine "Printing synthesized code"
- let synthCode = PrintImplCode prog solutions GetMethodsToAnalyze
+ let synthCode = PrintImplCode prog solutions GetMethodsToAnalyze Options.CONFIG.genRepr
fprintfn file "%s" synthCode
()
diff --git a/Jennisys/Jennisys/Ast.fs b/Jennisys/Jennisys/Ast.fs
index 1ddf1f31..b9105254 100644
--- a/Jennisys/Jennisys/Ast.fs
+++ b/Jennisys/Jennisys/Ast.fs
@@ -56,7 +56,6 @@ type Const =
| ThisConst of (* loc id *) string * Type option
| VarConst of string
| NewObj of (* loc id *) string * Type option
- | ExprConst of Expr
| Unresolved of (* loc id *) string
type Stmt =
diff --git a/Jennisys/Jennisys/AstUtils.fs b/Jennisys/Jennisys/AstUtils.fs
index 25d2a129..fa5a0a77 100644
--- a/Jennisys/Jennisys/AstUtils.fs
+++ b/Jennisys/Jennisys/AstUtils.fs
@@ -9,6 +9,9 @@ module AstUtils
open Ast
open Utils
+let PrintGenSym name =
+ sprintf "gensym%s" name
+
// =====================
/// Returns TRUE literal
// =====================
@@ -30,6 +33,12 @@ let UnaryNot sub =
| _ -> UnaryExpr("!", sub)
// =======================================================================
+/// Returns a binary PLUS of the two given expressions
+// =======================================================================
+let BinaryPlus (lhs: Expr) (rhs: Expr) =
+ BinaryExpr(50, "+", lhs, rhs)
+
+// =======================================================================
/// Returns a binary AND of the two given expressions with short-circuiting
// =======================================================================
let BinaryAnd (lhs: Expr) (rhs: Expr) =
@@ -62,37 +71,6 @@ let BinaryImplies lhs rhs =
| _, BoolLiteral(false) -> UnaryNot(lhs)
| _ -> BinaryExpr(20, "==>", lhs, rhs)
-
-//let TrueLiteral = IdLiteral("true")
-//let FalseLiteral = IdLiteral("false")
-//
-//// =======================================================================
-///// Returns a binary AND of the two given expressions with short-circuiting
-//// =======================================================================
-//let BinaryAnd (lhs: Expr) (rhs: Expr) =
-// match lhs, rhs with
-// | IdLiteral("true"), _ -> rhs
-// | IdLiteral("false"), _ -> IdLiteral("false")
-// | _, IdLiteral("true") -> lhs
-// | _, IdLiteral("false") -> IdLiteral("false")
-// | _, _ -> BinaryExpr(30, "&&", lhs, rhs)
-//
-//// =======================================================================
-///// Returns a binary OR of the two given expressions with short-circuiting
-//// =======================================================================
-//let BinaryOr (lhs: Expr) (rhs: Expr) =
-// match lhs, rhs with
-// | IdLiteral("true"), _ -> IdLiteral("true")
-// | IdLiteral("false"), _ -> rhs
-// | _, IdLiteral("true") -> IdLiteral("true")
-// | _, IdLiteral("false") -> lhs
-// | _, _ -> BinaryExpr(30, "||", lhs, rhs)
-//
-//// ===================================================================================
-///// Returns a binary IMPLIES of the two given expressions (TODO: with short-circuiting)
-//// ===================================================================================
-//let BinaryImplies lhs rhs = BinaryExpr(20, "==>", lhs, rhs)
-
// =======================================================
/// Constructors for binary EQ/NEQ of two given expressions
// =======================================================
@@ -100,6 +78,11 @@ let BinaryNeq lhs rhs = BinaryExpr(40, "!=", lhs, rhs)
let BinaryEq lhs rhs = BinaryExpr(40, "=", lhs, rhs)
// =======================================================
+/// Constructor for binary GETS
+// =======================================================
+let BinaryGets lhs rhs = Assign(lhs, rhs)
+
+// =======================================================
/// Constructors for binary IN/!IN of two given expressions
// =======================================================
let BinaryIn lhs rhs = BinaryExpr(40, "in", lhs, rhs)
@@ -134,11 +117,10 @@ let rec Const2Expr c =
let expSet = cset |> Set.fold (fun acc c -> Set.add (Const2Expr c) acc) Set.empty
SetExpr(Set.toList expSet)
| VarConst(id) -> VarLiteral(id)
- | ThisConst(name,_)
- | NewObj(name,_) -> ObjLiteral(name)
+ | ThisConst(_,_) -> ObjLiteral("this")
+ | NewObj(name,_) -> ObjLiteral(PrintGenSym name)
| NullConst -> ObjLiteral("null")
- | ExprConst(e) -> e
- | Unresolved(name) -> printf "What about unresolved stuff??"; failwith "don't want to convert unresolved to expr"
+ | Unresolved(name) -> failwithf "don't want to convert unresolved(%s) to expr" name // IdLiteral(name) //
| _ -> failwithf "not implemented or not supported: %O" c
let rec Expr2Const e =
@@ -147,7 +129,7 @@ let rec Expr2Const e =
| BoolLiteral(b) -> BoolConst(b)
| ObjLiteral("this") -> ThisConst("this",None)
| ObjLiteral("null") -> NullConst
- | ObjLiteral(name) -> NewObj(name, None) //TODO: or Unresolved?
+ | ObjLiteral(name) -> Unresolved(name)
| IdLiteral(id) -> Unresolved(id)
| VarLiteral(id) -> VarConst(id)
| SequenceExpr(elist) -> SeqConst(elist |> List.map Expr2Const)
@@ -207,6 +189,23 @@ let GetAllFields comp =
let aVars = FilterFieldMembers members
List.concat [aVars ; cVars]
| _ -> []
+
+// ===========================================================
+/// Returns a map (Type |--> Set<Var>) where all
+/// the given fields are grouped by their type
+///
+/// ensures: forall v :: v in ret.values.elems ==> v in fields
+/// ensures: forall k :: k in ret.keys ==>
+/// forall v1, v2 :: v1, v2 in ret[k].elems ==>
+/// v1.type = v2.type
+// ===========================================================
+let rec GroupFieldsByType fields =
+ match fields with
+ | Var(name, ty) :: rest ->
+ let map = GroupFieldsByType rest
+ let fldSet = Map.tryFind ty map |> Utils.ExtractOptionOr Set.empty
+ map |> Map.add ty (fldSet |> Set.add (Var(name, ty)))
+ | [] -> Map.empty
// =================================
/// Returns class name of a component
@@ -314,13 +313,36 @@ let FindMethod comp methodName =
// ==============================================
/// Finds a field of a class that has a given name
// ==============================================
-let FindVar (prog: Program) clsName fldName =
- let copt = FindComponent prog clsName
- match copt with
- | Some(comp) ->
- GetAllFields comp |> List.filter (function Var(name,_) when name = fldName -> true | _ -> false)
- |> Utils.ListToOption
- | None -> None
+//let FindCompVar prog clsName fldName =
+// let copt = FindComponent prog clsName
+// match copt with
+// | Some(comp) ->
+// GetAllFields comp |> List.filter (function Var(name,_) when name = fldName -> true | _ -> false)
+// |> Utils.ListToOption
+// | None -> None
+
+let FindVar comp fldName =
+ GetAllFields comp |> List.filter (function Var(name,_) when name = fldName -> true | _ -> false)
+ |> Utils.ListToOption
+
+// ======================================
+/// Returns the frame of a given component
+// ======================================
+let GetFrame comp =
+ match comp with
+ | Component(_, Model(_,_,_,frame,_), _) -> frame
+ | _ -> failwithf "not a valid component %O" comp
+
+let GetFrameFields comp =
+ let frame = GetFrame comp
+ frame |> List.choose (function IdLiteral(name) -> Some(name) | _ -> None) // TODO: is it really enough to handle only IdLiteral's
+ |> List.choose (fun varName ->
+ let v = FindVar comp varName
+ Utils.ExtractOptionMsg ("field not found: " + varName) v |> ignore
+ v
+ )
+
+////////////////////////
let AddPrecondition prog comp m e =
match prog, comp, m with
@@ -637,7 +659,7 @@ let ChangeThisReceiver receiver expr =
| UpdateExpr(e1,e2,e3) -> UpdateExpr(__ChangeThis locals e1, __ChangeThis locals e2, __ChangeThis locals e3)
| SequenceExpr(exs) -> SequenceExpr(exs |> List.map (__ChangeThis locals))
| SetExpr(exs) -> SetExpr(exs |> List.map (__ChangeThis locals))
- (* function body starts here *)
+ (* --- function body starts here --- *)
__ChangeThis Set.empty expr
let rec Rewrite rewriterFunc expr =
diff --git a/Jennisys/Jennisys/CodeGen.fs b/Jennisys/Jennisys/CodeGen.fs
index 5d7f8611..6b53112e 100644
--- a/Jennisys/Jennisys/CodeGen.fs
+++ b/Jennisys/Jennisys/CodeGen.fs
@@ -7,19 +7,52 @@ open Printer
open Resolver
open TypeChecker
open DafnyPrinter
+open DafnyModelUtils
-let numLoopUnrolls = 2
+// TODO: this should take a list of fields and unroll all possibilities (instead of unrolling on branch only, following exactly one field)
+//let rec GetUnrolledFieldValidExpr fldExpr fldName validFunName numUnrolls : Expr =
+// if numUnrolls = 0 then
+// TrueLiteral
+// else
+// BinaryImplies (BinaryNeq fldExpr (ObjLiteral("null")))
+// (BinaryAnd (Dot(fldExpr, validFunName))
+// (GetUnrolledFieldValidExpr (Dot(fldExpr, fldName)) fldName validFunName (numUnrolls-1)))
-let rec GetUnrolledFieldValidExpr fldExpr fldName validFunName numUnrolls : Expr =
+/// requires: numUnrols >= 0
+/// requires: |fldExprs| = |fldNames|
+let rec GetUnrolledFieldValidExpr fldExprs fldNames validFunName numUnrolls =
+ let rec __Combine exprLst strLst =
+ match exprLst with
+ | e :: rest ->
+ let resLst1 = strLst |> List.map (fun s -> Dot(e, s))
+ List.concat [resLst1; __Combine rest strLst]
+ | [] -> []
+ let rec __NotNull e =
+ match e with
+ | IdLiteral(_)
+ | ObjLiteral(_) -> BinaryNeq e (ObjLiteral("null"))
+ | Dot(sub, str) -> BinaryAnd (__NotNull sub) (BinaryNeq e (ObjLiteral("null")))
+ | _ -> failwith "not supposed to happen"
+ (* --- function body starts here --- *)
+ assert (numUnrolls >= 0)
if numUnrolls = 0 then
- TrueLiteral
+ [TrueLiteral]
else
- BinaryImplies (BinaryNeq fldExpr (IdLiteral("null")))
- (BinaryAnd (Dot(fldExpr, validFunName))
- (GetUnrolledFieldValidExpr (Dot(fldExpr, fldName)) fldName validFunName (numUnrolls-1)))
+ let exprList = fldExprs |> List.map (fun e -> BinaryImplies (__NotNull e) (Dot(e, validFunName)))
+ if numUnrolls = 1 then
+ exprList
+ else
+ let fldExprs = __Combine fldExprs fldNames
+ List.append exprList (GetUnrolledFieldValidExpr fldExprs fldNames validFunName (numUnrolls - 1))
+
-let GetFieldValidExpr fldName validFunName numUnrolls : Expr =
- GetUnrolledFieldValidExpr (IdLiteral(fldName)) fldName validFunName numUnrolls
+//let GetFieldValidExpr fldName validFunName numUnrolls : Expr =
+// GetUnrolledFieldValidExpr (IdLiteral(fldName)) fldName validFunName numUnrolls
+
+let GetFieldValidExpr flds validFunName numUnrolls =
+ let fldExprs = flds |> List.map (function Var(name, _) -> IdLiteral(name))
+ let fldNames = flds |> List.map (function Var(name, _) -> name)
+ GetUnrolledFieldValidExpr fldExprs fldNames validFunName numUnrolls
let GetFieldsForValidExpr allFields prog : VarDecl list =
allFields |> List.filter (function Var(name, tp) when IsUserType prog tp -> true
@@ -27,15 +60,24 @@ let GetFieldsForValidExpr allFields prog : VarDecl list =
let GetFieldsValidExprList clsName allFields prog : Expr list =
let fields = GetFieldsForValidExpr allFields prog
- fields |> List.map (function Var(name, t) ->
- let validFunName, numUnrolls =
- match t with
- | Some(ty) when clsName = (GetTypeShortName ty) -> "Valid_self()", numLoopUnrolls
- | _ -> "Valid()", 1
- GetFieldValidExpr name validFunName numUnrolls
- )
-
-let PrintValidFunctionCode comp prog : string =
+ let fieldsByType = GroupFieldsByType fields
+ fieldsByType |> Map.fold (fun acc t varSet ->
+ let validFunName, numUnrolls =
+ match t with
+ | Some(ty) when clsName = (GetTypeShortName ty) -> "Valid_self()", Options.CONFIG.numLoopUnrolls
+ | _ -> "Valid()", 1
+ acc |> List.append (GetFieldValidExpr (Set.toList varSet) validFunName numUnrolls)
+ ) []
+
+// fields |> List.map (function Var(name, t) ->
+// let validFunName, numUnrolls =
+// match t with
+// | Some(ty) when clsName = (GetTypeShortName ty) -> "Valid_self()", Options.CONFIG.numLoopUnrolls
+// | _ -> "Valid()", 1
+// GetFieldValidExpr name validFunName numUnrolls
+// )
+
+let PrintValidFunctionCode comp prog genRepr: string =
let idt = " "
let __PrintInvs invs =
invs |> List.fold (fun acc e -> List.concat [acc ; SplitIntoConjunts e]) []
@@ -45,16 +87,33 @@ let PrintValidFunctionCode comp prog : string =
let vars = GetAllFields comp
let allInvs = GetInvariantsAsList comp |> DesugarLst
let fieldsValid = GetFieldsValidExprList clsName vars prog
-
+
+ let frameFldNames = GetFrameFields comp |> List.choose (function Var(name,_) -> Some(name))
+ let validReprBody =
+ " this in Repr &&" + newline +
+ " null !in Repr" +
+ (PrintSep "" (fun x -> " &&" + newline + " ($x != null ==> $x in Repr && $x.Repr <= Repr && this !in $x.Repr)".Replace("$x", x)) frameFldNames)
+
+ let vr =
+ if genRepr then
+ " function Valid_repr(): bool" + newline +
+ " reads *;" + newline +
+ " {" + newline +
+ validReprBody + newline +
+ " }" + newline + newline
+ else
+ ""
// 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
// []
// (if List.isEmpty decrVars then "" else sprintf " decreases %s;%s" (PrintSep ", " (fun a -> a) decrVars) newline) +
+ vr +
" function Valid_self(): bool" + newline +
" reads *;" + newline +
" {" + newline +
+ (Utils.Ite genRepr (" Valid_repr() &&" + newline) "") +
(__PrintInvs allInvs) + newline +
" }" + newline +
newline +
@@ -65,13 +124,12 @@ let PrintValidFunctionCode comp prog : string =
(__PrintInvs fieldsValid) + newline +
" }" + newline
-let PrintDafnyCodeSkeleton prog methodPrinterFunc: string =
+let PrintDafnyCodeSkeleton prog methodPrinterFunc genRepr =
match prog with
| Program(components) -> components |> List.fold (fun acc comp ->
match comp with
| Component(Class(name,typeParams,members), Model(_,_,cVars,frame,inv), code) as comp ->
- let aVars = FilterFieldMembers members
- let allVars = List.concat [aVars ; cVars];
+ let aVars = FilterFieldMembers members |> List.append (Utils.Ite genRepr [Var("Repr", Some(SetType(NamedType("object", []))))] [])
let compMethods = FilterConstructorMembers members
// Now print it as a Dafny program
acc +
@@ -80,92 +138,118 @@ let PrintDafnyCodeSkeleton prog methodPrinterFunc: string =
(sprintf "%s" (PrintFields aVars 2 true)) + newline +
(sprintf "%s" (PrintFields cVars 2 false)) + newline +
// generate the Valid function
- (sprintf "%s" (PrintValidFunctionCode comp prog)) + newline +
+ (sprintf "%s" (PrintValidFunctionCode comp prog genRepr)) + newline +
// call the method printer function on all methods of this component
(compMethods |> List.fold (fun acc m -> acc + (methodPrinterFunc comp m)) "") +
// the end of the class
"}" + newline + newline
| _ -> assert false; "") ""
-
-let PrintAllocNewObjects (heap,env,ctx) indent =
+
+let PrintAllocNewObjects heapInst indent =
+ let idt = Indent indent
+ heapInst.assignments |> Map.fold (fun acc (obj,fld) _ ->
+ if not (obj.name = "this") then
+ acc |> Set.add obj
+ else
+ acc
+ ) Set.empty
+ |> Set.fold (fun acc obj -> acc + (sprintf "%svar %s := new %s;%s" idt obj.name (PrintType obj.objType) newline)) ""
+
+let PrintVarAssignments heapInst indent =
let idt = Indent indent
- env |> Map.fold (fun acc l v ->
- match v with
- | NewObj(_,_) -> acc |> Set.add v
- | _ -> acc
- ) Set.empty
- |> Set.fold (fun acc newObjConst ->
- match newObjConst with
- | NewObj(name, Some(tp)) -> acc + (sprintf "%svar %s := new %s;%s" idt (PrintGenSym name) (PrintType tp) newline)
- | _ -> failwithf "NewObj doesn't have a type: %O" newObjConst
- ) ""
-
-let PrintObjRefName o (env,ctx) =
- match Resolve (env,ctx) o with
- | ThisConst(_,_) -> "this";
- | NewObj(name, _) -> PrintGenSym name
- | _ -> failwith ("unresolved object ref: " + o.ToString())
-
-let CheckUnresolved c =
- match c with
- | Unresolved(_) -> Logger.WarnLine "!!! There are some unresolved constants in the output file !!!"; c
- | _ -> c
-
-let PrintVarAssignments (heap,env,ctx) indent =
+ heapInst.assignments |> Map.fold (fun acc (o,f) e ->
+ let fldName = PrintVarName f
+ let value = PrintExpr 0 e
+ acc + (sprintf "%s%s.%s := %s;" idt o.name fldName value) + newline
+ ) ""
+
+let PrintReprAssignments prog heapInst indent =
+ let __FollowsFunc o1 o2 =
+ heapInst.assignments |> Map.fold (fun acc (srcObj,fld) value ->
+ acc || (srcObj = o1 && value = ObjLiteral(o2.name))
+ ) false
let idt = Indent indent
- heap |> Map.fold (fun acc (o,f) l ->
- let objRef = PrintObjRefName o (env,ctx)
- let fldName = PrintVarName f
- let value = TryResolve (env,ctx) l |> CheckUnresolved |> PrintConst
- acc + (sprintf "%s%s.%s := %s;" idt objRef fldName value) + newline
- ) ""
-
-let rec PrintHeapCreationCode sol indent =
+ let objs = heapInst.assignments |> Map.fold (fun acc (obj,fld) _ -> acc |> Set.add obj) Set.empty
+ |> Set.toList
+ |> Utils.TopSort __FollowsFunc
+ |> List.rev
+ let reprGetsList = objs |> List.fold (fun acc obj ->
+ let expr = SetExpr([ObjLiteral(obj.name)])
+ let builder = CascadingBuilder<_>(expr)
+ let fullRhs = builder {
+ let typeName = GetTypeShortName obj.objType
+ let! comp = FindComponent prog typeName
+ let vars = GetFrameFields comp
+ let nonNullVars = vars |> List.filter (fun v ->
+ match Map.tryFind (obj,v) heapInst.assignments with
+ | Some(ObjLiteral(n)) when not (n = "null") -> true
+ | _ -> false)
+ return nonNullVars |> List.fold (fun a v ->
+ BinaryPlus a (Dot(Dot(ObjLiteral(obj.name), (PrintVarName v)), "Repr"))
+ ) expr
+ }
+ let fullReprExpr = BinaryGets (Dot(ObjLiteral(obj.name), "Repr")) fullRhs
+ fullReprExpr :: acc
+ ) []
+
+ idt + "// repr stuff" + newline +
+ (PrintStmtList reprGetsList indent)
+
+let rec PrintHeapCreationCode prog sol indent genRepr =
let idt = Indent indent
match sol with
- | (c, (heap,env,ctx)) :: rest ->
+ | (c, heapInst) :: rest ->
+ let __ReprAssignments ind =
+ if genRepr then
+ (PrintReprAssignments prog heapInst ind)
+ else
+ ""
if c = TrueLiteral then
- (PrintAllocNewObjects (heap,env,ctx) indent) +
- (PrintVarAssignments (heap,env,ctx) indent) +
- newline +
- (PrintHeapCreationCode rest indent)
+ (PrintAllocNewObjects heapInst indent) +
+ (PrintVarAssignments heapInst indent) +
+ (__ReprAssignments indent) +
+ (PrintHeapCreationCode prog rest indent genRepr)
else
if List.length rest > 0 then
idt + "if (" + (PrintExpr 0 c) + ") {" + newline +
- (PrintAllocNewObjects (heap,env,ctx) (indent+2)) +
- (PrintVarAssignments (heap,env,ctx) (indent+2)) +
+ (PrintAllocNewObjects heapInst (indent+2)) +
+ (PrintVarAssignments heapInst (indent+2)) +
+ (__ReprAssignments (indent+2)) +
idt + "} else {" + newline +
- (PrintHeapCreationCode rest (indent+2)) +
+ (PrintHeapCreationCode prog rest (indent+2) genRepr) +
idt + "}" + newline
else
- (PrintAllocNewObjects (heap,env,ctx) indent) +
- (PrintVarAssignments (heap,env,ctx) indent)
+ (PrintAllocNewObjects heapInst indent) +
+ (PrintVarAssignments heapInst indent) +
+ (__ReprAssignments indent)
| [] -> ""
-let GenConstructorCode mthd body =
+let GenConstructorCode mthd body genRepr =
let validExpr = IdLiteral("Valid()");
match mthd with
| Method(methodName, sign, pre, post, _) ->
- let __PrintPrePost pfix expr = SplitIntoConjunts expr |> PrintSep newline (fun e -> pfix + (PrintExpr 0 e) + ";")
+ let __PrintPrePost pfix expr = SplitIntoConjunts expr |> PrintSep "" (fun e -> pfix + (PrintExpr 0 e) + ";")
let preExpr = pre
let postExpr = BinaryAnd validExpr post
" method " + methodName + (PrintSig sign) + newline +
- " modifies this;" + newline +
- (__PrintPrePost " requires " preExpr) + newline +
- (__PrintPrePost " ensures " postExpr) + newline +
+ " modifies this;" +
+ (__PrintPrePost (newline + " requires ") preExpr) +
+ Utils.Ite genRepr (newline + " ensures fresh(Repr - {this});") "" +
+ (__PrintPrePost (newline + " ensures ") postExpr) +
+ newline +
" {" + newline +
body +
" }" + newline
| _ -> ""
-// solutions: (comp, constructor) |--> (heap, env, ctx)
-let PrintImplCode prog solutions methodsToPrintFunc =
+// solutions: (comp, constructor) |--> condition * heapInst
+let PrintImplCode prog solutions methodsToPrintFunc genRepr =
let methods = methodsToPrintFunc prog
PrintDafnyCodeSkeleton prog (fun comp mthd ->
if Utils.ListContains (comp,mthd) methods then
let mthdBody = match Map.tryFind (comp,mthd) solutions with
- | Some(sol) -> PrintHeapCreationCode sol 4
+ | Some(sol) -> PrintHeapCreationCode prog sol 4 genRepr
| _ -> " //unable to synthesize" + newline
- (GenConstructorCode mthd mthdBody) + newline
+ (GenConstructorCode mthd mthdBody genRepr) + newline
else
- "") \ No newline at end of file
+ "") genRepr \ No newline at end of file
diff --git a/Jennisys/Jennisys/DafnyModelUtils.fs b/Jennisys/Jennisys/DafnyModelUtils.fs
index 4b9b0c60..83de2292 100644
--- a/Jennisys/Jennisys/DafnyModelUtils.fs
+++ b/Jennisys/Jennisys/DafnyModelUtils.fs
@@ -24,6 +24,15 @@ open AstUtils
open Utils
open Microsoft.Boogie
+
+type HeapModel = {
+ heap : Map<Const * VarDecl, Const>;
+ env : Map<Const, Const>;
+ ctx : Set<Set<Const>>;
+}
+
+let MkHeapModel heap env ctx =
+ { heap = heap; env = env; ctx = ctx }
let GetElemFullName (elem: Model.Element) =
elem.Names |> Seq.filter (fun ft -> ft.Func.Arity = 0)
@@ -140,7 +149,11 @@ let ReadHeap (model: Microsoft.Boogie.Model) prog =
let clsName = if dotIdx = -1 then "" else fldFullName.Substring(0, dotIdx)
let refVal = ft.Result
let refObj = Unresolved(GetRefName ref)
- let fldVarOpt = FindVar prog clsName fldName
+ let nonebuilder = CascadingBuilder<_>(None)
+ let fldVarOpt = nonebuilder {
+ let! comp = FindComponent prog clsName
+ return FindVar comp fldName
+ }
match fldVarOpt with
| Some(fldVar) ->
let fldType = match fldVar with
@@ -165,7 +178,7 @@ let rec ReadArgValues (model: Microsoft.Boogie.Model) args =
assert (Seq.length func.Apps = 1)
let ft = Seq.head func.Apps
let fldVal = ConvertValue model (ft.Result)
- ReadArgValues model rest |> Map.add (Unresolved(name)) fldVal
+ ReadArgValues model rest |> Map.add (VarConst(name)) fldVal
| None -> failwith ("cannot find corresponding function for parameter " + name)
| [] -> Map.empty
@@ -234,11 +247,11 @@ let ReadSeq (model: Microsoft.Boogie.Model) (envMap,ctx) =
let f_seq_len = model.MkFunc("Seq#Length", 1)
let f_seq_idx = model.MkFunc("Seq#Index", 2)
- let f_seq_bld = model.MkFunc("Seq#Build", 4)
+ //let f_seq_bld = model.MkFunc("Seq#Build", 4)
let f_seq_app = model.MkFunc("Seq#Append", 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)
+ // |> __ReadSeqBuild model (List.ofSeq f_seq_bld.Apps)
|> __ReadSeqAppend model (List.ofSeq f_seq_app.Apps)
@@ -382,4 +395,4 @@ let ReadFieldValuesFromModel (model: Microsoft.Boogie.Model) prog comp meth =
let heap = ReadHeap model prog
let env0,ctx = ReadEnv model prog
let env = env0 |> Utils.MapAddAll (ReadArgValues model (GetMethodArgs meth))
- heap,env,ctx \ No newline at end of file
+ MkHeapModel heap env ctx \ No newline at end of file
diff --git a/Jennisys/Jennisys/DafnyPrinter.fs b/Jennisys/Jennisys/DafnyPrinter.fs
index d1dc73fc..86974f20 100644
--- a/Jennisys/Jennisys/DafnyPrinter.fs
+++ b/Jennisys/Jennisys/DafnyPrinter.fs
@@ -1,6 +1,7 @@
module DafnyPrinter
open Ast
+open AstUtils
open Printer
let rec PrintType ty =
@@ -56,7 +57,6 @@ let rec PrintConst cst =
| NullConst -> "null"
| NoneConst -> "<none>"
| ThisConst(_,_) -> "this"
- | ExprConst(e) -> PrintExpr 0 e
| NewObj(name,_) -> PrintGenSym name
| Unresolved(name) -> sprintf "Unresolved(%s)" name
@@ -69,4 +69,15 @@ 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 "%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
+ | Var(nm,Some(tp)) -> acc + (sprintf "%s%svar %s: %s;%s" (Indent indent) ghostStr nm (PrintType tp) newline)) ""
+
+let rec PrintStmt stmt indent =
+ let idt = (Indent indent)
+ match stmt with
+ | Block(stmts) ->
+ idt + "{" + newline +
+ (PrintStmtList stmts (indent + 2)) +
+ idt + "}" + newline
+ | Assign(lhs,rhs) -> sprintf "%s%s := %s;%s" idt (PrintExpr 0 lhs) (PrintExpr 0 rhs) newline
+and PrintStmtList stmts indent =
+ stmts |> List.fold (fun acc s -> acc + (PrintStmt s indent)) "" \ No newline at end of file
diff --git a/Jennisys/Jennisys/Jennisys.fsproj b/Jennisys/Jennisys/Jennisys.fsproj
index 5e1bea61..8642cb6b 100644
--- a/Jennisys/Jennisys/Jennisys.fsproj
+++ b/Jennisys/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\Number.jen /method:Number.Abs /checkUnifs</StartArguments>
+ <StartArguments>C:\boogie\Jennisys\Jennisys\examples\Set.jen /method:Set.Triple /genRepr /noVerifyParSol</StartArguments>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<DebugType>pdbonly</DebugType>
diff --git a/Jennisys/Jennisys/Options.fs b/Jennisys/Jennisys/Options.fs
index a03f7213..4bd59b11 100644
--- a/Jennisys/Jennisys/Options.fs
+++ b/Jennisys/Jennisys/Options.fs
@@ -11,19 +11,27 @@ open Utils
type Config = {
inputFilename: string;
methodToSynth: string;
+ verifyPartialSolutions: bool;
verifySolutions: bool;
checkUnifications: bool;
+ genRepr: bool;
timeout: int;
+ numLoopUnrolls: int;
}
let defaultConfig: Config = {
inputFilename = "";
methodToSynth = "*";
+ verifyPartialSolutions = true;
verifySolutions = true;
checkUnifications = false;
+ genRepr = false;
timeout = 0;
+ numLoopUnrolls = 2;
}
+/// Should not be mutated outside the ParseCmdLineArgs method, which is
+/// typically called only once at the beginning of the program execution
let mutable CONFIG = defaultConfig
exception InvalidCmdLineArg of string
@@ -78,6 +86,12 @@ let ParseCmdLineArgs args =
| "method" ->
__CheckNonEmpty value opt
__Parse rest { cfg with methodToSynth = value }
+ | "verifyParSol" ->
+ let b = __CheckBool value opt
+ __Parse rest { cfg with verifyPartialSolutions = b }
+ | "noVerifyParSol" ->
+ let b = __CheckBool value opt
+ __Parse rest { cfg with verifyPartialSolutions = not b }
| "verifySol" ->
let b = __CheckBool value opt
__Parse rest { cfg with verifySolutions = b }
@@ -90,24 +104,24 @@ let ParseCmdLineArgs args =
| "noCheckUnifs" ->
let b = __CheckBool value opt
__Parse rest { cfg with checkUnifications = not b }
+ | "genRepr" ->
+ let b = __CheckBool value opt
+ __Parse rest { cfg with genRepr = b }
+ | "noGenRepr" ->
+ let b = __CheckBool value opt
+ __Parse rest { cfg with genRepr = not b }
| "timeout" ->
let t = __CheckInt value opt
__Parse rest { cfg with timeout = t }
+ | "unrolls" ->
+ let t = __CheckInt value opt
+ __Parse rest { cfg with numLoopUnrolls = t }
| "" ->
__Parse rest { cfg with inputFilename = value }
| _ ->
raise (InvalidCmdLineOption("Unknown option: " + opt))
| [] -> cfg
- let __CheckBool value optName =
- if value = "" then
- true
- else
- try
- System.Boolean.Parse value
- with
- | ex -> raise (InvalidCmdLineArg("Option " + optName " must be boolean"))
-
(* --- function body starts here --- *)
CONFIG <- __Parse args defaultConfig
diff --git a/Jennisys/Jennisys/Printer.fs b/Jennisys/Jennisys/Printer.fs
index e051492f..f8f2933b 100644
--- a/Jennisys/Jennisys/Printer.fs
+++ b/Jennisys/Jennisys/Printer.fs
@@ -1,138 +1,134 @@
-module Printer
-
-open Ast
-open AstUtils
-
-let newline = System.Environment.NewLine // "\r\n"
-
-let PrintGenSym name =
- sprintf "gensym%s" name
-
-let rec PrintSep sep f list =
- match list with
- | [] -> ""
- | [a] -> f a
- | a :: more -> (f a) + sep + (PrintSep sep f more)
-
-let rec PrintType ty =
- match ty with
- | IntType -> "int"
- | BoolType -> "bool"
- | NamedType(id, args) -> if List.isEmpty args then id else (PrintSep ", " (fun s -> s) args)
- | SeqType(t) -> sprintf "seq[%s]" (PrintType t)
- | SetType(t) -> sprintf "set[%s]" (PrintType t)
- | InstantiatedType(id,args) -> sprintf "%s[%s]" id (PrintSep ", " (fun a -> PrintType a) args)
-
-let PrintVarDecl vd =
- match vd with
- | Var(id,None) -> id
- | Var(id,Some(ty)) -> sprintf "%s: %s" id (PrintType ty)
-
-let PrintVarName vd =
- match vd with
- | Var(id,_) -> id
-
-let rec PrintExpr ctx expr =
- match expr with
- | IntLiteral(d) -> sprintf "%d" d
- | BoolLiteral(b) -> sprintf "%b" b
- | ObjLiteral(id)
- | VarLiteral(id)
- | IdLiteral(id) -> id
- | Star -> "*"
- | Dot(e,id) -> sprintf "%s.%s" (PrintExpr 100 e) id
- | UnaryExpr(op,UnaryExpr(op2, e2)) -> sprintf "%s(%s)" op (PrintExpr 90 (UnaryExpr(op2, e2)))
- | UnaryExpr(op,e) -> sprintf "%s%s" op (PrintExpr 90 e)
- | BinaryExpr(strength,op,e0,e1) ->
- let needParens = strength <= ctx
- let openParen = if needParens then "(" else ""
- let closeParen = if needParens then ")" else ""
- sprintf "%s%s %s %s%s" openParen (PrintExpr strength e0) op (PrintExpr strength e1) closeParen
- | IteExpr(c,e1,e2) -> sprintf "%s ? %s : %s" (PrintExpr 25 c) (PrintExpr 25 e1) (PrintExpr 25 e2)
- | SelectExpr(e,i) -> sprintf "%s[%s]" (PrintExpr 100 e) (PrintExpr 0 i)
- | UpdateExpr(e,i,v) -> sprintf "%s[%s := %s]" (PrintExpr 100 e) (PrintExpr 0 i) (PrintExpr 0 v)
- | SequenceExpr(ee) -> sprintf "[%s]" (ee |> PrintSep " " (PrintExpr 0))
- | SeqLength(e) -> sprintf "|%s|" (PrintExpr 0 e)
- | SetExpr(ee) -> sprintf "{%s}" (ee |> PrintSep " " (PrintExpr 0))
- | ForallExpr(vv,e) ->
- let needParens = ctx <> 0
- let openParen = if needParens then "(" else ""
- let closeParen = if needParens then ")" else ""
- sprintf "%sforall %s :: %s%s" openParen (vv |> PrintSep ", " PrintVarDecl) (PrintExpr 0 e) closeParen
-
-let rec PrintConst cst =
- match cst with
- | IntConst(v) -> sprintf "%d" v
- | BoolConst(b) -> sprintf "%b" b
- | VarConst(v) -> sprintf "%s" v
- | SetConst(cset) -> sprintf "{%s}" (PrintSep " " (fun c -> PrintConst c) (Set.toList cset))
- | SeqConst(cseq) -> sprintf "[%s]" (PrintSep " " (fun c -> PrintConst c) cseq)
- | NullConst -> "null"
- | NoneConst -> "<none>"
- | ThisConst(_,_) -> "this"
- | ExprConst(e) -> PrintExpr 0 e
- | NewObj(name,_) -> PrintGenSym name
- | Unresolved(name) -> sprintf "Unresolved(%s)" name
-
-let PrintSig signature =
- match signature with
- | Sig(ins, outs) ->
- let returnClause =
- if outs <> [] then sprintf " returns (%s)" (outs |> PrintSep ", " PrintVarDecl)
- else ""
- sprintf "(%s)%s" (ins |> PrintSep ", " PrintVarDecl) returnClause
-
-let rec Indent i =
- if i = 0 then "" else " " + (Indent (i-1))
-
-let rec PrintStmt stmt indent =
- let idt = (Indent indent)
- match stmt with
- | Block(stmts) ->
- idt + "{" + newline +
- (PrintStmtList stmts (indent + 2)) +
- idt + "}" + newline
- | Assign(lhs,rhs) -> sprintf "%s%s := %s%s" idt (PrintExpr 0 lhs) (PrintExpr 0 rhs) newline
-and PrintStmtList stmts indent =
- stmts |> List.fold (fun acc s -> acc + (PrintStmt s indent)) ""
-
-let PrintRoutine signature pre body =
- let preStr = pre |> ForeachConjunct (fun e -> sprintf " requires %s%s" (PrintExpr 0 e) newline)
- sprintf "%s%s%s%s" (PrintSig signature) newline preStr (PrintExpr 0 body)
-
-let PrintMember m =
- match m with
- | Field(vd) -> sprintf " var %s%s" (PrintVarDecl vd) newline
- | Method(id,signature,pre,body,true) -> sprintf " constructor %s%s" id (PrintRoutine signature pre body)
- | Method(id,signature,pre,body,false) -> sprintf " method %s%s" id (PrintRoutine signature pre body)
- | Invariant(_) -> "" // invariants are handled separately
-
-let PrintTopLevelDeclHeader kind id typeParams =
- let typeParamStr =
- match typeParams with
- | [] -> ""
- | _ -> sprintf "[%s]" (typeParams |> PrintSep ", " (fun tp -> tp))
- sprintf "%s %s%s {%s" kind id typeParamStr newline
-
-let PrintDecl d =
- match d with
- | Class(id,typeParams,members) ->
- sprintf "%s%s}%s" (PrintTopLevelDeclHeader "class" id typeParams)
- (List.fold (fun acc m -> acc + (PrintMember m)) "" members)
- newline
- | Model(id,typeParams,vars,frame,inv) ->
- (PrintTopLevelDeclHeader "model" id typeParams) +
- (vars |> List.fold (fun acc vd -> acc + " var " + (PrintVarDecl vd) + newline) "") +
- " frame" + newline +
- (frame |> List.fold (fun acc fr -> acc + " " + (PrintExpr 0 fr) + newline) "") +
- " invariant" + newline +
- (inv |> ForeachConjunct (fun e -> " " + (PrintExpr 0 e) + newline)) +
- "}" + newline
- | Code(id,typeParams) ->
- (PrintTopLevelDeclHeader "code" id typeParams) + "}" + newline
-
-let PrintMethodSignFull indent m =
- let idt = Indent indent
+module Printer
+
+open Ast
+open AstUtils
+
+let newline = System.Environment.NewLine // "\r\n"
+
+let rec PrintSep sep f list =
+ match list with
+ | [] -> ""
+ | [a] -> f a
+ | a :: more -> (f a) + sep + (PrintSep sep f more)
+
+let rec PrintType ty =
+ match ty with
+ | IntType -> "int"
+ | BoolType -> "bool"
+ | NamedType(id, args) -> if List.isEmpty args then id else (PrintSep ", " (fun s -> s) args)
+ | SeqType(t) -> sprintf "seq[%s]" (PrintType t)
+ | SetType(t) -> sprintf "set[%s]" (PrintType t)
+ | InstantiatedType(id,args) -> sprintf "%s[%s]" id (PrintSep ", " (fun a -> PrintType a) args)
+
+let PrintVarDecl vd =
+ match vd with
+ | Var(id,None) -> id
+ | Var(id,Some(ty)) -> sprintf "%s: %s" id (PrintType ty)
+
+let PrintVarName vd =
+ match vd with
+ | Var(id,_) -> id
+
+let rec PrintExpr ctx expr =
+ match expr with
+ | IntLiteral(d) -> sprintf "%d" d
+ | BoolLiteral(b) -> sprintf "%b" b
+ | ObjLiteral(id)
+ | VarLiteral(id)
+ | IdLiteral(id) -> id
+ | Star -> "*"
+ | Dot(e,id) -> sprintf "%s.%s" (PrintExpr 100 e) id
+ | UnaryExpr(op,UnaryExpr(op2, e2)) -> sprintf "%s(%s)" op (PrintExpr 90 (UnaryExpr(op2, e2)))
+ | UnaryExpr(op,e) -> sprintf "%s%s" op (PrintExpr 90 e)
+ | BinaryExpr(strength,op,e0,e1) ->
+ let needParens = strength <= ctx
+ let openParen = if needParens then "(" else ""
+ let closeParen = if needParens then ")" else ""
+ sprintf "%s%s %s %s%s" openParen (PrintExpr strength e0) op (PrintExpr strength e1) closeParen
+ | IteExpr(c,e1,e2) -> sprintf "%s ? %s : %s" (PrintExpr 25 c) (PrintExpr 25 e1) (PrintExpr 25 e2)
+ | SelectExpr(e,i) -> sprintf "%s[%s]" (PrintExpr 100 e) (PrintExpr 0 i)
+ | UpdateExpr(e,i,v) -> sprintf "%s[%s := %s]" (PrintExpr 100 e) (PrintExpr 0 i) (PrintExpr 0 v)
+ | SequenceExpr(ee) -> sprintf "[%s]" (ee |> PrintSep " " (PrintExpr 0))
+ | SeqLength(e) -> sprintf "|%s|" (PrintExpr 0 e)
+ | SetExpr(ee) -> sprintf "{%s}" (ee |> PrintSep " " (PrintExpr 0))
+ | ForallExpr(vv,e) ->
+ let needParens = ctx <> 0
+ let openParen = if needParens then "(" else ""
+ let closeParen = if needParens then ")" else ""
+ sprintf "%sforall %s :: %s%s" openParen (vv |> PrintSep ", " PrintVarDecl) (PrintExpr 0 e) closeParen
+
+let rec PrintConst cst =
+ match cst with
+ | IntConst(v) -> sprintf "%d" v
+ | BoolConst(b) -> sprintf "%b" b
+ | VarConst(v) -> sprintf "%s" v
+ | SetConst(cset) -> sprintf "{%s}" (PrintSep " " (fun c -> PrintConst c) (Set.toList cset))
+ | SeqConst(cseq) -> sprintf "[%s]" (PrintSep " " (fun c -> PrintConst c) cseq)
+ | NullConst -> "null"
+ | NoneConst -> "<none>"
+ | ThisConst(_,_) -> "this"
+ | NewObj(name,_) -> PrintGenSym name
+ | Unresolved(name) -> sprintf "Unresolved(%s)" name
+
+let PrintSig signature =
+ match signature with
+ | Sig(ins, outs) ->
+ let returnClause =
+ if outs <> [] then sprintf " returns (%s)" (outs |> PrintSep ", " PrintVarDecl)
+ else ""
+ sprintf "(%s)%s" (ins |> PrintSep ", " PrintVarDecl) returnClause
+
+let rec Indent i =
+ if i = 0 then "" else " " + (Indent (i-1))
+
+let rec PrintStmt stmt indent =
+ let idt = (Indent indent)
+ match stmt with
+ | Block(stmts) ->
+ idt + "{" + newline +
+ (PrintStmtList stmts (indent + 2)) +
+ idt + "}" + newline
+ | Assign(lhs,rhs) -> sprintf "%s%s := %s%s" idt (PrintExpr 0 lhs) (PrintExpr 0 rhs) newline
+and PrintStmtList stmts indent =
+ stmts |> List.fold (fun acc s -> acc + (PrintStmt s indent)) ""
+
+let PrintRoutine signature pre body =
+ let preStr = pre |> ForeachConjunct (fun e -> sprintf " requires %s%s" (PrintExpr 0 e) newline)
+ sprintf "%s%s%s%s" (PrintSig signature) newline preStr (PrintExpr 0 body)
+
+let PrintMember m =
+ match m with
+ | Field(vd) -> sprintf " var %s%s" (PrintVarDecl vd) newline
+ | Method(id,signature,pre,body,true) -> sprintf " constructor %s%s" id (PrintRoutine signature pre body)
+ | Method(id,signature,pre,body,false) -> sprintf " method %s%s" id (PrintRoutine signature pre body)
+ | Invariant(_) -> "" // invariants are handled separately
+
+let PrintTopLevelDeclHeader kind id typeParams =
+ let typeParamStr =
+ match typeParams with
+ | [] -> ""
+ | _ -> sprintf "[%s]" (typeParams |> PrintSep ", " (fun tp -> tp))
+ sprintf "%s %s%s {%s" kind id typeParamStr newline
+
+let PrintDecl d =
+ match d with
+ | Class(id,typeParams,members) ->
+ sprintf "%s%s}%s" (PrintTopLevelDeclHeader "class" id typeParams)
+ (List.fold (fun acc m -> acc + (PrintMember m)) "" members)
+ newline
+ | Model(id,typeParams,vars,frame,inv) ->
+ (PrintTopLevelDeclHeader "model" id typeParams) +
+ (vars |> List.fold (fun acc vd -> acc + " var " + (PrintVarDecl vd) + newline) "") +
+ " frame" + newline +
+ (frame |> List.fold (fun acc fr -> acc + " " + (PrintExpr 0 fr) + newline) "") +
+ " invariant" + newline +
+ (inv |> ForeachConjunct (fun e -> " " + (PrintExpr 0 e) + newline)) +
+ "}" + newline
+ | Code(id,typeParams) ->
+ (PrintTopLevelDeclHeader "code" id typeParams) + "}" + newline
+
+let PrintMethodSignFull indent m =
+ let idt = Indent indent
let __PrintPrePost pfix expr = SplitIntoConjunts expr |> PrintSep newline (fun e -> pfix + (PrintExpr 0 e) + ";")
match m with
| Method(methodName, sgn, pre, post, isConstr) ->
@@ -142,9 +138,15 @@ let PrintMethodSignFull indent m =
idt + mc + " " + methodName + (PrintSig sgn) + newline +
preStr + (if preStr = "" then "" else newline) +
postStr
-
- | _ -> failwithf "not a method: %O" m
-
-let Print prog =
- match prog with
- | SProgram(decls) -> List.fold (fun acc d -> acc + (PrintDecl d)) "" decls
+
+ | _ -> failwithf "not a method: %O" m
+
+let Print prog =
+ match prog with
+ | SProgram(decls) -> List.fold (fun acc d -> acc + (PrintDecl d)) "" decls
+
+let PrintObjRefName o =
+ match o with
+ | ThisConst(_,_) -> "this";
+ | NewObj(name, _) -> PrintGenSym name
+ | _ -> failwith ("unresolved object ref: " + o.ToString()) \ No newline at end of file
diff --git a/Jennisys/Jennisys/Resolver.fs b/Jennisys/Jennisys/Resolver.fs
index af49e51a..64f80584 100644
--- a/Jennisys/Jennisys/Resolver.fs
+++ b/Jennisys/Jennisys/Resolver.fs
@@ -11,6 +11,15 @@ open Ast
open AstUtils
open Printer
open EnvUtils
+open DafnyModelUtils
+
+type Obj = { name: string; objType: Type }
+
+type HeapInstance = {
+ assignments: Map<Obj * VarDecl, Expr>; // the first string is the symbolic name of an object literal
+ methodArgs: Map<string, Const>;
+ globals: Map<string, Expr>;
+}
// resolving values
exception ConstResolveFailed of string
@@ -21,30 +30,35 @@ exception ConstResolveFailed of string
/// If unable to resolve, it just delegates the task to the
/// failResolver function
// ================================================================
-let rec ResolveCont (env,ctx) failResolver cst =
+let rec ResolveCont hModel failResolver cst =
match cst with
| Unresolved(_) as u ->
// see if it is in the env map first
- let envVal = Map.tryFind cst env
+ let envVal = Map.tryFind cst hModel.env
match envVal with
- | Some(c) -> ResolveCont (env,ctx) failResolver c
+ | Some(c) -> ResolveCont hModel failResolver c
| None ->
// not found in the env map --> check the equality sets
- let eq = ctx |> Set.filter (fun eqSet -> Set.contains u eqSet)
- |> Utils.SetToOption
+ let eq = hModel.ctx |> Set.filter (fun eqSet -> Set.contains u eqSet)
+ |> Utils.SetToOption
match eq with
| Some(eqSet) ->
let cOpt = eqSet |> Set.filter (function Unresolved(_) -> false | _ -> true)
|> Utils.SetToOption
match cOpt with
| Some(c) -> c
- | _ -> failResolver cst (env,ctx)
- | _ -> failResolver cst (env,ctx)
+ | _ -> failResolver cst hModel
+ | None ->
+ // finally, see if it's a method argument
+ let m = hModel.env |> Map.filter (fun k v -> v = u && match k with VarConst(name) -> true | _ -> false) |> Map.toList
+ match m with
+ | (vc,_) :: [] -> vc
+ | _ -> failResolver cst hModel
| SeqConst(cseq) ->
- let resolvedLst = cseq |> List.rev |> List.fold (fun acc c -> ResolveCont (env,ctx) failResolver c :: acc) []
+ let resolvedLst = cseq |> List.rev |> List.fold (fun acc c -> ResolveCont hModel failResolver c :: acc) []
SeqConst(resolvedLst)
| SetConst(cset) ->
- let resolvedSet = cset |> Set.fold (fun acc c -> acc |> Set.add (ResolveCont (env,ctx) failResolver c)) Set.empty
+ let resolvedSet = cset |> Set.fold (fun acc c -> acc |> Set.add (ResolveCont hModel failResolver c)) Set.empty
SetConst(resolvedSet)
| _ -> cst
@@ -53,39 +67,69 @@ let rec ResolveCont (env,ctx) failResolver cst =
///
/// If unable to resolve, just returns the original Unresolved const.
// =====================================================================
-let TryResolve (env,ctx) cst =
- ResolveCont (env,ctx) (fun c (e,x) -> c) cst
+let TryResolve hModel cst =
+ ResolveCont hModel (fun c _ -> c) cst
// ==============================================================
/// Resolves a given Const (cst) with respect to a given env/ctx.
///
/// If unable to resolve, raises a ConstResolveFailed exception
// ==============================================================
-let Resolve (env,ctx) cst =
- ResolveCont (env,ctx) (fun c (e,x) -> raise (ConstResolveFailed("failed to resolve " + c.ToString()))) cst
-
-// =================================================================
-/// Evaluates a given expression with respect to a given heap/env/ctx
-// =================================================================
-let Eval (heap,env,ctx) resolveVars expr =
+let Resolve hModel cst =
+ ResolveCont hModel (fun c _ -> raise (ConstResolveFailed("failed to resolve " + c.ToString()))) cst
+
+// ==================================================================
+/// Evaluates a given expression with respect to a given heap instance
+// ==================================================================
+let Eval heapInst resolveVars expr =
let rec __EvalResolver expr =
match expr with
- | VarLiteral(id) when not resolveVars -> VarConst(id)
- | ObjLiteral("this") -> GetThisLoc env
- | ObjLiteral("null") -> NullConst
- | IdLiteral("this") | IdLiteral("null") -> failwith "should never happen anymore" //TODO
- | VarLiteral(id)
+ | VarLiteral(id) when not resolveVars -> expr
+ | ObjLiteral("this") | ObjLiteral("null") -> expr
+ | IdLiteral("this") | IdLiteral("null") -> failwith "should never happen anymore" //TODO
+ | VarLiteral(id) ->
+ let argValue = heapInst.methodArgs |> Map.tryFind id |> Utils.ExtractOptionMsg ("cannot find value for method parameter " + id)
+ argValue |> Const2Expr
| IdLiteral(id) ->
- match TryResolve (env,ctx) (Unresolved(id)) with
- | Unresolved(_) -> __EvalResolver (Dot(ObjLiteral("this"), id))
- | _ as c -> c
+ let globalVal = heapInst.globals |> Map.tryFind id
+ match globalVal with
+ | Some(e) -> e
+ | None -> __EvalResolver (Dot(ObjLiteral("this"), id))
| Dot(e, str) ->
let discr = __EvalResolver e
- let h2 = Map.filter (fun (loc,Var(fldName,_)) v -> loc = discr && fldName = str) heap |> Map.toList
- match h2 with
- | ((_,_),x) :: [] -> x
- | _ :: _ -> raise (EvalFailed(sprintf "can't evaluate expression deterministically: %s.%s resolves to multiple locations" (PrintConst discr) str))
- | [] -> raise (EvalFailed(sprintf "can't find value for %s.%s" (PrintConst discr) str))
+ match discr with
+ | ObjLiteral(objName) ->
+ let h2 = heapInst.assignments |> Map.filter (fun (o,Var(fldName,_)) v -> o.name = objName && fldName = str) |> Map.toList
+ match h2 with
+ | ((_,_),x) :: [] -> x
+ | _ :: _ -> raise (EvalFailed(sprintf "can't evaluate expression deterministically: %s.%s resolves to multiple locations" objName str))
+ | [] -> raise (EvalFailed(sprintf "can't find value for %s.%s" objName str)) // TODO: what if that value doesn't matter for the solution, and that's why it's not present in the model???
+ | _ -> raise (EvalFailed(sprintf "Dot expression discriminator does not resolve to an object literal but %O" discr))
| _ -> failwith ("NOT IMPLEMENTED YET: " + (PrintExpr 0 expr))
(* --- function body starts here --- *)
- EvalSym (fun e -> __EvalResolver e |> Resolve (env,ctx) |> Const2Expr) expr
+ EvalSym (fun e -> __EvalResolver e) expr
+
+// =====================================================================
+/// Takes an unresolved model of the heap (HeapModel), resolves all
+/// references in the model and returns an instance of the heap
+/// (HeapInstance), where all fields for all objects have explicit
+/// assignments.
+// =====================================================================
+let ResolveModel hModel =
+ let hmap = hModel.heap |> Map.fold (fun acc (o,f) l ->
+ let objName, objType = match Resolve hModel o with
+ | ThisConst(_,t) -> "this", t;
+ | NewObj(name, t) -> PrintGenSym name, t
+ | _ -> failwith ("unresolved object ref: " + o.ToString())
+ let objType = objType |> Utils.ExtractOptionMsg "unknown object type"
+ let value = TryResolve hModel l |> Const2Expr
+ acc |> Map.add ({name = objName; objType = objType}, f) value
+ ) Map.empty
+ let argmap = hModel.env |> Map.fold (fun acc k v ->
+ match k with
+ | VarConst(name) -> acc |> Map.add name (Resolve hModel v)
+ | _ -> acc
+ ) Map.empty
+ { assignments = hmap;
+ methodArgs = argmap;
+ globals = Map.empty } \ No newline at end of file
diff --git a/Jennisys/Jennisys/Utils.fs b/Jennisys/Jennisys/Utils.fs
index 886d5868..c9f18e23 100644
--- a/Jennisys/Jennisys/Utils.fs
+++ b/Jennisys/Jennisys/Utils.fs
@@ -48,6 +48,15 @@ let ExtractOptionMsg msg x =
let ExtractOption x =
ExtractOptionMsg "can't extract anything from a None" x
+// ====================================
+/// ensures: res = Some(a) ==> ret = a
+/// ensures: res = None ==> ret = defVal
+// ====================================
+let ExtractOptionOr defVal opt =
+ match opt with
+ | Some(a) -> a
+ | None -> defVal
+
// ==========================================================
/// requres: List.length lst <= 1, otherwise fails with errMsg
/// ensures: if |lst| = 0 then
@@ -135,6 +144,12 @@ let ListReplace oldElem newElem lst =
let ListContains elem lst =
lst |> List.exists (fun e -> e = elem)
+// ====================================================
+/// Removes all elements in lst that are equal to "elem"
+// ====================================================
+let ListRemove elem lst =
+ lst |> List.choose (fun e -> if e = elem then None else Some(e))
+
// ===============================================================
/// ensures: |ret| = max(|lst| - cnt, 0)
/// ensures: forall i :: cnt <= i < |lst| ==> ret[i] = lst[i-cnt]
@@ -194,6 +209,25 @@ let rec ListSet idx v lst =
// =======================================
let rec MapAddAll map1 map2 =
map2 |> Map.fold (fun acc k v -> acc |> Map.add k v) map1
+
+// -------------------------------------------
+// ------------ algorithms -------------------
+// -------------------------------------------
+
+// =======================================================================
+/// Topologically sorts a given list
+///
+/// ensures: |ret| = |lst|
+/// ensures: forall e in lst :: e in ret
+/// ensures: forall i,j :: 0 <= i < j < ==> not (followsFunc ret[j] ret[i])
+// =======================================================================
+let rec TopSort followsFunc lst =
+ match lst with
+ | [] -> []
+ | fs :: [] -> [fs]
+ | fs :: rest ->
+ let min = rest |> List.fold (fun acc elem -> if followsFunc acc elem then elem else acc) fs
+ min :: TopSort followsFunc (ListRemove min lst)
// -------------------------------------------
// ------ string active patterns -------------
@@ -221,6 +255,12 @@ let IfDo2 cond func2 (a1,a2) =
else
a1,a2
+let Ite cond f1 f2 =
+ if cond then
+ f1
+ else
+ f2
+
type CascadingBuilder<'a>(failVal: 'a) =
member this.Bind(v, f) =
match v with
diff --git a/Jennisys/Jennisys/examples/List.jen b/Jennisys/Jennisys/examples/List.jen
index e7f42ddc..63535a20 100644
--- a/Jennisys/Jennisys/examples/List.jen
+++ b/Jennisys/Jennisys/examples/List.jen
@@ -15,10 +15,10 @@ model List[T] {
var root: Node[T]
frame
- root * root.list[*]
+ root
invariant
- (root = null) ==> (|list| = 0)
+ root = null ==> |list| = 0
root != null ==> list = root.list
}
@@ -40,7 +40,7 @@ model Node[T] {
var next: Node[T]
frame
- data * next
+ next
invariant
next = null <==> list = [data]
diff --git a/Jennisys/Jennisys/examples/List2.jen b/Jennisys/Jennisys/examples/List2.jen
index e99cf342..61fad148 100644
--- a/Jennisys/Jennisys/examples/List2.jen
+++ b/Jennisys/Jennisys/examples/List2.jen
@@ -27,7 +27,7 @@ model IntList {
var root: IntNode
frame
- root * root.list[*]
+ root
invariant
root = null <==> |list| = 0
@@ -49,7 +49,7 @@ model IntNode {
var next: IntNode
frame
- data * next
+ next
invariant
next = null ==> list = [data]
diff --git a/Jennisys/Jennisys/examples/List3.jen b/Jennisys/Jennisys/examples/List3.jen
index acb10ad5..776bd43d 100644
--- a/Jennisys/Jennisys/examples/List3.jen
+++ b/Jennisys/Jennisys/examples/List3.jen
@@ -27,7 +27,7 @@ model IntList {
var root: IntNode
frame
- root * root.list[*]
+ root
invariant
root = null ==> |list| = 0
@@ -63,7 +63,7 @@ model IntNode {
var next: IntNode
frame
- data * next
+ next
invariant
next = null ==> |succ| = 0
diff --git a/Jennisys/Jennisys/examples/Set.jen b/Jennisys/Jennisys/examples/Set.jen
index 6404bfd6..6006268e 100644
--- a/Jennisys/Jennisys/examples/Set.jen
+++ b/Jennisys/Jennisys/examples/Set.jen
@@ -13,13 +13,17 @@ class Set {
constructor Double(p: int, q: int)
requires p != q
ensures elems = {p q}
+
+ constructor Triple(p: int, q: int, r: int)
+ requires p != q && q != r && r != p
+ ensures elems = {p q r}
}
model Set {
var root: SetNode
frame
- root * root.elems[*]
+ root
invariant
root = null ==> elems = {}
@@ -35,6 +39,10 @@ class SetNode {
constructor Double(p: int, q: int)
requires p != q
ensures elems = {p q}
+
+ constructor Triple(p: int, q: int, r: int)
+ requires p != q && q != r && r != p
+ ensures elems = {p q r}
}
model SetNode {
@@ -43,7 +51,7 @@ model SetNode {
var right: SetNode
frame
- data * left * right
+ left * right
invariant
elems = {data} + (left != null ? left.elems : {}) + (right != null ? right.elems : {})
diff --git a/Jennisys/Jennisys/examples/jennisys-synth_List.dfy b/Jennisys/Jennisys/examples/jennisys-synth_List.dfy
new file mode 100644
index 00000000..0611c78b
--- /dev/null
+++ b/Jennisys/Jennisys/examples/jennisys-synth_List.dfy
@@ -0,0 +1,147 @@
+class List<T> {
+ ghost var Repr: set<object>;
+ ghost var list: seq<T>;
+
+ var root: Node<T>;
+
+ function Valid_repr(): bool
+ reads *;
+ {
+ this in Repr &&
+ null !in Repr &&
+ (root != null ==> root in Repr && root.Repr <= Repr && this !in root.Repr)
+ }
+
+ function Valid_self(): bool
+ reads *;
+ {
+ Valid_repr() &&
+ (root == null ==> |list| == 0) &&
+ (root != null ==> list == root.list)
+ }
+
+ function Valid(): bool
+ reads *;
+ {
+ this.Valid_self() &&
+ (root != null ==> root.Valid())
+ }
+
+ method Empty()
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [];
+ {
+ this.list := [];
+ this.root := null;
+ // repr stuff
+ this.Repr := {this};
+ }
+
+ method Singleton(t: T)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [t];
+ {
+ var gensym65 := new Node<T>;
+ gensym65.data := t;
+ gensym65.list := [t];
+ gensym65.next := null;
+ this.list := [t];
+ this.root := gensym65;
+ // repr stuff
+ gensym65.Repr := {gensym65};
+ this.Repr := {this} + this.root.Repr;
+ }
+
+ method Double(p: T, q: T)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [p, q];
+ {
+ var gensym66 := new Node<T>;
+ var gensym67 := new Node<T>;
+ gensym66.data := p;
+ gensym66.list := [p, q];
+ gensym66.next := gensym67;
+ gensym67.data := q;
+ gensym67.list := [q];
+ gensym67.next := null;
+ this.list := [p, q];
+ this.root := gensym66;
+ // repr stuff
+ gensym67.Repr := {gensym67};
+ gensym66.Repr := {gensym66} + gensym66.next.Repr;
+ this.Repr := {this} + this.root.Repr;
+ }
+
+}
+
+class Node<T> {
+ ghost var Repr: set<object>;
+ ghost var list: seq<T>;
+
+ var data: T;
+ var next: Node<T>;
+
+ function Valid_repr(): bool
+ reads *;
+ {
+ this in Repr &&
+ null !in Repr &&
+ (next != null ==> next in Repr && next.Repr <= Repr && this !in next.Repr)
+ }
+
+ function Valid_self(): bool
+ reads *;
+ {
+ Valid_repr() &&
+ (next == null <==> list == [data] && list[0] == data) &&
+ (next != null ==> list == [data] + next.list) &&
+ (|list| > 0)
+ }
+
+ function Valid(): bool
+ reads *;
+ {
+ this.Valid_self() &&
+ (next != null ==> next.Valid_self() && (next.next != null ==> next.next.Valid_self()))
+ }
+
+ method Init(t: T)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [t];
+ {
+ this.data := t;
+ this.list := [t];
+ this.next := null;
+ // repr stuff
+ this.Repr := {this};
+ }
+
+ method Double(p: T, q: T)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [p, q];
+ {
+ var gensym71 := new Node<T>;
+ gensym71.data := q;
+ gensym71.list := [q];
+ gensym71.next := null;
+ this.data := p;
+ this.list := [p, q];
+ this.next := gensym71;
+ // repr stuff
+ gensym71.Repr := {gensym71};
+ this.Repr := {this} + this.next.Repr;
+ }
+
+}
+
+
diff --git a/Jennisys/Jennisys/examples/jennisys-synth_List2.dfy b/Jennisys/Jennisys/examples/jennisys-synth_List2.dfy
new file mode 100644
index 00000000..13e521a8
--- /dev/null
+++ b/Jennisys/Jennisys/examples/jennisys-synth_List2.dfy
@@ -0,0 +1,207 @@
+class IntList {
+ ghost var Repr: set<object>;
+ ghost var list: seq<int>;
+
+ var root: IntNode;
+
+ function Valid_repr(): bool
+ reads *;
+ {
+ this in Repr &&
+ null !in Repr &&
+ (root != null ==> root in Repr && root.Repr <= Repr && this !in root.Repr)
+ }
+
+ function Valid_self(): bool
+ reads *;
+ {
+ Valid_repr() &&
+ (root == null <==> |list| == 0) &&
+ (root != null ==> list == root.list)
+ }
+
+ function Valid(): bool
+ reads *;
+ {
+ this.Valid_self() &&
+ (root != null ==> root.Valid())
+ }
+
+ method Empty()
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [];
+ {
+ this.list := [];
+ this.root := null;
+ // repr stuff
+ this.Repr := {this};
+ }
+
+ method SingletonTwo()
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [2];
+ {
+ var gensym65 := new IntNode;
+ gensym65.data := 2;
+ gensym65.list := [2];
+ gensym65.next := null;
+ this.list := [2];
+ this.root := gensym65;
+ // repr stuff
+ gensym65.Repr := {gensym65};
+ this.Repr := {this} + this.root.Repr;
+ }
+
+ method OneTwo()
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [1] + [2];
+ {
+ var gensym62 := new IntNode;
+ var gensym69 := new IntNode;
+ gensym62.data := 1;
+ gensym62.list := [1, 2];
+ gensym62.next := gensym69;
+ gensym69.data := 2;
+ gensym69.list := [2];
+ gensym69.next := null;
+ this.list := [1, 2];
+ this.root := gensym62;
+ // repr stuff
+ gensym69.Repr := {gensym69};
+ gensym62.Repr := {gensym62} + gensym62.next.Repr;
+ this.Repr := {this} + this.root.Repr;
+ }
+
+ method Singleton(p: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [p];
+ {
+ var gensym66 := new IntNode;
+ gensym66.data := p;
+ gensym66.list := [p];
+ gensym66.next := null;
+ this.list := [p];
+ this.root := gensym66;
+ // repr stuff
+ gensym66.Repr := {gensym66};
+ this.Repr := {this} + this.root.Repr;
+ }
+
+ method TwoConsecutive(p: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [p] + [p + 1];
+ {
+ var gensym63 := new IntNode;
+ var gensym71 := new IntNode;
+ gensym63.data := p;
+ gensym63.list := [p] + [p + 1];
+ gensym63.next := gensym71;
+ gensym71.data := p + 1;
+ gensym71.list := [p + 1];
+ gensym71.next := null;
+ this.list := [p] + [p + 1];
+ this.root := gensym63;
+ // repr stuff
+ gensym71.Repr := {gensym71};
+ gensym63.Repr := {gensym63} + gensym63.next.Repr;
+ this.Repr := {this} + this.root.Repr;
+ }
+
+ method Double(p: int, q: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [p] + [q];
+ {
+ var gensym64 := new IntNode;
+ var gensym71 := new IntNode;
+ gensym64.data := p;
+ gensym64.list := [p] + [q];
+ gensym64.next := gensym71;
+ gensym71.data := q;
+ gensym71.list := [q];
+ gensym71.next := null;
+ this.list := [p] + [q];
+ this.root := gensym64;
+ // repr stuff
+ gensym71.Repr := {gensym71};
+ gensym64.Repr := {gensym64} + gensym64.next.Repr;
+ this.Repr := {this} + this.root.Repr;
+ }
+
+ method Sum(p: int, q: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [p + q];
+ {
+ var gensym67 := new IntNode;
+ gensym67.data := p + q;
+ gensym67.list := [p + q];
+ gensym67.next := null;
+ this.list := [p + q];
+ this.root := gensym67;
+ // repr stuff
+ gensym67.Repr := {gensym67};
+ this.Repr := {this} + this.root.Repr;
+ }
+
+}
+
+class IntNode {
+ ghost var Repr: set<object>;
+ ghost var list: seq<int>;
+
+ var data: int;
+ var next: IntNode;
+
+ function Valid_repr(): bool
+ reads *;
+ {
+ this in Repr &&
+ null !in Repr &&
+ (next != null ==> next in Repr && next.Repr <= Repr && this !in next.Repr)
+ }
+
+ function Valid_self(): bool
+ reads *;
+ {
+ Valid_repr() &&
+ (next == null ==> list == [data] && list[0] == data) &&
+ (next != null ==> list == [data] + next.list) &&
+ (|list| > 0)
+ }
+
+ function Valid(): bool
+ reads *;
+ {
+ this.Valid_self() &&
+ (next != null ==> next.Valid_self() && (next.next != null ==> next.next.Valid_self()))
+ }
+
+ method SingletonZero()
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [0];
+ {
+ this.data := 0;
+ this.list := [0];
+ this.next := null;
+ // repr stuff
+ this.Repr := {this};
+ }
+
+}
+
+
diff --git a/Jennisys/Jennisys/examples/jennisys-synth_List3.dfy b/Jennisys/Jennisys/examples/jennisys-synth_List3.dfy
new file mode 100644
index 00000000..e202412f
--- /dev/null
+++ b/Jennisys/Jennisys/examples/jennisys-synth_List3.dfy
@@ -0,0 +1,255 @@
+class IntList {
+ ghost var Repr: set<object>;
+ ghost var list: seq<int>;
+
+ var root: IntNode;
+
+ function Valid_repr(): bool
+ reads *;
+ {
+ this in Repr &&
+ null !in Repr &&
+ (root != null ==> root in Repr && root.Repr <= Repr && this !in root.Repr)
+ }
+
+ function Valid_self(): bool
+ reads *;
+ {
+ Valid_repr() &&
+ (root == null ==> |list| == 0) &&
+ (root != null ==> |list| == |root.succ| + 1 && (list[0] == root.data && (forall i: int :: 0 < i && i <= |root.succ| ==> root.succ[i - 1] != null && list[i] == root.succ[i - 1].data)))
+ }
+
+ function Valid(): bool
+ reads *;
+ {
+ this.Valid_self() &&
+ (root != null ==> root.Valid())
+ }
+
+ method Empty()
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [];
+ {
+ this.list := [];
+ this.root := null;
+ // repr stuff
+ this.Repr := {this};
+ }
+
+ method SingletonTwo()
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [2];
+ {
+ var gensym65 := new IntNode;
+ gensym65.data := 2;
+ gensym65.next := null;
+ gensym65.succ := [];
+ this.list := [2];
+ this.root := gensym65;
+ // repr stuff
+ gensym65.Repr := {gensym65};
+ this.Repr := {this} + this.root.Repr;
+ }
+
+ method OneTwo()
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [1] + [2];
+ {
+ var gensym63 := new IntNode;
+ var gensym75 := new IntNode;
+ gensym63.data := 1;
+ gensym63.next := gensym75;
+ gensym63.succ := [gensym75];
+ gensym75.data := 2;
+ gensym75.next := null;
+ gensym75.succ := [];
+ this.list := [1, 2];
+ this.root := gensym63;
+ // repr stuff
+ gensym75.Repr := {gensym75};
+ gensym63.Repr := {gensym63} + gensym63.next.Repr;
+ this.Repr := {this} + this.root.Repr;
+ }
+
+ method Singleton(p: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [p];
+ {
+ var gensym66 := new IntNode;
+ gensym66.data := p;
+ gensym66.next := null;
+ gensym66.succ := [];
+ this.list := [p];
+ this.root := gensym66;
+ // repr stuff
+ gensym66.Repr := {gensym66};
+ this.Repr := {this} + this.root.Repr;
+ }
+
+ method TwoConsecutive(p: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [p] + [p + 1];
+ {
+ var gensym64 := new IntNode;
+ var gensym75 := new IntNode;
+ gensym64.data := p;
+ gensym64.next := gensym75;
+ gensym64.succ := [gensym75];
+ gensym75.data := p + 1;
+ gensym75.next := null;
+ gensym75.succ := [];
+ this.list := [p] + [p + 1];
+ this.root := gensym64;
+ // repr stuff
+ gensym75.Repr := {gensym75};
+ gensym64.Repr := {gensym64} + gensym64.next.Repr;
+ this.Repr := {this} + this.root.Repr;
+ }
+
+ method Double(p: int, q: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [p] + [q];
+ {
+ var gensym65 := new IntNode;
+ var gensym77 := new IntNode;
+ gensym65.data := p;
+ gensym65.next := gensym77;
+ gensym65.succ := [gensym77];
+ gensym77.data := q;
+ gensym77.next := null;
+ gensym77.succ := [];
+ this.list := [p] + [q];
+ this.root := gensym65;
+ // repr stuff
+ gensym77.Repr := {gensym77};
+ gensym65.Repr := {gensym65} + gensym65.next.Repr;
+ this.Repr := {this} + this.root.Repr;
+ }
+
+ method Sum(p: int, q: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [p + q];
+ {
+ var gensym67 := new IntNode;
+ gensym67.data := p + q;
+ gensym67.next := null;
+ gensym67.succ := [];
+ this.list := [p + q];
+ this.root := gensym67;
+ // repr stuff
+ gensym67.Repr := {gensym67};
+ this.Repr := {this} + this.root.Repr;
+ }
+
+}
+
+class IntNode {
+ ghost var Repr: set<object>;
+ ghost var succ: seq<IntNode>;
+ ghost var data: int;
+
+ var next: IntNode;
+
+ function Valid_repr(): bool
+ reads *;
+ {
+ this in Repr &&
+ null !in Repr &&
+ (next != null ==> next in Repr && next.Repr <= Repr && this !in next.Repr)
+ }
+
+ function Valid_self(): bool
+ reads *;
+ {
+ Valid_repr() &&
+ (next == null ==> |succ| == 0) &&
+ (next != null ==> succ == [next] + next.succ) &&
+ (!(null in succ))
+ }
+
+ function Valid(): bool
+ reads *;
+ {
+ this.Valid_self() &&
+ (next != null ==> next.Valid_self() && (next.next != null ==> next.next.Valid_self()))
+ }
+
+ method Zero()
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures data == 0;
+ ensures succ == [];
+ {
+ this.data := 0;
+ this.next := null;
+ this.succ := [];
+ // repr stuff
+ this.Repr := {this};
+ }
+
+ method OneTwo()
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures data == 1;
+ ensures |succ| == 1;
+ ensures succ[0] != null;
+ ensures succ[0].data == 2;
+ {
+ var gensym71 := new IntNode;
+ gensym71.data := 2;
+ gensym71.next := null;
+ gensym71.succ := [];
+ this.data := 1;
+ this.next := gensym71;
+ this.succ := [gensym71];
+ // repr stuff
+ gensym71.Repr := {gensym71};
+ this.Repr := {this} + this.next.Repr;
+ }
+
+ method Init(p: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures data == p;
+ {
+ this.data := p;
+ this.next := null;
+ this.succ := [];
+ // repr stuff
+ this.Repr := {this};
+ }
+
+ method InitInc(p: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures data == p + 1;
+ {
+ this.data := p + 1;
+ this.next := null;
+ this.succ := [];
+ // repr stuff
+ this.Repr := {this};
+ }
+
+}
+
+
diff --git a/Jennisys/Jennisys/examples/jennisys-synth_Number.dfy b/Jennisys/Jennisys/examples/jennisys-synth_Number.dfy
new file mode 100644
index 00000000..5ede7f5c
--- /dev/null
+++ b/Jennisys/Jennisys/examples/jennisys-synth_Number.dfy
@@ -0,0 +1,202 @@
+class Number {
+ ghost var Repr: set<object>;
+ ghost var num: int;
+
+
+ function Valid_repr(): bool
+ reads *;
+ {
+ this in Repr &&
+ null !in Repr
+ }
+
+ function Valid_self(): bool
+ reads *;
+ {
+ Valid_repr() &&
+ true
+ }
+
+ function Valid(): bool
+ reads *;
+ {
+ this.Valid_self() &&
+ true
+ }
+
+ method Init(p: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures num == p;
+ {
+ this.num := p;
+ // repr stuff
+ this.Repr := {this};
+ }
+
+ method Double(p: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures num == 2 * p;
+ {
+ this.num := 2 * p;
+ // repr stuff
+ this.Repr := {this};
+ }
+
+ method Sum(a: int, b: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures num == a + b;
+ {
+ this.num := a + b;
+ // repr stuff
+ this.Repr := {this};
+ }
+
+ method Min2(a: int, b: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures a < b ==> num == a;
+ ensures a >= b ==> num == b;
+ {
+ if (a >= b ==> a == b) {
+ this.num := a;
+ // repr stuff
+ this.Repr := {this};
+ } else {
+ this.num := b;
+ // repr stuff
+ this.Repr := {this};
+ }
+ }
+
+ method Min22(a: int, b: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures num in {a, b};
+ ensures num <= a;
+ ensures num <= b;
+ {
+ if (a <= b) {
+ this.num := a;
+ // repr stuff
+ this.Repr := {this};
+ } else {
+ this.num := b;
+ // repr stuff
+ this.Repr := {this};
+ }
+ }
+
+ method Min3(a: int, b: int, c: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures num in {a, b, c};
+ ensures num <= a;
+ ensures num <= b;
+ ensures num <= c;
+ {
+ if (a <= b && a <= c) {
+ this.num := a;
+ // repr stuff
+ this.Repr := {this};
+ } else {
+ if (c <= a && c <= b) {
+ this.num := c;
+ // repr stuff
+ this.Repr := {this};
+ } else {
+ this.num := b;
+ // repr stuff
+ this.Repr := {this};
+ }
+ }
+ }
+
+ method MinSum(a: int, b: int, c: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures num in {a + b, a + c, b + c};
+ ensures num <= a + b;
+ ensures num <= b + c;
+ ensures num <= a + c;
+ {
+ if (a + b <= b + c && a + b <= a + c) {
+ this.num := a + b;
+ // repr stuff
+ this.Repr := {this};
+ } else {
+ if (a + c <= a + b && a + c <= b + c) {
+ this.num := a + c;
+ // repr stuff
+ this.Repr := {this};
+ } else {
+ this.num := b + c;
+ // repr stuff
+ this.Repr := {this};
+ }
+ }
+ }
+
+ method Min4(a: int, b: int, c: int, d: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures num in {a, b, c, d};
+ ensures num <= a;
+ ensures num <= b;
+ ensures num <= c;
+ ensures num <= d;
+ {
+ if (a <= b && (a <= c && a <= d)) {
+ this.num := a;
+ // repr stuff
+ this.Repr := {this};
+ } else {
+ if (d <= a && (d <= b && d <= c)) {
+ this.num := d;
+ // repr stuff
+ this.Repr := {this};
+ } else {
+ if (c <= a && (c <= b && c <= d)) {
+ this.num := c;
+ // repr stuff
+ this.Repr := {this};
+ } else {
+ this.num := b;
+ // repr stuff
+ this.Repr := {this};
+ }
+ }
+ }
+ }
+
+ method Abs(a: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures a < 0 ==> num == -a;
+ ensures a >= 0 ==> num == a;
+ {
+ if (!(a >= 0)) {
+ this.num := -a;
+ // repr stuff
+ this.Repr := {this};
+ } else {
+ this.num := a;
+ // repr stuff
+ this.Repr := {this};
+ }
+ }
+
+}
+
+
diff --git a/Jennisys/Jennisys/examples/jennisys-synth_Set.dfy b/Jennisys/Jennisys/examples/jennisys-synth_Set.dfy
new file mode 100644
index 00000000..efc9aa07
--- /dev/null
+++ b/Jennisys/Jennisys/examples/jennisys-synth_Set.dfy
@@ -0,0 +1,344 @@
+class Set {
+ ghost var Repr: set<object>;
+ ghost var elems: set<int>;
+
+ var root: SetNode;
+
+ function Valid_repr(): bool
+ reads *;
+ {
+ this in Repr &&
+ null !in Repr &&
+ (root != null ==> root in Repr && root.Repr <= Repr && this !in root.Repr)
+ }
+
+ function Valid_self(): bool
+ reads *;
+ {
+ Valid_repr() &&
+ (root == null ==> elems == {}) &&
+ (root != null ==> elems == root.elems)
+ }
+
+ function Valid(): bool
+ reads *;
+ {
+ this.Valid_self() &&
+ (root != null ==> root.Valid())
+ }
+
+ method Empty()
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures elems == {};
+ {
+ this.elems := {};
+ this.root := null;
+ // repr stuff
+ this.Repr := {this};
+ }
+
+ method Singleton(t: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures elems == {t};
+ {
+ var gensym66 := new SetNode;
+ gensym66.data := t;
+ gensym66.elems := {t};
+ gensym66.left := null;
+ gensym66.right := null;
+ this.elems := {t};
+ this.root := gensym66;
+ // repr stuff
+ gensym66.Repr := {gensym66};
+ this.Repr := {this} + this.root.Repr;
+ }
+
+ method Sum(p: int, q: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures elems == {p + q};
+ {
+ var gensym68 := new SetNode;
+ gensym68.data := p + q;
+ gensym68.elems := {p + q};
+ gensym68.left := null;
+ gensym68.right := null;
+ this.elems := {p + q};
+ this.root := gensym68;
+ // repr stuff
+ gensym68.Repr := {gensym68};
+ this.Repr := {this} + this.root.Repr;
+ }
+
+ method Double(p: int, q: int)
+ modifies this;
+ requires p != q;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures elems == {p, q};
+ {
+ if (q < p) {
+ var gensym71 := new SetNode;
+ var gensym75 := new SetNode;
+ gensym71.data := p;
+ gensym71.elems := {p, q};
+ gensym71.left := gensym75;
+ gensym71.right := null;
+ gensym75.data := q;
+ gensym75.elems := {q};
+ gensym75.left := null;
+ gensym75.right := null;
+ this.elems := {p, q};
+ this.root := gensym71;
+ // repr stuff
+ gensym75.Repr := {gensym75};
+ gensym71.Repr := {gensym71} + gensym71.left.Repr;
+ this.Repr := {this} + this.root.Repr;
+ } else {
+ var gensym71 := new SetNode;
+ var gensym75 := new SetNode;
+ gensym71.data := q;
+ gensym71.elems := {p, q};
+ gensym71.left := gensym75;
+ gensym71.right := null;
+ gensym75.data := p;
+ gensym75.elems := {p};
+ gensym75.left := null;
+ gensym75.right := null;
+ this.elems := {p, q};
+ this.root := gensym71;
+ // repr stuff
+ gensym75.Repr := {gensym75};
+ gensym71.Repr := {gensym71} + gensym71.left.Repr;
+ this.Repr := {this} + this.root.Repr;
+ }
+ }
+
+}
+
+class SetNode {
+ ghost var Repr: set<object>;
+ ghost var elems: set<int>;
+
+ var data: int;
+ var left: SetNode;
+ var right: SetNode;
+
+ function Valid_repr(): bool
+ reads *;
+ {
+ this in Repr &&
+ null !in Repr &&
+ (left != null ==> left in Repr && left.Repr <= Repr && this !in left.Repr) &&
+ (right != null ==> right in Repr && right.Repr <= Repr && this !in right.Repr)
+ }
+
+ function Valid_self(): bool
+ reads *;
+ {
+ Valid_repr() &&
+ (elems == ({data} + (if left != null then left.elems else {})) + (if right != null then right.elems else {})) &&
+ (left != null ==> (forall e :: e in left.elems ==> e < data)) &&
+ (right != null ==> (forall e :: e in right.elems ==> e > data))
+ }
+
+ function Valid(): bool
+ reads *;
+ {
+ this.Valid_self() &&
+ (left != null ==> left.Valid_self() && (left.left != null ==> left.left.Valid_self())) &&
+ (right != null ==> right.Valid_self() && (right.right != null ==> right.right.Valid_self()))
+ }
+
+ method Init(t: int)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures elems == {t};
+ {
+ this.data := t;
+ this.elems := {t};
+ this.left := null;
+ this.right := null;
+ // repr stuff
+ this.Repr := {this};
+ }
+
+ method Double(p: int, q: int)
+ modifies this;
+ requires p != q;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures elems == {p, q};
+ {
+ if (q > p) {
+ var gensym79 := new SetNode;
+ gensym79.data := q;
+ gensym79.elems := {q};
+ gensym79.left := null;
+ gensym79.right := null;
+ this.data := p;
+ this.elems := {p, q};
+ this.left := null;
+ this.right := gensym79;
+ // repr stuff
+ gensym79.Repr := {gensym79};
+ this.Repr := {this} + this.right.Repr;
+ } else {
+ var gensym79 := new SetNode;
+ gensym79.data := p;
+ gensym79.elems := {p};
+ gensym79.left := null;
+ gensym79.right := null;
+ this.data := q;
+ this.elems := {p, q};
+ this.left := null;
+ this.right := gensym79;
+ // repr stuff
+ gensym79.Repr := {gensym79};
+ this.Repr := {this} + this.right.Repr;
+ }
+ }
+
+ method Triple(p: int, q: int, r: int)
+ modifies this;
+ requires p != q;
+ requires q != r;
+ requires r != p;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures elems == {p, q, r};
+ {
+ if (p < q && r > q) {
+ var gensym83 := new SetNode;
+ var gensym84 := new SetNode;
+ gensym83.data := r;
+ gensym83.elems := {r};
+ gensym83.left := null;
+ gensym83.right := null;
+ gensym84.data := p;
+ gensym84.elems := {p};
+ gensym84.left := null;
+ gensym84.right := null;
+ this.data := q;
+ this.elems := {p, q, r};
+ this.left := gensym84;
+ this.right := gensym83;
+ // repr stuff
+ gensym83.Repr := {gensym83};
+ gensym84.Repr := {gensym84};
+ this.Repr := ({this} + this.left.Repr) + this.right.Repr;
+ } else {
+ if (p < r && q > r) {
+ var gensym85 := new SetNode;
+ var gensym86 := new SetNode;
+ gensym85.data := q;
+ gensym85.elems := {q};
+ gensym85.left := null;
+ gensym85.right := null;
+ gensym86.data := p;
+ gensym86.elems := {p};
+ gensym86.left := null;
+ gensym86.right := null;
+ this.data := r;
+ this.elems := {p, q, r};
+ this.left := gensym86;
+ this.right := gensym85;
+ // repr stuff
+ gensym85.Repr := {gensym85};
+ gensym86.Repr := {gensym86};
+ this.Repr := ({this} + this.left.Repr) + this.right.Repr;
+ } else {
+ if (r < p && q > p) {
+ var gensym84 := new SetNode;
+ var gensym85 := new SetNode;
+ gensym84.data := q;
+ gensym84.elems := {q};
+ gensym84.left := null;
+ gensym84.right := null;
+ gensym85.data := r;
+ gensym85.elems := {r};
+ gensym85.left := null;
+ gensym85.right := null;
+ this.data := p;
+ this.elems := {p, q, r};
+ this.left := gensym85;
+ this.right := gensym84;
+ // repr stuff
+ gensym84.Repr := {gensym84};
+ gensym85.Repr := {gensym85};
+ this.Repr := ({this} + this.left.Repr) + this.right.Repr;
+ } else {
+ if (q < p && r > p) {
+ var gensym82 := new SetNode;
+ var gensym83 := new SetNode;
+ gensym82.data := r;
+ gensym82.elems := {r};
+ gensym82.left := null;
+ gensym82.right := null;
+ gensym83.data := q;
+ gensym83.elems := {q};
+ gensym83.left := null;
+ gensym83.right := null;
+ this.data := p;
+ this.elems := {p, q, r};
+ this.left := gensym83;
+ this.right := gensym82;
+ // repr stuff
+ gensym82.Repr := {gensym82};
+ gensym83.Repr := {gensym83};
+ this.Repr := ({this} + this.left.Repr) + this.right.Repr;
+ } else {
+ if (q < r && p > r) {
+ var gensym85 := new SetNode;
+ var gensym86 := new SetNode;
+ gensym85.data := p;
+ gensym85.elems := {p};
+ gensym85.left := null;
+ gensym85.right := null;
+ gensym86.data := q;
+ gensym86.elems := {q};
+ gensym86.left := null;
+ gensym86.right := null;
+ this.data := r;
+ this.elems := {p, q, r};
+ this.left := gensym86;
+ this.right := gensym85;
+ // repr stuff
+ gensym85.Repr := {gensym85};
+ gensym86.Repr := {gensym86};
+ this.Repr := ({this} + this.left.Repr) + this.right.Repr;
+ } else {
+ var gensym82 := new SetNode;
+ var gensym83 := new SetNode;
+ gensym82.data := p;
+ gensym82.elems := {p};
+ gensym82.left := null;
+ gensym82.right := null;
+ gensym83.data := r;
+ gensym83.elems := {r};
+ gensym83.left := null;
+ gensym83.right := null;
+ this.data := q;
+ this.elems := {p, q, r};
+ this.left := gensym83;
+ this.right := gensym82;
+ // repr stuff
+ gensym82.Repr := {gensym82};
+ gensym83.Repr := {gensym83};
+ this.Repr := ({this} + this.left.Repr) + this.right.Repr;
+ }
+ }
+ }
+ }
+ }
+ }
+
+}
+
+
diff --git a/Source/Dafny/Compiler.cs b/Source/Dafny/Compiler.cs
index 0653fe2e..6a448172 100644
--- a/Source/Dafny/Compiler.cs
+++ b/Source/Dafny/Compiler.cs
@@ -485,6 +485,7 @@ namespace Microsoft.Dafny {
// ----- Type ---------------------------------------------------------------------------------
readonly string DafnySetClass = "Dafny.Set";
+ readonly string DafnyMultiSetClass = "Dafny.MultiSet";
readonly string DafnySeqClass = "Dafny.Sequence";
string TypeName(Type type)
@@ -541,6 +542,12 @@ namespace Microsoft.Dafny {
Error("compilation of seq<object> is not supported; consider introducing a ghost");
}
return DafnySeqClass + "<" + TypeName(argType) + ">";
+ } else if (type is MultiSetType) {
+ Type argType = ((MultiSetType)type).Arg;
+ if (argType is ObjectType) {
+ Error("compilation of seq<object> is not supported; consider introducing a ghost");
+ }
+ return DafnyMultiSetClass + "<" + TypeName(argType) + ">";
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected type
}
@@ -607,6 +614,8 @@ namespace Microsoft.Dafny {
return "default(@" + udt.Name + ")";
} else if (type is SetType) {
return DafnySetClass + "<" + TypeName(((SetType)type).Arg) + ">.Empty";
+ } else if (type is MultiSetType) {
+ return DafnyMultiSetClass + "<" + TypeName(((MultiSetType)type).Arg) + ">.Empty";
} else if (type is SeqType) {
return DafnySeqClass + "<" + TypeName(((SeqType)type).Arg) + ">.Empty";
} else {
@@ -1193,6 +1202,12 @@ namespace Microsoft.Dafny {
wr.Write("{0}<{1}>.FromElements", DafnySetClass, TypeName(elType));
TrExprList(e.Elements);
+ } else if (expr is MultiSetDisplayExpr) {
+ MultiSetDisplayExpr e = (MultiSetDisplayExpr)expr;
+ Type elType = cce.NonNull((MultiSetType)e.Type).Arg;
+ wr.Write("{0}<{1}>.FromElements", DafnyMultiSetClass, TypeName(elType));
+ TrExprList(e.Elements);
+
} else if (expr is SeqDisplayExpr) {
SeqDisplayExpr e = (SeqDisplayExpr)expr;
Type elType = cce.NonNull((SeqType)e.Type).Arg;
@@ -1214,18 +1229,29 @@ namespace Microsoft.Dafny {
} else if (expr is SeqSelectExpr) {
SeqSelectExpr e = (SeqSelectExpr)expr;
- TrParenExpr(e.Seq);
Contract.Assert(e.Seq.Type != null);
if (e.Seq.Type.IsArrayType) {
- Contract.Assert(e.SelectOne);
- Contract.Assert(e.E0 != null && e.E1 == null);
- wr.Write("[(int)");
- TrParenExpr(e.E0);
- wr.Write("]");
+ if (e.SelectOne) {
+ Contract.Assert(e.E0 != null && e.E1 == null);
+ TrParenExpr(e.Seq);
+ wr.Write("[(int)");
+ TrParenExpr(e.E0);
+ wr.Write("]");
+ } else {
+ TrParenExpr("Dafny.Helpers.SeqFromArray", e.Seq);
+ if (e.E1 != null) {
+ TrParenExpr(".Take", e.E1);
+ }
+ if (e.E0 != null) {
+ TrParenExpr(".Drop", e.E0);
+ }
+ }
} else if (e.SelectOne) {
Contract.Assert(e.E0 != null && e.E1 == null);
+ TrParenExpr(e.Seq);
TrParenExpr(".Select", e.E0);
} else {
+ TrParenExpr(e.Seq);
if (e.E1 != null) {
TrParenExpr(".Take", e.E1);
}
@@ -1233,7 +1259,16 @@ namespace Microsoft.Dafny {
TrParenExpr(".Drop", e.E0);
}
}
-
+ } else if (expr is MultiSetFormingExpr) {
+ MultiSetFormingExpr e = (MultiSetFormingExpr)expr;
+ wr.Write("{0}<{1}>", DafnyMultiSetClass, TypeName(((CollectionType)e.E.Type).Arg));
+ if (e.E.Type is SeqType) {
+ TrParenExpr(".FromSeq", e.E);
+ } else if (e.E.Type is SetType) {
+ TrParenExpr(".FromSet", e.E);
+ } else {
+ Contract.Assert(false); throw new cce.UnreachableException();
+ }
} else if (expr is MultiSelectExpr) {
MultiSelectExpr e = (MultiSelectExpr)expr;
TrParenExpr(e.Array);
@@ -1389,29 +1424,37 @@ namespace Microsoft.Dafny {
wr.Write(")");
break;
case BinaryExpr.ResolvedOpcode.SetEq:
+ case BinaryExpr.ResolvedOpcode.MultiSetEq:
case BinaryExpr.ResolvedOpcode.SeqEq:
callString = "Equals"; break;
case BinaryExpr.ResolvedOpcode.SetNeq:
+ case BinaryExpr.ResolvedOpcode.MultiSetNeq:
case BinaryExpr.ResolvedOpcode.SeqNeq:
preOpString = "!"; callString = "Equals"; break;
-
case BinaryExpr.ResolvedOpcode.ProperSubset:
+ case BinaryExpr.ResolvedOpcode.ProperMultiSubset:
callString = "IsProperSubsetOf"; break;
case BinaryExpr.ResolvedOpcode.Subset:
+ case BinaryExpr.ResolvedOpcode.MultiSubset:
callString = "IsSubsetOf"; break;
case BinaryExpr.ResolvedOpcode.Superset:
+ case BinaryExpr.ResolvedOpcode.MultiSuperset:
callString = "IsSupersetOf"; break;
case BinaryExpr.ResolvedOpcode.ProperSuperset:
+ case BinaryExpr.ResolvedOpcode.ProperMultiSuperset:
callString = "IsProperSupersetOf"; break;
case BinaryExpr.ResolvedOpcode.Disjoint:
+ case BinaryExpr.ResolvedOpcode.MultiSetDisjoint:
callString = "IsDisjointFrom"; break;
case BinaryExpr.ResolvedOpcode.InSet:
+ case BinaryExpr.ResolvedOpcode.InMultiSet:
TrParenExpr(e.E1);
wr.Write(".Contains(");
TrExpr(e.E0);
wr.Write(")");
break;
case BinaryExpr.ResolvedOpcode.NotInSet:
+ case BinaryExpr.ResolvedOpcode.NotInMultiSet:
wr.Write("!");
TrParenExpr(e.E1);
wr.Write(".Contains(");
@@ -1419,10 +1462,13 @@ namespace Microsoft.Dafny {
wr.Write(")");
break;
case BinaryExpr.ResolvedOpcode.Union:
+ case BinaryExpr.ResolvedOpcode.MultiSetUnion:
callString = "Union"; break;
case BinaryExpr.ResolvedOpcode.Intersection:
+ case BinaryExpr.ResolvedOpcode.MultiSetIntersection:
callString = "Intersect"; break;
case BinaryExpr.ResolvedOpcode.SetDifference:
+ case BinaryExpr.ResolvedOpcode.MultiSetDifference:
callString = "Difference"; break;
case BinaryExpr.ResolvedOpcode.ProperPrefix:
diff --git a/Source/Dafny/Dafny.atg b/Source/Dafny/Dafny.atg
index c0aae345..028d6826 100644
--- a/Source/Dafny/Dafny.atg
+++ b/Source/Dafny/Dafny.atg
@@ -473,6 +473,12 @@ TypeAndToken<out IToken/*!*/ tok, out Type/*!*/ ty>
}
ty = new SetType(gt[0]);
.)
+ | "multiset" (. tok = t; gt = new List<Type/*!*/>(); .)
+ GenericInstantiation<gt> (. if (gt.Count != 1) {
+ SemErr("multiset type expects exactly one type argument");
+ }
+ ty = new MultiSetType(gt[0]);
+ .)
| "seq" (. tok = t; gt = new List<Type/*!*/>(); .)
GenericInstantiation<gt> (. if (gt.Count != 1) {
SemErr("seq type expects exactly one type argument");
@@ -1108,6 +1114,7 @@ UnaryExpression<out Expression/*!*/ e>
| DottedIdentifiersAndFunction<out e>
{ Suffix<ref e> }
| DisplayExpr<out e>
+ | MultiSetExpr<out e>
| ConstAtomExpression<out e>
{ Suffix<ref e> }
)
@@ -1153,17 +1160,32 @@ ConstAtomExpression<out Expression/*!*/ e>
.
DisplayExpr<out Expression e>
= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null);
- IToken/*!*/ x; List<Expression/*!*/>/*!*/ elements;
+ IToken/*!*/ x = null; List<Expression/*!*/>/*!*/ elements;
e = dummyExpr;
.)
( "{" (. x = t; elements = new List<Expression/*!*/>(); .)
- [ Expressions<elements> ] (. e = new SetDisplayExpr(x, elements); .)
+ [ Expressions<elements> ] (. e = new SetDisplayExpr(x, elements);.)
"}"
| "[" (. x = t; elements = new List<Expression/*!*/>(); .)
[ Expressions<elements> ] (. e = new SeqDisplayExpr(x, elements); .)
"]"
)
.
+MultiSetExpr<out Expression e>
+= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null);
+ IToken/*!*/ x = null; List<Expression/*!*/>/*!*/ elements;
+ e = dummyExpr;
+ .)
+ "multiset" (. x = t; .)
+ ( "{" (. elements = new List<Expression/*!*/>(); .)
+ [ Expressions<elements> ] (. e = new MultiSetDisplayExpr(x, elements);.)
+ "}"
+ | "(" (. x = t; elements = new List<Expression/*!*/>(); .)
+ Expression<out e> (. e = new MultiSetFormingExpr(x, e); .)
+ ")"
+ | (. SemErr("multiset must be followed by multiset literal or expression to coerce in parentheses."); .)
+ )
+ .
EndlessExpression<out Expression e>
= (. IToken/*!*/ x;
Expression e0, e1;
@@ -1249,7 +1271,9 @@ Suffix<ref Expression/*!*/ e>
.)
}
)
- | ".." Expression<out ee> (. anyDots = true; e1 = ee; .)
+ | ".." (. anyDots = true; .)
+ [ Expression<out ee> (. e1 = ee; .)
+ ]
)
(. if (multipleIndices != null) {
e = new MultiSelectExpr(x, e, multipleIndices);
@@ -1262,7 +1286,7 @@ Suffix<ref Expression/*!*/ e>
}
Contract.Assert(anyDots || e0 != null);
if (anyDots) {
- Contract.Assert(e0 != null || e1 != null);
+ //Contract.Assert(e0 != null || e1 != null);
e = new SeqSelectExpr(x, false, e, e0, e1);
} else if (e1 == null) {
Contract.Assert(e0 != null);
diff --git a/Source/Dafny/DafnyAst.cs b/Source/Dafny/DafnyAst.cs
index 8bb381ea..218f95e5 100644
--- a/Source/Dafny/DafnyAst.cs
+++ b/Source/Dafny/DafnyAst.cs
@@ -256,7 +256,7 @@ namespace Microsoft.Dafny {
this.Arg = arg;
}
}
-
+
public class SetType : CollectionType {
public SetType(Type arg) : base(arg) {
Contract.Requires(arg != null);
@@ -269,6 +269,19 @@ namespace Microsoft.Dafny {
}
}
+ public class MultiSetType : CollectionType
+ {
+ public MultiSetType(Type arg) : base(arg) {
+ Contract.Requires(arg != null);
+ }
+ [Pure]
+ public override string ToString() {
+ Contract.Ensures(Contract.Result<string>() != null);
+ Contract.Assume(cce.IsPeerConsistent(Arg));
+ return "multiset<" + base.Arg + ">";
+ }
+ }
+
public class SeqType : CollectionType {
public SeqType(Type arg) : base(arg) {
Contract.Requires(arg != null);
@@ -487,9 +500,9 @@ namespace Microsoft.Dafny {
/// <summary>
/// This proxy stands for either:
- /// int or set or seq
+ /// int or set or multiset or seq
/// if AllowSeq, or:
- /// int or set
+ /// int or set or multiset
/// if !AllowSeq.
/// </summary>
public class OperationTypeProxy : RestrictedTypeProxy {
@@ -2062,7 +2075,7 @@ namespace Microsoft.Dafny {
get { return Elements; }
}
}
-
+
public class SetDisplayExpr : DisplayExpression {
public SetDisplayExpr(IToken tok, List<Expression/*!*/>/*!*/ elements)
: base(tok, elements) {
@@ -2071,6 +2084,13 @@ namespace Microsoft.Dafny {
}
}
+ public class MultiSetDisplayExpr : DisplayExpression {
+ public MultiSetDisplayExpr(IToken tok, List<Expression/*!*/>/*!*/ elements) : base(tok, elements) {
+ Contract.Requires(tok != null);
+ Contract.Requires(cce.NonNullElements(elements));
+ }
+ }
+
public class SeqDisplayExpr : DisplayExpression {
public SeqDisplayExpr(IToken tok, List<Expression/*!*/>/*!*/ elements)
: base(tok, elements) {
@@ -2113,7 +2133,6 @@ namespace Microsoft.Dafny {
void ObjectInvariant() {
Contract.Invariant(Seq != null);
Contract.Invariant(!SelectOne || E1 == null);
- Contract.Invariant(E0 != null || E1 != null);
}
public SeqSelectExpr(IToken tok, bool selectOne, Expression seq, Expression e0, Expression e1)
@@ -2121,7 +2140,6 @@ namespace Microsoft.Dafny {
Contract.Requires(tok != null);
Contract.Requires(seq != null);
Contract.Requires(!selectOne || e1 == null);
- Contract.Requires(e0 != null || e1 != null);
SelectOne = selectOne;
Seq = seq;
@@ -2257,6 +2275,28 @@ namespace Microsoft.Dafny {
}
}
+ public class MultiSetFormingExpr : Expression
+ {
+ [Peer]
+ public readonly Expression E;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(E != null);
+ }
+
+ [Captured]
+ public MultiSetFormingExpr(IToken tok, Expression expr)
+ : base(tok) {
+ Contract.Requires(tok != null);
+ Contract.Requires(expr != null);
+ cce.Owner.AssignSame(this, expr);
+ E = expr;
+ }
+
+ public override IEnumerable<Expression> SubExpressions {
+ get { yield return E; }
+ }
+ }
public class FreshExpr : Expression {
public readonly Expression E;
[ContractInvariantMethod]
@@ -2378,6 +2418,19 @@ namespace Microsoft.Dafny {
Union,
Intersection,
SetDifference,
+ // multi-sets
+ MultiSetEq,
+ MultiSetNeq,
+ MultiSubset,
+ MultiSuperset,
+ ProperMultiSubset,
+ ProperMultiSuperset,
+ MultiSetDisjoint,
+ InMultiSet,
+ NotInMultiSet,
+ MultiSetUnion,
+ MultiSetIntersection,
+ MultiSetDifference,
// sequences
SeqEq,
SeqNeq,
diff --git a/Source/Dafny/Parser.cs b/Source/Dafny/Parser.cs
index 8fcb6bb0..31a46f4b 100644
--- a/Source/Dafny/Parser.cs
+++ b/Source/Dafny/Parser.cs
@@ -5,6 +5,8 @@ using System.IO;
using System.Text;
+
+
using System;
using System.Diagnostics.Contracts;
@@ -18,7 +20,7 @@ public class Parser {
public const int _digits = 2;
public const int _arrayToken = 3;
public const int _string = 4;
- public const int maxT = 104;
+ public const int maxT = 105;
const bool T = true;
const bool x = false;
@@ -33,16 +35,20 @@ public class Parser {
static List<ModuleDecl/*!*/> theModules;
static BuiltIns theBuiltIns;
+
+
static Expression/*!*/ dummyExpr = new LiteralExpr(Token.NoToken);
static FrameExpression/*!*/ dummyFrameExpr = new FrameExpression(dummyExpr, null);
static Statement/*!*/ dummyStmt = new ReturnStmt(Token.NoToken, null);
static Attributes.Argument/*!*/ dummyAttrArg = new Attributes.Argument("dummyAttrArg");
static int anonymousIds = 0;
+
struct MemberModifiers {
public bool IsGhost;
public bool IsStatic;
public bool IsUnlimited;
}
+
// helper routine for parsing call statements
private static Expression/*!*/ ConvertToLocal(Expression/*!*/ e)
{
@@ -54,6 +60,7 @@ Contract.Ensures(Contract.Result<Expression>() != null);
}
return e; // cannot convert to IdentifierExpr (or is already an IdentifierExpr)
}
+
///<summary>
/// Parses top-level things (modules, classes, datatypes, class members) from "filename"
/// and appends them in appropriate form to "modules".
@@ -74,6 +81,7 @@ public static int Parse (string/*!*/ filename, List<ModuleDecl/*!*/>/*!*/ module
}
}
}
+
///<summary>
/// Parses top-level things (modules, classes, datatypes, class members)
/// and appends them in appropriate form to "modules".
@@ -87,6 +95,7 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, List<ModuleDecl/*!
Errors errors = new Errors();
return Parse(s, filename, modules, builtIns, errors);
}
+
///<summary>
/// Parses top-level things (modules, classes, datatypes, class members)
/// and appends them in appropriate form to "modules".
@@ -112,6 +121,7 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, List<ModuleDecl/*!
theBuiltIns = oldBuiltIns;
return parser.errors.count;
}
+
/*--------------------------------------------------------------------------*/
@@ -186,20 +196,22 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, List<ModuleDecl/*!
void Dafny() {
ClassDecl/*!*/ c; DatatypeDecl/*!*/ dt;
Attributes attrs; IToken/*!*/ id; List<string/*!*/> theImports;
- List<MemberDecl/*!*/> membersDefaultClass = new List<MemberDecl/*!*/>();
- ModuleDecl module;
- // to support multiple files, create a default module only if theModules doesn't already contain one
- DefaultModuleDecl defaultModule = null;
- foreach (ModuleDecl mdecl in theModules) {
- defaultModule = mdecl as DefaultModuleDecl;
- if (defaultModule != null) { break; }
- }
- bool defaultModuleCreatedHere = false;
- if (defaultModule == null) {
- defaultModuleCreatedHere = true;
- defaultModule = new DefaultModuleDecl();
- }
+ List<MemberDecl/*!*/> membersDefaultClass = new List<MemberDecl/*!*/>();
+ ModuleDecl module;
+
+ // to support multiple files, create a default module only if theModules doesn't already contain one
+ DefaultModuleDecl defaultModule = null;
+ foreach (ModuleDecl mdecl in theModules) {
+ defaultModule = mdecl as DefaultModuleDecl;
+ if (defaultModule != null) { break; }
+ }
+ bool defaultModuleCreatedHere = false;
+ if (defaultModule == null) {
+ defaultModuleCreatedHere = true;
+ defaultModule = new DefaultModuleDecl();
+ }
+
while (StartOf(1)) {
if (la.kind == 5) {
Get();
@@ -234,21 +246,21 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, List<ModuleDecl/*!
DatatypeDecl(defaultModule, out dt);
defaultModule.TopLevelDecls.Add(dt);
} else {
- ClassMemberDecl(membersDefaultClass, false);
+ ClassMemberDecl(membersDefaultClass);
}
}
if (defaultModuleCreatedHere) {
defaultModule.TopLevelDecls.Add(new DefaultClassDecl(defaultModule, membersDefaultClass));
theModules.Add(defaultModule);
} else {
- // find the default class in the default module, then append membersDefaultClass to its member list
- foreach (TopLevelDecl topleveldecl in defaultModule.TopLevelDecls) {
- DefaultClassDecl defaultClass = topleveldecl as DefaultClassDecl;
- if (defaultClass != null) {
- defaultClass.Members.AddRange(membersDefaultClass);
- break;
- }
- }
+ // find the default class in the default module, then append membersDefaultClass to its member list
+ foreach (TopLevelDecl topleveldecl in defaultModule.TopLevelDecls) {
+ DefaultClassDecl defaultClass = topleveldecl as DefaultClassDecl;
+ if (defaultClass != null) {
+ defaultClass.Members.AddRange(membersDefaultClass);
+ break;
+ }
+ }
}
Expect(0);
@@ -304,13 +316,13 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, List<ModuleDecl/*!
Expect(7);
bodyStart = t;
while (StartOf(2)) {
- ClassMemberDecl(members, true);
+ ClassMemberDecl(members);
}
Expect(8);
- if (optionalId == null)
+ if (optionalId == null)
c = new ClassDecl(id, id.val, module, typeArgs, members, attrs);
- else
- c = new ClassRefinementDecl(id, id.val, module, typeArgs, members, attrs, optionalId);
+ else
+ c = new ClassRefinementDecl(id, id.val, module, typeArgs, members, attrs, optionalId);
c.BodyStartTok = bodyStart;
c.BodyEndTok = t;
@@ -347,7 +359,7 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, List<ModuleDecl/*!
}
- void ClassMemberDecl(List<MemberDecl/*!*/>/*!*/ mm, bool allowConstructors) {
+ void ClassMemberDecl(List<MemberDecl/*!*/>/*!*/ mm) {
Contract.Requires(cce.NonNullElements(mm));
Method/*!*/ m;
Function/*!*/ f;
@@ -367,15 +379,15 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, List<ModuleDecl/*!
}
if (la.kind == 18) {
FieldDecl(mmod, mm);
- } else if (la.kind == 41) {
+ } else if (la.kind == 42) {
FunctionDecl(mmod, out f);
mm.Add(f);
} else if (la.kind == 10 || la.kind == 25 || la.kind == 26) {
- MethodDecl(mmod, allowConstructors, out m);
+ MethodDecl(mmod, out m);
mm.Add(m);
} else if (la.kind == 20) {
CouplingInvDecl(mmod, mm);
- } else SynErr(105);
+ } else SynErr(106);
}
void GenericParameters(List<TypeParameter/*!*/>/*!*/ typeArgs) {
@@ -430,7 +442,7 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, List<ModuleDecl/*!
IToken bodyStart = Token.NoToken;
IToken bodyEnd = Token.NoToken;
- Expect(41);
+ Expect(42);
if (la.kind == 25) {
Get();
isFunctionMethod = true;
@@ -447,20 +459,25 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, List<ModuleDecl/*!
Formals(true, isFunctionMethod, formals);
Expect(22);
Type(out returnType);
- while (StartOf(3)) {
- FunctionSpec(reqs, reads, ens, decreases);
- }
- if (la.kind == 7) {
+ if (la.kind == 17) {
+ Get();
+ while (StartOf(3)) {
+ FunctionSpec(reqs, reads, ens, decreases);
+ }
+ } else if (StartOf(4)) {
+ while (StartOf(3)) {
+ FunctionSpec(reqs, reads, ens, decreases);
+ }
FunctionBody(out bb, out bodyStart, out bodyEnd);
body = bb;
- }
+ } else SynErr(107);
f = new Function(id, id.val, mmod.IsStatic, !isFunctionMethod, mmod.IsUnlimited, typeArgs, formals, returnType, reqs, reads, ens, decreases, body, attrs);
f.BodyStartTok = bodyStart;
f.BodyEndTok = bodyEnd;
}
- void MethodDecl(MemberModifiers mmod, bool allowConstructor, out Method/*!*/ m) {
+ void MethodDecl(MemberModifiers mmod, out Method/*!*/ m) {
Contract.Ensures(Contract.ValueAtReturn(out m) !=null);
IToken/*!*/ id;
Attributes attrs = null;
@@ -481,24 +498,19 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, List<ModuleDecl/*!
Get();
} else if (la.kind == 26) {
Get();
- if (allowConstructor) {
- isConstructor = true;
- } else {
- SemErr(t, "constructors are only allowed in classes");
- }
-
+ isConstructor = true;
} else if (la.kind == 10) {
Get();
isRefinement = true;
- } else SynErr(106);
+ } else SynErr(108);
if (mmod.IsUnlimited) { SemErr(t, "methods cannot be declared 'unlimited'"); }
if (isConstructor) {
- if (mmod.IsGhost) {
- SemErr(t, "constructors cannot be declared 'ghost'");
- }
- if (mmod.IsStatic) {
- SemErr(t, "constructors cannot be declared 'static'");
- }
+ if (mmod.IsGhost) {
+ SemErr(t, "constructors cannot be declared 'ghost'");
+ }
+ if (mmod.IsStatic) {
+ SemErr(t, "constructors cannot be declared 'static'");
+ }
}
while (la.kind == 7) {
@@ -514,19 +526,24 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, List<ModuleDecl/*!
if (isConstructor) { SemErr(t, "constructors cannot have out-parameters"); }
Formals(false, !mmod.IsGhost, outs);
}
- while (StartOf(4)) {
- MethodSpec(req, mod, ens, dec);
- }
- if (la.kind == 7) {
+ if (la.kind == 17) {
+ Get();
+ while (StartOf(5)) {
+ MethodSpec(req, mod, ens, dec);
+ }
+ } else if (StartOf(6)) {
+ while (StartOf(5)) {
+ MethodSpec(req, mod, ens, dec);
+ }
BlockStmt(out bb, out bodyStart, out bodyEnd);
body = (BlockStmt)bb;
- }
+ } else SynErr(109);
if (isRefinement)
m = new MethodRefinement(id, id.val, mmod.IsStatic, mmod.IsGhost, typeArgs, ins, outs, req, mod, ens, dec, body, attrs);
else if (isConstructor)
- m = new Constructor(id, id.val, typeArgs, ins, req, mod, ens, dec, body, attrs);
+ m = new Constructor(id, id.val, typeArgs, ins, req, mod, ens, dec, body, attrs);
else
- m = new Method(id, id.val, mmod.IsStatic, mmod.IsGhost, typeArgs, ins, outs, req, mod, ens, dec, body, attrs);
+ m = new Method(id, id.val, mmod.IsStatic, mmod.IsGhost, typeArgs, ins, outs, req, mod, ens, dec, body, attrs);
m.BodyStartTok = bodyStart;
m.BodyEndTok = bodyEnd;
@@ -579,7 +596,7 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, List<ModuleDecl/*!
void FormalsOptionalIds(List<Formal/*!*/>/*!*/ formals) {
Contract.Requires(cce.NonNullElements(formals)); IToken/*!*/ id; Type/*!*/ ty; string/*!*/ name; bool isGhost;
Expect(33);
- if (StartOf(5)) {
+ if (StartOf(7)) {
TypeIdentOptional(out id, out name, out ty, out isGhost);
formals.Add(new Formal(id, name, ty, true, isGhost));
while (la.kind == 19) {
@@ -656,9 +673,9 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, List<ModuleDecl/*!
Get();
UserDefinedType udt = ty as UserDefinedType;
if (udt != null && udt.TypeArgs.Count == 0) {
- name = udt.Name;
+ name = udt.Name;
} else {
- SemErr(id, "invalid formal-parameter name in datatype constructor");
+ SemErr(id, "invalid formal-parameter name in datatype constructor");
}
Type(out ty);
@@ -666,7 +683,7 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, List<ModuleDecl/*!
if (name != null) {
identName = name;
} else {
- identName = "#" + anonymousIds++;
+ identName = "#" + anonymousIds++;
}
}
@@ -707,17 +724,28 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, List<ModuleDecl/*!
tok = t; gt = new List<Type/*!*/>();
GenericInstantiation(gt);
if (gt.Count != 1) {
+ SemErr("multiset type expects exactly one type argument");
+ }
+ ty = new MultiSetType(gt[0]);
+
+ break;
+ }
+ case 40: {
+ Get();
+ tok = t; gt = new List<Type/*!*/>();
+ GenericInstantiation(gt);
+ if (gt.Count != 1) {
SemErr("seq type expects exactly one type argument");
}
ty = new SeqType(gt[0]);
break;
}
- case 1: case 3: case 40: {
+ case 1: case 3: case 41: {
ReferenceType(out tok, out ty);
break;
}
- default: SynErr(107); break;
+ default: SynErr(110); break;
}
}
@@ -743,7 +771,7 @@ List<Expression/*!*/>/*!*/ decreases) {
if (la.kind == 28) {
Get();
- if (StartOf(6)) {
+ if (StartOf(8)) {
FrameExpression(out fe);
mod.Add(fe);
while (la.kind == 19) {
@@ -768,12 +796,12 @@ List<Expression/*!*/>/*!*/ decreases) {
Expression(out e);
Expect(17);
ens.Add(new MaybeFreeExpression(e, isFree));
- } else SynErr(108);
+ } else SynErr(111);
} else if (la.kind == 32) {
Get();
DecreasesList(decreases, false);
Expect(17);
- } else SynErr(109);
+ } else SynErr(112);
}
void BlockStmt(out Statement/*!*/ block, out IToken bodyStart, out IToken bodyEnd) {
@@ -782,7 +810,7 @@ List<Expression/*!*/>/*!*/ decreases) {
Expect(7);
bodyStart = t;
- while (StartOf(7)) {
+ while (StartOf(9)) {
Stmt(body);
}
Expect(8);
@@ -793,7 +821,7 @@ List<Expression/*!*/>/*!*/ decreases) {
void FrameExpression(out FrameExpression/*!*/ fe) {
Contract.Ensures(Contract.ValueAtReturn(out fe) != null); Expression/*!*/ e; IToken/*!*/ id; string fieldName = null;
Expression(out e);
- if (la.kind == 44) {
+ if (la.kind == 45) {
Get();
Ident(out id);
fieldName = id.val;
@@ -807,7 +835,7 @@ List<Expression/*!*/>/*!*/ decreases) {
if (!allowWildcard && e is WildcardExpr) {
SemErr(e.tok, "'decreases *' is only allowed on loops");
} else {
- decreases.Add(e);
+ decreases.Add(e);
}
while (la.kind == 19) {
@@ -816,7 +844,7 @@ List<Expression/*!*/>/*!*/ decreases) {
if (!allowWildcard && e is WildcardExpr) {
SemErr(e.tok, "'decreases *' is only allowed on loops");
} else {
- decreases.Add(e);
+ decreases.Add(e);
}
}
@@ -840,7 +868,7 @@ List<Expression/*!*/>/*!*/ decreases) {
tok = Token.NoToken; ty = new BoolType(); /*keep compiler happy*/
List<Type/*!*/>/*!*/ gt;
- if (la.kind == 40) {
+ if (la.kind == 41) {
Get();
tok = t; ty = new ObjectType();
} else if (la.kind == 3) {
@@ -852,7 +880,7 @@ List<Expression/*!*/>/*!*/ decreases) {
}
int dims = 1;
if (tok.val.Length != 5) {
- dims = int.Parse(tok.val.Substring(5));
+ dims = int.Parse(tok.val.Substring(5));
}
ty = theBuiltIns.ArrayType(tok, dims, gt[0], true);
@@ -863,7 +891,7 @@ List<Expression/*!*/>/*!*/ decreases) {
GenericInstantiation(gt);
}
ty = new UserDefinedType(tok, tok.val, gt);
- } else SynErr(110);
+ } else SynErr(113);
}
void FunctionSpec(List<Expression/*!*/>/*!*/ reqs, List<FrameExpression/*!*/>/*!*/ reads, List<Expression/*!*/>/*!*/ ens, List<Expression/*!*/>/*!*/ decreases) {
@@ -874,9 +902,9 @@ List<Expression/*!*/>/*!*/ decreases) {
Expression(out e);
Expect(17);
reqs.Add(e);
- } else if (la.kind == 42) {
+ } else if (la.kind == 43) {
Get();
- if (StartOf(8)) {
+ if (StartOf(10)) {
PossiblyWildFrameExpression(out fe);
reads.Add(fe);
while (la.kind == 19) {
@@ -895,7 +923,7 @@ List<Expression/*!*/>/*!*/ decreases) {
Get();
DecreasesList(decreases, false);
Expect(17);
- } else SynErr(111);
+ } else SynErr(114);
}
void FunctionBody(out Expression/*!*/ e, out IToken bodyStart, out IToken bodyEnd) {
@@ -909,23 +937,23 @@ List<Expression/*!*/>/*!*/ decreases) {
void PossiblyWildFrameExpression(out FrameExpression/*!*/ fe) {
Contract.Ensures(Contract.ValueAtReturn(out fe) != null); fe = dummyFrameExpr;
- if (la.kind == 43) {
+ if (la.kind == 44) {
Get();
fe = new FrameExpression(new WildcardExpr(t), null);
- } else if (StartOf(6)) {
+ } else if (StartOf(8)) {
FrameExpression(out fe);
- } else SynErr(112);
+ } else SynErr(115);
}
void PossiblyWildExpression(out Expression/*!*/ e) {
Contract.Ensures(Contract.ValueAtReturn(out e)!=null);
e = dummyExpr;
- if (la.kind == 43) {
+ if (la.kind == 44) {
Get();
e = new WildcardExpr(t);
- } else if (StartOf(6)) {
+ } else if (StartOf(8)) {
Expression(out e);
- } else SynErr(113);
+ } else SynErr(116);
}
void Stmt(List<Statement/*!*/>/*!*/ ss) {
@@ -946,19 +974,19 @@ List<Expression/*!*/>/*!*/ decreases) {
BlockStmt(out s, out bodyStart, out bodyEnd);
break;
}
- case 63: {
+ case 64: {
AssertStmt(out s);
break;
}
- case 64: {
+ case 65: {
AssumeStmt(out s);
break;
}
- case 65: {
+ case 66: {
PrintStmt(out s);
break;
}
- case 1: case 2: case 16: case 33: case 89: case 90: case 91: case 92: case 93: case 94: case 95: {
+ case 1: case 2: case 16: case 33: case 90: case 91: case 92: case 93: case 94: case 95: case 96: {
UpdateStmt(out s);
break;
}
@@ -966,23 +994,23 @@ List<Expression/*!*/>/*!*/ decreases) {
VarDeclStatement(out s);
break;
}
- case 54: {
+ case 55: {
IfStmt(out s);
break;
}
- case 58: {
+ case 59: {
WhileStmt(out s);
break;
}
- case 60: {
+ case 61: {
MatchStmt(out s);
break;
}
- case 61: {
+ case 62: {
ForeachStmt(out s);
break;
}
- case 45: {
+ case 46: {
Get();
x = t;
Ident(out id);
@@ -991,33 +1019,33 @@ List<Expression/*!*/>/*!*/ decreases) {
s.Labels = new LabelNode(x, id.val, s.Labels);
break;
}
- case 46: {
+ case 47: {
Get();
x = t; breakCount = 1; label = null;
if (la.kind == 1) {
Ident(out id);
label = id.val;
- } else if (la.kind == 17 || la.kind == 46) {
- while (la.kind == 46) {
+ } else if (la.kind == 17 || la.kind == 47) {
+ while (la.kind == 47) {
Get();
breakCount++;
}
- } else SynErr(114);
+ } else SynErr(117);
Expect(17);
s = label != null ? new BreakStmt(x, label) : new BreakStmt(x, breakCount);
break;
}
- case 47: {
+ case 48: {
ReturnStmt(out s);
break;
}
- default: SynErr(115); break;
+ default: SynErr(118); break;
}
}
void AssertStmt(out Statement/*!*/ s) {
Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; Expression/*!*/ e;
- Expect(63);
+ Expect(64);
x = t;
Expression(out e);
Expect(17);
@@ -1026,7 +1054,7 @@ List<Expression/*!*/>/*!*/ decreases) {
void AssumeStmt(out Statement/*!*/ s) {
Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; Expression/*!*/ e;
- Expect(64);
+ Expect(65);
x = t;
Expression(out e);
Expect(17);
@@ -1037,7 +1065,7 @@ List<Expression/*!*/>/*!*/ decreases) {
Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; Attributes.Argument/*!*/ arg;
List<Attributes.Argument/*!*/> args = new List<Attributes.Argument/*!*/>();
- Expect(65);
+ Expect(66);
x = t;
AttributeArg(out arg);
args.Add(arg);
@@ -1062,14 +1090,14 @@ List<Expression/*!*/>/*!*/ decreases) {
if (la.kind == 17) {
Get();
rhss.Add(new ExprRhs(e));
- } else if (la.kind == 19 || la.kind == 48) {
+ } else if (la.kind == 19 || la.kind == 49) {
lhss.Add(e); lhs0 = e;
while (la.kind == 19) {
Get();
Lhs(out e);
lhss.Add(e);
}
- Expect(48);
+ Expect(49);
x = t;
Rhs(out r, lhs0);
rhss.Add(r);
@@ -1082,7 +1110,7 @@ List<Expression/*!*/>/*!*/ decreases) {
} else if (la.kind == 22) {
Get();
SemErr(t, "invalid statement (did you forget the 'label' keyword?)");
- } else SynErr(116);
+ } else SynErr(119);
s = new UpdateStmt(x, lhss, rhss);
}
@@ -1106,7 +1134,7 @@ List<Expression/*!*/>/*!*/ decreases) {
LocalIdentTypeOptional(out d, isGhost);
lhss.Add(d);
}
- if (la.kind == 48) {
+ if (la.kind == 49) {
Get();
assignTok = t; lhs0 = new IdentifierExpr(lhss[0].Tok, lhss[0].Name);
Rhs(out r, lhs0);
@@ -1120,13 +1148,13 @@ List<Expression/*!*/>/*!*/ decreases) {
Expect(17);
UpdateStmt update;
if (rhss.Count == 0) {
- update = null;
+ update = null;
} else {
- var ies = new List<Expression>();
- foreach (var lhs in lhss) {
- ies.Add(new AutoGhostIdentifierExpr(lhs.Tok, lhs.Name));
- }
- update = new UpdateStmt(assignTok, ies, rhss);
+ var ies = new List<Expression>();
+ foreach (var lhs in lhss) {
+ ies.Add(new AutoGhostIdentifierExpr(lhs.Tok, lhs.Name));
+ }
+ update = new UpdateStmt(assignTok, ies, rhss);
}
s = new VarDeclStmt(x, lhss, update);
@@ -1142,26 +1170,26 @@ List<Expression/*!*/>/*!*/ decreases) {
List<GuardedAlternative> alternatives;
ifStmt = dummyStmt; // to please the compiler
- Expect(54);
+ Expect(55);
x = t;
if (la.kind == 33) {
Guard(out guard);
BlockStmt(out thn, out bodyStart, out bodyEnd);
- if (la.kind == 55) {
+ if (la.kind == 56) {
Get();
- if (la.kind == 54) {
+ if (la.kind == 55) {
IfStmt(out s);
els = s;
} else if (la.kind == 7) {
BlockStmt(out s, out bodyStart, out bodyEnd);
els = s;
- } else SynErr(117);
+ } else SynErr(120);
}
ifStmt = new IfStmt(x, guard, thn, els);
} else if (la.kind == 7) {
AlternativeBlock(out alternatives);
ifStmt = new AlternativeStmt(x, alternatives);
- } else SynErr(118);
+ } else SynErr(121);
}
void WhileStmt(out Statement/*!*/ stmt) {
@@ -1175,7 +1203,7 @@ List<Expression/*!*/>/*!*/ decreases) {
List<GuardedAlternative> alternatives;
stmt = dummyStmt; // to please the compiler
- Expect(58);
+ Expect(59);
x = t;
if (la.kind == 33) {
Guard(out guard);
@@ -1183,22 +1211,22 @@ List<Expression/*!*/>/*!*/ decreases) {
LoopSpec(out invariants, out decreases, out mod);
BlockStmt(out body, out bodyStart, out bodyEnd);
stmt = new WhileStmt(x, guard, invariants, decreases, mod, body);
- } else if (StartOf(9)) {
+ } else if (StartOf(11)) {
LoopSpec(out invariants, out decreases, out mod);
AlternativeBlock(out alternatives);
stmt = new AlternativeLoopStmt(x, invariants, decreases, mod, alternatives);
- } else SynErr(119);
+ } else SynErr(122);
}
void MatchStmt(out Statement/*!*/ s) {
Contract.Ensures(Contract.ValueAtReturn(out s) != null);
Token x; Expression/*!*/ e; MatchCaseStmt/*!*/ c;
List<MatchCaseStmt/*!*/> cases = new List<MatchCaseStmt/*!*/>();
- Expect(60);
+ Expect(61);
x = t;
Expression(out e);
Expect(7);
- while (la.kind == 56) {
+ while (la.kind == 57) {
CaseStatement(out c);
cases.Add(c);
}
@@ -1215,7 +1243,7 @@ List<Expression/*!*/>/*!*/ decreases) {
List<PredicateStmt/*!*/> bodyPrefix = new List<PredicateStmt/*!*/>();
Statement bodyAssign = null;
- Expect(61);
+ Expect(62);
x = t;
range = new LiteralExpr(x, true);
ty = new InferredTypeProxy();
@@ -1226,7 +1254,7 @@ List<Expression/*!*/>/*!*/ decreases) {
Get();
Type(out ty);
}
- Expect(62);
+ Expect(63);
Expression(out collection);
if (la.kind == 16) {
Get();
@@ -1234,8 +1262,8 @@ List<Expression/*!*/>/*!*/ decreases) {
}
Expect(34);
Expect(7);
- while (la.kind == 63 || la.kind == 64) {
- if (la.kind == 63) {
+ while (la.kind == 64 || la.kind == 65) {
+ if (la.kind == 64) {
AssertStmt(out s);
if (s is PredicateStmt) { bodyPrefix.Add((PredicateStmt)s); }
} else {
@@ -1249,7 +1277,7 @@ List<Expression/*!*/>/*!*/ decreases) {
if (bodyAssign != null) {
s = new ForeachStmt(x, new BoundVar(boundVar, boundVar.val, ty), collection, range, bodyPrefix, bodyAssign);
} else {
- s = dummyStmt; // some error occurred in parsing the bodyAssign
+ s = dummyStmt; // some error occurred in parsing the bodyAssign
}
}
@@ -1259,9 +1287,9 @@ List<Expression/*!*/>/*!*/ decreases) {
List<AssignmentRhs> rhss = null;
AssignmentRhs r;
- Expect(47);
+ Expect(48);
returnTok = t;
- if (StartOf(10)) {
+ if (StartOf(12)) {
Rhs(out r, null);
rhss = new List<AssignmentRhs>(); rhss.Add(r);
while (la.kind == 19) {
@@ -1282,16 +1310,16 @@ List<Expression/*!*/>/*!*/ decreases) {
List<Expression> args;
r = null; // to please compiler
- if (la.kind == 49) {
+ if (la.kind == 50) {
Get();
newToken = t;
TypeAndToken(out x, out ty);
- if (la.kind == 50 || la.kind == 52) {
- if (la.kind == 50) {
+ if (la.kind == 51 || la.kind == 53) {
+ if (la.kind == 51) {
Get();
ee = new List<Expression>();
Expressions(ee);
- Expect(51);
+ Expect(52);
UserDefinedType tmp = theBuiltIns.ArrayType(x, ee.Count, new IntType(), true);
} else {
@@ -1299,7 +1327,7 @@ List<Expression/*!*/>/*!*/ decreases) {
Ident(out x);
Expect(33);
args = new List<Expression/*!*/>();
- if (StartOf(6)) {
+ if (StartOf(8)) {
Expressions(args);
}
Expect(34);
@@ -1310,21 +1338,21 @@ List<Expression/*!*/>/*!*/ decreases) {
if (ee != null) {
r = new TypeRhs(newToken, ty, ee);
} else {
- r = new TypeRhs(newToken, ty, initCall);
+ r = new TypeRhs(newToken, ty, initCall);
}
- } else if (la.kind == 53) {
+ } else if (la.kind == 54) {
Get();
x = t;
Expression(out e);
r = new ExprRhs(new UnaryExpr(x, UnaryExpr.Opcode.SetChoose, e));
- } else if (la.kind == 43) {
+ } else if (la.kind == 44) {
Get();
r = new HavocRhs(t);
- } else if (StartOf(6)) {
+ } else if (StartOf(8)) {
Expression(out e);
r = new ExprRhs(e);
- } else SynErr(120);
+ } else SynErr(123);
}
void Lhs(out Expression e) {
@@ -1332,16 +1360,16 @@ List<Expression/*!*/>/*!*/ decreases) {
if (la.kind == 1) {
DottedIdentifiersAndFunction(out e);
- while (la.kind == 50 || la.kind == 52) {
+ while (la.kind == 51 || la.kind == 53) {
Suffix(ref e);
}
- } else if (StartOf(11)) {
+ } else if (StartOf(13)) {
ConstAtomExpression(out e);
Suffix(ref e);
- while (la.kind == 50 || la.kind == 52) {
+ while (la.kind == 51 || la.kind == 53) {
Suffix(ref e);
}
- } else SynErr(121);
+ } else SynErr(124);
}
void Expressions(List<Expression/*!*/>/*!*/ args) {
@@ -1358,13 +1386,13 @@ List<Expression/*!*/>/*!*/ decreases) {
void Guard(out Expression e) {
Expression/*!*/ ee; e = null;
Expect(33);
- if (la.kind == 43) {
+ if (la.kind == 44) {
Get();
e = null;
- } else if (StartOf(6)) {
+ } else if (StartOf(8)) {
Expression(out ee);
e = ee;
- } else SynErr(122);
+ } else SynErr(125);
Expect(34);
}
@@ -1375,13 +1403,13 @@ List<Expression/*!*/>/*!*/ decreases) {
List<Statement> body;
Expect(7);
- while (la.kind == 56) {
+ while (la.kind == 57) {
Get();
x = t;
Expression(out e);
- Expect(57);
+ Expect(58);
body = new List<Statement>();
- while (StartOf(7)) {
+ while (StartOf(9)) {
Stmt(body);
}
alternatives.Add(new GuardedAlternative(x, e, body));
@@ -1395,14 +1423,14 @@ List<Expression/*!*/>/*!*/ decreases) {
decreases = new List<Expression/*!*/>();
mod = null;
- while (StartOf(12)) {
- if (la.kind == 29 || la.kind == 59) {
+ while (StartOf(14)) {
+ if (la.kind == 29 || la.kind == 60) {
isFree = false;
if (la.kind == 29) {
Get();
isFree = true;
}
- Expect(59);
+ Expect(60);
Expression(out e);
invariants.Add(new MaybeFreeExpression(e, isFree));
Expect(17);
@@ -1413,7 +1441,7 @@ List<Expression/*!*/>/*!*/ decreases) {
} else {
Get();
mod = mod ?? new List<FrameExpression>();
- if (StartOf(6)) {
+ if (StartOf(8)) {
FrameExpression(out fe);
mod.Add(fe);
while (la.kind == 19) {
@@ -1433,7 +1461,7 @@ List<Expression/*!*/>/*!*/ decreases) {
List<BoundVar/*!*/> arguments = new List<BoundVar/*!*/>();
List<Statement/*!*/> body = new List<Statement/*!*/>();
- Expect(56);
+ Expect(57);
x = t;
Ident(out id);
if (la.kind == 33) {
@@ -1447,8 +1475,8 @@ List<Expression/*!*/>/*!*/ decreases) {
}
Expect(34);
}
- Expect(57);
- while (StartOf(7)) {
+ Expect(58);
+ while (StartOf(9)) {
Stmt(body);
}
c = new MatchCaseStmt(x, id.val, arguments, body);
@@ -1459,16 +1487,16 @@ List<Expression/*!*/>/*!*/ decreases) {
if (la.kind == 4) {
Get();
arg = new Attributes.Argument(t.val.Substring(1, t.val.Length-2));
- } else if (StartOf(6)) {
+ } else if (StartOf(8)) {
Expression(out e);
arg = new Attributes.Argument(e);
- } else SynErr(123);
+ } else SynErr(126);
}
void EquivExpression(out Expression/*!*/ e0) {
Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1;
ImpliesExpression(out e0);
- while (la.kind == 66 || la.kind == 67) {
+ while (la.kind == 67 || la.kind == 68) {
EquivOp();
x = t;
ImpliesExpression(out e1);
@@ -1479,7 +1507,7 @@ List<Expression/*!*/>/*!*/ decreases) {
void ImpliesExpression(out Expression/*!*/ e0) {
Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1;
LogicalExpression(out e0);
- if (la.kind == 68 || la.kind == 69) {
+ if (la.kind == 69 || la.kind == 70) {
ImpliesOp();
x = t;
ImpliesExpression(out e1);
@@ -1488,23 +1516,23 @@ List<Expression/*!*/>/*!*/ decreases) {
}
void EquivOp() {
- if (la.kind == 66) {
+ if (la.kind == 67) {
Get();
- } else if (la.kind == 67) {
+ } else if (la.kind == 68) {
Get();
- } else SynErr(124);
+ } else SynErr(127);
}
void LogicalExpression(out Expression/*!*/ e0) {
Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1;
RelationalExpression(out e0);
- if (StartOf(13)) {
- if (la.kind == 70 || la.kind == 71) {
+ if (StartOf(15)) {
+ if (la.kind == 71 || la.kind == 72) {
AndOp();
x = t;
RelationalExpression(out e1);
e0 = new BinaryExpr(x, BinaryExpr.Opcode.And, e0, e1);
- while (la.kind == 70 || la.kind == 71) {
+ while (la.kind == 71 || la.kind == 72) {
AndOp();
x = t;
RelationalExpression(out e1);
@@ -1515,7 +1543,7 @@ List<Expression/*!*/>/*!*/ decreases) {
x = t;
RelationalExpression(out e1);
e0 = new BinaryExpr(x, BinaryExpr.Opcode.Or, e0, e1);
- while (la.kind == 72 || la.kind == 73) {
+ while (la.kind == 73 || la.kind == 74) {
OrOp();
x = t;
RelationalExpression(out e1);
@@ -1526,11 +1554,11 @@ List<Expression/*!*/>/*!*/ decreases) {
}
void ImpliesOp() {
- if (la.kind == 68) {
+ if (la.kind == 69) {
Get();
- } else if (la.kind == 69) {
+ } else if (la.kind == 70) {
Get();
- } else SynErr(125);
+ } else SynErr(128);
}
void RelationalExpression(out Expression/*!*/ e) {
@@ -1539,23 +1567,23 @@ List<Expression/*!*/>/*!*/ decreases) {
List<Expression> chain = null;
List<BinaryExpr.Opcode> ops = null;
int kind = 0; // 0 ("uncommitted") indicates chain of ==, possibly with one !=
- // 1 ("ascending") indicates chain of ==, <, <=, possibly with one !=
- // 2 ("descending") indicates chain of ==, >, >=, possibly with one !=
- // 3 ("illegal") indicates illegal chain
- // 4 ("disjoint") indicates chain of disjoint set operators
+ // 1 ("ascending") indicates chain of ==, <, <=, possibly with one !=
+ // 2 ("descending") indicates chain of ==, >, >=, possibly with one !=
+ // 3 ("illegal") indicates illegal chain
+ // 4 ("disjoint") indicates chain of disjoint set operators
bool hasSeenNeq = false;
Term(out e0);
e = e0;
- if (StartOf(14)) {
+ if (StartOf(16)) {
RelOp(out x, out op);
firstOpTok = x;
Term(out e1);
e = new BinaryExpr(x, op, e0, e1);
if (op == BinaryExpr.Opcode.Disjoint)
- acc = new BinaryExpr(x, BinaryExpr.Opcode.Add, e0, e1); // accumulate first two operands.
+ acc = new BinaryExpr(x, BinaryExpr.Opcode.Add, e0, e1); // accumulate first two operands.
- while (StartOf(14)) {
+ while (StartOf(16)) {
if (chain == null) {
chain = new List<Expression>();
ops = new List<BinaryExpr.Opcode>();
@@ -1609,11 +1637,11 @@ List<Expression/*!*/>/*!*/ decreases) {
Term(out e1);
ops.Add(op); chain.Add(e1);
if (op == BinaryExpr.Opcode.Disjoint) {
- e = new BinaryExpr(x, BinaryExpr.Opcode.And, e, new BinaryExpr(x, op, acc, e1));
- acc = new BinaryExpr(x, BinaryExpr.Opcode.Add, acc, e1); //e0 has already been added.
+ e = new BinaryExpr(x, BinaryExpr.Opcode.And, e, new BinaryExpr(x, op, acc, e1));
+ acc = new BinaryExpr(x, BinaryExpr.Opcode.Add, acc, e1); //e0 has already been added.
}
else
- e = new BinaryExpr(x, BinaryExpr.Opcode.And, e, new BinaryExpr(x, op, e0, e1));
+ e = new BinaryExpr(x, BinaryExpr.Opcode.And, e, new BinaryExpr(x, op, e0, e1));
}
}
@@ -1624,25 +1652,25 @@ List<Expression/*!*/>/*!*/ decreases) {
}
void AndOp() {
- if (la.kind == 70) {
+ if (la.kind == 71) {
Get();
- } else if (la.kind == 71) {
+ } else if (la.kind == 72) {
Get();
- } else SynErr(126);
+ } else SynErr(129);
}
void OrOp() {
- if (la.kind == 72) {
+ if (la.kind == 73) {
Get();
- } else if (la.kind == 73) {
+ } else if (la.kind == 74) {
Get();
- } else SynErr(127);
+ } else SynErr(130);
}
void Term(out Expression/*!*/ e0) {
Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1; BinaryExpr.Opcode op;
Factor(out e0);
- while (la.kind == 83 || la.kind == 84) {
+ while (la.kind == 84 || la.kind == 85) {
AddOp(out x, out op);
Factor(out e1);
e0 = new BinaryExpr(x, op, e0, e1);
@@ -1652,7 +1680,7 @@ List<Expression/*!*/>/*!*/ decreases) {
void RelOp(out IToken/*!*/ x, out BinaryExpr.Opcode op) {
Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op = BinaryExpr.Opcode.Add/*(dummy)*/;
switch (la.kind) {
- case 74: {
+ case 75: {
Get();
x = t; op = BinaryExpr.Opcode.Eq;
break;
@@ -1667,59 +1695,59 @@ List<Expression/*!*/>/*!*/ decreases) {
x = t; op = BinaryExpr.Opcode.Gt;
break;
}
- case 75: {
+ case 76: {
Get();
x = t; op = BinaryExpr.Opcode.Le;
break;
}
- case 76: {
+ case 77: {
Get();
x = t; op = BinaryExpr.Opcode.Ge;
break;
}
- case 77: {
+ case 78: {
Get();
x = t; op = BinaryExpr.Opcode.Neq;
break;
}
- case 78: {
+ case 79: {
Get();
x = t; op = BinaryExpr.Opcode.Disjoint;
break;
}
- case 62: {
+ case 63: {
Get();
x = t; op = BinaryExpr.Opcode.In;
break;
}
- case 79: {
+ case 80: {
Get();
x = t; op = BinaryExpr.Opcode.NotIn;
break;
}
- case 80: {
+ case 81: {
Get();
x = t; op = BinaryExpr.Opcode.Neq;
break;
}
- case 81: {
+ case 82: {
Get();
x = t; op = BinaryExpr.Opcode.Le;
break;
}
- case 82: {
+ case 83: {
Get();
x = t; op = BinaryExpr.Opcode.Ge;
break;
}
- default: SynErr(128); break;
+ default: SynErr(131); break;
}
}
void Factor(out Expression/*!*/ e0) {
Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1; BinaryExpr.Opcode op;
UnaryExpression(out e0);
- while (la.kind == 43 || la.kind == 85 || la.kind == 86) {
+ while (la.kind == 44 || la.kind == 86 || la.kind == 87) {
MulOp(out x, out op);
UnaryExpression(out e1);
e0 = new BinaryExpr(x, op, e0, e1);
@@ -1728,78 +1756,82 @@ List<Expression/*!*/>/*!*/ decreases) {
void AddOp(out IToken/*!*/ x, out BinaryExpr.Opcode op) {
Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryExpr.Opcode.Add/*(dummy)*/;
- if (la.kind == 83) {
+ if (la.kind == 84) {
Get();
x = t; op = BinaryExpr.Opcode.Add;
- } else if (la.kind == 84) {
+ } else if (la.kind == 85) {
Get();
x = t; op = BinaryExpr.Opcode.Sub;
- } else SynErr(129);
+ } else SynErr(132);
}
void UnaryExpression(out Expression/*!*/ e) {
Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; e = dummyExpr;
switch (la.kind) {
- case 84: {
+ case 85: {
Get();
x = t;
UnaryExpression(out e);
e = new BinaryExpr(x, BinaryExpr.Opcode.Sub, new LiteralExpr(x, 0), e);
break;
}
- case 87: case 88: {
+ case 88: case 89: {
NegOp();
x = t;
UnaryExpression(out e);
e = new UnaryExpr(x, UnaryExpr.Opcode.Not, e);
break;
}
- case 38: case 54: case 60: case 98: case 99: case 100: case 101: {
+ case 38: case 55: case 61: case 99: case 100: case 101: case 102: {
EndlessExpression(out e);
break;
}
case 1: {
DottedIdentifiersAndFunction(out e);
- while (la.kind == 50 || la.kind == 52) {
+ while (la.kind == 51 || la.kind == 53) {
Suffix(ref e);
}
break;
}
- case 7: case 50: {
+ case 7: case 51: {
DisplayExpr(out e);
break;
}
- case 2: case 16: case 33: case 89: case 90: case 91: case 92: case 93: case 94: case 95: {
+ case 39: {
+ MultiSetExpr(out e);
+ break;
+ }
+ case 2: case 16: case 33: case 90: case 91: case 92: case 93: case 94: case 95: case 96: {
ConstAtomExpression(out e);
- while (la.kind == 50 || la.kind == 52) {
+ while (la.kind == 51 || la.kind == 53) {
Suffix(ref e);
}
break;
}
- default: SynErr(130); break;
+ default: SynErr(133); break;
}
}
void MulOp(out IToken/*!*/ x, out BinaryExpr.Opcode op) {
Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op = BinaryExpr.Opcode.Add/*(dummy)*/;
- if (la.kind == 43) {
+ if (la.kind == 44) {
Get();
x = t; op = BinaryExpr.Opcode.Mul;
- } else if (la.kind == 85) {
+ } else if (la.kind == 86) {
Get();
x = t; op = BinaryExpr.Opcode.Div;
- } else if (la.kind == 86) {
+ } else if (la.kind == 87) {
Get();
x = t; op = BinaryExpr.Opcode.Mod;
- } else SynErr(131);
+ } else SynErr(134);
}
void NegOp() {
- if (la.kind == 87) {
+ if (la.kind == 88) {
Get();
- } else if (la.kind == 88) {
+ } else if (la.kind == 89) {
Get();
- } else SynErr(132);
+ } else SynErr(135);
}
void EndlessExpression(out Expression e) {
@@ -1807,22 +1839,22 @@ List<Expression/*!*/>/*!*/ decreases) {
Expression e0, e1;
e = dummyExpr;
- if (la.kind == 54) {
+ if (la.kind == 55) {
Get();
x = t;
Expression(out e);
- Expect(96);
+ Expect(97);
Expression(out e0);
- Expect(55);
+ Expect(56);
Expression(out e1);
e = new ITEExpr(x, e, e0, e1);
- } else if (la.kind == 60) {
+ } else if (la.kind == 61) {
MatchExpression(out e);
- } else if (StartOf(15)) {
+ } else if (StartOf(17)) {
QuantifierGuts(out e);
} else if (la.kind == 38) {
ComprehensionExpr(out e);
- } else SynErr(133);
+ } else SynErr(136);
}
void DottedIdentifiersAndFunction(out Expression e) {
@@ -1832,7 +1864,7 @@ List<Expression/*!*/>/*!*/ decreases) {
Ident(out id);
idents.Add(id);
- while (la.kind == 52) {
+ while (la.kind == 53) {
Get();
Ident(out id);
idents.Add(id);
@@ -1840,7 +1872,7 @@ List<Expression/*!*/>/*!*/ decreases) {
if (la.kind == 33) {
Get();
openParen = t; args = new List<Expression>();
- if (StartOf(6)) {
+ if (StartOf(8)) {
Expressions(args);
}
Expect(34);
@@ -1854,37 +1886,37 @@ List<Expression/*!*/>/*!*/ decreases) {
List<Expression> multipleIndices = null;
bool func = false;
- if (la.kind == 52) {
+ if (la.kind == 53) {
Get();
Ident(out id);
if (la.kind == 33) {
Get();
args = new List<Expression/*!*/>(); func = true;
- if (StartOf(6)) {
+ if (StartOf(8)) {
Expressions(args);
}
Expect(34);
e = new FunctionCallExpr(id, id.val, e, args);
}
if (!func) { e = new FieldSelectExpr(id, e, id.val); }
- } else if (la.kind == 50) {
+ } else if (la.kind == 51) {
Get();
x = t;
- if (StartOf(6)) {
+ if (StartOf(8)) {
Expression(out ee);
e0 = ee;
- if (la.kind == 97) {
+ if (la.kind == 98) {
Get();
anyDots = true;
- if (StartOf(6)) {
+ if (StartOf(8)) {
Expression(out ee);
e1 = ee;
}
- } else if (la.kind == 48) {
+ } else if (la.kind == 49) {
Get();
Expression(out ee);
e1 = ee;
- } else if (la.kind == 19 || la.kind == 51) {
+ } else if (la.kind == 19 || la.kind == 52) {
while (la.kind == 19) {
Get();
Expression(out ee);
@@ -1895,60 +1927,89 @@ List<Expression/*!*/>/*!*/ decreases) {
multipleIndices.Add(ee);
}
- } else SynErr(134);
- } else if (la.kind == 97) {
+ } else SynErr(137);
+ } else if (la.kind == 98) {
Get();
- Expression(out ee);
- anyDots = true; e1 = ee;
- } else SynErr(135);
+ anyDots = true;
+ if (StartOf(8)) {
+ Expression(out ee);
+ e1 = ee;
+ }
+ } else SynErr(138);
if (multipleIndices != null) {
e = new MultiSelectExpr(x, e, multipleIndices);
// make sure an array class with this dimensionality exists
UserDefinedType tmp = theBuiltIns.ArrayType(x, multipleIndices.Count, new IntType(), true);
} else {
- if (!anyDots && e0 == null) {
- /* a parsing error occurred */
- e0 = dummyExpr;
- }
- Contract.Assert(anyDots || e0 != null);
- if (anyDots) {
- Contract.Assert(e0 != null || e1 != null);
- e = new SeqSelectExpr(x, false, e, e0, e1);
- } else if (e1 == null) {
- Contract.Assert(e0 != null);
- e = new SeqSelectExpr(x, true, e, e0, null);
- } else {
- Contract.Assert(e0 != null);
- e = new SeqUpdateExpr(x, e, e0, e1);
- }
+ if (!anyDots && e0 == null) {
+ /* a parsing error occurred */
+ e0 = dummyExpr;
+ }
+ Contract.Assert(anyDots || e0 != null);
+ if (anyDots) {
+ //Contract.Assert(e0 != null || e1 != null);
+ e = new SeqSelectExpr(x, false, e, e0, e1);
+ } else if (e1 == null) {
+ Contract.Assert(e0 != null);
+ e = new SeqSelectExpr(x, true, e, e0, null);
+ } else {
+ Contract.Assert(e0 != null);
+ e = new SeqUpdateExpr(x, e, e0, e1);
+ }
}
- Expect(51);
- } else SynErr(136);
+ Expect(52);
+ } else SynErr(139);
}
void DisplayExpr(out Expression e) {
Contract.Ensures(Contract.ValueAtReturn(out e) != null);
- IToken/*!*/ x; List<Expression/*!*/>/*!*/ elements;
+ IToken/*!*/ x = null; List<Expression/*!*/>/*!*/ elements;
e = dummyExpr;
if (la.kind == 7) {
Get();
x = t; elements = new List<Expression/*!*/>();
- if (StartOf(6)) {
+ if (StartOf(8)) {
Expressions(elements);
}
- e = new SetDisplayExpr(x, elements);
+ e = new SetDisplayExpr(x, elements);
Expect(8);
- } else if (la.kind == 50) {
+ } else if (la.kind == 51) {
Get();
x = t; elements = new List<Expression/*!*/>();
- if (StartOf(6)) {
+ if (StartOf(8)) {
Expressions(elements);
}
e = new SeqDisplayExpr(x, elements);
- Expect(51);
- } else SynErr(137);
+ Expect(52);
+ } else SynErr(140);
+ }
+
+ void MultiSetExpr(out Expression e) {
+ Contract.Ensures(Contract.ValueAtReturn(out e) != null);
+ IToken/*!*/ x = null; List<Expression/*!*/>/*!*/ elements;
+ e = dummyExpr;
+
+ Expect(39);
+ x = t;
+ if (la.kind == 7) {
+ Get();
+ elements = new List<Expression/*!*/>();
+ if (StartOf(8)) {
+ Expressions(elements);
+ }
+ e = new MultiSetDisplayExpr(x, elements);
+ Expect(8);
+ } else if (la.kind == 33) {
+ Get();
+ x = t; elements = new List<Expression/*!*/>();
+ Expression(out e);
+ e = new MultiSetFormingExpr(x, e);
+ Expect(34);
+ } else if (StartOf(18)) {
+ SemErr("multiset must be followed by multiset literal or expression to coerce in parentheses.");
+ } else SynErr(141);
}
void ConstAtomExpression(out Expression/*!*/ e) {
@@ -1957,17 +2018,17 @@ List<Expression/*!*/>/*!*/ decreases) {
e = dummyExpr;
switch (la.kind) {
- case 89: {
+ case 90: {
Get();
e = new LiteralExpr(t, false);
break;
}
- case 90: {
+ case 91: {
Get();
e = new LiteralExpr(t, true);
break;
}
- case 91: {
+ case 92: {
Get();
e = new LiteralExpr(t);
break;
@@ -1977,12 +2038,12 @@ List<Expression/*!*/>/*!*/ decreases) {
e = new LiteralExpr(t, n);
break;
}
- case 92: {
+ case 93: {
Get();
e = new ThisExpr(t);
break;
}
- case 93: {
+ case 94: {
Get();
x = t;
Expect(33);
@@ -1991,7 +2052,7 @@ List<Expression/*!*/>/*!*/ decreases) {
e = new FreshExpr(x, e);
break;
}
- case 94: {
+ case 95: {
Get();
x = t;
Expect(33);
@@ -2000,7 +2061,7 @@ List<Expression/*!*/>/*!*/ decreases) {
e = new AllocatedExpr(x, e);
break;
}
- case 95: {
+ case 96: {
Get();
x = t;
Expect(33);
@@ -2025,7 +2086,7 @@ List<Expression/*!*/>/*!*/ decreases) {
Expect(34);
break;
}
- default: SynErr(138); break;
+ default: SynErr(142); break;
}
}
@@ -2034,8 +2095,8 @@ List<Expression/*!*/>/*!*/ decreases) {
try {
n = BigInteger.Parse(t.val);
} catch (System.FormatException) {
- SemErr("incorrectly formatted number");
- n = BigInteger.Zero;
+ SemErr("incorrectly formatted number");
+ n = BigInteger.Zero;
}
}
@@ -2044,10 +2105,10 @@ List<Expression/*!*/>/*!*/ decreases) {
Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; MatchCaseExpr/*!*/ c;
List<MatchCaseExpr/*!*/> cases = new List<MatchCaseExpr/*!*/>();
- Expect(60);
+ Expect(61);
x = t;
Expression(out e);
- while (la.kind == 56) {
+ while (la.kind == 57) {
CaseExpression(out c);
cases.Add(c);
}
@@ -2064,13 +2125,13 @@ List<Expression/*!*/>/*!*/ decreases) {
Expression range = null;
Expression/*!*/ body;
- if (la.kind == 98 || la.kind == 99) {
+ if (la.kind == 99 || la.kind == 100) {
Forall();
x = t; univ = true;
- } else if (la.kind == 100 || la.kind == 101) {
+ } else if (la.kind == 101 || la.kind == 102) {
Exists();
x = t;
- } else SynErr(139);
+ } else SynErr(143);
IdentTypeOptional(out bv);
bvars.Add(bv);
while (la.kind == 19) {
@@ -2090,7 +2151,7 @@ List<Expression/*!*/>/*!*/ decreases) {
if (univ) {
q = new ForallExpr(x, bvars, range, body, trigs, attrs);
} else {
- q = new ExistsExpr(x, bvars, range, body, trigs, attrs);
+ q = new ExistsExpr(x, bvars, range, body, trigs, attrs);
}
}
@@ -2114,7 +2175,7 @@ List<Expression/*!*/>/*!*/ decreases) {
}
Expect(16);
Expression(out range);
- if (la.kind == 102 || la.kind == 103) {
+ if (la.kind == 103 || la.kind == 104) {
QSep();
Expression(out body);
}
@@ -2128,7 +2189,7 @@ List<Expression/*!*/>/*!*/ decreases) {
List<BoundVar/*!*/> arguments = new List<BoundVar/*!*/>();
Expression/*!*/ body;
- Expect(56);
+ Expect(57);
x = t;
Ident(out id);
if (la.kind == 33) {
@@ -2142,25 +2203,25 @@ List<Expression/*!*/>/*!*/ decreases) {
}
Expect(34);
}
- Expect(57);
+ Expect(58);
Expression(out body);
c = new MatchCaseExpr(x, id.val, arguments, body);
}
void Forall() {
- if (la.kind == 98) {
+ if (la.kind == 99) {
Get();
- } else if (la.kind == 99) {
+ } else if (la.kind == 100) {
Get();
- } else SynErr(140);
+ } else SynErr(144);
}
void Exists() {
- if (la.kind == 100) {
+ if (la.kind == 101) {
Get();
- } else if (la.kind == 101) {
+ } else if (la.kind == 102) {
Get();
- } else SynErr(141);
+ } else SynErr(145);
}
void AttributeOrTrigger(ref Attributes attrs, ref Triggers trigs) {
@@ -2169,20 +2230,20 @@ List<Expression/*!*/>/*!*/ decreases) {
Expect(7);
if (la.kind == 22) {
AttributeBody(ref attrs);
- } else if (StartOf(6)) {
+ } else if (StartOf(8)) {
es = new List<Expression/*!*/>();
Expressions(es);
trigs = new Triggers(es, trigs);
- } else SynErr(142);
+ } else SynErr(146);
Expect(8);
}
void QSep() {
- if (la.kind == 102) {
+ if (la.kind == 103) {
Get();
- } else if (la.kind == 103) {
+ } else if (la.kind == 104) {
Get();
- } else SynErr(143);
+ } else SynErr(147);
}
void AttributeBody(ref Attributes attrs) {
@@ -2193,7 +2254,7 @@ List<Expression/*!*/>/*!*/ decreases) {
Expect(22);
Expect(1);
aName = t.val;
- if (StartOf(16)) {
+ if (StartOf(19)) {
AttributeArg(out aArg);
aArgs.Add(aArg);
while (la.kind == 19) {
@@ -2212,29 +2273,31 @@ List<Expression/*!*/>/*!*/ decreases) {
la.val = "";
Get();
Dafny();
- Expect(0);
Expect(0);
}
static readonly bool[,]/*!*/ set = {
- {T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
- {x,x,x,x, x,T,x,x, x,T,T,T, T,T,T,x, x,x,T,x, T,x,x,x, x,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
- {x,x,x,x, x,x,x,x, x,x,T,T, T,T,x,x, x,x,T,x, T,x,x,x, x,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
- {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
- {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
- {x,T,x,T, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
- {x,T,T,x, x,x,x,T, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,T,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,T, T,T,T,T, T,T,T,T, x,x,T,T, T,T,x,x, x,x},
- {x,T,T,x, x,x,x,T, x,x,x,T, x,x,x,x, T,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,T,T,T, x,x,x,x, x,x,T,x, x,x,T,x, T,T,x,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x},
- {x,T,T,x, x,x,x,T, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,x, x,x,x,T, x,x,x,x, x,x,T,x, x,x,T,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,T, T,T,T,T, T,T,T,T, x,x,T,T, T,T,x,x, x,x},
- {x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
- {x,T,T,x, x,x,x,T, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,x, x,x,x,T, x,x,x,x, x,T,T,x, x,T,T,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,T, T,T,T,T, T,T,T,T, x,x,T,T, T,T,x,x, x,x},
- {x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x},
- {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
- {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
- {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
- {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,x,x, x,x},
- {x,T,T,x, T,x,x,T, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,T,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,T, T,T,T,T, T,T,T,T, x,x,T,T, T,T,x,x, x,x}
+ {T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
+ {x,x,x,x, x,T,x,x, x,T,T,T, T,T,T,x, x,x,T,x, T,x,x,x, x,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
+ {x,x,x,x, x,x,x,x, x,x,T,T, T,T,x,x, x,x,T,x, T,x,x,x, x,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
+ {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
+ {x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
+ {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
+ {x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
+ {x,T,x,T, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
+ {x,T,T,x, x,x,x,T, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,T, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,T, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, T,T,T,T, T,T,T,T, T,x,x,T, T,T,T,x, x,x,x},
+ {x,T,T,x, x,x,x,T, x,x,x,T, x,x,x,x, T,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,x,x,x, x,x,x,T, x,x,x,T, x,T,T,x, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x},
+ {x,T,T,x, x,x,x,T, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,T, x,x,x,x, T,x,x,x, x,x,x,T, x,x,x,T, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, T,T,T,T, T,T,T,T, T,x,x,T, T,T,T,x, x,x,x},
+ {x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
+ {x,T,T,x, x,x,x,T, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,T, x,x,x,x, T,x,x,x, x,x,T,T, x,x,T,T, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, T,T,T,T, T,T,T,T, T,x,x,T, T,T,T,x, x,x,x},
+ {x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x},
+ {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
+ {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
+ {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
+ {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,x, x,x,x},
+ {x,x,x,x, x,x,x,T, T,x,x,x, x,x,x,x, T,T,x,T, x,x,x,T, T,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, T,T,x,x, x,T,x,x, T,x,x,x, T,T,T,x, x,x,x,T, x,x,x,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, x,x,x,x, x,x,x,x, x,T,T,x, x,x,x,T, T,x,x},
+ {x,T,T,x, T,x,x,T, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,T, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,T, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, T,T,T,T, T,T,T,T, T,x,x,T, T,T,T,x, x,x,x}
};
} // end Parser
@@ -2298,111 +2361,115 @@ public class Errors {
case 36: s = "\"nat\" expected"; break;
case 37: s = "\"int\" expected"; break;
case 38: s = "\"set\" expected"; break;
- case 39: s = "\"seq\" expected"; break;
- case 40: s = "\"object\" expected"; break;
- case 41: s = "\"function\" expected"; break;
- case 42: s = "\"reads\" expected"; break;
- case 43: s = "\"*\" expected"; break;
- case 44: s = "\"`\" expected"; break;
- case 45: s = "\"label\" expected"; break;
- case 46: s = "\"break\" expected"; break;
- case 47: s = "\"return\" expected"; break;
- case 48: s = "\":=\" expected"; break;
- case 49: s = "\"new\" expected"; break;
- case 50: s = "\"[\" expected"; break;
- case 51: s = "\"]\" expected"; break;
- case 52: s = "\".\" expected"; break;
- case 53: s = "\"choose\" expected"; break;
- case 54: s = "\"if\" expected"; break;
- case 55: s = "\"else\" expected"; break;
- case 56: s = "\"case\" expected"; break;
- case 57: s = "\"=>\" expected"; break;
- case 58: s = "\"while\" expected"; break;
- case 59: s = "\"invariant\" expected"; break;
- case 60: s = "\"match\" expected"; break;
- case 61: s = "\"foreach\" expected"; break;
- case 62: s = "\"in\" expected"; break;
- case 63: s = "\"assert\" expected"; break;
- case 64: s = "\"assume\" expected"; break;
- case 65: s = "\"print\" expected"; break;
- case 66: s = "\"<==>\" expected"; break;
- case 67: s = "\"\\u21d4\" expected"; break;
- case 68: s = "\"==>\" expected"; break;
- case 69: s = "\"\\u21d2\" expected"; break;
- case 70: s = "\"&&\" expected"; break;
- case 71: s = "\"\\u2227\" expected"; break;
- case 72: s = "\"||\" expected"; break;
- case 73: s = "\"\\u2228\" expected"; break;
- case 74: s = "\"==\" expected"; break;
- case 75: s = "\"<=\" expected"; break;
- case 76: s = "\">=\" expected"; break;
- case 77: s = "\"!=\" expected"; break;
- case 78: s = "\"!!\" expected"; break;
- case 79: s = "\"!in\" expected"; break;
- case 80: s = "\"\\u2260\" expected"; break;
- case 81: s = "\"\\u2264\" expected"; break;
- case 82: s = "\"\\u2265\" expected"; break;
- case 83: s = "\"+\" expected"; break;
- case 84: s = "\"-\" expected"; break;
- case 85: s = "\"/\" expected"; break;
- case 86: s = "\"%\" expected"; break;
- case 87: s = "\"!\" expected"; break;
- case 88: s = "\"\\u00ac\" expected"; break;
- case 89: s = "\"false\" expected"; break;
- case 90: s = "\"true\" expected"; break;
- case 91: s = "\"null\" expected"; break;
- case 92: s = "\"this\" expected"; break;
- case 93: s = "\"fresh\" expected"; break;
- case 94: s = "\"allocated\" expected"; break;
- case 95: s = "\"old\" expected"; break;
- case 96: s = "\"then\" expected"; break;
- case 97: s = "\"..\" expected"; break;
- case 98: s = "\"forall\" expected"; break;
- case 99: s = "\"\\u2200\" expected"; break;
- case 100: s = "\"exists\" expected"; break;
- case 101: s = "\"\\u2203\" expected"; break;
- case 102: s = "\"::\" expected"; break;
- case 103: s = "\"\\u2022\" expected"; break;
- case 104: s = "??? expected"; break;
- case 105: s = "invalid ClassMemberDecl"; break;
- case 106: s = "invalid MethodDecl"; break;
- case 107: s = "invalid TypeAndToken"; break;
- case 108: s = "invalid MethodSpec"; break;
- case 109: s = "invalid MethodSpec"; break;
- case 110: s = "invalid ReferenceType"; break;
- case 111: s = "invalid FunctionSpec"; break;
- case 112: s = "invalid PossiblyWildFrameExpression"; break;
- case 113: s = "invalid PossiblyWildExpression"; break;
- case 114: s = "invalid OneStmt"; break;
- case 115: s = "invalid OneStmt"; break;
- case 116: s = "invalid UpdateStmt"; break;
- case 117: s = "invalid IfStmt"; break;
- case 118: s = "invalid IfStmt"; break;
- case 119: s = "invalid WhileStmt"; break;
- case 120: s = "invalid Rhs"; break;
- case 121: s = "invalid Lhs"; break;
- case 122: s = "invalid Guard"; break;
- case 123: s = "invalid AttributeArg"; break;
- case 124: s = "invalid EquivOp"; break;
- case 125: s = "invalid ImpliesOp"; break;
- case 126: s = "invalid AndOp"; break;
- case 127: s = "invalid OrOp"; break;
- case 128: s = "invalid RelOp"; break;
- case 129: s = "invalid AddOp"; break;
- case 130: s = "invalid UnaryExpression"; break;
- case 131: s = "invalid MulOp"; break;
- case 132: s = "invalid NegOp"; break;
- case 133: s = "invalid EndlessExpression"; break;
- case 134: s = "invalid Suffix"; break;
- case 135: s = "invalid Suffix"; break;
- case 136: s = "invalid Suffix"; break;
- case 137: s = "invalid DisplayExpr"; break;
- case 138: s = "invalid ConstAtomExpression"; break;
- case 139: s = "invalid QuantifierGuts"; break;
- case 140: s = "invalid Forall"; break;
- case 141: s = "invalid Exists"; break;
- case 142: s = "invalid AttributeOrTrigger"; break;
- case 143: s = "invalid QSep"; break;
+ case 39: s = "\"multiset\" expected"; break;
+ case 40: s = "\"seq\" expected"; break;
+ case 41: s = "\"object\" expected"; break;
+ case 42: s = "\"function\" expected"; break;
+ case 43: s = "\"reads\" expected"; break;
+ case 44: s = "\"*\" expected"; break;
+ case 45: s = "\"`\" expected"; break;
+ case 46: s = "\"label\" expected"; break;
+ case 47: s = "\"break\" expected"; break;
+ case 48: s = "\"return\" expected"; break;
+ case 49: s = "\":=\" expected"; break;
+ case 50: s = "\"new\" expected"; break;
+ case 51: s = "\"[\" expected"; break;
+ case 52: s = "\"]\" expected"; break;
+ case 53: s = "\".\" expected"; break;
+ case 54: s = "\"choose\" expected"; break;
+ case 55: s = "\"if\" expected"; break;
+ case 56: s = "\"else\" expected"; break;
+ case 57: s = "\"case\" expected"; break;
+ case 58: s = "\"=>\" expected"; break;
+ case 59: s = "\"while\" expected"; break;
+ case 60: s = "\"invariant\" expected"; break;
+ case 61: s = "\"match\" expected"; break;
+ case 62: s = "\"foreach\" expected"; break;
+ case 63: s = "\"in\" expected"; break;
+ case 64: s = "\"assert\" expected"; break;
+ case 65: s = "\"assume\" expected"; break;
+ case 66: s = "\"print\" expected"; break;
+ case 67: s = "\"<==>\" expected"; break;
+ case 68: s = "\"\\u21d4\" expected"; break;
+ case 69: s = "\"==>\" expected"; break;
+ case 70: s = "\"\\u21d2\" expected"; break;
+ case 71: s = "\"&&\" expected"; break;
+ case 72: s = "\"\\u2227\" expected"; break;
+ case 73: s = "\"||\" expected"; break;
+ case 74: s = "\"\\u2228\" expected"; break;
+ case 75: s = "\"==\" expected"; break;
+ case 76: s = "\"<=\" expected"; break;
+ case 77: s = "\">=\" expected"; break;
+ case 78: s = "\"!=\" expected"; break;
+ case 79: s = "\"!!\" expected"; break;
+ case 80: s = "\"!in\" expected"; break;
+ case 81: s = "\"\\u2260\" expected"; break;
+ case 82: s = "\"\\u2264\" expected"; break;
+ case 83: s = "\"\\u2265\" expected"; break;
+ case 84: s = "\"+\" expected"; break;
+ case 85: s = "\"-\" expected"; break;
+ case 86: s = "\"/\" expected"; break;
+ case 87: s = "\"%\" expected"; break;
+ case 88: s = "\"!\" expected"; break;
+ case 89: s = "\"\\u00ac\" expected"; break;
+ case 90: s = "\"false\" expected"; break;
+ case 91: s = "\"true\" expected"; break;
+ case 92: s = "\"null\" expected"; break;
+ case 93: s = "\"this\" expected"; break;
+ case 94: s = "\"fresh\" expected"; break;
+ case 95: s = "\"allocated\" expected"; break;
+ case 96: s = "\"old\" expected"; break;
+ case 97: s = "\"then\" expected"; break;
+ case 98: s = "\"..\" expected"; break;
+ case 99: s = "\"forall\" expected"; break;
+ case 100: s = "\"\\u2200\" expected"; break;
+ case 101: s = "\"exists\" expected"; break;
+ case 102: s = "\"\\u2203\" expected"; break;
+ case 103: s = "\"::\" expected"; break;
+ case 104: s = "\"\\u2022\" expected"; break;
+ case 105: s = "??? expected"; break;
+ case 106: s = "invalid ClassMemberDecl"; break;
+ case 107: s = "invalid FunctionDecl"; break;
+ case 108: s = "invalid MethodDecl"; break;
+ case 109: s = "invalid MethodDecl"; break;
+ case 110: s = "invalid TypeAndToken"; break;
+ case 111: s = "invalid MethodSpec"; break;
+ case 112: s = "invalid MethodSpec"; break;
+ case 113: s = "invalid ReferenceType"; break;
+ case 114: s = "invalid FunctionSpec"; break;
+ case 115: s = "invalid PossiblyWildFrameExpression"; break;
+ case 116: s = "invalid PossiblyWildExpression"; break;
+ case 117: s = "invalid OneStmt"; break;
+ case 118: s = "invalid OneStmt"; break;
+ case 119: s = "invalid UpdateStmt"; break;
+ case 120: s = "invalid IfStmt"; break;
+ case 121: s = "invalid IfStmt"; break;
+ case 122: s = "invalid WhileStmt"; break;
+ case 123: s = "invalid Rhs"; break;
+ case 124: s = "invalid Lhs"; break;
+ case 125: s = "invalid Guard"; break;
+ case 126: s = "invalid AttributeArg"; break;
+ case 127: s = "invalid EquivOp"; break;
+ case 128: s = "invalid ImpliesOp"; break;
+ case 129: s = "invalid AndOp"; break;
+ case 130: s = "invalid OrOp"; break;
+ case 131: s = "invalid RelOp"; break;
+ case 132: s = "invalid AddOp"; break;
+ case 133: s = "invalid UnaryExpression"; break;
+ case 134: s = "invalid MulOp"; break;
+ case 135: s = "invalid NegOp"; break;
+ case 136: s = "invalid EndlessExpression"; break;
+ case 137: s = "invalid Suffix"; break;
+ case 138: s = "invalid Suffix"; break;
+ case 139: s = "invalid Suffix"; break;
+ case 140: s = "invalid DisplayExpr"; break;
+ case 141: s = "invalid MultiSetExpr"; break;
+ case 142: s = "invalid ConstAtomExpression"; break;
+ case 143: s = "invalid QuantifierGuts"; break;
+ case 144: s = "invalid Forall"; break;
+ case 145: s = "invalid Exists"; break;
+ case 146: s = "invalid AttributeOrTrigger"; break;
+ case 147: s = "invalid QSep"; break;
default: s = "error " + n; break;
}
@@ -2432,5 +2499,4 @@ public class FatalError: Exception {
public FatalError(string m): base(m) {}
}
-
} \ No newline at end of file
diff --git a/Source/Dafny/Printer.cs b/Source/Dafny/Printer.cs
index ba9963c7..63b5f926 100644
--- a/Source/Dafny/Printer.cs
+++ b/Source/Dafny/Printer.cs
@@ -788,9 +788,10 @@ namespace Microsoft.Dafny {
} else if (expr is DisplayExpression) {
DisplayExpression e = (DisplayExpression)expr;
- wr.Write(e is SetDisplayExpr ? "{" : "[");
+ if (e is MultiSetDisplayExpr) wr.Write("multiset");
+ wr.Write(e is SetDisplayExpr || e is MultiSetDisplayExpr ? "{" : "[");
PrintExpressionList(e.Elements);
- wr.Write(e is SetDisplayExpr ? "}" : "]");
+ wr.Write(e is SetDisplayExpr || e is MultiSetDisplayExpr ? "}" : "]");
} else if (expr is FieldSelectExpr) {
FieldSelectExpr e = (FieldSelectExpr)expr;
@@ -892,6 +893,11 @@ namespace Microsoft.Dafny {
PrintExpression(((OldExpr)expr).E);
wr.Write(")");
+ } else if (expr is MultiSetFormingExpr) {
+ wr.Write("multiset(");
+ PrintExpression(((MultiSetFormingExpr)expr).E);
+ wr.Write(")");
+
} else if (expr is FreshExpr) {
wr.Write("fresh(");
PrintExpression(((FreshExpr)expr).E);
diff --git a/Source/Dafny/Resolver.cs b/Source/Dafny/Resolver.cs
index 8ec5d4c1..098dbad2 100644
--- a/Source/Dafny/Resolver.cs
+++ b/Source/Dafny/Resolver.cs
@@ -897,6 +897,8 @@ namespace Microsoft.Dafny {
return b is ObjectType;
} else if (a is SetType) {
return b is SetType && UnifyTypes(((SetType)a).Arg, ((SetType)b).Arg);
+ } else if (a is MultiSetType) {
+ return b is MultiSetType && UnifyTypes(((MultiSetType)a).Arg, ((MultiSetType)b).Arg);
} else if (a is SeqType) {
return b is SeqType && UnifyTypes(((SeqType)a).Arg, ((SeqType)b).Arg);
} else if (a is UserDefinedType) {
@@ -994,7 +996,7 @@ namespace Microsoft.Dafny {
} else if (proxy is OperationTypeProxy) {
OperationTypeProxy opProxy = (OperationTypeProxy)proxy;
- if (t is IntType || t is SetType || (opProxy.AllowSeq && t is SeqType)) {
+ if (t is IntType || t is SetType || t is MultiSetType || (opProxy.AllowSeq && t is SeqType)) {
// this is the expected case
} else {
return false;
@@ -1302,15 +1304,14 @@ namespace Microsoft.Dafny {
// LHS is fine, provided the "sequence" is really an array
if (lhsResolvedSuccessfully) {
Contract.Assert(slhs.Seq.Type != null);
- Type elementType = new InferredTypeProxy();
- if (!UnifyTypes(slhs.Seq.Type, builtIns.ArrayType(1, elementType))) {
+ if (!UnifyTypes(slhs.Seq.Type, builtIns.ArrayType(1, new InferredTypeProxy()))) {
Error(slhs.Seq, "LHS of array assignment must denote an array element (found {0})", slhs.Seq.Type);
}
if (specContextOnly) {
Error(stmt, "Assignment to array element is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)");
}
- if (!slhs.SelectOne && !(s.Rhs is ExprRhs)) {
- Error(stmt, "Assignment to range of array elements must have a simple expression RHS; try using a temporary local variable");
+ if (!slhs.SelectOne) {
+ Error(stmt, "cannot assign to multiple array elements (try a foreach).");
}
}
@@ -1326,43 +1327,43 @@ namespace Microsoft.Dafny {
s.IsGhost = lvalueIsGhost;
Type lhsType = s.Lhs.Type;
if (lhs is SeqSelectExpr && !((SeqSelectExpr)lhs).SelectOne) {
- Contract.Assert(lhsType.IsArrayType);
- lhsType = UserDefinedType.ArrayElementType(lhsType);
- }
- if (s.Rhs is ExprRhs) {
- ExprRhs rr = (ExprRhs)s.Rhs;
- ResolveExpression(rr.Expr, true);
- if (!lvalueIsGhost) {
- CheckIsNonGhost(rr.Expr);
- }
- Contract.Assert(rr.Expr.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(lhsType, rr.Expr.Type)) {
- Error(stmt, "RHS (of type {0}) not assignable to LHS (of type {1})", rr.Expr.Type, lhsType);
- }
- } else if (s.Rhs is TypeRhs) {
- TypeRhs rr = (TypeRhs)s.Rhs;
- Type t = ResolveTypeRhs(rr, stmt, lvalueIsGhost, method);
- if (!lvalueIsGhost) {
- if (rr.ArrayDimensions != null) {
- foreach (var dim in rr.ArrayDimensions) {
- CheckIsNonGhost(dim);
- }
+ Error(stmt, "cannot assign to multiple array elements (try a foreach).");
+ //lhsType = UserDefinedType.ArrayElementType(lhsType);
+ } else {
+ if (s.Rhs is ExprRhs) {
+ ExprRhs rr = (ExprRhs)s.Rhs;
+ ResolveExpression(rr.Expr, true);
+ if (!lvalueIsGhost) {
+ CheckIsNonGhost(rr.Expr);
}
- if (rr.InitCall != null) {
- foreach (var arg in rr.InitCall.Args) {
- CheckIsNonGhost(arg);
+ Contract.Assert(rr.Expr.Type != null); // follows from postcondition of ResolveExpression
+ if (!UnifyTypes(lhsType, rr.Expr.Type)) {
+ Error(stmt, "RHS (of type {0}) not assignable to LHS (of type {1})", rr.Expr.Type, lhsType);
+ }
+ } else if (s.Rhs is TypeRhs) {
+ TypeRhs rr = (TypeRhs)s.Rhs;
+ Type t = ResolveTypeRhs(rr, stmt, lvalueIsGhost, method);
+ if (!lvalueIsGhost) {
+ if (rr.ArrayDimensions != null) {
+ foreach (var dim in rr.ArrayDimensions) {
+ CheckIsNonGhost(dim);
+ }
+ }
+ if (rr.InitCall != null) {
+ foreach (var arg in rr.InitCall.Args) {
+ CheckIsNonGhost(arg);
+ }
}
}
+ if (!UnifyTypes(lhsType, t)) {
+ Error(stmt, "type {0} is not assignable to LHS (of type {1})", t, lhsType);
+ }
+ } else if (s.Rhs is HavocRhs) {
+ // nothing else to do
+ } else {
+ Contract.Assert(false); throw new cce.UnreachableException(); // unexpected RHS
}
- if (!UnifyTypes(lhsType, t)) {
- Error(stmt, "type {0} is not assignable to LHS (of type {1})", t, lhsType);
- }
- } else if (s.Rhs is HavocRhs) {
- // nothing else to do
- } else {
- Contract.Assert(false); throw new cce.UnreachableException(); // unexpected RHS
}
-
} else if (stmt is VarDecl) {
VarDecl s = (VarDecl)stmt;
if (s.OptionalType != null) {
@@ -2097,6 +2098,8 @@ namespace Microsoft.Dafny {
return type;
} else if (type is SetType) {
return new SetType(arg);
+ } else if (type is MultiSetType) {
+ return new MultiSetType(arg);
} else if (type is SeqType) {
return new SeqType(arg);
} else {
@@ -2301,6 +2304,8 @@ namespace Microsoft.Dafny {
}
if (expr is SetDisplayExpr) {
expr.Type = new SetType(elementType);
+ } else if (expr is MultiSetDisplayExpr) {
+ expr.Type = new MultiSetType(elementType);
} else {
expr.Type = new SeqType(elementType);
}
@@ -2334,7 +2339,7 @@ namespace Microsoft.Dafny {
} else if (expr is SeqSelectExpr) {
SeqSelectExpr e = (SeqSelectExpr)expr;
- ResolveSeqSelectExpr(e, twoState, false);
+ ResolveSeqSelectExpr(e, twoState, true);
} else if (expr is MultiSelectExpr) {
MultiSelectExpr e = (MultiSelectExpr)expr;
@@ -2393,6 +2398,13 @@ namespace Microsoft.Dafny {
ResolveExpression(e.E, twoState);
expr.Type = e.E.Type;
+ } else if (expr is MultiSetFormingExpr) {
+ MultiSetFormingExpr e = (MultiSetFormingExpr)expr;
+ ResolveExpression(e.E, twoState);
+ if (!UnifyTypes(e.E.Type, new SetType(new InferredTypeProxy())) && !UnifyTypes(e.E.Type, new SeqType(new InferredTypeProxy()))) {
+ Error(e.tok, "can only form a multiset from a seq or set.");
+ }
+ expr.Type = new MultiSetType(((CollectionType)e.E.Type).Arg);
} else if (expr is FreshExpr) {
FreshExpr e = (FreshExpr)expr;
if (!twoState) {
@@ -2477,12 +2489,13 @@ namespace Microsoft.Dafny {
break;
case BinaryExpr.Opcode.Disjoint:
- if (!UnifyTypes(e.E0.Type, new SetType(new InferredTypeProxy()))) {
- Error(expr, "arguments must be of a set type (got {0})", e.E0.Type);
- }
+ // TODO: the error messages are backwards from what (ideally) they should be. this is necessary because UnifyTypes can't backtrack.
if (!UnifyTypes(e.E0.Type, e.E1.Type)) {
Error(expr, "arguments must have the same type (got {0} and {1})", e.E0.Type, e.E1.Type);
}
+ if (!UnifyTypes(e.E0.Type, new SetType(new InferredTypeProxy())) && !UnifyTypes(e.E0.Type, new MultiSetType(new InferredTypeProxy()))) {
+ Error(expr, "arguments must be of a [multi]set type (got {0})", e.E0.Type);
+ }
expr.Type = Type.Bool;
break;
@@ -3137,6 +3150,12 @@ namespace Microsoft.Dafny {
goto CHECK_NEXT_BOUND_VARIABLE;
}
break;
+ case BinaryExpr.ResolvedOpcode.InMultiSet:
+ if (whereIsBv == 0) {
+ bounds.Add(new QuantifierExpr.SetBoundedPool(e1));
+ goto CHECK_NEXT_BOUND_VARIABLE;
+ }
+ break;
case BinaryExpr.ResolvedOpcode.InSeq:
if (whereIsBv == 0) {
bounds.Add(new QuantifierExpr.SeqBoundedPool(e1));
@@ -3534,7 +3553,7 @@ namespace Microsoft.Dafny {
if (e.SelectOne) {
e.Type = elementType;
} else {
- e.Type = e.Seq.Type;
+ e.Type = new SeqType(elementType);
}
}
}
@@ -3553,6 +3572,8 @@ namespace Microsoft.Dafny {
case BinaryExpr.Opcode.Eq:
if (operandType is SetType) {
return BinaryExpr.ResolvedOpcode.SetEq;
+ } else if (operandType is MultiSetType) {
+ return BinaryExpr.ResolvedOpcode.MultiSetEq;
} else if (operandType is SeqType) {
return BinaryExpr.ResolvedOpcode.SeqEq;
} else {
@@ -3561,17 +3582,26 @@ namespace Microsoft.Dafny {
case BinaryExpr.Opcode.Neq:
if (operandType is SetType) {
return BinaryExpr.ResolvedOpcode.SetNeq;
+ } else if (operandType is MultiSetType) {
+ return BinaryExpr.ResolvedOpcode.MultiSetNeq;
} else if (operandType is SeqType) {
return BinaryExpr.ResolvedOpcode.SeqNeq;
} else {
return BinaryExpr.ResolvedOpcode.NeqCommon;
}
- case BinaryExpr.Opcode.Disjoint: return BinaryExpr.ResolvedOpcode.Disjoint;
+ case BinaryExpr.Opcode.Disjoint:
+ if (operandType is MultiSetType) {
+ return BinaryExpr.ResolvedOpcode.MultiSetDisjoint;
+ } else {
+ return BinaryExpr.ResolvedOpcode.Disjoint;
+ }
case BinaryExpr.Opcode.Lt:
if (operandType.IsDatatype) {
return BinaryExpr.ResolvedOpcode.RankLt;
} else if (operandType is SetType) {
return BinaryExpr.ResolvedOpcode.ProperSubset;
+ } else if (operandType is MultiSetType) {
+ return BinaryExpr.ResolvedOpcode.ProperMultiSubset;
} else if (operandType is SeqType) {
return BinaryExpr.ResolvedOpcode.ProperPrefix;
} else {
@@ -3580,6 +3610,8 @@ namespace Microsoft.Dafny {
case BinaryExpr.Opcode.Le:
if (operandType is SetType) {
return BinaryExpr.ResolvedOpcode.Subset;
+ } else if (operandType is MultiSetType) {
+ return BinaryExpr.ResolvedOpcode.MultiSubset;
} else if (operandType is SeqType) {
return BinaryExpr.ResolvedOpcode.Prefix;
} else {
@@ -3588,6 +3620,8 @@ namespace Microsoft.Dafny {
case BinaryExpr.Opcode.Add:
if (operandType is SetType) {
return BinaryExpr.ResolvedOpcode.Union;
+ } else if (operandType is MultiSetType) {
+ return BinaryExpr.ResolvedOpcode.MultiSetUnion;
} else if (operandType is SeqType) {
return BinaryExpr.ResolvedOpcode.Concat;
} else {
@@ -3596,12 +3630,16 @@ namespace Microsoft.Dafny {
case BinaryExpr.Opcode.Sub:
if (operandType is SetType) {
return BinaryExpr.ResolvedOpcode.SetDifference;
+ } else if (operandType is MultiSetType) {
+ return BinaryExpr.ResolvedOpcode.MultiSetDifference;
} else {
return BinaryExpr.ResolvedOpcode.Sub;
}
case BinaryExpr.Opcode.Mul:
if (operandType is SetType) {
return BinaryExpr.ResolvedOpcode.Intersection;
+ } else if (operandType is MultiSetType) {
+ return BinaryExpr.ResolvedOpcode.MultiSetIntersection;
} else {
return BinaryExpr.ResolvedOpcode.Mul;
}
@@ -3610,24 +3648,32 @@ namespace Microsoft.Dafny {
return BinaryExpr.ResolvedOpcode.RankGt;
} else if (operandType is SetType) {
return BinaryExpr.ResolvedOpcode.ProperSuperset;
+ } else if (operandType is MultiSetType) {
+ return BinaryExpr.ResolvedOpcode.ProperMultiSuperset;
} else {
return BinaryExpr.ResolvedOpcode.Gt;
}
case BinaryExpr.Opcode.Ge:
if (operandType is SetType) {
return BinaryExpr.ResolvedOpcode.Superset;
+ } else if (operandType is MultiSetType) {
+ return BinaryExpr.ResolvedOpcode.MultiSuperset;
} else {
return BinaryExpr.ResolvedOpcode.Ge;
}
case BinaryExpr.Opcode.In:
if (operandType is SetType) {
return BinaryExpr.ResolvedOpcode.InSet;
+ } else if (operandType is MultiSetType) {
+ return BinaryExpr.ResolvedOpcode.InMultiSet;
} else {
return BinaryExpr.ResolvedOpcode.InSeq;
}
case BinaryExpr.Opcode.NotIn:
if (operandType is SetType) {
return BinaryExpr.ResolvedOpcode.NotInSet;
+ } else if (operandType is MultiSetType) {
+ return BinaryExpr.ResolvedOpcode.NotInMultiSet;
} else {
return BinaryExpr.ResolvedOpcode.NotInSeq;
}
diff --git a/Source/Dafny/Scanner.cs b/Source/Dafny/Scanner.cs
index 37c08ddc..da72d8a1 100644
--- a/Source/Dafny/Scanner.cs
+++ b/Source/Dafny/Scanner.cs
@@ -211,8 +211,8 @@ public class UTF8Buffer: Buffer {
public class Scanner {
const char EOL = '\n';
const int eofSym = 0; /* pdt */
- const int maxT = 104;
- const int noSym = 104;
+ const int maxT = 105;
+ const int noSym = 105;
[ContractInvariantMethod]
@@ -232,7 +232,6 @@ public class Scanner {
Token/*!*/ t; // current token
int ch; // current input character
int pos; // byte position of current character
- int charPos;
int col; // column number of current character
int line; // line number of current character
int oldEols; // EOLs that appeared in a comment;
@@ -440,7 +439,7 @@ public class Scanner {
bool Comment0() {
- int level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos;
+ int level = 1, pos0 = pos, line0 = line, col0 = col;
NextCh();
if (ch == '/') {
NextCh();
@@ -453,13 +452,13 @@ public class Scanner {
else NextCh();
}
} else {
- buffer.Pos = pos0; NextCh(); line = line0; col = col0; charPos = charPos0;
+ buffer.Pos = pos0; NextCh(); line = line0; col = col0;
}
return false;
}
bool Comment1() {
- int level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos;
+ int level = 1, pos0 = pos, line0 = line, col0 = col;
NextCh();
if (ch == '*') {
NextCh();
@@ -480,7 +479,7 @@ public class Scanner {
else NextCh();
}
} else {
- buffer.Pos = pos0; NextCh(); line = line0; col = col0; charPos = charPos0;
+ buffer.Pos = pos0; NextCh(); line = line0; col = col0;
}
return false;
}
@@ -511,36 +510,37 @@ public class Scanner {
case "nat": t.kind = 36; break;
case "int": t.kind = 37; break;
case "set": t.kind = 38; break;
- case "seq": t.kind = 39; break;
- case "object": t.kind = 40; break;
- case "function": t.kind = 41; break;
- case "reads": t.kind = 42; break;
- case "label": t.kind = 45; break;
- case "break": t.kind = 46; break;
- case "return": t.kind = 47; break;
- case "new": t.kind = 49; break;
- case "choose": t.kind = 53; break;
- case "if": t.kind = 54; break;
- case "else": t.kind = 55; break;
- case "case": t.kind = 56; break;
- case "while": t.kind = 58; break;
- case "invariant": t.kind = 59; break;
- case "match": t.kind = 60; break;
- case "foreach": t.kind = 61; break;
- case "in": t.kind = 62; break;
- case "assert": t.kind = 63; break;
- case "assume": t.kind = 64; break;
- case "print": t.kind = 65; break;
- case "false": t.kind = 89; break;
- case "true": t.kind = 90; break;
- case "null": t.kind = 91; break;
- case "this": t.kind = 92; break;
- case "fresh": t.kind = 93; break;
- case "allocated": t.kind = 94; break;
- case "old": t.kind = 95; break;
- case "then": t.kind = 96; break;
- case "forall": t.kind = 98; break;
- case "exists": t.kind = 100; break;
+ case "multiset": t.kind = 39; break;
+ case "seq": t.kind = 40; break;
+ case "object": t.kind = 41; break;
+ case "function": t.kind = 42; break;
+ case "reads": t.kind = 43; break;
+ case "label": t.kind = 46; break;
+ case "break": t.kind = 47; break;
+ case "return": t.kind = 48; break;
+ case "new": t.kind = 50; break;
+ case "choose": t.kind = 54; break;
+ case "if": t.kind = 55; break;
+ case "else": t.kind = 56; break;
+ case "case": t.kind = 57; break;
+ case "while": t.kind = 59; break;
+ case "invariant": t.kind = 60; break;
+ case "match": t.kind = 61; break;
+ case "foreach": t.kind = 62; break;
+ case "in": t.kind = 63; break;
+ case "assert": t.kind = 64; break;
+ case "assume": t.kind = 65; break;
+ case "print": t.kind = 66; break;
+ case "false": t.kind = 90; break;
+ case "true": t.kind = 91; break;
+ case "null": t.kind = 92; break;
+ case "this": t.kind = 93; break;
+ case "fresh": t.kind = 94; break;
+ case "allocated": t.kind = 95; break;
+ case "old": t.kind = 96; break;
+ case "then": t.kind = 97; break;
+ case "forall": t.kind = 99; break;
+ case "exists": t.kind = 101; break;
default: break;
}
}
@@ -654,76 +654,76 @@ public class Scanner {
case 22:
{t.kind = 34; break;}
case 23:
- {t.kind = 43; break;}
- case 24:
{t.kind = 44; break;}
+ case 24:
+ {t.kind = 45; break;}
case 25:
- {t.kind = 48; break;}
+ {t.kind = 49; break;}
case 26:
- {t.kind = 50; break;}
- case 27:
{t.kind = 51; break;}
+ case 27:
+ {t.kind = 52; break;}
case 28:
- {t.kind = 57; break;}
+ {t.kind = 58; break;}
case 29:
if (ch == '>') {AddCh(); goto case 30;}
else {goto case 0;}
case 30:
- {t.kind = 66; break;}
- case 31:
{t.kind = 67; break;}
- case 32:
+ case 31:
{t.kind = 68; break;}
- case 33:
+ case 32:
{t.kind = 69; break;}
+ case 33:
+ {t.kind = 70; break;}
case 34:
if (ch == '&') {AddCh(); goto case 35;}
else {goto case 0;}
case 35:
- {t.kind = 70; break;}
- case 36:
{t.kind = 71; break;}
- case 37:
+ case 36:
{t.kind = 72; break;}
- case 38:
+ case 37:
{t.kind = 73; break;}
+ case 38:
+ {t.kind = 74; break;}
case 39:
- {t.kind = 76; break;}
- case 40:
{t.kind = 77; break;}
- case 41:
+ case 40:
{t.kind = 78; break;}
+ case 41:
+ {t.kind = 79; break;}
case 42:
if (ch == 'n') {AddCh(); goto case 43;}
else {goto case 0;}
case 43:
- {t.kind = 79; break;}
- case 44:
{t.kind = 80; break;}
- case 45:
+ case 44:
{t.kind = 81; break;}
- case 46:
+ case 45:
{t.kind = 82; break;}
- case 47:
+ case 46:
{t.kind = 83; break;}
- case 48:
+ case 47:
{t.kind = 84; break;}
- case 49:
+ case 48:
{t.kind = 85; break;}
- case 50:
+ case 49:
{t.kind = 86; break;}
+ case 50:
+ {t.kind = 87; break;}
case 51:
- {t.kind = 88; break;}
+ {t.kind = 89; break;}
case 52:
- {t.kind = 97; break;}
+ {t.kind = 98; break;}
case 53:
- {t.kind = 99; break;}
+ {t.kind = 100; break;}
case 54:
- {t.kind = 101; break;}
- case 55:
{t.kind = 102; break;}
- case 56:
+ case 55:
{t.kind = 103; break;}
+ case 56:
+ {t.kind = 104; break;}
case 57:
recEnd = pos; recKind = 15;
if (ch == '>') {AddCh(); goto case 28;}
@@ -747,23 +747,23 @@ public class Scanner {
if (ch == '=') {AddCh(); goto case 39;}
else {t.kind = 24; break;}
case 62:
- recEnd = pos; recKind = 52;
+ recEnd = pos; recKind = 53;
if (ch == '.') {AddCh(); goto case 52;}
- else {t.kind = 52; break;}
+ else {t.kind = 53; break;}
case 63:
- recEnd = pos; recKind = 87;
+ recEnd = pos; recKind = 88;
if (ch == '=') {AddCh(); goto case 40;}
else if (ch == '!') {AddCh(); goto case 41;}
else if (ch == 'i') {AddCh(); goto case 42;}
- else {t.kind = 87; break;}
+ else {t.kind = 88; break;}
case 64:
- recEnd = pos; recKind = 74;
+ recEnd = pos; recKind = 75;
if (ch == '>') {AddCh(); goto case 32;}
- else {t.kind = 74; break;}
+ else {t.kind = 75; break;}
case 65:
- recEnd = pos; recKind = 75;
+ recEnd = pos; recKind = 76;
if (ch == '=') {AddCh(); goto case 29;}
- else {t.kind = 75; break;}
+ else {t.kind = 76; break;}
}
t.val = new String(tval, 0, tlen);
diff --git a/Source/Dafny/Translator.cs b/Source/Dafny/Translator.cs
index 74d33479..cc97fb40 100644
--- a/Source/Dafny/Translator.cs
+++ b/Source/Dafny/Translator.cs
@@ -43,6 +43,8 @@ namespace Microsoft.Dafny {
public readonly Bpl.Type BoxType;
public readonly Bpl.Type TickType;
private readonly Bpl.TypeSynonymDecl setTypeCtor;
+ private readonly Bpl.TypeSynonymDecl multiSetTypeCtor;
+ public readonly Bpl.Function ArrayLength;
private readonly Bpl.TypeCtorDecl seqTypeCtor;
readonly Bpl.TypeCtorDecl fieldName;
public readonly Bpl.Type HeapType;
@@ -58,6 +60,8 @@ namespace Microsoft.Dafny {
Contract.Invariant(BoxType != null);
Contract.Invariant(TickType != null);
Contract.Invariant(setTypeCtor != null);
+ Contract.Invariant(multiSetTypeCtor != null);
+ Contract.Invariant(ArrayLength != null);
Contract.Invariant(seqTypeCtor != null);
Contract.Invariant(fieldName != null);
Contract.Invariant(HeapType != null);
@@ -78,6 +82,14 @@ namespace Microsoft.Dafny {
return new Bpl.TypeSynonymAnnotation(Token.NoToken, setTypeCtor, new Bpl.TypeSeq(ty));
}
+ public Bpl.Type MultiSetType(IToken tok, Bpl.Type ty) {
+ Contract.Requires(tok != null);
+ Contract.Requires(ty != null);
+ Contract.Ensures(Contract.Result<Bpl.Type>() != null);
+
+ return new Bpl.TypeSynonymAnnotation(Token.NoToken, multiSetTypeCtor, new Bpl.TypeSeq(ty));
+ }
+
public Bpl.Type SeqType(IToken tok, Bpl.Type ty) {
Contract.Requires(tok != null);
Contract.Requires(ty != null);
@@ -101,7 +113,7 @@ namespace Microsoft.Dafny {
}
public PredefinedDecls(Bpl.TypeCtorDecl refType, Bpl.TypeCtorDecl boxType, Bpl.TypeCtorDecl tickType,
- Bpl.TypeSynonymDecl setTypeCtor, Bpl.TypeCtorDecl seqTypeCtor, Bpl.TypeCtorDecl fieldNameType,
+ Bpl.TypeSynonymDecl setTypeCtor, Bpl.TypeSynonymDecl multiSetTypeCtor, Bpl.Function arrayLength, Bpl.TypeCtorDecl seqTypeCtor, Bpl.TypeCtorDecl fieldNameType,
Bpl.GlobalVariable heap, Bpl.TypeCtorDecl classNameType,
Bpl.TypeCtorDecl datatypeType, Bpl.TypeCtorDecl dtCtorId,
Bpl.Constant allocField) {
@@ -110,6 +122,7 @@ namespace Microsoft.Dafny {
Contract.Requires(boxType != null);
Contract.Requires(tickType != null);
Contract.Requires(setTypeCtor != null);
+ Contract.Requires(multiSetTypeCtor != null);
Contract.Requires(seqTypeCtor != null);
Contract.Requires(fieldNameType != null);
Contract.Requires(heap != null);
@@ -124,6 +137,8 @@ namespace Microsoft.Dafny {
this.BoxType = new Bpl.CtorType(Token.NoToken, boxType, new Bpl.TypeSeq());
this.TickType = new Bpl.CtorType(Token.NoToken, tickType, new Bpl.TypeSeq());
this.setTypeCtor = setTypeCtor;
+ this.multiSetTypeCtor = multiSetTypeCtor;
+ this.ArrayLength = arrayLength;
this.seqTypeCtor = seqTypeCtor;
this.fieldName = fieldNameType;
this.HeapType = heap.TypedIdent.Type;
@@ -145,6 +160,8 @@ namespace Microsoft.Dafny {
Bpl.TypeCtorDecl refType = null;
Bpl.TypeSynonymDecl setTypeCtor = null;
+ Bpl.TypeSynonymDecl multiSetTypeCtor = null;
+ Bpl.Function arrayLength = null;
Bpl.TypeCtorDecl seqTypeCtor = null;
Bpl.TypeCtorDecl fieldNameType = null;
Bpl.TypeCtorDecl classNameType = null;
@@ -154,7 +171,7 @@ namespace Microsoft.Dafny {
Bpl.TypeCtorDecl tickType = null;
Bpl.GlobalVariable heap = null;
Bpl.Constant allocField = null;
- foreach (Bpl.Declaration d in prog.TopLevelDeclarations) {
+ foreach (var d in prog.TopLevelDeclarations) {
if (d is Bpl.TypeCtorDecl) {
Bpl.TypeCtorDecl dt = (Bpl.TypeCtorDecl)d;
if (dt.Name == "Seq") {
@@ -179,6 +196,9 @@ namespace Microsoft.Dafny {
if (dt.Name == "Set") {
setTypeCtor = dt;
}
+ if (dt.Name == "MultiSet") {
+ multiSetTypeCtor = dt;
+ }
} else if (d is Bpl.Constant) {
Bpl.Constant c = (Bpl.Constant)d;
if (c.Name == "alloc") {
@@ -189,12 +209,20 @@ namespace Microsoft.Dafny {
if (v.Name == "$Heap") {
heap = v;
}
+ } else if (d is Bpl.Function) {
+ var f = (Bpl.Function)d;
+ if (f.Name == "array.Length")
+ arrayLength = f;
}
}
if (seqTypeCtor == null) {
Console.WriteLine("Error: Dafny prelude is missing declaration of type Seq");
} else if (setTypeCtor == null) {
Console.WriteLine("Error: Dafny prelude is missing declaration of type Set");
+ } else if (multiSetTypeCtor == null) {
+ Console.WriteLine("Error: Dafny prelude is missing declaration of type MultiSet");
+ } else if (arrayLength == null) {
+ Console.WriteLine("Error: Dafny prelude is missing declaration of function array.Length");
} else if (fieldNameType == null) {
Console.WriteLine("Error: Dafny prelude is missing declaration of type Field");
} else if (classNameType == null) {
@@ -215,7 +243,7 @@ namespace Microsoft.Dafny {
Console.WriteLine("Error: Dafny prelude is missing declaration of constant alloc");
} else {
return new PredefinedDecls(refType, boxType, tickType,
- setTypeCtor, seqTypeCtor, fieldNameType, heap, classNameType, datatypeType, dtCtorId,
+ setTypeCtor, multiSetTypeCtor, arrayLength, seqTypeCtor, fieldNameType, heap, classNameType, datatypeType, dtCtorId,
allocField);
}
return null;
@@ -435,6 +463,20 @@ namespace Microsoft.Dafny {
rhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, rhs);
q = new Bpl.ForallExpr(ctor.tok, bvs, Bpl.Expr.Imp(ante, Bpl.Expr.Lt(lhs, rhs)));
sink.TopLevelDeclarations.Add(new Bpl.Axiom(ctor.tok, q));
+ } else if (arg.Type is MultiSetType) {
+ // axiom (forall params, d: Datatype :: 0 < arg[d] ==> DtRank(d) < DtRank(#dt.ctor(params)));
+ // that is:
+ // axiom (forall params, d: Datatype :: 0 < arg[Box(d)] ==> DtRank(d) < DtRank(#dt.ctor(params)));
+ CreateBoundVariables(ctor.Formals, out bvs, out args);
+ Bpl.Variable dVar = new Bpl.BoundVariable(arg.tok, new Bpl.TypedIdent(arg.tok, "d", predef.DatatypeType));
+ bvs.Add(dVar);
+ Bpl.IdentifierExpr ie = new Bpl.IdentifierExpr(arg.tok, dVar);
+ Bpl.Expr ante = Bpl.Expr.Gt(Bpl.Expr.SelectTok(arg.tok, args[i], FunctionCall(arg.tok, BuiltinFunction.Box, null, ie)), Bpl.Expr.Literal(0));
+ lhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, ie);
+ Bpl.Expr rhs = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);
+ rhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, rhs);
+ q = new Bpl.ForallExpr(ctor.tok, bvs, Bpl.Expr.Imp(ante, Bpl.Expr.Lt(lhs, rhs)));
+ sink.TopLevelDeclarations.Add(new Bpl.Axiom(ctor.tok, q));
}
i++;
}
@@ -474,7 +516,8 @@ namespace Microsoft.Dafny {
sink.TopLevelDeclarations.Add(fc);
} else {
Bpl.Function ff = GetReadonlyField(f);
- sink.TopLevelDeclarations.Add(ff);
+ if (ff != predef.ArrayLength)
+ sink.TopLevelDeclarations.Add(ff);
}
AddAllocationAxiom(f);
@@ -1522,6 +1565,9 @@ namespace Microsoft.Dafny {
} else if (expr is OldExpr) {
OldExpr e = (OldExpr)expr;
return new Bpl.OldExpr(expr.tok, IsTotal(e.E, etran));
+ } else if (expr is MultiSetFormingExpr) {
+ MultiSetFormingExpr e = (MultiSetFormingExpr)expr;
+ return IsTotal(e.E, etran);
} else if (expr is FreshExpr) {
FreshExpr e = (FreshExpr)expr;
return IsTotal(e.E, etran);
@@ -1621,7 +1667,7 @@ namespace Microsoft.Dafny {
}
} else if (expr is SeqSelectExpr) {
SeqSelectExpr e = (SeqSelectExpr)expr;
- bool isSequence = e.Seq.Type is SeqType;
+ //bool isSequence = e.Seq.Type is SeqType;
Bpl.Expr total = CanCallAssumption(e.Seq, etran);
Bpl.Expr seq = etran.TrExpr(e.Seq);
Bpl.Expr e0 = null;
@@ -1667,6 +1713,9 @@ namespace Microsoft.Dafny {
} else if (expr is OldExpr) {
OldExpr e = (OldExpr)expr;
return new Bpl.OldExpr(expr.tok, CanCallAssumption(e.E, etran));
+ } else if (expr is MultiSetFormingExpr) {
+ MultiSetFormingExpr e = (MultiSetFormingExpr)expr;
+ return CanCallAssumption(e.E, etran);
} else if (expr is FreshExpr) {
FreshExpr e = (FreshExpr)expr;
return CanCallAssumption(e.E, etran);
@@ -2003,6 +2052,9 @@ namespace Microsoft.Dafny {
} else if (expr is OldExpr) {
OldExpr e = (OldExpr)expr;
CheckWellformed(e.E, options, locals, builder, etran.Old);
+ } else if (expr is MultiSetFormingExpr) {
+ MultiSetFormingExpr e = (MultiSetFormingExpr)expr;
+ CheckWellformed(e.E, options, locals, builder, etran);
} else if (expr is FreshExpr) {
FreshExpr e = (FreshExpr)expr;
CheckWellformed(e.E, options, locals, builder, etran);
@@ -2355,7 +2407,7 @@ namespace Microsoft.Dafny {
if (a == null) {
return null;
}
- Bpl.Expr t = new Bpl.IdentifierExpr(tok, ct is SetType ? "class.set" : "class.seq", predef.ClassNameType);
+ Bpl.Expr t = new Bpl.IdentifierExpr(tok, ct is SetType ? "class.set" : (ct is SeqType ? "class.seq" : "class.multiset"), predef.ClassNameType); // ^^^ todo: this needs to talk about multisets too.
return FunctionCall(tok, BuiltinFunction.TypeTuple, null, t, a);
} else {
UserDefinedType ct = (UserDefinedType)type;
@@ -2407,6 +2459,10 @@ namespace Microsoft.Dafny {
if (fieldFunctions.TryGetValue(f, out ff)) {
Contract.Assert(ff != null);
} else {
+ if (f.EnclosingClass is ArrayClassDecl && f.Name == "Length") { // link directly to the function in the prelude.
+ fieldFunctions.Add(f, predef.ArrayLength);
+ return predef.ArrayLength;
+ }
// function f(Ref): ty;
Bpl.Type ty = TrType(f.Type);
Bpl.VariableSeq args = new Bpl.VariableSeq();
@@ -2891,6 +2947,8 @@ namespace Microsoft.Dafny {
return predef.DatatypeType;
} else if (type is SetType) {
return predef.SetType(Token.NoToken, predef.BoxType);
+ } else if (type is MultiSetType) {
+ return predef.MultiSetType(Token.NoToken, predef.BoxType);
} else if (type is SeqType) {
return predef.SeqType(Token.NoToken, predef.BoxType);
} else {
@@ -3194,6 +3252,10 @@ namespace Microsoft.Dafny {
Bpl.Expr oInS;
if (s.Collection.Type is SetType) {
oInS = etran.TrInSet(stmt.Tok, o, s.Collection, ((SetType)s.Collection.Type).Arg);
+ } else if (s.Collection.Type is MultiSetType) {
+ // should not be reached.
+ Contract.Assert(false);
+ throw new cce.UnreachableException();
} else {
Bpl.BoundVariable iVar = new Bpl.BoundVariable(stmt.Tok, new Bpl.TypedIdent(stmt.Tok, "$i", Bpl.Type.Int));
Bpl.IdentifierExpr i = new Bpl.IdentifierExpr(stmt.Tok, iVar);
@@ -4017,6 +4079,22 @@ namespace Microsoft.Dafny {
return new Bpl.ForallExpr(tok, new Bpl.VariableSeq(tVar), tr, Bpl.Expr.Imp(xSubT, wh));
}
+ } else if (type is MultiSetType) {
+ MultiSetType st = (MultiSetType)type;
+ // $IsGoodMultiSet(x) && (forall t: BoxType :: { x[t] } 0 < x[t] ==> Unbox(t)-has-the-expected-type)
+ Bpl.BoundVariable tVar = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, "$t#" + otherTmpVarCount, predef.BoxType));
+ otherTmpVarCount++;
+ Bpl.Expr t = new Bpl.IdentifierExpr(tok, tVar);
+ Bpl.Expr xSubT = Bpl.Expr.Gt(Bpl.Expr.SelectTok(tok, x, t), Bpl.Expr.Literal(0));
+ Bpl.Expr unboxT = ExpressionTranslator.ModeledAsBoxType(st.Arg) ? t : FunctionCall(tok, BuiltinFunction.Unbox, TrType(st.Arg), t);
+
+ Bpl.Expr wh = GetWhereClause(tok, unboxT, st.Arg, etran);
+ if (wh != null) {
+ Bpl.Trigger tr = new Bpl.Trigger(tok, true, new Bpl.ExprSeq(xSubT));
+ return Bpl.Expr.And(FunctionCall(tok, BuiltinFunction.IsGoodMultiSet, Bpl.Type.Bool, x),
+ new Bpl.ForallExpr(tok, new Bpl.VariableSeq(tVar), tr, Bpl.Expr.Imp(xSubT, wh)));
+ }
+ return FunctionCall(tok, BuiltinFunction.IsGoodMultiSet, null, x);
} else if (type is SeqType) {
SeqType st = (SeqType)type;
// (forall i: int :: { Seq#Index(x,i) }
@@ -4617,13 +4695,22 @@ namespace Microsoft.Dafny {
}
return s;
+ } else if (expr is MultiSetDisplayExpr) {
+ MultiSetDisplayExpr e = (MultiSetDisplayExpr)expr;
+ Bpl.Expr s = translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetEmpty, predef.BoxType);
+ foreach (Expression ee in e.Elements) {
+ Bpl.Expr ss = BoxIfNecessary(expr.tok, TrExpr(ee), cce.NonNull(ee.Type));
+ s = translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetUnionOne, predef.BoxType, s, ss);
+ }
+ return s;
+
} else if (expr is SeqDisplayExpr) {
SeqDisplayExpr e = (SeqDisplayExpr)expr;
Bpl.Expr s = translator.FunctionCall(expr.tok, BuiltinFunction.SeqEmpty, predef.BoxType);
int i = 0;
foreach (Expression ee in e.Elements) {
- Bpl.Expr ss = BoxIfNecessary(expr.tok, TrExpr(ee), cce.NonNull(ee.Type));
- s = translator.FunctionCall(expr.tok, BuiltinFunction.SeqBuild, predef.BoxType, s, Bpl.Expr.Literal(i), ss, Bpl.Expr.Literal(i+1));
+ Bpl.Expr elt = BoxIfNecessary(expr.tok, TrExpr(ee), cce.NonNull(ee.Type));
+ s = translator.FunctionCall(expr.tok, BuiltinFunction.SeqBuild, predef.BoxType, s, elt);
i++;
}
return s;
@@ -4646,7 +4733,6 @@ namespace Microsoft.Dafny {
Type elmtType;
Contract.Assert(e.Seq.Type != null); // the expression has been successfully resolved
if (e.Seq.Type.IsArrayType) {
- Contract.Assert(e.SelectOne); // resolution enforces that a non-unit array selections is allowed only as an assignment LHS
elmtType = UserDefinedType.ArrayElementType(e.Seq.Type);
} else {
elmtType = ((SeqType)e.Seq.Type).Arg;
@@ -4668,12 +4754,16 @@ namespace Microsoft.Dafny {
}
return x;
} else {
+ if (e.Seq.Type.IsArrayType) {
+ seq = translator.FunctionCall(expr.tok, BuiltinFunction.SeqFromArray, elType, HeapExpr, seq);
+ }
if (e1 != null) {
seq = translator.FunctionCall(expr.tok, BuiltinFunction.SeqTake, elType, seq, e1);
}
if (e0 != null) {
seq = translator.FunctionCall(expr.tok, BuiltinFunction.SeqDrop, elType, seq, e0);
}
+ // if e0 == null && e1 == null, then we have the identity operation seq[..] == seq;
return seq;
}
@@ -4732,6 +4822,17 @@ namespace Microsoft.Dafny {
OldExpr e = (OldExpr)expr;
return new Bpl.OldExpr(expr.tok, TrExpr(e.E));
+ } else if (expr is MultiSetFormingExpr) {
+ MultiSetFormingExpr e = (MultiSetFormingExpr)expr;
+ if (e.E.Type is SetType) {
+ return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetFromSet, translator.TrType(cce.NonNull((SetType)e.E.Type).Arg), TrExpr(e.E));
+ } else if (e.E.Type is SeqType) {
+ return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetFromSeq, translator.TrType(cce.NonNull((SeqType)e.E.Type).Arg), TrExpr(e.E));
+ } else {
+ Contract.Assert(false); throw new cce.UnreachableException();
+ }
+
+
} else if (expr is FreshExpr) {
FreshExpr e = (FreshExpr)expr;
Bpl.Expr oldHeap = new Bpl.OldExpr(expr.tok, HeapExpr);
@@ -4798,6 +4899,11 @@ namespace Microsoft.Dafny {
} else if (e.ResolvedOp == BinaryExpr.ResolvedOpcode.NotInSet) {
Bpl.Expr arg = TrInSet(expr.tok, e0, e.E1, cce.NonNull(e.E0.Type)); // let TrInSet translate e.E1
return Bpl.Expr.Unary(expr.tok, UnaryOperator.Opcode.Not, arg);
+ } else if (e.ResolvedOp == BinaryExpr.ResolvedOpcode.InMultiSet) {
+ return TrInMultiSet(expr.tok, e0, e.E1, cce.NonNull(e.E0.Type)); // let TrInMultiSet translate e.E1
+ } else if (e.ResolvedOp == BinaryExpr.ResolvedOpcode.NotInMultiSet) {
+ Bpl.Expr arg = TrInMultiSet(expr.tok, e0, e.E1, cce.NonNull(e.E0.Type)); // let TrInMultiSet translate e.E1
+ return Bpl.Expr.Unary(expr.tok, UnaryOperator.Opcode.Not, arg);
}
Bpl.Expr e1 = TrExpr(e.E1);
BinaryOperator.Opcode bOpcode;
@@ -4840,7 +4946,9 @@ namespace Microsoft.Dafny {
case BinaryExpr.ResolvedOpcode.SetNeq:
return Bpl.Expr.Unary(expr.tok, UnaryOperator.Opcode.Not, translator.FunctionCall(expr.tok, BuiltinFunction.SetEqual, null, e0, e1));
case BinaryExpr.ResolvedOpcode.ProperSubset:
- return ProperSubset(expr.tok, e0, e1);
+ return Bpl.Expr.Binary(expr.tok, BinaryOperator.Opcode.And,
+ translator.FunctionCall(expr.tok, BuiltinFunction.SetSubset, null, e0, e1),
+ Bpl.Expr.Not(translator.FunctionCall(expr.tok, BuiltinFunction.SetEqual, null, e0, e1)));
case BinaryExpr.ResolvedOpcode.Subset:
return translator.FunctionCall(expr.tok, BuiltinFunction.SetSubset, null, e0, e1);
case BinaryExpr.ResolvedOpcode.Superset:
@@ -4853,12 +4961,43 @@ namespace Microsoft.Dafny {
return translator.FunctionCall(expr.tok, BuiltinFunction.SetDisjoint, null, e0, e1);
case BinaryExpr.ResolvedOpcode.InSet:
Contract.Assert(false); throw new cce.UnreachableException(); // this case handled above
+ case BinaryExpr.ResolvedOpcode.NotInSet:
+ Contract.Assert(false); throw new cce.UnreachableException(); // this case handled above
case BinaryExpr.ResolvedOpcode.Union:
return translator.FunctionCall(expr.tok, BuiltinFunction.SetUnion, translator.TrType(cce.NonNull((SetType)expr.Type).Arg), e0, e1);
case BinaryExpr.ResolvedOpcode.Intersection:
return translator.FunctionCall(expr.tok, BuiltinFunction.SetIntersection, translator.TrType(cce.NonNull((SetType)expr.Type).Arg), e0, e1);
case BinaryExpr.ResolvedOpcode.SetDifference:
return translator.FunctionCall(expr.tok, BuiltinFunction.SetDifference, translator.TrType(cce.NonNull((SetType)expr.Type).Arg), e0, e1);
+
+ case BinaryExpr.ResolvedOpcode.MultiSetEq:
+ return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetEqual, null, e0, e1);
+ case BinaryExpr.ResolvedOpcode.MultiSetNeq:
+ return Bpl.Expr.Unary(expr.tok, UnaryOperator.Opcode.Not, translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetEqual, null, e0, e1));
+ case BinaryExpr.ResolvedOpcode.ProperMultiSubset:
+ return Bpl.Expr.Binary(expr.tok, BinaryOperator.Opcode.And,
+ translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetSubset, null, e0, e1),
+ Bpl.Expr.Not(translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetEqual, null, e0, e1)));
+ case BinaryExpr.ResolvedOpcode.MultiSubset:
+ return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetSubset, null, e0, e1);
+ case BinaryExpr.ResolvedOpcode.MultiSuperset:
+ return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetSubset, null, e1, e0);
+ case BinaryExpr.ResolvedOpcode.ProperMultiSuperset:
+ return Bpl.Expr.Binary(expr.tok, BinaryOperator.Opcode.And,
+ translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetSubset, null, e1, e0),
+ Bpl.Expr.Not(translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetEqual, null, e0, e1)));
+ case BinaryExpr.ResolvedOpcode.MultiSetDisjoint:
+ return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetDisjoint, null, e0, e1);
+ case BinaryExpr.ResolvedOpcode.InMultiSet:
+ Contract.Assert(false); throw new cce.UnreachableException(); // this case handled above
+ case BinaryExpr.ResolvedOpcode.NotInMultiSet:
+ Contract.Assert(false); throw new cce.UnreachableException(); // this case handled above
+ case BinaryExpr.ResolvedOpcode.MultiSetUnion:
+ return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetUnion, translator.TrType(cce.NonNull((MultiSetType)expr.Type).Arg), e0, e1);
+ case BinaryExpr.ResolvedOpcode.MultiSetIntersection:
+ return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetIntersection, translator.TrType(cce.NonNull((MultiSetType)expr.Type).Arg), e0, e1);
+ case BinaryExpr.ResolvedOpcode.MultiSetDifference:
+ return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetDifference, translator.TrType(cce.NonNull((MultiSetType)expr.Type).Arg), e0, e1);
case BinaryExpr.ResolvedOpcode.SeqEq:
return translator.FunctionCall(expr.tok, BuiltinFunction.SeqEqual, null, e0, e1);
@@ -5174,6 +5313,48 @@ namespace Microsoft.Dafny {
return Bpl.Expr.SelectTok(tok, TrExpr(s), BoxIfNecessary(tok, elmt, elmtType));
}
+ /// <summary>
+ /// Translate like 0 < s[Box(elmt)], but try to avoid as many set functions as possible in the
+ /// translation, because such functions can mess up triggering.
+ /// </summary>
+ public Bpl.Expr TrInMultiSet(IToken tok, Bpl.Expr elmt, Expression s, Type elmtType) {
+ Contract.Requires(tok != null);
+ Contract.Requires(elmt != null);
+ Contract.Requires(s != null);
+ Contract.Requires(elmtType != null);
+
+ Contract.Ensures(Contract.Result<Bpl.Expr>() != null);
+
+ if (s is BinaryExpr) {
+ BinaryExpr bin = (BinaryExpr)s;
+ switch (bin.ResolvedOp) {
+ case BinaryExpr.ResolvedOpcode.MultiSetUnion:
+ return Bpl.Expr.Or(TrInMultiSet(tok, elmt, bin.E0, elmtType), TrInMultiSet(tok, elmt, bin.E1, elmtType));
+ case BinaryExpr.ResolvedOpcode.MultiSetIntersection:
+ return Bpl.Expr.And(TrInMultiSet(tok, elmt, bin.E0, elmtType), TrInMultiSet(tok, elmt, bin.E1, elmtType));
+ default:
+ break;
+ }
+ } else if (s is MultiSetDisplayExpr) {
+ MultiSetDisplayExpr disp = (MultiSetDisplayExpr)s;
+ Bpl.Expr disjunction = null;
+ foreach (Expression a in disp.Elements) {
+ Bpl.Expr disjunct = Bpl.Expr.Eq(elmt, TrExpr(a));
+ if (disjunction == null) {
+ disjunction = disjunct;
+ } else {
+ disjunction = Bpl.Expr.Or(disjunction, disjunct);
+ }
+ }
+ if (disjunction == null) {
+ return Bpl.Expr.False;
+ } else {
+ return disjunction;
+ }
+ }
+ return Bpl.Expr.Gt(Bpl.Expr.SelectTok(tok, TrExpr(s), BoxIfNecessary(tok, elmt, elmtType)), Bpl.Expr.Literal(0));
+ }
+
Bpl.QKeyValue TrAttributes(Attributes attrs) {
Bpl.QKeyValue kv = null;
while (attrs != null) {
@@ -5302,6 +5483,18 @@ namespace Microsoft.Dafny {
SetDisjoint,
SetChoose,
+ MultiSetEmpty,
+ MultiSetUnionOne,
+ MultiSetUnion,
+ MultiSetIntersection,
+ MultiSetDifference,
+ MultiSetEqual,
+ MultiSetSubset,
+ MultiSetDisjoint,
+ MultiSetFromSet,
+ MultiSetFromSeq,
+ IsGoodMultiSet,
+
SeqLength,
SeqEmpty,
SeqBuild,
@@ -5313,6 +5506,7 @@ namespace Microsoft.Dafny {
SeqTake,
SeqEqual,
SeqSameUntil,
+ SeqFromArray,
IndexField,
MultiIndexField,
@@ -5387,6 +5581,59 @@ namespace Microsoft.Dafny {
Contract.Assert(typeInstantiation != null);
return FunctionCall(tok, "Set#Choose", typeInstantiation, args);
+
+ case BuiltinFunction.MultiSetEmpty: {
+ Contract.Assert(args.Length == 0);
+ Contract.Assert(typeInstantiation != null);
+ Bpl.Type resultType = predef.MultiSetType(tok, typeInstantiation);
+ return Bpl.Expr.CoerceType(tok, FunctionCall(tok, "MultiSet#Empty", resultType, args), resultType);
+ }
+ case BuiltinFunction.MultiSetUnionOne:
+ Contract.Assert(args.Length == 2);
+ Contract.Assert(typeInstantiation != null);
+ return FunctionCall(tok, "MultiSet#UnionOne", predef.MultiSetType(tok, typeInstantiation), args);
+ case BuiltinFunction.MultiSetUnion:
+ Contract.Assert(args.Length == 2);
+ Contract.Assert(typeInstantiation != null);
+ return FunctionCall(tok, "MultiSet#Union", predef.MultiSetType(tok, typeInstantiation), args);
+ case BuiltinFunction.MultiSetIntersection:
+ Contract.Assert(args.Length == 2);
+ Contract.Assert(typeInstantiation != null);
+ return FunctionCall(tok, "MultiSet#Intersection", predef.MultiSetType(tok, typeInstantiation), args);
+ case BuiltinFunction.MultiSetDifference:
+ Contract.Assert(args.Length == 2);
+ Contract.Assert(typeInstantiation != null);
+ return FunctionCall(tok, "MultiSet#Difference", predef.MultiSetType(tok, typeInstantiation), args);
+ case BuiltinFunction.MultiSetEqual:
+ Contract.Assert(args.Length == 2);
+ Contract.Assert(typeInstantiation == null);
+ return FunctionCall(tok, "MultiSet#Equal", Bpl.Type.Bool, args);
+ case BuiltinFunction.MultiSetSubset:
+ Contract.Assert(args.Length == 2);
+ Contract.Assert(typeInstantiation == null);
+ return FunctionCall(tok, "MultiSet#Subset", Bpl.Type.Bool, args);
+ case BuiltinFunction.MultiSetDisjoint:
+ Contract.Assert(args.Length == 2);
+ Contract.Assert(typeInstantiation == null);
+ return FunctionCall(tok, "MultiSet#Disjoint", Bpl.Type.Bool, args);
+ case BuiltinFunction.MultiSetFromSet:
+ Contract.Assert(args.Length == 1);
+ Contract.Assert(typeInstantiation != null);
+ return FunctionCall(tok, "MultiSet#FromSet", predef.MultiSetType(tok, typeInstantiation), args);
+ case BuiltinFunction.MultiSetFromSeq:
+ Contract.Assert(args.Length == 1);
+ Contract.Assert(typeInstantiation != null);
+ return FunctionCall(tok, "MultiSet#FromSeq", predef.MultiSetType(tok, typeInstantiation), args);
+ case BuiltinFunction.IsGoodMultiSet:
+ Contract.Assert(args.Length == 1);
+ Contract.Assert(typeInstantiation == null);
+ return FunctionCall(tok, "$IsGoodMultiSet", Bpl.Type.Bool, args);
+ // avoiding this for now
+ /*case BuiltinFunction.SetChoose:
+ Contract.Assert(args.Length == 2);
+ Contract.Assert(typeInstantiation != null);
+ return FunctionCall(tok, "Set#Choose", typeInstantiation, args);*/
+
case BuiltinFunction.SeqLength:
Contract.Assert(args.Length == 1);
Contract.Assert(typeInstantiation == null);
@@ -5398,7 +5645,7 @@ namespace Microsoft.Dafny {
return Bpl.Expr.CoerceType(tok, FunctionCall(tok, "Seq#Empty", resultType, args), resultType);
}
case BuiltinFunction.SeqBuild:
- Contract.Assert(args.Length == 4);
+ Contract.Assert(args.Length == 2);
Contract.Assert(typeInstantiation != null);
return FunctionCall(tok, "Seq#Build", predef.SeqType(tok, typeInstantiation), args);
case BuiltinFunction.SeqAppend:
@@ -5433,6 +5680,10 @@ namespace Microsoft.Dafny {
Contract.Assert(args.Length == 3);
Contract.Assert(typeInstantiation == null);
return FunctionCall(tok, "Seq#SameUntil", Bpl.Type.Bool, args);
+ case BuiltinFunction.SeqFromArray:
+ Contract.Assert(args.Length == 2);
+ Contract.Assert(typeInstantiation != null);
+ return FunctionCall(tok, "Seq#FromArray", typeInstantiation, args);
case BuiltinFunction.IndexField:
Contract.Assert(args.Length == 1);
@@ -5920,6 +6171,9 @@ namespace Microsoft.Dafny {
} else if (expr is OldExpr) {
var e = (OldExpr)expr;
return VarOccursInArgumentToRecursiveFunction(e.E, n, p);
+ } else if (expr is MultiSetFormingExpr) {
+ var e = (MultiSetFormingExpr)expr;
+ return VarOccursInArgumentToRecursiveFunction(e.E, n, p);
} else if (expr is FreshExpr) {
var e = (FreshExpr)expr;
return VarOccursInArgumentToRecursiveFunction(e.E, n, null);
@@ -6033,6 +6287,8 @@ namespace Microsoft.Dafny {
if (newElements != e.Elements) {
if (expr is SetDisplayExpr) {
newExpr = new SetDisplayExpr(expr.tok, newElements);
+ } else if (expr is MultiSetDisplayExpr) {
+ newExpr = new MultiSetDisplayExpr(expr.tok, newElements);
} else {
newExpr = new SeqDisplayExpr(expr.tok, newElements);
}
diff --git a/Test/VSI-Benchmarks/Answer b/Test/VSI-Benchmarks/Answer
index 2a4587f4..e2456408 100644
--- a/Test/VSI-Benchmarks/Answer
+++ b/Test/VSI-Benchmarks/Answer
@@ -7,10 +7,6 @@ Dafny program verifier finished with 10 verified, 0 errors
Dafny program verifier finished with 6 verified, 0 errors
--------------------- b3.dfy --------------------
-
-Dafny program verifier finished with 10 verified, 0 errors
-
-------------------- b4.dfy --------------------
Dafny program verifier finished with 11 verified, 0 errors
@@ -22,11 +18,3 @@ Dafny program verifier finished with 22 verified, 0 errors
-------------------- b6.dfy --------------------
Dafny program verifier finished with 21 verified, 0 errors
-
--------------------- b7.dfy --------------------
-
-Dafny program verifier finished with 23 verified, 0 errors
-
--------------------- b8.dfy --------------------
-
-Dafny program verifier finished with 42 verified, 0 errors
diff --git a/Test/VSI-Benchmarks/runtest.bat b/Test/VSI-Benchmarks/runtest.bat
index a733a1c0..799e1d40 100644
--- a/Test/VSI-Benchmarks/runtest.bat
+++ b/Test/VSI-Benchmarks/runtest.bat
@@ -6,7 +6,9 @@ set DAFNY_EXE=%BOOGIEDIR%\Dafny.exe
set BPLEXE=%BOOGIEDIR%\Boogie.exe
set CSC=c:/Windows/Microsoft.NET/Framework/v4.0.30319/csc.exe
-for %%f in (b1.dfy b2.dfy b3.dfy b4.dfy b5.dfy b6.dfy b7.dfy b8.dfy) do (
+REM b3, b7 and b8 need reworking to not use body-less functions and methods.
+
+for %%f in (b1.dfy b2.dfy b4.dfy b5.dfy b6.dfy) do (
echo.
echo -------------------- %%f --------------------
diff --git a/Test/dafny0/AdvancedLHS.dfy b/Test/dafny0/AdvancedLHS.dfy
index cc07cbb5..f1fc7d48 100644
--- a/Test/dafny0/AdvancedLHS.dfy
+++ b/Test/dafny0/AdvancedLHS.dfy
@@ -34,7 +34,6 @@ class C {
if (a != null && 10 <= a.Length) {
a[2] := new C;
- a[4..8] := null;
a[3] := *;
}
if (b != null && 10 <= b.Length0 && 20 <= b.Length1) {
diff --git a/Test/dafny0/Answer b/Test/dafny0/Answer
index 7a972f22..0723bcba 100644
--- a/Test/dafny0/Answer
+++ b/Test/dafny0/Answer
@@ -74,12 +74,14 @@ TypeTests.dfy(58,8): Error: Duplicate local-variable name: x
TypeTests.dfy(61,6): Error: Duplicate local-variable name: y
TypeTests.dfy(68,17): Error: member F in type C does not refer to a method
TypeTests.dfy(69,17): Error: a method called as an initialization method must not have any result arguments
-TypeTests.dfy(78,10): Error: Assignment to range of array elements must have a simple expression RHS; try using a temporary local variable
-TypeTests.dfy(79,10): Error: Assignment to range of array elements must have a simple expression RHS; try using a temporary local variable
+TypeTests.dfy(78,10): Error: cannot assign to multiple array elements (try a foreach).
+TypeTests.dfy(78,10): Error: cannot assign to multiple array elements (try a foreach).
+TypeTests.dfy(79,10): Error: cannot assign to multiple array elements (try a foreach).
+TypeTests.dfy(79,10): Error: cannot assign to multiple array elements (try a foreach).
TypeTests.dfy(85,9): Error: sorry, cannot instantiate type parameter with a subrange type
TypeTests.dfy(86,8): Error: sorry, cannot instantiate 'array' type with a subrange type
TypeTests.dfy(87,8): Error: sorry, cannot instantiate 'array' type with a subrange type
-21 resolution/type errors detected in TypeTests.dfy
+23 resolution/type errors detected in TypeTests.dfy
-------------------- NatTypes.dfy --------------------
NatTypes.dfy(7,5): Error: value assigned to a nat must be non-negative
@@ -102,20 +104,20 @@ NatTypes.dfy(40,14): Error: assertion violation
Execution trace:
(0,0): anon0
(0,0): anon4_Then
-NatTypes.dfy(54,16): Error: assertion violation
+NatTypes.dfy(57,16): Error: assertion violation
Execution trace:
(0,0): anon0
(0,0): anon3_Then
-NatTypes.dfy(68,16): Error: assertion violation
+NatTypes.dfy(71,16): Error: assertion violation
Execution trace:
(0,0): anon0
(0,0): anon5_Else
(0,0): anon6_Then
-NatTypes.dfy(86,19): Error: value assigned to a nat must be non-negative
+NatTypes.dfy(89,19): Error: value assigned to a nat must be non-negative
Execution trace:
(0,0): anon0
(0,0): anon3_Then
-NatTypes.dfy(101,45): Error: value assigned to a nat must be non-negative
+NatTypes.dfy(104,45): Error: value assigned to a nat must be non-negative
Execution trace:
(0,0): anon6_Else
(0,0): anon7_Else
@@ -231,149 +233,167 @@ Execution trace:
Definedness.dfy(50,18): Error: target object may be null
Execution trace:
(0,0): anon0
-Definedness.dfy(55,18): Error: target object may be null
+Definedness.dfy(51,3): Error BP5003: A postcondition might not hold on this return path.
+Definedness.dfy(50,22): Related location: This is the postcondition that might not hold.
Execution trace:
(0,0): anon0
-Definedness.dfy(77,7): Error: target object may be null
+Definedness.dfy(57,18): Error: target object may be null
Execution trace:
(0,0): anon0
-Definedness.dfy(78,5): Error: possible violation of function precondition
+Definedness.dfy(58,3): Error BP5003: A postcondition might not hold on this return path.
+Definedness.dfy(57,22): Related location: This is the postcondition that might not hold.
Execution trace:
(0,0): anon0
-Definedness.dfy(79,10): Error: possible violation of function precondition
+Definedness.dfy(65,3): Error BP5003: A postcondition might not hold on this return path.
+Definedness.dfy(64,22): Related location: This is the postcondition that might not hold.
Execution trace:
(0,0): anon0
-Definedness.dfy(84,14): Error: possible division by zero
+Definedness.dfy(85,7): Error: target object may be null
Execution trace:
(0,0): anon0
-Definedness.dfy(84,23): Error: possible division by zero
+Definedness.dfy(86,5): Error: possible violation of function precondition
Execution trace:
(0,0): anon0
-Definedness.dfy(85,15): Error: possible division by zero
+Definedness.dfy(86,10): Error: assignment may update an object not in the enclosing context's modifies clause
Execution trace:
(0,0): anon0
-Definedness.dfy(90,12): Error: possible division by zero
+Definedness.dfy(86,10): Error: target object may be null
Execution trace:
(0,0): anon0
-Definedness.dfy(97,15): Error: possible division by zero
+Definedness.dfy(87,10): Error: possible violation of function precondition
Execution trace:
(0,0): anon0
- Definedness.dfy(97,5): anon8_LoopHead
+Definedness.dfy(92,14): Error: possible division by zero
+Execution trace:
+ (0,0): anon0
+Definedness.dfy(92,23): Error: possible division by zero
+Execution trace:
+ (0,0): anon0
+Definedness.dfy(93,15): Error: possible division by zero
+Execution trace:
+ (0,0): anon0
+Definedness.dfy(98,12): Error: possible division by zero
+Execution trace:
+ (0,0): anon0
+Definedness.dfy(105,15): Error: possible division by zero
+Execution trace:
+ (0,0): anon0
+ Definedness.dfy(105,5): anon8_LoopHead
(0,0): anon8_LoopBody
- Definedness.dfy(97,5): anon9_Else
+ Definedness.dfy(105,5): anon9_Else
(0,0): anon3
-Definedness.dfy(106,23): Error: possible violation of function precondition
+Definedness.dfy(114,23): Error: possible violation of function precondition
Execution trace:
(0,0): anon0
- Definedness.dfy(105,5): anon13_LoopHead
+ Definedness.dfy(113,5): anon13_LoopHead
(0,0): anon13_LoopBody
(0,0): anon14_Then
-Definedness.dfy(112,17): Error: possible violation of function precondition
+Definedness.dfy(120,17): Error: possible violation of function precondition
Execution trace:
(0,0): anon0
- Definedness.dfy(105,5): anon13_LoopHead
+ Definedness.dfy(113,5): anon13_LoopHead
(0,0): anon13_LoopBody
- Definedness.dfy(105,5): anon14_Else
+ Definedness.dfy(113,5): anon14_Else
(0,0): anon3
(0,0): anon15_Then
(0,0): anon6
- Definedness.dfy(111,5): anon16_LoopHead
+ Definedness.dfy(119,5): anon16_LoopHead
(0,0): anon16_LoopBody
(0,0): anon17_Then
-Definedness.dfy(122,17): Error: possible violation of function precondition
+Definedness.dfy(130,17): Error: possible violation of function precondition
Execution trace:
(0,0): anon0
- Definedness.dfy(121,5): anon7_LoopHead
+ Definedness.dfy(129,5): anon7_LoopHead
(0,0): anon7_LoopBody
(0,0): anon8_Then
-Definedness.dfy(122,22): Error BP5004: This loop invariant might not hold on entry.
+Definedness.dfy(130,22): Error BP5004: This loop invariant might not hold on entry.
Execution trace:
(0,0): anon0
-Definedness.dfy(123,17): Error: possible violation of function precondition
+Definedness.dfy(131,17): Error: possible violation of function precondition
Execution trace:
(0,0): anon0
- Definedness.dfy(121,5): anon7_LoopHead
+ Definedness.dfy(129,5): anon7_LoopHead
(0,0): anon7_LoopBody
(0,0): anon8_Then
-Definedness.dfy(132,15): Error: possible division by zero
+Definedness.dfy(140,15): Error: possible division by zero
Execution trace:
(0,0): anon0
- Definedness.dfy(132,5): anon9_LoopHead
+ Definedness.dfy(140,5): anon9_LoopHead
(0,0): anon9_LoopBody
- Definedness.dfy(132,5): anon10_Else
+ Definedness.dfy(140,5): anon10_Else
(0,0): anon3
-Definedness.dfy(151,15): Error: possible division by zero
+Definedness.dfy(159,15): Error: possible division by zero
Execution trace:
(0,0): anon0
- Definedness.dfy(145,5): anon17_LoopHead
+ Definedness.dfy(153,5): anon17_LoopHead
(0,0): anon17_LoopBody
- Definedness.dfy(145,5): anon18_Else
+ Definedness.dfy(153,5): anon18_Else
(0,0): anon3
(0,0): anon19_Then
(0,0): anon5
(0,0): anon20_Then
(0,0): anon8
- Definedness.dfy(151,5): anon21_LoopHead
+ Definedness.dfy(159,5): anon21_LoopHead
(0,0): anon21_LoopBody
- Definedness.dfy(151,5): anon22_Else
+ Definedness.dfy(159,5): anon22_Else
(0,0): anon11
-Definedness.dfy(170,17): Error: possible violation of function precondition
+Definedness.dfy(172,28): Error BP5004: This loop invariant might not hold on entry.
+Execution trace:
+ (0,0): anon0
+Definedness.dfy(178,17): Error: possible violation of function precondition
Execution trace:
(0,0): anon0
- Definedness.dfy(162,5): anon19_LoopHead
+ Definedness.dfy(170,5): anon19_LoopHead
(0,0): anon19_LoopBody
- Definedness.dfy(162,5): anon20_Else
+ Definedness.dfy(170,5): anon20_Else
(0,0): anon3
(0,0): anon21_Then
(0,0): anon6
- Definedness.dfy(169,5): anon22_LoopHead
+ Definedness.dfy(177,5): anon22_LoopHead
(0,0): anon22_LoopBody
(0,0): anon23_Then
(0,0): anon24_Then
(0,0): anon11
-Definedness.dfy(191,24): Error: possible violation of function precondition
-Execution trace:
- (0,0): anon0
-Definedness.dfy(193,11): Error: foreach assignment may update an object not in the enclosing method's modifies clause
+Definedness.dfy(199,24): Error: possible violation of function precondition
Execution trace:
(0,0): anon0
-Definedness.dfy(195,33): Error: range expression must be well defined
+Definedness.dfy(201,11): Error: foreach assignment may update an object not in the enclosing method's modifies clause
Execution trace:
(0,0): anon0
-Definedness.dfy(201,18): Error: RHS of assignment must be well defined
+Definedness.dfy(203,33): Error: range expression must be well defined
Execution trace:
(0,0): anon0
-Definedness.dfy(210,19): Error: possible division by zero
+Definedness.dfy(218,19): Error: possible division by zero
Execution trace:
(0,0): anon0
- Definedness.dfy(208,5): anon7_LoopHead
+ Definedness.dfy(216,5): anon7_LoopHead
(0,0): anon7_LoopBody
(0,0): anon8_Then
-Definedness.dfy(210,23): Error BP5004: This loop invariant might not hold on entry.
+Definedness.dfy(218,23): Error BP5004: This loop invariant might not hold on entry.
Execution trace:
(0,0): anon0
-Definedness.dfy(210,28): Error: possible division by zero
+Definedness.dfy(218,28): Error: possible division by zero
Execution trace:
(0,0): anon0
- Definedness.dfy(208,5): anon7_LoopHead
+ Definedness.dfy(216,5): anon7_LoopHead
(0,0): anon7_LoopBody
(0,0): anon8_Then
-Definedness.dfy(231,46): Error: possible violation of function postcondition
+Definedness.dfy(239,46): Error: possible violation of function postcondition
Execution trace:
(0,0): anon0
(0,0): anon5_Else
-Definedness.dfy(238,22): Error: target object may be null
+Definedness.dfy(246,22): Error: target object may be null
Execution trace:
(0,0): anon5_Then
(0,0): anon2
(0,0): anon6_Then
-Definedness.dfy(254,24): Error: possible violation of function postcondition
+Definedness.dfy(262,24): Error: possible violation of function postcondition
Execution trace:
(0,0): anon7_Then
(0,0): anon2
(0,0): anon8_Else
-Dafny program verifier finished with 23 verified, 34 errors
+Dafny program verifier finished with 23 verified, 39 errors
-------------------- FunctionSpecifications.dfy --------------------
FunctionSpecifications.dfy(28,13): Error: possible violation of function postcondition
@@ -484,27 +504,24 @@ Execution trace:
(0,0): anon5_Then
(0,0): anon2
(0,0): anon6_Then
-Array.dfy(95,18): Error: assertion violation
-Execution trace:
- (0,0): anon0
-Array.dfy(107,6): Error: insufficient reads clause to read array element
+Array.dfy(97,6): Error: insufficient reads clause to read array element
Execution trace:
(0,0): anon7_Else
(0,0): anon8_Then
(0,0): anon9_Then
-Array.dfy(115,6): Error: insufficient reads clause to read array element
+Array.dfy(105,6): Error: insufficient reads clause to read array element
Execution trace:
(0,0): anon7_Else
(0,0): anon8_Then
(0,0): anon9_Then
-Array.dfy(131,6): Error: assignment may update an array element not in the enclosing context's modifies clause
+Array.dfy(121,6): Error: assignment may update an array element not in the enclosing context's modifies clause
Execution trace:
(0,0): anon0
-Array.dfy(138,6): Error: assignment may update an array element not in the enclosing context's modifies clause
+Array.dfy(128,6): Error: assignment may update an array element not in the enclosing context's modifies clause
Execution trace:
(0,0): anon0
-Dafny program verifier finished with 22 verified, 11 errors
+Dafny program verifier finished with 21 verified, 10 errors
-------------------- MultiDimArray.dfy --------------------
MultiDimArray.dfy(53,21): Error: assertion violation
@@ -812,61 +829,61 @@ Execution trace:
Dafny program verifier finished with 18 verified, 10 errors
-------------------- Termination.dfy --------------------
-Termination.dfy(100,3): Error: cannot prove termination; try supplying a decreases clause for the loop
+Termination.dfy(105,3): Error: cannot prove termination; try supplying a decreases clause for the loop
Execution trace:
(0,0): anon0
- Termination.dfy(100,3): anon7_LoopHead
+ Termination.dfy(105,3): anon7_LoopHead
(0,0): anon7_LoopBody
- Termination.dfy(100,3): anon8_Else
+ Termination.dfy(105,3): anon8_Else
(0,0): anon3
- Termination.dfy(100,3): anon9_Else
+ Termination.dfy(105,3): anon9_Else
(0,0): anon5
-Termination.dfy(108,3): Error: cannot prove termination; try supplying a decreases clause for the loop
+Termination.dfy(113,3): Error: cannot prove termination; try supplying a decreases clause for the loop
Execution trace:
(0,0): anon0
- Termination.dfy(108,3): anon9_LoopHead
+ Termination.dfy(113,3): anon9_LoopHead
(0,0): anon9_LoopBody
- Termination.dfy(108,3): anon10_Else
+ Termination.dfy(113,3): anon10_Else
(0,0): anon11_Then
(0,0): anon5
- Termination.dfy(108,3): anon12_Else
+ Termination.dfy(113,3): anon12_Else
(0,0): anon7
-Termination.dfy(117,3): Error: decreases expression might not decrease
+Termination.dfy(122,3): Error: decreases expression might not decrease
Execution trace:
(0,0): anon0
- Termination.dfy(117,3): anon9_LoopHead
+ Termination.dfy(122,3): anon9_LoopHead
(0,0): anon9_LoopBody
- Termination.dfy(117,3): anon10_Else
+ Termination.dfy(122,3): anon10_Else
(0,0): anon11_Then
(0,0): anon5
- Termination.dfy(117,3): anon12_Else
+ Termination.dfy(122,3): anon12_Else
(0,0): anon7
-Termination.dfy(118,17): Error: decreases expression must be bounded below by 0 at end of loop iteration
+Termination.dfy(123,17): Error: decreases expression must be bounded below by 0 at end of loop iteration
Execution trace:
(0,0): anon0
- Termination.dfy(117,3): anon9_LoopHead
+ Termination.dfy(122,3): anon9_LoopHead
(0,0): anon9_LoopBody
- Termination.dfy(117,3): anon10_Else
+ Termination.dfy(122,3): anon10_Else
(0,0): anon11_Then
(0,0): anon5
- Termination.dfy(117,3): anon12_Else
+ Termination.dfy(122,3): anon12_Else
(0,0): anon7
-Termination.dfy(246,35): Error: cannot prove termination; try supplying a decreases clause
+Termination.dfy(251,35): Error: cannot prove termination; try supplying a decreases clause
Execution trace:
(0,0): anon6_Else
(0,0): anon7_Else
(0,0): anon8_Then
-Termination.dfy(286,3): Error: decreases expression might not decrease
+Termination.dfy(291,3): Error: decreases expression might not decrease
Execution trace:
(0,0): anon0
- Termination.dfy(286,3): anon10_LoopHead
+ Termination.dfy(291,3): anon10_LoopHead
(0,0): anon10_LoopBody
- Termination.dfy(286,3): anon11_Else
- Termination.dfy(286,3): anon12_Else
+ Termination.dfy(291,3): anon11_Else
+ Termination.dfy(291,3): anon12_Else
(0,0): anon13_Else
(0,0): anon8
-Dafny program verifier finished with 44 verified, 6 errors
+Dafny program verifier finished with 45 verified, 6 errors
-------------------- DTypes.dfy --------------------
DTypes.dfy(15,14): Error: assertion violation
@@ -898,46 +915,46 @@ Execution trace:
Dafny program verifier finished with 27 verified, 6 errors
-------------------- TypeParameters.dfy --------------------
-TypeParameters.dfy(41,22): Error: assertion violation
+TypeParameters.dfy(44,22): Error: assertion violation
Execution trace:
(0,0): anon0
-TypeParameters.dfy(63,27): Error: assertion violation
+TypeParameters.dfy(66,27): Error: assertion violation
Execution trace:
(0,0): anon0
(0,0): anon3_Then
(0,0): anon2
-TypeParameters.dfy(130,12): Error: assertion violation
-TypeParameters.dfy(130,28): Related location: Related location
+TypeParameters.dfy(138,12): Error: assertion violation
+TypeParameters.dfy(138,28): Related location: Related location
Execution trace:
(0,0): anon0
(0,0): anon14_Then
- TypeParameters.dfy(130,32): anon15_Else
+ TypeParameters.dfy(138,32): anon15_Else
(0,0): anon5
-TypeParameters.dfy(132,12): Error: assertion violation
-TypeParameters.dfy(132,33): Related location: Related location
+TypeParameters.dfy(140,12): Error: assertion violation
+TypeParameters.dfy(140,33): Related location: Related location
Execution trace:
(0,0): anon0
(0,0): anon17_Then
- TypeParameters.dfy(132,37): anon18_Else
+ TypeParameters.dfy(140,37): anon18_Else
(0,0): anon11
-TypeParameters.dfy(146,15): Error BP5005: This loop invariant might not be maintained by the loop.
-TypeParameters.dfy(146,38): Related location: Related location
+TypeParameters.dfy(154,15): Error BP5005: This loop invariant might not be maintained by the loop.
+TypeParameters.dfy(154,38): Related location: Related location
Execution trace:
(0,0): anon0
- TypeParameters.dfy(139,3): anon17_LoopHead
+ TypeParameters.dfy(147,3): anon17_LoopHead
(0,0): anon17_LoopBody
- TypeParameters.dfy(139,3): anon18_Else
+ TypeParameters.dfy(147,3): anon18_Else
(0,0): anon5
(0,0): anon20_Then
(0,0): anon8
- TypeParameters.dfy(145,3): anon21_LoopHead
+ TypeParameters.dfy(153,3): anon21_LoopHead
(0,0): anon21_LoopBody
- TypeParameters.dfy(145,3): anon22_Else
+ TypeParameters.dfy(153,3): anon22_Else
(0,0): anon13
- TypeParameters.dfy(145,3): anon24_Else
+ TypeParameters.dfy(153,3): anon24_Else
(0,0): anon15
-Dafny program verifier finished with 33 verified, 5 errors
+Dafny program verifier finished with 35 verified, 5 errors
-------------------- Datatypes.dfy --------------------
Datatypes.dfy(79,20): Error: assertion violation
@@ -1108,3 +1125,7 @@ Dafny program verifier finished with 6 verified, 0 errors
CallStmtTests.dfy(4,3): Error: LHS of assignment must denote a mutable variable
CallStmtTests.dfy(15,8): Error: actual out-parameter 0 is required to be a ghost variable
2 resolution/type errors detected in CallStmtTests.dfy
+
+-------------------- MultiSets.dfy --------------------
+
+Dafny program verifier finished with 22 verified, 0 errors
diff --git a/Test/dafny0/Array.dfy b/Test/dafny0/Array.dfy
index 60854f63..f667e699 100644
--- a/Test/dafny0/Array.dfy
+++ b/Test/dafny0/Array.dfy
@@ -72,27 +72,17 @@ class A {
}
method Q() {
- var y := new object[100];
- y[5] := null;
- y[0..] := null;
- y[..83] := null;
- y[0..y.Length] := null;
- }
-
- method R() {
- var y := new int[100];
- y[55] := 80;
- y[10..] := 25;
- y[..83] := 30;
- y[50..60] := 35;
- y[55] := 90;
-
- assert y[54] == 35;
- assert y[55] == 90;
- assert y[83] == 25;
- assert y[8] == 30;
- assert y[90] + y[91] + y[0] + 20 == y.Length;
- assert y[93] == 24; // error (it's 25)
+ var a := new int[5];
+ a[0],a[1],a[2],a[3],a[4] := 0,1,2,3,4;
+
+ assert [1,2,3,4] == a[1..];
+ assert [1,2,3,4] == a[1.. a.Length];
+ assert [1] == a[1..2];
+ assert [0,1] == a[..2];
+ assert [0,1] == a[0..2];
+ assert forall i :: 0 <= i <= a.Length ==> [] == a[i..i];
+ assert [0,1,2,3,4] == a[..];
+ assert forall i :: 0 <= i < a.Length ==> a[i] == i;
}
}
diff --git a/Test/dafny0/Definedness.dfy b/Test/dafny0/Definedness.dfy
index 2063eec4..44b54f3d 100644
--- a/Test/dafny0/Definedness.dfy
+++ b/Test/dafny0/Definedness.dfy
@@ -48,27 +48,35 @@ class SoWellformed {
requires next != null;
modifies this;
ensures next.xyz < 100; // error: may not be well-defined (if body sets next to null)
+ {
+ }
method Q(a: SoWellformed, s: set<SoWellformed>) returns (c: bool, d: SoWellformed)
requires next != null;
modifies s;
ensures next.xyz < 100; // error: may not be well-defined (if this in s and body sets next to null)
-
+ {
+
+ }
method R(a: SoWellformed, s: set<SoWellformed>) returns (c: bool, d: SoWellformed)
requires next != null && this !in s;
modifies s;
ensures next.xyz < 100; // fine
+ {
+
+ }
}
// ---------------------- welldefinedness checks for statements -------------------
class StatementTwoShoes {
var x: int;
-
+ var s: StatementTwoShoes;
function method F(b: int): StatementTwoShoes
requires 0 <= b;
+ reads this;
{
- this
+ s
}
method M(p: StatementTwoShoes, a: int)
@@ -175,7 +183,7 @@ class StatementTwoShoes {
}
function G(w: int): int { 5 }
- function method H(x: int): int
+ function method H(x: int): int { -x }
method V(s: set<StatementTwoShoes>, a: int, b: int)
modifies s;
diff --git a/Test/dafny0/MultiSets.dfy b/Test/dafny0/MultiSets.dfy
new file mode 100644
index 00000000..0bc1004f
--- /dev/null
+++ b/Test/dafny0/MultiSets.dfy
@@ -0,0 +1,103 @@
+
+method test1()
+{
+ var ms: multiset<int> := multiset{1,1,1};
+ var ms2: multiset<int> := multiset{3};
+ assert 1 in ms;
+ assert forall i :: i != 1 ==> i !in ms; // 1 is the only thing in ms.
+
+ assert ((ms - multiset{1}) - multiset {1}) != multiset{}; // it has more than 2 ones
+ assert ((ms - multiset{1}) - multiset {1}) - multiset{1} == multiset{}; // and exactly three
+
+ assert ms2 - ms == ms2; // set difference works correctly.
+ assert ms - multiset{1} == multiset{1,1};
+ assert !(multiset{1} !! multiset{1});
+ assert exists m :: !(m !! multiset{1});
+ assert forall m :: m !! multiset{};
+
+ assert forall s :: (s == set x: int | x in ms :: x) ==> s == {1};
+}
+
+method test2(ms: multiset<int>)
+{
+ var s := set x | x in ms :: x; // seems to be a reasonable conversion
+ assert forall x :: x in s <==> x in ms;
+ assert ms !! multiset{};
+}
+
+method test3(s: set<int>)
+{
+ assert forall x :: x in s <==> x in multiset(s);
+}
+method test4(sq: seq<int>, a: array<int>)
+ requires a != null;
+ modifies a;
+{
+ assert sq == sq[..|sq|];
+ assert sq == sq[0..];
+ assert sq == sq[..];
+
+ assert a.Length >= 0;
+ var s := a[..];
+}
+
+method test5()
+{
+ assert multiset({1,1}) == multiset{1};
+ assert multiset([1,1]) == multiset{1,1};
+}
+
+method test6(a: array<int>, n: int, e: int)
+ requires a != null && 0 <= n < a.Length;
+ modifies a;
+ ensures multiset(a[..n+1]) == multiset(a[..n]) + multiset{e};
+{
+ a[n] := e;
+ assert a[..n+1] == a[..n] + [e];
+}
+method test7(a: array<int>, i: int, j: int)
+ requires a != null && 0 <= i < j < a.Length;
+ modifies a;
+ ensures old(multiset(a[..])) == multiset(a[..]);
+ ensures a[j] == old (a[i]) && a[i] == old(a[j]);
+ ensures forall k :: 0 <= k < a.Length && k !in {i, j} ==> a[k] == old(a[k]);
+{
+ ghost var s := a[..i] + [a[i]] + a[i+1 .. j] + [a[j]] + a[j+1..];
+ assert a[..] == s;
+ a[i], a[j] := a[j], a[i];
+ assert a[..] == a[..i] + [a[i]] + a[i+1 .. j] + [a[j]] + a[j+1..];
+ assert s == a[..i] + [old(a[i])] + a[i+1 .. j] + [old(a[j])] + a[j+1..];
+}
+method test8(a: array<int>, i: int, j: int)
+ requires a != null && 0 <= i < j < a.Length;
+ modifies a;
+ ensures old(multiset(a[..])) == multiset(a[..]);
+ ensures a[j] == old (a[i]) && a[i] == old(a[j]);
+ ensures forall k :: 0 <= k < a.Length && k !in {i, j} ==> a[k] == old(a[k]);
+{
+ a[i], a[j] := a[j], a[i];
+}
+method test9(a: array<int>, i: int, j: int, limit: int)
+ requires a != null && 0 <= i < j < limit <= a.Length;
+ modifies a;
+ ensures old(multiset(a[0..limit])) == multiset(a[0..limit]);
+ ensures a[j] == old (a[i]) && a[i] == old(a[j]);
+ ensures forall k :: 0 <= k < limit && k !in {i, j} ==> a[k] == old(a[k]);
+{
+ a[i], a[j] := a[j], a[i];
+}
+method test10(s: seq<int>)
+ requires |s| > 4;
+{
+ assert multiset( s[3 := 2] ) == multiset(s) - multiset{s[3]} + multiset{2};
+ assert multiset( (s[2 := 1])[3 := 2] ) == (((multiset(s) - multiset{s[2]}) + multiset{1}) - multiset{s[3]}) + multiset{2};
+ assert multiset( (s[2 := s[3]])[3 := s[2]] ) == (((multiset(s) - multiset{s[2]}) + multiset{s[3]}) - multiset{s[3]}) + multiset{s[2]};
+}
+
+method test11(a: array<int>, n: int, c: int)
+ requires a != null && 0 <= c < n <= a.Length;
+ modifies a;
+ ensures multiset(a[c..n-1]) == multiset(a[c..n]) - multiset{a[n-1]};
+{
+
+} \ No newline at end of file
diff --git a/Test/dafny0/NatTypes.dfy b/Test/dafny0/NatTypes.dfy
index e56b4122..47bc22e1 100644
--- a/Test/dafny0/NatTypes.dfy
+++ b/Test/dafny0/NatTypes.dfy
@@ -43,6 +43,9 @@ method Generic<T>(i: int, t0: T, t1: T) returns (r: T) {
}
function method FenEric<T>(t0: T, t1: T): T
+{
+ t1
+}
datatype Pair<T> = Pr(T, T);
diff --git a/Test/dafny0/Termination.dfy b/Test/dafny0/Termination.dfy
index f31935af..1482dc24 100644
--- a/Test/dafny0/Termination.dfy
+++ b/Test/dafny0/Termination.dfy
@@ -90,6 +90,11 @@ class Termination {
method Traverse<T>(a: List<T>) returns (val: T, b: List<T>)
requires a != List.Nil;
ensures a == List.Cons(val, b);
+ {
+ match a {
+ case Cons(v, r) => val := v; b := r;
+ }
+ }
}
datatype List<T> = Nil | Cons(T, List<T>);
diff --git a/Test/dafny0/TypeAntecedents.dfy b/Test/dafny0/TypeAntecedents.dfy
index 710e9838..5982a9e6 100644
--- a/Test/dafny0/TypeAntecedents.dfy
+++ b/Test/dafny0/TypeAntecedents.dfy
@@ -87,8 +87,8 @@ method N() returns (k: MyClass)
{
k := new MyClass;
}
-
-function NF(): MyClass
+var a: MyClass;
+function NF(): MyClass reads this; { a }
function TakesADatatype(a: List): int { 12 }
diff --git a/Test/dafny0/TypeParameters.dfy b/Test/dafny0/TypeParameters.dfy
index 8f3f8b87..d6804661 100644
--- a/Test/dafny0/TypeParameters.dfy
+++ b/Test/dafny0/TypeParameters.dfy
@@ -14,10 +14,13 @@ class C<U> {
{
var t := F(3,u) && F(this,u);
var kz := M(t,u);
- assert kz && (G() || !G());
+ var a := G();
+ assert kz && (a || !a);
+ }
+ method G<Y>() returns (a: Y)
+ {
+
}
-
- function G<Y>(): Y
}
class SetTest {
@@ -101,6 +104,9 @@ class CClient {
static function IsCelebrity<Person>(c: Person, people: set<Person>): bool
requires c == c || c in people;
+{
+ false
+}
method FindCelebrity3(people: set<int>, ghost c: int)
requires IsCelebrity(c, people); // once upon a time, this caused the translator to produce bad Boogie
@@ -112,7 +118,9 @@ method FindCelebrity3(people: set<int>, ghost c: int)
static function F(c: int, people: set<int>): bool
requires IsCelebrity(c, people);
-
+{
+ false
+}
function RogerThat<G>(g: G): G
{
g
@@ -154,7 +162,14 @@ method LoopyRoger(n: int)
class TyKn_C<T> {
var x: T;
function G(): T
+ reads this;
+ {
+ x
+ }
method M() returns (t: T)
+ {
+
+ }
}
class TyKn_K {
diff --git a/Test/dafny0/runtest.bat b/Test/dafny0/runtest.bat
index 7aa1b38e..8aaa143b 100644
--- a/Test/dafny0/runtest.bat
+++ b/Test/dafny0/runtest.bat
@@ -20,7 +20,7 @@ for %%f in (TypeTests.dfy NatTypes.dfy SmallTests.dfy Definedness.dfy
TypeParameters.dfy Datatypes.dfy TypeAntecedents.dfy SplitExpr.dfy
Refinement.dfy RefinementErrors.dfy LoopModifies.dfy
ReturnErrors.dfy ReturnTests.dfy ChainingDisjointTests.dfy
- CallStmtTests.dfy) do (
+ CallStmtTests.dfy MultiSets.dfy) do (
echo.
echo -------------------- %%f --------------------
%DAFNY_EXE% /compile:0 %* %%f
diff --git a/Test/dafny1/Answer b/Test/dafny1/Answer
index 5ee9f921..5bb746d8 100644
--- a/Test/dafny1/Answer
+++ b/Test/dafny1/Answer
@@ -85,12 +85,12 @@ Dafny program verifier finished with 29 verified, 0 errors
-------------------- Rippling.dfy --------------------
-Dafny program verifier finished with 132 verified, 0 errors
+Dafny program verifier finished with 122 verified, 0 errors
-------------------- Celebrity.dfy --------------------
-Dafny program verifier finished with 10 verified, 0 errors
+Dafny program verifier finished with 8 verified, 0 errors
-------------------- UltraFilter.dfy --------------------
-Dafny program verifier finished with 19 verified, 0 errors
+Dafny program verifier finished with 20 verified, 0 errors
diff --git a/Test/dafny1/Celebrity.dfy b/Test/dafny1/Celebrity.dfy
index 21b895aa..a10c4324 100644
--- a/Test/dafny1/Celebrity.dfy
+++ b/Test/dafny1/Celebrity.dfy
@@ -1,15 +1,26 @@
// Celebrity example, inspired by the Rodin tutorial
-static function method Knows<Person>(a: Person, b: Person): bool
- requires a != b; // forbid asking about the reflexive case
+class Person
+{
+
+}
+
+var pa: seq<Person>;
-static function IsCelebrity<Person>(c: Person, people: set<Person>): bool
+function method Knows(a: Person, b: Person): bool
+ reads this;
+ requires a != b; // forbid asking about the reflexive case
+{
+ exists i | 0 <= i && i < |pa| :: 0 <= i < |pa| / 2 ==> pa[2*i] == a && pa[2*i+1] == b
+}
+function IsCelebrity(c: Person, people: set<Person>): bool
+ reads this;
{
c in people &&
(forall p :: p in people && p != c ==> Knows(p, c) && !Knows(c, p))
}
-method FindCelebrity0<Person>(people: set<Person>, ghost c: Person) returns (r: Person)
+method FindCelebrity0(people: set<Person>, ghost c: Person) returns (r: Person)
requires (exists c :: IsCelebrity(c, people));
ensures r == c;
{
@@ -17,7 +28,7 @@ method FindCelebrity0<Person>(people: set<Person>, ghost c: Person) returns (r:
r := cc;
}
-method FindCelebrity1<Person>(people: set<Person>, ghost c: Person) returns (r: Person)
+method FindCelebrity1(people: set<Person>, ghost c: Person) returns (r: Person)
requires IsCelebrity(c, people);
ensures r == c;
{
@@ -40,7 +51,7 @@ method FindCelebrity1<Person>(people: set<Person>, ghost c: Person) returns (r:
r := x;
}
-method FindCelebrity2<Person>(people: set<Person>, ghost c: Person) returns (r: Person)
+method FindCelebrity2(people: set<Person>, ghost c: Person) returns (r: Person)
requires IsCelebrity(c, people);
ensures r == c;
{
@@ -64,7 +75,7 @@ method FindCelebrity2<Person>(people: set<Person>, ghost c: Person) returns (r:
}
r := b;
}
-
+/*
method FindCelebrity3(n: int, people: set<int>, ghost c: int) returns (r: int)
requires 0 < n;
requires (forall p :: p in people <==> 0 <= p && p < n);
@@ -88,3 +99,4 @@ method FindCelebrity3(n: int, people: set<int>, ghost c: int) returns (r: int)
}
r := b;
}
+*/ \ No newline at end of file
diff --git a/Test/dafny1/Rippling.dfy b/Test/dafny1/Rippling.dfy
index 0a4d541d..78905b6e 100644
--- a/Test/dafny1/Rippling.dfy
+++ b/Test/dafny1/Rippling.dfy
@@ -157,13 +157,14 @@ function last(xs: List): Nat
case Cons(z, zs) => last(ys)
}
+/*
function mapF(xs: List): List
{
match xs
case Nil => Nil
case Cons(y, ys) => Cons(HardcodedUninterpretedFunction(y), mapF(ys))
}
-function HardcodedUninterpretedFunction(n: Nat): Nat
+function HardcodedUninterpretedFunction(n: Nat): Nat*/
function takeWhileAlways(hardcodedResultOfP: Bool, xs: List): List
{
@@ -186,7 +187,7 @@ function dropWhileAlways(hardcodedResultOfP: Bool, xs: List): List
else Cons(y, ys)
}
-function filterP(xs: List): List
+/*function filterP(xs: List): List
{
match xs
case Nil => Nil
@@ -195,7 +196,7 @@ function filterP(xs: List): List
then Cons(y, filterP(ys))
else filterP(ys)
}
-function HardcodedUninterpretedPredicate(n: Nat): Bool
+function HardcodedUninterpretedPredicate(n: Nat): Bool*/
function insort(n: Nat, xs: List): List
{
@@ -327,21 +328,22 @@ ghost method P11()
{
}
+/*
ghost method P12()
ensures (forall n, xs :: drop(n, mapF(xs)) == mapF(drop(n, xs)));
{
-}
+}*/
ghost method P13()
ensures (forall n, x, xs :: drop(Suc(n), Cons(x, xs)) == drop(n, xs));
{
}
-
+/*
ghost method P14()
ensures (forall xs, ys :: filterP(concat(xs, ys)) == concat(filterP(xs), filterP(ys)));
{
}
-
+*/
ghost method P15()
ensures (forall x, xs :: len(ins(x, xs)) == Suc(len(xs)));
{
@@ -478,12 +480,12 @@ ghost method P40()
ensures (forall xs :: take(Zero, xs) == Nil);
{
}
-
+/*
ghost method P41()
ensures (forall n, xs :: take(n, mapF(xs)) == mapF(take(n, xs)));
{
}
-
+*/
ghost method P42()
ensures (forall n, x, xs :: take(Suc(n), Cons(x, xs)) == Cons(x, take(n, xs)));
{
diff --git a/Test/dafny1/UltraFilter.dfy b/Test/dafny1/UltraFilter.dfy
index c8419890..0dfb6683 100644
--- a/Test/dafny1/UltraFilter.dfy
+++ b/Test/dafny1/UltraFilter.dfy
@@ -31,6 +31,9 @@ class UltraFilter<G> {
// Dafny currently does not have a set comprehension expression, so this method stub will have to do
method H(f: set<set<G>>, S: set<G>, M: set<G>) returns (h: set<set<G>>)
ensures (forall X :: X in h <==> M + X in f);
+ {
+ assume false;
+ }
method Lemma_HIsFilter(h: set<set<G>>, f: set<set<G>>, S: set<G>, M: set<G>)
requires IsFilter(f, S);
diff --git a/Test/sanity/Answer b/Test/sanity/Answer
index 98607529..41d2f18c 100644
--- a/Test/sanity/Answer
+++ b/Test/sanity/Answer
@@ -1,4 +1,4 @@
Boogie program verifier finished with 1 verified, 0 errors
-Dafny program verifier finished with 10 verified, 0 errors
+Dafny program verifier finished with 8 verified, 0 errors
diff --git a/Util/VS2010/Dafny/DafnyLanguageService/Grammar.cs b/Util/VS2010/Dafny/DafnyLanguageService/Grammar.cs
index 73c3891d..0cd95bbd 100644
--- a/Util/VS2010/Dafny/DafnyLanguageService/Grammar.cs
+++ b/Util/VS2010/Dafny/DafnyLanguageService/Grammar.cs
@@ -25,7 +25,7 @@ namespace Demo
"bool", "nat", "int", "false", "true", "null",
"function", "free",
"in", "forall", "exists",
- "seq", "set", "array", "array2", "array3",
+ "seq", "set", "multiset", "array", "array2", "array3",
"match", "case",
"fresh", "allocated", "old", "choose"
);
@@ -308,6 +308,7 @@ namespace Demo
| "exists"
| "seq"
| "set"
+ | "multiset"
| "array"
| "array2"
| "array3"