From ea068f2bddb4be2eb4827f75418f46f52fd3a1f9 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Fri, 17 Apr 2015 11:55:39 -0600 Subject: Added the fp32 class, copied from the previously existing BigDec class. No significant changes from BigDec have been made --- Binaries/Boogie.vshost.exe.manifest | 11 + Source/Basetypes/Basetypes.csproj | 7 +- Source/Basetypes/fp32.cs | 397 ++++++++++++++++++++++++++++++++++++ Test/z3api/bar1.bpl | 2 +- 4 files changed, 413 insertions(+), 4 deletions(-) create mode 100644 Binaries/Boogie.vshost.exe.manifest create mode 100644 Source/Basetypes/fp32.cs diff --git a/Binaries/Boogie.vshost.exe.manifest b/Binaries/Boogie.vshost.exe.manifest new file mode 100644 index 00000000..061c9ca9 --- /dev/null +++ b/Binaries/Boogie.vshost.exe.manifest @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Source/Basetypes/Basetypes.csproj b/Source/Basetypes/Basetypes.csproj index 8e6310e6..fea8eebc 100644 --- a/Source/Basetypes/Basetypes.csproj +++ b/Source/Basetypes/Basetypes.csproj @@ -1,4 +1,4 @@ - + Debug @@ -34,7 +34,7 @@ false false true - Client + Client true @@ -163,6 +163,7 @@ + @@ -200,4 +201,4 @@ --> - + \ No newline at end of file diff --git a/Source/Basetypes/fp32.cs b/Source/Basetypes/fp32.cs new file mode 100644 index 00000000..c64afa54 --- /dev/null +++ b/Source/Basetypes/fp32.cs @@ -0,0 +1,397 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Diagnostics.Contracts; +using System.Diagnostics; + +namespace Basetypes +{ + using BIM = System.Numerics.BigInteger; + + /// + /// A representation of a 32-bit floating point value + /// Note that this value has a 1-bit sign, 8-bit exponent, and 23-bit mantissa + /// + public struct fp32 + { + //Please note that this code outline is copy-pasted from BigDec.cs + + // the internal representation + [Rep] + internal readonly BIM mantissa; //TODO: restrict mantissa to be 23-bits wide + [Rep] + internal readonly int exponent; //TODO: restrict exponent to be 8-bits wide + [Rep] + internal readonly Boolean isNegative; //represents the sign bit + + public BIM Mantissa { + get { + return mantissa; + } + } + + public int Exponent { + get { + return exponent; + } + } + + public static readonly fp32 ZERO = FromInt(0); + private static readonly BIM two = new BIM(2); + private static readonly BIM ten = new BIM(10); + + + //////////////////////////////////////////////////////////////////////////// + // Constructors + + //Please note that these constructors will be called throughout boogie + //For a complete summary of where this class has been added, simply view constructor references + + [Pure] + public static fp32 FromInt(int v) { + return new fp32(v, 0, v < 0); //TODO: modify for correct fp representation + } + + [Pure] + public static fp32 FromBigInt(BIM v) { + return new fp32(v, 0, v < 0); //TODO: modify for correct fp representation + } + + [Pure] + public static fp32 FromString(string v) { + //TODO: completely copied from BigDec.cs at the moment + if (v == null) throw new FormatException(); + + BIM integral = BIM.Zero; + BIM fraction = BIM.Zero; + int exponent = 0; + + int len = v.Length; + + int i = v.IndexOf('e'); + if (i >= 0) { + if (i + 1 == v.Length) throw new FormatException(); + exponent = Int32.Parse(v.Substring(i + 1, len - i - 1)); + len = i; + } + + int fractionLen = 0; + i = v.IndexOf('.'); + if (i >= 0) { + if (i + 1 == v.Length) throw new FormatException(); + fractionLen = len - i - 1; + fraction = BIM.Parse(v.Substring(i + 1, fractionLen)); + len = i; + } + + integral = BIM.Parse(v.Substring(0, len)); + + if (!fraction.IsZero) { + while (fractionLen > 0) { + integral = integral * ten; + exponent = exponent - 1; + fractionLen = fractionLen - 1; + } + } + return new fp32(integral - fraction, exponent, integral.Sign == -1); + } + + internal fp32(BIM mantissa, int exponent, bool isNegative) { + this.isNegative = isNegative; + if (mantissa.IsZero) { + this.mantissa = mantissa; + this.exponent = 0; + } + else { + while (mantissa % ten == BIM.Zero) { //TODO: get this to work as expected :P + mantissa = mantissa / ten; + exponent = exponent + 1; + } + this.mantissa = mantissa; + this.exponent = exponent; + } + } + + + //////////////////////////////////////////////////////////////////////////// + // Basic object operations + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is fp32)) + return false; + + return (this == (fp32)obj); + } + + [Pure] + public override int GetHashCode() { + return this.mantissa.GetHashCode() * 13 + this.exponent.GetHashCode(); + } + + [Pure] + public override string/*!*/ ToString() { + //TODO: modify to reflect floating points + Contract.Ensures(Contract.Result() != null); + return String.Format("{0}e{1}", this.mantissa.ToString(), this.exponent.ToString()); + } + + + //////////////////////////////////////////////////////////////////////////// + // Conversion operations + + // ``floor`` rounds towards negative infinity (like SMT-LIBv2's to_int). + /// + /// Computes the floor and ceiling of this fp32. Note the choice of rounding towards negative + /// infinity rather than zero for floor is because SMT-LIBv2's to_int function floors this way. + /// + /// The Floor (rounded towards negative infinity) + /// Ceiling (rounded towards positive infinity) + public void FloorCeiling(out BIM floor, out BIM ceiling) { + //TODO: fix for fp functionality + BIM n = this.mantissa; + int e = this.exponent; + if (n.IsZero) { + floor = ceiling = n; + } else if (0 <= e) { + // it's an integer + for (; 0 < e; e--) { + n = n * ten; + } + floor = ceiling = n; + } else { + // it's a non-zero integer, so the ceiling is one more than the floor + for (; e < 0 && !n.IsZero; e++) { + n = n / ten; // Division rounds towards negative infinity + } + + if (this.mantissa >= 0) { + floor = n; + ceiling = n + 1; + } else { + ceiling = n; + floor = n - 1; + } + } + Debug.Assert(floor <= ceiling, "Invariant was not maintained"); + } + + [Pure] + public String ToDecimalString(int maxDigits) { + //TODO: fix for fp functionality + string s = this.mantissa.ToString(); + int digits = (this.mantissa >= 0) ? s.Length : s.Length - 1; + BIM max = BIM.Pow(10, maxDigits); + BIM min = -max; + + if (this.exponent >= 0) { + if (maxDigits < digits || maxDigits - digits < this.exponent) { + return String.Format("{0}.0", (this.mantissa >= 0) ? max.ToString() : min.ToString()); + } + else { + return String.Format("{0}{1}.0", s, new string('0', this.exponent)); + } + } + else { + int exp = -this.exponent; + + if (exp < digits) { + int intDigits = digits - exp; + if (maxDigits < intDigits) { + return String.Format("{0}.0", (this.mantissa >= 0) ? max.ToString() : min.ToString()); + } + else { + int fracDigits = Math.Min(maxDigits, digits - intDigits); + return String.Format("{0}.{1}", s.Substring(0, intDigits), s.Substring(intDigits, fracDigits)); + } + } + else { + int fracDigits = Math.Min(maxDigits, digits); + return String.Format("0.{0}{1}", new string('0', exp - fracDigits), s.Substring(0, fracDigits)); + } + } + } + + [Pure] + public string ToDecimalString() { + //TODO: fix for fp functionality + string m = this.mantissa.ToString(); + var e = this.exponent; + if (0 <= this.exponent) { + return m + Zeros(e) + ".0"; + } else { + e = -e; + // compute k to be the longest suffix of m consisting of all zeros (but no longer than e, and not the entire string) + var maxK = e < m.Length ? e : m.Length - 1; + var last = m.Length - 1; + var k = 0; + while (k < maxK && m[last - k] == '0') { + k++; + } + if (0 < k) { + // chop off the suffix of k zeros from m and adjust e accordingly + m = m.Substring(0, m.Length - k); + e -= k; + } + if (e == 0) { + return m; + } else if (e < m.Length) { + var n = m.Length - e; + return m.Substring(0, n) + "." + m.Substring(n); + } else { + return "0." + Zeros(e - m.Length) + m; + } + } + } + + [Pure] + public static string Zeros(int n) { + //TODO: fix for fp functionality + Contract.Requires(0 <= n); + if (n <= 10) { + var tenZeros = "0000000000"; + return tenZeros.Substring(0, n); + } else { + var d = n / 2; + var s = Zeros(d); + if (n % 2 == 0) { + return s + s; + } else { + return s + s + "0"; + } + } + } + + + //////////////////////////////////////////////////////////////////////////// + // Basic arithmetic operations + + [Pure] + public fp32 Abs { + //TODO: fix for fp functionality + get { + return new fp32(BIM.Abs(this.mantissa), this.exponent, false); + } + } + + [Pure] + public fp32 Negate { + //TODO: Modify for correct fp functionality + get { + return new fp32(BIM.Negate(this.mantissa), this.exponent, this.Mantissa >= 0); + } + } + + [Pure] + public static fp32 operator -(fp32 x) { + return x.Negate; + } + + [Pure] + public static fp32 operator +(fp32 x, fp32 y) { + //TODO: Modify for correct fp functionality + BIM m1 = x.mantissa; + int e1 = x.exponent; + BIM m2 = y.mantissa; + int e2 = y.exponent; + if (e2 < e1) { + m1 = y.mantissa; + e1 = y.exponent; + m2 = x.mantissa; + e2 = x.exponent; + } + + while (e2 > e1) { + m2 = m2 * ten; + e2 = e2 - 1; + } + + return new fp32(m1 + m2, e1, true); + } + + [Pure] + public static fp32 operator -(fp32 x, fp32 y) { + return x + y.Negate; + } + + [Pure] + public static fp32 operator *(fp32 x, fp32 y) { + //TODO: modify for correct fp functionality + return new fp32(x.mantissa * y.mantissa, x.exponent + y.exponent, false); + } + + + //////////////////////////////////////////////////////////////////////////// + // Some basic comparison operations + + public bool IsPositive { + get { + return (this.mantissa > BIM.Zero); + } + } + + public bool IsNegative { + get { + return (isNegative); + } + } + + public bool IsZero { + get { + return this.mantissa.IsZero; + } + } + + [Pure] + public int CompareTo(fp32 that) { + //TODO: Modify for correct fp functionality + if (this.mantissa == that.mantissa && this.exponent == that.exponent) { + return 0; + } + else { + fp32 d = this - that; + return d.IsNegative ? -1 : 1; + } + } + + [Pure] + public static bool operator ==(fp32 x, fp32 y) { + return x.CompareTo(y) == 0; + } + + [Pure] + public static bool operator !=(fp32 x, fp32 y) { + return x.CompareTo(y) != 0; + } + + [Pure] + public static bool operator <(fp32 x, fp32 y) { + return x.CompareTo(y) < 0; + } + + [Pure] + public static bool operator >(fp32 x, fp32 y) { + return x.CompareTo(y) > 0; + } + + [Pure] + public static bool operator <=(fp32 x, fp32 y) { + return x.CompareTo(y) <= 0; + } + + [Pure] + public static bool operator >=(fp32 x, fp32 y) { + return x.CompareTo(y) >= 0; + } + } +} diff --git a/Test/z3api/bar1.bpl b/Test/z3api/bar1.bpl index 845954d5..22d87f90 100644 --- a/Test/z3api/bar1.bpl +++ b/Test/z3api/bar1.bpl @@ -1,4 +1,4 @@ -var x: int; + var x: int; var y: int; procedure {:inline 1} bar() -- cgit v1.2.3 From 02326abeca88715427d09f8995ee5ccfd9dab397 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Fri, 17 Apr 2015 12:29:04 -0600 Subject: adding references to the floating point type wherever references to the real type exist. This remains a work in progress --- Source/Basetypes/Basetypes.csproj | 2 +- Source/Basetypes/fp32.cs | 62 +++++++++++++------------- Source/Core/AbsyExpr.cs | 15 +++++++ Source/Core/AbsyType.cs | 11 +++++ Source/Core/Core.csproj | 4 +- Source/Core/Parser.cs | 7 ++- Source/UnitTests/CoreTests/CoreTests.csproj | 2 +- Source/UnitTests/CoreTests/ExprImmutability.cs | 3 ++ 8 files changed, 69 insertions(+), 37 deletions(-) diff --git a/Source/Basetypes/Basetypes.csproj b/Source/Basetypes/Basetypes.csproj index fea8eebc..84a6ffd1 100644 --- a/Source/Basetypes/Basetypes.csproj +++ b/Source/Basetypes/Basetypes.csproj @@ -163,7 +163,7 @@ - + diff --git a/Source/Basetypes/fp32.cs b/Source/Basetypes/fp32.cs index c64afa54..5d76737b 100644 --- a/Source/Basetypes/fp32.cs +++ b/Source/Basetypes/fp32.cs @@ -11,7 +11,7 @@ using System.Text; using System.Diagnostics.Contracts; using System.Diagnostics; -namespace Basetypes +namespace Microsoft.Basetypes { using BIM = System.Numerics.BigInteger; @@ -19,7 +19,7 @@ namespace Basetypes /// A representation of a 32-bit floating point value /// Note that this value has a 1-bit sign, 8-bit exponent, and 23-bit mantissa /// - public struct fp32 + public struct FP32 { //Please note that this code outline is copy-pasted from BigDec.cs @@ -43,7 +43,7 @@ namespace Basetypes } } - public static readonly fp32 ZERO = FromInt(0); + public static readonly FP32 ZERO = FromInt(0); private static readonly BIM two = new BIM(2); private static readonly BIM ten = new BIM(10); @@ -55,17 +55,17 @@ namespace Basetypes //For a complete summary of where this class has been added, simply view constructor references [Pure] - public static fp32 FromInt(int v) { - return new fp32(v, 0, v < 0); //TODO: modify for correct fp representation + public static FP32 FromInt(int v) { + return new FP32(v, 0, v < 0); //TODO: modify for correct fp representation } [Pure] - public static fp32 FromBigInt(BIM v) { - return new fp32(v, 0, v < 0); //TODO: modify for correct fp representation + public static FP32 FromBigInt(BIM v) { + return new FP32(v, 0, v < 0); //TODO: modify for correct fp representation } [Pure] - public static fp32 FromString(string v) { + public static FP32 FromString(string v) { //TODO: completely copied from BigDec.cs at the moment if (v == null) throw new FormatException(); @@ -100,10 +100,10 @@ namespace Basetypes fractionLen = fractionLen - 1; } } - return new fp32(integral - fraction, exponent, integral.Sign == -1); + return new FP32(integral - fraction, exponent, integral.Sign == -1); } - internal fp32(BIM mantissa, int exponent, bool isNegative) { + internal FP32(BIM mantissa, int exponent, bool isNegative) { this.isNegative = isNegative; if (mantissa.IsZero) { this.mantissa = mantissa; @@ -128,10 +128,10 @@ namespace Basetypes public override bool Equals(object obj) { if (obj == null) return false; - if (!(obj is fp32)) + if (!(obj is FP32)) return false; - return (this == (fp32)obj); + return (this == (FP32)obj); } [Pure] @@ -152,7 +152,7 @@ namespace Basetypes // ``floor`` rounds towards negative infinity (like SMT-LIBv2's to_int). /// - /// Computes the floor and ceiling of this fp32. Note the choice of rounding towards negative + /// Computes the floor and ceiling of this FP32. Note the choice of rounding towards negative /// infinity rather than zero for floor is because SMT-LIBv2's to_int function floors this way. /// /// The Floor (rounded towards negative infinity) @@ -277,28 +277,28 @@ namespace Basetypes // Basic arithmetic operations [Pure] - public fp32 Abs { + public FP32 Abs { //TODO: fix for fp functionality get { - return new fp32(BIM.Abs(this.mantissa), this.exponent, false); + return new FP32(BIM.Abs(this.mantissa), this.exponent, false); } } [Pure] - public fp32 Negate { + public FP32 Negate { //TODO: Modify for correct fp functionality get { - return new fp32(BIM.Negate(this.mantissa), this.exponent, this.Mantissa >= 0); + return new FP32(BIM.Negate(this.mantissa), this.exponent, this.Mantissa >= 0); } } [Pure] - public static fp32 operator -(fp32 x) { + public static FP32 operator -(FP32 x) { return x.Negate; } [Pure] - public static fp32 operator +(fp32 x, fp32 y) { + public static FP32 operator +(FP32 x, FP32 y) { //TODO: Modify for correct fp functionality BIM m1 = x.mantissa; int e1 = x.exponent; @@ -316,18 +316,18 @@ namespace Basetypes e2 = e2 - 1; } - return new fp32(m1 + m2, e1, true); + return new FP32(m1 + m2, e1, true); } [Pure] - public static fp32 operator -(fp32 x, fp32 y) { + public static FP32 operator -(FP32 x, FP32 y) { return x + y.Negate; } [Pure] - public static fp32 operator *(fp32 x, fp32 y) { + public static FP32 operator *(FP32 x, FP32 y) { //TODO: modify for correct fp functionality - return new fp32(x.mantissa * y.mantissa, x.exponent + y.exponent, false); + return new FP32(x.mantissa * y.mantissa, x.exponent + y.exponent, false); } @@ -353,44 +353,44 @@ namespace Basetypes } [Pure] - public int CompareTo(fp32 that) { + public int CompareTo(FP32 that) { //TODO: Modify for correct fp functionality if (this.mantissa == that.mantissa && this.exponent == that.exponent) { return 0; } else { - fp32 d = this - that; + FP32 d = this - that; return d.IsNegative ? -1 : 1; } } [Pure] - public static bool operator ==(fp32 x, fp32 y) { + public static bool operator ==(FP32 x, FP32 y) { return x.CompareTo(y) == 0; } [Pure] - public static bool operator !=(fp32 x, fp32 y) { + public static bool operator !=(FP32 x, FP32 y) { return x.CompareTo(y) != 0; } [Pure] - public static bool operator <(fp32 x, fp32 y) { + public static bool operator <(FP32 x, FP32 y) { return x.CompareTo(y) < 0; } [Pure] - public static bool operator >(fp32 x, fp32 y) { + public static bool operator >(FP32 x, FP32 y) { return x.CompareTo(y) > 0; } [Pure] - public static bool operator <=(fp32 x, fp32 y) { + public static bool operator <=(FP32 x, FP32 y) { return x.CompareTo(y) <= 0; } [Pure] - public static bool operator >=(fp32 x, fp32 y) { + public static bool operator >=(FP32 x, FP32 y) { return x.CompareTo(y) >= 0; } } diff --git a/Source/Core/AbsyExpr.cs b/Source/Core/AbsyExpr.cs index f3a943b8..00306a5e 100644 --- a/Source/Core/AbsyExpr.cs +++ b/Source/Core/AbsyExpr.cs @@ -552,6 +552,21 @@ namespace Microsoft.Boogie { CachedHashCode = ComputeHashCode(); } + /// + /// Creates a literal expression for the floating point value "v". + /// + /// + /// + public LiteralExpr(IToken/*!*/ tok, FP32 v, bool immutable = false) + : base(tok, immutable) + { + Contract.Requires(tok != null); + Val = v; + Type = Type.Float; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + [Pure] [Reads(ReadsAttribute.Reads.Nothing)] public override bool Equals(object obj) { diff --git a/Source/Core/AbsyType.cs b/Source/Core/AbsyType.cs index 97309155..ec8cd9e2 100644 --- a/Source/Core/AbsyType.cs +++ b/Source/Core/AbsyType.cs @@ -336,6 +336,7 @@ namespace Microsoft.Boogie { public static readonly Type/*!*/ Int = new BasicType(SimpleType.Int); public static readonly Type/*!*/ Real = new BasicType(SimpleType.Real); + public static readonly Type/*!*/ Float = new BasicType(SimpleType.Float); public static readonly Type/*!*/ Bool = new BasicType(SimpleType.Bool); private static BvType[] bvtypeCache; @@ -871,6 +872,8 @@ namespace Microsoft.Boogie { return "int"; case SimpleType.Real: return "real"; + case SimpleType.Float: + return "float"; case SimpleType.Bool: return "bool"; } @@ -993,6 +996,13 @@ namespace Microsoft.Boogie { return this.T == SimpleType.Real; } } + public override bool IsFloat + { + get + { + return this.T == SimpleType.Float; + } + } public override bool IsBool { get { return this.T == SimpleType.Bool; @@ -3526,6 +3536,7 @@ Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); public enum SimpleType { Int, Real, + Float, Bool }; diff --git a/Source/Core/Core.csproj b/Source/Core/Core.csproj index 27f4eea7..fbb23cfe 100644 --- a/Source/Core/Core.csproj +++ b/Source/Core/Core.csproj @@ -34,7 +34,7 @@ false false true - Client + Client true @@ -186,7 +186,7 @@ - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} + {43dfad18-3e35-4558-9be2-caff6b5ba8a0} Basetypes diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index 9a0bab51..1d4b38b8 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -664,8 +664,11 @@ private class BvBounds : Expr { ty = new BasicType(t, SimpleType.Int); } else if (la.kind == 15) { Get(); - ty = new BasicType(t, SimpleType.Real); - } else if (la.kind == 16) { + ty = new BasicType(t, SimpleType.Real); + } else if (la.kind == 112837) { + Get(); + ty = new BasicType(t, SimpleType.Float); + } else if (la.kind == 16) { Get(); ty = new BasicType(t, SimpleType.Bool); } else if (la.kind == 9) { diff --git a/Source/UnitTests/CoreTests/CoreTests.csproj b/Source/UnitTests/CoreTests/CoreTests.csproj index 9b319d85..ddf310be 100644 --- a/Source/UnitTests/CoreTests/CoreTests.csproj +++ b/Source/UnitTests/CoreTests/CoreTests.csproj @@ -54,7 +54,7 @@ - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} + {43dfad18-3e35-4558-9be2-caff6b5ba8a0} Basetypes diff --git a/Source/UnitTests/CoreTests/ExprImmutability.cs b/Source/UnitTests/CoreTests/ExprImmutability.cs index b83983b6..7f266074 100644 --- a/Source/UnitTests/CoreTests/ExprImmutability.cs +++ b/Source/UnitTests/CoreTests/ExprImmutability.cs @@ -29,6 +29,9 @@ namespace CoreTests var literal4 = new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(0), 8, /*immutable=*/true); Assert.AreEqual(literal4.ComputeHashCode(), literal4.GetHashCode()); + + var literal5 = new LiteralExpr(Token.NoToken, Microsoft.Basetypes.FP32.FromInt(0), /*immutable=*/true); + Assert.AreEqual(literal5.ComputeHashCode(), literal5.GetHashCode()); } [Test()] -- cgit v1.2.3 From b5f62842c113ec93dee7f9ac067ae6d410e7bc29 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Fri, 17 Apr 2015 20:10:46 -0600 Subject: added float type definition to AbsyType and parser (parser definition may be unfinished) --- Source/Core/AbsyType.cs | 30 ++++++++++++++++++++++++------ Source/Core/Parser.cs | 1 + 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/Source/Core/AbsyType.cs b/Source/Core/AbsyType.cs index ec8cd9e2..ae307f7a 100644 --- a/Source/Core/AbsyType.cs +++ b/Source/Core/AbsyType.cs @@ -244,6 +244,11 @@ namespace Microsoft.Boogie { return false; } } + public virtual bool IsFloat { + get { + return false; + } + } public virtual bool IsBool { get { return false; @@ -996,10 +1001,8 @@ namespace Microsoft.Boogie { return this.T == SimpleType.Real; } } - public override bool IsFloat - { - get - { + public override bool IsFloat { + get { return this.T == SimpleType.Float; } } @@ -1909,6 +1912,12 @@ Contract.Requires(that != null); return p != null && p.IsReal; } } + public override bool IsFloat { + get { + Type p = ProxyFor; + return p != null && p.IsFloat; + } + } public override bool IsBool { get { Type p = ProxyFor; @@ -2757,11 +2766,20 @@ Contract.Requires(that != null); return ExpandedType.IsInt; } } - public override bool IsReal { - get { + public override bool IsReal + { + get + { return ExpandedType.IsReal; } } + public override bool IsFloat + { + get + { + return ExpandedType.IsFloat; + } + } public override bool IsBool { get { return ExpandedType.IsBool; diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index 1d4b38b8..4bf11e53 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -2258,6 +2258,7 @@ public class Errors { case 132: s = "invalid AttributeOrTrigger"; break; case 133: s = "invalid AttributeParameter"; break; case 134: s = "invalid QSep"; break; + case 135: s = "\"float\" expected"; break; default: s = "error " + n; break; } -- cgit v1.2.3 From 0776b808b14e62833b3eac1c30c8ac8cc7e62c20 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Mon, 20 Apr 2015 03:44:03 -0600 Subject: added float tipe to AbsyExpr and IntervalDomain. The methods added may require later modification --- Source/AbsInt/IntervalDomain.cs | 7 +++++++ Source/Core/AbsyExpr.cs | 5 +++++ Source/Core/Parser.cs | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Source/AbsInt/IntervalDomain.cs b/Source/AbsInt/IntervalDomain.cs index 1ac80970..b7c6ab5b 100644 --- a/Source/AbsInt/IntervalDomain.cs +++ b/Source/AbsInt/IntervalDomain.cs @@ -208,6 +208,8 @@ namespace Microsoft.Boogie.AbstractInterpretation return null; } else if (ty.IsReal) { return Expr.Literal(Basetypes.BigDec.FromBigInt(n)); + } else if (ty.IsFloat) { + return Expr.Literal(Basetypes.FP32.FromBigInt(n)); } else { Contract.Assume(ty.IsInt); return Expr.Literal(Basetypes.BigNum.FromBigInt(n)); @@ -669,6 +671,11 @@ namespace Microsoft.Boogie.AbstractInterpretation ((BigDec)node.Val).FloorCeiling(out floor, out ceiling); Lo = floor; Hi = ceiling; + } else if (node.Val is FP32) { + BigInteger floor, ceiling; + ((BigDec)node.Val).FloorCeiling(out floor, out ceiling); + Lo = floor; + Hi = ceiling; } else if (node.Val is bool) { if ((bool)node.Val) { // true diff --git a/Source/Core/AbsyExpr.cs b/Source/Core/AbsyExpr.cs index 00306a5e..62145eed 100644 --- a/Source/Core/AbsyExpr.cs +++ b/Source/Core/AbsyExpr.cs @@ -356,6 +356,11 @@ namespace Microsoft.Boogie { Contract.Ensures(Contract.Result() != null); return new LiteralExpr(Token.NoToken, value); } + public static LiteralExpr Literal(FP32 value) + { + Contract.Ensures(Contract.Result() != null); + return new LiteralExpr(Token.NoToken, value); + } private static LiteralExpr/*!*/ true_ = Literal(true); public static LiteralExpr/*!*/ True { diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index 4bf11e53..696a72ed 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -665,7 +665,7 @@ private class BvBounds : Expr { } else if (la.kind == 15) { Get(); ty = new BasicType(t, SimpleType.Real); - } else if (la.kind == 112837) { + } else if (la.kind == 135) { Get(); ty = new BasicType(t, SimpleType.Float); } else if (la.kind == 16) { -- cgit v1.2.3 From 50ea5ab6baf31da6fa3be4f1420d683fd54013cd Mon Sep 17 00:00:00 2001 From: Dietrich Date: Mon, 20 Apr 2015 04:17:46 -0600 Subject: Added float type to the Parser and Scanner --- Source/Core/Parser.cs | 24 ++++++++++++++++++++++-- Source/Core/Scanner.cs | 1 + 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index 696a72ed..5545d8c4 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -1717,7 +1717,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } void AtomExpression(out Expr/*!*/ e) { - Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; int n; BigNum bn; BigDec bd; + Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; int n; BigNum bn; BigDec bd; FP32 fp; List/*!*/ es; List/*!*/ ds; Trigger trig; List/*!*/ typeParams; IdentifierExpr/*!*/ id; @@ -1742,11 +1742,16 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { e = new LiteralExpr(t, bn); break; } - case 5: case 6: { + case 5: { Dec(out bd); e = new LiteralExpr(t, bd); break; } + case 6: { + Float(out fp); + e = new LiteralExpr(t, fp); + break; + } case 2: { BvLit(out bn, out n); e = new LiteralExpr(t, bn, n); @@ -1856,6 +1861,21 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } + void Float(out FP32 n) + { + string s = ""; + if (la.kind == 6) { + Get(); + s = t.val; + } else SynErr(126); + try { + n = FP32.FromString(s); + } catch (FormatException) { + this.SemErr("incorrectly formatted number"); + n = FP32.ZERO; + } + } + void BvLit(out BigNum n, out int m) { Expect(2); int pos = t.val.IndexOf("bv"); diff --git a/Source/Core/Scanner.cs b/Source/Core/Scanner.cs index b23a46a4..a3c139c8 100644 --- a/Source/Core/Scanner.cs +++ b/Source/Core/Scanner.cs @@ -508,6 +508,7 @@ public class Scanner { case "int": t.kind = 14; break; case "real": t.kind = 15; break; case "bool": t.kind = 16; break; + case "float": t.kind = 135; break; case "const": t.kind = 21; break; case "unique": t.kind = 22; break; case "extends": t.kind = 23; break; -- cgit v1.2.3 From bdb6a7db94de0310fb6535facb33782fe231c013 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Mon, 20 Apr 2015 04:19:48 -0600 Subject: added a file for float type testing --- float_test.bpl | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 float_test.bpl diff --git a/float_test.bpl b/float_test.bpl new file mode 100644 index 00000000..22e436a1 --- /dev/null +++ b/float_test.bpl @@ -0,0 +1,11 @@ +procedure F(n: int) returns (r: int) + ensures 100 < n ==> r == n - 10; // This postcondition is easy to check by hand + ensures n <= 100 ==> r == 91; // Do you believe this one is true? +{ + if (100 < n) { + r := n - 10; + } else { + call r := F(n + 11); + call r := F(r); + } +} \ No newline at end of file -- cgit v1.2.3 From 4f35766542c5735374b85f66006afea875f07b79 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Mon, 20 Apr 2015 05:20:06 -0600 Subject: added a collection of console writes for debugging. These should be removed in a future commit --- Source/Core/AbsyExpr.cs | 2 ++ Source/Core/Parser.cs | 2 ++ Source/Core/Scanner.cs | 3 +++ float_test.bpl | 12 +++--------- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Source/Core/AbsyExpr.cs b/Source/Core/AbsyExpr.cs index 62145eed..7aa457fe 100644 --- a/Source/Core/AbsyExpr.cs +++ b/Source/Core/AbsyExpr.cs @@ -630,6 +630,8 @@ namespace Microsoft.Boogie { return Type.Int; } else if (Val is BigDec) { return Type.Real; + } else if (Val is FP32) { + return Type.Float; } else if (Val is BvConst) { return Type.GetBvType(((BvConst)Val).Bits); } else { diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index 5545d8c4..bbe7af4b 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -170,6 +170,7 @@ private class BvBounds : Expr { for (;;) { t = la; la = scanner.Scan(); + Console.WriteLine("Just got the value " + la.kind + " with value " + la.val); if (la.kind <= maxT) { ++errDist; break; } la = t; @@ -597,6 +598,7 @@ private class BvBounds : Expr { void Type(out Bpl.Type/*!*/ ty) { Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken/*!*/ tok; ty = dummyType; + Console.WriteLine(la.kind + " from parser.Type"); if (StartOf(5)) { TypeAtom(out ty); } else if (la.kind == 1) { diff --git a/Source/Core/Scanner.cs b/Source/Core/Scanner.cs index a3c139c8..2df118d6 100644 --- a/Source/Core/Scanner.cs +++ b/Source/Core/Scanner.cs @@ -502,6 +502,7 @@ public class Scanner { void CheckLiteral() { + Console.Write(t.val + " is a literal"); switch (t.val) { case "var": t.kind = 7; break; case "where": t.kind = 13; break; @@ -548,6 +549,7 @@ public class Scanner { case "lambda": t.kind = 92; break; default: break; } + Console.WriteLine(" and is kind " + t.kind); } Token/*!*/ NextToken() { @@ -777,6 +779,7 @@ public class Scanner { } t.val = new String(tval, 0, tlen); + Console.WriteLine("Scanning a token with value " + t._val); return t; } diff --git a/float_test.bpl b/float_test.bpl index 22e436a1..ebd0ab47 100644 --- a/float_test.bpl +++ b/float_test.bpl @@ -1,11 +1,5 @@ -procedure F(n: int) returns (r: int) - ensures 100 < n ==> r == n - 10; // This postcondition is easy to check by hand - ensures n <= 100 ==> r == 91; // Do you believe this one is true? +procedure F(n: float) returns(r: float) + ensures r == n; { - if (100 < n) { - r := n - 10; - } else { - call r := F(n + 11); - call r := F(r); - } + r := n; } \ No newline at end of file -- cgit v1.2.3 From ac54b6451035fd3c0fab62ce1044d48114053c15 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Mon, 20 Apr 2015 13:52:49 -0600 Subject: added minor commenting to Parser.cs --- Source/Core/Parser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index bbe7af4b..e3ffc1c9 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -2103,7 +2103,7 @@ out QKeyValue kv, out Trigger trig, out Expr/*!*/ body) { Expect(0); } - static readonly bool[,]/*!*/ set = { + static readonly bool[,]/*!*/ set = { //17 x 98 grid of true-false values {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,T, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,T,x,x, x,T,T,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, x,x,x,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,T,x,x, x,x,T,T, T,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,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x}, -- cgit v1.2.3 From 1621e22e7758046e1262b22410a48250388abf29 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Mon, 20 Apr 2015 14:56:59 -0600 Subject: renamed fp32 to BigFloat --- Source/AbsInt/IntervalDomain.cs | 4 +- Source/Basetypes/Basetypes.csproj | 2 +- Source/Basetypes/BigFloat.cs | 397 +++++++++++++++++++++++++ Source/Basetypes/fp32.cs | 397 ------------------------- Source/Core/AbsyExpr.cs | 6 +- Source/Core/Parser.cs | 8 +- Source/UnitTests/CoreTests/ExprImmutability.cs | 2 +- 7 files changed, 408 insertions(+), 408 deletions(-) create mode 100644 Source/Basetypes/BigFloat.cs delete mode 100644 Source/Basetypes/fp32.cs diff --git a/Source/AbsInt/IntervalDomain.cs b/Source/AbsInt/IntervalDomain.cs index b7c6ab5b..502b7075 100644 --- a/Source/AbsInt/IntervalDomain.cs +++ b/Source/AbsInt/IntervalDomain.cs @@ -209,7 +209,7 @@ namespace Microsoft.Boogie.AbstractInterpretation } else if (ty.IsReal) { return Expr.Literal(Basetypes.BigDec.FromBigInt(n)); } else if (ty.IsFloat) { - return Expr.Literal(Basetypes.FP32.FromBigInt(n)); + return Expr.Literal(Basetypes.BigFloat.FromBigInt(n)); } else { Contract.Assume(ty.IsInt); return Expr.Literal(Basetypes.BigNum.FromBigInt(n)); @@ -671,7 +671,7 @@ namespace Microsoft.Boogie.AbstractInterpretation ((BigDec)node.Val).FloorCeiling(out floor, out ceiling); Lo = floor; Hi = ceiling; - } else if (node.Val is FP32) { + } else if (node.Val is BigFloat) { BigInteger floor, ceiling; ((BigDec)node.Val).FloorCeiling(out floor, out ceiling); Lo = floor; diff --git a/Source/Basetypes/Basetypes.csproj b/Source/Basetypes/Basetypes.csproj index 84a6ffd1..4ecdee8d 100644 --- a/Source/Basetypes/Basetypes.csproj +++ b/Source/Basetypes/Basetypes.csproj @@ -163,7 +163,7 @@ - + diff --git a/Source/Basetypes/BigFloat.cs b/Source/Basetypes/BigFloat.cs new file mode 100644 index 00000000..d1ee73a4 --- /dev/null +++ b/Source/Basetypes/BigFloat.cs @@ -0,0 +1,397 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Diagnostics.Contracts; +using System.Diagnostics; + +namespace Microsoft.Basetypes +{ + using BIM = System.Numerics.BigInteger; + + /// + /// A representation of a 32-bit floating point value + /// Note that this value has a 1-bit sign, 8-bit exponent, and 23-bit mantissa + /// + public struct BigFloat + { + //Please note that this code outline is copy-pasted from BigDec.cs + + // the internal representation + [Rep] + internal readonly BIM mantissa; //TODO: restrict mantissa to be 23-bits wide + [Rep] + internal readonly int exponent; //TODO: restrict exponent to be 8-bits wide + [Rep] + internal readonly Boolean isNegative; //represents the sign bit + + public BIM Mantissa { + get { + return mantissa; + } + } + + public int Exponent { + get { + return exponent; + } + } + + public static readonly BigFloat ZERO = FromInt(0); + private static readonly BIM two = new BIM(2); + private static readonly BIM ten = new BIM(10); + + + //////////////////////////////////////////////////////////////////////////// + // Constructors + + //Please note that these constructors will be called throughout boogie + //For a complete summary of where this class has been added, simply view constructor references + + [Pure] + public static BigFloat FromInt(int v) { + return new BigFloat(v, 0, v < 0); //TODO: modify for correct fp representation + } + + [Pure] + public static BigFloat FromBigInt(BIM v) { + return new BigFloat(v, 0, v < 0); //TODO: modify for correct fp representation + } + + [Pure] + public static BigFloat FromString(string v) { + //TODO: completely copied from BigDec.cs at the moment + if (v == null) throw new FormatException(); + + BIM integral = BIM.Zero; + BIM fraction = BIM.Zero; + int exponent = 0; + + int len = v.Length; + + int i = v.IndexOf('e'); + if (i >= 0) { + if (i + 1 == v.Length) throw new FormatException(); + exponent = Int32.Parse(v.Substring(i + 1, len - i - 1)); + len = i; + } + + int fractionLen = 0; + i = v.IndexOf('.'); + if (i >= 0) { + if (i + 1 == v.Length) throw new FormatException(); + fractionLen = len - i - 1; + fraction = BIM.Parse(v.Substring(i + 1, fractionLen)); + len = i; + } + + integral = BIM.Parse(v.Substring(0, len)); + + if (!fraction.IsZero) { + while (fractionLen > 0) { + integral = integral * ten; + exponent = exponent - 1; + fractionLen = fractionLen - 1; + } + } + return new BigFloat(integral - fraction, exponent, integral.Sign == -1); + } + + internal BigFloat(BIM mantissa, int exponent, bool isNegative) { + this.isNegative = isNegative; + if (mantissa.IsZero) { + this.mantissa = mantissa; + this.exponent = 0; + } + else { + while (mantissa % ten == BIM.Zero) { //TODO: get this to work as expected :P + mantissa = mantissa / ten; + exponent = exponent + 1; + } + this.mantissa = mantissa; + this.exponent = exponent; + } + } + + + //////////////////////////////////////////////////////////////////////////// + // Basic object operations + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is BigFloat)) + return false; + + return (this == (BigFloat)obj); + } + + [Pure] + public override int GetHashCode() { + return this.mantissa.GetHashCode() * 13 + this.exponent.GetHashCode(); + } + + [Pure] + public override string/*!*/ ToString() { + //TODO: modify to reflect floating points + Contract.Ensures(Contract.Result() != null); + return String.Format("{0}e{1}", this.mantissa.ToString(), this.exponent.ToString()); + } + + + //////////////////////////////////////////////////////////////////////////// + // Conversion operations + + // ``floor`` rounds towards negative infinity (like SMT-LIBv2's to_int). + /// + /// Computes the floor and ceiling of this BigFloat. Note the choice of rounding towards negative + /// infinity rather than zero for floor is because SMT-LIBv2's to_int function floors this way. + /// + /// The Floor (rounded towards negative infinity) + /// Ceiling (rounded towards positive infinity) + public void FloorCeiling(out BIM floor, out BIM ceiling) { + //TODO: fix for fp functionality + BIM n = this.mantissa; + int e = this.exponent; + if (n.IsZero) { + floor = ceiling = n; + } else if (0 <= e) { + // it's an integer + for (; 0 < e; e--) { + n = n * ten; + } + floor = ceiling = n; + } else { + // it's a non-zero integer, so the ceiling is one more than the floor + for (; e < 0 && !n.IsZero; e++) { + n = n / ten; // Division rounds towards negative infinity + } + + if (this.mantissa >= 0) { + floor = n; + ceiling = n + 1; + } else { + ceiling = n; + floor = n - 1; + } + } + Debug.Assert(floor <= ceiling, "Invariant was not maintained"); + } + + [Pure] + public String ToDecimalString(int maxDigits) { + //TODO: fix for fp functionality + string s = this.mantissa.ToString(); + int digits = (this.mantissa >= 0) ? s.Length : s.Length - 1; + BIM max = BIM.Pow(10, maxDigits); + BIM min = -max; + + if (this.exponent >= 0) { + if (maxDigits < digits || maxDigits - digits < this.exponent) { + return String.Format("{0}.0", (this.mantissa >= 0) ? max.ToString() : min.ToString()); + } + else { + return String.Format("{0}{1}.0", s, new string('0', this.exponent)); + } + } + else { + int exp = -this.exponent; + + if (exp < digits) { + int intDigits = digits - exp; + if (maxDigits < intDigits) { + return String.Format("{0}.0", (this.mantissa >= 0) ? max.ToString() : min.ToString()); + } + else { + int fracDigits = Math.Min(maxDigits, digits - intDigits); + return String.Format("{0}.{1}", s.Substring(0, intDigits), s.Substring(intDigits, fracDigits)); + } + } + else { + int fracDigits = Math.Min(maxDigits, digits); + return String.Format("0.{0}{1}", new string('0', exp - fracDigits), s.Substring(0, fracDigits)); + } + } + } + + [Pure] + public string ToDecimalString() { + //TODO: fix for fp functionality + string m = this.mantissa.ToString(); + var e = this.exponent; + if (0 <= this.exponent) { + return m + Zeros(e) + ".0"; + } else { + e = -e; + // compute k to be the longest suffix of m consisting of all zeros (but no longer than e, and not the entire string) + var maxK = e < m.Length ? e : m.Length - 1; + var last = m.Length - 1; + var k = 0; + while (k < maxK && m[last - k] == '0') { + k++; + } + if (0 < k) { + // chop off the suffix of k zeros from m and adjust e accordingly + m = m.Substring(0, m.Length - k); + e -= k; + } + if (e == 0) { + return m; + } else if (e < m.Length) { + var n = m.Length - e; + return m.Substring(0, n) + "." + m.Substring(n); + } else { + return "0." + Zeros(e - m.Length) + m; + } + } + } + + [Pure] + public static string Zeros(int n) { + //TODO: fix for fp functionality + Contract.Requires(0 <= n); + if (n <= 10) { + var tenZeros = "0000000000"; + return tenZeros.Substring(0, n); + } else { + var d = n / 2; + var s = Zeros(d); + if (n % 2 == 0) { + return s + s; + } else { + return s + s + "0"; + } + } + } + + + //////////////////////////////////////////////////////////////////////////// + // Basic arithmetic operations + + [Pure] + public BigFloat Abs { + //TODO: fix for fp functionality + get { + return new BigFloat(BIM.Abs(this.mantissa), this.exponent, false); + } + } + + [Pure] + public BigFloat Negate { + //TODO: Modify for correct fp functionality + get { + return new BigFloat(BIM.Negate(this.mantissa), this.exponent, this.Mantissa >= 0); + } + } + + [Pure] + public static BigFloat operator -(BigFloat x) { + return x.Negate; + } + + [Pure] + public static BigFloat operator +(BigFloat x, BigFloat y) { + //TODO: Modify for correct fp functionality + BIM m1 = x.mantissa; + int e1 = x.exponent; + BIM m2 = y.mantissa; + int e2 = y.exponent; + if (e2 < e1) { + m1 = y.mantissa; + e1 = y.exponent; + m2 = x.mantissa; + e2 = x.exponent; + } + + while (e2 > e1) { + m2 = m2 * ten; + e2 = e2 - 1; + } + + return new BigFloat(m1 + m2, e1, true); + } + + [Pure] + public static BigFloat operator -(BigFloat x, BigFloat y) { + return x + y.Negate; + } + + [Pure] + public static BigFloat operator *(BigFloat x, BigFloat y) { + //TODO: modify for correct fp functionality + return new BigFloat(x.mantissa * y.mantissa, x.exponent + y.exponent, false); + } + + + //////////////////////////////////////////////////////////////////////////// + // Some basic comparison operations + + public bool IsPositive { + get { + return (this.mantissa > BIM.Zero); + } + } + + public bool IsNegative { + get { + return (isNegative); + } + } + + public bool IsZero { + get { + return this.mantissa.IsZero; + } + } + + [Pure] + public int CompareTo(BigFloat that) { + //TODO: Modify for correct fp functionality + if (this.mantissa == that.mantissa && this.exponent == that.exponent) { + return 0; + } + else { + BigFloat d = this - that; + return d.IsNegative ? -1 : 1; + } + } + + [Pure] + public static bool operator ==(BigFloat x, BigFloat y) { + return x.CompareTo(y) == 0; + } + + [Pure] + public static bool operator !=(BigFloat x, BigFloat y) { + return x.CompareTo(y) != 0; + } + + [Pure] + public static bool operator <(BigFloat x, BigFloat y) { + return x.CompareTo(y) < 0; + } + + [Pure] + public static bool operator >(BigFloat x, BigFloat y) { + return x.CompareTo(y) > 0; + } + + [Pure] + public static bool operator <=(BigFloat x, BigFloat y) { + return x.CompareTo(y) <= 0; + } + + [Pure] + public static bool operator >=(BigFloat x, BigFloat y) { + return x.CompareTo(y) >= 0; + } + } +} diff --git a/Source/Basetypes/fp32.cs b/Source/Basetypes/fp32.cs deleted file mode 100644 index 5d76737b..00000000 --- a/Source/Basetypes/fp32.cs +++ /dev/null @@ -1,397 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Diagnostics.Contracts; -using System.Diagnostics; - -namespace Microsoft.Basetypes -{ - using BIM = System.Numerics.BigInteger; - - /// - /// A representation of a 32-bit floating point value - /// Note that this value has a 1-bit sign, 8-bit exponent, and 23-bit mantissa - /// - public struct FP32 - { - //Please note that this code outline is copy-pasted from BigDec.cs - - // the internal representation - [Rep] - internal readonly BIM mantissa; //TODO: restrict mantissa to be 23-bits wide - [Rep] - internal readonly int exponent; //TODO: restrict exponent to be 8-bits wide - [Rep] - internal readonly Boolean isNegative; //represents the sign bit - - public BIM Mantissa { - get { - return mantissa; - } - } - - public int Exponent { - get { - return exponent; - } - } - - public static readonly FP32 ZERO = FromInt(0); - private static readonly BIM two = new BIM(2); - private static readonly BIM ten = new BIM(10); - - - //////////////////////////////////////////////////////////////////////////// - // Constructors - - //Please note that these constructors will be called throughout boogie - //For a complete summary of where this class has been added, simply view constructor references - - [Pure] - public static FP32 FromInt(int v) { - return new FP32(v, 0, v < 0); //TODO: modify for correct fp representation - } - - [Pure] - public static FP32 FromBigInt(BIM v) { - return new FP32(v, 0, v < 0); //TODO: modify for correct fp representation - } - - [Pure] - public static FP32 FromString(string v) { - //TODO: completely copied from BigDec.cs at the moment - if (v == null) throw new FormatException(); - - BIM integral = BIM.Zero; - BIM fraction = BIM.Zero; - int exponent = 0; - - int len = v.Length; - - int i = v.IndexOf('e'); - if (i >= 0) { - if (i + 1 == v.Length) throw new FormatException(); - exponent = Int32.Parse(v.Substring(i + 1, len - i - 1)); - len = i; - } - - int fractionLen = 0; - i = v.IndexOf('.'); - if (i >= 0) { - if (i + 1 == v.Length) throw new FormatException(); - fractionLen = len - i - 1; - fraction = BIM.Parse(v.Substring(i + 1, fractionLen)); - len = i; - } - - integral = BIM.Parse(v.Substring(0, len)); - - if (!fraction.IsZero) { - while (fractionLen > 0) { - integral = integral * ten; - exponent = exponent - 1; - fractionLen = fractionLen - 1; - } - } - return new FP32(integral - fraction, exponent, integral.Sign == -1); - } - - internal FP32(BIM mantissa, int exponent, bool isNegative) { - this.isNegative = isNegative; - if (mantissa.IsZero) { - this.mantissa = mantissa; - this.exponent = 0; - } - else { - while (mantissa % ten == BIM.Zero) { //TODO: get this to work as expected :P - mantissa = mantissa / ten; - exponent = exponent + 1; - } - this.mantissa = mantissa; - this.exponent = exponent; - } - } - - - //////////////////////////////////////////////////////////////////////////// - // Basic object operations - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is FP32)) - return false; - - return (this == (FP32)obj); - } - - [Pure] - public override int GetHashCode() { - return this.mantissa.GetHashCode() * 13 + this.exponent.GetHashCode(); - } - - [Pure] - public override string/*!*/ ToString() { - //TODO: modify to reflect floating points - Contract.Ensures(Contract.Result() != null); - return String.Format("{0}e{1}", this.mantissa.ToString(), this.exponent.ToString()); - } - - - //////////////////////////////////////////////////////////////////////////// - // Conversion operations - - // ``floor`` rounds towards negative infinity (like SMT-LIBv2's to_int). - /// - /// Computes the floor and ceiling of this FP32. Note the choice of rounding towards negative - /// infinity rather than zero for floor is because SMT-LIBv2's to_int function floors this way. - /// - /// The Floor (rounded towards negative infinity) - /// Ceiling (rounded towards positive infinity) - public void FloorCeiling(out BIM floor, out BIM ceiling) { - //TODO: fix for fp functionality - BIM n = this.mantissa; - int e = this.exponent; - if (n.IsZero) { - floor = ceiling = n; - } else if (0 <= e) { - // it's an integer - for (; 0 < e; e--) { - n = n * ten; - } - floor = ceiling = n; - } else { - // it's a non-zero integer, so the ceiling is one more than the floor - for (; e < 0 && !n.IsZero; e++) { - n = n / ten; // Division rounds towards negative infinity - } - - if (this.mantissa >= 0) { - floor = n; - ceiling = n + 1; - } else { - ceiling = n; - floor = n - 1; - } - } - Debug.Assert(floor <= ceiling, "Invariant was not maintained"); - } - - [Pure] - public String ToDecimalString(int maxDigits) { - //TODO: fix for fp functionality - string s = this.mantissa.ToString(); - int digits = (this.mantissa >= 0) ? s.Length : s.Length - 1; - BIM max = BIM.Pow(10, maxDigits); - BIM min = -max; - - if (this.exponent >= 0) { - if (maxDigits < digits || maxDigits - digits < this.exponent) { - return String.Format("{0}.0", (this.mantissa >= 0) ? max.ToString() : min.ToString()); - } - else { - return String.Format("{0}{1}.0", s, new string('0', this.exponent)); - } - } - else { - int exp = -this.exponent; - - if (exp < digits) { - int intDigits = digits - exp; - if (maxDigits < intDigits) { - return String.Format("{0}.0", (this.mantissa >= 0) ? max.ToString() : min.ToString()); - } - else { - int fracDigits = Math.Min(maxDigits, digits - intDigits); - return String.Format("{0}.{1}", s.Substring(0, intDigits), s.Substring(intDigits, fracDigits)); - } - } - else { - int fracDigits = Math.Min(maxDigits, digits); - return String.Format("0.{0}{1}", new string('0', exp - fracDigits), s.Substring(0, fracDigits)); - } - } - } - - [Pure] - public string ToDecimalString() { - //TODO: fix for fp functionality - string m = this.mantissa.ToString(); - var e = this.exponent; - if (0 <= this.exponent) { - return m + Zeros(e) + ".0"; - } else { - e = -e; - // compute k to be the longest suffix of m consisting of all zeros (but no longer than e, and not the entire string) - var maxK = e < m.Length ? e : m.Length - 1; - var last = m.Length - 1; - var k = 0; - while (k < maxK && m[last - k] == '0') { - k++; - } - if (0 < k) { - // chop off the suffix of k zeros from m and adjust e accordingly - m = m.Substring(0, m.Length - k); - e -= k; - } - if (e == 0) { - return m; - } else if (e < m.Length) { - var n = m.Length - e; - return m.Substring(0, n) + "." + m.Substring(n); - } else { - return "0." + Zeros(e - m.Length) + m; - } - } - } - - [Pure] - public static string Zeros(int n) { - //TODO: fix for fp functionality - Contract.Requires(0 <= n); - if (n <= 10) { - var tenZeros = "0000000000"; - return tenZeros.Substring(0, n); - } else { - var d = n / 2; - var s = Zeros(d); - if (n % 2 == 0) { - return s + s; - } else { - return s + s + "0"; - } - } - } - - - //////////////////////////////////////////////////////////////////////////// - // Basic arithmetic operations - - [Pure] - public FP32 Abs { - //TODO: fix for fp functionality - get { - return new FP32(BIM.Abs(this.mantissa), this.exponent, false); - } - } - - [Pure] - public FP32 Negate { - //TODO: Modify for correct fp functionality - get { - return new FP32(BIM.Negate(this.mantissa), this.exponent, this.Mantissa >= 0); - } - } - - [Pure] - public static FP32 operator -(FP32 x) { - return x.Negate; - } - - [Pure] - public static FP32 operator +(FP32 x, FP32 y) { - //TODO: Modify for correct fp functionality - BIM m1 = x.mantissa; - int e1 = x.exponent; - BIM m2 = y.mantissa; - int e2 = y.exponent; - if (e2 < e1) { - m1 = y.mantissa; - e1 = y.exponent; - m2 = x.mantissa; - e2 = x.exponent; - } - - while (e2 > e1) { - m2 = m2 * ten; - e2 = e2 - 1; - } - - return new FP32(m1 + m2, e1, true); - } - - [Pure] - public static FP32 operator -(FP32 x, FP32 y) { - return x + y.Negate; - } - - [Pure] - public static FP32 operator *(FP32 x, FP32 y) { - //TODO: modify for correct fp functionality - return new FP32(x.mantissa * y.mantissa, x.exponent + y.exponent, false); - } - - - //////////////////////////////////////////////////////////////////////////// - // Some basic comparison operations - - public bool IsPositive { - get { - return (this.mantissa > BIM.Zero); - } - } - - public bool IsNegative { - get { - return (isNegative); - } - } - - public bool IsZero { - get { - return this.mantissa.IsZero; - } - } - - [Pure] - public int CompareTo(FP32 that) { - //TODO: Modify for correct fp functionality - if (this.mantissa == that.mantissa && this.exponent == that.exponent) { - return 0; - } - else { - FP32 d = this - that; - return d.IsNegative ? -1 : 1; - } - } - - [Pure] - public static bool operator ==(FP32 x, FP32 y) { - return x.CompareTo(y) == 0; - } - - [Pure] - public static bool operator !=(FP32 x, FP32 y) { - return x.CompareTo(y) != 0; - } - - [Pure] - public static bool operator <(FP32 x, FP32 y) { - return x.CompareTo(y) < 0; - } - - [Pure] - public static bool operator >(FP32 x, FP32 y) { - return x.CompareTo(y) > 0; - } - - [Pure] - public static bool operator <=(FP32 x, FP32 y) { - return x.CompareTo(y) <= 0; - } - - [Pure] - public static bool operator >=(FP32 x, FP32 y) { - return x.CompareTo(y) >= 0; - } - } -} diff --git a/Source/Core/AbsyExpr.cs b/Source/Core/AbsyExpr.cs index 7aa457fe..15ff87db 100644 --- a/Source/Core/AbsyExpr.cs +++ b/Source/Core/AbsyExpr.cs @@ -356,7 +356,7 @@ namespace Microsoft.Boogie { Contract.Ensures(Contract.Result() != null); return new LiteralExpr(Token.NoToken, value); } - public static LiteralExpr Literal(FP32 value) + public static LiteralExpr Literal(BigFloat value) { Contract.Ensures(Contract.Result() != null); return new LiteralExpr(Token.NoToken, value); @@ -562,7 +562,7 @@ namespace Microsoft.Boogie { /// /// /// - public LiteralExpr(IToken/*!*/ tok, FP32 v, bool immutable = false) + public LiteralExpr(IToken/*!*/ tok, BigFloat v, bool immutable = false) : base(tok, immutable) { Contract.Requires(tok != null); @@ -630,7 +630,7 @@ namespace Microsoft.Boogie { return Type.Int; } else if (Val is BigDec) { return Type.Real; - } else if (Val is FP32) { + } else if (Val is BigFloat) { return Type.Float; } else if (Val is BvConst) { return Type.GetBvType(((BvConst)Val).Bits); diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index e3ffc1c9..8edcebdf 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -1719,7 +1719,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } void AtomExpression(out Expr/*!*/ e) { - Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; int n; BigNum bn; BigDec bd; FP32 fp; + Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; int n; BigNum bn; BigDec bd; BigFloat fp; List/*!*/ es; List/*!*/ ds; Trigger trig; List/*!*/ typeParams; IdentifierExpr/*!*/ id; @@ -1863,7 +1863,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } - void Float(out FP32 n) + void Float(out BigFloat n) { string s = ""; if (la.kind == 6) { @@ -1871,10 +1871,10 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { s = t.val; } else SynErr(126); try { - n = FP32.FromString(s); + n = BigFloat.FromString(s); } catch (FormatException) { this.SemErr("incorrectly formatted number"); - n = FP32.ZERO; + n = BigFloat.ZERO; } } diff --git a/Source/UnitTests/CoreTests/ExprImmutability.cs b/Source/UnitTests/CoreTests/ExprImmutability.cs index 7f266074..86018d9b 100644 --- a/Source/UnitTests/CoreTests/ExprImmutability.cs +++ b/Source/UnitTests/CoreTests/ExprImmutability.cs @@ -30,7 +30,7 @@ namespace CoreTests var literal4 = new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(0), 8, /*immutable=*/true); Assert.AreEqual(literal4.ComputeHashCode(), literal4.GetHashCode()); - var literal5 = new LiteralExpr(Token.NoToken, Microsoft.Basetypes.FP32.FromInt(0), /*immutable=*/true); + var literal5 = new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigFloat.FromInt(0), /*immutable=*/true); Assert.AreEqual(literal5.ComputeHashCode(), literal5.GetHashCode()); } -- cgit v1.2.3 From 55cce70250dbf31b6261159ffbf8d0071f77d762 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Sun, 26 Apr 2015 14:08:15 -0600 Subject: added float type to Arithmetic Expression and added a new float test --- Source/Core/AbsyExpr.cs | 9 ++++++++- Source/Core/Parser.cs | 35 ++++++++++++++++++++++++++++------- Source/Core/Scanner.cs | 2 +- float_test2.bpl | 5 +++++ 4 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 float_test2.bpl diff --git a/Source/Core/AbsyExpr.cs b/Source/Core/AbsyExpr.cs index 15ff87db..c0966256 100644 --- a/Source/Core/AbsyExpr.cs +++ b/Source/Core/AbsyExpr.cs @@ -2168,7 +2168,8 @@ namespace Microsoft.Boogie { public class ArithmeticCoercion : IAppliable { public enum CoercionType { ToInt, - ToReal + ToReal, + ToFloat } private IToken/*!*/ tok; @@ -2195,6 +2196,12 @@ namespace Microsoft.Boogie { this.argType = Type.Int; this.hashCode = 2; break; + case CoercionType.ToFloat: + this.name = "float"; + this.type = Type.Real; + this.argType = Type.Int; + this.hashCode = 3; + break; default: Contract.Assert(false); break; diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index 8edcebdf..8661b829 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -667,7 +667,7 @@ private class BvBounds : Expr { } else if (la.kind == 15) { Get(); ty = new BasicType(t, SimpleType.Real); - } else if (la.kind == 135) { + } else if (la.kind == 136) { Get(); ty = new BasicType(t, SimpleType.Float); } else if (la.kind == 16) { @@ -1744,12 +1744,12 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { e = new LiteralExpr(t, bn); break; } - case 5: { + case 5: case 6: { Dec(out bd); e = new LiteralExpr(t, bd); break; } - case 6: { + case 135: { Float(out fp); e = new LiteralExpr(t, fp); break; @@ -1801,6 +1801,15 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToReal), new List{ e }); break; } + case 136: { + Get(); + x = t; + Expect(9); + Expression(out e); + Expect(10); + e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToFloat), new List { e }); + break; + } case 9: { Get(); if (StartOf(9)) { @@ -1863,17 +1872,22 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } + /// + /// Creates a floating point from the current token value + /// + /// void Float(out BigFloat n) { + //To be modified string s = ""; - if (la.kind == 6) { + if (la.kind == 135) { Get(); s = t.val; } else SynErr(126); try { n = BigFloat.FromString(s); } catch (FormatException) { - this.SemErr("incorrectly formatted number"); + this.SemErr("incorrectly formatted floating point"); n = BigFloat.ZERO; } } @@ -2103,7 +2117,7 @@ out QKeyValue kv, out Trigger trig, out Expr/*!*/ body) { Expect(0); } - static readonly bool[,]/*!*/ set = { //17 x 98 grid of true-false values + static readonly bool[,]/*!*/ set = { //grid is 17 x 98 {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,T, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,T,x,x, x,T,T,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, x,x,x,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,T,x,x, x,x,T,T, T,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,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x}, @@ -2142,6 +2156,12 @@ public class Errors { count++; } + /// + /// Returns a string corresponding to the syntax error of the given type + /// Note that many of these errors (0-96, 135, 136) correspond to token types (e.g. the la token) + /// + /// + /// string GetSyntaxErrorString(int n) { string s; switch (n) { @@ -2280,7 +2300,8 @@ public class Errors { case 132: s = "invalid AttributeOrTrigger"; break; case 133: s = "invalid AttributeParameter"; break; case 134: s = "invalid QSep"; break; - case 135: s = "\"float\" expected"; break; + case 135: s = "fp expected"; break; + case 136: s = "\"float\" expected"; break; default: s = "error " + n; break; } diff --git a/Source/Core/Scanner.cs b/Source/Core/Scanner.cs index 2df118d6..2e49726e 100644 --- a/Source/Core/Scanner.cs +++ b/Source/Core/Scanner.cs @@ -509,7 +509,7 @@ public class Scanner { case "int": t.kind = 14; break; case "real": t.kind = 15; break; case "bool": t.kind = 16; break; - case "float": t.kind = 135; break; + case "float": t.kind = 136; break; case "const": t.kind = 21; break; case "unique": t.kind = 22; break; case "extends": t.kind = 23; break; diff --git a/float_test2.bpl b/float_test2.bpl new file mode 100644 index 00000000..69b893c4 --- /dev/null +++ b/float_test2.bpl @@ -0,0 +1,5 @@ +procedure F() returns () { + var x : real; + var y : real; + assert (x == y); +} \ No newline at end of file -- cgit v1.2.3 From 00cd756578ed23a4739138dff4940e112d86fe4c Mon Sep 17 00:00:00 2001 From: Dietrich Date: Sun, 26 Apr 2015 15:05:25 -0600 Subject: removed comments from Scanner.cs, changed the value of the float token kind to 97/98 (from 135/136) --- Source/Core/Parser.cs | 168 ++++++++++++++++++++++++------------------------- Source/Core/Scanner.cs | 3 - float_test2.bpl | 6 +- 3 files changed, 87 insertions(+), 90 deletions(-) diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index 8661b829..578b9e5f 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -171,7 +171,7 @@ private class BvBounds : Expr { t = la; la = scanner.Scan(); Console.WriteLine("Just got the value " + la.kind + " with value " + la.val); - if (la.kind <= maxT) { ++errDist; break; } + if (la.kind <= maxT || la.kind > 134) { ++errDist; break; } //TODO: should modify float to have value < maxT... la = t; } @@ -366,7 +366,7 @@ private class BvBounds : Expr { Get(); Type(out retTy); retTyd = new TypedIdent(retTy.tok, TypedIdent.NoName, retTy); - } else SynErr(97); + } else SynErr(99); if (la.kind == 27) { Get(); Expression(out tmp); @@ -374,7 +374,7 @@ private class BvBounds : Expr { Expect(28); } else if (la.kind == 8) { Get(); - } else SynErr(98); + } else SynErr(100); if (retTyd == null) { // construct a dummy type for the case of syntax error retTyd = new TypedIdent(t, TypedIdent.NoName, new BasicType(t, SimpleType.Int)); @@ -497,7 +497,7 @@ private class BvBounds : Expr { impl = new Implementation(x, x.val, typeParams, Formal.StripWhereClauses(ins), Formal.StripWhereClauses(outs), locals, stmtList, kv == null ? null : (QKeyValue)kv.Clone(), this.errors); - } else SynErr(99); + } else SynErr(101); proc = new Procedure(x, x.val, typeParams, ins, outs, pre, mods, post, kv); } @@ -610,7 +610,7 @@ private class BvBounds : Expr { ty = new UnresolvedTypeIdentifier (tok, tok.val, args); } else if (la.kind == 17 || la.kind == 19) { MapType(out ty); - } else SynErr(100); + } else SynErr(102); } void AttributesIdsTypeWhere(bool allowAttributes, bool allowWhereClauses, string context, System.Action action ) { @@ -667,7 +667,7 @@ private class BvBounds : Expr { } else if (la.kind == 15) { Get(); ty = new BasicType(t, SimpleType.Real); - } else if (la.kind == 136) { + } else if (la.kind == 98) { Get(); ty = new BasicType(t, SimpleType.Float); } else if (la.kind == 16) { @@ -677,7 +677,7 @@ private class BvBounds : Expr { Get(); Type(out ty); Expect(10); - } else SynErr(101); + } else SynErr(103); } void Ident(out IToken/*!*/ x) { @@ -707,7 +707,7 @@ private class BvBounds : Expr { } else if (la.kind == 17 || la.kind == 19) { MapType(out ty); ts.Add(ty); - } else SynErr(102); + } else SynErr(104); } void MapType(out Bpl.Type/*!*/ ty) { @@ -892,7 +892,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { SpecPrePost(true, pre, post); } else if (la.kind == 36 || la.kind == 37) { SpecPrePost(false, pre, post); - } else SynErr(103); + } else SynErr(105); } void ImplBody(out List/*!*/ locals, out StmtList/*!*/ stmtList) { @@ -924,7 +924,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { Proposition(out e); Expect(8); post.Add(new Ensures(tok, free, e, null, kv)); - } else SynErr(104); + } else SynErr(106); } void StmtList(out StmtList/*!*/ stmtList) { @@ -1063,7 +1063,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { c = new YieldCmd(x); break; } - default: SynErr(105); break; + default: SynErr(107); break; } } @@ -1080,7 +1080,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } else if (la.kind == 45) { BreakCmd(out bcmd); ec = bcmd; - } else SynErr(106); + } else SynErr(108); } void TransferCmd(out TransferCmd/*!*/ tc) { @@ -1100,7 +1100,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } else if (la.kind == 39) { Get(); tc = new ReturnCmd(t); - } else SynErr(107); + } else SynErr(109); Expect(8); } @@ -1125,7 +1125,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { Get(); StmtList(out els); elseOption = els; - } else SynErr(108); + } else SynErr(110); } ifcmd = new IfCmd(x, guard, thn, elseIfOption, elseOption); } @@ -1189,7 +1189,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } else if (StartOf(9)) { Expression(out ee); e = ee; - } else SynErr(109); + } else SynErr(111); Expect(10); } @@ -1236,7 +1236,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } Expect(8); c = new AssignCmd(x, lhss, rhss); - } else SynErr(110); + } else SynErr(112); } void CallCmd(out Cmd c) { @@ -1353,7 +1353,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } Expect(10); c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync; - } else SynErr(111); + } else SynErr(113); } void Expressions(out List/*!*/ es) { @@ -1398,7 +1398,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { Get(); } else if (la.kind == 56) { Get(); - } else SynErr(112); + } else SynErr(114); } void LogicalExpression(out Expr/*!*/ e0) { @@ -1436,7 +1436,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { Get(); } else if (la.kind == 58) { Get(); - } else SynErr(113); + } else SynErr(115); } void ExpliesOp() { @@ -1444,7 +1444,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { Get(); } else if (la.kind == 60) { Get(); - } else SynErr(114); + } else SynErr(116); } void RelationalExpression(out Expr/*!*/ e0) { @@ -1462,7 +1462,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { Get(); } else if (la.kind == 62) { Get(); - } else SynErr(115); + } else SynErr(117); } void OrOp() { @@ -1470,7 +1470,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { Get(); } else if (la.kind == 64) { Get(); - } else SynErr(116); + } else SynErr(118); } void BvTerm(out Expr/*!*/ e0) { @@ -1537,7 +1537,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { x = t; op=BinaryOperator.Opcode.Ge; break; } - default: SynErr(117); break; + default: SynErr(119); break; } } @@ -1569,7 +1569,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } else if (la.kind == 75) { Get(); x = t; op=BinaryOperator.Opcode.Sub; - } else SynErr(118); + } else SynErr(120); } void Power(out Expr/*!*/ e0) { @@ -1597,7 +1597,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } else if (la.kind == 78) { Get(); x = t; op=BinaryOperator.Opcode.RealDiv; - } else SynErr(119); + } else SynErr(121); } void UnaryExpression(out Expr/*!*/ e) { @@ -1616,7 +1616,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { e = Expr.Unary(x, UnaryOperator.Opcode.Not, e); } else if (StartOf(14)) { CoercionExpression(out e); - } else SynErr(120); + } else SynErr(122); } void NegOp() { @@ -1624,7 +1624,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { Get(); } else if (la.kind == 81) { Get(); - } else SynErr(121); + } else SynErr(123); } void CoercionExpression(out Expr/*!*/ e) { @@ -1648,7 +1648,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { e = new BvBounds(x, bn, ((LiteralExpr)e).asBigNum); } - } else SynErr(122); + } else SynErr(124); } } @@ -1749,7 +1749,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { e = new LiteralExpr(t, bd); break; } - case 135: { + case 97: { Float(out fp); e = new LiteralExpr(t, fp); break; @@ -1769,7 +1769,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { e = new NAryExpr(x, new FunctionCall(id), es); } else if (la.kind == 10) { e = new NAryExpr(x, new FunctionCall(id), new List()); - } else SynErr(123); + } else SynErr(125); Expect(10); } break; @@ -1801,7 +1801,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToReal), new List{ e }); break; } - case 136: { + case 98: { Get(); x = t; Expect(9); @@ -1837,7 +1837,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { SemErr("triggers not allowed in lambda expressions"); if (typeParams.Count + ds.Count > 0) e = new LambdaExpr(x, typeParams, ds, kv, e); - } else SynErr(124); + } else SynErr(126); Expect(10); break; } @@ -1850,7 +1850,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { e = new CodeExpr(locals, blocks); break; } - default: SynErr(125); break; + default: SynErr(127); break; } } @@ -1862,7 +1862,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } else if (la.kind == 6) { Get(); s = t.val; - } else SynErr(126); + } else SynErr(128); try { n = BigDec.FromString(s); } catch (FormatException) { @@ -1880,10 +1880,10 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { { //To be modified string s = ""; - if (la.kind == 135) { + if (la.kind == 97) { Get(); s = t.val; - } else SynErr(126); + } else SynErr(128); try { n = BigFloat.FromString(s); } catch (FormatException) { @@ -1913,7 +1913,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { Get(); } else if (la.kind == 89) { Get(); - } else SynErr(127); + } else SynErr(129); } void QuantifierBody(IToken/*!*/ q, out List/*!*/ typeParams, out List/*!*/ ds, @@ -1931,7 +1931,7 @@ out QKeyValue kv, out Trigger trig, out Expr/*!*/ body) { } } else if (la.kind == 1 || la.kind == 27) { BoundVars(q, out ds); - } else SynErr(128); + } else SynErr(130); QSep(); while (la.kind == 27) { AttributeOrTrigger(ref kv, ref trig); @@ -1944,7 +1944,7 @@ out QKeyValue kv, out Trigger trig, out Expr/*!*/ body) { Get(); } else if (la.kind == 91) { Get(); - } else SynErr(129); + } else SynErr(131); } void Lambda() { @@ -1952,7 +1952,7 @@ out QKeyValue kv, out Trigger trig, out Expr/*!*/ body) { Get(); } else if (la.kind == 93) { Get(); - } else SynErr(130); + } else SynErr(132); } void IfThenElseExpression(out Expr/*!*/ e) { @@ -2022,7 +2022,7 @@ out QKeyValue kv, out Trigger trig, out Expr/*!*/ body) { Get(); Expression(out e); b = new Block(x,x.val,cs,new ReturnExprCmd(t,e)); - } else SynErr(131); + } else SynErr(133); Expect(8); } @@ -2079,7 +2079,7 @@ out QKeyValue kv, out Trigger trig, out Expr/*!*/ body) { trig.AddLast(new Trigger(tok, true, es, null)); } - } else SynErr(132); + } else SynErr(134); Expect(28); } @@ -2094,7 +2094,7 @@ out QKeyValue kv, out Trigger trig, out Expr/*!*/ body) { } else if (StartOf(9)) { Expression(out e); o = e; - } else SynErr(133); + } else SynErr(135); } void QSep() { @@ -2102,7 +2102,7 @@ out QKeyValue kv, out Trigger trig, out Expr/*!*/ body) { Get(); } else if (la.kind == 95) { Get(); - } else SynErr(134); + } else SynErr(136); } @@ -2158,7 +2158,7 @@ public class Errors { /// /// Returns a string corresponding to the syntax error of the given type - /// Note that many of these errors (0-96, 135, 136) correspond to token types (e.g. the la token) + /// Note that many of these errors (0-98) correspond to token types (e.g. the la token) /// /// /// @@ -2262,46 +2262,46 @@ public class Errors { case 94: s = "\"::\" expected"; break; case 95: s = "\"\\u2022\" expected"; break; case 96: s = "??? expected"; break; - case 97: s = "invalid Function"; break; - case 98: s = "invalid Function"; break; - case 99: s = "invalid Procedure"; break; - case 100: s = "invalid Type"; break; - case 101: s = "invalid TypeAtom"; break; - case 102: s = "invalid TypeArgs"; break; - case 103: s = "invalid Spec"; break; - case 104: s = "invalid SpecPrePost"; break; - case 105: s = "invalid LabelOrCmd"; break; - case 106: s = "invalid StructuredCmd"; break; - case 107: s = "invalid TransferCmd"; break; - case 108: s = "invalid IfCmd"; break; - case 109: s = "invalid Guard"; break; - case 110: s = "invalid LabelOrAssign"; break; - case 111: s = "invalid CallParams"; break; - case 112: s = "invalid EquivOp"; break; - case 113: s = "invalid ImpliesOp"; break; - case 114: s = "invalid ExpliesOp"; break; - case 115: s = "invalid AndOp"; break; - case 116: s = "invalid OrOp"; break; - case 117: s = "invalid RelOp"; break; - case 118: s = "invalid AddOp"; break; - case 119: s = "invalid MulOp"; break; - case 120: s = "invalid UnaryExpression"; break; - case 121: s = "invalid NegOp"; break; - case 122: s = "invalid CoercionExpression"; break; - case 123: s = "invalid AtomExpression"; break; - case 124: s = "invalid AtomExpression"; break; + case 97: s = "fp expected"; break; + case 98: s = "\"float\" expected"; break; + case 99: s = "invalid Function"; break; + case 100: s = "invalid Function"; break; + case 101: s = "invalid Procedure"; break; + case 102: s = "invalid Type"; break; + case 103: s = "invalid TypeAtom"; break; + case 104: s = "invalid TypeArgs"; break; + case 105: s = "invalid Spec"; break; + case 106: s = "invalid SpecPrePost"; break; + case 107: s = "invalid LabelOrCmd"; break; + case 108: s = "invalid StructuredCmd"; break; + case 109: s = "invalid TransferCmd"; break; + case 110: s = "invalid IfCmd"; break; + case 111: s = "invalid Guard"; break; + case 112: s = "invalid LabelOrAssign"; break; + case 113: s = "invalid CallParams"; break; + case 114: s = "invalid EquivOp"; break; + case 115: s = "invalid ImpliesOp"; break; + case 116: s = "invalid ExpliesOp"; break; + case 117: s = "invalid AndOp"; break; + case 118: s = "invalid OrOp"; break; + case 119: s = "invalid RelOp"; break; + case 120: s = "invalid AddOp"; break; + case 121: s = "invalid MulOp"; break; + case 122: s = "invalid UnaryExpression"; break; + case 123: s = "invalid NegOp"; break; + case 124: s = "invalid CoercionExpression"; break; case 125: s = "invalid AtomExpression"; break; - case 126: s = "invalid Dec"; break; - case 127: s = "invalid Forall"; break; - case 128: s = "invalid QuantifierBody"; break; - case 129: s = "invalid Exists"; break; - case 130: s = "invalid Lambda"; break; - case 131: s = "invalid SpecBlock"; break; - case 132: s = "invalid AttributeOrTrigger"; break; - case 133: s = "invalid AttributeParameter"; break; - case 134: s = "invalid QSep"; break; - case 135: s = "fp expected"; break; - case 136: s = "\"float\" expected"; break; + case 126: s = "invalid AtomExpression"; break; + case 127: s = "invalid AtomExpression"; break; + case 128: s = "invalid Dec"; break; + case 129: s = "invalid Forall"; break; + case 130: s = "invalid QuantifierBody"; break; + case 131: s = "invalid Exists"; break; + case 132: s = "invalid Lambda"; break; + case 133: s = "invalid SpecBlock"; break; + case 134: s = "invalid AttributeOrTrigger"; break; + case 135: s = "invalid AttributeParameter"; break; + case 136: s = "invalid QSep"; break; default: s = "error " + n; break; } diff --git a/Source/Core/Scanner.cs b/Source/Core/Scanner.cs index 2e49726e..9ac26b7b 100644 --- a/Source/Core/Scanner.cs +++ b/Source/Core/Scanner.cs @@ -502,7 +502,6 @@ public class Scanner { void CheckLiteral() { - Console.Write(t.val + " is a literal"); switch (t.val) { case "var": t.kind = 7; break; case "where": t.kind = 13; break; @@ -549,7 +548,6 @@ public class Scanner { case "lambda": t.kind = 92; break; default: break; } - Console.WriteLine(" and is kind " + t.kind); } Token/*!*/ NextToken() { @@ -779,7 +777,6 @@ public class Scanner { } t.val = new String(tval, 0, tlen); - Console.WriteLine("Scanning a token with value " + t._val); return t; } diff --git a/float_test2.bpl b/float_test2.bpl index 69b893c4..fa34d8cf 100644 --- a/float_test2.bpl +++ b/float_test2.bpl @@ -1,5 +1,5 @@ procedure F() returns () { - var x : real; - var y : real; - assert (x == y); + var x : float; + var y : float; + assert x == y; } \ No newline at end of file -- cgit v1.2.3 From eed63d900b802e5551bf3c31772c39d365e7fcec Mon Sep 17 00:00:00 2001 From: Dietrich Date: Sun, 26 Apr 2015 15:24:07 -0600 Subject: added float type to the set array in Parser --- Source/Core/Parser.cs | 48 ++++++++++++++++++++++++------------------------ Source/Core/Scanner.cs | 2 +- float_test2.bpl | 4 ++-- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index 578b9e5f..9a664606 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -366,7 +366,7 @@ private class BvBounds : Expr { Get(); Type(out retTy); retTyd = new TypedIdent(retTy.tok, TypedIdent.NoName, retTy); - } else SynErr(99); + } else SynErr(97); if (la.kind == 27) { Get(); Expression(out tmp); @@ -374,7 +374,7 @@ private class BvBounds : Expr { Expect(28); } else if (la.kind == 8) { Get(); - } else SynErr(100); + } else SynErr(98); if (retTyd == null) { // construct a dummy type for the case of syntax error retTyd = new TypedIdent(t, TypedIdent.NoName, new BasicType(t, SimpleType.Int)); @@ -497,7 +497,7 @@ private class BvBounds : Expr { impl = new Implementation(x, x.val, typeParams, Formal.StripWhereClauses(ins), Formal.StripWhereClauses(outs), locals, stmtList, kv == null ? null : (QKeyValue)kv.Clone(), this.errors); - } else SynErr(101); + } else SynErr(99); proc = new Procedure(x, x.val, typeParams, ins, outs, pre, mods, post, kv); } @@ -610,7 +610,7 @@ private class BvBounds : Expr { ty = new UnresolvedTypeIdentifier (tok, tok.val, args); } else if (la.kind == 17 || la.kind == 19) { MapType(out ty); - } else SynErr(102); + } else SynErr(100); } void AttributesIdsTypeWhere(bool allowAttributes, bool allowWhereClauses, string context, System.Action action ) { @@ -677,7 +677,7 @@ private class BvBounds : Expr { Get(); Type(out ty); Expect(10); - } else SynErr(103); + } else SynErr(101); } void Ident(out IToken/*!*/ x) { @@ -707,7 +707,7 @@ private class BvBounds : Expr { } else if (la.kind == 17 || la.kind == 19) { MapType(out ty); ts.Add(ty); - } else SynErr(104); + } else SynErr(102); } void MapType(out Bpl.Type/*!*/ ty) { @@ -892,7 +892,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { SpecPrePost(true, pre, post); } else if (la.kind == 36 || la.kind == 37) { SpecPrePost(false, pre, post); - } else SynErr(105); + } else SynErr(103); } void ImplBody(out List/*!*/ locals, out StmtList/*!*/ stmtList) { @@ -924,7 +924,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { Proposition(out e); Expect(8); post.Add(new Ensures(tok, free, e, null, kv)); - } else SynErr(106); + } else SynErr(104); } void StmtList(out StmtList/*!*/ stmtList) { @@ -1063,7 +1063,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { c = new YieldCmd(x); break; } - default: SynErr(107); break; + default: SynErr(105); break; } } @@ -1080,7 +1080,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } else if (la.kind == 45) { BreakCmd(out bcmd); ec = bcmd; - } else SynErr(108); + } else SynErr(106); } void TransferCmd(out TransferCmd/*!*/ tc) { @@ -1100,7 +1100,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } else if (la.kind == 39) { Get(); tc = new ReturnCmd(t); - } else SynErr(109); + } else SynErr(107); Expect(8); } @@ -1125,7 +1125,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { Get(); StmtList(out els); elseOption = els; - } else SynErr(110); + } else SynErr(108); } ifcmd = new IfCmd(x, guard, thn, elseIfOption, elseOption); } @@ -1189,7 +1189,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } else if (StartOf(9)) { Expression(out ee); e = ee; - } else SynErr(111); + } else SynErr(109); Expect(10); } @@ -1236,7 +1236,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } Expect(8); c = new AssignCmd(x, lhss, rhss); - } else SynErr(112); + } else SynErr(110); } void CallCmd(out Cmd c) { @@ -1353,7 +1353,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } Expect(10); c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync; - } else SynErr(113); + } else SynErr(111); } void Expressions(out List/*!*/ es) { @@ -1398,7 +1398,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { Get(); } else if (la.kind == 56) { Get(); - } else SynErr(114); + } else SynErr(112); } void LogicalExpression(out Expr/*!*/ e0) { @@ -1436,7 +1436,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { Get(); } else if (la.kind == 58) { Get(); - } else SynErr(115); + } else SynErr(113); } void ExpliesOp() { @@ -1444,7 +1444,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { Get(); } else if (la.kind == 60) { Get(); - } else SynErr(116); + } else SynErr(114); } void RelationalExpression(out Expr/*!*/ e0) { @@ -1462,7 +1462,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { Get(); } else if (la.kind == 62) { Get(); - } else SynErr(117); + } else SynErr(115); } void OrOp() { @@ -1470,7 +1470,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { Get(); } else if (la.kind == 64) { Get(); - } else SynErr(118); + } else SynErr(116); } void BvTerm(out Expr/*!*/ e0) { @@ -1537,7 +1537,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { x = t; op=BinaryOperator.Opcode.Ge; break; } - default: SynErr(119); break; + default: SynErr(117); break; } } @@ -1569,7 +1569,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } else if (la.kind == 75) { Get(); x = t; op=BinaryOperator.Opcode.Sub; - } else SynErr(120); + } else SynErr(118); } void Power(out Expr/*!*/ e0) { @@ -1597,7 +1597,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { } else if (la.kind == 78) { Get(); x = t; op=BinaryOperator.Opcode.RealDiv; - } else SynErr(121); + } else SynErr(119); } void UnaryExpression(out Expr/*!*/ e) { @@ -1616,7 +1616,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { e = Expr.Unary(x, UnaryOperator.Opcode.Not, e); } else if (StartOf(14)) { CoercionExpression(out e); - } else SynErr(122); + } else SynErr(120); } void NegOp() { diff --git a/Source/Core/Scanner.cs b/Source/Core/Scanner.cs index 9ac26b7b..c41d0a9e 100644 --- a/Source/Core/Scanner.cs +++ b/Source/Core/Scanner.cs @@ -508,7 +508,7 @@ public class Scanner { case "int": t.kind = 14; break; case "real": t.kind = 15; break; case "bool": t.kind = 16; break; - case "float": t.kind = 136; break; + case "float": t.kind = 98; break; case "const": t.kind = 21; break; case "unique": t.kind = 22; break; case "extends": t.kind = 23; break; diff --git a/float_test2.bpl b/float_test2.bpl index fa34d8cf..71ea7dee 100644 --- a/float_test2.bpl +++ b/float_test2.bpl @@ -1,5 +1,5 @@ procedure F() returns () { - var x : float; - var y : float; + var x : real; + var y : real; assert x == y; } \ No newline at end of file -- cgit v1.2.3 From 1797c235986f576998e28380e1ec4e6005087ebb Mon Sep 17 00:00:00 2001 From: Dietrich Date: Sun, 26 Apr 2015 16:21:38 -0600 Subject: Successfully parsed the float type --- Source/Core/Parser.cs | 40 ++++++++++++++++++++-------------------- float_test2.bpl | 4 ++-- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index 9a664606..552b3824 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -24,7 +24,7 @@ public class Parser { public const int _string = 4; public const int _decimal = 5; public const int _float = 6; - public const int maxT = 96; + public const int maxT = 98; const bool T = true; const bool x = false; @@ -170,8 +170,8 @@ private class BvBounds : Expr { for (;;) { t = la; la = scanner.Scan(); - Console.WriteLine("Just got the value " + la.kind + " with value " + la.val); - if (la.kind <= maxT || la.kind > 134) { ++errDist; break; } //TODO: should modify float to have value < maxT... + //Console.WriteLine("Just got the value " + la.kind + " with value " + la.val); + if (la.kind <= maxT) { ++errDist; break; } //TODO: should modify float to have value < maxT... la = t; } @@ -2118,23 +2118,23 @@ out QKeyValue kv, out Trigger trig, out Expr/*!*/ body) { } static readonly bool[,]/*!*/ set = { //grid is 17 x 98 - {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,T, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,T,x,x, x,T,T,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, x,x,x,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,T,x,x, x,x,T,T, T,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,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x}, - {x,x,x,x, x,x,x,x, x,x,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,x,x,x, x,x}, - {x,x,x,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,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,T,x,x, x,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, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,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,T,x,x, x,x,T,T, T,T,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,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,T, x,x,T,T, T,x,T,x, x,T,T,T, 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,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,T, x,x,x,x, x,x,x,x, x,x,T,T, 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,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,T,T,x, x,T,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, 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,T, 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,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,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,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,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,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, 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, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x}, - {x,T,T,T, x,T,T,x, x,T,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, 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,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x}, - {x,T,T,T, x,T,T,x, x,T,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, 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,T, x,x,x,x, T,T,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x}, - {x,T,T,T, T,T,T,x, x,T,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, 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,T, x,x,x,x, T,T,T,T, T,T,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,T, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,T,x,x, x,T,T,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, x,x,x,x, x,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,T,x,x, x,x,T,T, T,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,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x}, + {x,x,x,x, x,x,x,x, x,x,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,x,x,x, x,x,x,x}, + {x,x,x,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,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,T,x,x, x,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, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,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,T,x,x, x,x,x,x, x,T,x,x, x,x,T,T, T,T,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,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,x,x,x, x,x,x,T, x,x,T,T, T,x,T,x, x,T,T,T, 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,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,T, x,x,x,x, x,x,x,x, x,x,T,T, 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,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,T,T,x, x,T,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, 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,T, 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, 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, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,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,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,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, 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, 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,T,T,T, x,T,T,x, x,T,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, 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,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x}, + {x,T,T,T, x,T,T,x, x,T,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, 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,T, 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,T,T,T, T,T,T,x, x,T,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, 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,T, x,x,x,x, T,T,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x} }; } // end Parser diff --git a/float_test2.bpl b/float_test2.bpl index 71ea7dee..fa34d8cf 100644 --- a/float_test2.bpl +++ b/float_test2.bpl @@ -1,5 +1,5 @@ procedure F() returns () { - var x : real; - var y : real; + var x : float; + var y : float; assert x == y; } \ No newline at end of file -- cgit v1.2.3 From 7b670a303c25dffb9b51ec74783a4b5fc995f432 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Sun, 26 Apr 2015 16:29:12 -0600 Subject: removed the last console writes (used for testing) --- Source/Core/Parser.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index 552b3824..a41597f3 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -170,7 +170,6 @@ private class BvBounds : Expr { for (;;) { t = la; la = scanner.Scan(); - //Console.WriteLine("Just got the value " + la.kind + " with value " + la.val); if (la.kind <= maxT) { ++errDist; break; } //TODO: should modify float to have value < maxT... la = t; @@ -598,7 +597,6 @@ private class BvBounds : Expr { void Type(out Bpl.Type/*!*/ ty) { Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken/*!*/ tok; ty = dummyType; - Console.WriteLine(la.kind + " from parser.Type"); if (StartOf(5)) { TypeAtom(out ty); } else if (la.kind == 1) { -- cgit v1.2.3 From 45a783affd5b5c070e56850b1ba662bb3f3d7a21 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Mon, 27 Apr 2015 04:11:19 -0600 Subject: Finished up Parser modifications --- Source/Core/Parser.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index a41597f3..b333f654 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -24,6 +24,7 @@ public class Parser { public const int _string = 4; public const int _decimal = 5; public const int _float = 6; + public const int _fp = 97; public const int maxT = 98; const bool T = true; @@ -170,7 +171,7 @@ private class BvBounds : Expr { for (;;) { t = la; la = scanner.Scan(); - if (la.kind <= maxT) { ++errDist; break; } //TODO: should modify float to have value < maxT... + if (la.kind <= maxT) { ++errDist; break; } la = t; } @@ -2115,7 +2116,7 @@ out QKeyValue kv, out Trigger trig, out Expr/*!*/ body) { Expect(0); } - static readonly bool[,]/*!*/ set = { //grid is 17 x 98 + static readonly bool[,]/*!*/ set = { //grid is 17 x 100 {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,T, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,T,x,x, x,T,T,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, x,x,x,x, x,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,T,x,x, x,x,T,T, T,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,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x}, -- cgit v1.2.3 From 94a9542de594ef210d1ede1ff05e12289dfb2dc7 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Mon, 27 Apr 2015 04:39:39 -0600 Subject: Added float operations to AbsyExpr. Note that float operations work as real operations at the moment --- Source/Core/AbsyExpr.cs | 109 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 92 insertions(+), 17 deletions(-) diff --git a/Source/Core/AbsyExpr.cs b/Source/Core/AbsyExpr.cs index c0966256..a8c82f08 100644 --- a/Source/Core/AbsyExpr.cs +++ b/Source/Core/AbsyExpr.cs @@ -313,6 +313,13 @@ namespace Microsoft.Boogie { Contract.Ensures(Contract.Result() != null); return Binary(BinaryOperator.Opcode.RealDiv, e1, e2); } + public static NAryExpr FloatDiv(Expr e1, Expr e2) + { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.FloatDiv, e1, e2); + } public static NAryExpr Pow(Expr e1, Expr e2) { Contract.Requires(e2 != null); Contract.Requires(e1 != null); @@ -496,7 +503,7 @@ namespace Microsoft.Boogie { } public class LiteralExpr : Expr { - public readonly object/*!*/ Val; // false, true, a BigNum, a BigDec, or a BvConst + public readonly object/*!*/ Val; // false, true, a BigNum, a BigDec, a BigFloat, or a BvConst [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(Val != null); @@ -544,19 +551,6 @@ namespace Microsoft.Boogie { CachedHashCode = ComputeHashCode(); } - /// - /// Creates a literal expression for the bitvector value "v". - /// - public LiteralExpr(IToken/*!*/ tok, BigNum v, int b, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Contract.Requires(0 <= b); - Val = new BvConst(v, b); - Type = Type.GetBvType(b); - if (immutable) - CachedHashCode = ComputeHashCode(); - } - /// /// Creates a literal expression for the floating point value "v". /// @@ -572,6 +566,19 @@ namespace Microsoft.Boogie { CachedHashCode = ComputeHashCode(); } + /// + /// Creates a literal expression for the bitvector value "v". + /// + public LiteralExpr(IToken/*!*/ tok, BigNum v, int b, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Contract.Requires(0 <= b); + Val = new BvConst(v, b); + Type = Type.GetBvType(b); + if (immutable) + CachedHashCode = ComputeHashCode(); + } + [Pure] [Reads(ReadsAttribute.Reads.Nothing)] public override bool Equals(object obj) { @@ -680,6 +687,14 @@ namespace Microsoft.Boogie { } } + public bool isBigFloat + { + get + { + return Val is BigFloat; + } + } + public BigDec asBigDec { get { Contract.Assert(isBigDec); @@ -687,6 +702,13 @@ namespace Microsoft.Boogie { } } + public BigFloat asBigFloat { + get { + Contract.Assert(isBigFloat); + return (BigFloat)cce.NonNull(Val); + } + } + public bool isBool { get { return Val is bool; @@ -1354,6 +1376,9 @@ namespace Microsoft.Boogie { if (arg0type.Unify(Type.Real)) { return Type.Real; } + if (arg0type.Unify(Type.Float)) { + return Type.Float; + } goto BAD_TYPE; case Opcode.Not: if (arg0type.Unify(Type.Bool)) { @@ -1398,6 +1423,9 @@ namespace Microsoft.Boogie { if (argument is BigDec) { return -((BigDec)argument); } + if (argument is BigFloat) { + return -((BigFloat)argument); + } break; case Opcode.Not: if (argument is bool) { @@ -1430,6 +1458,7 @@ namespace Microsoft.Boogie { Div, Mod, RealDiv, + FloatDiv, Pow, Eq, Neq, @@ -1489,6 +1518,8 @@ namespace Microsoft.Boogie { return "mod"; case Opcode.RealDiv: return "/"; + case Opcode.FloatDiv: + return "/f"; case Opcode.Pow: return "**"; case Opcode.Eq: @@ -1551,6 +1582,10 @@ namespace Microsoft.Boogie { opBindingStrength = 0x50; fragileRightContext = true; break; + case Opcode.FloatDiv: //TODO: Modify (potentially) + opBindingStrength = 0x50; + fragileRightContext = true; + break; case Opcode.Pow: opBindingStrength = 0x60; fragileRightContext = true; @@ -1612,6 +1647,7 @@ namespace Microsoft.Boogie { case Opcode.Div: case Opcode.Mod: case Opcode.RealDiv: + case Opcode.FloatDiv: case Opcode.Pow: case Opcode.Neq: // Neq is allowed, but not Eq case Opcode.Subtype: @@ -1683,6 +1719,13 @@ namespace Microsoft.Boogie { return Type.Real; } goto BAD_TYPE; + case Opcode.FloatDiv: //TODO: Modify + if ((arg0type.Unify(Type.Int) || arg0type.Unify(Type.Real) || arg0type.Unify(Type.Float)) && + (arg1type.Unify(Type.Int) || arg1type.Unify(Type.Real) || arg0type.Unify(Type.Float))) + { + return Type.Float; + } + goto BAD_TYPE; case Opcode.Pow: if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { return Type.Real; @@ -1758,6 +1801,9 @@ namespace Microsoft.Boogie { case Opcode.Pow: return Type.Real; + case Opcode.FloatDiv: + return Type.Float; + case Opcode.Eq: case Opcode.Neq: case Opcode.Gt: @@ -1824,6 +1870,9 @@ namespace Microsoft.Boogie { if (e1 is BigDec && e2 is BigDec) { return ((BigDec)e1) + ((BigDec)e2); } + if (e1 is BigFloat && e2 is BigFloat) { + return ((BigFloat)e1) + ((BigFloat)e2); + } break; case Opcode.Sub: if (e1 is BigNum && e2 is BigNum) { @@ -1832,6 +1881,9 @@ namespace Microsoft.Boogie { if (e1 is BigDec && e2 is BigDec) { return ((BigDec)e1) - ((BigDec)e2); } + if (e1 is BigFloat && e2 is BigFloat) { + return ((BigFloat)e1) - ((BigFloat)e2); + } break; case Opcode.Mul: if (e1 is BigNum && e2 is BigNum) { @@ -1840,6 +1892,9 @@ namespace Microsoft.Boogie { if (e1 is BigDec && e2 is BigDec) { return ((BigDec)e1) * ((BigDec)e2); } + if (e1 is BigFloat && e2 is BigFloat) { + return ((BigFloat)e1) * ((BigFloat)e2); + } break; case Opcode.Div: if (e1 is BigNum && e2 is BigNum) { @@ -1854,6 +1909,9 @@ namespace Microsoft.Boogie { case Opcode.RealDiv: // TODO: add partial evaluation fro real division break; + case Opcode.FloatDiv: + //TODO: add float division + break; case Opcode.Pow: // TODO: add partial evaluation fro real exponentiation break; @@ -1864,6 +1922,9 @@ namespace Microsoft.Boogie { if (e1 is BigDec && e2 is BigDec) { return ((BigDec)e1) < ((BigDec)e2); } + if (e1 is BigFloat && e2 is BigFloat) { + return ((BigFloat)e1) < ((BigFloat)e2); + } break; case Opcode.Le: if (e1 is BigNum && e2 is BigNum) { @@ -1872,6 +1933,9 @@ namespace Microsoft.Boogie { if (e1 is BigDec && e2 is BigDec) { return ((BigDec)e1) <= ((BigDec)e2); } + if (e1 is BigFloat && e2 is BigFloat) { + return ((BigFloat)e1) <= ((BigFloat)e2); + } break; case Opcode.Gt: if (e1 is BigNum && e2 is BigNum) { @@ -1880,6 +1944,9 @@ namespace Microsoft.Boogie { if (e1 is BigDec && e2 is BigDec) { return ((BigDec)e1) > ((BigDec)e2); } + if (e1 is BigFloat && e2 is BigFloat) { + return ((BigFloat)e1) > ((BigFloat)e2); + } break; case Opcode.Ge: if (e1 is BigNum && e2 is BigNum) { @@ -1888,6 +1955,9 @@ namespace Microsoft.Boogie { if (e1 is BigDec && e2 is BigDec) { return ((BigDec)e1) >= ((BigDec)e2); } + if (e1 is BigFloat && e2 is BigFloat) { + return ((BigFloat)e1) >= ((BigFloat)e2); + } break; case Opcode.And: @@ -2177,6 +2247,7 @@ namespace Microsoft.Boogie { private readonly string name; private readonly Type type; private readonly Type argType; + private readonly Type argType2; private readonly int hashCode; public ArithmeticCoercion(IToken tok, CoercionType coercion) { @@ -2188,18 +2259,21 @@ namespace Microsoft.Boogie { this.name = "int"; this.type = Type.Int; this.argType = Type.Real; + this.argType2 = Type.Float; this.hashCode = 1; break; case CoercionType.ToReal: this.name = "real"; this.type = Type.Real; this.argType = Type.Int; + this.argType2 = Type.Float; this.hashCode = 2; break; case CoercionType.ToFloat: this.name = "float"; - this.type = Type.Real; + this.type = Type.Float; this.argType = Type.Int; + this.argType2 = Type.Real; this.hashCode = 3; break; default: @@ -2262,8 +2336,9 @@ namespace Microsoft.Boogie { tpInstantiation = SimpleTypeParamInstantiation.EMPTY; - if (!cce.NonNull(cce.NonNull(args[0]).Type).Unify(argType)) { - tc.Error(this.tok, "argument type {0} does not match expected type {1}", cce.NonNull(args[0]).Type, this.argType); + if (!(cce.NonNull(cce.NonNull(args[0]).Type).Unify(argType) || cce.NonNull(cce.NonNull(args[0]).Type).Unify(argType2))) + { + tc.Error(this.tok, "argument type {0} does not match expected type {1} or type {2}", cce.NonNull(args[0]).Type, this.argType, this.argType2); } return this.type; -- cgit v1.2.3 From 2dae113e5996e050ca6595542de5030747245929 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Mon, 27 Apr 2015 05:37:19 -0600 Subject: Began adding the float type to VC expression --- Source/Core/AbsyExpr.cs | 8 ++++++ Source/Provers/SMTLib/SMTLibLineariser.cs | 12 +++++++++ Source/VCExpr/Boogie2VCExpr.cs | 10 +++++-- Source/VCExpr/SimplifyLikeLineariser.cs | 36 ++++++++++++++++++++++--- Source/VCExpr/VCExprAST.cs | 45 ++++++++++++++++++++++++++++++- Source/VCExpr/VCExprASTPrinter.cs | 12 +++++++++ Source/VCExpr/VCExprASTVisitors.cs | 23 ++++++++++++++++ Test/test1/IntReal.bpl.expect | 4 +-- float_test3.bpl | 6 +++++ 9 files changed, 148 insertions(+), 8 deletions(-) create mode 100644 float_test3.bpl diff --git a/Source/Core/AbsyExpr.cs b/Source/Core/AbsyExpr.cs index a8c82f08..9297bcbc 100644 --- a/Source/Core/AbsyExpr.cs +++ b/Source/Core/AbsyExpr.cs @@ -1706,6 +1706,10 @@ namespace Microsoft.Boogie { if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { return Type.Real; } + if (arg0type.Unify(Type.Float) && arg1type.Unify(Type.Float)) + { + return Type.Float; + } goto BAD_TYPE; case Opcode.Div: case Opcode.Mod: @@ -1757,6 +1761,10 @@ namespace Microsoft.Boogie { if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { return Type.Bool; } + if (arg0type.Unify(Type.Float) && arg1type.Unify(Type.Float)) + { + return Type.Bool; + } goto BAD_TYPE; case Opcode.And: case Opcode.Or: diff --git a/Source/Provers/SMTLib/SMTLibLineariser.cs b/Source/Provers/SMTLib/SMTLibLineariser.cs index f431c3d5..6accf79f 100644 --- a/Source/Provers/SMTLib/SMTLibLineariser.cs +++ b/Source/Provers/SMTLib/SMTLibLineariser.cs @@ -678,6 +678,12 @@ namespace Microsoft.Boogie.SMTLib return true; } + public bool VisitFloatDivOp(VCExprNAry node, LineariserOptions options) + { + WriteApplication("/f", node, options); + return true; + } + public bool VisitPowOp(VCExprNAry node, LineariserOptions options) { WriteApplication("real_pow", node, options); return true; @@ -729,6 +735,12 @@ namespace Microsoft.Boogie.SMTLib return true; } + public bool VisitToFloatOp(VCExprNAry node, LineariserOptions options) + { + WriteApplication("to_float", node, options); + return true; + } + private string ExtractDatatype(Function func) { if (func is DatatypeSelector) { DatatypeSelector selector = (DatatypeSelector) func; diff --git a/Source/VCExpr/Boogie2VCExpr.cs b/Source/VCExpr/Boogie2VCExpr.cs index 8674f8c0..aa246c37 100644 --- a/Source/VCExpr/Boogie2VCExpr.cs +++ b/Source/VCExpr/Boogie2VCExpr.cs @@ -334,7 +334,10 @@ namespace Microsoft.Boogie.VCExprAST { return Gen.Integer(node.asBigNum); } else if (node.Val is BigDec) { return Gen.Real(node.asBigDec); - } else if (node.Val is BvConst) { + } else if (node.Val is BigFloat) { + return Gen.Float(node.asBigFloat); + } + else if (node.Val is BvConst) { return Gen.Bitvector((BvConst)node.Val); } else { System.Diagnostics.Debug.Assert(false, "unknown kind of literal " + node.tok.ToString()); @@ -1002,9 +1005,12 @@ namespace Microsoft.Boogie.VCExprAST { if (cce.NonNull(e.Type).IsInt) { return Gen.Function(VCExpressionGenerator.SubIOp, Gen.Integer(BigNum.ZERO), e); } - else { + else if (cce.NonNull(e.Type).IsReal) { return Gen.Function(VCExpressionGenerator.SubROp, Gen.Real(BigDec.ZERO), e); } + else {//is float + return Gen.Function(VCExpressionGenerator.SubFOp, Gen.Float(BigFloat.ZERO), e); + } } else { return Gen.Not(this.args); diff --git a/Source/VCExpr/SimplifyLikeLineariser.cs b/Source/VCExpr/SimplifyLikeLineariser.cs index e0a4b4c6..0ff6d67f 100644 --- a/Source/VCExpr/SimplifyLikeLineariser.cs +++ b/Source/VCExpr/SimplifyLikeLineariser.cs @@ -380,9 +380,14 @@ namespace Microsoft.Boogie.VCExprAST { internal const string realSubName = "realSub"; internal const string realMulName = "realMul"; internal const string realDivName = "realDiv"; + internal const string floatAddName = "floatAdd"; + internal const string floatSubName = "floatSub"; + internal const string floatMulName = "floatMul"; + internal const string floatDivName = "floatDiv"; internal const string realPowName = "realPow"; internal const string toIntName = "toIntCoercion"; internal const string toRealName = "toRealCoercion"; + internal const string toFloatName = "toFloatCoercion"; internal void AssertAsTerm(string x, LineariserOptions options) { Contract.Requires(options != null); @@ -943,9 +948,12 @@ namespace Microsoft.Boogie.VCExprAST { WriteTermApplication(intAddName, node, options); } } - else { + else if (node.Type.IsReal) { WriteTermApplication(realAddName, node, options); } + else { + WriteTermApplication(floatAddName, node, options); + } return true; } @@ -955,9 +963,12 @@ namespace Microsoft.Boogie.VCExprAST { if (node.Type.IsInt) { WriteTermApplication(intSubName, node, options); } - else { + else if (node.Type.IsReal) { WriteTermApplication(realSubName, node, options); } + else { + WriteTermApplication(floatSubName, node, options); + } return true; } @@ -967,9 +978,12 @@ namespace Microsoft.Boogie.VCExprAST { if (node.Type.IsInt) { WriteTermApplication(intMulName, node, options); } - else { + else if (node.Type.IsReal) { WriteTermApplication(realMulName, node, options); } + else { + WriteTermApplication(floatMulName, node, options); + } return true; } @@ -994,6 +1008,14 @@ namespace Microsoft.Boogie.VCExprAST { return true; } + public bool VisitFloatDivOp(VCExprNAry node, LineariserOptions options) + { + //Contract.Requires(options != null); + //Contract.Requires(node != null); + WriteTermApplication(floatDivName, node, options); + return true; + } + public bool VisitPowOp(VCExprNAry node, LineariserOptions options) { //Contract.Requires(options != null); //Contract.Requires(node != null); @@ -1057,6 +1079,14 @@ namespace Microsoft.Boogie.VCExprAST { return true; } + public bool VisitToFloatOp(VCExprNAry node, LineariserOptions options) + { + //Contract.Requires(options != null); + //Contract.Requires(node != null); + WriteApplication(toFloatName, node, options); + return true; + } + public bool VisitBoogieFunctionOp(VCExprNAry node, LineariserOptions options) { //Contract.Requires(options != null); //Contract.Requires(node != null); diff --git a/Source/VCExpr/VCExprAST.cs b/Source/VCExpr/VCExprAST.cs index 4f8dc08e..291d6d42 100644 --- a/Source/VCExpr/VCExprAST.cs +++ b/Source/VCExpr/VCExprAST.cs @@ -55,6 +55,13 @@ namespace Microsoft.Boogie { return new VCExprRealLit(x); } + public VCExpr/*!*/ Float(BigFloat x) + { + Contract.Ensures(Contract.Result() != null); + + return new VCExprFloatLit(x); + } + public VCExpr/*!*/ Function(VCExprOp/*!*/ op, List/*!*/ arguments, List/*!*/ typeArguments) { @@ -317,12 +324,16 @@ namespace Microsoft.Boogie { public static readonly VCExprOp AddIOp = new VCExprNAryOp(2, Type.Int); public static readonly VCExprOp AddROp = new VCExprNAryOp(2, Type.Real); + public static readonly VCExprOp AddFOp = new VCExprNAryOp(2, Type.Float); public static readonly VCExprOp SubIOp = new VCExprNAryOp(2, Type.Int); public static readonly VCExprOp SubROp = new VCExprNAryOp(2, Type.Real); + public static readonly VCExprOp SubFOp = new VCExprNAryOp(2, Type.Float); public static readonly VCExprOp MulIOp = new VCExprNAryOp(2, Type.Int); public static readonly VCExprOp MulROp = new VCExprNAryOp(2, Type.Real); + public static readonly VCExprOp MulFOp = new VCExprNAryOp(2, Type.Float); public static readonly VCExprOp DivIOp = new VCExprNAryOp(2, Type.Int); public static readonly VCExprOp DivROp = new VCExprNAryOp(2, Type.Real); + public static readonly VCExprOp DivFOp = new VCExprNAryOp(2, Type.Float); public static readonly VCExprOp ModOp = new VCExprNAryOp(2, Type.Int); public static readonly VCExprOp PowOp = new VCExprNAryOp(2, Type.Real); public static readonly VCExprOp LtOp = new VCExprNAryOp(2, Type.Bool); @@ -336,6 +347,7 @@ namespace Microsoft.Boogie { public static readonly VCExprOp IfThenElseOp = new VCExprIfThenElseOp(); public static readonly VCExprOp ToIntOp = new VCExprNAryOp(1, Type.Int); public static readonly VCExprOp ToRealOp = new VCExprNAryOp(1, Type.Real); + public static readonly VCExprOp ToFloatOp = new VCExprNAryOp(1, Type.Float); public static readonly VCExprOp TickleBoolOp = new VCExprCustomOp("tickleBool", 1, Type.Bool); @@ -391,6 +403,7 @@ namespace Microsoft.Boogie { DivOp, ModOp, RealDivOp, + FloatDivOp, PowOp, LtOp, LeOp, @@ -400,7 +413,8 @@ namespace Microsoft.Boogie { Subtype3Op, BvConcatOp, ToIntOp, - ToRealOp + ToRealOp, + ToFloatOp }; internal static Dictionary/*!*/ SingletonOpDict; [ContractInvariantMethod] @@ -425,6 +439,7 @@ namespace Microsoft.Boogie { SingletonOpDict.Add(MulROp, SingletonOp.MulOp); SingletonOpDict.Add(DivIOp, SingletonOp.DivOp); SingletonOpDict.Add(DivROp, SingletonOp.RealDivOp); + SingletonOpDict.Add(DivFOp, SingletonOp.FloatDivOp); SingletonOpDict.Add(ModOp, SingletonOp.ModOp); SingletonOpDict.Add(PowOp, SingletonOp.PowOp); SingletonOpDict.Add(LtOp, SingletonOp.LtOp); @@ -435,6 +450,7 @@ namespace Microsoft.Boogie { SingletonOpDict.Add(Subtype3Op, SingletonOp.Subtype3Op); SingletonOpDict.Add(ToIntOp, SingletonOp.ToIntOp); SingletonOpDict.Add(ToRealOp, SingletonOp.ToRealOp); + SingletonOpDict.Add(ToFloatOp, SingletonOp.ToFloatOp); } //////////////////////////////////////////////////////////////////////////////// @@ -856,6 +872,31 @@ namespace Microsoft.Boogie.VCExprAST { } } + public class VCExprFloatLit : VCExprLiteral + { + public readonly BigFloat Val; + internal VCExprFloatLit(BigFloat val) + : base(Type.Float) + { + this.Val = val; + } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) + { + if (Object.ReferenceEquals(this, that)) + return true; + if (that is VCExprFloatLit) + return Val == ((VCExprFloatLit)that).Val; + return false; + } + [Pure] + public override int GetHashCode() + { + return Val.GetHashCode() * 72321; + } + } + ///////////////////////////////////////////////////////////////////////////////// // Operator expressions with fixed arity [ContractClassFor(typeof(VCExprNAry))] @@ -1265,6 +1306,8 @@ namespace Microsoft.Boogie.VCExprAST { return visitor.VisitModOp(expr, arg); case VCExpressionGenerator.SingletonOp.RealDivOp: return visitor.VisitRealDivOp(expr, arg); + case VCExpressionGenerator.SingletonOp.FloatDivOp: + return visitor.VisitFloatDivOp(expr, arg); case VCExpressionGenerator.SingletonOp.PowOp: return visitor.VisitPowOp(expr, arg); case VCExpressionGenerator.SingletonOp.LtOp: diff --git a/Source/VCExpr/VCExprASTPrinter.cs b/Source/VCExpr/VCExprASTPrinter.cs index 00e6fb9c..8b79b0e5 100644 --- a/Source/VCExpr/VCExprASTPrinter.cs +++ b/Source/VCExpr/VCExprASTPrinter.cs @@ -302,6 +302,12 @@ namespace Microsoft.Boogie.VCExprAST { //Contract.Requires(node != null); return PrintNAry("/", node, wr); } + public bool VisitFloatDivOp(VCExprNAry node, TextWriter wr) + { + //Contract.Requires(wr != null); + //Contract.Requires(node != null); + return PrintNAry("/f", node, wr); + } public bool VisitPowOp(VCExprNAry node, TextWriter wr) { //Contract.Requires(wr != null); //Contract.Requires(node != null); @@ -347,6 +353,12 @@ namespace Microsoft.Boogie.VCExprAST { //Contract.Requires(node != null); return PrintNAry("real", node, wr); } + public bool VisitToFloatOp(VCExprNAry node, TextWriter wr) + { + //Contract.Requires(wr != null); + //Contract.Requires(node != null); + return PrintNAry("float", node, wr); + } public bool VisitBoogieFunctionOp(VCExprNAry node, TextWriter wr) { //Contract.Requires(wr != null); //Contract.Requires(node != null); diff --git a/Source/VCExpr/VCExprASTVisitors.cs b/Source/VCExpr/VCExprASTVisitors.cs index ad0c270d..1bcce113 100644 --- a/Source/VCExpr/VCExprASTVisitors.cs +++ b/Source/VCExpr/VCExprASTVisitors.cs @@ -77,6 +77,7 @@ namespace Microsoft.Boogie.VCExprAST { Result VisitDivOp(VCExprNAry node, Arg arg); Result VisitModOp(VCExprNAry node, Arg arg); Result VisitRealDivOp(VCExprNAry node, Arg arg); + Result VisitFloatDivOp(VCExprNAry node, Arg arg); //TODO: Add this to references from above and below Result VisitPowOp(VCExprNAry node, Arg arg); Result VisitLtOp(VCExprNAry node, Arg arg); Result VisitLeOp(VCExprNAry node, Arg arg); @@ -189,6 +190,12 @@ namespace Microsoft.Boogie.VCExprAST { throw new NotImplementedException(); } + public Result VisitFloatDivOp(VCExprNAry node, Arg arg) + { + Contract.Requires(node != null); + throw new NotImplementedException(); + } + public Result VisitPowOp(VCExprNAry node, Arg arg) { Contract.Requires(node != null); throw new NotImplementedException(); @@ -234,6 +241,12 @@ namespace Microsoft.Boogie.VCExprAST { throw new NotImplementedException(); } + public Result VisitToFloat(VCExprNAry node, Arg arg) //TODO: modify later + { + Contract.Requires(node != null); + throw new NotImplementedException(); + } + public Result VisitBoogieFunctionOp(VCExprNAry node, Arg arg) { Contract.Requires(node != null); throw new NotImplementedException(); @@ -1482,6 +1495,11 @@ namespace Microsoft.Boogie.VCExprAST { //Contract.Requires(node != null); return StandardResult(node, arg); } + public virtual Result VisitFloatDivOp(VCExprNAry node, Arg arg) + { + //Contract.Requires(node != null); + return StandardResult(node, arg); + } public virtual Result VisitPowOp(VCExprNAry node, Arg arg) { //Contract.Requires(node != null); return StandardResult(node, arg); @@ -1518,6 +1536,11 @@ namespace Microsoft.Boogie.VCExprAST { //Contract.Requires(node != null); return StandardResult(node, arg); } + public virtual Result VisitToFloatOp(VCExprNAry node, Arg arg) + { + //Contract.Requires(node != null); + return StandardResult(node, arg); + } public virtual Result VisitBoogieFunctionOp(VCExprNAry node, Arg arg) { //Contract.Requires(node != null); return StandardResult(node, arg); diff --git a/Test/test1/IntReal.bpl.expect b/Test/test1/IntReal.bpl.expect index 021a8389..b532d22a 100644 --- a/Test/test1/IntReal.bpl.expect +++ b/Test/test1/IntReal.bpl.expect @@ -12,8 +12,8 @@ IntReal.bpl(19,12): Error: invalid argument types (real and int) to binary opera IntReal.bpl(25,8): Error: invalid argument types (int and real) to binary operator ** IntReal.bpl(29,14): Error: invalid argument types (real and int) to binary operator == IntReal.bpl(31,13): Error: invalid argument types (int and real) to binary operator == -IntReal.bpl(34,6): Error: argument type int does not match expected type real -IntReal.bpl(35,6): Error: argument type real does not match expected type int +IntReal.bpl(34,6): Error: argument type int does not match expected type real or type float +IntReal.bpl(35,6): Error: argument type real does not match expected type int or type float IntReal.bpl(47,8): Error: invalid argument types (real and int) to binary operator div IntReal.bpl(48,8): Error: invalid argument types (real and int) to binary operator mod 18 type checking errors detected in IntReal.bpl diff --git a/float_test3.bpl b/float_test3.bpl new file mode 100644 index 00000000..cd0ea59e --- /dev/null +++ b/float_test3.bpl @@ -0,0 +1,6 @@ + procedure F() returns () { + var x : float; + var y : float; + y := x - x; + assert y != x; +} \ No newline at end of file -- cgit v1.2.3 From 1058d935425fa9c9544fbf18dad184cd8333e0d9 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Mon, 27 Apr 2015 09:41:09 -0600 Subject: modified the third float_test slightly --- float_test3.bpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/float_test3.bpl b/float_test3.bpl index cd0ea59e..1b70ebf4 100644 --- a/float_test3.bpl +++ b/float_test3.bpl @@ -2,5 +2,5 @@ var x : float; var y : float; y := x - x; - assert y != x; + assert y == x; } \ No newline at end of file -- cgit v1.2.3 From d213a71b16a344dab7ac5d08507668abebffd21e Mon Sep 17 00:00:00 2001 From: Dietrich Date: Mon, 4 May 2015 03:46:22 -0600 Subject: integrated the named float type to act as a real in boogie --- Source/Provers/SMTLib/SMTLibLineariser.cs | 13 ++++++++++++- Source/Provers/SMTLib/TypeDeclCollector.cs | 2 +- Source/VCExpr/TypeErasure.cs | 7 +++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Source/Provers/SMTLib/SMTLibLineariser.cs b/Source/Provers/SMTLib/SMTLibLineariser.cs index 6accf79f..b834aa6b 100644 --- a/Source/Provers/SMTLib/SMTLibLineariser.cs +++ b/Source/Provers/SMTLib/SMTLibLineariser.cs @@ -116,7 +116,7 @@ namespace Microsoft.Boogie.SMTLib } sb.Append(']'); TypeToStringHelper(m.Result, sb); - } else if (t.IsBool || t.IsInt || t.IsReal || t.IsBv) { + } else if (t.IsBool || t.IsInt || t.IsReal || t.IsFloat || t.IsBv) { sb.Append(TypeToString(t)); } else { System.IO.StringWriter buffer = new System.IO.StringWriter(); @@ -140,6 +140,8 @@ namespace Microsoft.Boogie.SMTLib return "Int"; else if (t.IsReal) return "Real"; + else if (t.IsFloat) + return "Real"; //TODO: Make to be a float else if (t.IsBv) { return "(_ BitVec " + t.BvBits + ")"; } else { @@ -199,6 +201,15 @@ namespace Microsoft.Boogie.SMTLib else wr.Write(lit.ToDecimalString()); } + else if (node is VCExprFloatLit) + { + BigFloat lit = ((VCExprFloatLit)node).Val; + if (lit.IsNegative) + // In SMT2 "-42" is an identifier (SMT2, Sect. 3.2 "Symbols") + wr.Write("(- 0.0 {0})", lit.Abs.ToDecimalString()); + else + wr.Write(lit.ToDecimalString()); + } else { Contract.Assert(false); throw new cce.UnreachableException(); diff --git a/Source/Provers/SMTLib/TypeDeclCollector.cs b/Source/Provers/SMTLib/TypeDeclCollector.cs index 30363102..2b053410 100644 --- a/Source/Provers/SMTLib/TypeDeclCollector.cs +++ b/Source/Provers/SMTLib/TypeDeclCollector.cs @@ -296,7 +296,7 @@ void ObjectInvariant() return; } - if (type.IsBool || type.IsInt || type.IsReal || type.IsBv) + if (type.IsBool || type.IsInt || type.IsReal || type.IsFloat || type.IsBv) return; CtorType ctorType = type as CtorType; diff --git a/Source/VCExpr/TypeErasure.cs b/Source/VCExpr/TypeErasure.cs index 2326ba7a..4632b1e4 100644 --- a/Source/VCExpr/TypeErasure.cs +++ b/Source/VCExpr/TypeErasure.cs @@ -1424,6 +1424,13 @@ namespace Microsoft.Boogie.TypeErasure { Contract.Ensures(Contract.Result() != null); return CastArguments(node, Type.Real, bindings, 0); } + public override VCExpr VisitFloatDivOp(VCExprNAry node, VariableBindings bindings) + { + Contract.Requires((bindings != null)); + Contract.Requires((node != null)); + Contract.Ensures(Contract.Result() != null); + return CastArguments(node, Type.Float, bindings, 0); + } public override VCExpr VisitPowOp(VCExprNAry node, VariableBindings bindings) { Contract.Requires((bindings != null)); Contract.Requires((node != null)); -- cgit v1.2.3 From ed8913170a86b73dc14ba09e40de1eba0cad4c9d Mon Sep 17 00:00:00 2001 From: Dietrich Date: Mon, 4 May 2015 18:10:09 -0600 Subject: added general floating point mantissa and exponent management --- Source/Basetypes/BigFloat.cs | 78 ++++++++++++++++++++++++++------------------ Source/Core/Scanner.cs | 1 + float_test4.bpl | 6 ++++ 3 files changed, 54 insertions(+), 31 deletions(-) create mode 100644 float_test4.bpl diff --git a/Source/Basetypes/BigFloat.cs b/Source/Basetypes/BigFloat.cs index d1ee73a4..7c8b6001 100644 --- a/Source/Basetypes/BigFloat.cs +++ b/Source/Basetypes/BigFloat.cs @@ -25,11 +25,13 @@ namespace Microsoft.Basetypes // the internal representation [Rep] - internal readonly BIM mantissa; //TODO: restrict mantissa to be 23-bits wide + internal readonly BIM mantissa; //TODO: restrict mantissa. Note that mantissa includes the sign [Rep] internal readonly int exponent; //TODO: restrict exponent to be 8-bits wide [Rep] - internal readonly Boolean isNegative; //represents the sign bit + internal readonly int mantissaSize; //Represents the maximum size of the mantissa + [Rep] + internal readonly int exponentSize; //Represents the maximum size of the exponent public BIM Mantissa { get { @@ -43,9 +45,24 @@ namespace Microsoft.Basetypes } } + public int MantissaSize + { + get + { + return mantissaSize; + } + } + + public int ExponentSize + { + get + { + return exponentSize; + } + } + public static readonly BigFloat ZERO = FromInt(0); private static readonly BIM two = new BIM(2); - private static readonly BIM ten = new BIM(10); //////////////////////////////////////////////////////////////////////////// @@ -56,17 +73,21 @@ namespace Microsoft.Basetypes [Pure] public static BigFloat FromInt(int v) { - return new BigFloat(v, 0, v < 0); //TODO: modify for correct fp representation + return new BigFloat(v, 0, 23, 8); //TODO: modify for correct fp representation } [Pure] public static BigFloat FromBigInt(BIM v) { - return new BigFloat(v, 0, v < 0); //TODO: modify for correct fp representation + return new BigFloat(v, 0, 23, 8); //TODO: modify for correct fp representation + } + + public static BigFloat FromBigDec(BIM v) + { + return new BigFloat(v, 0, 23, 8); //TODO: modify for correct fp representation } [Pure] public static BigFloat FromString(string v) { - //TODO: completely copied from BigDec.cs at the moment if (v == null) throw new FormatException(); BIM integral = BIM.Zero; @@ -95,30 +116,25 @@ namespace Microsoft.Basetypes if (!fraction.IsZero) { while (fractionLen > 0) { - integral = integral * ten; + integral = integral * two; exponent = exponent - 1; fractionLen = fractionLen - 1; } } - return new BigFloat(integral - fraction, exponent, integral.Sign == -1); + return new BigFloat(integral - fraction, exponent, 23, 8); } - internal BigFloat(BIM mantissa, int exponent, bool isNegative) { - this.isNegative = isNegative; - if (mantissa.IsZero) { - this.mantissa = mantissa; - this.exponent = 0; - } - else { - while (mantissa % ten == BIM.Zero) { //TODO: get this to work as expected :P - mantissa = mantissa / ten; - exponent = exponent + 1; - } - this.mantissa = mantissa; - this.exponent = exponent; - } + internal BigFloat(BIM mantissa, int exponent, int mantissaSize, int exponentSize) { + this.mantissaSize = mantissaSize; + this.exponentSize = mantissaSize; + this.mantissa = mantissa; + this.exponent = exponent; } + private int maxMantissa() { return (int)Math.Pow(2, mantissaSize); } + private int maxExponent() { return (int)Math.Pow(2, exponentSize); } + + //////////////////////////////////////////////////////////////////////////// // Basic object operations @@ -166,13 +182,13 @@ namespace Microsoft.Basetypes } else if (0 <= e) { // it's an integer for (; 0 < e; e--) { - n = n * ten; + n = n * two; } floor = ceiling = n; } else { // it's a non-zero integer, so the ceiling is one more than the floor for (; e < 0 && !n.IsZero; e++) { - n = n / ten; // Division rounds towards negative infinity + n = n / two; // Division rounds towards negative infinity } if (this.mantissa >= 0) { @@ -280,7 +296,7 @@ namespace Microsoft.Basetypes public BigFloat Abs { //TODO: fix for fp functionality get { - return new BigFloat(BIM.Abs(this.mantissa), this.exponent, false); + return new BigFloat(BIM.Abs(this.mantissa), this.exponent, this.mantissaSize, this.exponentSize); } } @@ -288,7 +304,7 @@ namespace Microsoft.Basetypes public BigFloat Negate { //TODO: Modify for correct fp functionality get { - return new BigFloat(BIM.Negate(this.mantissa), this.exponent, this.Mantissa >= 0); + return new BigFloat(BIM.Negate(this.mantissa), this.exponent, this.mantissaSize, this.exponentSize); } } @@ -312,11 +328,11 @@ namespace Microsoft.Basetypes } while (e2 > e1) { - m2 = m2 * ten; + m2 = m2 * two; e2 = e2 - 1; } - return new BigFloat(m1 + m2, e1, true); + return new BigFloat(m1 + m2, e1, Math.Max(x.MantissaSize, y.MantissaSize), Math.Max(x.ExponentSize, y.ExponentSize)); } [Pure] @@ -327,7 +343,7 @@ namespace Microsoft.Basetypes [Pure] public static BigFloat operator *(BigFloat x, BigFloat y) { //TODO: modify for correct fp functionality - return new BigFloat(x.mantissa * y.mantissa, x.exponent + y.exponent, false); + return new BigFloat(x.mantissa * y.mantissa, x.exponent + y.exponent, Math.Max(x.MantissaSize, y.MantissaSize), Math.Max(x.ExponentSize, y.ExponentSize)); } @@ -342,13 +358,13 @@ namespace Microsoft.Basetypes public bool IsNegative { get { - return (isNegative); + return (this.mantissa < BIM.Zero); } } public bool IsZero { get { - return this.mantissa.IsZero; + return this.mantissa.IsZero && this.exponent == 0; } } diff --git a/Source/Core/Scanner.cs b/Source/Core/Scanner.cs index c41d0a9e..bc294aba 100644 --- a/Source/Core/Scanner.cs +++ b/Source/Core/Scanner.cs @@ -508,6 +508,7 @@ public class Scanner { case "int": t.kind = 14; break; case "real": t.kind = 15; break; case "bool": t.kind = 16; break; + case "fp": t.kind = 97; break; case "float": t.kind = 98; break; case "const": t.kind = 21; break; case "unique": t.kind = 22; break; diff --git a/float_test4.bpl b/float_test4.bpl new file mode 100644 index 00000000..a962713b --- /dev/null +++ b/float_test4.bpl @@ -0,0 +1,6 @@ + procedure F() returns () { + var x : float; + var y : float; + y := x - x; + assert y == fp (0,0,23,8); +} \ No newline at end of file -- cgit v1.2.3 From f9df0e2ea8e0b03352f5bbba54f091f2ee25b161 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Tue, 5 May 2015 04:50:47 -0600 Subject: added decimal reading functionality to the float type --- Source/AbsInt/IntervalDomain.cs | 2 +- Source/Basetypes/BigFloat.cs | 56 ++++++++++++++++++----------------------- Source/Core/Parser.cs | 33 +++++++++++++++++------- float_test4.bpl | 5 ++-- float_test5.bpl | 5 ++++ float_test6.bpl | 5 ++++ 6 files changed, 61 insertions(+), 45 deletions(-) create mode 100644 float_test5.bpl create mode 100644 float_test6.bpl diff --git a/Source/AbsInt/IntervalDomain.cs b/Source/AbsInt/IntervalDomain.cs index 502b7075..a27ae68d 100644 --- a/Source/AbsInt/IntervalDomain.cs +++ b/Source/AbsInt/IntervalDomain.cs @@ -673,7 +673,7 @@ namespace Microsoft.Boogie.AbstractInterpretation Hi = ceiling; } else if (node.Val is BigFloat) { BigInteger floor, ceiling; - ((BigDec)node.Val).FloorCeiling(out floor, out ceiling); + ((BigFloat)node.Val).FloorCeiling(out floor, out ceiling); Lo = floor; Hi = ceiling; } else if (node.Val is bool) { diff --git a/Source/Basetypes/BigFloat.cs b/Source/Basetypes/BigFloat.cs index 7c8b6001..d93f7d7b 100644 --- a/Source/Basetypes/BigFloat.cs +++ b/Source/Basetypes/BigFloat.cs @@ -88,40 +88,27 @@ namespace Microsoft.Basetypes [Pure] public static BigFloat FromString(string v) { - if (v == null) throw new FormatException(); - - BIM integral = BIM.Zero; - BIM fraction = BIM.Zero; - int exponent = 0; - - int len = v.Length; - - int i = v.IndexOf('e'); - if (i >= 0) { - if (i + 1 == v.Length) throw new FormatException(); - exponent = Int32.Parse(v.Substring(i + 1, len - i - 1)); - len = i; - } - - int fractionLen = 0; - i = v.IndexOf('.'); - if (i >= 0) { - if (i + 1 == v.Length) throw new FormatException(); - fractionLen = len - i - 1; - fraction = BIM.Parse(v.Substring(i + 1, fractionLen)); - len = i; - } - - integral = BIM.Parse(v.Substring(0, len)); - - if (!fraction.IsZero) { - while (fractionLen > 0) { - integral = integral * two; - exponent = exponent - 1; - fractionLen = fractionLen - 1; + String[] vals = v.Split(' '); + if (vals.Length == 0 || vals.Length > 4) + throw new FormatException(); + try + { + switch (vals.Length) { + case 1: + return Round(decimal.Parse(vals[0]), 23, 8); + case 2: + return new BigFloat(BIM.Parse(vals[0]), Int32.Parse(vals[1]), 23, 8); + case 3: + return Round(decimal.Parse(vals[0]), Int32.Parse(vals[1]), Int32.Parse(vals[2])); + case 4: + return new BigFloat(BIM.Parse(vals[0]), Int32.Parse(vals[1]), Int32.Parse(vals[2]), Int32.Parse(vals[3])); + default: + throw new FormatException(); //Unreachable } } - return new BigFloat(integral - fraction, exponent, 23, 8); + catch (Exception) { //Catch parsing errors + throw new FormatException(); + } } internal BigFloat(BIM mantissa, int exponent, int mantissaSize, int exponentSize) { @@ -166,6 +153,11 @@ namespace Microsoft.Basetypes //////////////////////////////////////////////////////////////////////////// // Conversion operations + public static BigFloat Round(decimal d, int mantissaSize, int exponentSize) + { //TODO: round the given decimal to the nearest fp value + return new BigFloat(0, 0, mantissaSize, exponentSize); + } + // ``floor`` rounds towards negative infinity (like SMT-LIBv2's to_int). /// /// Computes the floor and ceiling of this BigFloat. Note the choice of rounding towards negative diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index b333f654..7335dd37 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -1879,15 +1879,29 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { { //To be modified string s = ""; - if (la.kind == 97) { - Get(); - s = t.val; - } else SynErr(128); - try { - n = BigFloat.FromString(s); - } catch (FormatException) { + try + { + if (la.kind == 97) + { + //Expected format = fp (a b) || fp (a b c d) + Get(); //Skip the fp token + Get(); + if (t.val != "(") { throw new FormatException(); } + while (la.kind == 3 || la.kind == 6) { //Get values between the parens + Get(); + s += t.val + " "; + } + Get(); + if (t.val != ")") { throw new FormatException(); } + } + else SynErr(137); + + n = BigFloat.FromString(s.Trim()); + } + catch (FormatException) + { this.SemErr("incorrectly formatted floating point"); - n = BigFloat.ZERO; + n = BigFloat.ZERO; } } @@ -2131,7 +2145,7 @@ out QKeyValue kv, out Trigger trig, out Expr/*!*/ body) { {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,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,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,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, 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, 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,T,T,T, x,T,T,x, x,T,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, 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,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x}, + {x,T,T,T, x,T,T,x, x,T,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, 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,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,T,x,x}, {x,T,T,T, x,T,T,x, x,T,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, 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,T, 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,T,T,T, T,T,T,x, x,T,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, 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,T, x,x,x,x, T,T,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x} @@ -2301,6 +2315,7 @@ public class Errors { case 134: s = "invalid AttributeOrTrigger"; break; case 135: s = "invalid AttributeParameter"; break; case 136: s = "invalid QSep"; break; + case 137: s = "invalid Float"; break; default: s = "error " + n; break; } diff --git a/float_test4.bpl b/float_test4.bpl index a962713b..2388a281 100644 --- a/float_test4.bpl +++ b/float_test4.bpl @@ -1,6 +1,5 @@ procedure F() returns () { var x : float; - var y : float; - y := x - x; - assert y == fp (0,0,23,8); + x := fp (0 0); + assert x == fp (0 0 23 8); } \ No newline at end of file diff --git a/float_test5.bpl b/float_test5.bpl new file mode 100644 index 00000000..b91e53e9 --- /dev/null +++ b/float_test5.bpl @@ -0,0 +1,5 @@ + procedure F() returns () { + var x : float; + x := fp (0 0); + assert x == fp (1 0 23 8); +} \ No newline at end of file diff --git a/float_test6.bpl b/float_test6.bpl new file mode 100644 index 00000000..532798d6 --- /dev/null +++ b/float_test6.bpl @@ -0,0 +1,5 @@ + procedure F() returns () { + var x : float; + x := fp (1.5); + assert x == fp (1 0 23 8); +} \ No newline at end of file -- cgit v1.2.3 From c55533de9fc0b0bcc47cfca5fd26de93afac4d3b Mon Sep 17 00:00:00 2001 From: Dietrich Date: Thu, 7 May 2015 14:09:39 -0600 Subject: Made significant changes to internal representation of BigFloat. Remains a work in progress --- Source/Basetypes/BigFloat.cs | 114 ++++++++++++++++++++++++++----------------- float_test6.bpl | 4 +- float_test7.bpl | 5 ++ 3 files changed, 76 insertions(+), 47 deletions(-) create mode 100644 float_test7.bpl diff --git a/Source/Basetypes/BigFloat.cs b/Source/Basetypes/BigFloat.cs index d93f7d7b..0b35c237 100644 --- a/Source/Basetypes/BigFloat.cs +++ b/Source/Basetypes/BigFloat.cs @@ -25,23 +25,27 @@ namespace Microsoft.Basetypes // the internal representation [Rep] - internal readonly BIM mantissa; //TODO: restrict mantissa. Note that mantissa includes the sign + internal readonly Boolean[] mantissa; //Note that the first element of the mantissa array is the least significant bit for coding simplicity [Rep] - internal readonly int exponent; //TODO: restrict exponent to be 8-bits wide + internal readonly Boolean isNegative; //The left-most (sign) bit in the float representation [Rep] - internal readonly int mantissaSize; //Represents the maximum size of the mantissa + internal readonly int exponent; [Rep] - internal readonly int exponentSize; //Represents the maximum size of the exponent + internal readonly int exponentSize; //The maximum bit size of the exponent public BIM Mantissa { get { - return mantissa; + BIM toReturn = 0; + for (int i = 0; i < mantissa.Length; i++) + if (mantissa[i]) + toReturn += (int) Math.Pow(2, i); + return isNegative ? -toReturn : toReturn; } } public int Exponent { get { - return exponent; + return exponent - (int)Math.Pow(2, exponentSize - 1); //account for shift } } @@ -49,7 +53,7 @@ namespace Microsoft.Basetypes { get { - return mantissaSize; + return mantissa.Length; } } @@ -95,11 +99,11 @@ namespace Microsoft.Basetypes { switch (vals.Length) { case 1: - return Round(decimal.Parse(vals[0]), 23, 8); + return Round(vals[0], 23, 8); case 2: return new BigFloat(BIM.Parse(vals[0]), Int32.Parse(vals[1]), 23, 8); case 3: - return Round(decimal.Parse(vals[0]), Int32.Parse(vals[1]), Int32.Parse(vals[2])); + return Round(vals[0], Int32.Parse(vals[1]), Int32.Parse(vals[2])); case 4: return new BigFloat(BIM.Parse(vals[0]), Int32.Parse(vals[1]), Int32.Parse(vals[2]), Int32.Parse(vals[3])); default: @@ -112,14 +116,17 @@ namespace Microsoft.Basetypes } internal BigFloat(BIM mantissa, int exponent, int mantissaSize, int exponentSize) { - this.mantissaSize = mantissaSize; - this.exponentSize = mantissaSize; - this.mantissa = mantissa; + this.mantissa = new Boolean[mantissaSize]; + this.exponentSize = exponentSize; this.exponent = exponent; + //TODO: Add overflow check for exponent vs exponent size + this.isNegative = mantissa < 0; + if (this.isNegative) + mantissa = -mantissa; } - private int maxMantissa() { return (int)Math.Pow(2, mantissaSize); } - private int maxExponent() { return (int)Math.Pow(2, exponentSize); } + private int maxExponent() { return (int)Math.Pow(2, exponentSize - 1) - 1; } + private int minExponent() { return -(int)Math.Pow(2, exponentSize - 1); } @@ -139,21 +146,38 @@ namespace Microsoft.Basetypes [Pure] public override int GetHashCode() { - return this.mantissa.GetHashCode() * 13 + this.exponent.GetHashCode(); + return Mantissa.GetHashCode() * 13 + Exponent.GetHashCode(); } [Pure] public override string/*!*/ ToString() { //TODO: modify to reflect floating points Contract.Ensures(Contract.Result() != null); - return String.Format("{0}e{1}", this.mantissa.ToString(), this.exponent.ToString()); + return String.Format("{0}e{1}", Mantissa.ToString(), Exponent.ToString()); } //////////////////////////////////////////////////////////////////////////// // Conversion operations - public static BigFloat Round(decimal d, int mantissaSize, int exponentSize) + public static BigFloat Round(String value, int mantissaSize, int exponentSize) + { + int i = value.IndexOf('.'); + if (i == -1) + return Round(BIM.Parse(value), 0, mantissaSize, exponentSize); + return Round(BIM.Parse(value.Substring(0, i - 1)), BIM.Parse(value.Substring(i + 1, value.Length - i - 1)), mantissaSize, exponentSize); + } + + /// + /// Converts value.dec_value to a float with mantissaSize, exponentSize + /// Returns the result of this calculation + /// + /// + /// + /// + /// + /// + public static BigFloat Round(BIM value, BIM dec_value, int mantissaSize, int exponentSize) { //TODO: round the given decimal to the nearest fp value return new BigFloat(0, 0, mantissaSize, exponentSize); } @@ -167,8 +191,8 @@ namespace Microsoft.Basetypes /// Ceiling (rounded towards positive infinity) public void FloorCeiling(out BIM floor, out BIM ceiling) { //TODO: fix for fp functionality - BIM n = this.mantissa; - int e = this.exponent; + BIM n = Mantissa; + int e = Exponent; if (n.IsZero) { floor = ceiling = n; } else if (0 <= e) { @@ -183,7 +207,7 @@ namespace Microsoft.Basetypes n = n / two; // Division rounds towards negative infinity } - if (this.mantissa >= 0) { + if (!isNegative) { floor = n; ceiling = n + 1; } else { @@ -197,26 +221,26 @@ namespace Microsoft.Basetypes [Pure] public String ToDecimalString(int maxDigits) { //TODO: fix for fp functionality - string s = this.mantissa.ToString(); - int digits = (this.mantissa >= 0) ? s.Length : s.Length - 1; + string s = Mantissa.ToString(); + int digits = (isNegative) ? s.Length - 1 : s.Length; BIM max = BIM.Pow(10, maxDigits); BIM min = -max; - if (this.exponent >= 0) { - if (maxDigits < digits || maxDigits - digits < this.exponent) { - return String.Format("{0}.0", (this.mantissa >= 0) ? max.ToString() : min.ToString()); + if (Exponent >= 0) { + if (maxDigits < digits || maxDigits - digits < Exponent) { + return String.Format("{0}.0", (!isNegative) ? max.ToString() : min.ToString()); } else { - return String.Format("{0}{1}.0", s, new string('0', this.exponent)); + return String.Format("{0}{1}.0", s, new string('0', Exponent)); } } else { - int exp = -this.exponent; + int exp = -Exponent; if (exp < digits) { int intDigits = digits - exp; if (maxDigits < intDigits) { - return String.Format("{0}.0", (this.mantissa >= 0) ? max.ToString() : min.ToString()); + return String.Format("{0}.0", (!isNegative) ? max.ToString() : min.ToString()); } else { int fracDigits = Math.Min(maxDigits, digits - intDigits); @@ -233,9 +257,9 @@ namespace Microsoft.Basetypes [Pure] public string ToDecimalString() { //TODO: fix for fp functionality - string m = this.mantissa.ToString(); - var e = this.exponent; - if (0 <= this.exponent) { + string m = Mantissa.ToString(); + var e = Exponent; + if (0 <= Exponent) { return m + Zeros(e) + ".0"; } else { e = -e; @@ -288,7 +312,7 @@ namespace Microsoft.Basetypes public BigFloat Abs { //TODO: fix for fp functionality get { - return new BigFloat(BIM.Abs(this.mantissa), this.exponent, this.mantissaSize, this.exponentSize); + return new BigFloat(BIM.Abs(Mantissa), Exponent, MantissaSize, ExponentSize); } } @@ -296,7 +320,7 @@ namespace Microsoft.Basetypes public BigFloat Negate { //TODO: Modify for correct fp functionality get { - return new BigFloat(BIM.Negate(this.mantissa), this.exponent, this.mantissaSize, this.exponentSize); + return new BigFloat(BIM.Negate(Mantissa), Exponent, MantissaSize, ExponentSize); } } @@ -308,15 +332,15 @@ namespace Microsoft.Basetypes [Pure] public static BigFloat operator +(BigFloat x, BigFloat y) { //TODO: Modify for correct fp functionality - BIM m1 = x.mantissa; - int e1 = x.exponent; - BIM m2 = y.mantissa; - int e2 = y.exponent; + BIM m1 = x.Mantissa; + int e1 = x.Exponent; + BIM m2 = y.Mantissa; + int e2 = y.Exponent; if (e2 < e1) { - m1 = y.mantissa; - e1 = y.exponent; - m2 = x.mantissa; - e2 = x.exponent; + m1 = y.Mantissa; + e1 = y.Exponent; + m2 = x.Mantissa; + e2 = x.Exponent; } while (e2 > e1) { @@ -335,7 +359,7 @@ namespace Microsoft.Basetypes [Pure] public static BigFloat operator *(BigFloat x, BigFloat y) { //TODO: modify for correct fp functionality - return new BigFloat(x.mantissa * y.mantissa, x.exponent + y.exponent, Math.Max(x.MantissaSize, y.MantissaSize), Math.Max(x.ExponentSize, y.ExponentSize)); + return new BigFloat(x.Mantissa * y.Mantissa, x.Exponent + y.Exponent, Math.Max(x.MantissaSize, y.MantissaSize), Math.Max(x.ExponentSize, y.ExponentSize)); } @@ -344,19 +368,19 @@ namespace Microsoft.Basetypes public bool IsPositive { get { - return (this.mantissa > BIM.Zero); + return (Mantissa > BIM.Zero); } } public bool IsNegative { get { - return (this.mantissa < BIM.Zero); + return (Mantissa < BIM.Zero); } } public bool IsZero { get { - return this.mantissa.IsZero && this.exponent == 0; + return Mantissa.IsZero && Exponent == 0; } } diff --git a/float_test6.bpl b/float_test6.bpl index 532798d6..12cfbabe 100644 --- a/float_test6.bpl +++ b/float_test6.bpl @@ -1,5 +1,5 @@ procedure F() returns () { var x : float; - x := fp (1.5); - assert x == fp (1 0 23 8); + x := fp (3); + assert x == fp (8388608 1 23 8); } \ No newline at end of file diff --git a/float_test7.bpl b/float_test7.bpl new file mode 100644 index 00000000..1638724d --- /dev/null +++ b/float_test7.bpl @@ -0,0 +1,5 @@ + procedure F() returns () { + var x : float; + x := fp (0.5); + assert x == fp (0 -1 23 8); +} \ No newline at end of file -- cgit v1.2.3 From 25fca02e1deb9e60e6e330803731c9b4fcd45d34 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Mon, 18 May 2015 22:08:43 -0600 Subject: added interpretation of floating point constants to the parser --- Source/Basetypes/BigFloat.cs | 155 +++++++++++++++++++++++++++++++---------- Source/Core/Parser.cs | 9 ++- Source/VCExpr/Boogie2VCExpr.cs | 2 +- float_test7.bpl | 4 +- 4 files changed, 128 insertions(+), 42 deletions(-) diff --git a/Source/Basetypes/BigFloat.cs b/Source/Basetypes/BigFloat.cs index 0b35c237..a4cd6574 100644 --- a/Source/Basetypes/BigFloat.cs +++ b/Source/Basetypes/BigFloat.cs @@ -25,21 +25,19 @@ namespace Microsoft.Basetypes // the internal representation [Rep] - internal readonly Boolean[] mantissa; //Note that the first element of the mantissa array is the least significant bit for coding simplicity + internal readonly BIM mantissa; //Note that the mantissa arrangement matches standard fp arrangement (most significant bit is farthest left) [Rep] internal readonly Boolean isNegative; //The left-most (sign) bit in the float representation [Rep] - internal readonly int exponent; + internal readonly int mantissaSize; [Rep] - internal readonly int exponentSize; //The maximum bit size of the exponent + internal readonly int exponent; //The value of the exponent is always positive as per fp representation requirements + [Rep] + internal readonly int exponentSize; //The bit size of the exponent public BIM Mantissa { get { - BIM toReturn = 0; - for (int i = 0; i < mantissa.Length; i++) - if (mantissa[i]) - toReturn += (int) Math.Pow(2, i); - return isNegative ? -toReturn : toReturn; + return isNegative ? -mantissa : mantissa; } } @@ -53,7 +51,7 @@ namespace Microsoft.Basetypes { get { - return mantissa.Length; + return mantissaSize; } } @@ -65,8 +63,18 @@ namespace Microsoft.Basetypes } } - public static readonly BigFloat ZERO = FromInt(0); + public static BigFloat ZERO(int mantissaSize, int exponentSize) { return new BigFloat(0, 0, mantissaSize, exponentSize); } //Does not include negative zero + public static BigFloat INF(int mantissaSize, int exponentSize) { return new BigFloat(0, 0, mantissaSize, exponentSize); } //Modify for IEEE standard + public static BigFloat NEGINF(int mantissaSize, int exponentSize) { return new BigFloat(0, 0, mantissaSize, exponentSize); } //Modify for IEEE standard + public static BigFloat NAN(int mantissaSize, int exponentSize) { return new BigFloat(0, 0, mantissaSize, exponentSize); } //Modify for IEEE standard + private static readonly BIM two = new BIM(2); + private static BIM two_n(int n) { + BIM toReturn = new BIM(1); + for (int i = 0; i < n; i++) + toReturn = toReturn * two; + return toReturn; + } //////////////////////////////////////////////////////////////////////////// @@ -116,17 +124,39 @@ namespace Microsoft.Basetypes } internal BigFloat(BIM mantissa, int exponent, int mantissaSize, int exponentSize) { - this.mantissa = new Boolean[mantissaSize]; + this.mantissa = mantissa; + this.mantissaSize = mantissaSize; this.exponentSize = exponentSize; - this.exponent = exponent; - //TODO: Add overflow check for exponent vs exponent size + this.exponent = exponent + (int)Math.Pow(2, exponentSize - 1); + if (exponent < 0) { //ZERO case since the exponent is less than the minimum + mantissa = 0; + exponent = 0; + this.isNegative = false; + return; + } + this.isNegative = mantissa < 0; if (this.isNegative) - mantissa = -mantissa; + mantissa = -mantissa; // ==> mantissa > 0 + + BIM max = maxMantissa(); + while (this.mantissa > max) { + this.mantissa = this.mantissa / two; + this.exponent++; + } + + //TODO: Add overflow check for exponent vs exponent size + //this.exponent = this.exponent % this.exponentSize; ?? } - private int maxExponent() { return (int)Math.Pow(2, exponentSize - 1) - 1; } - private int minExponent() { return -(int)Math.Pow(2, exponentSize - 1); } + private BIM maxMantissa() + { + BIM result = new BIM(1); + for (int i = 0; i < mantissaSize; i++) + result = result * two; + return result - 1; + } + private int maxExponent() { return (int)Math.Pow(2, exponentSize) - 1; } @@ -151,25 +181,32 @@ namespace Microsoft.Basetypes [Pure] public override string/*!*/ ToString() { - //TODO: modify to reflect floating points Contract.Ensures(Contract.Result() != null); - return String.Format("{0}e{1}", Mantissa.ToString(), Exponent.ToString()); + return String.Format("{0}x2^{1}", Mantissa.ToString(), Exponent.ToString()); } //////////////////////////////////////////////////////////////////////////// // Conversion operations + /// + /// Converts the given decimal value (provided as a string) to the nearest floating point approximation + /// the returned fp assumes the given mantissa and exponent size + /// + /// + /// + /// + /// public static BigFloat Round(String value, int mantissaSize, int exponentSize) { int i = value.IndexOf('.'); if (i == -1) return Round(BIM.Parse(value), 0, mantissaSize, exponentSize); - return Round(BIM.Parse(value.Substring(0, i - 1)), BIM.Parse(value.Substring(i + 1, value.Length - i - 1)), mantissaSize, exponentSize); + return Round(i == 0 ? 0 : BIM.Parse(value.Substring(0, i)), BIM.Parse(value.Substring(i + 1, value.Length - i - 1)), mantissaSize, exponentSize); } /// - /// Converts value.dec_value to a float with mantissaSize, exponentSize + /// Converts value.dec_value to a the closest float approximation with the given mantissaSize, exponentSize /// Returns the result of this calculation /// /// @@ -178,8 +215,54 @@ namespace Microsoft.Basetypes /// /// public static BigFloat Round(BIM value, BIM dec_value, int mantissaSize, int exponentSize) - { //TODO: round the given decimal to the nearest fp value - return new BigFloat(0, 0, mantissaSize, exponentSize); + { + int exp = 0; + BIM one = new BIM(1); + BIM ten = new BIM(10); + BIM dec_max = new BIM(0); //represents the order of magnitude of dec_value for carrying during calculations + + //First, determine the exponent + while (value > one) { //Divide by two, increment exponent by 1 + if (!(value % two).IsZero) { //Add "1.0" to the decimal + dec_max = new BIM(10); + while (dec_max < dec_value) + dec_max = dec_max * ten; + dec_value = dec_value + dec_max; + } + value = value / two; + if (!(dec_value % ten).IsZero) + dec_value = dec_value * ten; //Creates excess zeroes to avoid losing data during division + dec_value = dec_value / two; + exp++; + } + if (value.IsZero && !dec_value.IsZero) { + dec_max = new BIM(10); + while (dec_max < dec_value) + dec_max = dec_max * ten; + while (value.IsZero) {//Multiply by two, decrement exponent by 1 + dec_value = dec_value * two; + if (dec_value >= dec_max) { + dec_value = dec_value - dec_max; + value = value + one; + } + exp--; + } + } + + //Second, calculate the mantissa + value = new BIM(0); //remove implicit bit + dec_max = new BIM(10); + while (dec_max < dec_value) + dec_max = dec_max * ten; + for (int i = mantissaSize; i > 0 && !dec_value.IsZero; i--) { //Multiply by two until the mantissa is fully calculated + dec_value = dec_value * two; + if (dec_value >= dec_max) { + dec_value = dec_value - dec_max; + value = value + two_n(i); //Note that i is decrementing so that the most significant bit is left-most in the representation + } + } + + return new BigFloat(value, exp, mantissaSize, exponentSize); } // ``floor`` rounds towards negative infinity (like SMT-LIBv2's to_int). @@ -336,16 +419,18 @@ namespace Microsoft.Basetypes int e1 = x.Exponent; BIM m2 = y.Mantissa; int e2 = y.Exponent; - if (e2 < e1) { + m1 = m1 + two_n(x.mantissaSize + 1); //Add implicit bit + m2 = m2 + two_n(y.mantissaSize + 1); + if (e2 > e1) { m1 = y.Mantissa; e1 = y.Exponent; m2 = x.Mantissa; e2 = x.Exponent; } - while (e2 > e1) { - m2 = m2 * two; - e2 = e2 - 1; + while (e2 < e1) { + m2 = m2 / two; + e2++; } return new BigFloat(m1 + m2, e1, Math.Max(x.MantissaSize, y.MantissaSize), Math.Max(x.ExponentSize, y.ExponentSize)); @@ -358,7 +443,6 @@ namespace Microsoft.Basetypes [Pure] public static BigFloat operator *(BigFloat x, BigFloat y) { - //TODO: modify for correct fp functionality return new BigFloat(x.Mantissa * y.Mantissa, x.Exponent + y.Exponent, Math.Max(x.MantissaSize, y.MantissaSize), Math.Max(x.ExponentSize, y.ExponentSize)); } @@ -368,13 +452,13 @@ namespace Microsoft.Basetypes public bool IsPositive { get { - return (Mantissa > BIM.Zero); + return (!isNegative); } } public bool IsNegative { get { - return (Mantissa < BIM.Zero); + return (isNegative); } } @@ -386,14 +470,13 @@ namespace Microsoft.Basetypes [Pure] public int CompareTo(BigFloat that) { - //TODO: Modify for correct fp functionality - if (this.mantissa == that.mantissa && this.exponent == that.exponent) { + if (this.exponent > that.exponent) + return 1; + if (this.exponent < that.exponent) + return -1; + if (this.Mantissa == that.Mantissa) return 0; - } - else { - BigFloat d = this - that; - return d.IsNegative ? -1 : 1; - } + return this.Mantissa > that.Mantissa ? 1 : -1; } [Pure] diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index 7335dd37..6f793503 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -1887,9 +1887,12 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { Get(); //Skip the fp token Get(); if (t.val != "(") { throw new FormatException(); } - while (la.kind == 3 || la.kind == 6) { //Get values between the parens + while (la.kind == 1 || la.kind == 3 || la.kind == 6 || la.kind == 75) { //Get values between the parens Get(); - s += t.val + " "; + if (t.val == "-") //special negative case (la.kind == 75) + s += t.val; + else + s += t.val + " "; } Get(); if (t.val != ")") { throw new FormatException(); } @@ -1901,7 +1904,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { catch (FormatException) { this.SemErr("incorrectly formatted floating point"); - n = BigFloat.ZERO; + n = BigFloat.ZERO(8, 23); } } diff --git a/Source/VCExpr/Boogie2VCExpr.cs b/Source/VCExpr/Boogie2VCExpr.cs index aa246c37..942116eb 100644 --- a/Source/VCExpr/Boogie2VCExpr.cs +++ b/Source/VCExpr/Boogie2VCExpr.cs @@ -1009,7 +1009,7 @@ namespace Microsoft.Boogie.VCExprAST { return Gen.Function(VCExpressionGenerator.SubROp, Gen.Real(BigDec.ZERO), e); } else {//is float - return Gen.Function(VCExpressionGenerator.SubFOp, Gen.Float(BigFloat.ZERO), e); + return Gen.Function(VCExpressionGenerator.SubFOp, Gen.Float(BigFloat.ZERO(8, 23)), e); } } else { diff --git a/float_test7.bpl b/float_test7.bpl index 1638724d..ca33eb08 100644 --- a/float_test7.bpl +++ b/float_test7.bpl @@ -1,5 +1,5 @@ procedure F() returns () { var x : float; - x := fp (0.5); - assert x == fp (0 -1 23 8); + x := fp (.5 23 8); + assert x == fp (0 -1); } \ No newline at end of file -- cgit v1.2.3 From fe331e0a63c7921a996e007860182bad9628fb0d Mon Sep 17 00:00:00 2001 From: Dietrich Date: Fri, 22 May 2015 00:57:33 -0600 Subject: added some float addition tests --- float_test10.bpl | 5 +++++ float_test8.bpl | 5 +++++ float_test9.bpl | 5 +++++ 3 files changed, 15 insertions(+) create mode 100644 float_test10.bpl create mode 100644 float_test8.bpl create mode 100644 float_test9.bpl diff --git a/float_test10.bpl b/float_test10.bpl new file mode 100644 index 00000000..7423a3a0 --- /dev/null +++ b/float_test10.bpl @@ -0,0 +1,5 @@ + procedure F() returns () { + var x : float; + x := fp (0.5 23 8); + assert x == fp (0 -1); +} \ No newline at end of file diff --git a/float_test8.bpl b/float_test8.bpl new file mode 100644 index 00000000..8d881126 --- /dev/null +++ b/float_test8.bpl @@ -0,0 +1,5 @@ +procedure F() returns () { + var x : float; + x := fp(.1) + fp(.1); + assert x == fp(.2); +} \ No newline at end of file diff --git a/float_test9.bpl b/float_test9.bpl new file mode 100644 index 00000000..7423a3a0 --- /dev/null +++ b/float_test9.bpl @@ -0,0 +1,5 @@ + procedure F() returns () { + var x : float; + x := fp (0.5 23 8); + assert x == fp (0 -1); +} \ No newline at end of file -- cgit v1.2.3 From 52aa9b8f63a3d955031e7a0dfd6e575ca7cf76b3 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Mon, 13 Jul 2015 19:40:09 -0600 Subject: Modified internal abstract float representation to allow user-defined mantissa and exponent --- Source/Core/AbsyExpr.cs | 49 +++----- Source/Core/AbsyType.cs | 197 ++++++++++++++++++++++++++++-- Source/Core/Parser.cs | 12 +- Source/Core/StandardVisitor.cs | 6 + Source/Provers/SMTLib/SMTLibLineariser.cs | 4 +- Source/Provers/SMTLib/SMTLibProcess.cs | 1 + Source/VCExpr/Boogie2VCExpr.cs | 8 +- Source/VCExpr/TypeErasure.cs | 4 +- Source/VCExpr/VCExprAST.cs | 19 +-- 9 files changed, 242 insertions(+), 58 deletions(-) diff --git a/Source/Core/AbsyExpr.cs b/Source/Core/AbsyExpr.cs index 9297bcbc..7e7ed10a 100644 --- a/Source/Core/AbsyExpr.cs +++ b/Source/Core/AbsyExpr.cs @@ -561,7 +561,7 @@ namespace Microsoft.Boogie { { Contract.Requires(tok != null); Val = v; - Type = Type.Float; + Type = Type.GetFloatType(v.ExponentSize, v.MantissaSize); if (immutable) CachedHashCode = ComputeHashCode(); } @@ -638,7 +638,8 @@ namespace Microsoft.Boogie { } else if (Val is BigDec) { return Type.Real; } else if (Val is BigFloat) { - return Type.Float; + BigFloat temp = (BigFloat)Val; + return Type.GetFloatType(temp.ExponentSize, temp.MantissaSize); } else if (Val is BvConst) { return Type.GetBvType(((BvConst)Val).Bits); } else { @@ -1376,9 +1377,9 @@ namespace Microsoft.Boogie { if (arg0type.Unify(Type.Real)) { return Type.Real; } - if (arg0type.Unify(Type.Float)) { - return Type.Float; - } + //if (arg0type.Unify(Type.Float)) { + //return Type.Float; + //} goto BAD_TYPE; case Opcode.Not: if (arg0type.Unify(Type.Bool)) { @@ -1519,7 +1520,7 @@ namespace Microsoft.Boogie { case Opcode.RealDiv: return "/"; case Opcode.FloatDiv: - return "/f"; + return "/"; case Opcode.Pow: return "**"; case Opcode.Eq: @@ -1706,10 +1707,10 @@ namespace Microsoft.Boogie { if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { return Type.Real; } - if (arg0type.Unify(Type.Float) && arg1type.Unify(Type.Float)) - { - return Type.Float; - } + //if (arg0type.Unify(Type.Float) && arg1type.Unify(Type.Float)) + //{ + //return Type.Float; + //} goto BAD_TYPE; case Opcode.Div: case Opcode.Mod: @@ -1723,13 +1724,6 @@ namespace Microsoft.Boogie { return Type.Real; } goto BAD_TYPE; - case Opcode.FloatDiv: //TODO: Modify - if ((arg0type.Unify(Type.Int) || arg0type.Unify(Type.Real) || arg0type.Unify(Type.Float)) && - (arg1type.Unify(Type.Int) || arg1type.Unify(Type.Real) || arg0type.Unify(Type.Float))) - { - return Type.Float; - } - goto BAD_TYPE; case Opcode.Pow: if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { return Type.Real; @@ -1761,10 +1755,10 @@ namespace Microsoft.Boogie { if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { return Type.Bool; } - if (arg0type.Unify(Type.Float) && arg1type.Unify(Type.Float)) - { - return Type.Bool; - } + //if (arg0type.Unify(Type.Float) && arg1type.Unify(Type.Float)) + //{ + //return Type.Bool; + //} goto BAD_TYPE; case Opcode.And: case Opcode.Or: @@ -1809,8 +1803,8 @@ namespace Microsoft.Boogie { case Opcode.Pow: return Type.Real; - case Opcode.FloatDiv: - return Type.Float; + //case Opcode.FloatDiv: + //return Type.Float; case Opcode.Eq: case Opcode.Neq: @@ -2267,23 +2261,14 @@ namespace Microsoft.Boogie { this.name = "int"; this.type = Type.Int; this.argType = Type.Real; - this.argType2 = Type.Float; this.hashCode = 1; break; case CoercionType.ToReal: this.name = "real"; this.type = Type.Real; this.argType = Type.Int; - this.argType2 = Type.Float; this.hashCode = 2; break; - case CoercionType.ToFloat: - this.name = "float"; - this.type = Type.Float; - this.argType = Type.Int; - this.argType2 = Type.Real; - this.hashCode = 3; - break; default: Contract.Assert(false); break; diff --git a/Source/Core/AbsyType.cs b/Source/Core/AbsyType.cs index ae307f7a..50fde975 100644 --- a/Source/Core/AbsyType.cs +++ b/Source/Core/AbsyType.cs @@ -325,6 +325,27 @@ namespace Microsoft.Boogie { } } + public virtual bool isFloat { + get { + return false; + } + } + public virtual int FloatMantissa { + get { + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // Type.FloatMantissa should never be called + } + } + public virtual int FloatExponent { + get { + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // Type.FloatExponent should never be called + } + } public virtual bool IsBv { get { return false; @@ -341,7 +362,6 @@ namespace Microsoft.Boogie { public static readonly Type/*!*/ Int = new BasicType(SimpleType.Int); public static readonly Type/*!*/ Real = new BasicType(SimpleType.Real); - public static readonly Type/*!*/ Float = new BasicType(SimpleType.Float); public static readonly Type/*!*/ Bool = new BasicType(SimpleType.Bool); private static BvType[] bvtypeCache; @@ -364,6 +384,14 @@ namespace Microsoft.Boogie { } } + static public FloatType GetFloatType(int exp, int man) { + Contract.Requires(0 <= exp); + Contract.Requires(0 <= man); + Contract.Ensures(Contract.Result() != null); + + return new FloatType(exp, man); + } + //------------ Match formal argument types on actual argument types //------------ and return the resulting substitution of type variables @@ -877,8 +905,6 @@ namespace Microsoft.Boogie { return "int"; case SimpleType.Real: return "real"; - case SimpleType.Float: - return "float"; case SimpleType.Bool: return "bool"; } @@ -1001,11 +1027,6 @@ namespace Microsoft.Boogie { return this.T == SimpleType.Real; } } - public override bool IsFloat { - get { - return this.T == SimpleType.Float; - } - } public override bool IsBool { get { return this.T == SimpleType.Bool; @@ -1021,6 +1042,165 @@ namespace Microsoft.Boogie { //===================================================================== + //Note that the functions in this class were directly copied from the BV class just below + public class FloatType : Type { + public readonly int Mantissa; //Size of mantissa in bits + public readonly int Exponent; //Size of exponent in bits + + public FloatType(IToken token, int exponent, int mantissa) + : base(token) { + Contract.Requires(token != null); + Mantissa = mantissa; + Exponent = exponent; + } + + public FloatType(int exponent, int mantissa) + : base(Token.NoToken) { + Mantissa = mantissa; + Exponent = exponent; + } + + //----------- Cloning ---------------------------------- + // We implement our own clone-method, because bound type variables + // have to be created in the right way. It is /not/ ok to just clone + // everything recursively. + + public override Type Clone(IDictionary/*!*/ varMap) + { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + // FloatTypes are immutable anyway, we do not clone + return this; + } + + public override Type CloneUnresolved() + { + Contract.Ensures(Contract.Result() != null); + return this; + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) + { + //Contract.Requires(stream != null); + // no parentheses are necessary for bitvector-types + stream.SetToken(this); + stream.Write("{0}", this); + } + + public override string ToString() + { + Contract.Ensures(Contract.Result() != null); + return "(_ FP " + Exponent + " " + Mantissa + ")"; + } + + //----------- Equality ---------------------------------- + + [Pure] + public override bool Equals(Type/*!*/ that, + List/*!*/ thisBoundVariables, + List/*!*/ thatBoundVariables) + { + FloatType thatFloatType = TypeProxy.FollowProxy(that.Expanded) as FloatType; + return thatFloatType != null && this.Mantissa == thatFloatType.Mantissa && this.Exponent == thatFloatType.Exponent; + } + + //----------- Unification of types ----------- + + public override bool Unify(Type/*!*/ that, + List/*!*/ unifiableVariables, + // an idempotent substitution that describes the + // unification result up to a certain point + IDictionary/*!*/ unifier) + { + //Contract.Requires(that != null); + //Contract.Requires(unifiableVariables != null); + //Contract.Requires(cce.NonNullElements(unifier)); + that = that.Expanded; + if (that is TypeProxy || that is TypeVariable) { + return that.Unify(this, unifiableVariables, unifier); + } + else { + return this.Equals(that); + } + } + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) + { + Contract.Ensures(Contract.Result() != null); + return this; + } + + //----------- Hashcodes ---------------------------------- + + [Pure] + public override int GetHashCode(List boundVariables) + { + return this.Mantissa.GetHashCode() + this.Exponent.GetHashCode(); + } + + //----------- Resolution ---------------------------------- + + public override Type ResolveType(ResolutionContext rc) + { + //Contract.Requires(rc != null); + Contract.Ensures(Contract.Result() != null); + // nothing to resolve + return this; + } + + // determine the free variables in a type, in the order in which the variables occur + public override List/*!*/ FreeVariables + { + get + { + Contract.Ensures(Contract.Result>() != null); + + return new List(); // bitvector-type are closed + } + } + + public override List/*!*/ FreeProxies + { + get + { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return new List(); + } + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsFloat { + get { + return true; + } + } + public override int FloatMantissa { + get { + return Mantissa; + } + } + public override int FloatExponent { + get { + return Exponent; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) + { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitFloatType(this); + } + + } + + //===================================================================== + public class BvType : Type { public readonly int Bits; @@ -3554,7 +3734,6 @@ Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); public enum SimpleType { Int, Real, - Float, Bool }; diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index 6f793503..bb372cfb 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -668,7 +668,17 @@ private class BvBounds : Expr { ty = new BasicType(t, SimpleType.Real); } else if (la.kind == 98) { Get(); - ty = new BasicType(t, SimpleType.Float); + if (la.kind == 9) { + Get(); + Expect(3); + int exp = Int32.Parse(t.val); + Expect(3); + int man = Int32.Parse(t.val); + ty = new FloatType(t, exp, man); + Expect(10); + } + else + ty = new FloatType(t, 8, 23); } else if (la.kind == 16) { Get(); ty = new BasicType(t, SimpleType.Bool); diff --git a/Source/Core/StandardVisitor.cs b/Source/Core/StandardVisitor.cs index 0323d4db..97215cfb 100644 --- a/Source/Core/StandardVisitor.cs +++ b/Source/Core/StandardVisitor.cs @@ -103,6 +103,12 @@ namespace Microsoft.Boogie { Contract.Ensures(Contract.Result() != null); return this.VisitType(node); } + public virtual Type VisitFloatType(FloatType node) + { + Contract.Requires(node != null); + Contract.Ensures(Contract.Result() != null); + return this.VisitType(node); + } public virtual Expr VisitBvConcatExpr(BvConcatExpr node) { Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); diff --git a/Source/Provers/SMTLib/SMTLibLineariser.cs b/Source/Provers/SMTLib/SMTLibLineariser.cs index b834aa6b..c7ae9d57 100644 --- a/Source/Provers/SMTLib/SMTLibLineariser.cs +++ b/Source/Provers/SMTLib/SMTLibLineariser.cs @@ -141,7 +141,7 @@ namespace Microsoft.Boogie.SMTLib else if (t.IsReal) return "Real"; else if (t.IsFloat) - return "Real"; //TODO: Make to be a float + return t.ToString(); //TODO: Match z3 syntax else if (t.IsBv) { return "(_ BitVec " + t.BvBits + ")"; } else { @@ -690,7 +690,7 @@ namespace Microsoft.Boogie.SMTLib } public bool VisitFloatDivOp(VCExprNAry node, LineariserOptions options) - { + { //TODO: match z3 WriteApplication("/f", node, options); return true; } diff --git a/Source/Provers/SMTLib/SMTLibProcess.cs b/Source/Provers/SMTLib/SMTLibProcess.cs index 4a1331c5..2b09362b 100644 --- a/Source/Provers/SMTLib/SMTLibProcess.cs +++ b/Source/Provers/SMTLib/SMTLibProcess.cs @@ -93,6 +93,7 @@ namespace Microsoft.Boogie.SMTLib log = log.Replace("\r", "").Replace("\n", " "); Console.WriteLine("[SMT-INP-{0}] {1}", smtProcessId, log); } + Console.WriteLine(cmd); //TODO: Remove This Line toProver.WriteLine(cmd); } diff --git a/Source/VCExpr/Boogie2VCExpr.cs b/Source/VCExpr/Boogie2VCExpr.cs index 942116eb..f0dc505d 100644 --- a/Source/VCExpr/Boogie2VCExpr.cs +++ b/Source/VCExpr/Boogie2VCExpr.cs @@ -1005,12 +1005,12 @@ namespace Microsoft.Boogie.VCExprAST { if (cce.NonNull(e.Type).IsInt) { return Gen.Function(VCExpressionGenerator.SubIOp, Gen.Integer(BigNum.ZERO), e); } - else if (cce.NonNull(e.Type).IsReal) { + else {// if (cce.NonNull(e.Type).IsReal) { return Gen.Function(VCExpressionGenerator.SubROp, Gen.Real(BigDec.ZERO), e); } - else {//is float - return Gen.Function(VCExpressionGenerator.SubFOp, Gen.Float(BigFloat.ZERO(8, 23)), e); - } + //else {//is float + //return Gen.Function(VCExpressionGenerator.SubFOp, Gen.Float(BigFloat.ZERO(8, 23)), e); + //} } else { return Gen.Not(this.args); diff --git a/Source/VCExpr/TypeErasure.cs b/Source/VCExpr/TypeErasure.cs index 4632b1e4..5e821ea2 100644 --- a/Source/VCExpr/TypeErasure.cs +++ b/Source/VCExpr/TypeErasure.cs @@ -1424,13 +1424,13 @@ namespace Microsoft.Boogie.TypeErasure { Contract.Ensures(Contract.Result() != null); return CastArguments(node, Type.Real, bindings, 0); } - public override VCExpr VisitFloatDivOp(VCExprNAry node, VariableBindings bindings) + /*public override VCExpr VisitFloatDivOp(VCExprNAry node, VariableBindings bindings) { Contract.Requires((bindings != null)); Contract.Requires((node != null)); Contract.Ensures(Contract.Result() != null); return CastArguments(node, Type.Float, bindings, 0); - } + }*/ public override VCExpr VisitPowOp(VCExprNAry node, VariableBindings bindings) { Contract.Requires((bindings != null)); Contract.Requires((node != null)); diff --git a/Source/VCExpr/VCExprAST.cs b/Source/VCExpr/VCExprAST.cs index 291d6d42..36692f30 100644 --- a/Source/VCExpr/VCExprAST.cs +++ b/Source/VCExpr/VCExprAST.cs @@ -324,16 +324,16 @@ namespace Microsoft.Boogie { public static readonly VCExprOp AddIOp = new VCExprNAryOp(2, Type.Int); public static readonly VCExprOp AddROp = new VCExprNAryOp(2, Type.Real); - public static readonly VCExprOp AddFOp = new VCExprNAryOp(2, Type.Float); + //public static readonly VCExprOp AddFOp = new VCExprNAryOp(2, Type.Float); public static readonly VCExprOp SubIOp = new VCExprNAryOp(2, Type.Int); public static readonly VCExprOp SubROp = new VCExprNAryOp(2, Type.Real); - public static readonly VCExprOp SubFOp = new VCExprNAryOp(2, Type.Float); + // public static readonly VCExprOp SubFOp = new VCExprNAryOp(2, Type.Float); public static readonly VCExprOp MulIOp = new VCExprNAryOp(2, Type.Int); public static readonly VCExprOp MulROp = new VCExprNAryOp(2, Type.Real); - public static readonly VCExprOp MulFOp = new VCExprNAryOp(2, Type.Float); + //public static readonly VCExprOp MulFOp = new VCExprNAryOp(2, Type.Float); public static readonly VCExprOp DivIOp = new VCExprNAryOp(2, Type.Int); public static readonly VCExprOp DivROp = new VCExprNAryOp(2, Type.Real); - public static readonly VCExprOp DivFOp = new VCExprNAryOp(2, Type.Float); + //public static readonly VCExprOp DivFOp = new VCExprNAryOp(2, Type.Float); public static readonly VCExprOp ModOp = new VCExprNAryOp(2, Type.Int); public static readonly VCExprOp PowOp = new VCExprNAryOp(2, Type.Real); public static readonly VCExprOp LtOp = new VCExprNAryOp(2, Type.Bool); @@ -347,7 +347,7 @@ namespace Microsoft.Boogie { public static readonly VCExprOp IfThenElseOp = new VCExprIfThenElseOp(); public static readonly VCExprOp ToIntOp = new VCExprNAryOp(1, Type.Int); public static readonly VCExprOp ToRealOp = new VCExprNAryOp(1, Type.Real); - public static readonly VCExprOp ToFloatOp = new VCExprNAryOp(1, Type.Float); + //public static readonly VCExprOp ToFloatOp = new VCExprNAryOp(1, Type.Float); public static readonly VCExprOp TickleBoolOp = new VCExprCustomOp("tickleBool", 1, Type.Bool); @@ -433,13 +433,16 @@ namespace Microsoft.Boogie { SingletonOpDict.Add(ImpliesOp, SingletonOp.ImpliesOp); SingletonOpDict.Add(AddIOp, SingletonOp.AddOp); SingletonOpDict.Add(AddROp, SingletonOp.AddOp); + //SingletonOpDict.Add(AddFOp, SingletonOp.AddOp); SingletonOpDict.Add(SubIOp, SingletonOp.SubOp); SingletonOpDict.Add(SubROp, SingletonOp.SubOp); + //SingletonOpDict.Add(SubFOp, SingletonOp.SubOp); SingletonOpDict.Add(MulIOp, SingletonOp.MulOp); SingletonOpDict.Add(MulROp, SingletonOp.MulOp); + //SingletonOpDict.Add(MulFOp, SingletonOp.MulOp); SingletonOpDict.Add(DivIOp, SingletonOp.DivOp); SingletonOpDict.Add(DivROp, SingletonOp.RealDivOp); - SingletonOpDict.Add(DivFOp, SingletonOp.FloatDivOp); + //SingletonOpDict.Add(DivFOp, SingletonOp.FloatDivOp); SingletonOpDict.Add(ModOp, SingletonOp.ModOp); SingletonOpDict.Add(PowOp, SingletonOp.PowOp); SingletonOpDict.Add(LtOp, SingletonOp.LtOp); @@ -450,7 +453,7 @@ namespace Microsoft.Boogie { SingletonOpDict.Add(Subtype3Op, SingletonOp.Subtype3Op); SingletonOpDict.Add(ToIntOp, SingletonOp.ToIntOp); SingletonOpDict.Add(ToRealOp, SingletonOp.ToRealOp); - SingletonOpDict.Add(ToFloatOp, SingletonOp.ToFloatOp); + //SingletonOpDict.Add(ToFloatOp, SingletonOp.ToFloatOp); } //////////////////////////////////////////////////////////////////////////////// @@ -876,7 +879,7 @@ namespace Microsoft.Boogie.VCExprAST { { public readonly BigFloat Val; internal VCExprFloatLit(BigFloat val) - : base(Type.Float) + : base(Type.GetFloatType(val.ExponentSize, val.MantissaSize)) { this.Val = val; } -- cgit v1.2.3 From bb5395b35dcea5078c9b38a2f091f26256faac34 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Mon, 20 Jul 2015 22:27:32 -0600 Subject: Float type now works correctly for simple variable declaration and comparison. --- Source/Basetypes/BigFloat.cs | 38 +++++++++++++++++-------------- Source/Core/AbsyType.cs | 22 ++++++++++-------- Source/Core/Parser.cs | 4 ++-- Source/Provers/SMTLib/SMTLibLineariser.cs | 2 +- Source/Provers/SMTLib/SMTLibProcess.cs | 1 - float_test2.bpl | 4 ++-- float_test3.bpl | 5 +--- float_test4.bpl | 4 ++-- float_test5.bpl | 2 +- float_test6.bpl | 6 ++--- float_test7.bpl | 6 ++--- float_test8.bpl | 1 + 12 files changed, 49 insertions(+), 46 deletions(-) diff --git a/Source/Basetypes/BigFloat.cs b/Source/Basetypes/BigFloat.cs index a4cd6574..1fb05005 100644 --- a/Source/Basetypes/BigFloat.cs +++ b/Source/Basetypes/BigFloat.cs @@ -90,12 +90,12 @@ namespace Microsoft.Basetypes [Pure] public static BigFloat FromBigInt(BIM v) { - return new BigFloat(v, 0, 23, 8); //TODO: modify for correct fp representation + return new BigFloat(0, v, 8, 23); //TODO: modify for correct fp representation } public static BigFloat FromBigDec(BIM v) { - return new BigFloat(v, 0, 23, 8); //TODO: modify for correct fp representation + return new BigFloat(0, v, 8, 23); //TODO: modify for correct fp representation } [Pure] @@ -107,13 +107,13 @@ namespace Microsoft.Basetypes { switch (vals.Length) { case 1: - return Round(vals[0], 23, 8); + return Round(vals[0], 8, 23); case 2: - return new BigFloat(BIM.Parse(vals[0]), Int32.Parse(vals[1]), 23, 8); + return new BigFloat(Int32.Parse(vals[0]), BIM.Parse(vals[1]), 8, 23); case 3: return Round(vals[0], Int32.Parse(vals[1]), Int32.Parse(vals[2])); case 4: - return new BigFloat(BIM.Parse(vals[0]), Int32.Parse(vals[1]), Int32.Parse(vals[2]), Int32.Parse(vals[3])); + return new BigFloat(Int32.Parse(vals[0]), BIM.Parse(vals[1]), Int32.Parse(vals[2]), Int32.Parse(vals[3])); default: throw new FormatException(); //Unreachable } @@ -123,11 +123,11 @@ namespace Microsoft.Basetypes } } - internal BigFloat(BIM mantissa, int exponent, int mantissaSize, int exponentSize) { - this.mantissa = mantissa; - this.mantissaSize = mantissaSize; + internal BigFloat(int exponent, BIM mantissa, int exponentSize, int mantissaSize) { this.exponentSize = exponentSize; this.exponent = exponent + (int)Math.Pow(2, exponentSize - 1); + this.mantissa = mantissa; + this.mantissaSize = mantissaSize; if (exponent < 0) { //ZERO case since the exponent is less than the minimum mantissa = 0; exponent = 0; @@ -197,12 +197,12 @@ namespace Microsoft.Basetypes /// /// /// - public static BigFloat Round(String value, int mantissaSize, int exponentSize) + public static BigFloat Round(String value, int exponentSize, int mantissaSize) { int i = value.IndexOf('.'); if (i == -1) - return Round(BIM.Parse(value), 0, mantissaSize, exponentSize); - return Round(i == 0 ? 0 : BIM.Parse(value.Substring(0, i)), BIM.Parse(value.Substring(i + 1, value.Length - i - 1)), mantissaSize, exponentSize); + return Round(BIM.Parse(value), 0, exponentSize, mantissaSize); + return Round(i == 0 ? 0 : BIM.Parse(value.Substring(0, i)), BIM.Parse(value.Substring(i + 1, value.Length - i - 1)), exponentSize, mantissaSize); } /// @@ -214,7 +214,7 @@ namespace Microsoft.Basetypes /// /// /// - public static BigFloat Round(BIM value, BIM dec_value, int mantissaSize, int exponentSize) + public static BigFloat Round(BIM value, BIM dec_value, int exponentSize, int mantissaSize) { int exp = 0; BIM one = new BIM(1); @@ -262,7 +262,7 @@ namespace Microsoft.Basetypes } } - return new BigFloat(value, exp, mantissaSize, exponentSize); + return new BigFloat(exp, value, exponentSize, mantissaSize); } // ``floor`` rounds towards negative infinity (like SMT-LIBv2's to_int). @@ -395,7 +395,7 @@ namespace Microsoft.Basetypes public BigFloat Abs { //TODO: fix for fp functionality get { - return new BigFloat(BIM.Abs(Mantissa), Exponent, MantissaSize, ExponentSize); + return new BigFloat(Exponent, BIM.Abs(Mantissa), ExponentSize, MantissaSize); } } @@ -403,7 +403,7 @@ namespace Microsoft.Basetypes public BigFloat Negate { //TODO: Modify for correct fp functionality get { - return new BigFloat(BIM.Negate(Mantissa), Exponent, MantissaSize, ExponentSize); + return new BigFloat(Exponent, BIM.Negate(Mantissa), ExponentSize, MantissaSize); } } @@ -415,6 +415,8 @@ namespace Microsoft.Basetypes [Pure] public static BigFloat operator +(BigFloat x, BigFloat y) { //TODO: Modify for correct fp functionality + Contract.Requires(x.ExponentSize == y.ExponentSize); + Contract.Requires(x.MantissaSize == y.MantissaSize); BIM m1 = x.Mantissa; int e1 = x.Exponent; BIM m2 = y.Mantissa; @@ -433,7 +435,7 @@ namespace Microsoft.Basetypes e2++; } - return new BigFloat(m1 + m2, e1, Math.Max(x.MantissaSize, y.MantissaSize), Math.Max(x.ExponentSize, y.ExponentSize)); + return new BigFloat(e1, m1 + m2, x.MantissaSize, x.ExponentSize); } [Pure] @@ -443,7 +445,9 @@ namespace Microsoft.Basetypes [Pure] public static BigFloat operator *(BigFloat x, BigFloat y) { - return new BigFloat(x.Mantissa * y.Mantissa, x.Exponent + y.Exponent, Math.Max(x.MantissaSize, y.MantissaSize), Math.Max(x.ExponentSize, y.ExponentSize)); + Contract.Requires(x.ExponentSize == y.ExponentSize); + Contract.Requires(x.MantissaSize == y.MantissaSize); + return new BigFloat(x.Exponent + y.Exponent, x.Mantissa * y.Mantissa, x.MantissaSize, x.ExponentSize); } diff --git a/Source/Core/AbsyType.cs b/Source/Core/AbsyType.cs index 50fde975..5d41a8dd 100644 --- a/Source/Core/AbsyType.cs +++ b/Source/Core/AbsyType.cs @@ -330,20 +330,22 @@ namespace Microsoft.Boogie { return false; } } - public virtual int FloatMantissa { - get { + public virtual int FloatExponent + { + get + { { Contract.Assert(false); throw new cce.UnreachableException(); - } // Type.FloatMantissa should never be called + } // Type.FloatExponent should never be called } } - public virtual int FloatExponent { + public virtual int FloatMantissa { get { { Contract.Assert(false); throw new cce.UnreachableException(); - } // Type.FloatExponent should never be called + } // Type.FloatMantissa should never be called } } public virtual bool IsBv { @@ -1050,14 +1052,14 @@ namespace Microsoft.Boogie { public FloatType(IToken token, int exponent, int mantissa) : base(token) { Contract.Requires(token != null); - Mantissa = mantissa; Exponent = exponent; + Mantissa = mantissa; } public FloatType(int exponent, int mantissa) : base(Token.NoToken) { - Mantissa = mantissa; Exponent = exponent; + Mantissa = mantissa; } //----------- Cloning ---------------------------------- @@ -1092,7 +1094,7 @@ namespace Microsoft.Boogie { public override string ToString() { Contract.Ensures(Contract.Result() != null); - return "(_ FP " + Exponent + " " + Mantissa + ")"; + return "float (" + Exponent + " " + Mantissa + ")"; } //----------- Equality ---------------------------------- @@ -1119,10 +1121,10 @@ namespace Microsoft.Boogie { //Contract.Requires(cce.NonNullElements(unifier)); that = that.Expanded; if (that is TypeProxy || that is TypeVariable) { - return that.Unify(this, unifiableVariables, unifier); + return that.Unify(this, unifiableVariables, unifier); } else { - return this.Equals(that); + return this.Equals(that); } } diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index bb372cfb..2550c334 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -366,7 +366,7 @@ private class BvBounds : Expr { Get(); Type(out retTy); retTyd = new TypedIdent(retTy.tok, TypedIdent.NoName, retTy); - } else SynErr(97); + } else SynErr(99); if (la.kind == 27) { Get(); Expression(out tmp); @@ -374,7 +374,7 @@ private class BvBounds : Expr { Expect(28); } else if (la.kind == 8) { Get(); - } else SynErr(98); + } else SynErr(100); if (retTyd == null) { // construct a dummy type for the case of syntax error retTyd = new TypedIdent(t, TypedIdent.NoName, new BasicType(t, SimpleType.Int)); diff --git a/Source/Provers/SMTLib/SMTLibLineariser.cs b/Source/Provers/SMTLib/SMTLibLineariser.cs index c7ae9d57..3633a9c0 100644 --- a/Source/Provers/SMTLib/SMTLibLineariser.cs +++ b/Source/Provers/SMTLib/SMTLibLineariser.cs @@ -141,7 +141,7 @@ namespace Microsoft.Boogie.SMTLib else if (t.IsReal) return "Real"; else if (t.IsFloat) - return t.ToString(); //TODO: Match z3 syntax + return "(_ FloatingPoint " + t.FloatExponent + " " + t.FloatMantissa + ")"; //TODO: Match z3 syntax else if (t.IsBv) { return "(_ BitVec " + t.BvBits + ")"; } else { diff --git a/Source/Provers/SMTLib/SMTLibProcess.cs b/Source/Provers/SMTLib/SMTLibProcess.cs index 2b09362b..4a1331c5 100644 --- a/Source/Provers/SMTLib/SMTLibProcess.cs +++ b/Source/Provers/SMTLib/SMTLibProcess.cs @@ -93,7 +93,6 @@ namespace Microsoft.Boogie.SMTLib log = log.Replace("\r", "").Replace("\n", " "); Console.WriteLine("[SMT-INP-{0}] {1}", smtProcessId, log); } - Console.WriteLine(cmd); //TODO: Remove This Line toProver.WriteLine(cmd); } diff --git a/float_test2.bpl b/float_test2.bpl index fa34d8cf..956ac757 100644 --- a/float_test2.bpl +++ b/float_test2.bpl @@ -1,5 +1,5 @@ procedure F() returns () { - var x : float; - var y : float; + var x : float(11 53); + var y : float(11 53); assert x == y; } \ No newline at end of file diff --git a/float_test3.bpl b/float_test3.bpl index 1b70ebf4..e93e7df7 100644 --- a/float_test3.bpl +++ b/float_test3.bpl @@ -1,6 +1,3 @@ procedure F() returns () { - var x : float; - var y : float; - y := x - x; - assert y == x; + assert fp(5) == fp(5 8 23); } \ No newline at end of file diff --git a/float_test4.bpl b/float_test4.bpl index 2388a281..1252dc71 100644 --- a/float_test4.bpl +++ b/float_test4.bpl @@ -1,5 +1,5 @@ procedure F() returns () { var x : float; - x := fp (0 0); - assert x == fp (0 0 23 8); + x := fp (.5 8 23); + assert x == fp (-1 0); } \ No newline at end of file diff --git a/float_test5.bpl b/float_test5.bpl index b91e53e9..2f565b27 100644 --- a/float_test5.bpl +++ b/float_test5.bpl @@ -1,5 +1,5 @@ procedure F() returns () { var x : float; x := fp (0 0); - assert x == fp (1 0 23 8); + assert x == fp (0 0 8 30); } \ No newline at end of file diff --git a/float_test6.bpl b/float_test6.bpl index 12cfbabe..307da9f7 100644 --- a/float_test6.bpl +++ b/float_test6.bpl @@ -1,5 +1,5 @@ - procedure F() returns () { +procedure F() returns () { var x : float; - x := fp (3); - assert x == fp (8388608 1 23 8); + x := fp(1) + fp(1); + assert x == fp(2); } \ No newline at end of file diff --git a/float_test7.bpl b/float_test7.bpl index ca33eb08..cc7a040b 100644 --- a/float_test7.bpl +++ b/float_test7.bpl @@ -1,5 +1,5 @@ - procedure F() returns () { +procedure F() returns () { var x : float; - x := fp (.5 23 8); - assert x == fp (0 -1); + x := fp(.1) + fp(.1) + fp(.1); + assert x == fp(.3); } \ No newline at end of file diff --git a/float_test8.bpl b/float_test8.bpl index 8d881126..7c23c74f 100644 --- a/float_test8.bpl +++ b/float_test8.bpl @@ -1,4 +1,5 @@ procedure F() returns () { + Logic=QF_FP; var x : float; x := fp(.1) + fp(.1); assert x == fp(.2); -- cgit v1.2.3 From 28a20e6eba2919e008f70874b4c12a3ce7ad049c Mon Sep 17 00:00:00 2001 From: Checkmate50 Date: Thu, 17 Sep 2015 03:14:27 -0600 Subject: Added initial support for float addition --- Binaries/Boogie.vshost.exe.manifest | 22 ++++++------ Source/Basetypes/BigFloat.cs | 12 +++---- Source/Core/AbsyExpr.cs | 16 ++++----- Source/Core/Parser.cs | 4 +-- Source/Provers/SMTLib/SMTLibProcess.cs | 1 + Source/Provers/SMTLib/Z3.cs | 4 +-- Source/VCExpr/VCExprAST.cs | 62 ++++++++++++++++++++++++++++++++-- Source/VCExpr/VCExprASTVisitors.cs | 1 - float_test5.bpl | 4 +-- 9 files changed, 89 insertions(+), 37 deletions(-) diff --git a/Binaries/Boogie.vshost.exe.manifest b/Binaries/Boogie.vshost.exe.manifest index 061c9ca9..f96b1d6b 100644 --- a/Binaries/Boogie.vshost.exe.manifest +++ b/Binaries/Boogie.vshost.exe.manifest @@ -1,11 +1,11 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/Source/Basetypes/BigFloat.cs b/Source/Basetypes/BigFloat.cs index 1fb05005..33860a4f 100644 --- a/Source/Basetypes/BigFloat.cs +++ b/Source/Basetypes/BigFloat.cs @@ -17,7 +17,7 @@ namespace Microsoft.Basetypes /// /// A representation of a 32-bit floating point value - /// Note that this value has a 1-bit sign, 8-bit exponent, and 23-bit mantissa + /// Note that this value has a 1-bit sign, 8-bit exponent, and 24-bit mantissa /// public struct BigFloat { @@ -85,17 +85,17 @@ namespace Microsoft.Basetypes [Pure] public static BigFloat FromInt(int v) { - return new BigFloat(v, 0, 23, 8); //TODO: modify for correct fp representation + return new BigFloat(v, 0, 24, 8); //TODO: modify for correct fp representation } [Pure] public static BigFloat FromBigInt(BIM v) { - return new BigFloat(0, v, 8, 23); //TODO: modify for correct fp representation + return new BigFloat(0, v, 8, 24); //TODO: modify for correct fp representation } public static BigFloat FromBigDec(BIM v) { - return new BigFloat(0, v, 8, 23); //TODO: modify for correct fp representation + return new BigFloat(0, v, 8, 24); //TODO: modify for correct fp representation } [Pure] @@ -107,9 +107,9 @@ namespace Microsoft.Basetypes { switch (vals.Length) { case 1: - return Round(vals[0], 8, 23); + return Round(vals[0], 8, 24); case 2: - return new BigFloat(Int32.Parse(vals[0]), BIM.Parse(vals[1]), 8, 23); + return new BigFloat(Int32.Parse(vals[0]), BIM.Parse(vals[1]), 8, 24); case 3: return Round(vals[0], Int32.Parse(vals[1]), Int32.Parse(vals[2])); case 4: diff --git a/Source/Core/AbsyExpr.cs b/Source/Core/AbsyExpr.cs index 7e7ed10a..181076a7 100644 --- a/Source/Core/AbsyExpr.cs +++ b/Source/Core/AbsyExpr.cs @@ -1519,8 +1519,6 @@ namespace Microsoft.Boogie { return "mod"; case Opcode.RealDiv: return "/"; - case Opcode.FloatDiv: - return "/"; case Opcode.Pow: return "**"; case Opcode.Eq: @@ -1583,10 +1581,6 @@ namespace Microsoft.Boogie { opBindingStrength = 0x50; fragileRightContext = true; break; - case Opcode.FloatDiv: //TODO: Modify (potentially) - opBindingStrength = 0x50; - fragileRightContext = true; - break; case Opcode.Pow: opBindingStrength = 0x60; fragileRightContext = true; @@ -1707,10 +1701,12 @@ namespace Microsoft.Boogie { if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { return Type.Real; } - //if (arg0type.Unify(Type.Float) && arg1type.Unify(Type.Float)) - //{ - //return Type.Float; - //} + if (arg0type.IsFloat && arg0type.Unify(arg1type)) { + return new FloatType(arg0.Type.FloatExponent, arg0.Type.FloatMantissa); + } + if (arg1type.IsFloat && arg1type.Unify(arg0type)) { + return new FloatType(arg1.Type.FloatExponent, arg1.Type.FloatMantissa); + } goto BAD_TYPE; case Opcode.Div: case Opcode.Mod: diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index 2550c334..889d7be8 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -678,7 +678,7 @@ private class BvBounds : Expr { Expect(10); } else - ty = new FloatType(t, 8, 23); + ty = new FloatType(t, 8, 24); } else if (la.kind == 16) { Get(); ty = new BasicType(t, SimpleType.Bool); @@ -1914,7 +1914,7 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { catch (FormatException) { this.SemErr("incorrectly formatted floating point"); - n = BigFloat.ZERO(8, 23); + n = BigFloat.ZERO(8, 24); } } diff --git a/Source/Provers/SMTLib/SMTLibProcess.cs b/Source/Provers/SMTLib/SMTLibProcess.cs index 4a1331c5..4982d81e 100644 --- a/Source/Provers/SMTLib/SMTLibProcess.cs +++ b/Source/Provers/SMTLib/SMTLibProcess.cs @@ -93,6 +93,7 @@ namespace Microsoft.Boogie.SMTLib log = log.Replace("\r", "").Replace("\n", " "); Console.WriteLine("[SMT-INP-{0}] {1}", smtProcessId, log); } + Console.WriteLine(cmd); toProver.WriteLine(cmd); } diff --git a/Source/Provers/SMTLib/Z3.cs b/Source/Provers/SMTLib/Z3.cs index 250e04c9..8e8b2d55 100644 --- a/Source/Provers/SMTLib/Z3.cs +++ b/Source/Provers/SMTLib/Z3.cs @@ -253,7 +253,7 @@ namespace Microsoft.Boogie.SMTLib //if (options.Inspector != null) // options.WeakAddSmtOption("PROGRESS_SAMPLING_FREQ", "100"); - options.AddWeakSmtOption("TYPE_CHECK", "true"); + options.AddWeakSmtOption("TYPE_CHECK", "false"); options.AddWeakSmtOption("smt.BV.REFLECT", "true"); if (options.TimeLimit > 0) @@ -334,7 +334,7 @@ namespace Microsoft.Boogie.SMTLib //if (options.Inspector != null) // options.WeakAddSmtOption("PROGRESS_SAMPLING_FREQ", "100"); - options.AddWeakSmtOption("TYPE_CHECK", "true"); + options.AddWeakSmtOption("TYPE_CHECK", "false"); options.AddWeakSmtOption("BV_REFLECT", "true"); if (options.TimeLimit > 0) diff --git a/Source/VCExpr/VCExprAST.cs b/Source/VCExpr/VCExprAST.cs index 36692f30..c44800fc 100644 --- a/Source/VCExpr/VCExprAST.cs +++ b/Source/VCExpr/VCExprAST.cs @@ -357,6 +357,15 @@ namespace Microsoft.Boogie { return new VCExprBoogieFunctionOp(func); } + // Float nodes + + public VCExpr AddFOp(VCExpr f1, VCExpr f2) + { + Contract.Requires(f1 != null); + Contract.Requires(f2 != null); + return Function(new VCExprFloatOp(f1.Type.FloatExponent, f1.Type.FloatMantissa)); + } + // Bitvector nodes public VCExpr Bitvector(BvConst bv) { @@ -403,7 +412,6 @@ namespace Microsoft.Boogie { DivOp, ModOp, RealDivOp, - FloatDivOp, PowOp, LtOp, LeOp, @@ -1309,8 +1317,6 @@ namespace Microsoft.Boogie.VCExprAST { return visitor.VisitModOp(expr, arg); case VCExpressionGenerator.SingletonOp.RealDivOp: return visitor.VisitRealDivOp(expr, arg); - case VCExpressionGenerator.SingletonOp.FloatDivOp: - return visitor.VisitFloatDivOp(expr, arg); case VCExpressionGenerator.SingletonOp.PowOp: return visitor.VisitPowOp(expr, arg); case VCExpressionGenerator.SingletonOp.LtOp: @@ -1668,6 +1674,56 @@ namespace Microsoft.Boogie.VCExprAST { } } + ///////////////////////////////////////////////////////////////////////////////// + // Float operators + + public class VCExprFloatOp : VCExprOp { + public readonly int Mantissa; + public readonly int Exponent; + + public override int Arity { + get { + return 1; + } + } + public override int TypeParamArity { + get { + return 0; + } + } + public override Type InferType(List args, List/*!*/ typeArgs) { + //Contract.Requires(cce.NonNullElements(typeArgs)); + //Contract.Requires(cce.NonNullElements(args)); + Contract.Ensures(Contract.Result() != null); + return Type.GetFloatType(Exponent, Mantissa); + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (Object.ReferenceEquals(this, that)) + return true; + if (that is VCExprFloatOp) + return this.Exponent == ((VCExprFloatOp)that).Exponent && this.Mantissa == ((VCExprFloatOp)that).Mantissa; + return false; + } + [Pure] + public override int GetHashCode() { + return Exponent * 81748912 + Mantissa * 67867979; + } + + internal VCExprFloatOp(int exp, int man) { + this.Exponent = exp; + this.Mantissa = man; + } + public override Result Accept + (VCExprNAry expr, IVCExprOpVisitor visitor, Arg arg) { + //Contract.Requires(visitor != null); + //Contract.Requires(expr != null); + return visitor.VisitBvOp(expr, arg); + } + } + ///////////////////////////////////////////////////////////////////////////////// // Bitvector operators diff --git a/Source/VCExpr/VCExprASTVisitors.cs b/Source/VCExpr/VCExprASTVisitors.cs index 1bcce113..a1fb2ff4 100644 --- a/Source/VCExpr/VCExprASTVisitors.cs +++ b/Source/VCExpr/VCExprASTVisitors.cs @@ -77,7 +77,6 @@ namespace Microsoft.Boogie.VCExprAST { Result VisitDivOp(VCExprNAry node, Arg arg); Result VisitModOp(VCExprNAry node, Arg arg); Result VisitRealDivOp(VCExprNAry node, Arg arg); - Result VisitFloatDivOp(VCExprNAry node, Arg arg); //TODO: Add this to references from above and below Result VisitPowOp(VCExprNAry node, Arg arg); Result VisitLtOp(VCExprNAry node, Arg arg); Result VisitLeOp(VCExprNAry node, Arg arg); diff --git a/float_test5.bpl b/float_test5.bpl index 2f565b27..c3d279f2 100644 --- a/float_test5.bpl +++ b/float_test5.bpl @@ -1,5 +1,5 @@ procedure F() returns () { var x : float; - x := fp (0 0); - assert x == fp (0 0 8 30); + var y : float; + assert x + y == fp(0); } \ No newline at end of file -- cgit v1.2.3 From 80f3d4ed1bb221adbd3c7162acea10920b9fab73 Mon Sep 17 00:00:00 2001 From: Checkmate50 Date: Wed, 23 Sep 2015 04:08:00 -0600 Subject: Modified BigFloat to avoid evaluating the floating point value before sending it to z3 --- Source/Basetypes/BigFloat.cs | 1006 ++++++++++++++--------------- Source/Core/AbsyExpr.cs | 20 +- Source/Provers/SMTLib/SMTLibLineariser.cs | 12 - Source/VCExpr/VCExprASTPrinter.cs | 12 - float_test5.bpl | 5 +- float_test6.bpl | 4 +- 6 files changed, 505 insertions(+), 554 deletions(-) diff --git a/Source/Basetypes/BigFloat.cs b/Source/Basetypes/BigFloat.cs index 33860a4f..e9d5e670 100644 --- a/Source/Basetypes/BigFloat.cs +++ b/Source/Basetypes/BigFloat.cs @@ -1,516 +1,490 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Diagnostics.Contracts; -using System.Diagnostics; - -namespace Microsoft.Basetypes -{ - using BIM = System.Numerics.BigInteger; - - /// - /// A representation of a 32-bit floating point value - /// Note that this value has a 1-bit sign, 8-bit exponent, and 24-bit mantissa - /// - public struct BigFloat - { - //Please note that this code outline is copy-pasted from BigDec.cs - - // the internal representation - [Rep] - internal readonly BIM mantissa; //Note that the mantissa arrangement matches standard fp arrangement (most significant bit is farthest left) - [Rep] - internal readonly Boolean isNegative; //The left-most (sign) bit in the float representation - [Rep] - internal readonly int mantissaSize; - [Rep] - internal readonly int exponent; //The value of the exponent is always positive as per fp representation requirements - [Rep] - internal readonly int exponentSize; //The bit size of the exponent - - public BIM Mantissa { - get { - return isNegative ? -mantissa : mantissa; - } - } - - public int Exponent { - get { - return exponent - (int)Math.Pow(2, exponentSize - 1); //account for shift - } - } - - public int MantissaSize - { - get - { - return mantissaSize; - } - } - - public int ExponentSize - { - get - { - return exponentSize; - } - } - - public static BigFloat ZERO(int mantissaSize, int exponentSize) { return new BigFloat(0, 0, mantissaSize, exponentSize); } //Does not include negative zero - public static BigFloat INF(int mantissaSize, int exponentSize) { return new BigFloat(0, 0, mantissaSize, exponentSize); } //Modify for IEEE standard - public static BigFloat NEGINF(int mantissaSize, int exponentSize) { return new BigFloat(0, 0, mantissaSize, exponentSize); } //Modify for IEEE standard - public static BigFloat NAN(int mantissaSize, int exponentSize) { return new BigFloat(0, 0, mantissaSize, exponentSize); } //Modify for IEEE standard - - private static readonly BIM two = new BIM(2); - private static BIM two_n(int n) { - BIM toReturn = new BIM(1); - for (int i = 0; i < n; i++) - toReturn = toReturn * two; - return toReturn; - } - - - //////////////////////////////////////////////////////////////////////////// - // Constructors - - //Please note that these constructors will be called throughout boogie - //For a complete summary of where this class has been added, simply view constructor references - - [Pure] - public static BigFloat FromInt(int v) { - return new BigFloat(v, 0, 24, 8); //TODO: modify for correct fp representation - } - - [Pure] - public static BigFloat FromBigInt(BIM v) { - return new BigFloat(0, v, 8, 24); //TODO: modify for correct fp representation - } - - public static BigFloat FromBigDec(BIM v) - { - return new BigFloat(0, v, 8, 24); //TODO: modify for correct fp representation - } - - [Pure] - public static BigFloat FromString(string v) { - String[] vals = v.Split(' '); - if (vals.Length == 0 || vals.Length > 4) - throw new FormatException(); - try - { - switch (vals.Length) { - case 1: - return Round(vals[0], 8, 24); - case 2: - return new BigFloat(Int32.Parse(vals[0]), BIM.Parse(vals[1]), 8, 24); - case 3: - return Round(vals[0], Int32.Parse(vals[1]), Int32.Parse(vals[2])); - case 4: - return new BigFloat(Int32.Parse(vals[0]), BIM.Parse(vals[1]), Int32.Parse(vals[2]), Int32.Parse(vals[3])); - default: - throw new FormatException(); //Unreachable - } - } - catch (Exception) { //Catch parsing errors - throw new FormatException(); - } - } - - internal BigFloat(int exponent, BIM mantissa, int exponentSize, int mantissaSize) { - this.exponentSize = exponentSize; - this.exponent = exponent + (int)Math.Pow(2, exponentSize - 1); - this.mantissa = mantissa; - this.mantissaSize = mantissaSize; - if (exponent < 0) { //ZERO case since the exponent is less than the minimum - mantissa = 0; - exponent = 0; - this.isNegative = false; - return; - } - - this.isNegative = mantissa < 0; - if (this.isNegative) - mantissa = -mantissa; // ==> mantissa > 0 - - BIM max = maxMantissa(); - while (this.mantissa > max) { - this.mantissa = this.mantissa / two; - this.exponent++; - } - - //TODO: Add overflow check for exponent vs exponent size - //this.exponent = this.exponent % this.exponentSize; ?? - } - - private BIM maxMantissa() - { - BIM result = new BIM(1); - for (int i = 0; i < mantissaSize; i++) - result = result * two; - return result - 1; - } - private int maxExponent() { return (int)Math.Pow(2, exponentSize) - 1; } - - - - //////////////////////////////////////////////////////////////////////////// - // Basic object operations - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is BigFloat)) - return false; - - return (this == (BigFloat)obj); - } - - [Pure] - public override int GetHashCode() { - return Mantissa.GetHashCode() * 13 + Exponent.GetHashCode(); - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return String.Format("{0}x2^{1}", Mantissa.ToString(), Exponent.ToString()); - } - - - //////////////////////////////////////////////////////////////////////////// - // Conversion operations - - /// - /// Converts the given decimal value (provided as a string) to the nearest floating point approximation - /// the returned fp assumes the given mantissa and exponent size - /// - /// - /// - /// - /// - public static BigFloat Round(String value, int exponentSize, int mantissaSize) - { - int i = value.IndexOf('.'); - if (i == -1) - return Round(BIM.Parse(value), 0, exponentSize, mantissaSize); - return Round(i == 0 ? 0 : BIM.Parse(value.Substring(0, i)), BIM.Parse(value.Substring(i + 1, value.Length - i - 1)), exponentSize, mantissaSize); - } - - /// - /// Converts value.dec_value to a the closest float approximation with the given mantissaSize, exponentSize - /// Returns the result of this calculation - /// - /// - /// - /// - /// - /// - public static BigFloat Round(BIM value, BIM dec_value, int exponentSize, int mantissaSize) - { - int exp = 0; - BIM one = new BIM(1); - BIM ten = new BIM(10); - BIM dec_max = new BIM(0); //represents the order of magnitude of dec_value for carrying during calculations - - //First, determine the exponent - while (value > one) { //Divide by two, increment exponent by 1 - if (!(value % two).IsZero) { //Add "1.0" to the decimal - dec_max = new BIM(10); - while (dec_max < dec_value) - dec_max = dec_max * ten; - dec_value = dec_value + dec_max; - } - value = value / two; - if (!(dec_value % ten).IsZero) - dec_value = dec_value * ten; //Creates excess zeroes to avoid losing data during division - dec_value = dec_value / two; - exp++; - } - if (value.IsZero && !dec_value.IsZero) { - dec_max = new BIM(10); - while (dec_max < dec_value) - dec_max = dec_max * ten; - while (value.IsZero) {//Multiply by two, decrement exponent by 1 - dec_value = dec_value * two; - if (dec_value >= dec_max) { - dec_value = dec_value - dec_max; - value = value + one; - } - exp--; - } - } - - //Second, calculate the mantissa - value = new BIM(0); //remove implicit bit - dec_max = new BIM(10); - while (dec_max < dec_value) - dec_max = dec_max * ten; - for (int i = mantissaSize; i > 0 && !dec_value.IsZero; i--) { //Multiply by two until the mantissa is fully calculated - dec_value = dec_value * two; - if (dec_value >= dec_max) { - dec_value = dec_value - dec_max; - value = value + two_n(i); //Note that i is decrementing so that the most significant bit is left-most in the representation - } - } - - return new BigFloat(exp, value, exponentSize, mantissaSize); - } - - // ``floor`` rounds towards negative infinity (like SMT-LIBv2's to_int). - /// - /// Computes the floor and ceiling of this BigFloat. Note the choice of rounding towards negative - /// infinity rather than zero for floor is because SMT-LIBv2's to_int function floors this way. - /// - /// The Floor (rounded towards negative infinity) - /// Ceiling (rounded towards positive infinity) - public void FloorCeiling(out BIM floor, out BIM ceiling) { - //TODO: fix for fp functionality - BIM n = Mantissa; - int e = Exponent; - if (n.IsZero) { - floor = ceiling = n; - } else if (0 <= e) { - // it's an integer - for (; 0 < e; e--) { - n = n * two; - } - floor = ceiling = n; - } else { - // it's a non-zero integer, so the ceiling is one more than the floor - for (; e < 0 && !n.IsZero; e++) { - n = n / two; // Division rounds towards negative infinity - } - - if (!isNegative) { - floor = n; - ceiling = n + 1; - } else { - ceiling = n; - floor = n - 1; - } - } - Debug.Assert(floor <= ceiling, "Invariant was not maintained"); - } - - [Pure] - public String ToDecimalString(int maxDigits) { - //TODO: fix for fp functionality - string s = Mantissa.ToString(); - int digits = (isNegative) ? s.Length - 1 : s.Length; - BIM max = BIM.Pow(10, maxDigits); - BIM min = -max; - - if (Exponent >= 0) { - if (maxDigits < digits || maxDigits - digits < Exponent) { - return String.Format("{0}.0", (!isNegative) ? max.ToString() : min.ToString()); - } - else { - return String.Format("{0}{1}.0", s, new string('0', Exponent)); - } - } - else { - int exp = -Exponent; - - if (exp < digits) { - int intDigits = digits - exp; - if (maxDigits < intDigits) { - return String.Format("{0}.0", (!isNegative) ? max.ToString() : min.ToString()); - } - else { - int fracDigits = Math.Min(maxDigits, digits - intDigits); - return String.Format("{0}.{1}", s.Substring(0, intDigits), s.Substring(intDigits, fracDigits)); - } - } - else { - int fracDigits = Math.Min(maxDigits, digits); - return String.Format("0.{0}{1}", new string('0', exp - fracDigits), s.Substring(0, fracDigits)); - } - } - } - - [Pure] - public string ToDecimalString() { - //TODO: fix for fp functionality - string m = Mantissa.ToString(); - var e = Exponent; - if (0 <= Exponent) { - return m + Zeros(e) + ".0"; - } else { - e = -e; - // compute k to be the longest suffix of m consisting of all zeros (but no longer than e, and not the entire string) - var maxK = e < m.Length ? e : m.Length - 1; - var last = m.Length - 1; - var k = 0; - while (k < maxK && m[last - k] == '0') { - k++; - } - if (0 < k) { - // chop off the suffix of k zeros from m and adjust e accordingly - m = m.Substring(0, m.Length - k); - e -= k; - } - if (e == 0) { - return m; - } else if (e < m.Length) { - var n = m.Length - e; - return m.Substring(0, n) + "." + m.Substring(n); - } else { - return "0." + Zeros(e - m.Length) + m; - } - } - } - - [Pure] - public static string Zeros(int n) { - //TODO: fix for fp functionality - Contract.Requires(0 <= n); - if (n <= 10) { - var tenZeros = "0000000000"; - return tenZeros.Substring(0, n); - } else { - var d = n / 2; - var s = Zeros(d); - if (n % 2 == 0) { - return s + s; - } else { - return s + s + "0"; - } - } - } - - - //////////////////////////////////////////////////////////////////////////// - // Basic arithmetic operations - - [Pure] - public BigFloat Abs { - //TODO: fix for fp functionality - get { - return new BigFloat(Exponent, BIM.Abs(Mantissa), ExponentSize, MantissaSize); - } - } - - [Pure] - public BigFloat Negate { - //TODO: Modify for correct fp functionality - get { - return new BigFloat(Exponent, BIM.Negate(Mantissa), ExponentSize, MantissaSize); - } - } - - [Pure] - public static BigFloat operator -(BigFloat x) { - return x.Negate; - } - - [Pure] - public static BigFloat operator +(BigFloat x, BigFloat y) { - //TODO: Modify for correct fp functionality - Contract.Requires(x.ExponentSize == y.ExponentSize); - Contract.Requires(x.MantissaSize == y.MantissaSize); - BIM m1 = x.Mantissa; - int e1 = x.Exponent; - BIM m2 = y.Mantissa; - int e2 = y.Exponent; - m1 = m1 + two_n(x.mantissaSize + 1); //Add implicit bit - m2 = m2 + two_n(y.mantissaSize + 1); - if (e2 > e1) { - m1 = y.Mantissa; - e1 = y.Exponent; - m2 = x.Mantissa; - e2 = x.Exponent; - } - - while (e2 < e1) { - m2 = m2 / two; - e2++; - } - - return new BigFloat(e1, m1 + m2, x.MantissaSize, x.ExponentSize); - } - - [Pure] - public static BigFloat operator -(BigFloat x, BigFloat y) { - return x + y.Negate; - } - - [Pure] - public static BigFloat operator *(BigFloat x, BigFloat y) { - Contract.Requires(x.ExponentSize == y.ExponentSize); - Contract.Requires(x.MantissaSize == y.MantissaSize); - return new BigFloat(x.Exponent + y.Exponent, x.Mantissa * y.Mantissa, x.MantissaSize, x.ExponentSize); - } - - - //////////////////////////////////////////////////////////////////////////// - // Some basic comparison operations - - public bool IsPositive { - get { - return (!isNegative); - } - } - - public bool IsNegative { - get { - return (isNegative); - } - } - - public bool IsZero { - get { - return Mantissa.IsZero && Exponent == 0; - } - } - - [Pure] - public int CompareTo(BigFloat that) { - if (this.exponent > that.exponent) - return 1; - if (this.exponent < that.exponent) - return -1; - if (this.Mantissa == that.Mantissa) - return 0; - return this.Mantissa > that.Mantissa ? 1 : -1; - } - - [Pure] - public static bool operator ==(BigFloat x, BigFloat y) { - return x.CompareTo(y) == 0; - } - - [Pure] - public static bool operator !=(BigFloat x, BigFloat y) { - return x.CompareTo(y) != 0; - } - - [Pure] - public static bool operator <(BigFloat x, BigFloat y) { - return x.CompareTo(y) < 0; - } - - [Pure] - public static bool operator >(BigFloat x, BigFloat y) { - return x.CompareTo(y) > 0; - } - - [Pure] - public static bool operator <=(BigFloat x, BigFloat y) { - return x.CompareTo(y) <= 0; - } - - [Pure] - public static bool operator >=(BigFloat x, BigFloat y) { - return x.CompareTo(y) >= 0; - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Diagnostics.Contracts; +using System.Diagnostics; + +namespace Microsoft.Basetypes +{ + using BIM = System.Numerics.BigInteger; + + /// + /// A representation of a 32-bit floating point value + /// Note that this value has a 1-bit sign, 8-bit exponent, and 24-bit mantissa + /// + public struct BigFloat + { + //Please note that this code outline is copy-pasted from BigDec.cs + + // the internal representation + [Rep] + internal readonly BIM mantissa; //Note that the mantissa arrangement matches standard fp arrangement (most significant bit is farthest left) + [Rep] + internal readonly int mantissaSize; + [Rep] + internal readonly int exponent; //The value of the exponent is always positive as per fp representation requirements + [Rep] + internal readonly int exponentSize; //The bit size of the exponent + [Rep] + internal readonly BigDec dec_value; + [Rep] + internal readonly bool isDec; + + public BIM Mantissa { + get { + return mantissa; + } + } + + public int Exponent { + get { + return exponent; + } + } + + public int MantissaSize { + get { + return mantissaSize; + } + } + + public int ExponentSize { + get { + return exponentSize; + } + } + + public BigDec Decimal { + get { + return dec_value; + } + } + + public bool IsDec { + get { + return IsDec; + } + } + + public static BigFloat ZERO(int mantissaSize, int exponentSize) { return new BigFloat(0, 0, mantissaSize, exponentSize); } //Does not include negative zero + + private static readonly BIM two = new BIM(2); + private static BIM two_n(int n) { + BIM toReturn = new BIM(1); + for (int i = 0; i < n; i++) + toReturn = toReturn * two; + return toReturn; + } + + + //////////////////////////////////////////////////////////////////////////// + // Constructors + + //Please note that these constructors will be called throughout boogie + //For a complete summary of where this class has been added, simply view constructor references + + [Pure] + public static BigFloat FromInt(int v) { + return new BigFloat(v, 0, 24, 8); + } + + [Pure] + public static BigFloat FromBigInt(BIM v) { + return new BigFloat(0, v, 8, 24); + } + + public static BigFloat FromBigDec(BigDec v) + { + return new BigFloat(v, 8, 24); + } + + [Pure] + public static BigFloat FromString(string v) { + String[] vals = v.Split(' '); + if (vals.Length == 0 || vals.Length > 4) + throw new FormatException(); + try + { + switch (vals.Length) { + case 1: + return new BigFloat(BigDec.FromString(vals[0]), 8, 24); + case 2: + return new BigFloat(Int32.Parse(vals[0]), BIM.Parse(vals[1]), 8, 24); + case 3: + return new BigFloat(BigDec.FromString(vals[0]), Int32.Parse(vals[1]), Int32.Parse(vals[2])); + case 4: + return new BigFloat(Int32.Parse(vals[0]), BIM.Parse(vals[1]), Int32.Parse(vals[2]), Int32.Parse(vals[3])); + default: + throw new FormatException(); //Unreachable + } + } + catch (Exception) { //Catch parsing errors + throw new FormatException(); + } + } + + internal BigFloat(int exponent, BIM mantissa, int exponentSize, int mantissaSize) { + this.exponentSize = exponentSize; + this.exponent = exponent; + this.mantissa = mantissa; + this.mantissaSize = mantissaSize; + this.isDec = false; + this.dec_value = BigDec.ZERO; + } + + internal BigFloat(BigDec dec_value, int exponentSize, int mantissaSize) { + this.exponentSize = exponentSize; + this.mantissaSize = mantissaSize; + this.exponent = 0; + this.mantissa = 0; + this.isDec = true; + this.dec_value = dec_value; + } + + private BIM maxMantissa() + { + BIM result = new BIM(1); + for (int i = 0; i < mantissaSize; i++) + result = result * two; + return result - 1; + } + private int maxExponent() { return (int)Math.Pow(2, exponentSize) - 1; } + + + + //////////////////////////////////////////////////////////////////////////// + // Basic object operations + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is BigFloat)) + return false; + + return (this == (BigFloat)obj); + } + + [Pure] + public override int GetHashCode() { + return Mantissa.GetHashCode() * 13 + Exponent.GetHashCode(); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return String.Format("{0}x2^{1}", Mantissa.ToString(), Exponent.ToString()); + } + + + //////////////////////////////////////////////////////////////////////////// + // Conversion operations + + /// + /// NOTE: THIS METHOD MAY NOT WORK AS EXPECTED!!! + /// Converts the given decimal value (provided as a string) to the nearest floating point approximation + /// the returned fp assumes the given mantissa and exponent size + /// + /// + /// + /// + /// + public static BigFloat Round(String value, int exponentSize, int mantissaSize) + { + int i = value.IndexOf('.'); + if (i == -1) + return Round(BIM.Parse(value), 0, exponentSize, mantissaSize); + return Round(i == 0 ? 0 : BIM.Parse(value.Substring(0, i)), BIM.Parse(value.Substring(i + 1, value.Length - i - 1)), exponentSize, mantissaSize); + } + + /// + /// NOTE: THIS METHOD MAY NOT WORK AS EXPECTED!!!! + /// Converts value.dec_value to a the closest float approximation with the given mantissaSize, exponentSize + /// Returns the result of this calculation + /// + /// + /// + /// + /// + /// + public static BigFloat Round(BIM value, BIM dec_value, int exponentSize, int mantissaSize) + { + int exp = 0; + BIM one = new BIM(1); + BIM ten = new BIM(10); + BIM dec_max = new BIM(0); //represents the order of magnitude of dec_value for carrying during calculations + + //First, determine the exponent + while (value > one) { //Divide by two, increment exponent by 1 + if (!(value % two).IsZero) { //Add "1.0" to the decimal + dec_max = new BIM(10); + while (dec_max < dec_value) + dec_max = dec_max * ten; + dec_value = dec_value + dec_max; + } + value = value / two; + if (!(dec_value % ten).IsZero) + dec_value = dec_value * ten; //Creates excess zeroes to avoid losing data during division + dec_value = dec_value / two; + exp++; + } + if (value.IsZero && !dec_value.IsZero) { + dec_max = new BIM(10); + while (dec_max < dec_value) + dec_max = dec_max * ten; + while (value.IsZero) {//Multiply by two, decrement exponent by 1 + dec_value = dec_value * two; + if (dec_value >= dec_max) { + dec_value = dec_value - dec_max; + value = value + one; + } + exp--; + } + } + + //Second, calculate the mantissa + value = new BIM(0); //remove implicit bit + dec_max = new BIM(10); + while (dec_max < dec_value) + dec_max = dec_max * ten; + for (int i = mantissaSize; i > 0 && !dec_value.IsZero; i--) { //Multiply by two until the mantissa is fully calculated + dec_value = dec_value * two; + if (dec_value >= dec_max) { + dec_value = dec_value - dec_max; + value = value + two_n(i); //Note that i is decrementing so that the most significant bit is left-most in the representation + } + } + + return new BigFloat(exp, value, exponentSize, mantissaSize); + } + + // ``floor`` rounds towards negative infinity (like SMT-LIBv2's to_int). + /// + /// NOTE: THIS PROBABLY WON'T GIVE USEFUL OUTPUT!!! + /// Computes the floor and ceiling of this BigFloat. Note the choice of rounding towards negative + /// infinity rather than zero for floor is because SMT-LIBv2's to_int function floors this way. + /// + /// The Floor (rounded towards negative infinity) + /// Ceiling (rounded towards positive infinity) + public void FloorCeiling(out BIM floor, out BIM ceiling) { + //TODO: fix for fp functionality + BIM n = Mantissa; + int e = Exponent; + if (n.IsZero) { + floor = ceiling = n; + } else if (0 <= e) { + // it's an integer + for (; 0 < e; e--) { + n = n * two; + } + floor = ceiling = n; + } else { + // it's a non-zero integer, so the ceiling is one more than the floor + for (; e < 0 && !n.IsZero; e++) { + n = n / two; // Division rounds towards negative infinity + } + + if (!IsNegative) { + floor = n; + ceiling = n + 1; + } else { + ceiling = n; + floor = n - 1; + } + } + Debug.Assert(floor <= ceiling, "Invariant was not maintained"); + } + + [Pure] + public String ToDecimalString(int maxDigits) { + //TODO: fix for fp functionality + { + throw new NotImplementedException(); + } + } + + [Pure] + public string ToDecimalString() { + //TODO: fix for fp functionality + string m = Mantissa.ToString(); + var e = Exponent; + if (0 <= Exponent) { + return m + Zeros(e) + ".0"; + } else { + e = -e; + // compute k to be the longest suffix of m consisting of all zeros (but no longer than e, and not the entire string) + var maxK = e < m.Length ? e : m.Length - 1; + var last = m.Length - 1; + var k = 0; + while (k < maxK && m[last - k] == '0') { + k++; + } + if (0 < k) { + // chop off the suffix of k zeros from m and adjust e accordingly + m = m.Substring(0, m.Length - k); + e -= k; + } + if (e == 0) { + return m; + } else if (e < m.Length) { + var n = m.Length - e; + return m.Substring(0, n) + "." + m.Substring(n); + } else { + return "0." + Zeros(e - m.Length) + m; + } + } + } + + [Pure] + public static string Zeros(int n) { + //TODO: fix for fp functionality + Contract.Requires(0 <= n); + if (n <= 10) { + var tenZeros = "0000000000"; + return tenZeros.Substring(0, n); + } else { + var d = n / 2; + var s = Zeros(d); + if (n % 2 == 0) { + return s + s; + } else { + return s + s + "0"; + } + } + } + + + //////////////////////////////////////////////////////////////////////////// + // Basic arithmetic operations + + [Pure] + public BigFloat Abs { + //TODO: fix for fp functionality + get { + return new BigFloat(Exponent, BIM.Abs(Mantissa), ExponentSize, MantissaSize); + } + } + + [Pure] + public BigFloat Negate { + //TODO: Modify for correct fp functionality + get { + return new BigFloat(Exponent, BIM.Negate(Mantissa), ExponentSize, MantissaSize); + } + } + + [Pure] + public static BigFloat operator -(BigFloat x) { + return x.Negate; + } + + [Pure] + public static BigFloat operator +(BigFloat x, BigFloat y) { + //TODO: Modify for correct fp functionality + Contract.Requires(x.ExponentSize == y.ExponentSize); + Contract.Requires(x.MantissaSize == y.MantissaSize); + BIM m1 = x.Mantissa; + int e1 = x.Exponent; + BIM m2 = y.Mantissa; + int e2 = y.Exponent; + m1 = m1 + two_n(x.mantissaSize + 1); //Add implicit bit + m2 = m2 + two_n(y.mantissaSize + 1); + if (e2 > e1) { + m1 = y.Mantissa; + e1 = y.Exponent; + m2 = x.Mantissa; + e2 = x.Exponent; + } + + while (e2 < e1) { + m2 = m2 / two; + e2++; + } + + return new BigFloat(e1, m1 + m2, x.MantissaSize, x.ExponentSize); + } + + [Pure] + public static BigFloat operator -(BigFloat x, BigFloat y) { + return x + y.Negate; + } + + [Pure] + public static BigFloat operator *(BigFloat x, BigFloat y) { + Contract.Requires(x.ExponentSize == y.ExponentSize); + Contract.Requires(x.MantissaSize == y.MantissaSize); + return new BigFloat(x.Exponent + y.Exponent, x.Mantissa * y.Mantissa, x.MantissaSize, x.ExponentSize); + } + + + //////////////////////////////////////////////////////////////////////////// + // Some basic comparison operations + + public bool IsPositive { + get { + return !IsNegative; + } + } + + public bool IsNegative { + get { + return (isDec && dec_value >= BigDec.ZERO) || mantissa >= 0; + } + } + + public bool IsZero { + get { + return Mantissa.IsZero && Exponent == 0; + } + } + + [Pure] + public int CompareTo(BigFloat that) { + if (this.exponent > that.exponent) + return 1; + if (this.exponent < that.exponent) + return -1; + if (this.Mantissa == that.Mantissa) + return 0; + return this.Mantissa > that.Mantissa ? 1 : -1; + } + + [Pure] + public static bool operator ==(BigFloat x, BigFloat y) { + return x.CompareTo(y) == 0; + } + + [Pure] + public static bool operator !=(BigFloat x, BigFloat y) { + return x.CompareTo(y) != 0; + } + + [Pure] + public static bool operator <(BigFloat x, BigFloat y) { + return x.CompareTo(y) < 0; + } + + [Pure] + public static bool operator >(BigFloat x, BigFloat y) { + return x.CompareTo(y) > 0; + } + + [Pure] + public static bool operator <=(BigFloat x, BigFloat y) { + return x.CompareTo(y) <= 0; + } + + [Pure] + public static bool operator >=(BigFloat x, BigFloat y) { + return x.CompareTo(y) >= 0; + } + } +} diff --git a/Source/Core/AbsyExpr.cs b/Source/Core/AbsyExpr.cs index 181076a7..cf6fb922 100644 --- a/Source/Core/AbsyExpr.cs +++ b/Source/Core/AbsyExpr.cs @@ -1702,10 +1702,10 @@ namespace Microsoft.Boogie { return Type.Real; } if (arg0type.IsFloat && arg0type.Unify(arg1type)) { - return new FloatType(arg0.Type.FloatExponent, arg0.Type.FloatMantissa); + return Type.GetFloatType(arg0.Type.FloatExponent, arg0.Type.FloatMantissa); } if (arg1type.IsFloat && arg1type.Unify(arg0type)) { - return new FloatType(arg1.Type.FloatExponent, arg1.Type.FloatMantissa); + return Type.GetFloatType(arg1.Type.FloatExponent, arg1.Type.FloatMantissa); } goto BAD_TYPE; case Opcode.Div: @@ -1719,6 +1719,12 @@ namespace Microsoft.Boogie { (arg1type.Unify(Type.Int) || arg1type.Unify(Type.Real))) { return Type.Real; } + if (arg0type.IsFloat && arg0type.Unify(arg1type)) { + return Type.GetFloatType(arg0.Type.FloatExponent, arg0.Type.FloatMantissa); + } + if (arg1type.IsFloat && arg1type.Unify(arg0type)) { + return Type.GetFloatType(arg1.Type.FloatExponent, arg1.Type.FloatMantissa); + } goto BAD_TYPE; case Opcode.Pow: if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { @@ -1751,10 +1757,9 @@ namespace Microsoft.Boogie { if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { return Type.Bool; } - //if (arg0type.Unify(Type.Float) && arg1type.Unify(Type.Float)) - //{ - //return Type.Bool; - //} + if ((arg0type.IsFloat && arg0type.Unify(arg1type)) || (arg1type.IsFloat && arg1type.Unify(arg0type))) { + return Type.Bool; + } goto BAD_TYPE; case Opcode.And: case Opcode.Or: @@ -1799,9 +1804,6 @@ namespace Microsoft.Boogie { case Opcode.Pow: return Type.Real; - //case Opcode.FloatDiv: - //return Type.Float; - case Opcode.Eq: case Opcode.Neq: case Opcode.Gt: diff --git a/Source/Provers/SMTLib/SMTLibLineariser.cs b/Source/Provers/SMTLib/SMTLibLineariser.cs index 3633a9c0..f030870e 100644 --- a/Source/Provers/SMTLib/SMTLibLineariser.cs +++ b/Source/Provers/SMTLib/SMTLibLineariser.cs @@ -689,12 +689,6 @@ namespace Microsoft.Boogie.SMTLib return true; } - public bool VisitFloatDivOp(VCExprNAry node, LineariserOptions options) - { //TODO: match z3 - WriteApplication("/f", node, options); - return true; - } - public bool VisitPowOp(VCExprNAry node, LineariserOptions options) { WriteApplication("real_pow", node, options); return true; @@ -746,12 +740,6 @@ namespace Microsoft.Boogie.SMTLib return true; } - public bool VisitToFloatOp(VCExprNAry node, LineariserOptions options) - { - WriteApplication("to_float", node, options); - return true; - } - private string ExtractDatatype(Function func) { if (func is DatatypeSelector) { DatatypeSelector selector = (DatatypeSelector) func; diff --git a/Source/VCExpr/VCExprASTPrinter.cs b/Source/VCExpr/VCExprASTPrinter.cs index 8b79b0e5..00e6fb9c 100644 --- a/Source/VCExpr/VCExprASTPrinter.cs +++ b/Source/VCExpr/VCExprASTPrinter.cs @@ -302,12 +302,6 @@ namespace Microsoft.Boogie.VCExprAST { //Contract.Requires(node != null); return PrintNAry("/", node, wr); } - public bool VisitFloatDivOp(VCExprNAry node, TextWriter wr) - { - //Contract.Requires(wr != null); - //Contract.Requires(node != null); - return PrintNAry("/f", node, wr); - } public bool VisitPowOp(VCExprNAry node, TextWriter wr) { //Contract.Requires(wr != null); //Contract.Requires(node != null); @@ -353,12 +347,6 @@ namespace Microsoft.Boogie.VCExprAST { //Contract.Requires(node != null); return PrintNAry("real", node, wr); } - public bool VisitToFloatOp(VCExprNAry node, TextWriter wr) - { - //Contract.Requires(wr != null); - //Contract.Requires(node != null); - return PrintNAry("float", node, wr); - } public bool VisitBoogieFunctionOp(VCExprNAry node, TextWriter wr) { //Contract.Requires(wr != null); //Contract.Requires(node != null); diff --git a/float_test5.bpl b/float_test5.bpl index c3d279f2..be72b988 100644 --- a/float_test5.bpl +++ b/float_test5.bpl @@ -1,5 +1,4 @@ - procedure F() returns () { +procedure F() returns () { var x : float; - var y : float; - assert x + y == fp(0); + assert x - x == fp(0); } \ No newline at end of file diff --git a/float_test6.bpl b/float_test6.bpl index 307da9f7..423bc45a 100644 --- a/float_test6.bpl +++ b/float_test6.bpl @@ -1,5 +1,5 @@ procedure F() returns () { var x : float; - x := fp(1) + fp(1); - assert x == fp(2); + var y : float; + assert (x + x) + (y + y) == fp(0); } \ No newline at end of file -- cgit v1.2.3 From 0324757fb1a12d76861a51be988690bf8de75f64 Mon Sep 17 00:00:00 2001 From: Checkmate50 Date: Wed, 14 Oct 2015 12:57:50 -0600 Subject: Modified translation so that z3 runs with type checking for simple binary operations --- Source/Basetypes/BigFloat.cs | 48 +++------- Source/Core/AbsyExpr.cs | 1 - Source/Provers/SMTLib/SMTLibLineariser.cs | 76 ++++++++++++++- Source/Provers/SMTLib/Z3.cs | 4 +- Source/VCExpr/Boogie2VCExpr.cs | 36 +++++-- Source/VCExpr/SimplifyLikeLineariser.cs | 120 ++++++++++++++++++++--- Source/VCExpr/TypeErasure.cs | 84 ++++++++++++++++ Source/VCExpr/VCExprAST.cs | 56 ++++++++--- Source/VCExpr/VCExprASTPrinter.cs | 72 ++++++++++++++ Source/VCExpr/VCExprASTVisitors.cs | 154 +++++++++++++++++++++++++++--- float_test5.bpl | 2 +- float_test8.bpl | 5 +- 12 files changed, 570 insertions(+), 88 deletions(-) diff --git a/Source/Basetypes/BigFloat.cs b/Source/Basetypes/BigFloat.cs index e9d5e670..9e798959 100644 --- a/Source/Basetypes/BigFloat.cs +++ b/Source/Basetypes/BigFloat.cs @@ -33,7 +33,7 @@ namespace Microsoft.Basetypes [Rep] internal readonly int exponentSize; //The bit size of the exponent [Rep] - internal readonly BigDec dec_value; + internal readonly String dec_value; [Rep] internal readonly bool isDec; @@ -61,7 +61,7 @@ namespace Microsoft.Basetypes } } - public BigDec Decimal { + public String Decimal { get { return dec_value; } @@ -102,7 +102,7 @@ namespace Microsoft.Basetypes public static BigFloat FromBigDec(BigDec v) { - return new BigFloat(v, 8, 24); + return new BigFloat(v.ToDecimalString(), 8, 24); } [Pure] @@ -114,11 +114,11 @@ namespace Microsoft.Basetypes { switch (vals.Length) { case 1: - return new BigFloat(BigDec.FromString(vals[0]), 8, 24); + return new BigFloat(vals[0], 8, 24); case 2: return new BigFloat(Int32.Parse(vals[0]), BIM.Parse(vals[1]), 8, 24); case 3: - return new BigFloat(BigDec.FromString(vals[0]), Int32.Parse(vals[1]), Int32.Parse(vals[2])); + return new BigFloat(vals[0], Int32.Parse(vals[1]), Int32.Parse(vals[2])); case 4: return new BigFloat(Int32.Parse(vals[0]), BIM.Parse(vals[1]), Int32.Parse(vals[2]), Int32.Parse(vals[3])); default: @@ -136,10 +136,10 @@ namespace Microsoft.Basetypes this.mantissa = mantissa; this.mantissaSize = mantissaSize; this.isDec = false; - this.dec_value = BigDec.ZERO; + this.dec_value = ""; } - internal BigFloat(BigDec dec_value, int exponentSize, int mantissaSize) { + internal BigFloat(String dec_value, int exponentSize, int mantissaSize) { this.exponentSize = exponentSize; this.mantissaSize = mantissaSize; this.exponent = 0; @@ -181,7 +181,7 @@ namespace Microsoft.Basetypes [Pure] public override string/*!*/ ToString() { Contract.Ensures(Contract.Result() != null); - return String.Format("{0}x2^{1}", Mantissa.ToString(), Exponent.ToString()); + return isDec ? dec_value : String.Format("{0}x2^{1}", Mantissa.ToString(), Exponent.ToString()); } @@ -313,34 +313,8 @@ namespace Microsoft.Basetypes [Pure] public string ToDecimalString() { - //TODO: fix for fp functionality - string m = Mantissa.ToString(); - var e = Exponent; - if (0 <= Exponent) { - return m + Zeros(e) + ".0"; - } else { - e = -e; - // compute k to be the longest suffix of m consisting of all zeros (but no longer than e, and not the entire string) - var maxK = e < m.Length ? e : m.Length - 1; - var last = m.Length - 1; - var k = 0; - while (k < maxK && m[last - k] == '0') { - k++; - } - if (0 < k) { - // chop off the suffix of k zeros from m and adjust e accordingly - m = m.Substring(0, m.Length - k); - e -= k; - } - if (e == 0) { - return m; - } else if (e < m.Length) { - var n = m.Length - e; - return m.Substring(0, n) + "." + m.Substring(n); - } else { - return "0." + Zeros(e - m.Length) + m; - } - } + Contract.Ensures(Contract.Result() != null); + return isDec ? dec_value : String.Format("{0}x2^{1}", Mantissa.ToString(), Exponent.ToString()); } [Pure] @@ -436,7 +410,7 @@ namespace Microsoft.Basetypes public bool IsNegative { get { - return (isDec && dec_value >= BigDec.ZERO) || mantissa >= 0; + return (isDec && dec_value[0] == '-') || mantissa < 0; } } diff --git a/Source/Core/AbsyExpr.cs b/Source/Core/AbsyExpr.cs index cf6fb922..ad537288 100644 --- a/Source/Core/AbsyExpr.cs +++ b/Source/Core/AbsyExpr.cs @@ -1642,7 +1642,6 @@ namespace Microsoft.Boogie { case Opcode.Div: case Opcode.Mod: case Opcode.RealDiv: - case Opcode.FloatDiv: case Opcode.Pow: case Opcode.Neq: // Neq is allowed, but not Eq case Opcode.Subtype: diff --git a/Source/Provers/SMTLib/SMTLibLineariser.cs b/Source/Provers/SMTLib/SMTLibLineariser.cs index f030870e..629f7e2d 100644 --- a/Source/Provers/SMTLib/SMTLibLineariser.cs +++ b/Source/Provers/SMTLib/SMTLibLineariser.cs @@ -141,7 +141,7 @@ namespace Microsoft.Boogie.SMTLib else if (t.IsReal) return "Real"; else if (t.IsFloat) - return "(_ FloatingPoint " + t.FloatExponent + " " + t.FloatMantissa + ")"; //TODO: Match z3 syntax + return "(_ FloatingPoint " + t.FloatExponent + " " + t.FloatMantissa + ")"; else if (t.IsBv) { return "(_ BitVec " + t.BvBits + ")"; } else { @@ -204,11 +204,13 @@ namespace Microsoft.Boogie.SMTLib else if (node is VCExprFloatLit) { BigFloat lit = ((VCExprFloatLit)node).Val; + wr.Write(("((_ to_fp 8 24) roundTowardZero ")); if (lit.IsNegative) // In SMT2 "-42" is an identifier (SMT2, Sect. 3.2 "Symbols") wr.Write("(- 0.0 {0})", lit.Abs.ToDecimalString()); else wr.Write(lit.ToDecimalString()); + wr.Write(")"); } else { Contract.Assert(false); @@ -616,6 +618,78 @@ namespace Microsoft.Boogie.SMTLib return true; } + public bool VisitFloatAddOp(VCExprNAry node, LineariserOptions options) + { + WriteApplication("fp.add roundTowardZero", node, options); + return true; + } + + public bool VisitFloatSubOp(VCExprNAry node, LineariserOptions options) + { + WriteApplication("fp.sub roundTowardZero", node, options); + return true; + } + + public bool VisitFloatMulOp(VCExprNAry node, LineariserOptions options) + { + WriteApplication("fp.mul roundTowardZero", node, options); + return true; + } + + public bool VisitFloatDivOp(VCExprNAry node, LineariserOptions options) + { + WriteApplication("fp.div roundTowardZero", node, options); + return true; + } + + public bool VisitFloatRemOp(VCExprNAry node, LineariserOptions options) + { + WriteApplication("fp.rem roundTowardZero", node, options); + return true; + } + + public bool VisitFloatMinOp(VCExprNAry node, LineariserOptions options) + { + WriteApplication("fp.min", node, options); + return true; + } + + public bool VisitFloatMaxOp(VCExprNAry node, LineariserOptions options) + { + WriteApplication("fp.max", node, options); + return true; + } + + public bool VisitFloatLeqOp(VCExprNAry node, LineariserOptions options) + { + WriteApplication("fp.leq", node, options); + return true; + } + + public bool VisitFloatLtOp(VCExprNAry node, LineariserOptions options) + { + WriteApplication("fp.lt", node, options); + return true; + } + + public bool VisitFloatGeqOp(VCExprNAry node, LineariserOptions options) + { + WriteApplication("fp.geq", node, options); + return true; + } + + public bool VisitFloatGtOp(VCExprNAry node, LineariserOptions options) + { + WriteApplication("fp.gt", node, options); + return true; + } + + public bool VisitFloatEqOp(VCExprNAry node, LineariserOptions options) + { + WriteApplication("fp.eq", node, options); + return true; + } + static char[] hex = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; public bool VisitBvOp(VCExprNAry node, LineariserOptions options) { diff --git a/Source/Provers/SMTLib/Z3.cs b/Source/Provers/SMTLib/Z3.cs index 8e8b2d55..250e04c9 100644 --- a/Source/Provers/SMTLib/Z3.cs +++ b/Source/Provers/SMTLib/Z3.cs @@ -253,7 +253,7 @@ namespace Microsoft.Boogie.SMTLib //if (options.Inspector != null) // options.WeakAddSmtOption("PROGRESS_SAMPLING_FREQ", "100"); - options.AddWeakSmtOption("TYPE_CHECK", "false"); + options.AddWeakSmtOption("TYPE_CHECK", "true"); options.AddWeakSmtOption("smt.BV.REFLECT", "true"); if (options.TimeLimit > 0) @@ -334,7 +334,7 @@ namespace Microsoft.Boogie.SMTLib //if (options.Inspector != null) // options.WeakAddSmtOption("PROGRESS_SAMPLING_FREQ", "100"); - options.AddWeakSmtOption("TYPE_CHECK", "false"); + options.AddWeakSmtOption("TYPE_CHECK", "true"); options.AddWeakSmtOption("BV_REFLECT", "true"); if (options.TimeLimit > 0) diff --git a/Source/VCExpr/Boogie2VCExpr.cs b/Source/VCExpr/Boogie2VCExpr.cs index f0dc505d..ad319c0e 100644 --- a/Source/VCExpr/Boogie2VCExpr.cs +++ b/Source/VCExpr/Boogie2VCExpr.cs @@ -1076,34 +1076,48 @@ namespace Microsoft.Boogie.VCExprAST { Contract.Requires(cce.NonNullElements(args)); Contract.Ensures(Contract.Result() != null); Contract.Assert(args.Count == 2); + Type t = cce.NonNull(cce.NonNull(args[0]).Type); switch (app.Op) { case BinaryOperator.Opcode.Add: - if (cce.NonNull(cce.NonNull(args[0]).Type).IsInt) { + if (t.IsInt) { return Gen.Function(VCExpressionGenerator.AddIOp, args); } - else { + else if (t.IsReal) { return Gen.Function(VCExpressionGenerator.AddROp, args); } + else { //t is float + return Gen.Function(Gen.BinaryFloatOp(t.FloatExponent, t.FloatMantissa, "+"), args); + } case BinaryOperator.Opcode.Sub: - if (cce.NonNull(cce.NonNull(args[0]).Type).IsInt) { + if (t.IsInt) { return Gen.Function(VCExpressionGenerator.SubIOp, args); } - else { + else if (t.IsReal) { return Gen.Function(VCExpressionGenerator.SubROp, args); } + else { //t is float + return Gen.Function(Gen.BinaryFloatOp(t.FloatExponent, t.FloatMantissa, "-"), args); + } case BinaryOperator.Opcode.Mul: - if (cce.NonNull(cce.NonNull(args[0]).Type).IsInt) { + if (t.IsInt) { return Gen.Function(VCExpressionGenerator.MulIOp, args); } - else { + else if (t.IsReal) { return Gen.Function(VCExpressionGenerator.MulROp, args); } + else + { //t is float + return Gen.Function(Gen.BinaryFloatOp(t.FloatExponent, t.FloatMantissa, "*"), args); + } case BinaryOperator.Opcode.Div: return Gen.Function(VCExpressionGenerator.DivIOp, args); case BinaryOperator.Opcode.Mod: return Gen.Function(VCExpressionGenerator.ModOp, args); case BinaryOperator.Opcode.RealDiv: + if (t.IsFloat) { + return Gen.Function(Gen.BinaryFloatOp(t.FloatExponent, t.FloatMantissa, "/"), args); + } VCExpr arg0 = cce.NonNull(args[0]); VCExpr arg1 = cce.NonNull(args[1]); if (cce.NonNull(arg0.Type).IsInt) { @@ -1118,16 +1132,26 @@ namespace Microsoft.Boogie.VCExprAST { case BinaryOperator.Opcode.Eq: case BinaryOperator.Opcode.Iff: // we don't distinguish between equality and equivalence at this point + if (t.IsFloat) + return Gen.Function(Gen.BinaryFloatOp(t.FloatExponent, t.FloatMantissa, "=="), args); return Gen.Function(VCExpressionGenerator.EqOp, args); case BinaryOperator.Opcode.Neq: return Gen.Function(VCExpressionGenerator.NeqOp, args); case BinaryOperator.Opcode.Lt: + if (t.IsFloat) + return Gen.Function(Gen.BinaryFloatOp(t.FloatExponent, t.FloatMantissa, "<"), args); return Gen.Function(VCExpressionGenerator.LtOp, args); case BinaryOperator.Opcode.Le: + if (t.IsFloat) + return Gen.Function(Gen.BinaryFloatOp(t.FloatExponent, t.FloatMantissa, "<="), args); return Gen.Function(VCExpressionGenerator.LeOp, args); case BinaryOperator.Opcode.Ge: + if (t.IsFloat) + return Gen.Function(Gen.BinaryFloatOp(t.FloatExponent, t.FloatMantissa, ">="), args); return Gen.Function(VCExpressionGenerator.GeOp, args); case BinaryOperator.Opcode.Gt: + if (t.IsFloat) + return Gen.Function(Gen.BinaryFloatOp(t.FloatExponent, t.FloatMantissa, ">"), args); return Gen.Function(VCExpressionGenerator.GtOp, args); case BinaryOperator.Opcode.Imp: return Gen.Function(VCExpressionGenerator.ImpliesOp, args); diff --git a/Source/VCExpr/SimplifyLikeLineariser.cs b/Source/VCExpr/SimplifyLikeLineariser.cs index 0ff6d67f..6f74fe08 100644 --- a/Source/VCExpr/SimplifyLikeLineariser.cs +++ b/Source/VCExpr/SimplifyLikeLineariser.cs @@ -384,6 +384,14 @@ namespace Microsoft.Boogie.VCExprAST { internal const string floatSubName = "floatSub"; internal const string floatMulName = "floatMul"; internal const string floatDivName = "floatDiv"; + internal const string floatRemName = "floatRem"; + internal const string floatMinName = "floatMin"; + internal const string floatMaxName = "floatMax"; + internal const string floatLeqName = "floatLeq"; + internal const string floatLtName = "floatLt"; + internal const string floatGeqName = "floatGeq"; + internal const string floatGtName = "floatGt"; + internal const string floatEqName = "floatEq"; internal const string realPowName = "realPow"; internal const string toIntName = "toIntCoercion"; internal const string toRealName = "toRealCoercion"; @@ -888,7 +896,104 @@ namespace Microsoft.Boogie.VCExprAST { return true; } - public bool VisitBvOp(VCExprNAry node, LineariserOptions options) { + public bool VisitFloatAddOp(VCExprNAry node, LineariserOptions options) + { + //Contract.Requires(options != null); + //Contract.Requires(node != null); + WriteTermApplication(floatAddName, node, options); + return true; + } + + public bool VisitFloatSubOp(VCExprNAry node, LineariserOptions options) + { + //Contract.Requires(options != null); + //Contract.Requires(node != null); + WriteTermApplication(floatSubName, node, options); + return true; + } + + public bool VisitFloatMulOp(VCExprNAry node, LineariserOptions options) + { + //Contract.Requires(options != null); + //Contract.Requires(node != null); + WriteTermApplication(floatMulName, node, options); + return true; + } + + public bool VisitFloatDivOp(VCExprNAry node, LineariserOptions options) + { + //Contract.Requires(options != null); + //Contract.Requires(node != null); + WriteTermApplication(floatDivName, node, options); + return true; + } + + public bool VisitFloatRemOp(VCExprNAry node, LineariserOptions options) + { + //Contract.Requires(options != null); + //Contract.Requires(node != null); + WriteTermApplication(floatRemName, node, options); + return true; + } + + public bool VisitFloatMinOp(VCExprNAry node, LineariserOptions options) + { + //Contract.Requires(options != null); + //Contract.Requires(node != null); + WriteTermApplication(floatMinName, node, options); + return true; + } + + public bool VisitFloatMaxOp(VCExprNAry node, LineariserOptions options) + { + //Contract.Requires(options != null); + //Contract.Requires(node != null); + WriteTermApplication(floatMaxName, node, options); + return true; + } + + public bool VisitFloatLeqOp(VCExprNAry node, LineariserOptions options) + { + //Contract.Requires(options != null); + //Contract.Requires(node != null); + WriteTermApplication(floatLeqName, node, options); + return true; + } + + public bool VisitFloatLtOp(VCExprNAry node, LineariserOptions options) + { + //Contract.Requires(options != null); + //Contract.Requires(node != null); + WriteTermApplication(floatLtName, node, options); + return true; + } + + public bool VisitFloatGeqOp(VCExprNAry node, LineariserOptions options) + { + //Contract.Requires(options != null); + //Contract.Requires(node != null); + WriteTermApplication(floatGeqName, node, options); + return true; + } + + public bool VisitFloatGtOp(VCExprNAry node, LineariserOptions options) + { + //Contract.Requires(options != null); + //Contract.Requires(node != null); + WriteTermApplication(floatGtName, node, options); + return true; + } + + public bool VisitFloatEqOp(VCExprNAry node, LineariserOptions options) + { + //Contract.Requires(options != null); + //Contract.Requires(node != null); + WriteTermApplication(floatEqName, node, options); + return true; + } + + public bool VisitBvOp(VCExprNAry node, LineariserOptions options) + { //Contract.Requires(options != null); //Contract.Requires(node != null); WriteTermApplication("$make_bv" + node.Type.BvBits, node, options); @@ -948,11 +1053,8 @@ namespace Microsoft.Boogie.VCExprAST { WriteTermApplication(intAddName, node, options); } } - else if (node.Type.IsReal) { - WriteTermApplication(realAddName, node, options); - } else { - WriteTermApplication(floatAddName, node, options); + WriteTermApplication(realAddName, node, options); } return true; } @@ -1008,14 +1110,6 @@ namespace Microsoft.Boogie.VCExprAST { return true; } - public bool VisitFloatDivOp(VCExprNAry node, LineariserOptions options) - { - //Contract.Requires(options != null); - //Contract.Requires(node != null); - WriteTermApplication(floatDivName, node, options); - return true; - } - public bool VisitPowOp(VCExprNAry node, LineariserOptions options) { //Contract.Requires(options != null); //Contract.Requires(node != null); diff --git a/Source/VCExpr/TypeErasure.cs b/Source/VCExpr/TypeErasure.cs index 5e821ea2..6fb38c27 100644 --- a/Source/VCExpr/TypeErasure.cs +++ b/Source/VCExpr/TypeErasure.cs @@ -1479,6 +1479,90 @@ namespace Microsoft.Boogie.TypeErasure { Contract.Ensures(Contract.Result() != null); return CastArgumentsToOldType(node, bindings, 0); } + public override VCExpr VisitFloatAddOp(VCExprNAry node, VariableBindings bindings) + { + Contract.Requires((bindings != null)); + Contract.Requires((node != null)); + Contract.Ensures(Contract.Result() != null); + return CastArgumentsToOldType(node, bindings, 0); + } + public override VCExpr VisitFloatSubOp(VCExprNAry node, VariableBindings bindings) + { + Contract.Requires((bindings != null)); + Contract.Requires((node != null)); + Contract.Ensures(Contract.Result() != null); + return CastArgumentsToOldType(node, bindings, 0); + } + public override VCExpr VisitFloatMulOp(VCExprNAry node, VariableBindings bindings) + { + Contract.Requires((bindings != null)); + Contract.Requires((node != null)); + Contract.Ensures(Contract.Result() != null); + return CastArgumentsToOldType(node, bindings, 0); + } + public override VCExpr VisitFloatDivOp(VCExprNAry node, VariableBindings bindings) + { + Contract.Requires((bindings != null)); + Contract.Requires((node != null)); + Contract.Ensures(Contract.Result() != null); + return CastArgumentsToOldType(node, bindings, 0); + } + public override VCExpr VisitFloatRemOp(VCExprNAry node, VariableBindings bindings) + { + Contract.Requires((bindings != null)); + Contract.Requires((node != null)); + Contract.Ensures(Contract.Result() != null); + return CastArgumentsToOldType(node, bindings, 0); + } + public override VCExpr VisitFloatMinOp(VCExprNAry node, VariableBindings bindings) + { + Contract.Requires((bindings != null)); + Contract.Requires((node != null)); + Contract.Ensures(Contract.Result() != null); + return CastArgumentsToOldType(node, bindings, 0); + } + public override VCExpr VisitFloatMaxOp(VCExprNAry node, VariableBindings bindings) + { + Contract.Requires((bindings != null)); + Contract.Requires((node != null)); + Contract.Ensures(Contract.Result() != null); + return CastArgumentsToOldType(node, bindings, 0); + } + public override VCExpr VisitFloatLeqOp(VCExprNAry node, VariableBindings bindings) + { + Contract.Requires((bindings != null)); + Contract.Requires((node != null)); + Contract.Ensures(Contract.Result() != null); + return CastArgumentsToOldType(node, bindings, 0); + } + public override VCExpr VisitFloatLtOp(VCExprNAry node, VariableBindings bindings) + { + Contract.Requires((bindings != null)); + Contract.Requires((node != null)); + Contract.Ensures(Contract.Result() != null); + return CastArgumentsToOldType(node, bindings, 0); + } + public override VCExpr VisitFloatGeqOp(VCExprNAry node, VariableBindings bindings) + { + Contract.Requires((bindings != null)); + Contract.Requires((node != null)); + Contract.Ensures(Contract.Result() != null); + return CastArgumentsToOldType(node, bindings, 0); + } + public override VCExpr VisitFloatGtOp(VCExprNAry node, VariableBindings bindings) + { + Contract.Requires((bindings != null)); + Contract.Requires((node != null)); + Contract.Ensures(Contract.Result() != null); + return CastArgumentsToOldType(node, bindings, 0); + } + public override VCExpr VisitFloatEqOp(VCExprNAry node, VariableBindings bindings) + { + Contract.Requires((bindings != null)); + Contract.Requires((node != null)); + Contract.Ensures(Contract.Result() != null); + return CastArgumentsToOldType(node, bindings, 0); + } public override VCExpr VisitBvOp(VCExprNAry node, VariableBindings bindings) { Contract.Requires((bindings != null)); Contract.Requires((node != null)); diff --git a/Source/VCExpr/VCExprAST.cs b/Source/VCExpr/VCExprAST.cs index c44800fc..3f6e3b7a 100644 --- a/Source/VCExpr/VCExprAST.cs +++ b/Source/VCExpr/VCExprAST.cs @@ -324,7 +324,6 @@ namespace Microsoft.Boogie { public static readonly VCExprOp AddIOp = new VCExprNAryOp(2, Type.Int); public static readonly VCExprOp AddROp = new VCExprNAryOp(2, Type.Real); - //public static readonly VCExprOp AddFOp = new VCExprNAryOp(2, Type.Float); public static readonly VCExprOp SubIOp = new VCExprNAryOp(2, Type.Int); public static readonly VCExprOp SubROp = new VCExprNAryOp(2, Type.Real); // public static readonly VCExprOp SubFOp = new VCExprNAryOp(2, Type.Float); @@ -359,11 +358,13 @@ namespace Microsoft.Boogie { // Float nodes - public VCExpr AddFOp(VCExpr f1, VCExpr f2) + public VCExprOp BinaryFloatOp(int exp, int man, string op) { - Contract.Requires(f1 != null); - Contract.Requires(f2 != null); - return Function(new VCExprFloatOp(f1.Type.FloatExponent, f1.Type.FloatMantissa)); + Contract.Requires(exp > 0); + Contract.Requires(man > 0); + Contract.Requires(op != null); + Contract.Ensures(Contract.Result() != null); + return new VCExprBinaryFloatOp(exp, man, op); } // Bitvector nodes @@ -441,7 +442,6 @@ namespace Microsoft.Boogie { SingletonOpDict.Add(ImpliesOp, SingletonOp.ImpliesOp); SingletonOpDict.Add(AddIOp, SingletonOp.AddOp); SingletonOpDict.Add(AddROp, SingletonOp.AddOp); - //SingletonOpDict.Add(AddFOp, SingletonOp.AddOp); SingletonOpDict.Add(SubIOp, SingletonOp.SubOp); SingletonOpDict.Add(SubROp, SingletonOp.SubOp); //SingletonOpDict.Add(SubFOp, SingletonOp.SubOp); @@ -1677,18 +1677,19 @@ namespace Microsoft.Boogie.VCExprAST { ///////////////////////////////////////////////////////////////////////////////// // Float operators - public class VCExprFloatOp : VCExprOp { + public class VCExprBinaryFloatOp : VCExprOp { public readonly int Mantissa; public readonly int Exponent; + private string op; public override int Arity { get { - return 1; + return 2; } } public override int TypeParamArity { get { - return 0; + return 2; } } public override Type InferType(List args, List/*!*/ typeArgs) { @@ -1703,8 +1704,8 @@ namespace Microsoft.Boogie.VCExprAST { public override bool Equals(object that) { if (Object.ReferenceEquals(this, that)) return true; - if (that is VCExprFloatOp) - return this.Exponent == ((VCExprFloatOp)that).Exponent && this.Mantissa == ((VCExprFloatOp)that).Mantissa; + if (that is VCExprBinaryFloatOp) + return this.Exponent == ((VCExprBinaryFloatOp)that).Exponent && this.Mantissa == ((VCExprBinaryFloatOp)that).Mantissa; return false; } [Pure] @@ -1712,15 +1713,44 @@ namespace Microsoft.Boogie.VCExprAST { return Exponent * 81748912 + Mantissa * 67867979; } - internal VCExprFloatOp(int exp, int man) { + internal VCExprBinaryFloatOp(int exp, int man, string op) { this.Exponent = exp; this.Mantissa = man; + this.op = op; } public override Result Accept (VCExprNAry expr, IVCExprOpVisitor visitor, Arg arg) { //Contract.Requires(visitor != null); //Contract.Requires(expr != null); - return visitor.VisitBvOp(expr, arg); + switch (op) { + case ("+"): + return visitor.VisitFloatAddOp(expr, arg); + case ("-"): + return visitor.VisitFloatSubOp(expr, arg); + case ("*"): + return visitor.VisitFloatMulOp(expr, arg); + case ("/"): + return visitor.VisitFloatDivOp(expr, arg); + case ("rem"): + return visitor.VisitFloatRemOp(expr, arg); + case ("min"): + return visitor.VisitFloatMinOp(expr, arg); + case ("max"): + return visitor.VisitFloatMaxOp(expr, arg); + case ("<="): + return visitor.VisitFloatLeqOp(expr, arg); + case ("<"): + return visitor.VisitFloatLtOp(expr, arg); + case (">="): + return visitor.VisitFloatGeqOp(expr, arg); + case (">"): + return visitor.VisitFloatGtOp(expr, arg); + case ("=="): + return visitor.VisitFloatEqOp(expr, arg); + default: + Contract.Assert(false); + throw new cce.UnreachableException(); + } } } diff --git a/Source/VCExpr/VCExprASTPrinter.cs b/Source/VCExpr/VCExprASTPrinter.cs index 00e6fb9c..8e2f5d12 100644 --- a/Source/VCExpr/VCExprASTPrinter.cs +++ b/Source/VCExpr/VCExprASTPrinter.cs @@ -242,6 +242,78 @@ namespace Microsoft.Boogie.VCExprAST { //Contract.Requires(node != null); return PrintNAry("Store", node, wr); } + public bool VisitFloatAddOp(VCExprNAry node, TextWriter wr) + { + //Contract.Requires(wr != null); + //Contract.Requires(node != null); + return PrintNAry("fp.add", node, wr); + } + public bool VisitFloatSubOp(VCExprNAry node, TextWriter wr) + { + //Contract.Requires(wr != null); + //Contract.Requires(node != null); + return PrintNAry("fp.sub", node, wr); + } + public bool VisitFloatMulOp(VCExprNAry node, TextWriter wr) + { + //Contract.Requires(wr != null); + //Contract.Requires(node != null); + return PrintNAry("fp.mul", node, wr); + } + public bool VisitFloatDivOp(VCExprNAry node, TextWriter wr) + { + //Contract.Requires(wr != null); + //Contract.Requires(node != null); + return PrintNAry("fp.div", node, wr); + } + public bool VisitFloatRemOp(VCExprNAry node, TextWriter wr) + { + //Contract.Requires(wr != null); + //Contract.Requires(node != null); + return PrintNAry("fp.rem", node, wr); + } + public bool VisitFloatMinOp(VCExprNAry node, TextWriter wr) + { + //Contract.Requires(wr != null); + //Contract.Requires(node != null); + return PrintNAry("fp.min", node, wr); + } + public bool VisitFloatMaxOp(VCExprNAry node, TextWriter wr) + { + //Contract.Requires(wr != null); + //Contract.Requires(node != null); + return PrintNAry("fp.max", node, wr); + } + public bool VisitFloatLeqOp(VCExprNAry node, TextWriter wr) + { + //Contract.Requires(wr != null); + //Contract.Requires(node != null); + return PrintNAry("fp.leq", node, wr); + } + public bool VisitFloatLtOp(VCExprNAry node, TextWriter wr) + { + //Contract.Requires(wr != null); + //Contract.Requires(node != null); + return PrintNAry("fp.lt", node, wr); + } + public bool VisitFloatGeqOp(VCExprNAry node, TextWriter wr) + { + //Contract.Requires(wr != null); + //Contract.Requires(node != null); + return PrintNAry("fp.geq", node, wr); + } + public bool VisitFloatGtOp(VCExprNAry node, TextWriter wr) + { + //Contract.Requires(wr != null); + //Contract.Requires(node != null); + return PrintNAry("fp.gt", node, wr); + } + public bool VisitFloatEqOp(VCExprNAry node, TextWriter wr) + { + //Contract.Requires(wr != null); + //Contract.Requires(node != null); + return PrintNAry("fp.eq", node, wr); + } public bool VisitBvOp(VCExprNAry node, TextWriter wr) { //Contract.Requires(wr != null); //Contract.Requires(node != null); diff --git a/Source/VCExpr/VCExprASTVisitors.cs b/Source/VCExpr/VCExprASTVisitors.cs index a1fb2ff4..c81f69e5 100644 --- a/Source/VCExpr/VCExprASTVisitors.cs +++ b/Source/VCExpr/VCExprASTVisitors.cs @@ -68,6 +68,18 @@ namespace Microsoft.Boogie.VCExprAST { Result VisitLabelOp(VCExprNAry node, Arg arg); Result VisitSelectOp(VCExprNAry node, Arg arg); Result VisitStoreOp(VCExprNAry node, Arg arg); + Result VisitFloatAddOp(VCExprNAry node, Arg arg); + Result VisitFloatSubOp(VCExprNAry node, Arg arg); + Result VisitFloatMulOp(VCExprNAry node, Arg arg); + Result VisitFloatDivOp(VCExprNAry node, Arg arg); + Result VisitFloatRemOp(VCExprNAry node, Arg arg); + Result VisitFloatMinOp(VCExprNAry node, Arg arg); + Result VisitFloatMaxOp(VCExprNAry node, Arg arg); + Result VisitFloatLeqOp(VCExprNAry node, Arg arg); + Result VisitFloatLtOp(VCExprNAry node, Arg arg); + Result VisitFloatGeqOp(VCExprNAry node, Arg arg); + Result VisitFloatGtOp(VCExprNAry node, Arg arg); + Result VisitFloatEqOp(VCExprNAry node, Arg arg); Result VisitBvOp(VCExprNAry node, Arg arg); Result VisitBvExtractOp(VCExprNAry node, Arg arg); Result VisitBvConcatOp(VCExprNAry node, Arg arg); @@ -144,6 +156,78 @@ namespace Microsoft.Boogie.VCExprAST { throw new NotImplementedException(); } + public Result VisitFloatAddOp(VCExprNAry node, Arg arg) + { + Contract.Requires(node != null); + throw new NotImplementedException(); + } + + public Result VisitFloatSubOp(VCExprNAry node, Arg arg) + { + Contract.Requires(node != null); + throw new NotImplementedException(); + } + + public Result VisitFloatMulOp(VCExprNAry node, Arg arg) + { + Contract.Requires(node != null); + throw new NotImplementedException(); + } + + public Result VisitFloatDivOp(VCExprNAry node, Arg arg) + { + Contract.Requires(node != null); + throw new NotImplementedException(); + } + + public Result VisitFloatRemOp(VCExprNAry node, Arg arg) + { + Contract.Requires(node != null); + throw new NotImplementedException(); + } + + public Result VisitFloatMinOp(VCExprNAry node, Arg arg) + { + Contract.Requires(node != null); + throw new NotImplementedException(); + } + + public Result VisitFloatMaxOp(VCExprNAry node, Arg arg) + { + Contract.Requires(node != null); + throw new NotImplementedException(); + } + + public Result VisitFloatLeqOp(VCExprNAry node, Arg arg) + { + Contract.Requires(node != null); + throw new NotImplementedException(); + } + + public Result VisitFloatLtOp(VCExprNAry node, Arg arg) + { + Contract.Requires(node != null); + throw new NotImplementedException(); + } + + public Result VisitFloatGeqOp(VCExprNAry node, Arg arg) + { + Contract.Requires(node != null); + throw new NotImplementedException(); + } + + public Result VisitFloatGtOp(VCExprNAry node, Arg arg) + { + Contract.Requires(node != null); + throw new NotImplementedException(); + } + + public Result VisitFloatEqOp(VCExprNAry node, Arg arg) + { + Contract.Requires(node != null); + throw new NotImplementedException(); + } + public Result VisitBvOp(VCExprNAry node, Arg arg) { Contract.Requires(node != null); throw new NotImplementedException(); @@ -189,12 +273,6 @@ namespace Microsoft.Boogie.VCExprAST { throw new NotImplementedException(); } - public Result VisitFloatDivOp(VCExprNAry node, Arg arg) - { - Contract.Requires(node != null); - throw new NotImplementedException(); - } - public Result VisitPowOp(VCExprNAry node, Arg arg) { Contract.Requires(node != null); throw new NotImplementedException(); @@ -1450,6 +1528,65 @@ namespace Microsoft.Boogie.VCExprAST { //Contract.Requires(node != null); return StandardResult(node, arg); } + public virtual Result VisitFloatAddOp(VCExprNAry node, Arg arg) { + //Contract.Requires(node != null); + return StandardResult(node, arg); + } + public virtual Result VisitFloatSubOp(VCExprNAry node, Arg arg) + { + //Contract.Requires(node != null); + return StandardResult(node, arg); + } + public virtual Result VisitFloatMulOp(VCExprNAry node, Arg arg) + { + //Contract.Requires(node != null); + return StandardResult(node, arg); + } + public virtual Result VisitFloatDivOp(VCExprNAry node, Arg arg) + { + //Contract.Requires(node != null); + return StandardResult(node, arg); + } + public virtual Result VisitFloatRemOp(VCExprNAry node, Arg arg) + { + //Contract.Requires(node != null); + return StandardResult(node, arg); + } + public virtual Result VisitFloatMinOp(VCExprNAry node, Arg arg) + { + //Contract.Requires(node != null); + return StandardResult(node, arg); + } + public virtual Result VisitFloatMaxOp(VCExprNAry node, Arg arg) + { + //Contract.Requires(node != null); + return StandardResult(node, arg); + } + public virtual Result VisitFloatLeqOp(VCExprNAry node, Arg arg) + { + //Contract.Requires(node != null); + return StandardResult(node, arg); + } + public virtual Result VisitFloatLtOp(VCExprNAry node, Arg arg) + { + //Contract.Requires(node != null); + return StandardResult(node, arg); + } + public virtual Result VisitFloatGeqOp(VCExprNAry node, Arg arg) + { + //Contract.Requires(node != null); + return StandardResult(node, arg); + } + public virtual Result VisitFloatGtOp(VCExprNAry node, Arg arg) + { + //Contract.Requires(node != null); + return StandardResult(node, arg); + } + public virtual Result VisitFloatEqOp(VCExprNAry node, Arg arg) + { + //Contract.Requires(node != null); + return StandardResult(node, arg); + } public virtual Result VisitBvOp(VCExprNAry node, Arg arg) { //Contract.Requires(node != null); return StandardResult(node, arg); @@ -1494,11 +1631,6 @@ namespace Microsoft.Boogie.VCExprAST { //Contract.Requires(node != null); return StandardResult(node, arg); } - public virtual Result VisitFloatDivOp(VCExprNAry node, Arg arg) - { - //Contract.Requires(node != null); - return StandardResult(node, arg); - } public virtual Result VisitPowOp(VCExprNAry node, Arg arg) { //Contract.Requires(node != null); return StandardResult(node, arg); diff --git a/float_test5.bpl b/float_test5.bpl index be72b988..2661a736 100644 --- a/float_test5.bpl +++ b/float_test5.bpl @@ -1,4 +1,4 @@ procedure F() returns () { var x : float; - assert x - x == fp(0); + assert x - x == fp(0.0); } \ No newline at end of file diff --git a/float_test8.bpl b/float_test8.bpl index 7c23c74f..32fb8863 100644 --- a/float_test8.bpl +++ b/float_test8.bpl @@ -1,6 +1,5 @@ procedure F() returns () { - Logic=QF_FP; var x : float; - x := fp(.1) + fp(.1); - assert x == fp(.2); + x := fp(0.1) + fp(0.1); + assert x == fp(0.2); } \ No newline at end of file -- cgit v1.2.3 From a3b2bfa16f991f4d5f844b6d18e836e57b4195a1 Mon Sep 17 00:00:00 2001 From: Checkmate50 Date: Wed, 14 Oct 2015 13:02:48 -0600 Subject: Floating point constants given as integers are now translated correctly --- Source/Basetypes/BigFloat.cs | 2 ++ float_test5.bpl | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/Basetypes/BigFloat.cs b/Source/Basetypes/BigFloat.cs index 9e798959..bbc39db4 100644 --- a/Source/Basetypes/BigFloat.cs +++ b/Source/Basetypes/BigFloat.cs @@ -146,6 +146,8 @@ namespace Microsoft.Basetypes this.mantissa = 0; this.isDec = true; this.dec_value = dec_value; + if (this.dec_value.IndexOf(".") == -1) + this.dec_value += ".0"; //Assures that the decimal value is a "real" number } private BIM maxMantissa() diff --git a/float_test5.bpl b/float_test5.bpl index 2661a736..be72b988 100644 --- a/float_test5.bpl +++ b/float_test5.bpl @@ -1,4 +1,4 @@ procedure F() returns () { var x : float; - assert x - x == fp(0.0); + assert x - x == fp(0); } \ No newline at end of file -- cgit v1.2.3 From a1c9e11736bda4bf8ea4bf431523b9b975b01670 Mon Sep 17 00:00:00 2001 From: Checkmate50 Date: Sun, 29 Nov 2015 14:28:17 -0700 Subject: Special fp types (such as infinity and NaN are now translated by boogie --- Source/Basetypes/BigFloat.cs | 68 +++++++++++++++++++++++-------- Source/Core/Parser.cs | 4 +- Source/Provers/SMTLib/SMTLibLineariser.cs | 16 +++++--- float_test8.bpl | 4 +- 4 files changed, 64 insertions(+), 28 deletions(-) diff --git a/Source/Basetypes/BigFloat.cs b/Source/Basetypes/BigFloat.cs index bbc39db4..6cf94feb 100644 --- a/Source/Basetypes/BigFloat.cs +++ b/Source/Basetypes/BigFloat.cs @@ -25,7 +25,7 @@ namespace Microsoft.Basetypes // the internal representation [Rep] - internal readonly BIM mantissa; //Note that the mantissa arrangement matches standard fp arrangement (most significant bit is farthest left) + internal readonly long mantissa; //Note that the mantissa arrangement matches standard fp arrangement (most significant bit is farthest left) [Rep] internal readonly int mantissaSize; [Rep] @@ -37,7 +37,7 @@ namespace Microsoft.Basetypes [Rep] internal readonly bool isDec; - public BIM Mantissa { + public long Mantissa { get { return mantissa; } @@ -69,17 +69,17 @@ namespace Microsoft.Basetypes public bool IsDec { get { - return IsDec; + return isDec; } } public static BigFloat ZERO(int mantissaSize, int exponentSize) { return new BigFloat(0, 0, mantissaSize, exponentSize); } //Does not include negative zero private static readonly BIM two = new BIM(2); - private static BIM two_n(int n) { - BIM toReturn = new BIM(1); + private static long two_n(int n) { + long toReturn = 1; for (int i = 0; i < n; i++) - toReturn = toReturn * two; + toReturn = toReturn * 2; return toReturn; } @@ -96,10 +96,14 @@ namespace Microsoft.Basetypes } [Pure] - public static BigFloat FromBigInt(BIM v) { + public static BigFloat FromLong(long v) { return new BigFloat(0, v, 8, 24); } + public static BigFloat FromBigInt(BIM v) { + return FromLong(Int64.Parse(v.ToString())); //Sketchy. Hope this doesn't cause problems + } + public static BigFloat FromBigDec(BigDec v) { return new BigFloat(v.ToDecimalString(), 8, 24); @@ -116,11 +120,11 @@ namespace Microsoft.Basetypes case 1: return new BigFloat(vals[0], 8, 24); case 2: - return new BigFloat(Int32.Parse(vals[0]), BIM.Parse(vals[1]), 8, 24); + return new BigFloat(Int32.Parse(vals[0]), Int64.Parse(vals[1]), 8, 24); case 3: return new BigFloat(vals[0], Int32.Parse(vals[1]), Int32.Parse(vals[2])); case 4: - return new BigFloat(Int32.Parse(vals[0]), BIM.Parse(vals[1]), Int32.Parse(vals[2]), Int32.Parse(vals[3])); + return new BigFloat(Int32.Parse(vals[0]), Int64.Parse(vals[1]), Int32.Parse(vals[2]), Int32.Parse(vals[3])); default: throw new FormatException(); //Unreachable } @@ -130,7 +134,7 @@ namespace Microsoft.Basetypes } } - internal BigFloat(int exponent, BIM mantissa, int exponentSize, int mantissaSize) { + internal BigFloat(int exponent, long mantissa, int exponentSize, int mantissaSize) { this.exponentSize = exponentSize; this.exponent = exponent; this.mantissa = mantissa; @@ -146,8 +150,30 @@ namespace Microsoft.Basetypes this.mantissa = 0; this.isDec = true; this.dec_value = dec_value; + //Special cases: + if (this.dec_value.Equals("+oo") || this.dec_value.Equals("-oo") || this.dec_value.Equals("-zero")) + return; + if (this.dec_value.ToLower().Equals("nan")) { + this.dec_value = "NaN"; + return; + } + if (this.dec_value.Equals("INF") || this.dec_value.Equals("+INF")) { + this.dec_value = "+oo"; + return; + } + if (this.dec_value.Equals("-INF")) { + this.dec_value = "-oo"; + return; + } + if (this.dec_value.Equals("+zero")) { + this.dec_value = "0.0"; + return; + } + //End special cases if (this.dec_value.IndexOf(".") == -1) this.dec_value += ".0"; //Assures that the decimal value is a "real" number + if (this.dec_value.IndexOf(".") == 0) + this.dec_value = "0" + this.dec_value; //Assures that decimals always have a 0 in front } private BIM maxMantissa() @@ -265,7 +291,7 @@ namespace Microsoft.Basetypes } } - return new BigFloat(exp, value, exponentSize, mantissaSize); + return new BigFloat(exp, Int64.Parse(value.ToString()), exponentSize, mantissaSize); } // ``floor`` rounds towards negative infinity (like SMT-LIBv2's to_int). @@ -345,7 +371,7 @@ namespace Microsoft.Basetypes public BigFloat Abs { //TODO: fix for fp functionality get { - return new BigFloat(Exponent, BIM.Abs(Mantissa), ExponentSize, MantissaSize); + return new BigFloat(Exponent, Math.Abs(Mantissa), ExponentSize, MantissaSize); } } @@ -353,7 +379,7 @@ namespace Microsoft.Basetypes public BigFloat Negate { //TODO: Modify for correct fp functionality get { - return new BigFloat(Exponent, BIM.Negate(Mantissa), ExponentSize, MantissaSize); + return new BigFloat(Exponent, -Mantissa, ExponentSize, MantissaSize); } } @@ -367,9 +393,9 @@ namespace Microsoft.Basetypes //TODO: Modify for correct fp functionality Contract.Requires(x.ExponentSize == y.ExponentSize); Contract.Requires(x.MantissaSize == y.MantissaSize); - BIM m1 = x.Mantissa; + long m1 = x.Mantissa; int e1 = x.Exponent; - BIM m2 = y.Mantissa; + long m2 = y.Mantissa; int e2 = y.Exponent; m1 = m1 + two_n(x.mantissaSize + 1); //Add implicit bit m2 = m2 + two_n(y.mantissaSize + 1); @@ -381,7 +407,7 @@ namespace Microsoft.Basetypes } while (e2 < e1) { - m2 = m2 / two; + m2 = m2 / 2; e2++; } @@ -404,6 +430,14 @@ namespace Microsoft.Basetypes //////////////////////////////////////////////////////////////////////////// // Some basic comparison operations + public bool IsSpecialType { + get { + if (!IsDec) + return false; + return (dec_value.Equals("NaN") || dec_value.Equals("+oo") || dec_value.Equals("-oo") || dec_value.Equals("-zero")); + } + } + public bool IsPositive { get { return !IsNegative; @@ -418,7 +452,7 @@ namespace Microsoft.Basetypes public bool IsZero { get { - return Mantissa.IsZero && Exponent == 0; + return Mantissa == 0 && Exponent == 0; } } diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index 889d7be8..5fcb1cdc 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -1897,9 +1897,9 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { Get(); //Skip the fp token Get(); if (t.val != "(") { throw new FormatException(); } - while (la.kind == 1 || la.kind == 3 || la.kind == 6 || la.kind == 75) { //Get values between the parens + while (la.kind == 1 || la.kind == 3 || la.kind == 6 || la.kind == 4 || la.kind == 74 || la.kind == 75) { //Get values between the parens Get(); - if (t.val == "-") //special negative case (la.kind == 75) + if (t.val == "-" || t.val == "+") //special sign case (la.kind == 74 or 75) s += t.val; else s += t.val + " "; diff --git a/Source/Provers/SMTLib/SMTLibLineariser.cs b/Source/Provers/SMTLib/SMTLibLineariser.cs index 629f7e2d..7c3ae960 100644 --- a/Source/Provers/SMTLib/SMTLibLineariser.cs +++ b/Source/Provers/SMTLib/SMTLibLineariser.cs @@ -204,7 +204,11 @@ namespace Microsoft.Boogie.SMTLib else if (node is VCExprFloatLit) { BigFloat lit = ((VCExprFloatLit)node).Val; - wr.Write(("((_ to_fp 8 24) roundTowardZero ")); + if (lit.IsSpecialType) { + wr.Write("(_ " + lit.Decimal + " " + lit.ExponentSize.ToString() + " " + lit.MantissaSize.ToString() + ")"); + return true; + } + wr.Write("((_ to_fp " + lit.ExponentSize.ToString() + " " + lit.MantissaSize.ToString() + ") RNE "); if (lit.IsNegative) // In SMT2 "-42" is an identifier (SMT2, Sect. 3.2 "Symbols") wr.Write("(- 0.0 {0})", lit.Abs.ToDecimalString()); @@ -620,31 +624,31 @@ namespace Microsoft.Boogie.SMTLib public bool VisitFloatAddOp(VCExprNAry node, LineariserOptions options) { - WriteApplication("fp.add roundTowardZero", node, options); + WriteApplication("fp.add RNE", node, options); return true; } public bool VisitFloatSubOp(VCExprNAry node, LineariserOptions options) { - WriteApplication("fp.sub roundTowardZero", node, options); + WriteApplication("fp.sub RNE", node, options); return true; } public bool VisitFloatMulOp(VCExprNAry node, LineariserOptions options) { - WriteApplication("fp.mul roundTowardZero", node, options); + WriteApplication("fp.mul RNE", node, options); return true; } public bool VisitFloatDivOp(VCExprNAry node, LineariserOptions options) { - WriteApplication("fp.div roundTowardZero", node, options); + WriteApplication("fp.div RNE", node, options); return true; } public bool VisitFloatRemOp(VCExprNAry node, LineariserOptions options) { - WriteApplication("fp.rem roundTowardZero", node, options); + WriteApplication("fp.rem RNE", node, options); return true; } diff --git a/float_test8.bpl b/float_test8.bpl index 32fb8863..554dcf00 100644 --- a/float_test8.bpl +++ b/float_test8.bpl @@ -1,5 +1,3 @@ procedure F() returns () { - var x : float; - x := fp(0.1) + fp(0.1); - assert x == fp(0.2); + assert fp(-oo)==fp(-oo); } \ No newline at end of file -- cgit v1.2.3 From 6fad4313b1a4e7f8e6cfcd12b92126a3d9ad58d0 Mon Sep 17 00:00:00 2001 From: Checkmate50 Date: Mon, 4 Jan 2016 19:26:36 -0800 Subject: Added several test cases and some basic documentation for fp usage --- Source/AbsInt/IntervalDomain.cs | 29 ++++++++++++-- Source/Basetypes/BigFloat.cs | 30 +++++++++----- Source/BoogieDriver/BoogieDriver.cs | 2 +- float_test.bpl | 16 ++++++-- float_test10.bpl | 21 ++++++++-- float_test11.bpl | 38 ++++++++++++++++++ float_test12.bpl | 43 ++++++++++++++++++++ float_test13.bpl | 17 ++++++++ float_test14.bpl | 17 ++++++++ float_test15.bpl | 24 +++++++++++ float_test16.bpl | 8 ++++ float_test17.bpl | 11 ++++++ float_test18.bpl | 36 +++++++++++++++++ float_test19.bpl | 36 +++++++++++++++++ float_test2.bpl | 16 ++++++-- float_test20.bpl | 14 +++++++ float_test3.bpl | 14 ++++++- float_test4.bpl | 23 +++++++++-- float_test5.bpl | 35 ++++++++++++++-- float_test6.bpl | 43 ++++++++++++++++++-- float_test7.bpl | 41 +++++++++++++++++-- float_test8.bpl | 13 +++++- float_test9.bpl | 37 +++++++++++++++-- fp_documentation.txt | 79 +++++++++++++++++++++++++++++++++++++ 24 files changed, 596 insertions(+), 47 deletions(-) create mode 100644 float_test11.bpl create mode 100644 float_test12.bpl create mode 100644 float_test13.bpl create mode 100644 float_test14.bpl create mode 100644 float_test15.bpl create mode 100644 float_test16.bpl create mode 100644 float_test17.bpl create mode 100644 float_test18.bpl create mode 100644 float_test19.bpl create mode 100644 float_test20.bpl create mode 100644 fp_documentation.txt diff --git a/Source/AbsInt/IntervalDomain.cs b/Source/AbsInt/IntervalDomain.cs index a27ae68d..0c954f9a 100644 --- a/Source/AbsInt/IntervalDomain.cs +++ b/Source/AbsInt/IntervalDomain.cs @@ -180,8 +180,7 @@ namespace Microsoft.Boogie.AbstractInterpretation } } return e; - } else { - Contract.Assert(V.TypedIdent.Type.IsReal); + } else if (V.TypedIdent.Type.IsReal){ Expr e = Expr.True; if (Lo != null && Hi != null && Lo == Hi) { // produce an equality @@ -199,6 +198,30 @@ namespace Microsoft.Boogie.AbstractInterpretation } } return e; + } else { + Contract.Assert(V.TypedIdent.Type.IsFloat); + Expr e = Expr.True; + if (Lo != null && Hi != null && Lo == Hi) + { + // produce an equality + var ide = new IdentifierExpr(Token.NoToken, V); + e = Expr.And(e, BplEq(ide, NumberToExpr((BigInteger)Lo, V.TypedIdent.Type))); + } + else + { + // produce a (possibly empty) conjunction of inequalities + if (Lo != null) + { + var ide = new IdentifierExpr(Token.NoToken, V); + e = Expr.And(e, BplLe(NumberToExpr((BigInteger)Lo, V.TypedIdent.Type), ide)); + } + if (Hi != null) + { + var ide = new IdentifierExpr(Token.NoToken, V); + e = Expr.And(e, BplLe(ide, NumberToExpr((BigInteger)Hi, V.TypedIdent.Type))); + } + } + return e; } } } @@ -209,7 +232,7 @@ namespace Microsoft.Boogie.AbstractInterpretation } else if (ty.IsReal) { return Expr.Literal(Basetypes.BigDec.FromBigInt(n)); } else if (ty.IsFloat) { - return Expr.Literal(Basetypes.BigFloat.FromBigInt(n)); + return Expr.Literal(Basetypes.BigFloat.FromBigInt(n, ty.FloatExponent, ty.FloatMantissa)); } else { Contract.Assume(ty.IsInt); return Expr.Literal(Basetypes.BigNum.FromBigInt(n)); diff --git a/Source/Basetypes/BigFloat.cs b/Source/Basetypes/BigFloat.cs index 6cf94feb..5b169263 100644 --- a/Source/Basetypes/BigFloat.cs +++ b/Source/Basetypes/BigFloat.cs @@ -92,16 +92,21 @@ namespace Microsoft.Basetypes [Pure] public static BigFloat FromInt(int v) { - return new BigFloat(v, 0, 24, 8); + return new BigFloat(v.ToString(), 8, 24); } - [Pure] - public static BigFloat FromLong(long v) { - return new BigFloat(0, v, 8, 24); + public static BigFloat FromInt(int v, int exponentSize, int mantissaSize) + { + return new BigFloat(v.ToString(), exponentSize, mantissaSize); } public static BigFloat FromBigInt(BIM v) { - return FromLong(Int64.Parse(v.ToString())); //Sketchy. Hope this doesn't cause problems + return new BigFloat(v.ToString(), 8, 24); + } + + public static BigFloat FromBigInt(BIM v, int exponentSize, int mantissaSize) + { + return new BigFloat(v.ToString(), exponentSize, mantissaSize); } public static BigFloat FromBigDec(BigDec v) @@ -109,6 +114,11 @@ namespace Microsoft.Basetypes return new BigFloat(v.ToDecimalString(), 8, 24); } + public static BigFloat FromBigDec(BigDec v, int exponentSize, int mantissaSize) + { + return new BigFloat(v.ToDecimalString(), exponentSize, mantissaSize); + } + [Pure] public static BigFloat FromString(string v) { String[] vals = v.Split(' '); @@ -170,9 +180,9 @@ namespace Microsoft.Basetypes return; } //End special cases - if (this.dec_value.IndexOf(".") == -1) + if (this.dec_value.IndexOf('.') == -1 && this.dec_value.IndexOf('e') == -1) this.dec_value += ".0"; //Assures that the decimal value is a "real" number - if (this.dec_value.IndexOf(".") == 0) + if (this.dec_value.IndexOf('.') == 0) this.dec_value = "0" + this.dec_value; //Assures that decimals always have a 0 in front } @@ -369,16 +379,18 @@ namespace Microsoft.Basetypes [Pure] public BigFloat Abs { - //TODO: fix for fp functionality get { + if (IsDec) + return dec_value[0] == '-' ? new BigFloat(dec_value.Remove(0, 1), ExponentSize, MantissaSize) : this; return new BigFloat(Exponent, Math.Abs(Mantissa), ExponentSize, MantissaSize); } } [Pure] public BigFloat Negate { - //TODO: Modify for correct fp functionality get { + if (IsDec) + return dec_value[0] == '-' ? new BigFloat(dec_value.Remove(0, 1), ExponentSize, MantissaSize) : new BigFloat("-" + dec_value, ExponentSize, MantissaSize); return new BigFloat(Exponent, -Mantissa, ExponentSize, MantissaSize); } } diff --git a/Source/BoogieDriver/BoogieDriver.cs b/Source/BoogieDriver/BoogieDriver.cs index cba74bc5..2345cc1e 100644 --- a/Source/BoogieDriver/BoogieDriver.cs +++ b/Source/BoogieDriver/BoogieDriver.cs @@ -90,7 +90,7 @@ namespace Microsoft.Boogie { } } ExecutionEngine.ProcessFiles(fileList); - return 0; + return 0; END: if (CommandLineOptions.Clo.XmlSink != null) { diff --git a/float_test.bpl b/float_test.bpl index ebd0ab47..fbf8e4e3 100644 --- a/float_test.bpl +++ b/float_test.bpl @@ -1,5 +1,13 @@ -procedure F(n: float) returns(r: float) - ensures r == n; -{ - r := n; +//Translation from addsub_double_exact.c +//Should Verify +procedure main() returns () { + var x : float(11 53); + var y : float(11 53); + var z : float(11 53); + var r : float(11 53); + x := fp(10000000 11 53); + y := x + fp(1 11 53); + z := x - fp(1 11 53); + r := y - z; + assert r == fp(2 11 53); } \ No newline at end of file diff --git a/float_test10.bpl b/float_test10.bpl index 7423a3a0..566f7a56 100644 --- a/float_test10.bpl +++ b/float_test10.bpl @@ -1,5 +1,20 @@ - procedure F() returns () { +//Translation from loop.c +//Should return an error? (The real case does as well...) + +procedure main() returns () { var x : float; - x := fp (0.5 23 8); - assert x == fp (0 -1); + var y : float; + var z : float; + + x := fp(1); + y := fp(10000000); + z := fp(42); + + while (x < y) { + x := x + fp(1); + y := y - fp(1); + z := z + fp(1); + } + + assert(z >= fp(0) && z <= fp(10000000)); } \ No newline at end of file diff --git a/float_test11.bpl b/float_test11.bpl new file mode 100644 index 00000000..cf9fd3a2 --- /dev/null +++ b/float_test11.bpl @@ -0,0 +1,38 @@ +//Translation from interpolation.c +//Should Verify +//Returns inconclusize? What does that mean? + +procedure main() returns () { + var i : int; + var z : float; + var t : float; + var min : [int] float; + var max : [int] float; + + min[0] := fp(5); + min[1] := fp(10); + min[2] := fp(12); + min[3] := fp(30); + min[4] := fp(150); + + max[0] := fp(10); + max[1] := fp(12); + max[2] := fp(30); + max[3] := fp(150); + max[4] := fp(300); + + havoc t; + assume(t >= min[0] && t <= max[4]); + + i := 0; + while (i < 5) { + if (t <= max[i]) { + break; + } + i := i + 1; + } + + z := (t - min[i]) / (max[i] - min[i]); + + assert(z >= fp(0) && z <= fp(1)); +} \ No newline at end of file diff --git a/float_test12.bpl b/float_test12.bpl new file mode 100644 index 00000000..c733b9f4 --- /dev/null +++ b/float_test12.bpl @@ -0,0 +1,43 @@ +//Translation from inv_Newton.c +//Should Verify +//Unfinished code! + +procedure inv(float(11 53)) returns(float(11 53)) { + var z : float(11 53); + var t : float(11 53); + var t : float(11 53); + + +} + +procedure main() returns () { + var t : float(11 53); + var t : float(11 53); + + min[0] := fp(5); + min[1] := fp(10); + min[2] := fp(12); + min[3] := fp(30); + min[4] := fp(150); + + max[0] := fp(10); + max[1] := fp(12); + max[2] := fp(30); + max[3] := fp(150); + max[4] := fp(300); + + havoc t; + assume(t >= min[0] && t <= max[4]); + + i := 0; + while (i < 5) { + if (t <= max[i]) { + break; + } + i := i + 1; + } + + z := (t - min[i]) / (max[i] - min[i]); + + assert(z >= fp(0) && z <= fp(1)); +} \ No newline at end of file diff --git a/float_test13.bpl b/float_test13.bpl new file mode 100644 index 00000000..d073836d --- /dev/null +++ b/float_test13.bpl @@ -0,0 +1,17 @@ +//Translation from inv_square_false-unreach-call.c +//Should return an error (without crashing) + +procedure main() returns () { + var x : float; + var y : float; + var z : float; + + havoc x; + assume(x >= fp(-1) && x <= fp(1)); + + if (x != fp(0)) { + y := x * x; + assert(y != fp(0)); + z := fp(1) / y; + } +} \ No newline at end of file diff --git a/float_test14.bpl b/float_test14.bpl new file mode 100644 index 00000000..9b5dab0a --- /dev/null +++ b/float_test14.bpl @@ -0,0 +1,17 @@ +//Translation from inv_square_false-unreach-call.c +//Should Verify + +procedure main() returns () { + var x : float; + var y : float; + var z : float; + + havoc x; + assume(x >= fp(-1) && x <= fp(1)); + + if (x <= fp(-.00000000000000000001) || x >= fp(.00000000000000000001)) { + y := x * x; + assert(y != fp(0)); + z := fp(1) / y; + } +} \ No newline at end of file diff --git a/float_test15.bpl b/float_test15.bpl new file mode 100644 index 00000000..1dc549ac --- /dev/null +++ b/float_test15.bpl @@ -0,0 +1,24 @@ +//Translation from Muller_Kahan.c +//Should Verify +//NOTE: (fp(....)) causes a compiler error! +//FAILS! Heavily... + +procedure main() returns () { + var x0 : float(11 53); + var x1 : float(11 53); + var x2 : float(11 53); + var i : int; + + x0 := fp(11 11 53) / fp(2 11 53); + x1 := fp(61 11 53) / fp(11 11 53); + i := 0; + while (i < 100) { + x2 := fp(1130 11 53) - fp(3000 11 53) / x0; + x2 := fp(111 11 53) - x2 / x1; + x0 := x1; + x1 := x2; + i := i + 1; + } + + assert(x0 >= fp(99 11 53) && x0 <= fp(101 11 53)); +} \ No newline at end of file diff --git a/float_test16.bpl b/float_test16.bpl new file mode 100644 index 00000000..69ae243d --- /dev/null +++ b/float_test16.bpl @@ -0,0 +1,8 @@ +//Translation from nan_double_false-unreach-call.c +//Should return an error + +procedure main() returns () { + var x : float(11 53); + havoc x; + assert(x==x); +} \ No newline at end of file diff --git a/float_test17.bpl b/float_test17.bpl new file mode 100644 index 00000000..caa1fa74 --- /dev/null +++ b/float_test17.bpl @@ -0,0 +1,11 @@ +//Translation from nan_double_range_true-unreach-call.c +//Should verify +//Uggghhhh, should I add support for e? + +procedure main() returns () { + var x : float(11 53); + havoc x; + if (x >= fp(-100000000000000000000000000 11 53) && x <= fp(100000000000000000000000000 11 53)) { + assert(x==x); + } +} \ No newline at end of file diff --git a/float_test18.bpl b/float_test18.bpl new file mode 100644 index 00000000..71eb5286 --- /dev/null +++ b/float_test18.bpl @@ -0,0 +1,36 @@ +//Translation from rlim_exit.c +//Should verify +//Unary - unsupported float operations (on my end)... + +procedure main() returns () { + var X : float; + var Y : float; + var S : float; + var R : float; + var D : float; + var i : int; + + Y := fp(0); + + i := 0; + while (i < 100000) { + havoc X; + havoc D; + assume(X >= fp(-128) && X <= fp(128)); + assume(D >= fp(0) && D <= fp(16)); + + S := Y; + Y := X; + R := X - S; + if (R <= fp(0)-D) { + Y := S - D; + } + else if(R >= D) { + Y := S + D; + } + + i := i + 1; + } + + assert(Y >= fp(-129) && Y <= fp(129)); +} \ No newline at end of file diff --git a/float_test19.bpl b/float_test19.bpl new file mode 100644 index 00000000..f00d8a2b --- /dev/null +++ b/float_test19.bpl @@ -0,0 +1,36 @@ +//Translation from flim_invariant.c +//Should verify +//Unary - unsupported float operations (on my end)... + +procedure main() returns () { + var X : float; + var Y : float; + var S : float; + var R : float; + var D : float; + var i : int; + + Y := fp(0); + + i := 0; + while (i < 100000) { + havoc X; + havoc D; + assume(X >= fp(-128) && X <= fp(128)); + assume(D >= fp(0) && D <= fp(16)); + + S := Y; + Y := X; + R := X - S; + if (R <= fp(0)-D) { + Y := S - D; + } + else if(R >= D) { + Y := S + D; + } + + assert(Y >= fp(-129) && Y <= fp(129)); + + i := i + 1; + } +} \ No newline at end of file diff --git a/float_test2.bpl b/float_test2.bpl index 956ac757..da74909b 100644 --- a/float_test2.bpl +++ b/float_test2.bpl @@ -1,5 +1,13 @@ -procedure F() returns () { - var x : float(11 53); - var y : float(11 53); - assert x == y; +//Translation from addsub_float_exact.c +//Should Verify +procedure main() returns () { + var x : float; + var y : float; + var z : float; + var r : float; + x := fp(1000000); + y := x + fp(1); + z := x - fp(1); + r := y - z; + assert r == fp(2); } \ No newline at end of file diff --git a/float_test20.bpl b/float_test20.bpl new file mode 100644 index 00000000..57c605fd --- /dev/null +++ b/float_test20.bpl @@ -0,0 +1,14 @@ +//Should return an error? +//Translation from Rump_double.c + +procedure main() returns () { + var x : float(11 53); + var y : float(11 53); + var r : float(11 53); + + x := fp(77617 11 53); + y := fp(33096 11 53); + r := y*y*y*y*y*y * fp(333.75 11 53) + x*x * (x*x*y*y*fp(11 11 53) - y*y*y*y*y*y - y*y*y*y * fp(121 11 53) - fp(2 11 53)) + y*y*y*y*y*y*y*y * fp(5.5 11 53) + x / (y*fp(2 11 53)); + + assert(r >= fp(0 11 53)); +} \ No newline at end of file diff --git a/float_test3.bpl b/float_test3.bpl index e93e7df7..dd0c1ba4 100644 --- a/float_test3.bpl +++ b/float_test3.bpl @@ -1,3 +1,13 @@ - procedure F() returns () { - assert fp(5) == fp(5 8 23); +//Translation from addsub_float_inexact.c +//Should give an error +procedure main() returns () { + var x : float; + var y : float; + var z : float; + var r : float; + x := fp(10000000); + y := x + fp(1); + z := x - fp(1); + r := y - z; + assert r == fp(0); } \ No newline at end of file diff --git a/float_test4.bpl b/float_test4.bpl index 1252dc71..a7aa8c4b 100644 --- a/float_test4.bpl +++ b/float_test4.bpl @@ -1,5 +1,20 @@ - procedure F() returns () { - var x : float; - x := fp (.5 8 23); - assert x == fp (-1 0); +//Translation from drift_tenth.c +//Should Verify +//FAILS; note that it succeeds when tick == fp(.1) + +procedure main() returns () { + var tick : float; + var time : float; + var i: int; + + tick := fp(1)/fp(10); + time := fp(0); + + i := 0; + while (i < 10) + { + time := time + tick; + i := i + 1; + } + assert(time == fp(1)); } \ No newline at end of file diff --git a/float_test5.bpl b/float_test5.bpl index be72b988..ce5d2bc7 100644 --- a/float_test5.bpl +++ b/float_test5.bpl @@ -1,4 +1,33 @@ -procedure F() returns () { - var x : float; - assert x - x == fp(0); +//Translation from filter1.c +//Should Verify + +procedure main() returns () { + var E0 : float(11 53); + var E1 : float(11 53); + var S : float(11 53); + var i : int; + var rand : int; + + E1 := fp(0 11 53); + S := fp(0 11 53); + + i := 0; + while (i <= 1000000) + { + havoc E0; + assume(E0 >= fp(-1 11 53) && E0 <= fp(1 11 53)); + + havoc rand; + if (rand != 0) { + S := fp(0 11 53); + } + else { + S := fp(0.999 11 53) * S + E0 - E1; + } + E1 := E0; + + //assert(1==0); + assert(S >= fp(-1 11 53) && S <= fp(1 11 53)); + i := i + 1; + } } \ No newline at end of file diff --git a/float_test6.bpl b/float_test6.bpl index 423bc45a..6bef1137 100644 --- a/float_test6.bpl +++ b/float_test6.bpl @@ -1,5 +1,40 @@ -procedure F() returns () { - var x : float; - var y : float; - assert (x + x) + (y + y) == fp(0); +//Translation from filter2.c +//Should give an error +//FAILS; doesn't generate terms! + +procedure main() returns () { + var E : float(11 53); + var E0 : float(11 53); + var E1 : float(11 53); + var S : float(11 53); + var S0 : float(11 53); + var S1 : float(11 53); + var i: int; + + havoc E; + havoc E0; + assume(E >= fp(0.0 11 53) && E <= fp(1.0 11 53)); + assume(E0 >= fp(0.0 11 53) && E0 <= fp(1.0 11 53)); + + E1 := fp(0.0 11 53); + S1 := fp(0.0 11 53); + S0 := fp(0.0 11 53); + S := fp(0.0 11 53); + + i := 0; +// while (i <= 1000000) +// { + E1 := E0; + E0 := E; + + havoc E; + assume(E >= fp(0.0 11 53) && E <= fp(1.0 11 53)); + + S1 := S0; + S0 := S; + S := E*fp(0.7 11 53) - E0*fp(1.3 11 53) + E1*fp(1.1 11 53) + S0*fp(1.4 11 53) - S1*fp(0.7 11 53); + + assert(S >= fp(-4.0 11 53) && S <= fp(4.0 11 53)); + //i := i + 1; +// } } \ No newline at end of file diff --git a/float_test7.bpl b/float_test7.bpl index cc7a040b..8e07878d 100644 --- a/float_test7.bpl +++ b/float_test7.bpl @@ -1,5 +1,38 @@ -procedure F() returns () { - var x : float; - x := fp(.1) + fp(.1) + fp(.1); - assert x == fp(.3); +//Translation from filter2.c +//Should give an error +//Same as the previous one; it works with reals! + +procedure main() returns () { + var E : real; + var E0 : real; + var E1 : real; + var S : real; + var S0 : real; + var S1 : real; + var i: int; + + havoc E; + havoc E0; + assume(E >= 0.0 && E <= 1.0); + assume(E0 >= 0.0 && E0 <= 1.0); + + S0 := 0.0; + S := 0.0; + + i := 0; + while (i <= 1000000) + { + E1 := E0; + E0 := E; + + havoc E; + assume(E >= 0.0 && E <= 1.0); + + S1 := S0; + S0 := S; + S := E*0.7 - E0*1.3 + E1*1.1 + S0*1.4 - S1*0.7; + + assert(S >= -4.0 && S <= 4.0); + i := i + 1; + } } \ No newline at end of file diff --git a/float_test8.bpl b/float_test8.bpl index 554dcf00..995ed4fa 100644 --- a/float_test8.bpl +++ b/float_test8.bpl @@ -1,3 +1,12 @@ -procedure F() returns () { - assert fp(-oo)==fp(-oo); +//Translation from float_double.c +//Should Verify +//FAILS: I don't have this functionality yet... + +procedure main() returns () { + var x : float(11 53); + var y : float; + + x := fp(100000000000000000001 11 53); + y := x; + assert(x != y); } \ No newline at end of file diff --git a/float_test9.bpl b/float_test9.bpl index 7423a3a0..c3a42e6b 100644 --- a/float_test9.bpl +++ b/float_test9.bpl @@ -1,5 +1,34 @@ - procedure F() returns () { - var x : float; - x := fp (0.5 23 8); - assert x == fp (0 -1); +//Translation from feedback_diverge.c +//Should give an error +//Not sure on this one... + +procedure main() returns () { + var A : float; + var B : float; + var X : float; + var i : int; + var rand : int; + + A := fp(0); + B := fp(0); + + i := 0; + while (i < 3600000) { + + havoc rand; + if (rand != 0) { + havoc X; + assume(X >= fp(-20) && X <= fp(20)); + } + else { + X := B; + } + + B := B - (B * fp(2.0) - A - X) * fp(.005); + A := X; + + i := i + 1; + } + + assert(A >= fp(-100) && A <= fp(100)); } \ No newline at end of file diff --git a/fp_documentation.txt b/fp_documentation.txt new file mode 100644 index 00000000..09e60b9a --- /dev/null +++ b/fp_documentation.txt @@ -0,0 +1,79 @@ +Floating Point Documentation for Boogie +Written by Dietrich Geisler +Contact: dgeisler50@gmail.com + +This document aims to describe the syntax for declaring and using floating points in Boogie + +-------------------------------------------------------------------------------- +Declaring Variables: + +The syntax for declaring a floating point variable is as follows: +var name: float(exp man); +Where exp is the size of the float exponent and man is the size of the float mantissa + +It is also acceptable to use the following syntax: +var name: float(); +This syntax assumes the float exponent to be size 8 and the mantissa to be size 24 + +example: +var x: float(11 53) +Declares a variable called x with a exponent sized 11 and mantissa sized 53 + +-------------------------------------------------------------------------------- +Declaring Constants: + +All of the following syntax are viable for declaring a floating point constant: +float(dec) +float(exp_val man_val) +float(dec exp man) +float(exp_val man_val exp man) + +Where dec is the decimal value of the constant, +exp_val/man_value are the integer values of their respective fields, +And exp/man are the sizes of their respective fields. +Note that when exp and man are not specified, they are given sizes 8 and 24 respectively + +-------------------------------------------------------------------------------- +Defined Operations: + +Given two floating point values x and y with the same size of exponent and mantissa +The following operations operate as defined in Operators section of this document: +http://smtlib.cs.uiowa.edu/theories-FloatingPoint.shtml +(Note that rounding mode is always assumed to be Round to Nearest Even (RNE)) +(Also note that operations not listed here are undefined) + +operatation boogie syntax +neg(x) -x +add(x, y) x + y +sub(x, y) x - y +mul(x, y) x * y +div(x, y) x / y +leq(x, y) x <= y +lt(x, y) x < y +geq(x, y) x >= y +gt(x, y) x > y +eq(x, y) x == y + +-------------------------------------------------------------------------------- +Other: + +The following special values can be declared with the following syntax: +Value Declaration +NaN fp(nan exp man) ++oo fp(oo exp man) OR fp(INF exp man) +-oo fp(-oo exp man) OR fp(INF exp man) +-zero fp(-zero exp man) +Where exp and man are the sizes of the exponent and mantissa respectively + +-------------------------------------------------------------------------------- +Known Issues: + +There is currently no way to convert from a floating point to any other data type + +There is currently no way to convert the value of a variable to a floating point type +For example, the following statements fails: +var x : real; +fp(x); + +Statements of the following form cause a parser error (parenthesis followed by fp constant) +... (fp(1) + fp(1)); \ No newline at end of file -- cgit v1.2.3 From 6ac996211d6f42f0c7f61ea108388d6bb798ecf8 Mon Sep 17 00:00:00 2001 From: Checkmate50 Date: Sat, 20 Feb 2016 20:53:08 -0700 Subject: Modified BigFloat and parser to accept correct SMT-LIB syntax --- Source/Basetypes/BigFloat.cs | 250 ++++++++++++++---------------- Source/Core/Parser.cs | 90 +++++++---- Source/Provers/SMTLib/SMTLibLineariser.cs | 4 +- fp_documentation.txt | 19 ++- 4 files changed, 192 insertions(+), 171 deletions(-) diff --git a/Source/Basetypes/BigFloat.cs b/Source/Basetypes/BigFloat.cs index 5b169263..8cde2cb9 100644 --- a/Source/Basetypes/BigFloat.cs +++ b/Source/Basetypes/BigFloat.cs @@ -17,7 +17,7 @@ namespace Microsoft.Basetypes /// /// A representation of a 32-bit floating point value - /// Note that this value has a 1-bit sign, 8-bit exponent, and 24-bit mantissa + /// Note that this value has a 1-bit sign, 8-bit exponent, and 24-bit significand /// public struct BigFloat { @@ -25,33 +25,33 @@ namespace Microsoft.Basetypes // the internal representation [Rep] - internal readonly long mantissa; //Note that the mantissa arrangement matches standard fp arrangement (most significant bit is farthest left) + internal readonly BigNum significand; //Note that the significand arrangement matches standard fp arrangement (most significant bit is farthest left) [Rep] - internal readonly int mantissaSize; + internal readonly int significandSize; [Rep] - internal readonly int exponent; //The value of the exponent is always positive as per fp representation requirements + internal readonly BigNum exponent; //The value of the exponent is always positive as per fp representation requirements [Rep] internal readonly int exponentSize; //The bit size of the exponent [Rep] - internal readonly String dec_value; + internal readonly String value; //Only used with second syntax [Rep] - internal readonly bool isDec; + internal readonly bool isNeg; - public long Mantissa { + public BigNum Significand { get { - return mantissa; + return significand; } } - public int Exponent { + public BigNum Exponent { get { return exponent; } } - public int MantissaSize { + public int SignificandSize { get { - return mantissaSize; + return significandSize; } } @@ -61,25 +61,26 @@ namespace Microsoft.Basetypes } } - public String Decimal { + public bool IsNegative { get { - return dec_value; + return this.isNeg; } } - public bool IsDec { + public String Value { get { - return isDec; + return value; } } - public static BigFloat ZERO(int mantissaSize, int exponentSize) { return new BigFloat(0, 0, mantissaSize, exponentSize); } //Does not include negative zero + public static BigFloat ZERO(int exponentSize, int significandSize) { return new BigFloat(false, BigNum.ZERO, BigNum.ZERO, exponentSize, significandSize); } //Does not include negative zero - private static readonly BIM two = new BIM(2); - private static long two_n(int n) { - long toReturn = 1; + private static readonly BigNum two = new BigNum(2); + private static readonly BigNum one = new BigNum(1); + private static BigNum two_n(int n) { + BigNum toReturn = one; for (int i = 0; i < n; i++) - toReturn = toReturn * 2; + toReturn = toReturn * two; return toReturn; } @@ -95,18 +96,18 @@ namespace Microsoft.Basetypes return new BigFloat(v.ToString(), 8, 24); } - public static BigFloat FromInt(int v, int exponentSize, int mantissaSize) + public static BigFloat FromInt(int v, int exponentSize, int significandSize) { - return new BigFloat(v.ToString(), exponentSize, mantissaSize); + return new BigFloat(v.ToString(), exponentSize, significandSize); } public static BigFloat FromBigInt(BIM v) { return new BigFloat(v.ToString(), 8, 24); } - public static BigFloat FromBigInt(BIM v, int exponentSize, int mantissaSize) + public static BigFloat FromBigInt(BIM v, int exponentSize, int significandSize) { - return new BigFloat(v.ToString(), exponentSize, mantissaSize); + return new BigFloat(v.ToString(), exponentSize, significandSize); } public static BigFloat FromBigDec(BigDec v) @@ -114,84 +115,67 @@ namespace Microsoft.Basetypes return new BigFloat(v.ToDecimalString(), 8, 24); } - public static BigFloat FromBigDec(BigDec v, int exponentSize, int mantissaSize) + public static BigFloat FromBigDec(BigDec v, int exponentSize, int significandSize) { - return new BigFloat(v.ToDecimalString(), exponentSize, mantissaSize); + return new BigFloat(v.ToDecimalString(), exponentSize, significandSize); } [Pure] - public static BigFloat FromString(string v) { - String[] vals = v.Split(' '); - if (vals.Length == 0 || vals.Length > 4) - throw new FormatException(); - try - { - switch (vals.Length) { - case 1: - return new BigFloat(vals[0], 8, 24); - case 2: - return new BigFloat(Int32.Parse(vals[0]), Int64.Parse(vals[1]), 8, 24); - case 3: - return new BigFloat(vals[0], Int32.Parse(vals[1]), Int32.Parse(vals[2])); - case 4: - return new BigFloat(Int32.Parse(vals[0]), Int64.Parse(vals[1]), Int32.Parse(vals[2]), Int32.Parse(vals[3])); - default: - throw new FormatException(); //Unreachable - } - } - catch (Exception) { //Catch parsing errors - throw new FormatException(); - } + public static BigFloat FromString(String v, int exp, int sig) { //String must be + return new BigFloat(v, exp, sig); } - internal BigFloat(int exponent, long mantissa, int exponentSize, int mantissaSize) { + public BigFloat(bool sign, BigNum exponent, BigNum significand, int exponentSize, int significandSize) { this.exponentSize = exponentSize; this.exponent = exponent; - this.mantissa = mantissa; - this.mantissaSize = mantissaSize; - this.isDec = false; - this.dec_value = ""; + this.significand = significand; + this.significandSize = significandSize; + this.isNeg = sign; + this.value = ""; } - internal BigFloat(String dec_value, int exponentSize, int mantissaSize) { + public BigFloat(String value, int exponentSize, int significandSize) { this.exponentSize = exponentSize; - this.mantissaSize = mantissaSize; - this.exponent = 0; - this.mantissa = 0; - this.isDec = true; - this.dec_value = dec_value; + this.significandSize = significandSize; + this.exponent = BigNum.ZERO; + this.significand = BigNum.ZERO; + this.value = value; + this.isNeg = value[0] == '-'; //Special cases: - if (this.dec_value.Equals("+oo") || this.dec_value.Equals("-oo") || this.dec_value.Equals("-zero")) + if (this.value.Equals("+oo") || this.value.Equals("-oo") || this.value.Equals("-zero")) return; - if (this.dec_value.ToLower().Equals("nan")) { - this.dec_value = "NaN"; + if (this.value.ToLower().Equals("nan")) { + this.value = "NaN"; return; } - if (this.dec_value.Equals("INF") || this.dec_value.Equals("+INF")) { - this.dec_value = "+oo"; + if (this.value.Equals("INF") || this.value.Equals("+INF")) + { + this.value = "+oo"; return; } - if (this.dec_value.Equals("-INF")) { - this.dec_value = "-oo"; + if (this.value.Equals("-INF")) + { + this.value = "-oo"; return; } - if (this.dec_value.Equals("+zero")) { - this.dec_value = "0.0"; + if (this.value.Equals("+zero")) + { + this.value = "0.0"; return; } //End special cases - if (this.dec_value.IndexOf('.') == -1 && this.dec_value.IndexOf('e') == -1) - this.dec_value += ".0"; //Assures that the decimal value is a "real" number - if (this.dec_value.IndexOf('.') == 0) - this.dec_value = "0" + this.dec_value; //Assures that decimals always have a 0 in front + if (this.value.IndexOf('.') == -1 && this.value.IndexOf('e') == -1) + this.value += ".0"; //Assures that the decimal value is a "real" number + if (this.value.IndexOf('.') == 0) + this.value = "0" + this.value; //Assures that decimals always have a 0 in front } - private BIM maxMantissa() + private BigNum maxsignificand() { - BIM result = new BIM(1); - for (int i = 0; i < mantissaSize; i++) + BigNum result = one; + for (int i = 0; i < significandSize; i++) result = result * two; - return result - 1; + return result - one; } private int maxExponent() { return (int)Math.Pow(2, exponentSize) - 1; } @@ -213,13 +197,13 @@ namespace Microsoft.Basetypes [Pure] public override int GetHashCode() { - return Mantissa.GetHashCode() * 13 + Exponent.GetHashCode(); + return significand.GetHashCode() * 13 + Exponent.GetHashCode(); } [Pure] public override string/*!*/ ToString() { Contract.Ensures(Contract.Result() != null); - return isDec ? dec_value : String.Format("{0}x2^{1}", Mantissa.ToString(), Exponent.ToString()); + return value=="" ? String.Format("{0}x2^{1}", significand.ToString(), Exponent.ToString()) : value; } @@ -229,41 +213,41 @@ namespace Microsoft.Basetypes /// /// NOTE: THIS METHOD MAY NOT WORK AS EXPECTED!!! /// Converts the given decimal value (provided as a string) to the nearest floating point approximation - /// the returned fp assumes the given mantissa and exponent size + /// the returned fp assumes the given significand and exponent size /// /// - /// + /// /// /// - public static BigFloat Round(String value, int exponentSize, int mantissaSize) + public static BigFloat Round(String value, int exponentSize, int significandSize) { int i = value.IndexOf('.'); if (i == -1) - return Round(BIM.Parse(value), 0, exponentSize, mantissaSize); - return Round(i == 0 ? 0 : BIM.Parse(value.Substring(0, i)), BIM.Parse(value.Substring(i + 1, value.Length - i - 1)), exponentSize, mantissaSize); + return Round(BigNum.FromString(value), BigNum.ZERO, exponentSize, significandSize); + return Round(i == 0 ? BigNum.ZERO : BigNum.FromString(value.Substring(0, i)), BigNum.FromString(value.Substring(i + 1, value.Length - i - 1)), exponentSize, significandSize); } /// /// NOTE: THIS METHOD MAY NOT WORK AS EXPECTED!!!! - /// Converts value.dec_value to a the closest float approximation with the given mantissaSize, exponentSize + /// Converts value.dec_value to a the closest float approximation with the given significandSize, exponentSize /// Returns the result of this calculation /// /// /// - /// + /// /// /// - public static BigFloat Round(BIM value, BIM dec_value, int exponentSize, int mantissaSize) + public static BigFloat Round(BigNum value, BigNum dec_value, int exponentSize, int significandSize) { int exp = 0; - BIM one = new BIM(1); - BIM ten = new BIM(10); - BIM dec_max = new BIM(0); //represents the order of magnitude of dec_value for carrying during calculations + BigNum one = new BigNum(1); + BigNum ten = new BigNum(10); + BigNum dec_max = new BigNum(0); //represents the order of magnitude of dec_value for carrying during calculations //First, determine the exponent while (value > one) { //Divide by two, increment exponent by 1 if (!(value % two).IsZero) { //Add "1.0" to the decimal - dec_max = new BIM(10); + dec_max = new BigNum(10); while (dec_max < dec_value) dec_max = dec_max * ten; dec_value = dec_value + dec_max; @@ -275,7 +259,7 @@ namespace Microsoft.Basetypes exp++; } if (value.IsZero && !dec_value.IsZero) { - dec_max = new BIM(10); + dec_max = new BigNum(10); while (dec_max < dec_value) dec_max = dec_max * ten; while (value.IsZero) {//Multiply by two, decrement exponent by 1 @@ -288,12 +272,12 @@ namespace Microsoft.Basetypes } } - //Second, calculate the mantissa - value = new BIM(0); //remove implicit bit - dec_max = new BIM(10); + //Second, calculate the significand + value = new BigNum(0); //remove implicit bit + dec_max = new BigNum(10); while (dec_max < dec_value) dec_max = dec_max * ten; - for (int i = mantissaSize; i > 0 && !dec_value.IsZero; i--) { //Multiply by two until the mantissa is fully calculated + for (int i = significandSize; i > 0 && !dec_value.IsZero; i--) { //Multiply by two until the significand is fully calculated dec_value = dec_value * two; if (dec_value >= dec_max) { dec_value = dec_value - dec_max; @@ -301,7 +285,7 @@ namespace Microsoft.Basetypes } } - return new BigFloat(exp, Int64.Parse(value.ToString()), exponentSize, mantissaSize); + return new BigFloat(false, BigNum.ZERO, BigNum.FromString(value.ToString()), exponentSize, significandSize); //Sign not actually checked... } // ``floor`` rounds towards negative infinity (like SMT-LIBv2's to_int). @@ -312,30 +296,32 @@ namespace Microsoft.Basetypes /// /// The Floor (rounded towards negative infinity) /// Ceiling (rounded towards positive infinity) - public void FloorCeiling(out BIM floor, out BIM ceiling) { + public void FloorCeiling(out BigNum floor, out BigNum ceiling) { //TODO: fix for fp functionality - BIM n = Mantissa; - int e = Exponent; + BigNum n = Significand; + BigNum e = Exponent; if (n.IsZero) { floor = ceiling = n; - } else if (0 <= e) { + } else if (BigNum.ZERO <= e) { // it's an integer - for (; 0 < e; e--) { + for (; BigNum.ZERO < e; e = e - one) + { n = n * two; } floor = ceiling = n; } else { // it's a non-zero integer, so the ceiling is one more than the floor - for (; e < 0 && !n.IsZero; e++) { + for (; BigNum.ZERO < e && !n.IsZero; e = e + one) + { n = n / two; // Division rounds towards negative infinity } if (!IsNegative) { floor = n; - ceiling = n + 1; + ceiling = n + one; } else { ceiling = n; - floor = n - 1; + floor = n - one; } } Debug.Assert(floor <= ceiling, "Invariant was not maintained"); @@ -352,7 +338,7 @@ namespace Microsoft.Basetypes [Pure] public string ToDecimalString() { Contract.Ensures(Contract.Result() != null); - return isDec ? dec_value : String.Format("{0}x2^{1}", Mantissa.ToString(), Exponent.ToString()); + return value=="" ? String.Format("{0}x2^{1}", significand.ToString(), Exponent.ToString()) : value; } [Pure] @@ -380,18 +366,16 @@ namespace Microsoft.Basetypes [Pure] public BigFloat Abs { get { - if (IsDec) - return dec_value[0] == '-' ? new BigFloat(dec_value.Remove(0, 1), ExponentSize, MantissaSize) : this; - return new BigFloat(Exponent, Math.Abs(Mantissa), ExponentSize, MantissaSize); + return new BigFloat(true, Exponent, Significand, ExponentSize, SignificandSize); } } [Pure] public BigFloat Negate { get { - if (IsDec) - return dec_value[0] == '-' ? new BigFloat(dec_value.Remove(0, 1), ExponentSize, MantissaSize) : new BigFloat("-" + dec_value, ExponentSize, MantissaSize); - return new BigFloat(Exponent, -Mantissa, ExponentSize, MantissaSize); + if (value != "") + return value[0] == '-' ? new BigFloat(value.Remove(0, 1), ExponentSize, significandSize) : new BigFloat("-" + value, ExponentSize, significandSize); + return new BigFloat(!isNeg, Exponent, Significand, ExponentSize, SignificandSize); } } @@ -404,26 +388,26 @@ namespace Microsoft.Basetypes public static BigFloat operator +(BigFloat x, BigFloat y) { //TODO: Modify for correct fp functionality Contract.Requires(x.ExponentSize == y.ExponentSize); - Contract.Requires(x.MantissaSize == y.MantissaSize); - long m1 = x.Mantissa; - int e1 = x.Exponent; - long m2 = y.Mantissa; - int e2 = y.Exponent; - m1 = m1 + two_n(x.mantissaSize + 1); //Add implicit bit - m2 = m2 + two_n(y.mantissaSize + 1); + Contract.Requires(x.significandSize == y.significandSize); + BigNum m1 = x.significand; + BigNum e1 = x.Exponent; + BigNum m2 = y.significand; + BigNum e2 = y.Exponent; + m1 = m1 + two_n(x.significandSize + 1); //Add implicit bit + m2 = m2 + two_n(y.significandSize + 1); if (e2 > e1) { - m1 = y.Mantissa; + m1 = y.significand; e1 = y.Exponent; - m2 = x.Mantissa; + m2 = x.significand; e2 = x.Exponent; } while (e2 < e1) { - m2 = m2 / 2; - e2++; + m2 = m2 / two; + e2 = e2 + one; } - return new BigFloat(e1, m1 + m2, x.MantissaSize, x.ExponentSize); + return new BigFloat(false, e1, m1 + m2, x.significandSize, x.ExponentSize); } [Pure] @@ -434,8 +418,8 @@ namespace Microsoft.Basetypes [Pure] public static BigFloat operator *(BigFloat x, BigFloat y) { Contract.Requires(x.ExponentSize == y.ExponentSize); - Contract.Requires(x.MantissaSize == y.MantissaSize); - return new BigFloat(x.Exponent + y.Exponent, x.Mantissa * y.Mantissa, x.MantissaSize, x.ExponentSize); + Contract.Requires(x.significandSize == y.significandSize); + return new BigFloat(x.isNeg ^ y.isNeg, x.Exponent + y.Exponent, x.significand * y.significand, x.significandSize, x.ExponentSize); } @@ -444,9 +428,9 @@ namespace Microsoft.Basetypes public bool IsSpecialType { get { - if (!IsDec) + if (value == "") return false; - return (dec_value.Equals("NaN") || dec_value.Equals("+oo") || dec_value.Equals("-oo") || dec_value.Equals("-zero")); + return (value.Equals("NaN") || value.Equals("+oo") || value.Equals("-oo") || value.Equals("-zero")); } } @@ -456,15 +440,9 @@ namespace Microsoft.Basetypes } } - public bool IsNegative { - get { - return (isDec && dec_value[0] == '-') || mantissa < 0; - } - } - public bool IsZero { get { - return Mantissa == 0 && Exponent == 0; + return significand.Equals(BigNum.ZERO) && Exponent == BigNum.ZERO; } } @@ -474,9 +452,9 @@ namespace Microsoft.Basetypes return 1; if (this.exponent < that.exponent) return -1; - if (this.Mantissa == that.Mantissa) + if (this.significand == that.significand) return 0; - return this.Mantissa > that.Mantissa ? 1 : -1; + return this.significand > that.significand ? 1 : -1; } [Pure] diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index 5fcb1cdc..bf35ccbe 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -668,17 +668,35 @@ private class BvBounds : Expr { ty = new BasicType(t, SimpleType.Real); } else if (la.kind == 98) { Get(); - if (la.kind == 9) { - Get(); - Expect(3); - int exp = Int32.Parse(t.val); - Expect(3); - int man = Int32.Parse(t.val); - ty = new FloatType(t, exp, man); - Expect(10); + if (la.kind == 3) { + Expect(3); + switch (Int32.Parse(t.val)) { + case 16: + ty = new FloatType(t, 5, 11); + break; + case 32: + ty = new FloatType(t, 8, 24); + break; + case 64: + ty = new FloatType(t, 11, 53); + break; + case 128: + ty = new FloatType(t, 15, 113); + break; + default: + SynErr(3); + break; + } + } + else { + Expect(19); + Expect(3); + int exp = Int32.Parse(t.val); + Expect(3); + int man = Int32.Parse(t.val); + ty = new FloatType(t, exp, man); + Expect(20); } - else - ty = new FloatType(t, 8, 24); } else if (la.kind == 16) { Get(); ty = new BasicType(t, SimpleType.Bool); @@ -1813,9 +1831,9 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { case 98: { Get(); x = t; - Expect(9); + Expect(19); Expression(out e); - Expect(10); + Expect(20); e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToFloat), new List { e }); break; } @@ -1887,29 +1905,45 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { /// void Float(out BigFloat n) { - //To be modified - string s = ""; try { - if (la.kind == 97) - { - //Expected format = fp (a b) || fp (a b c d) + if (la.kind == 97) { + bool negative = false; + int exp, sig; + BigNum exp_val, sig_val, value; + //Expected format = fp(sign exp_val sig_val) || fp(value) Get(); //Skip the fp token Get(); - if (t.val != "(") { throw new FormatException(); } - while (la.kind == 1 || la.kind == 3 || la.kind == 6 || la.kind == 4 || la.kind == 74 || la.kind == 75) { //Get values between the parens + if (t.val == "(") { Get(); - if (t.val == "-" || t.val == "+") //special sign case (la.kind == 74 or 75) - s += t.val; - else - s += t.val + " "; + negative = Boolean.Parse(t.val); + BvLit(out exp_val, out exp); + BvLit(out sig_val, out sig); + n = new BigFloat(negative, exp_val, sig_val, exp, sig); + } + else if (t.val == "<") { + Expect(14); + exp = Int32.Parse(t.val); + Expect(14); + sig = Int32.Parse(t.val); + int size; + BvLit(out value, out size); + if (size != exp + sig) + { + this.SemErr("The given bitvector size of " + size + "does not match the provided floating-point size of " + (exp + sig)); + n = BigFloat.ZERO(8, 24); + return; + } + n = new BigFloat(t.val, exp, sig); + } + else { + throw new FormatException(); } - Get(); - if (t.val != ")") { throw new FormatException(); } } - else SynErr(137); - - n = BigFloat.FromString(s.Trim()); + else { + n = BigFloat.ZERO(8, 24); + SynErr(137); + } } catch (FormatException) { diff --git a/Source/Provers/SMTLib/SMTLibLineariser.cs b/Source/Provers/SMTLib/SMTLibLineariser.cs index 7c3ae960..59b6b7e7 100644 --- a/Source/Provers/SMTLib/SMTLibLineariser.cs +++ b/Source/Provers/SMTLib/SMTLibLineariser.cs @@ -205,10 +205,10 @@ namespace Microsoft.Boogie.SMTLib { BigFloat lit = ((VCExprFloatLit)node).Val; if (lit.IsSpecialType) { - wr.Write("(_ " + lit.Decimal + " " + lit.ExponentSize.ToString() + " " + lit.MantissaSize.ToString() + ")"); + wr.Write("(_ " + lit.Decimal + " " + lit.ExponentSize.ToString() + " " + lit.SignificandSize.ToString() + ")"); return true; } - wr.Write("((_ to_fp " + lit.ExponentSize.ToString() + " " + lit.MantissaSize.ToString() + ") RNE "); + wr.Write("((_ to_fp " + lit.ExponentSize.ToString() + " " + lit.SignificandSize.ToString() + ") RNE "); if (lit.IsNegative) // In SMT2 "-42" is an identifier (SMT2, Sect. 3.2 "Symbols") wr.Write("(- 0.0 {0})", lit.Abs.ToDecimalString()); diff --git a/fp_documentation.txt b/fp_documentation.txt index 09e60b9a..d3fafdcb 100644 --- a/fp_documentation.txt +++ b/fp_documentation.txt @@ -10,7 +10,9 @@ Declaring Variables: The syntax for declaring a floating point variable is as follows: var name: float(exp man); Where exp is the size of the float exponent and man is the size of the float mantissa +Please note that +**REMOVE THIS SYNTAX** It is also acceptable to use the following syntax: var name: float(); This syntax assumes the float exponent to be size 8 and the mantissa to be size 24 @@ -23,10 +25,11 @@ Declares a variable called x with a exponent sized 11 and mantissa sized 53 Declaring Constants: All of the following syntax are viable for declaring a floating point constant: -float(dec) -float(exp_val man_val) -float(dec exp man) -float(exp_val man_val exp man) +**REMOVE THE FIRST OF THESE TWO SYNTAXES** +fp(dec) +fp(exp_val man_val) +fp(dec exp man) +fp(exp_val man_val exp man) Where dec is the decimal value of the constant, exp_val/man_value are the integer values of their respective fields, @@ -68,6 +71,8 @@ Where exp and man are the sizes of the exponent and mantissa respectively -------------------------------------------------------------------------------- Known Issues: +float16, float32, float64, and float128 still need to be added + There is currently no way to convert from a floating point to any other data type There is currently no way to convert the value of a variable to a floating point type @@ -76,4 +81,8 @@ var x : real; fp(x); Statements of the following form cause a parser error (parenthesis followed by fp constant) -... (fp(1) + fp(1)); \ No newline at end of file +... (fp(1) + fp(1)); + +Attempts by Boogie to infer the behavior of loops fail when floating points are involved + +Describing loop behavior manually is untested (using loop unroll appears to work) \ No newline at end of file -- cgit v1.2.3 From 51b7e8146f413b83a412572fcc9e3a1a8b302b79 Mon Sep 17 00:00:00 2001 From: Checkmate50 Date: Thu, 17 Mar 2016 13:01:10 -0600 Subject: modified floating point syntax and modified floating point constants to use bitvector values --- Source/AbsInt/IntervalDomain.cs | 6 ++-- Source/Basetypes/BigFloat.cs | 43 ++++++++++------------------- Source/BoogieDriver/BoogieDriver.cs | 2 +- Source/Core/AbsyExpr.cs | 4 +-- Source/Core/Parser.cs | 46 ++++++++++++++++++------------- Source/Provers/SMTLib/SMTLibLineariser.cs | 12 +------- Source/VCExpr/VCExprAST.cs | 2 +- float_test.bpl | 16 +++++------ 8 files changed, 57 insertions(+), 74 deletions(-) diff --git a/Source/AbsInt/IntervalDomain.cs b/Source/AbsInt/IntervalDomain.cs index 0c954f9a..d5a5efc9 100644 --- a/Source/AbsInt/IntervalDomain.cs +++ b/Source/AbsInt/IntervalDomain.cs @@ -695,10 +695,10 @@ namespace Microsoft.Boogie.AbstractInterpretation Lo = floor; Hi = ceiling; } else if (node.Val is BigFloat) { - BigInteger floor, ceiling; + BigNum floor, ceiling; ((BigFloat)node.Val).FloorCeiling(out floor, out ceiling); - Lo = floor; - Hi = ceiling; + Lo = floor.ToBigInteger; + Hi = ceiling.ToBigInteger; } else if (node.Val is bool) { if ((bool)node.Val) { // true diff --git a/Source/Basetypes/BigFloat.cs b/Source/Basetypes/BigFloat.cs index 8cde2cb9..a0ce03a5 100644 --- a/Source/Basetypes/BigFloat.cs +++ b/Source/Basetypes/BigFloat.cs @@ -129,7 +129,7 @@ namespace Microsoft.Basetypes this.exponentSize = exponentSize; this.exponent = exponent; this.significand = significand; - this.significandSize = significandSize; + this.significandSize = significandSize+1; this.isNeg = sign; this.value = ""; } @@ -141,33 +141,6 @@ namespace Microsoft.Basetypes this.significand = BigNum.ZERO; this.value = value; this.isNeg = value[0] == '-'; - //Special cases: - if (this.value.Equals("+oo") || this.value.Equals("-oo") || this.value.Equals("-zero")) - return; - if (this.value.ToLower().Equals("nan")) { - this.value = "NaN"; - return; - } - if (this.value.Equals("INF") || this.value.Equals("+INF")) - { - this.value = "+oo"; - return; - } - if (this.value.Equals("-INF")) - { - this.value = "-oo"; - return; - } - if (this.value.Equals("+zero")) - { - this.value = "0.0"; - return; - } - //End special cases - if (this.value.IndexOf('.') == -1 && this.value.IndexOf('e') == -1) - this.value += ".0"; //Assures that the decimal value is a "real" number - if (this.value.IndexOf('.') == 0) - this.value = "0" + this.value; //Assures that decimals always have a 0 in front } private BigNum maxsignificand() @@ -335,6 +308,18 @@ namespace Microsoft.Basetypes } } + public String ToBVString(){ + if (this.IsSpecialType) { + return "_ " + this.value + " " + this.exponentSize + " " + this.significandSize; + } + else if (this.Value == "") { + return "fp (_ bv" + (this.isNeg ? "1" : "0") + " 1) (_ bv" + this.exponent + " " + this.exponentSize + ") (_ bv" + this.significand + " " + this.significandSize + ")"; + } + else { + return "(_ to_fp " + this.exponentSize + " " + this.significandSize + ") (_ bv" + this.value + " " + (this.exponentSize + this.significandSize).ToString() + ")"; + } + } + [Pure] public string ToDecimalString() { Contract.Ensures(Contract.Result() != null); @@ -430,7 +415,7 @@ namespace Microsoft.Basetypes get { if (value == "") return false; - return (value.Equals("NaN") || value.Equals("+oo") || value.Equals("-oo") || value.Equals("-zero")); + return (value.Equals("NaN") || value.Equals("+oo") || value.Equals("-oo") || value.Equals("zero") || value.Equals("-zero")); } } diff --git a/Source/BoogieDriver/BoogieDriver.cs b/Source/BoogieDriver/BoogieDriver.cs index 2345cc1e..fa038803 100644 --- a/Source/BoogieDriver/BoogieDriver.cs +++ b/Source/BoogieDriver/BoogieDriver.cs @@ -90,7 +90,7 @@ namespace Microsoft.Boogie { } } ExecutionEngine.ProcessFiles(fileList); - return 0; + return 0; END: if (CommandLineOptions.Clo.XmlSink != null) { diff --git a/Source/Core/AbsyExpr.cs b/Source/Core/AbsyExpr.cs index ad537288..6b2e1201 100644 --- a/Source/Core/AbsyExpr.cs +++ b/Source/Core/AbsyExpr.cs @@ -561,7 +561,7 @@ namespace Microsoft.Boogie { { Contract.Requires(tok != null); Val = v; - Type = Type.GetFloatType(v.ExponentSize, v.MantissaSize); + Type = Type.GetFloatType(v.ExponentSize, v.SignificandSize); if (immutable) CachedHashCode = ComputeHashCode(); } @@ -639,7 +639,7 @@ namespace Microsoft.Boogie { return Type.Real; } else if (Val is BigFloat) { BigFloat temp = (BigFloat)Val; - return Type.GetFloatType(temp.ExponentSize, temp.MantissaSize); + return Type.GetFloatType(temp.ExponentSize, temp.SignificandSize); } else if (Val is BvConst) { return Type.GetBvType(((BvConst)Val).Bits); } else { diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index bf35ccbe..77100d1c 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -669,7 +669,7 @@ private class BvBounds : Expr { } else if (la.kind == 98) { Get(); if (la.kind == 3) { - Expect(3); + Get(); switch (Int32.Parse(t.val)) { case 16: ty = new FloatType(t, 5, 11); @@ -689,13 +689,14 @@ private class BvBounds : Expr { } } else { - Expect(19); + Expect(19); //< Expect(3); int exp = Int32.Parse(t.val); + Expect(12); //, Expect(3); int man = Int32.Parse(t.val); ty = new FloatType(t, exp, man); - Expect(20); + Expect(20); //> } } else if (la.kind == 16) { Get(); @@ -1909,32 +1910,39 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { { if (la.kind == 97) { bool negative = false; - int exp, sig; + int exp, sig, size; BigNum exp_val, sig_val, value; - //Expected format = fp(sign exp_val sig_val) || fp(value) - Get(); //Skip the fp token - Get(); - if (t.val == "(") { + //Expected format = float(sign exp_val sig_val) || float(value) + Get(); //Skip the float token + if (la.val == "(") { Get(); + Expect(16); //bool negative = Boolean.Parse(t.val); + Expect(12); //, BvLit(out exp_val, out exp); + Expect(12); BvLit(out sig_val, out sig); n = new BigFloat(negative, exp_val, sig_val, exp, sig); + Expect(10); //) } - else if (t.val == "<") { - Expect(14); + else if (la.val == "<") { + Get(); + Expect(3); exp = Int32.Parse(t.val); - Expect(14); + Expect(12); + Expect(3); sig = Int32.Parse(t.val); - int size; - BvLit(out value, out size); - if (size != exp + sig) - { - this.SemErr("The given bitvector size of " + size + "does not match the provided floating-point size of " + (exp + sig)); - n = BigFloat.ZERO(8, 24); - return; + Expect(20); //> + Expect(9); //( + if (la.kind == 4) { + Get(); + n = new BigFloat(t.val, exp, sig); + } + else { + BvLit(out value, out size); + n = new BigFloat(value.ToString(), exp, sig); } - n = new BigFloat(t.val, exp, sig); + Expect(10); //) } else { throw new FormatException(); diff --git a/Source/Provers/SMTLib/SMTLibLineariser.cs b/Source/Provers/SMTLib/SMTLibLineariser.cs index 59b6b7e7..96d5b290 100644 --- a/Source/Provers/SMTLib/SMTLibLineariser.cs +++ b/Source/Provers/SMTLib/SMTLibLineariser.cs @@ -204,17 +204,7 @@ namespace Microsoft.Boogie.SMTLib else if (node is VCExprFloatLit) { BigFloat lit = ((VCExprFloatLit)node).Val; - if (lit.IsSpecialType) { - wr.Write("(_ " + lit.Decimal + " " + lit.ExponentSize.ToString() + " " + lit.SignificandSize.ToString() + ")"); - return true; - } - wr.Write("((_ to_fp " + lit.ExponentSize.ToString() + " " + lit.SignificandSize.ToString() + ") RNE "); - if (lit.IsNegative) - // In SMT2 "-42" is an identifier (SMT2, Sect. 3.2 "Symbols") - wr.Write("(- 0.0 {0})", lit.Abs.ToDecimalString()); - else - wr.Write(lit.ToDecimalString()); - wr.Write(")"); + wr.Write("(" + lit.ToBVString() + ")"); } else { Contract.Assert(false); diff --git a/Source/VCExpr/VCExprAST.cs b/Source/VCExpr/VCExprAST.cs index 3f6e3b7a..b22853ce 100644 --- a/Source/VCExpr/VCExprAST.cs +++ b/Source/VCExpr/VCExprAST.cs @@ -887,7 +887,7 @@ namespace Microsoft.Boogie.VCExprAST { { public readonly BigFloat Val; internal VCExprFloatLit(BigFloat val) - : base(Type.GetFloatType(val.ExponentSize, val.MantissaSize)) + : base(Type.GetFloatType(val.ExponentSize, val.SignificandSize)) { this.Val = val; } diff --git a/float_test.bpl b/float_test.bpl index fbf8e4e3..e893e098 100644 --- a/float_test.bpl +++ b/float_test.bpl @@ -1,13 +1,13 @@ //Translation from addsub_double_exact.c //Should Verify procedure main() returns () { - var x : float(11 53); - var y : float(11 53); - var z : float(11 53); - var r : float(11 53); - x := fp(10000000 11 53); - y := x + fp(1 11 53); - z := x - fp(1 11 53); + var x : float<11, 53>; + var y : float<11, 53>; + var z : float<11, 53>; + var r : float<11, 53>; + x := fp<11, 53> (10000000bv64); + y := x + fp<11, 53>(1bv64); + z := x - fp<11, 53>(1bv64); r := y - z; - assert r == fp(2 11 53); + assert r == fp<11, 53> (2bv64); } \ No newline at end of file -- cgit v1.2.3 From 6f7fc01346c0ebe9072e61ace2cfede4fcedea09 Mon Sep 17 00:00:00 2001 From: Checkmate50 Date: Tue, 31 May 2016 12:08:07 -0600 Subject: Initial round of testing works with new syntax. Fixed an error where floating points could not be given as a function argument --- Source/Core/Parser.cs | 27 ++++++++++++------------ Source/Core/Scanner.cs | 2 +- float_test11.bpl | 57 ++++++++++++++++++++++++++++++++------------------ float_test13.bpl | 16 +++++++------- float_test14.bpl | 19 ++++++++++------- float_test2.bpl | 20 +++++++++++------- float_test3.bpl | 16 +++++++------- float_test4.bpl | 38 +++++++++++++++++++++------------ float_test5.bpl | 13 +++++++----- float_test8.bpl | 16 ++++++++------ 10 files changed, 134 insertions(+), 90 deletions(-) diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index 77100d1c..8161544f 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -668,9 +668,8 @@ private class BvBounds : Expr { ty = new BasicType(t, SimpleType.Real); } else if (la.kind == 98) { Get(); - if (la.kind == 3) { - Get(); - switch (Int32.Parse(t.val)) { + if (t.val.Length > 5) { + switch (Int32.Parse(t.val.Substring(5))) { case 16: ty = new FloatType(t, 5, 11); break; @@ -690,10 +689,10 @@ private class BvBounds : Expr { } else { Expect(19); //< - Expect(3); + Expect(3); //int int exp = Int32.Parse(t.val); Expect(12); //, - Expect(3); + Expect(3); //int int man = Int32.Parse(t.val); ty = new FloatType(t, exp, man); Expect(20); //> @@ -1830,14 +1829,14 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { break; } case 98: { - Get(); - x = t; - Expect(19); - Expression(out e); - Expect(20); - e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToFloat), new List { e }); - break; - } + Get(); + x = t; + Expect(19); + Expression(out e); + Expect(20); + e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToFloat), new List { e }); + break; + } case 9: { Get(); if (StartOf(9)) { @@ -2188,7 +2187,7 @@ out QKeyValue kv, out Trigger trig, out Expr/*!*/ body) { static readonly bool[,]/*!*/ set = { //grid is 17 x 100 {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,T, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,T,x,x, x,T,T,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, x,x,x,x, x,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,T,x,x, x,x,T,T, T,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,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,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,T,x,x, x,x,T,T, T,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,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,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,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,T, 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,x,x,x, x,x,x,x}, {x,x,x,x, x,x,x,x, x,T,x,x, x,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, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,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}, diff --git a/Source/Core/Scanner.cs b/Source/Core/Scanner.cs index bc294aba..ca7db1e1 100644 --- a/Source/Core/Scanner.cs +++ b/Source/Core/Scanner.cs @@ -509,7 +509,7 @@ public class Scanner { case "real": t.kind = 15; break; case "bool": t.kind = 16; break; case "fp": t.kind = 97; break; - case "float": t.kind = 98; break; + case "float": case "float16": case "float32": case "float64": case "float128": t.kind = 98; break; case "const": t.kind = 21; break; case "unique": t.kind = 22; break; case "extends": t.kind = 23; break; diff --git a/float_test11.bpl b/float_test11.bpl index cf9fd3a2..cee3e36e 100644 --- a/float_test11.bpl +++ b/float_test11.bpl @@ -1,38 +1,55 @@ //Translation from interpolation.c //Should Verify -//Returns inconclusize? What does that mean? +//Returns inconclusive? What does that mean? +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); procedure main() returns () { var i : int; - var z : float; - var t : float; - var min : [int] float; - var max : [int] float; + var z : float32; + var t : float32; + var min : [int] float32; + var max : [int] float32; - min[0] := fp(5); - min[1] := fp(10); - min[2] := fp(12); - min[3] := fp(30); - min[4] := fp(150); + min[0] := TO_FLOAT32_INT(5); + min[1] := TO_FLOAT32_INT(10); + min[2] := TO_FLOAT32_INT(12); + min[3] := TO_FLOAT32_INT(30); + min[4] := TO_FLOAT32_INT(150); - max[0] := fp(10); - max[1] := fp(12); - max[2] := fp(30); - max[3] := fp(150); - max[4] := fp(300); + max[0] := TO_FLOAT32_INT(10); + max[1] := TO_FLOAT32_INT(12); + max[2] := TO_FLOAT32_INT(30); + max[3] := TO_FLOAT32_INT(150); + max[4] := TO_FLOAT32_INT(300); havoc t; assume(t >= min[0] && t <= max[4]); i := 0; - while (i < 5) { - if (t <= max[i]) { - break; - } + //while (i < 5) { + //if (t <= max[i]) { + //break; + //} + //i := i + 1; + //} + + if (t > max[0]) { //1 + i := i + 1; + } + if (t > max[1]) { //2 + i := i + 1; + } + if (t > max[2]) { //3 + i := i + 1; + } + if (t > max[3]) { //4 + i := i + 1; + } + if (t > max[4]) { //5 i := i + 1; } z := (t - min[i]) / (max[i] - min[i]); - assert(z >= fp(0) && z <= fp(1)); + assert(z >= TO_FLOAT32_INT(0) && z <= TO_FLOAT32_INT(1)); } \ No newline at end of file diff --git a/float_test13.bpl b/float_test13.bpl index d073836d..e5402539 100644 --- a/float_test13.bpl +++ b/float_test13.bpl @@ -1,17 +1,19 @@ //Translation from inv_square_false-unreach-call.c //Should return an error (without crashing) +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); + procedure main() returns () { - var x : float; - var y : float; - var z : float; + var x : float32; + var y : float32; + var z : float32; havoc x; - assume(x >= fp(-1) && x <= fp(1)); + assume(x >= TO_FLOAT32_INT(-1) && x <= TO_FLOAT32_INT(1)); - if (x != fp(0)) { + if (x != TO_FLOAT32_INT(0)) { y := x * x; - assert(y != fp(0)); - z := fp(1) / y; + assert(y != TO_FLOAT32_INT(0)); + z := TO_FLOAT32_INT(1) / y; } } \ No newline at end of file diff --git a/float_test14.bpl b/float_test14.bpl index 9b5dab0a..1505c361 100644 --- a/float_test14.bpl +++ b/float_test14.bpl @@ -1,17 +1,20 @@ -//Translation from inv_square_false-unreach-call.c +//Translation from inv_square_true-unreach-call.c //Should Verify +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_REAL(real) returns (float32); + procedure main() returns () { - var x : float; - var y : float; - var z : float; + var x : float32; + var y : float32; + var z : float32; havoc x; - assume(x >= fp(-1) && x <= fp(1)); + assume(x >= TO_FLOAT32_INT(-1) && x <= TO_FLOAT32_INT(1)); - if (x <= fp(-.00000000000000000001) || x >= fp(.00000000000000000001)) { + if (x <= TO_FLOAT32_REAL(-1e-20) || x >= TO_FLOAT32_REAL(1e-20)) { y := x * x; - assert(y != fp(0)); - z := fp(1) / y; + assert(y != TO_FLOAT32_INT(0)); + z := TO_FLOAT32_INT(1) / y; } } \ No newline at end of file diff --git a/float_test2.bpl b/float_test2.bpl index da74909b..d78c339d 100644 --- a/float_test2.bpl +++ b/float_test2.bpl @@ -1,13 +1,17 @@ //Translation from addsub_float_exact.c //Should Verify + +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_REAL(real) returns (float32); + procedure main() returns () { - var x : float; - var y : float; - var z : float; - var r : float; - x := fp(1000000); - y := x + fp(1); - z := x - fp(1); + var x : float32; + var y : float32; + var z : float32; + var r : float32; + x := TO_FLOAT32_REAL(1e7); + y := x + TO_FLOAT32_INT(1); + z := x - TO_FLOAT32_INT(1); r := y - z; - assert r == fp(2); + assert r == TO_FLOAT32_INT(2); } \ No newline at end of file diff --git a/float_test3.bpl b/float_test3.bpl index dd0c1ba4..67c6ba48 100644 --- a/float_test3.bpl +++ b/float_test3.bpl @@ -1,13 +1,13 @@ //Translation from addsub_float_inexact.c //Should give an error procedure main() returns () { - var x : float; - var y : float; - var z : float; - var r : float; - x := fp(10000000); - y := x + fp(1); - z := x - fp(1); + var x : float32; + var y : float32; + var z : float32; + var r : float32; + x := fp<8, 24>(3221225472bv32); + y := x + fp<8, 24>(1bv32); + z := x - fp<8, 24>(1bv32); r := y - z; - assert r == fp(0); + assert r == fp<8, 24>(2bv32); } \ No newline at end of file diff --git a/float_test4.bpl b/float_test4.bpl index a7aa8c4b..a31aa215 100644 --- a/float_test4.bpl +++ b/float_test4.bpl @@ -1,20 +1,32 @@ //Translation from drift_tenth.c -//Should Verify -//FAILS; note that it succeeds when tick == fp(.1) +//Should Fail + +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_REAL(real) returns (float32); procedure main() returns () { - var tick : float; - var time : float; + var tick : float32; + var time : float32; var i: int; - tick := fp(1)/fp(10); - time := fp(0); + tick := TO_FLOAT32_INT(1)/TO_FLOAT32_INT(10); + time := TO_FLOAT32_INT(0); - i := 0; - while (i < 10) - { - time := time + tick; - i := i + 1; - } - assert(time == fp(1)); + //i := 0; + //while (i < 10) + //{ + // time := time + tick; + // i := i + 1; + //} + time := time + tick;//1 + time := time + tick;//2 + time := time + tick;//3 + time := time + tick;//4 + time := time + tick;//5 + time := time + tick;//6 + time := time + tick;//7 + time := time + tick;//8 + time := time + tick;//9 + time := time + tick;//10 + assert time == TO_FLOAT32_INT(1); } \ No newline at end of file diff --git a/float_test5.bpl b/float_test5.bpl index ce5d2bc7..7536f8fd 100644 --- a/float_test5.bpl +++ b/float_test5.bpl @@ -1,15 +1,18 @@ //Translation from filter1.c //Should Verify +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_INT(int) returns (float64); +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_REAL(real) returns (float64); + procedure main() returns () { - var E0 : float(11 53); - var E1 : float(11 53); - var S : float(11 53); + var E0 : float64; + var E1 : float64; + var S : float64); var i : int; var rand : int; - E1 := fp(0 11 53); - S := fp(0 11 53); + E1 := TO_FLOAT64_INT(0); + S := TO_FLOAT64_INT(0); i := 0; while (i <= 1000000) diff --git a/float_test8.bpl b/float_test8.bpl index 995ed4fa..7e78e206 100644 --- a/float_test8.bpl +++ b/float_test8.bpl @@ -1,12 +1,16 @@ //Translation from float_double.c //Should Verify -//FAILS: I don't have this functionality yet... + +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_FLOAT32(float32) returns (float64); +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_FLOAT64(float64) returns (float32); +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_INT(int) returns (float64); +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_REAL(real) returns (float64); procedure main() returns () { - var x : float(11 53); - var y : float; + var x : float64; + var y : float32; - x := fp(100000000000000000001 11 53); - y := x; - assert(x != y); + x := TO_FLOAT64_REAL(1e20)+TO_FLOAT64_INT(1); + y := TO_FLOAT32_FLOAT64(x); + assert x != TO_FLOAT64_FLOAT32(y); } \ No newline at end of file -- cgit v1.2.3 From c19c2495497d0dfa7aaf871cf833cd5e5f986d33 Mon Sep 17 00:00:00 2001 From: Checkmate50 Date: Tue, 31 May 2016 12:59:38 -0600 Subject: moved all the tests to the testing folder --- Test/floats/test1.bpl | 13 ++++++++++++ Test/floats/test10.bpl | 20 ++++++++++++++++++ Test/floats/test11.bpl | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++ Test/floats/test12.bpl | 43 +++++++++++++++++++++++++++++++++++++++ Test/floats/test13.bpl | 19 +++++++++++++++++ Test/floats/test14.bpl | 20 ++++++++++++++++++ Test/floats/test15.bpl | 24 ++++++++++++++++++++++ Test/floats/test16.bpl | 8 ++++++++ Test/floats/test17.bpl | 11 ++++++++++ Test/floats/test18.bpl | 36 +++++++++++++++++++++++++++++++++ Test/floats/test19.bpl | 36 +++++++++++++++++++++++++++++++++ Test/floats/test2.bpl | 17 ++++++++++++++++ Test/floats/test20.bpl | 14 +++++++++++++ Test/floats/test3.bpl | 13 ++++++++++++ Test/floats/test4.bpl | 32 +++++++++++++++++++++++++++++ Test/floats/test5.bpl | 36 +++++++++++++++++++++++++++++++++ Test/floats/test6.bpl | 40 ++++++++++++++++++++++++++++++++++++ Test/floats/test7.bpl | 38 ++++++++++++++++++++++++++++++++++ Test/floats/test8.bpl | 16 +++++++++++++++ Test/floats/test9.bpl | 34 +++++++++++++++++++++++++++++++ float_test.bpl | 13 ------------ float_test10.bpl | 20 ------------------ float_test11.bpl | 55 -------------------------------------------------- float_test12.bpl | 43 --------------------------------------- float_test13.bpl | 19 ----------------- float_test14.bpl | 20 ------------------ float_test15.bpl | 24 ---------------------- float_test16.bpl | 8 -------- float_test17.bpl | 11 ---------- float_test18.bpl | 36 --------------------------------- float_test19.bpl | 36 --------------------------------- float_test2.bpl | 17 ---------------- float_test20.bpl | 14 ------------- float_test3.bpl | 13 ------------ float_test4.bpl | 32 ----------------------------- float_test5.bpl | 36 --------------------------------- float_test6.bpl | 40 ------------------------------------ float_test7.bpl | 38 ---------------------------------- float_test8.bpl | 16 --------------- float_test9.bpl | 34 ------------------------------- 40 files changed, 525 insertions(+), 525 deletions(-) create mode 100644 Test/floats/test1.bpl create mode 100644 Test/floats/test10.bpl create mode 100644 Test/floats/test11.bpl create mode 100644 Test/floats/test12.bpl create mode 100644 Test/floats/test13.bpl create mode 100644 Test/floats/test14.bpl create mode 100644 Test/floats/test15.bpl create mode 100644 Test/floats/test16.bpl create mode 100644 Test/floats/test17.bpl create mode 100644 Test/floats/test18.bpl create mode 100644 Test/floats/test19.bpl create mode 100644 Test/floats/test2.bpl create mode 100644 Test/floats/test20.bpl create mode 100644 Test/floats/test3.bpl create mode 100644 Test/floats/test4.bpl create mode 100644 Test/floats/test5.bpl create mode 100644 Test/floats/test6.bpl create mode 100644 Test/floats/test7.bpl create mode 100644 Test/floats/test8.bpl create mode 100644 Test/floats/test9.bpl delete mode 100644 float_test.bpl delete mode 100644 float_test10.bpl delete mode 100644 float_test11.bpl delete mode 100644 float_test12.bpl delete mode 100644 float_test13.bpl delete mode 100644 float_test14.bpl delete mode 100644 float_test15.bpl delete mode 100644 float_test16.bpl delete mode 100644 float_test17.bpl delete mode 100644 float_test18.bpl delete mode 100644 float_test19.bpl delete mode 100644 float_test2.bpl delete mode 100644 float_test20.bpl delete mode 100644 float_test3.bpl delete mode 100644 float_test4.bpl delete mode 100644 float_test5.bpl delete mode 100644 float_test6.bpl delete mode 100644 float_test7.bpl delete mode 100644 float_test8.bpl delete mode 100644 float_test9.bpl diff --git a/Test/floats/test1.bpl b/Test/floats/test1.bpl new file mode 100644 index 00000000..e893e098 --- /dev/null +++ b/Test/floats/test1.bpl @@ -0,0 +1,13 @@ +//Translation from addsub_double_exact.c +//Should Verify +procedure main() returns () { + var x : float<11, 53>; + var y : float<11, 53>; + var z : float<11, 53>; + var r : float<11, 53>; + x := fp<11, 53> (10000000bv64); + y := x + fp<11, 53>(1bv64); + z := x - fp<11, 53>(1bv64); + r := y - z; + assert r == fp<11, 53> (2bv64); +} \ No newline at end of file diff --git a/Test/floats/test10.bpl b/Test/floats/test10.bpl new file mode 100644 index 00000000..566f7a56 --- /dev/null +++ b/Test/floats/test10.bpl @@ -0,0 +1,20 @@ +//Translation from loop.c +//Should return an error? (The real case does as well...) + +procedure main() returns () { + var x : float; + var y : float; + var z : float; + + x := fp(1); + y := fp(10000000); + z := fp(42); + + while (x < y) { + x := x + fp(1); + y := y - fp(1); + z := z + fp(1); + } + + assert(z >= fp(0) && z <= fp(10000000)); +} \ No newline at end of file diff --git a/Test/floats/test11.bpl b/Test/floats/test11.bpl new file mode 100644 index 00000000..cee3e36e --- /dev/null +++ b/Test/floats/test11.bpl @@ -0,0 +1,55 @@ +//Translation from interpolation.c +//Should Verify +//Returns inconclusive? What does that mean? + +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); +procedure main() returns () { + var i : int; + var z : float32; + var t : float32; + var min : [int] float32; + var max : [int] float32; + + min[0] := TO_FLOAT32_INT(5); + min[1] := TO_FLOAT32_INT(10); + min[2] := TO_FLOAT32_INT(12); + min[3] := TO_FLOAT32_INT(30); + min[4] := TO_FLOAT32_INT(150); + + max[0] := TO_FLOAT32_INT(10); + max[1] := TO_FLOAT32_INT(12); + max[2] := TO_FLOAT32_INT(30); + max[3] := TO_FLOAT32_INT(150); + max[4] := TO_FLOAT32_INT(300); + + havoc t; + assume(t >= min[0] && t <= max[4]); + + i := 0; + //while (i < 5) { + //if (t <= max[i]) { + //break; + //} + //i := i + 1; + //} + + if (t > max[0]) { //1 + i := i + 1; + } + if (t > max[1]) { //2 + i := i + 1; + } + if (t > max[2]) { //3 + i := i + 1; + } + if (t > max[3]) { //4 + i := i + 1; + } + if (t > max[4]) { //5 + i := i + 1; + } + + z := (t - min[i]) / (max[i] - min[i]); + + assert(z >= TO_FLOAT32_INT(0) && z <= TO_FLOAT32_INT(1)); +} \ No newline at end of file diff --git a/Test/floats/test12.bpl b/Test/floats/test12.bpl new file mode 100644 index 00000000..c733b9f4 --- /dev/null +++ b/Test/floats/test12.bpl @@ -0,0 +1,43 @@ +//Translation from inv_Newton.c +//Should Verify +//Unfinished code! + +procedure inv(float(11 53)) returns(float(11 53)) { + var z : float(11 53); + var t : float(11 53); + var t : float(11 53); + + +} + +procedure main() returns () { + var t : float(11 53); + var t : float(11 53); + + min[0] := fp(5); + min[1] := fp(10); + min[2] := fp(12); + min[3] := fp(30); + min[4] := fp(150); + + max[0] := fp(10); + max[1] := fp(12); + max[2] := fp(30); + max[3] := fp(150); + max[4] := fp(300); + + havoc t; + assume(t >= min[0] && t <= max[4]); + + i := 0; + while (i < 5) { + if (t <= max[i]) { + break; + } + i := i + 1; + } + + z := (t - min[i]) / (max[i] - min[i]); + + assert(z >= fp(0) && z <= fp(1)); +} \ No newline at end of file diff --git a/Test/floats/test13.bpl b/Test/floats/test13.bpl new file mode 100644 index 00000000..e5402539 --- /dev/null +++ b/Test/floats/test13.bpl @@ -0,0 +1,19 @@ +//Translation from inv_square_false-unreach-call.c +//Should return an error (without crashing) + +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); + +procedure main() returns () { + var x : float32; + var y : float32; + var z : float32; + + havoc x; + assume(x >= TO_FLOAT32_INT(-1) && x <= TO_FLOAT32_INT(1)); + + if (x != TO_FLOAT32_INT(0)) { + y := x * x; + assert(y != TO_FLOAT32_INT(0)); + z := TO_FLOAT32_INT(1) / y; + } +} \ No newline at end of file diff --git a/Test/floats/test14.bpl b/Test/floats/test14.bpl new file mode 100644 index 00000000..1505c361 --- /dev/null +++ b/Test/floats/test14.bpl @@ -0,0 +1,20 @@ +//Translation from inv_square_true-unreach-call.c +//Should Verify + +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_REAL(real) returns (float32); + +procedure main() returns () { + var x : float32; + var y : float32; + var z : float32; + + havoc x; + assume(x >= TO_FLOAT32_INT(-1) && x <= TO_FLOAT32_INT(1)); + + if (x <= TO_FLOAT32_REAL(-1e-20) || x >= TO_FLOAT32_REAL(1e-20)) { + y := x * x; + assert(y != TO_FLOAT32_INT(0)); + z := TO_FLOAT32_INT(1) / y; + } +} \ No newline at end of file diff --git a/Test/floats/test15.bpl b/Test/floats/test15.bpl new file mode 100644 index 00000000..1dc549ac --- /dev/null +++ b/Test/floats/test15.bpl @@ -0,0 +1,24 @@ +//Translation from Muller_Kahan.c +//Should Verify +//NOTE: (fp(....)) causes a compiler error! +//FAILS! Heavily... + +procedure main() returns () { + var x0 : float(11 53); + var x1 : float(11 53); + var x2 : float(11 53); + var i : int; + + x0 := fp(11 11 53) / fp(2 11 53); + x1 := fp(61 11 53) / fp(11 11 53); + i := 0; + while (i < 100) { + x2 := fp(1130 11 53) - fp(3000 11 53) / x0; + x2 := fp(111 11 53) - x2 / x1; + x0 := x1; + x1 := x2; + i := i + 1; + } + + assert(x0 >= fp(99 11 53) && x0 <= fp(101 11 53)); +} \ No newline at end of file diff --git a/Test/floats/test16.bpl b/Test/floats/test16.bpl new file mode 100644 index 00000000..69ae243d --- /dev/null +++ b/Test/floats/test16.bpl @@ -0,0 +1,8 @@ +//Translation from nan_double_false-unreach-call.c +//Should return an error + +procedure main() returns () { + var x : float(11 53); + havoc x; + assert(x==x); +} \ No newline at end of file diff --git a/Test/floats/test17.bpl b/Test/floats/test17.bpl new file mode 100644 index 00000000..caa1fa74 --- /dev/null +++ b/Test/floats/test17.bpl @@ -0,0 +1,11 @@ +//Translation from nan_double_range_true-unreach-call.c +//Should verify +//Uggghhhh, should I add support for e? + +procedure main() returns () { + var x : float(11 53); + havoc x; + if (x >= fp(-100000000000000000000000000 11 53) && x <= fp(100000000000000000000000000 11 53)) { + assert(x==x); + } +} \ No newline at end of file diff --git a/Test/floats/test18.bpl b/Test/floats/test18.bpl new file mode 100644 index 00000000..71eb5286 --- /dev/null +++ b/Test/floats/test18.bpl @@ -0,0 +1,36 @@ +//Translation from rlim_exit.c +//Should verify +//Unary - unsupported float operations (on my end)... + +procedure main() returns () { + var X : float; + var Y : float; + var S : float; + var R : float; + var D : float; + var i : int; + + Y := fp(0); + + i := 0; + while (i < 100000) { + havoc X; + havoc D; + assume(X >= fp(-128) && X <= fp(128)); + assume(D >= fp(0) && D <= fp(16)); + + S := Y; + Y := X; + R := X - S; + if (R <= fp(0)-D) { + Y := S - D; + } + else if(R >= D) { + Y := S + D; + } + + i := i + 1; + } + + assert(Y >= fp(-129) && Y <= fp(129)); +} \ No newline at end of file diff --git a/Test/floats/test19.bpl b/Test/floats/test19.bpl new file mode 100644 index 00000000..f00d8a2b --- /dev/null +++ b/Test/floats/test19.bpl @@ -0,0 +1,36 @@ +//Translation from flim_invariant.c +//Should verify +//Unary - unsupported float operations (on my end)... + +procedure main() returns () { + var X : float; + var Y : float; + var S : float; + var R : float; + var D : float; + var i : int; + + Y := fp(0); + + i := 0; + while (i < 100000) { + havoc X; + havoc D; + assume(X >= fp(-128) && X <= fp(128)); + assume(D >= fp(0) && D <= fp(16)); + + S := Y; + Y := X; + R := X - S; + if (R <= fp(0)-D) { + Y := S - D; + } + else if(R >= D) { + Y := S + D; + } + + assert(Y >= fp(-129) && Y <= fp(129)); + + i := i + 1; + } +} \ No newline at end of file diff --git a/Test/floats/test2.bpl b/Test/floats/test2.bpl new file mode 100644 index 00000000..d78c339d --- /dev/null +++ b/Test/floats/test2.bpl @@ -0,0 +1,17 @@ +//Translation from addsub_float_exact.c +//Should Verify + +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_REAL(real) returns (float32); + +procedure main() returns () { + var x : float32; + var y : float32; + var z : float32; + var r : float32; + x := TO_FLOAT32_REAL(1e7); + y := x + TO_FLOAT32_INT(1); + z := x - TO_FLOAT32_INT(1); + r := y - z; + assert r == TO_FLOAT32_INT(2); +} \ No newline at end of file diff --git a/Test/floats/test20.bpl b/Test/floats/test20.bpl new file mode 100644 index 00000000..57c605fd --- /dev/null +++ b/Test/floats/test20.bpl @@ -0,0 +1,14 @@ +//Should return an error? +//Translation from Rump_double.c + +procedure main() returns () { + var x : float(11 53); + var y : float(11 53); + var r : float(11 53); + + x := fp(77617 11 53); + y := fp(33096 11 53); + r := y*y*y*y*y*y * fp(333.75 11 53) + x*x * (x*x*y*y*fp(11 11 53) - y*y*y*y*y*y - y*y*y*y * fp(121 11 53) - fp(2 11 53)) + y*y*y*y*y*y*y*y * fp(5.5 11 53) + x / (y*fp(2 11 53)); + + assert(r >= fp(0 11 53)); +} \ No newline at end of file diff --git a/Test/floats/test3.bpl b/Test/floats/test3.bpl new file mode 100644 index 00000000..67c6ba48 --- /dev/null +++ b/Test/floats/test3.bpl @@ -0,0 +1,13 @@ +//Translation from addsub_float_inexact.c +//Should give an error +procedure main() returns () { + var x : float32; + var y : float32; + var z : float32; + var r : float32; + x := fp<8, 24>(3221225472bv32); + y := x + fp<8, 24>(1bv32); + z := x - fp<8, 24>(1bv32); + r := y - z; + assert r == fp<8, 24>(2bv32); +} \ No newline at end of file diff --git a/Test/floats/test4.bpl b/Test/floats/test4.bpl new file mode 100644 index 00000000..a31aa215 --- /dev/null +++ b/Test/floats/test4.bpl @@ -0,0 +1,32 @@ +//Translation from drift_tenth.c +//Should Fail + +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_REAL(real) returns (float32); + +procedure main() returns () { + var tick : float32; + var time : float32; + var i: int; + + tick := TO_FLOAT32_INT(1)/TO_FLOAT32_INT(10); + time := TO_FLOAT32_INT(0); + + //i := 0; + //while (i < 10) + //{ + // time := time + tick; + // i := i + 1; + //} + time := time + tick;//1 + time := time + tick;//2 + time := time + tick;//3 + time := time + tick;//4 + time := time + tick;//5 + time := time + tick;//6 + time := time + tick;//7 + time := time + tick;//8 + time := time + tick;//9 + time := time + tick;//10 + assert time == TO_FLOAT32_INT(1); +} \ No newline at end of file diff --git a/Test/floats/test5.bpl b/Test/floats/test5.bpl new file mode 100644 index 00000000..7536f8fd --- /dev/null +++ b/Test/floats/test5.bpl @@ -0,0 +1,36 @@ +//Translation from filter1.c +//Should Verify + +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_INT(int) returns (float64); +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_REAL(real) returns (float64); + +procedure main() returns () { + var E0 : float64; + var E1 : float64; + var S : float64); + var i : int; + var rand : int; + + E1 := TO_FLOAT64_INT(0); + S := TO_FLOAT64_INT(0); + + i := 0; + while (i <= 1000000) + { + havoc E0; + assume(E0 >= fp(-1 11 53) && E0 <= fp(1 11 53)); + + havoc rand; + if (rand != 0) { + S := fp(0 11 53); + } + else { + S := fp(0.999 11 53) * S + E0 - E1; + } + E1 := E0; + + //assert(1==0); + assert(S >= fp(-1 11 53) && S <= fp(1 11 53)); + i := i + 1; + } +} \ No newline at end of file diff --git a/Test/floats/test6.bpl b/Test/floats/test6.bpl new file mode 100644 index 00000000..6bef1137 --- /dev/null +++ b/Test/floats/test6.bpl @@ -0,0 +1,40 @@ +//Translation from filter2.c +//Should give an error +//FAILS; doesn't generate terms! + +procedure main() returns () { + var E : float(11 53); + var E0 : float(11 53); + var E1 : float(11 53); + var S : float(11 53); + var S0 : float(11 53); + var S1 : float(11 53); + var i: int; + + havoc E; + havoc E0; + assume(E >= fp(0.0 11 53) && E <= fp(1.0 11 53)); + assume(E0 >= fp(0.0 11 53) && E0 <= fp(1.0 11 53)); + + E1 := fp(0.0 11 53); + S1 := fp(0.0 11 53); + S0 := fp(0.0 11 53); + S := fp(0.0 11 53); + + i := 0; +// while (i <= 1000000) +// { + E1 := E0; + E0 := E; + + havoc E; + assume(E >= fp(0.0 11 53) && E <= fp(1.0 11 53)); + + S1 := S0; + S0 := S; + S := E*fp(0.7 11 53) - E0*fp(1.3 11 53) + E1*fp(1.1 11 53) + S0*fp(1.4 11 53) - S1*fp(0.7 11 53); + + assert(S >= fp(-4.0 11 53) && S <= fp(4.0 11 53)); + //i := i + 1; +// } +} \ No newline at end of file diff --git a/Test/floats/test7.bpl b/Test/floats/test7.bpl new file mode 100644 index 00000000..8e07878d --- /dev/null +++ b/Test/floats/test7.bpl @@ -0,0 +1,38 @@ +//Translation from filter2.c +//Should give an error +//Same as the previous one; it works with reals! + +procedure main() returns () { + var E : real; + var E0 : real; + var E1 : real; + var S : real; + var S0 : real; + var S1 : real; + var i: int; + + havoc E; + havoc E0; + assume(E >= 0.0 && E <= 1.0); + assume(E0 >= 0.0 && E0 <= 1.0); + + S0 := 0.0; + S := 0.0; + + i := 0; + while (i <= 1000000) + { + E1 := E0; + E0 := E; + + havoc E; + assume(E >= 0.0 && E <= 1.0); + + S1 := S0; + S0 := S; + S := E*0.7 - E0*1.3 + E1*1.1 + S0*1.4 - S1*0.7; + + assert(S >= -4.0 && S <= 4.0); + i := i + 1; + } +} \ No newline at end of file diff --git a/Test/floats/test8.bpl b/Test/floats/test8.bpl new file mode 100644 index 00000000..7e78e206 --- /dev/null +++ b/Test/floats/test8.bpl @@ -0,0 +1,16 @@ +//Translation from float_double.c +//Should Verify + +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_FLOAT32(float32) returns (float64); +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_FLOAT64(float64) returns (float32); +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_INT(int) returns (float64); +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_REAL(real) returns (float64); + +procedure main() returns () { + var x : float64; + var y : float32; + + x := TO_FLOAT64_REAL(1e20)+TO_FLOAT64_INT(1); + y := TO_FLOAT32_FLOAT64(x); + assert x != TO_FLOAT64_FLOAT32(y); +} \ No newline at end of file diff --git a/Test/floats/test9.bpl b/Test/floats/test9.bpl new file mode 100644 index 00000000..c3a42e6b --- /dev/null +++ b/Test/floats/test9.bpl @@ -0,0 +1,34 @@ +//Translation from feedback_diverge.c +//Should give an error +//Not sure on this one... + +procedure main() returns () { + var A : float; + var B : float; + var X : float; + var i : int; + var rand : int; + + A := fp(0); + B := fp(0); + + i := 0; + while (i < 3600000) { + + havoc rand; + if (rand != 0) { + havoc X; + assume(X >= fp(-20) && X <= fp(20)); + } + else { + X := B; + } + + B := B - (B * fp(2.0) - A - X) * fp(.005); + A := X; + + i := i + 1; + } + + assert(A >= fp(-100) && A <= fp(100)); +} \ No newline at end of file diff --git a/float_test.bpl b/float_test.bpl deleted file mode 100644 index e893e098..00000000 --- a/float_test.bpl +++ /dev/null @@ -1,13 +0,0 @@ -//Translation from addsub_double_exact.c -//Should Verify -procedure main() returns () { - var x : float<11, 53>; - var y : float<11, 53>; - var z : float<11, 53>; - var r : float<11, 53>; - x := fp<11, 53> (10000000bv64); - y := x + fp<11, 53>(1bv64); - z := x - fp<11, 53>(1bv64); - r := y - z; - assert r == fp<11, 53> (2bv64); -} \ No newline at end of file diff --git a/float_test10.bpl b/float_test10.bpl deleted file mode 100644 index 566f7a56..00000000 --- a/float_test10.bpl +++ /dev/null @@ -1,20 +0,0 @@ -//Translation from loop.c -//Should return an error? (The real case does as well...) - -procedure main() returns () { - var x : float; - var y : float; - var z : float; - - x := fp(1); - y := fp(10000000); - z := fp(42); - - while (x < y) { - x := x + fp(1); - y := y - fp(1); - z := z + fp(1); - } - - assert(z >= fp(0) && z <= fp(10000000)); -} \ No newline at end of file diff --git a/float_test11.bpl b/float_test11.bpl deleted file mode 100644 index cee3e36e..00000000 --- a/float_test11.bpl +++ /dev/null @@ -1,55 +0,0 @@ -//Translation from interpolation.c -//Should Verify -//Returns inconclusive? What does that mean? - -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); -procedure main() returns () { - var i : int; - var z : float32; - var t : float32; - var min : [int] float32; - var max : [int] float32; - - min[0] := TO_FLOAT32_INT(5); - min[1] := TO_FLOAT32_INT(10); - min[2] := TO_FLOAT32_INT(12); - min[3] := TO_FLOAT32_INT(30); - min[4] := TO_FLOAT32_INT(150); - - max[0] := TO_FLOAT32_INT(10); - max[1] := TO_FLOAT32_INT(12); - max[2] := TO_FLOAT32_INT(30); - max[3] := TO_FLOAT32_INT(150); - max[4] := TO_FLOAT32_INT(300); - - havoc t; - assume(t >= min[0] && t <= max[4]); - - i := 0; - //while (i < 5) { - //if (t <= max[i]) { - //break; - //} - //i := i + 1; - //} - - if (t > max[0]) { //1 - i := i + 1; - } - if (t > max[1]) { //2 - i := i + 1; - } - if (t > max[2]) { //3 - i := i + 1; - } - if (t > max[3]) { //4 - i := i + 1; - } - if (t > max[4]) { //5 - i := i + 1; - } - - z := (t - min[i]) / (max[i] - min[i]); - - assert(z >= TO_FLOAT32_INT(0) && z <= TO_FLOAT32_INT(1)); -} \ No newline at end of file diff --git a/float_test12.bpl b/float_test12.bpl deleted file mode 100644 index c733b9f4..00000000 --- a/float_test12.bpl +++ /dev/null @@ -1,43 +0,0 @@ -//Translation from inv_Newton.c -//Should Verify -//Unfinished code! - -procedure inv(float(11 53)) returns(float(11 53)) { - var z : float(11 53); - var t : float(11 53); - var t : float(11 53); - - -} - -procedure main() returns () { - var t : float(11 53); - var t : float(11 53); - - min[0] := fp(5); - min[1] := fp(10); - min[2] := fp(12); - min[3] := fp(30); - min[4] := fp(150); - - max[0] := fp(10); - max[1] := fp(12); - max[2] := fp(30); - max[3] := fp(150); - max[4] := fp(300); - - havoc t; - assume(t >= min[0] && t <= max[4]); - - i := 0; - while (i < 5) { - if (t <= max[i]) { - break; - } - i := i + 1; - } - - z := (t - min[i]) / (max[i] - min[i]); - - assert(z >= fp(0) && z <= fp(1)); -} \ No newline at end of file diff --git a/float_test13.bpl b/float_test13.bpl deleted file mode 100644 index e5402539..00000000 --- a/float_test13.bpl +++ /dev/null @@ -1,19 +0,0 @@ -//Translation from inv_square_false-unreach-call.c -//Should return an error (without crashing) - -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); - -procedure main() returns () { - var x : float32; - var y : float32; - var z : float32; - - havoc x; - assume(x >= TO_FLOAT32_INT(-1) && x <= TO_FLOAT32_INT(1)); - - if (x != TO_FLOAT32_INT(0)) { - y := x * x; - assert(y != TO_FLOAT32_INT(0)); - z := TO_FLOAT32_INT(1) / y; - } -} \ No newline at end of file diff --git a/float_test14.bpl b/float_test14.bpl deleted file mode 100644 index 1505c361..00000000 --- a/float_test14.bpl +++ /dev/null @@ -1,20 +0,0 @@ -//Translation from inv_square_true-unreach-call.c -//Should Verify - -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_REAL(real) returns (float32); - -procedure main() returns () { - var x : float32; - var y : float32; - var z : float32; - - havoc x; - assume(x >= TO_FLOAT32_INT(-1) && x <= TO_FLOAT32_INT(1)); - - if (x <= TO_FLOAT32_REAL(-1e-20) || x >= TO_FLOAT32_REAL(1e-20)) { - y := x * x; - assert(y != TO_FLOAT32_INT(0)); - z := TO_FLOAT32_INT(1) / y; - } -} \ No newline at end of file diff --git a/float_test15.bpl b/float_test15.bpl deleted file mode 100644 index 1dc549ac..00000000 --- a/float_test15.bpl +++ /dev/null @@ -1,24 +0,0 @@ -//Translation from Muller_Kahan.c -//Should Verify -//NOTE: (fp(....)) causes a compiler error! -//FAILS! Heavily... - -procedure main() returns () { - var x0 : float(11 53); - var x1 : float(11 53); - var x2 : float(11 53); - var i : int; - - x0 := fp(11 11 53) / fp(2 11 53); - x1 := fp(61 11 53) / fp(11 11 53); - i := 0; - while (i < 100) { - x2 := fp(1130 11 53) - fp(3000 11 53) / x0; - x2 := fp(111 11 53) - x2 / x1; - x0 := x1; - x1 := x2; - i := i + 1; - } - - assert(x0 >= fp(99 11 53) && x0 <= fp(101 11 53)); -} \ No newline at end of file diff --git a/float_test16.bpl b/float_test16.bpl deleted file mode 100644 index 69ae243d..00000000 --- a/float_test16.bpl +++ /dev/null @@ -1,8 +0,0 @@ -//Translation from nan_double_false-unreach-call.c -//Should return an error - -procedure main() returns () { - var x : float(11 53); - havoc x; - assert(x==x); -} \ No newline at end of file diff --git a/float_test17.bpl b/float_test17.bpl deleted file mode 100644 index caa1fa74..00000000 --- a/float_test17.bpl +++ /dev/null @@ -1,11 +0,0 @@ -//Translation from nan_double_range_true-unreach-call.c -//Should verify -//Uggghhhh, should I add support for e? - -procedure main() returns () { - var x : float(11 53); - havoc x; - if (x >= fp(-100000000000000000000000000 11 53) && x <= fp(100000000000000000000000000 11 53)) { - assert(x==x); - } -} \ No newline at end of file diff --git a/float_test18.bpl b/float_test18.bpl deleted file mode 100644 index 71eb5286..00000000 --- a/float_test18.bpl +++ /dev/null @@ -1,36 +0,0 @@ -//Translation from rlim_exit.c -//Should verify -//Unary - unsupported float operations (on my end)... - -procedure main() returns () { - var X : float; - var Y : float; - var S : float; - var R : float; - var D : float; - var i : int; - - Y := fp(0); - - i := 0; - while (i < 100000) { - havoc X; - havoc D; - assume(X >= fp(-128) && X <= fp(128)); - assume(D >= fp(0) && D <= fp(16)); - - S := Y; - Y := X; - R := X - S; - if (R <= fp(0)-D) { - Y := S - D; - } - else if(R >= D) { - Y := S + D; - } - - i := i + 1; - } - - assert(Y >= fp(-129) && Y <= fp(129)); -} \ No newline at end of file diff --git a/float_test19.bpl b/float_test19.bpl deleted file mode 100644 index f00d8a2b..00000000 --- a/float_test19.bpl +++ /dev/null @@ -1,36 +0,0 @@ -//Translation from flim_invariant.c -//Should verify -//Unary - unsupported float operations (on my end)... - -procedure main() returns () { - var X : float; - var Y : float; - var S : float; - var R : float; - var D : float; - var i : int; - - Y := fp(0); - - i := 0; - while (i < 100000) { - havoc X; - havoc D; - assume(X >= fp(-128) && X <= fp(128)); - assume(D >= fp(0) && D <= fp(16)); - - S := Y; - Y := X; - R := X - S; - if (R <= fp(0)-D) { - Y := S - D; - } - else if(R >= D) { - Y := S + D; - } - - assert(Y >= fp(-129) && Y <= fp(129)); - - i := i + 1; - } -} \ No newline at end of file diff --git a/float_test2.bpl b/float_test2.bpl deleted file mode 100644 index d78c339d..00000000 --- a/float_test2.bpl +++ /dev/null @@ -1,17 +0,0 @@ -//Translation from addsub_float_exact.c -//Should Verify - -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_REAL(real) returns (float32); - -procedure main() returns () { - var x : float32; - var y : float32; - var z : float32; - var r : float32; - x := TO_FLOAT32_REAL(1e7); - y := x + TO_FLOAT32_INT(1); - z := x - TO_FLOAT32_INT(1); - r := y - z; - assert r == TO_FLOAT32_INT(2); -} \ No newline at end of file diff --git a/float_test20.bpl b/float_test20.bpl deleted file mode 100644 index 57c605fd..00000000 --- a/float_test20.bpl +++ /dev/null @@ -1,14 +0,0 @@ -//Should return an error? -//Translation from Rump_double.c - -procedure main() returns () { - var x : float(11 53); - var y : float(11 53); - var r : float(11 53); - - x := fp(77617 11 53); - y := fp(33096 11 53); - r := y*y*y*y*y*y * fp(333.75 11 53) + x*x * (x*x*y*y*fp(11 11 53) - y*y*y*y*y*y - y*y*y*y * fp(121 11 53) - fp(2 11 53)) + y*y*y*y*y*y*y*y * fp(5.5 11 53) + x / (y*fp(2 11 53)); - - assert(r >= fp(0 11 53)); -} \ No newline at end of file diff --git a/float_test3.bpl b/float_test3.bpl deleted file mode 100644 index 67c6ba48..00000000 --- a/float_test3.bpl +++ /dev/null @@ -1,13 +0,0 @@ -//Translation from addsub_float_inexact.c -//Should give an error -procedure main() returns () { - var x : float32; - var y : float32; - var z : float32; - var r : float32; - x := fp<8, 24>(3221225472bv32); - y := x + fp<8, 24>(1bv32); - z := x - fp<8, 24>(1bv32); - r := y - z; - assert r == fp<8, 24>(2bv32); -} \ No newline at end of file diff --git a/float_test4.bpl b/float_test4.bpl deleted file mode 100644 index a31aa215..00000000 --- a/float_test4.bpl +++ /dev/null @@ -1,32 +0,0 @@ -//Translation from drift_tenth.c -//Should Fail - -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_REAL(real) returns (float32); - -procedure main() returns () { - var tick : float32; - var time : float32; - var i: int; - - tick := TO_FLOAT32_INT(1)/TO_FLOAT32_INT(10); - time := TO_FLOAT32_INT(0); - - //i := 0; - //while (i < 10) - //{ - // time := time + tick; - // i := i + 1; - //} - time := time + tick;//1 - time := time + tick;//2 - time := time + tick;//3 - time := time + tick;//4 - time := time + tick;//5 - time := time + tick;//6 - time := time + tick;//7 - time := time + tick;//8 - time := time + tick;//9 - time := time + tick;//10 - assert time == TO_FLOAT32_INT(1); -} \ No newline at end of file diff --git a/float_test5.bpl b/float_test5.bpl deleted file mode 100644 index 7536f8fd..00000000 --- a/float_test5.bpl +++ /dev/null @@ -1,36 +0,0 @@ -//Translation from filter1.c -//Should Verify - -function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_INT(int) returns (float64); -function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_REAL(real) returns (float64); - -procedure main() returns () { - var E0 : float64; - var E1 : float64; - var S : float64); - var i : int; - var rand : int; - - E1 := TO_FLOAT64_INT(0); - S := TO_FLOAT64_INT(0); - - i := 0; - while (i <= 1000000) - { - havoc E0; - assume(E0 >= fp(-1 11 53) && E0 <= fp(1 11 53)); - - havoc rand; - if (rand != 0) { - S := fp(0 11 53); - } - else { - S := fp(0.999 11 53) * S + E0 - E1; - } - E1 := E0; - - //assert(1==0); - assert(S >= fp(-1 11 53) && S <= fp(1 11 53)); - i := i + 1; - } -} \ No newline at end of file diff --git a/float_test6.bpl b/float_test6.bpl deleted file mode 100644 index 6bef1137..00000000 --- a/float_test6.bpl +++ /dev/null @@ -1,40 +0,0 @@ -//Translation from filter2.c -//Should give an error -//FAILS; doesn't generate terms! - -procedure main() returns () { - var E : float(11 53); - var E0 : float(11 53); - var E1 : float(11 53); - var S : float(11 53); - var S0 : float(11 53); - var S1 : float(11 53); - var i: int; - - havoc E; - havoc E0; - assume(E >= fp(0.0 11 53) && E <= fp(1.0 11 53)); - assume(E0 >= fp(0.0 11 53) && E0 <= fp(1.0 11 53)); - - E1 := fp(0.0 11 53); - S1 := fp(0.0 11 53); - S0 := fp(0.0 11 53); - S := fp(0.0 11 53); - - i := 0; -// while (i <= 1000000) -// { - E1 := E0; - E0 := E; - - havoc E; - assume(E >= fp(0.0 11 53) && E <= fp(1.0 11 53)); - - S1 := S0; - S0 := S; - S := E*fp(0.7 11 53) - E0*fp(1.3 11 53) + E1*fp(1.1 11 53) + S0*fp(1.4 11 53) - S1*fp(0.7 11 53); - - assert(S >= fp(-4.0 11 53) && S <= fp(4.0 11 53)); - //i := i + 1; -// } -} \ No newline at end of file diff --git a/float_test7.bpl b/float_test7.bpl deleted file mode 100644 index 8e07878d..00000000 --- a/float_test7.bpl +++ /dev/null @@ -1,38 +0,0 @@ -//Translation from filter2.c -//Should give an error -//Same as the previous one; it works with reals! - -procedure main() returns () { - var E : real; - var E0 : real; - var E1 : real; - var S : real; - var S0 : real; - var S1 : real; - var i: int; - - havoc E; - havoc E0; - assume(E >= 0.0 && E <= 1.0); - assume(E0 >= 0.0 && E0 <= 1.0); - - S0 := 0.0; - S := 0.0; - - i := 0; - while (i <= 1000000) - { - E1 := E0; - E0 := E; - - havoc E; - assume(E >= 0.0 && E <= 1.0); - - S1 := S0; - S0 := S; - S := E*0.7 - E0*1.3 + E1*1.1 + S0*1.4 - S1*0.7; - - assert(S >= -4.0 && S <= 4.0); - i := i + 1; - } -} \ No newline at end of file diff --git a/float_test8.bpl b/float_test8.bpl deleted file mode 100644 index 7e78e206..00000000 --- a/float_test8.bpl +++ /dev/null @@ -1,16 +0,0 @@ -//Translation from float_double.c -//Should Verify - -function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_FLOAT32(float32) returns (float64); -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_FLOAT64(float64) returns (float32); -function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_INT(int) returns (float64); -function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_REAL(real) returns (float64); - -procedure main() returns () { - var x : float64; - var y : float32; - - x := TO_FLOAT64_REAL(1e20)+TO_FLOAT64_INT(1); - y := TO_FLOAT32_FLOAT64(x); - assert x != TO_FLOAT64_FLOAT32(y); -} \ No newline at end of file diff --git a/float_test9.bpl b/float_test9.bpl deleted file mode 100644 index c3a42e6b..00000000 --- a/float_test9.bpl +++ /dev/null @@ -1,34 +0,0 @@ -//Translation from feedback_diverge.c -//Should give an error -//Not sure on this one... - -procedure main() returns () { - var A : float; - var B : float; - var X : float; - var i : int; - var rand : int; - - A := fp(0); - B := fp(0); - - i := 0; - while (i < 3600000) { - - havoc rand; - if (rand != 0) { - havoc X; - assume(X >= fp(-20) && X <= fp(20)); - } - else { - X := B; - } - - B := B - (B * fp(2.0) - A - X) * fp(.005); - A := X; - - i := i + 1; - } - - assert(A >= fp(-100) && A <= fp(100)); -} \ No newline at end of file -- cgit v1.2.3 From 5cff8cd77c629ec8e48a2498b1e704173306586a Mon Sep 17 00:00:00 2001 From: Checkmate50 Date: Mon, 6 Jun 2016 21:09:06 -0600 Subject: finished testing, fixed several minor compiler bugs --- Source/Basetypes/BigFloat.cs | 2 +- Source/Core/Parser.cs | 82 ++++++++++++++++++++-------------- Source/Provers/SMTLib/SMTLibProcess.cs | 2 +- Test/floats/float0.bpl | 14 ++++++ Test/floats/float0.bpl.expect | 8 ++++ Test/floats/float1.bpl | 13 ++++++ Test/floats/float1.bpl.expect | 2 + Test/floats/float10.bpl | 18 ++++++++ Test/floats/float10.bpl.expect | 5 +++ Test/floats/float11.bpl | 22 +++++++++ Test/floats/float11.bpl.expect | 7 +++ Test/floats/float12.bpl | 16 +++++++ Test/floats/float12.bpl.expect | 2 + Test/floats/float13.bpl | 23 ++++++++++ Test/floats/float14.bpl | 17 +++++++ Test/floats/float15.bpl | 36 +++++++++++++++ Test/floats/float16.bpl | 40 +++++++++++++++++ Test/floats/float17.bpl | 38 ++++++++++++++++ Test/floats/float18.bpl | 16 +++++++ Test/floats/float19.bpl | 34 ++++++++++++++ Test/floats/float2.bpl | 15 +++++++ Test/floats/float2.bpl.expect | 7 +++ Test/floats/float20.bpl | 14 ++++++ Test/floats/float21.bpl | 35 +++++++++++++++ Test/floats/float22.bpl | 20 +++++++++ Test/floats/float23.bpl | 8 ++++ Test/floats/float3.bpl | 27 +++++++++++ Test/floats/float3.bpl.expect | 2 + Test/floats/float4.bpl | 11 +++++ Test/floats/float4.bpl.expect | 2 + Test/floats/float5.bpl | 24 ++++++++++ Test/floats/float5.bpl.expect | 9 ++++ Test/floats/float6.bpl | 50 +++++++++++++++++++++ Test/floats/float6.bpl.expect | 2 + Test/floats/float7.bpl | 13 ++++++ Test/floats/float7.bpl.expect | 2 + Test/floats/float8.bpl | 13 ++++++ Test/floats/float8.bpl.expect | 5 +++ Test/floats/float9.bpl | 17 +++++++ Test/floats/float9.bpl.expect | 2 + Test/floats/modpath.py | 13 ++++++ Test/floats/test1.bpl | 13 ------ Test/floats/test10.bpl | 20 --------- Test/floats/test11.bpl | 55 ----------------------- Test/floats/test12.bpl | 43 ------------------ Test/floats/test13.bpl | 19 -------- Test/floats/test14.bpl | 20 --------- Test/floats/test15.bpl | 24 ---------- Test/floats/test16.bpl | 8 ---- Test/floats/test17.bpl | 11 ----- Test/floats/test18.bpl | 36 --------------- Test/floats/test19.bpl | 36 --------------- Test/floats/test2.bpl | 17 ------- Test/floats/test20.bpl | 14 ------ Test/floats/test3.bpl | 13 ------ Test/floats/test4.bpl | 32 ------------- Test/floats/test5.bpl | 36 --------------- Test/floats/test6.bpl | 40 ----------------- Test/floats/test7.bpl | 38 ---------------- Test/floats/test8.bpl | 16 ------- Test/floats/test9.bpl | 34 -------------- 61 files changed, 653 insertions(+), 560 deletions(-) create mode 100644 Test/floats/float0.bpl create mode 100644 Test/floats/float0.bpl.expect create mode 100644 Test/floats/float1.bpl create mode 100644 Test/floats/float1.bpl.expect create mode 100644 Test/floats/float10.bpl create mode 100644 Test/floats/float10.bpl.expect create mode 100644 Test/floats/float11.bpl create mode 100644 Test/floats/float11.bpl.expect create mode 100644 Test/floats/float12.bpl create mode 100644 Test/floats/float12.bpl.expect create mode 100644 Test/floats/float13.bpl create mode 100644 Test/floats/float14.bpl create mode 100644 Test/floats/float15.bpl create mode 100644 Test/floats/float16.bpl create mode 100644 Test/floats/float17.bpl create mode 100644 Test/floats/float18.bpl create mode 100644 Test/floats/float19.bpl create mode 100644 Test/floats/float2.bpl create mode 100644 Test/floats/float2.bpl.expect create mode 100644 Test/floats/float20.bpl create mode 100644 Test/floats/float21.bpl create mode 100644 Test/floats/float22.bpl create mode 100644 Test/floats/float23.bpl create mode 100644 Test/floats/float3.bpl create mode 100644 Test/floats/float3.bpl.expect create mode 100644 Test/floats/float4.bpl create mode 100644 Test/floats/float4.bpl.expect create mode 100644 Test/floats/float5.bpl create mode 100644 Test/floats/float5.bpl.expect create mode 100644 Test/floats/float6.bpl create mode 100644 Test/floats/float6.bpl.expect create mode 100644 Test/floats/float7.bpl create mode 100644 Test/floats/float7.bpl.expect create mode 100644 Test/floats/float8.bpl create mode 100644 Test/floats/float8.bpl.expect create mode 100644 Test/floats/float9.bpl create mode 100644 Test/floats/float9.bpl.expect create mode 100644 Test/floats/modpath.py delete mode 100644 Test/floats/test1.bpl delete mode 100644 Test/floats/test10.bpl delete mode 100644 Test/floats/test11.bpl delete mode 100644 Test/floats/test12.bpl delete mode 100644 Test/floats/test13.bpl delete mode 100644 Test/floats/test14.bpl delete mode 100644 Test/floats/test15.bpl delete mode 100644 Test/floats/test16.bpl delete mode 100644 Test/floats/test17.bpl delete mode 100644 Test/floats/test18.bpl delete mode 100644 Test/floats/test19.bpl delete mode 100644 Test/floats/test2.bpl delete mode 100644 Test/floats/test20.bpl delete mode 100644 Test/floats/test3.bpl delete mode 100644 Test/floats/test4.bpl delete mode 100644 Test/floats/test5.bpl delete mode 100644 Test/floats/test6.bpl delete mode 100644 Test/floats/test7.bpl delete mode 100644 Test/floats/test8.bpl delete mode 100644 Test/floats/test9.bpl diff --git a/Source/Basetypes/BigFloat.cs b/Source/Basetypes/BigFloat.cs index a0ce03a5..3c4cc40a 100644 --- a/Source/Basetypes/BigFloat.cs +++ b/Source/Basetypes/BigFloat.cs @@ -313,7 +313,7 @@ namespace Microsoft.Basetypes return "_ " + this.value + " " + this.exponentSize + " " + this.significandSize; } else if (this.Value == "") { - return "fp (_ bv" + (this.isNeg ? "1" : "0") + " 1) (_ bv" + this.exponent + " " + this.exponentSize + ") (_ bv" + this.significand + " " + this.significandSize + ")"; + return "fp (_ bv" + (this.isNeg ? "1" : "0") + " 1) (_ bv" + this.exponent + " " + this.exponentSize + ") (_ bv" + this.significand + " " + (this.significandSize-1) + ")"; } else { return "(_ to_fp " + this.exponentSize + " " + this.significandSize + ") (_ bv" + this.value + " " + (this.exponentSize + this.significandSize).ToString() + ")"; diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index 8161544f..7982f594 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -668,35 +668,7 @@ private class BvBounds : Expr { ty = new BasicType(t, SimpleType.Real); } else if (la.kind == 98) { Get(); - if (t.val.Length > 5) { - switch (Int32.Parse(t.val.Substring(5))) { - case 16: - ty = new FloatType(t, 5, 11); - break; - case 32: - ty = new FloatType(t, 8, 24); - break; - case 64: - ty = new FloatType(t, 11, 53); - break; - case 128: - ty = new FloatType(t, 15, 113); - break; - default: - SynErr(3); - break; - } - } - else { - Expect(19); //< - Expect(3); //int - int exp = Int32.Parse(t.val); - Expect(12); //, - Expect(3); //int - int man = Int32.Parse(t.val); - ty = new FloatType(t, exp, man); - Expect(20); //> - } + ty = FType(); } else if (la.kind == 16) { Get(); ty = new BasicType(t, SimpleType.Bool); @@ -707,6 +679,39 @@ private class BvBounds : Expr { } else SynErr(101); } + FloatType FType() { + if (t.val.Length > 5) { + switch (Int32.Parse(t.val.Substring(5))) { + case 16: + return new FloatType(t, 5, 11); + case 32: + return new FloatType(t, 8, 24); + case 64: + return new FloatType(t, 11, 53); + case 128: + return new FloatType(t, 15, 113); + default: + SynErr(3); + return new FloatType(t, 0, 0); + } + } + else { + try { + Expect(19); //< + Expect(3); //int + int exp = Int32.Parse(t.val); + Expect(12); //, + Expect(3); //int + int man = Int32.Parse(t.val); + Expect(20); //> + return new FloatType(t, exp, man); + } + catch (Exception) { + return new FloatType(t, 0, 0); + } + } + } + void Ident(out IToken/*!*/ x) { Contract.Ensures(Contract.ValueAtReturn(out x) != null); Expect(1); @@ -1915,8 +1920,13 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { Get(); //Skip the float token if (la.val == "(") { Get(); - Expect(16); //bool - negative = Boolean.Parse(t.val); + if (la.val == "false") + negative = false; + else if (la.val == "true") + negative = true; + else + throw new FormatException(); + Get(); Expect(12); //, BvLit(out exp_val, out exp); Expect(12); @@ -1933,10 +1943,16 @@ out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv) { sig = Int32.Parse(t.val); Expect(20); //> Expect(9); //( - if (la.kind == 4) { + if (la.kind == 1) { //NaN Get(); n = new BigFloat(t.val, exp, sig); } + else if (la.kind == 74 || la.kind == 75) { //+ or - + Get(); + String s = t.val; + Get(); + n = new BigFloat(s + t.val, exp, sig); + } else { BvLit(out value, out size); n = new BigFloat(value.ToString(), exp, sig); @@ -2194,7 +2210,7 @@ out QKeyValue kv, out Trigger trig, out Expr/*!*/ body) { {x,T,x,x, x,x,x,x, x,T,x,x, x,x,T,T, T,T,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,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,x,x,x, x,x,x,T, x,x,T,T, T,x,T,x, x,T,T,T, 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,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,T, x,x,x,x, x,x,x,x, x,x,T,T, 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,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,T,T,x, x,T,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, 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,T, 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,T,T,T, x,T,T,x, x,T,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, 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,T, x,x,x,x, T,T,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,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,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, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,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,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,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}, diff --git a/Source/Provers/SMTLib/SMTLibProcess.cs b/Source/Provers/SMTLib/SMTLibProcess.cs index 4982d81e..bc94e253 100644 --- a/Source/Provers/SMTLib/SMTLibProcess.cs +++ b/Source/Provers/SMTLib/SMTLibProcess.cs @@ -93,7 +93,7 @@ namespace Microsoft.Boogie.SMTLib log = log.Replace("\r", "").Replace("\n", " "); Console.WriteLine("[SMT-INP-{0}] {1}", smtProcessId, log); } - Console.WriteLine(cmd); + //Console.WriteLine(cmd); toProver.WriteLine(cmd); } diff --git a/Test/floats/float0.bpl b/Test/floats/float0.bpl new file mode 100644 index 00000000..b1a240be --- /dev/null +++ b/Test/floats/float0.bpl @@ -0,0 +1,14 @@ +// RUN: %boogie -proverWarnings:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +procedure foo(x : real) returns (r : float<8, 24>) +{ + r := 15; // Error + r := 15.0; // Error + r := fp(false, 1bv8, 0bv22); // Error + r := fp<8, 23>(1bv31); // Error + r := x; // Error + r := fp<8, 23>(1bv31) + fp<8, 23>(1bv31); // Error + r := fp<8, 24>(1bv32) + fp<8, 23>(1bv31); // Error + + return; +} \ No newline at end of file diff --git a/Test/floats/float0.bpl.expect b/Test/floats/float0.bpl.expect new file mode 100644 index 00000000..4c934700 --- /dev/null +++ b/Test/floats/float0.bpl.expect @@ -0,0 +1,8 @@ +float0.bpl(5,1): Error: mismatched types in assignment command (cannot assign int to float (8 24)) +float0.bpl(6,1): Error: mismatched types in assignment command (cannot assign real to float (8 24)) +float0.bpl(7,1): Error: mismatched types in assignment command (cannot assign float (8 23) to float (8 24)) +float0.bpl(8,1): Error: mismatched types in assignment command (cannot assign float (8 23) to float (8 24)) +float0.bpl(9,1): Error: mismatched types in assignment command (cannot assign real to float (8 24)) +float0.bpl(10,1): Error: mismatched types in assignment command (cannot assign float (8 23) to float (8 24)) +float0.bpl(11,23): Error: invalid argument types (float (8 24) and float (8 23)) to binary operator + +7 type checking errors detected in float0.bpl diff --git a/Test/floats/float1.bpl b/Test/floats/float1.bpl new file mode 100644 index 00000000..9ed62579 --- /dev/null +++ b/Test/floats/float1.bpl @@ -0,0 +1,13 @@ +// RUN: %boogie -proverWarnings:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +procedure foo(x : float<8, 24>) returns (r : float<8, 24>) +{ + r := fp(false, 1bv8, 0bv23); + r := fp<8, 24>(1bv32); + r := x; + r := x + fp<8, 24>(1bv32); + r := fp<8, 24>(1bv32) + fp<8, 24>(1bv32); + assert(r == fp<8, 24>(2bv32)); + + return; +} \ No newline at end of file diff --git a/Test/floats/float1.bpl.expect b/Test/floats/float1.bpl.expect new file mode 100644 index 00000000..6abb715b --- /dev/null +++ b/Test/floats/float1.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 1 verified, 0 errors diff --git a/Test/floats/float10.bpl b/Test/floats/float10.bpl new file mode 100644 index 00000000..bf07aec6 --- /dev/null +++ b/Test/floats/float10.bpl @@ -0,0 +1,18 @@ +// RUN: %boogie -proverWarnings:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_REAL(real) returns (float64); + +procedure double_range_true() returns () { + var x : float64; + havoc x; + if (x >= TO_FLOAT64_REAL(-1e307) && x <= TO_FLOAT64_REAL(1e307)) { + assert(x==x); + } +} + +procedure double_range_false() returns () { + var x : float64; + havoc x; + assert(x==x); +} \ No newline at end of file diff --git a/Test/floats/float10.bpl.expect b/Test/floats/float10.bpl.expect new file mode 100644 index 00000000..cae8d781 --- /dev/null +++ b/Test/floats/float10.bpl.expect @@ -0,0 +1,5 @@ +float10.bpl(17,2): Error BP5001: This assertion might not hold. +Execution trace: + float10.bpl(16,2): anon0 + +Boogie program verifier finished with 1 verified, 1 error diff --git a/Test/floats/float11.bpl b/Test/floats/float11.bpl new file mode 100644 index 00000000..424c5a2d --- /dev/null +++ b/Test/floats/float11.bpl @@ -0,0 +1,22 @@ +// RUN: %boogie -proverWarnings:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_REAL(real) returns (float32); + +procedure main() returns () { + var tick : float32; + var time : float32; + var i: int; + + tick := TO_FLOAT32_INT(1)/TO_FLOAT32_INT(10); + time := TO_FLOAT32_INT(0); + + i := 0; + while (i < 10) + { + time := time + tick; + i := i + 1; + } + assert time == TO_FLOAT32_INT(1); +} \ No newline at end of file diff --git a/Test/floats/float11.bpl.expect b/Test/floats/float11.bpl.expect new file mode 100644 index 00000000..19e55fef --- /dev/null +++ b/Test/floats/float11.bpl.expect @@ -0,0 +1,7 @@ +..\Test\floats\float11.bpl(21,2): Error BP5001: This assertion might not hold. +Execution trace: + ..\Test\floats\float11.bpl(12,7): anon0 + ..\Test\floats\float11.bpl(16,2): anon3_LoopHead + ..\Test\floats\float11.bpl(16,2): anon3_LoopDone + +Boogie program verifier finished with 0 verified, 1 error diff --git a/Test/floats/float12.bpl b/Test/floats/float12.bpl new file mode 100644 index 00000000..349abb41 --- /dev/null +++ b/Test/floats/float12.bpl @@ -0,0 +1,16 @@ +// RUN: %boogie -proverWarnings:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_FLOAT32(float32) returns (float64); +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_FLOAT64(float64) returns (float32); +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_INT(int) returns (float64); +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_REAL(real) returns (float64); + +procedure main() returns () { + var x : float64; + var y : float32; + + x := TO_FLOAT64_REAL(1e20)+TO_FLOAT64_INT(1); + y := TO_FLOAT32_FLOAT64(x); + assert x != TO_FLOAT64_FLOAT32(y); +} \ No newline at end of file diff --git a/Test/floats/float12.bpl.expect b/Test/floats/float12.bpl.expect new file mode 100644 index 00000000..6abb715b --- /dev/null +++ b/Test/floats/float12.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 1 verified, 0 errors diff --git a/Test/floats/float13.bpl b/Test/floats/float13.bpl new file mode 100644 index 00000000..4fe25140 --- /dev/null +++ b/Test/floats/float13.bpl @@ -0,0 +1,23 @@ +// RUN: %boogie -proverWarnings:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_INT(int) returns (float64); +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_REAL(real) returns (float64); + +procedure main() returns () { + var x : float64; + var y : float64; + + havoc x; + assume(x >= TO_FLOAT64_INT(0) && x <= TO_FLOAT64_INT(10)); + + y := x*x - x; + if (y >= TO_FLOAT64_INT(0)) { + y := x / TO_FLOAT64_INT(10); + } + else { + y := x*x + TO_FLOAT64_INT(2); + } + + assert(y >= TO_FLOAT64_INT(0) && y <= TO_FLOAT64_INT(105)); +} \ No newline at end of file diff --git a/Test/floats/float14.bpl b/Test/floats/float14.bpl new file mode 100644 index 00000000..46c1b07d --- /dev/null +++ b/Test/floats/float14.bpl @@ -0,0 +1,17 @@ +// RUN: %boogie -proverWarnings:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_INT(int) returns (float64); +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_REAL(real) returns (float64); + +procedure main() returns () { + var x : float64; + var y : float64; + var r : float64; + + x := TO_FLOAT64_INT(77617); + y := TO_FLOAT64_INT(33096); + r := y*y*y*y*y*y * TO_FLOAT64_REAL(333.75) + x*x * (x*x*y*y*TO_FLOAT64_INT(11) - y*y*y*y*y*y - y*y*y*y * TO_FLOAT64_INT(121) - TO_FLOAT64_INT(2)) + y*y*y*y*y*y*y*y * TO_FLOAT64_REAL(5.5) + x / (y*TO_FLOAT64_INT(2)); + + assert(r >= TO_FLOAT64_INT(0)); +} \ No newline at end of file diff --git a/Test/floats/float15.bpl b/Test/floats/float15.bpl new file mode 100644 index 00000000..7536f8fd --- /dev/null +++ b/Test/floats/float15.bpl @@ -0,0 +1,36 @@ +//Translation from filter1.c +//Should Verify + +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_INT(int) returns (float64); +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_REAL(real) returns (float64); + +procedure main() returns () { + var E0 : float64; + var E1 : float64; + var S : float64); + var i : int; + var rand : int; + + E1 := TO_FLOAT64_INT(0); + S := TO_FLOAT64_INT(0); + + i := 0; + while (i <= 1000000) + { + havoc E0; + assume(E0 >= fp(-1 11 53) && E0 <= fp(1 11 53)); + + havoc rand; + if (rand != 0) { + S := fp(0 11 53); + } + else { + S := fp(0.999 11 53) * S + E0 - E1; + } + E1 := E0; + + //assert(1==0); + assert(S >= fp(-1 11 53) && S <= fp(1 11 53)); + i := i + 1; + } +} \ No newline at end of file diff --git a/Test/floats/float16.bpl b/Test/floats/float16.bpl new file mode 100644 index 00000000..6bef1137 --- /dev/null +++ b/Test/floats/float16.bpl @@ -0,0 +1,40 @@ +//Translation from filter2.c +//Should give an error +//FAILS; doesn't generate terms! + +procedure main() returns () { + var E : float(11 53); + var E0 : float(11 53); + var E1 : float(11 53); + var S : float(11 53); + var S0 : float(11 53); + var S1 : float(11 53); + var i: int; + + havoc E; + havoc E0; + assume(E >= fp(0.0 11 53) && E <= fp(1.0 11 53)); + assume(E0 >= fp(0.0 11 53) && E0 <= fp(1.0 11 53)); + + E1 := fp(0.0 11 53); + S1 := fp(0.0 11 53); + S0 := fp(0.0 11 53); + S := fp(0.0 11 53); + + i := 0; +// while (i <= 1000000) +// { + E1 := E0; + E0 := E; + + havoc E; + assume(E >= fp(0.0 11 53) && E <= fp(1.0 11 53)); + + S1 := S0; + S0 := S; + S := E*fp(0.7 11 53) - E0*fp(1.3 11 53) + E1*fp(1.1 11 53) + S0*fp(1.4 11 53) - S1*fp(0.7 11 53); + + assert(S >= fp(-4.0 11 53) && S <= fp(4.0 11 53)); + //i := i + 1; +// } +} \ No newline at end of file diff --git a/Test/floats/float17.bpl b/Test/floats/float17.bpl new file mode 100644 index 00000000..8e07878d --- /dev/null +++ b/Test/floats/float17.bpl @@ -0,0 +1,38 @@ +//Translation from filter2.c +//Should give an error +//Same as the previous one; it works with reals! + +procedure main() returns () { + var E : real; + var E0 : real; + var E1 : real; + var S : real; + var S0 : real; + var S1 : real; + var i: int; + + havoc E; + havoc E0; + assume(E >= 0.0 && E <= 1.0); + assume(E0 >= 0.0 && E0 <= 1.0); + + S0 := 0.0; + S := 0.0; + + i := 0; + while (i <= 1000000) + { + E1 := E0; + E0 := E; + + havoc E; + assume(E >= 0.0 && E <= 1.0); + + S1 := S0; + S0 := S; + S := E*0.7 - E0*1.3 + E1*1.1 + S0*1.4 - S1*0.7; + + assert(S >= -4.0 && S <= 4.0); + i := i + 1; + } +} \ No newline at end of file diff --git a/Test/floats/float18.bpl b/Test/floats/float18.bpl new file mode 100644 index 00000000..7e78e206 --- /dev/null +++ b/Test/floats/float18.bpl @@ -0,0 +1,16 @@ +//Translation from float_double.c +//Should Verify + +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_FLOAT32(float32) returns (float64); +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_FLOAT64(float64) returns (float32); +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_INT(int) returns (float64); +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_REAL(real) returns (float64); + +procedure main() returns () { + var x : float64; + var y : float32; + + x := TO_FLOAT64_REAL(1e20)+TO_FLOAT64_INT(1); + y := TO_FLOAT32_FLOAT64(x); + assert x != TO_FLOAT64_FLOAT32(y); +} \ No newline at end of file diff --git a/Test/floats/float19.bpl b/Test/floats/float19.bpl new file mode 100644 index 00000000..c3a42e6b --- /dev/null +++ b/Test/floats/float19.bpl @@ -0,0 +1,34 @@ +//Translation from feedback_diverge.c +//Should give an error +//Not sure on this one... + +procedure main() returns () { + var A : float; + var B : float; + var X : float; + var i : int; + var rand : int; + + A := fp(0); + B := fp(0); + + i := 0; + while (i < 3600000) { + + havoc rand; + if (rand != 0) { + havoc X; + assume(X >= fp(-20) && X <= fp(20)); + } + else { + X := B; + } + + B := B - (B * fp(2.0) - A - X) * fp(.005); + A := X; + + i := i + 1; + } + + assert(A >= fp(-100) && A <= fp(100)); +} \ No newline at end of file diff --git a/Test/floats/float2.bpl b/Test/floats/float2.bpl new file mode 100644 index 00000000..1a4d02cd --- /dev/null +++ b/Test/floats/float2.bpl @@ -0,0 +1,15 @@ +// RUN: %boogie -proverWarnings:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +procedure foo(x : float16) returns(r : float32) { + var y : float64; + var z : float128; + + r := x; // Error + r := y; // Error + r := z; // Error + y := x; // Error + y := z; // Error + z := x; // Error + + return; +} \ No newline at end of file diff --git a/Test/floats/float2.bpl.expect b/Test/floats/float2.bpl.expect new file mode 100644 index 00000000..62348741 --- /dev/null +++ b/Test/floats/float2.bpl.expect @@ -0,0 +1,7 @@ +float2.bpl(7,1): Error: mismatched types in assignment command (cannot assign float (5 11) to float (8 24)) +float2.bpl(8,1): Error: mismatched types in assignment command (cannot assign float (11 53) to float (8 24)) +float2.bpl(9,1): Error: mismatched types in assignment command (cannot assign float (15 113) to float (8 24)) +float2.bpl(10,1): Error: mismatched types in assignment command (cannot assign float (5 11) to float (11 53)) +float2.bpl(11,1): Error: mismatched types in assignment command (cannot assign float (15 113) to float (11 53)) +float2.bpl(12,1): Error: mismatched types in assignment command (cannot assign float (5 11) to float (15 113)) +6 type checking errors detected in float2.bpl diff --git a/Test/floats/float20.bpl b/Test/floats/float20.bpl new file mode 100644 index 00000000..57c605fd --- /dev/null +++ b/Test/floats/float20.bpl @@ -0,0 +1,14 @@ +//Should return an error? +//Translation from Rump_double.c + +procedure main() returns () { + var x : float(11 53); + var y : float(11 53); + var r : float(11 53); + + x := fp(77617 11 53); + y := fp(33096 11 53); + r := y*y*y*y*y*y * fp(333.75 11 53) + x*x * (x*x*y*y*fp(11 11 53) - y*y*y*y*y*y - y*y*y*y * fp(121 11 53) - fp(2 11 53)) + y*y*y*y*y*y*y*y * fp(5.5 11 53) + x / (y*fp(2 11 53)); + + assert(r >= fp(0 11 53)); +} \ No newline at end of file diff --git a/Test/floats/float21.bpl b/Test/floats/float21.bpl new file mode 100644 index 00000000..5fad5859 --- /dev/null +++ b/Test/floats/float21.bpl @@ -0,0 +1,35 @@ +// RUN: %boogie -proverWarnings:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_REAL(real) returns (float32); + +procedure main() returns () { + var x : float32; + var y : float32; + var z : float32; + + havoc x; + assume(x >= TO_FLOAT32_INT(-1) && x <= TO_FLOAT32_INT(1)); + + if (x != TO_FLOAT32_INT(0)) { + y := x * x; + assert(y != TO_FLOAT32_INT(0)); + z := TO_FLOAT32_INT(1) / y; + } +} + +procedure main() returns () { + var x : float32; + var y : float32; + var z : float32; + + havoc x; + assume(x >= TO_FLOAT32_INT(-1) && x <= TO_FLOAT32_INT(1)); + + if (x <= TO_FLOAT32_REAL(-1e-20) || x >= TO_FLOAT32_REAL(1e-20)) { + y := x * x; + assert(y != TO_FLOAT32_INT(0)); + z := TO_FLOAT32_INT(1) / y; + } +} \ No newline at end of file diff --git a/Test/floats/float22.bpl b/Test/floats/float22.bpl new file mode 100644 index 00000000..1505c361 --- /dev/null +++ b/Test/floats/float22.bpl @@ -0,0 +1,20 @@ +//Translation from inv_square_true-unreach-call.c +//Should Verify + +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_REAL(real) returns (float32); + +procedure main() returns () { + var x : float32; + var y : float32; + var z : float32; + + havoc x; + assume(x >= TO_FLOAT32_INT(-1) && x <= TO_FLOAT32_INT(1)); + + if (x <= TO_FLOAT32_REAL(-1e-20) || x >= TO_FLOAT32_REAL(1e-20)) { + y := x * x; + assert(y != TO_FLOAT32_INT(0)); + z := TO_FLOAT32_INT(1) / y; + } +} \ No newline at end of file diff --git a/Test/floats/float23.bpl b/Test/floats/float23.bpl new file mode 100644 index 00000000..69ae243d --- /dev/null +++ b/Test/floats/float23.bpl @@ -0,0 +1,8 @@ +//Translation from nan_double_false-unreach-call.c +//Should return an error + +procedure main() returns () { + var x : float(11 53); + havoc x; + assert(x==x); +} \ No newline at end of file diff --git a/Test/floats/float3.bpl b/Test/floats/float3.bpl new file mode 100644 index 00000000..34059f80 --- /dev/null +++ b/Test/floats/float3.bpl @@ -0,0 +1,27 @@ +// RUN: %boogie -proverWarnings:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +procedure main() returns () { + var x : float32; + var y : float32; + var z : float32; + + z := x + y; + z := x - y; + z := x * y; + assume(y != fp<8, 24>(0bv32)); + z := x / y; + + z := (fp<8, 24>(1bv32) + fp<8, 24>(1bv32)) + fp<8, 24>(0bv32); + assert(z == fp<8, 24>(2bv32)); + + z := fp<8, 24>(2bv32) - fp<8, 24>(1bv32); + assert(z == fp<8, 24>(1bv32)); + + z := fp(false, 127bv8, 0bv23) * fp(false, 127bv8, 0bv23); + assert(z == fp(false, 127bv8, 0bv23)); + + z := fp<8, 24>(1bv32) / fp<8, 24>(1bv32); + assert(z == fp(false, 127bv8, 0bv23)); + + return; +} \ No newline at end of file diff --git a/Test/floats/float3.bpl.expect b/Test/floats/float3.bpl.expect new file mode 100644 index 00000000..6abb715b --- /dev/null +++ b/Test/floats/float3.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 1 verified, 0 errors diff --git a/Test/floats/float4.bpl b/Test/floats/float4.bpl new file mode 100644 index 00000000..7bb24250 --- /dev/null +++ b/Test/floats/float4.bpl @@ -0,0 +1,11 @@ +// RUN: %boogie -proverWarnings:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +procedure foo() returns (r : float32) { + r := fp<8, 24>(NaN); + r := fp<8, 24>(+oo); + r := fp<8, 24>(-oo); + r := fp<8, 24>(+zero); + r := fp<8, 24>(-zero); + + return; +} \ No newline at end of file diff --git a/Test/floats/float4.bpl.expect b/Test/floats/float4.bpl.expect new file mode 100644 index 00000000..6abb715b --- /dev/null +++ b/Test/floats/float4.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 1 verified, 0 errors diff --git a/Test/floats/float5.bpl b/Test/floats/float5.bpl new file mode 100644 index 00000000..fd630394 --- /dev/null +++ b/Test/floats/float5.bpl @@ -0,0 +1,24 @@ +// RUN: %boogie -proverWarnings:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +function {:builtin "(_ to_fp 8 23) RNE"} TO_FLOAT823_INT(int) returns (float<8, 23>); +function {:builtin "(_ to_fp 8 23) RNE"} TO_FLOAT823_REAL(real) returns (float<8, 23>); +function {:builtin "(_ to_fp 8 23) RNE"} TO_FLOAT823_BV31(bv31) returns (float<8, 23>); +function {:builtin "(_ to_fp 8 23) RNE"} TO_FLOAT823_BV32(bv32) returns (float<8, 23>); +function {:builtin "(_ to_fp 8 23) RNE"} TO_FLOAT823_FLOAT824(float<8, 24>) returns (float<8, 23>); +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT824_FLOAT823(float<8, 23>) returns (float<8, 24>); + +procedure foo(x : float<8, 24>) returns (r : float<8, 24>) { + r := TO_FLOAT823_INT(5); // Error + r := TO_FLOAT823_REAL(5.0); // Error + r := TO_FLOAT823_BV31(0bv31); // Error + r := TO_FLOAT823_BV32(0bv32); // Error + r := TO_FLOAT823_FLOAT824(fp<8, 24>(1bv32)); // Error + r := TO_FLOAT824_FLOAT823(fp<8, 24>(1bv32)); // Error + r := TO_FLOAT824_FLOAT823(fp<8, 23>(1bv31)); + + r := TO_FLOAT823_FLOAT824(x); // Error + r := TO_FLOAT824_FLOAT823(x); // Error + + return; +} \ No newline at end of file diff --git a/Test/floats/float5.bpl.expect b/Test/floats/float5.bpl.expect new file mode 100644 index 00000000..6c0b86af --- /dev/null +++ b/Test/floats/float5.bpl.expect @@ -0,0 +1,9 @@ +float5.bpl(12,1): Error: mismatched types in assignment command (cannot assign float (8 23) to float (8 24)) +float5.bpl(13,1): Error: mismatched types in assignment command (cannot assign float (8 23) to float (8 24)) +float5.bpl(14,1): Error: mismatched types in assignment command (cannot assign float (8 23) to float (8 24)) +float5.bpl(15,1): Error: mismatched types in assignment command (cannot assign float (8 23) to float (8 24)) +float5.bpl(16,1): Error: mismatched types in assignment command (cannot assign float (8 23) to float (8 24)) +float5.bpl(17,42): Error: invalid type for argument 0 in application of TO_FLOAT824_FLOAT823: float (8 24) (expected: float (8 23)) +float5.bpl(20,1): Error: mismatched types in assignment command (cannot assign float (8 23) to float (8 24)) +float5.bpl(21,27): Error: invalid type for argument 0 in application of TO_FLOAT824_FLOAT823: float (8 24) (expected: float (8 23)) +8 type checking errors detected in float5.bpl diff --git a/Test/floats/float6.bpl b/Test/floats/float6.bpl new file mode 100644 index 00000000..fe0eab0e --- /dev/null +++ b/Test/floats/float6.bpl @@ -0,0 +1,50 @@ +// RUN: %boogie -proverWarnings:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT824_INT(int) returns (float<8, 24>); +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT824_REAL(real) returns (float<8, 24>); +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT824_BV32(bv32) returns (float<8, 24>); +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT1153_BV64(bv64) returns (float<11, 53>); +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT824_FLOAT32(float32) returns (float<8, 24>); //Should just be an identity function +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_FLOAT824(float<8, 24>) returns (float32); //Should just be an identity function +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_FLOAT64(float64) returns (float32); +function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_FLOAT32(float32) returns (float64); + +procedure main() returns () { + var i : int; + var r : real; + var f824 : float<8, 24>; + var f32 : float32; + var f1153 : float<11, 53>; + var f64 : float64; + + f824 := TO_FLOAT824_INT(5); + f32 := TO_FLOAT824_INT(5); + f824 := TO_FLOAT824_REAL(5.0); + f32 := TO_FLOAT824_REAL(5.0); + + f824 := TO_FLOAT824_BV32(0bv32); + f32 := TO_FLOAT824_BV32(0bv32); + f1153 := TO_FLOAT1153_BV64(0bv64); + f64 := TO_FLOAT1153_BV64(0bv64); + + f824 := TO_FLOAT824_FLOAT32(fp<8, 24>(0bv32)); + f32 := TO_FLOAT32_FLOAT824(fp<8, 24>(0bv32)); + f824 := TO_FLOAT32_FLOAT64(fp<11, 53>(0bv32)); + f32 := TO_FLOAT32_FLOAT64(fp<11, 53>(0bv32)); + f1153 := TO_FLOAT64_FLOAT32(fp<8, 24>(0bv32)); + f64 := TO_FLOAT64_FLOAT32(fp<8, 24>(0bv32)); + + f824 := TO_FLOAT824_INT(5); + f32 := TO_FLOAT32_FLOAT824(f824); + assert(f32 == f824); + + f32 := TO_FLOAT824_INT(5); + f824 := TO_FLOAT824_FLOAT32(f32); + assert(f32 == f824); + + f32 := TO_FLOAT32_FLOAT64(f64); + f64 := TO_FLOAT64_FLOAT32(f32); + + return; +} \ No newline at end of file diff --git a/Test/floats/float6.bpl.expect b/Test/floats/float6.bpl.expect new file mode 100644 index 00000000..6abb715b --- /dev/null +++ b/Test/floats/float6.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 1 verified, 0 errors diff --git a/Test/floats/float7.bpl b/Test/floats/float7.bpl new file mode 100644 index 00000000..f330b2ea --- /dev/null +++ b/Test/floats/float7.bpl @@ -0,0 +1,13 @@ +// RUN: %boogie -proverWarnings:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +procedure main() returns () { + var x : float<11, 53>; + var y : float<11, 53>; + var z : float<11, 53>; + var r : float<11, 53>; + x := fp<11, 53> (10000000bv64); + y := x + fp<11, 53>(1bv64); + z := x - fp<11, 53>(1bv64); + r := y - z; + assert r == fp<11, 53> (2bv64); +} \ No newline at end of file diff --git a/Test/floats/float7.bpl.expect b/Test/floats/float7.bpl.expect new file mode 100644 index 00000000..6abb715b --- /dev/null +++ b/Test/floats/float7.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 1 verified, 0 errors diff --git a/Test/floats/float8.bpl b/Test/floats/float8.bpl new file mode 100644 index 00000000..78c11a2b --- /dev/null +++ b/Test/floats/float8.bpl @@ -0,0 +1,13 @@ +// RUN: %boogie -proverWarnings:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +procedure main() returns () { + var x : float32; + var y : float32; + var z : float32; + var r : float32; + x := fp<8, 24>(3221225472bv32); + y := x + fp<8, 24>(1bv32); + z := x - fp<8, 24>(1bv32); + r := y - z; + assert r == fp<8, 24>(2bv32); +} \ No newline at end of file diff --git a/Test/floats/float8.bpl.expect b/Test/floats/float8.bpl.expect new file mode 100644 index 00000000..426c21e0 --- /dev/null +++ b/Test/floats/float8.bpl.expect @@ -0,0 +1,5 @@ +float8.bpl(12,2): Error BP5001: This assertion might not hold. +Execution trace: + float8.bpl(8,4): anon0 + +Boogie program verifier finished with 0 verified, 1 error diff --git a/Test/floats/float9.bpl b/Test/floats/float9.bpl new file mode 100644 index 00000000..cb4f3afd --- /dev/null +++ b/Test/floats/float9.bpl @@ -0,0 +1,17 @@ +// RUN: %boogie -proverWarnings:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); +function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_REAL(real) returns (float32); + +procedure main() returns () { + var x : float32; + var y : float32; + var z : float32; + var r : float32; + x := TO_FLOAT32_REAL(1e7); + y := x + TO_FLOAT32_INT(1); + z := x - TO_FLOAT32_INT(1); + r := y - z; + assert r == TO_FLOAT32_INT(2); +} \ No newline at end of file diff --git a/Test/floats/float9.bpl.expect b/Test/floats/float9.bpl.expect new file mode 100644 index 00000000..6abb715b --- /dev/null +++ b/Test/floats/float9.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 1 verified, 0 errors diff --git a/Test/floats/modpath.py b/Test/floats/modpath.py new file mode 100644 index 00000000..90707701 --- /dev/null +++ b/Test/floats/modpath.py @@ -0,0 +1,13 @@ +import sys + +f = open(sys.argv[1], 'r') +to_write = "" + +for i in f: + to_write += i.replace("..\\Test\\floats\\", "") + +f.close() + +f = open(sys.argv[1], 'w') + +f.write(to_write) \ No newline at end of file diff --git a/Test/floats/test1.bpl b/Test/floats/test1.bpl deleted file mode 100644 index e893e098..00000000 --- a/Test/floats/test1.bpl +++ /dev/null @@ -1,13 +0,0 @@ -//Translation from addsub_double_exact.c -//Should Verify -procedure main() returns () { - var x : float<11, 53>; - var y : float<11, 53>; - var z : float<11, 53>; - var r : float<11, 53>; - x := fp<11, 53> (10000000bv64); - y := x + fp<11, 53>(1bv64); - z := x - fp<11, 53>(1bv64); - r := y - z; - assert r == fp<11, 53> (2bv64); -} \ No newline at end of file diff --git a/Test/floats/test10.bpl b/Test/floats/test10.bpl deleted file mode 100644 index 566f7a56..00000000 --- a/Test/floats/test10.bpl +++ /dev/null @@ -1,20 +0,0 @@ -//Translation from loop.c -//Should return an error? (The real case does as well...) - -procedure main() returns () { - var x : float; - var y : float; - var z : float; - - x := fp(1); - y := fp(10000000); - z := fp(42); - - while (x < y) { - x := x + fp(1); - y := y - fp(1); - z := z + fp(1); - } - - assert(z >= fp(0) && z <= fp(10000000)); -} \ No newline at end of file diff --git a/Test/floats/test11.bpl b/Test/floats/test11.bpl deleted file mode 100644 index cee3e36e..00000000 --- a/Test/floats/test11.bpl +++ /dev/null @@ -1,55 +0,0 @@ -//Translation from interpolation.c -//Should Verify -//Returns inconclusive? What does that mean? - -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); -procedure main() returns () { - var i : int; - var z : float32; - var t : float32; - var min : [int] float32; - var max : [int] float32; - - min[0] := TO_FLOAT32_INT(5); - min[1] := TO_FLOAT32_INT(10); - min[2] := TO_FLOAT32_INT(12); - min[3] := TO_FLOAT32_INT(30); - min[4] := TO_FLOAT32_INT(150); - - max[0] := TO_FLOAT32_INT(10); - max[1] := TO_FLOAT32_INT(12); - max[2] := TO_FLOAT32_INT(30); - max[3] := TO_FLOAT32_INT(150); - max[4] := TO_FLOAT32_INT(300); - - havoc t; - assume(t >= min[0] && t <= max[4]); - - i := 0; - //while (i < 5) { - //if (t <= max[i]) { - //break; - //} - //i := i + 1; - //} - - if (t > max[0]) { //1 - i := i + 1; - } - if (t > max[1]) { //2 - i := i + 1; - } - if (t > max[2]) { //3 - i := i + 1; - } - if (t > max[3]) { //4 - i := i + 1; - } - if (t > max[4]) { //5 - i := i + 1; - } - - z := (t - min[i]) / (max[i] - min[i]); - - assert(z >= TO_FLOAT32_INT(0) && z <= TO_FLOAT32_INT(1)); -} \ No newline at end of file diff --git a/Test/floats/test12.bpl b/Test/floats/test12.bpl deleted file mode 100644 index c733b9f4..00000000 --- a/Test/floats/test12.bpl +++ /dev/null @@ -1,43 +0,0 @@ -//Translation from inv_Newton.c -//Should Verify -//Unfinished code! - -procedure inv(float(11 53)) returns(float(11 53)) { - var z : float(11 53); - var t : float(11 53); - var t : float(11 53); - - -} - -procedure main() returns () { - var t : float(11 53); - var t : float(11 53); - - min[0] := fp(5); - min[1] := fp(10); - min[2] := fp(12); - min[3] := fp(30); - min[4] := fp(150); - - max[0] := fp(10); - max[1] := fp(12); - max[2] := fp(30); - max[3] := fp(150); - max[4] := fp(300); - - havoc t; - assume(t >= min[0] && t <= max[4]); - - i := 0; - while (i < 5) { - if (t <= max[i]) { - break; - } - i := i + 1; - } - - z := (t - min[i]) / (max[i] - min[i]); - - assert(z >= fp(0) && z <= fp(1)); -} \ No newline at end of file diff --git a/Test/floats/test13.bpl b/Test/floats/test13.bpl deleted file mode 100644 index e5402539..00000000 --- a/Test/floats/test13.bpl +++ /dev/null @@ -1,19 +0,0 @@ -//Translation from inv_square_false-unreach-call.c -//Should return an error (without crashing) - -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); - -procedure main() returns () { - var x : float32; - var y : float32; - var z : float32; - - havoc x; - assume(x >= TO_FLOAT32_INT(-1) && x <= TO_FLOAT32_INT(1)); - - if (x != TO_FLOAT32_INT(0)) { - y := x * x; - assert(y != TO_FLOAT32_INT(0)); - z := TO_FLOAT32_INT(1) / y; - } -} \ No newline at end of file diff --git a/Test/floats/test14.bpl b/Test/floats/test14.bpl deleted file mode 100644 index 1505c361..00000000 --- a/Test/floats/test14.bpl +++ /dev/null @@ -1,20 +0,0 @@ -//Translation from inv_square_true-unreach-call.c -//Should Verify - -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_REAL(real) returns (float32); - -procedure main() returns () { - var x : float32; - var y : float32; - var z : float32; - - havoc x; - assume(x >= TO_FLOAT32_INT(-1) && x <= TO_FLOAT32_INT(1)); - - if (x <= TO_FLOAT32_REAL(-1e-20) || x >= TO_FLOAT32_REAL(1e-20)) { - y := x * x; - assert(y != TO_FLOAT32_INT(0)); - z := TO_FLOAT32_INT(1) / y; - } -} \ No newline at end of file diff --git a/Test/floats/test15.bpl b/Test/floats/test15.bpl deleted file mode 100644 index 1dc549ac..00000000 --- a/Test/floats/test15.bpl +++ /dev/null @@ -1,24 +0,0 @@ -//Translation from Muller_Kahan.c -//Should Verify -//NOTE: (fp(....)) causes a compiler error! -//FAILS! Heavily... - -procedure main() returns () { - var x0 : float(11 53); - var x1 : float(11 53); - var x2 : float(11 53); - var i : int; - - x0 := fp(11 11 53) / fp(2 11 53); - x1 := fp(61 11 53) / fp(11 11 53); - i := 0; - while (i < 100) { - x2 := fp(1130 11 53) - fp(3000 11 53) / x0; - x2 := fp(111 11 53) - x2 / x1; - x0 := x1; - x1 := x2; - i := i + 1; - } - - assert(x0 >= fp(99 11 53) && x0 <= fp(101 11 53)); -} \ No newline at end of file diff --git a/Test/floats/test16.bpl b/Test/floats/test16.bpl deleted file mode 100644 index 69ae243d..00000000 --- a/Test/floats/test16.bpl +++ /dev/null @@ -1,8 +0,0 @@ -//Translation from nan_double_false-unreach-call.c -//Should return an error - -procedure main() returns () { - var x : float(11 53); - havoc x; - assert(x==x); -} \ No newline at end of file diff --git a/Test/floats/test17.bpl b/Test/floats/test17.bpl deleted file mode 100644 index caa1fa74..00000000 --- a/Test/floats/test17.bpl +++ /dev/null @@ -1,11 +0,0 @@ -//Translation from nan_double_range_true-unreach-call.c -//Should verify -//Uggghhhh, should I add support for e? - -procedure main() returns () { - var x : float(11 53); - havoc x; - if (x >= fp(-100000000000000000000000000 11 53) && x <= fp(100000000000000000000000000 11 53)) { - assert(x==x); - } -} \ No newline at end of file diff --git a/Test/floats/test18.bpl b/Test/floats/test18.bpl deleted file mode 100644 index 71eb5286..00000000 --- a/Test/floats/test18.bpl +++ /dev/null @@ -1,36 +0,0 @@ -//Translation from rlim_exit.c -//Should verify -//Unary - unsupported float operations (on my end)... - -procedure main() returns () { - var X : float; - var Y : float; - var S : float; - var R : float; - var D : float; - var i : int; - - Y := fp(0); - - i := 0; - while (i < 100000) { - havoc X; - havoc D; - assume(X >= fp(-128) && X <= fp(128)); - assume(D >= fp(0) && D <= fp(16)); - - S := Y; - Y := X; - R := X - S; - if (R <= fp(0)-D) { - Y := S - D; - } - else if(R >= D) { - Y := S + D; - } - - i := i + 1; - } - - assert(Y >= fp(-129) && Y <= fp(129)); -} \ No newline at end of file diff --git a/Test/floats/test19.bpl b/Test/floats/test19.bpl deleted file mode 100644 index f00d8a2b..00000000 --- a/Test/floats/test19.bpl +++ /dev/null @@ -1,36 +0,0 @@ -//Translation from flim_invariant.c -//Should verify -//Unary - unsupported float operations (on my end)... - -procedure main() returns () { - var X : float; - var Y : float; - var S : float; - var R : float; - var D : float; - var i : int; - - Y := fp(0); - - i := 0; - while (i < 100000) { - havoc X; - havoc D; - assume(X >= fp(-128) && X <= fp(128)); - assume(D >= fp(0) && D <= fp(16)); - - S := Y; - Y := X; - R := X - S; - if (R <= fp(0)-D) { - Y := S - D; - } - else if(R >= D) { - Y := S + D; - } - - assert(Y >= fp(-129) && Y <= fp(129)); - - i := i + 1; - } -} \ No newline at end of file diff --git a/Test/floats/test2.bpl b/Test/floats/test2.bpl deleted file mode 100644 index d78c339d..00000000 --- a/Test/floats/test2.bpl +++ /dev/null @@ -1,17 +0,0 @@ -//Translation from addsub_float_exact.c -//Should Verify - -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_REAL(real) returns (float32); - -procedure main() returns () { - var x : float32; - var y : float32; - var z : float32; - var r : float32; - x := TO_FLOAT32_REAL(1e7); - y := x + TO_FLOAT32_INT(1); - z := x - TO_FLOAT32_INT(1); - r := y - z; - assert r == TO_FLOAT32_INT(2); -} \ No newline at end of file diff --git a/Test/floats/test20.bpl b/Test/floats/test20.bpl deleted file mode 100644 index 57c605fd..00000000 --- a/Test/floats/test20.bpl +++ /dev/null @@ -1,14 +0,0 @@ -//Should return an error? -//Translation from Rump_double.c - -procedure main() returns () { - var x : float(11 53); - var y : float(11 53); - var r : float(11 53); - - x := fp(77617 11 53); - y := fp(33096 11 53); - r := y*y*y*y*y*y * fp(333.75 11 53) + x*x * (x*x*y*y*fp(11 11 53) - y*y*y*y*y*y - y*y*y*y * fp(121 11 53) - fp(2 11 53)) + y*y*y*y*y*y*y*y * fp(5.5 11 53) + x / (y*fp(2 11 53)); - - assert(r >= fp(0 11 53)); -} \ No newline at end of file diff --git a/Test/floats/test3.bpl b/Test/floats/test3.bpl deleted file mode 100644 index 67c6ba48..00000000 --- a/Test/floats/test3.bpl +++ /dev/null @@ -1,13 +0,0 @@ -//Translation from addsub_float_inexact.c -//Should give an error -procedure main() returns () { - var x : float32; - var y : float32; - var z : float32; - var r : float32; - x := fp<8, 24>(3221225472bv32); - y := x + fp<8, 24>(1bv32); - z := x - fp<8, 24>(1bv32); - r := y - z; - assert r == fp<8, 24>(2bv32); -} \ No newline at end of file diff --git a/Test/floats/test4.bpl b/Test/floats/test4.bpl deleted file mode 100644 index a31aa215..00000000 --- a/Test/floats/test4.bpl +++ /dev/null @@ -1,32 +0,0 @@ -//Translation from drift_tenth.c -//Should Fail - -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_REAL(real) returns (float32); - -procedure main() returns () { - var tick : float32; - var time : float32; - var i: int; - - tick := TO_FLOAT32_INT(1)/TO_FLOAT32_INT(10); - time := TO_FLOAT32_INT(0); - - //i := 0; - //while (i < 10) - //{ - // time := time + tick; - // i := i + 1; - //} - time := time + tick;//1 - time := time + tick;//2 - time := time + tick;//3 - time := time + tick;//4 - time := time + tick;//5 - time := time + tick;//6 - time := time + tick;//7 - time := time + tick;//8 - time := time + tick;//9 - time := time + tick;//10 - assert time == TO_FLOAT32_INT(1); -} \ No newline at end of file diff --git a/Test/floats/test5.bpl b/Test/floats/test5.bpl deleted file mode 100644 index 7536f8fd..00000000 --- a/Test/floats/test5.bpl +++ /dev/null @@ -1,36 +0,0 @@ -//Translation from filter1.c -//Should Verify - -function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_INT(int) returns (float64); -function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_REAL(real) returns (float64); - -procedure main() returns () { - var E0 : float64; - var E1 : float64; - var S : float64); - var i : int; - var rand : int; - - E1 := TO_FLOAT64_INT(0); - S := TO_FLOAT64_INT(0); - - i := 0; - while (i <= 1000000) - { - havoc E0; - assume(E0 >= fp(-1 11 53) && E0 <= fp(1 11 53)); - - havoc rand; - if (rand != 0) { - S := fp(0 11 53); - } - else { - S := fp(0.999 11 53) * S + E0 - E1; - } - E1 := E0; - - //assert(1==0); - assert(S >= fp(-1 11 53) && S <= fp(1 11 53)); - i := i + 1; - } -} \ No newline at end of file diff --git a/Test/floats/test6.bpl b/Test/floats/test6.bpl deleted file mode 100644 index 6bef1137..00000000 --- a/Test/floats/test6.bpl +++ /dev/null @@ -1,40 +0,0 @@ -//Translation from filter2.c -//Should give an error -//FAILS; doesn't generate terms! - -procedure main() returns () { - var E : float(11 53); - var E0 : float(11 53); - var E1 : float(11 53); - var S : float(11 53); - var S0 : float(11 53); - var S1 : float(11 53); - var i: int; - - havoc E; - havoc E0; - assume(E >= fp(0.0 11 53) && E <= fp(1.0 11 53)); - assume(E0 >= fp(0.0 11 53) && E0 <= fp(1.0 11 53)); - - E1 := fp(0.0 11 53); - S1 := fp(0.0 11 53); - S0 := fp(0.0 11 53); - S := fp(0.0 11 53); - - i := 0; -// while (i <= 1000000) -// { - E1 := E0; - E0 := E; - - havoc E; - assume(E >= fp(0.0 11 53) && E <= fp(1.0 11 53)); - - S1 := S0; - S0 := S; - S := E*fp(0.7 11 53) - E0*fp(1.3 11 53) + E1*fp(1.1 11 53) + S0*fp(1.4 11 53) - S1*fp(0.7 11 53); - - assert(S >= fp(-4.0 11 53) && S <= fp(4.0 11 53)); - //i := i + 1; -// } -} \ No newline at end of file diff --git a/Test/floats/test7.bpl b/Test/floats/test7.bpl deleted file mode 100644 index 8e07878d..00000000 --- a/Test/floats/test7.bpl +++ /dev/null @@ -1,38 +0,0 @@ -//Translation from filter2.c -//Should give an error -//Same as the previous one; it works with reals! - -procedure main() returns () { - var E : real; - var E0 : real; - var E1 : real; - var S : real; - var S0 : real; - var S1 : real; - var i: int; - - havoc E; - havoc E0; - assume(E >= 0.0 && E <= 1.0); - assume(E0 >= 0.0 && E0 <= 1.0); - - S0 := 0.0; - S := 0.0; - - i := 0; - while (i <= 1000000) - { - E1 := E0; - E0 := E; - - havoc E; - assume(E >= 0.0 && E <= 1.0); - - S1 := S0; - S0 := S; - S := E*0.7 - E0*1.3 + E1*1.1 + S0*1.4 - S1*0.7; - - assert(S >= -4.0 && S <= 4.0); - i := i + 1; - } -} \ No newline at end of file diff --git a/Test/floats/test8.bpl b/Test/floats/test8.bpl deleted file mode 100644 index 7e78e206..00000000 --- a/Test/floats/test8.bpl +++ /dev/null @@ -1,16 +0,0 @@ -//Translation from float_double.c -//Should Verify - -function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_FLOAT32(float32) returns (float64); -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_FLOAT64(float64) returns (float32); -function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_INT(int) returns (float64); -function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_REAL(real) returns (float64); - -procedure main() returns () { - var x : float64; - var y : float32; - - x := TO_FLOAT64_REAL(1e20)+TO_FLOAT64_INT(1); - y := TO_FLOAT32_FLOAT64(x); - assert x != TO_FLOAT64_FLOAT32(y); -} \ No newline at end of file diff --git a/Test/floats/test9.bpl b/Test/floats/test9.bpl deleted file mode 100644 index c3a42e6b..00000000 --- a/Test/floats/test9.bpl +++ /dev/null @@ -1,34 +0,0 @@ -//Translation from feedback_diverge.c -//Should give an error -//Not sure on this one... - -procedure main() returns () { - var A : float; - var B : float; - var X : float; - var i : int; - var rand : int; - - A := fp(0); - B := fp(0); - - i := 0; - while (i < 3600000) { - - havoc rand; - if (rand != 0) { - havoc X; - assume(X >= fp(-20) && X <= fp(20)); - } - else { - X := B; - } - - B := B - (B * fp(2.0) - A - X) * fp(.005); - A := X; - - i := i + 1; - } - - assert(A >= fp(-100) && A <= fp(100)); -} \ No newline at end of file -- cgit v1.2.3 From 754f7d3ef36e11740a40a2d687f3b15195f63d9a Mon Sep 17 00:00:00 2001 From: Checkmate50 Date: Mon, 6 Jun 2016 21:11:23 -0600 Subject: Polished up the floats test folder. Preparing to rebase --- Test/floats/float11.bpl.expect | 8 ++++---- Test/floats/float13.bpl | 23 ----------------------- Test/floats/float14.bpl | 17 ----------------- Test/floats/float15.bpl | 36 ------------------------------------ Test/floats/float16.bpl | 40 ---------------------------------------- Test/floats/float17.bpl | 38 -------------------------------------- Test/floats/float18.bpl | 16 ---------------- Test/floats/float19.bpl | 34 ---------------------------------- Test/floats/float20.bpl | 14 -------------- Test/floats/float21.bpl | 35 ----------------------------------- Test/floats/float22.bpl | 20 -------------------- Test/floats/float23.bpl | 8 -------- Test/floats/modpath.py | 13 ------------- 13 files changed, 4 insertions(+), 298 deletions(-) delete mode 100644 Test/floats/float13.bpl delete mode 100644 Test/floats/float14.bpl delete mode 100644 Test/floats/float15.bpl delete mode 100644 Test/floats/float16.bpl delete mode 100644 Test/floats/float17.bpl delete mode 100644 Test/floats/float18.bpl delete mode 100644 Test/floats/float19.bpl delete mode 100644 Test/floats/float20.bpl delete mode 100644 Test/floats/float21.bpl delete mode 100644 Test/floats/float22.bpl delete mode 100644 Test/floats/float23.bpl delete mode 100644 Test/floats/modpath.py diff --git a/Test/floats/float11.bpl.expect b/Test/floats/float11.bpl.expect index 19e55fef..9365da58 100644 --- a/Test/floats/float11.bpl.expect +++ b/Test/floats/float11.bpl.expect @@ -1,7 +1,7 @@ -..\Test\floats\float11.bpl(21,2): Error BP5001: This assertion might not hold. +float11.bpl(21,2): Error BP5001: This assertion might not hold. Execution trace: - ..\Test\floats\float11.bpl(12,7): anon0 - ..\Test\floats\float11.bpl(16,2): anon3_LoopHead - ..\Test\floats\float11.bpl(16,2): anon3_LoopDone + float11.bpl(12,7): anon0 + float11.bpl(16,2): anon3_LoopHead + float11.bpl(16,2): anon3_LoopDone Boogie program verifier finished with 0 verified, 1 error diff --git a/Test/floats/float13.bpl b/Test/floats/float13.bpl deleted file mode 100644 index 4fe25140..00000000 --- a/Test/floats/float13.bpl +++ /dev/null @@ -1,23 +0,0 @@ -// RUN: %boogie -proverWarnings:1 "%s" > "%t" -// RUN: %diff "%s.expect" "%t" - -function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_INT(int) returns (float64); -function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_REAL(real) returns (float64); - -procedure main() returns () { - var x : float64; - var y : float64; - - havoc x; - assume(x >= TO_FLOAT64_INT(0) && x <= TO_FLOAT64_INT(10)); - - y := x*x - x; - if (y >= TO_FLOAT64_INT(0)) { - y := x / TO_FLOAT64_INT(10); - } - else { - y := x*x + TO_FLOAT64_INT(2); - } - - assert(y >= TO_FLOAT64_INT(0) && y <= TO_FLOAT64_INT(105)); -} \ No newline at end of file diff --git a/Test/floats/float14.bpl b/Test/floats/float14.bpl deleted file mode 100644 index 46c1b07d..00000000 --- a/Test/floats/float14.bpl +++ /dev/null @@ -1,17 +0,0 @@ -// RUN: %boogie -proverWarnings:1 "%s" > "%t" -// RUN: %diff "%s.expect" "%t" - -function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_INT(int) returns (float64); -function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_REAL(real) returns (float64); - -procedure main() returns () { - var x : float64; - var y : float64; - var r : float64; - - x := TO_FLOAT64_INT(77617); - y := TO_FLOAT64_INT(33096); - r := y*y*y*y*y*y * TO_FLOAT64_REAL(333.75) + x*x * (x*x*y*y*TO_FLOAT64_INT(11) - y*y*y*y*y*y - y*y*y*y * TO_FLOAT64_INT(121) - TO_FLOAT64_INT(2)) + y*y*y*y*y*y*y*y * TO_FLOAT64_REAL(5.5) + x / (y*TO_FLOAT64_INT(2)); - - assert(r >= TO_FLOAT64_INT(0)); -} \ No newline at end of file diff --git a/Test/floats/float15.bpl b/Test/floats/float15.bpl deleted file mode 100644 index 7536f8fd..00000000 --- a/Test/floats/float15.bpl +++ /dev/null @@ -1,36 +0,0 @@ -//Translation from filter1.c -//Should Verify - -function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_INT(int) returns (float64); -function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_REAL(real) returns (float64); - -procedure main() returns () { - var E0 : float64; - var E1 : float64; - var S : float64); - var i : int; - var rand : int; - - E1 := TO_FLOAT64_INT(0); - S := TO_FLOAT64_INT(0); - - i := 0; - while (i <= 1000000) - { - havoc E0; - assume(E0 >= fp(-1 11 53) && E0 <= fp(1 11 53)); - - havoc rand; - if (rand != 0) { - S := fp(0 11 53); - } - else { - S := fp(0.999 11 53) * S + E0 - E1; - } - E1 := E0; - - //assert(1==0); - assert(S >= fp(-1 11 53) && S <= fp(1 11 53)); - i := i + 1; - } -} \ No newline at end of file diff --git a/Test/floats/float16.bpl b/Test/floats/float16.bpl deleted file mode 100644 index 6bef1137..00000000 --- a/Test/floats/float16.bpl +++ /dev/null @@ -1,40 +0,0 @@ -//Translation from filter2.c -//Should give an error -//FAILS; doesn't generate terms! - -procedure main() returns () { - var E : float(11 53); - var E0 : float(11 53); - var E1 : float(11 53); - var S : float(11 53); - var S0 : float(11 53); - var S1 : float(11 53); - var i: int; - - havoc E; - havoc E0; - assume(E >= fp(0.0 11 53) && E <= fp(1.0 11 53)); - assume(E0 >= fp(0.0 11 53) && E0 <= fp(1.0 11 53)); - - E1 := fp(0.0 11 53); - S1 := fp(0.0 11 53); - S0 := fp(0.0 11 53); - S := fp(0.0 11 53); - - i := 0; -// while (i <= 1000000) -// { - E1 := E0; - E0 := E; - - havoc E; - assume(E >= fp(0.0 11 53) && E <= fp(1.0 11 53)); - - S1 := S0; - S0 := S; - S := E*fp(0.7 11 53) - E0*fp(1.3 11 53) + E1*fp(1.1 11 53) + S0*fp(1.4 11 53) - S1*fp(0.7 11 53); - - assert(S >= fp(-4.0 11 53) && S <= fp(4.0 11 53)); - //i := i + 1; -// } -} \ No newline at end of file diff --git a/Test/floats/float17.bpl b/Test/floats/float17.bpl deleted file mode 100644 index 8e07878d..00000000 --- a/Test/floats/float17.bpl +++ /dev/null @@ -1,38 +0,0 @@ -//Translation from filter2.c -//Should give an error -//Same as the previous one; it works with reals! - -procedure main() returns () { - var E : real; - var E0 : real; - var E1 : real; - var S : real; - var S0 : real; - var S1 : real; - var i: int; - - havoc E; - havoc E0; - assume(E >= 0.0 && E <= 1.0); - assume(E0 >= 0.0 && E0 <= 1.0); - - S0 := 0.0; - S := 0.0; - - i := 0; - while (i <= 1000000) - { - E1 := E0; - E0 := E; - - havoc E; - assume(E >= 0.0 && E <= 1.0); - - S1 := S0; - S0 := S; - S := E*0.7 - E0*1.3 + E1*1.1 + S0*1.4 - S1*0.7; - - assert(S >= -4.0 && S <= 4.0); - i := i + 1; - } -} \ No newline at end of file diff --git a/Test/floats/float18.bpl b/Test/floats/float18.bpl deleted file mode 100644 index 7e78e206..00000000 --- a/Test/floats/float18.bpl +++ /dev/null @@ -1,16 +0,0 @@ -//Translation from float_double.c -//Should Verify - -function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_FLOAT32(float32) returns (float64); -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_FLOAT64(float64) returns (float32); -function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_INT(int) returns (float64); -function {:builtin "(_ to_fp 11 53) RNE"} TO_FLOAT64_REAL(real) returns (float64); - -procedure main() returns () { - var x : float64; - var y : float32; - - x := TO_FLOAT64_REAL(1e20)+TO_FLOAT64_INT(1); - y := TO_FLOAT32_FLOAT64(x); - assert x != TO_FLOAT64_FLOAT32(y); -} \ No newline at end of file diff --git a/Test/floats/float19.bpl b/Test/floats/float19.bpl deleted file mode 100644 index c3a42e6b..00000000 --- a/Test/floats/float19.bpl +++ /dev/null @@ -1,34 +0,0 @@ -//Translation from feedback_diverge.c -//Should give an error -//Not sure on this one... - -procedure main() returns () { - var A : float; - var B : float; - var X : float; - var i : int; - var rand : int; - - A := fp(0); - B := fp(0); - - i := 0; - while (i < 3600000) { - - havoc rand; - if (rand != 0) { - havoc X; - assume(X >= fp(-20) && X <= fp(20)); - } - else { - X := B; - } - - B := B - (B * fp(2.0) - A - X) * fp(.005); - A := X; - - i := i + 1; - } - - assert(A >= fp(-100) && A <= fp(100)); -} \ No newline at end of file diff --git a/Test/floats/float20.bpl b/Test/floats/float20.bpl deleted file mode 100644 index 57c605fd..00000000 --- a/Test/floats/float20.bpl +++ /dev/null @@ -1,14 +0,0 @@ -//Should return an error? -//Translation from Rump_double.c - -procedure main() returns () { - var x : float(11 53); - var y : float(11 53); - var r : float(11 53); - - x := fp(77617 11 53); - y := fp(33096 11 53); - r := y*y*y*y*y*y * fp(333.75 11 53) + x*x * (x*x*y*y*fp(11 11 53) - y*y*y*y*y*y - y*y*y*y * fp(121 11 53) - fp(2 11 53)) + y*y*y*y*y*y*y*y * fp(5.5 11 53) + x / (y*fp(2 11 53)); - - assert(r >= fp(0 11 53)); -} \ No newline at end of file diff --git a/Test/floats/float21.bpl b/Test/floats/float21.bpl deleted file mode 100644 index 5fad5859..00000000 --- a/Test/floats/float21.bpl +++ /dev/null @@ -1,35 +0,0 @@ -// RUN: %boogie -proverWarnings:1 "%s" > "%t" -// RUN: %diff "%s.expect" "%t" - -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_REAL(real) returns (float32); - -procedure main() returns () { - var x : float32; - var y : float32; - var z : float32; - - havoc x; - assume(x >= TO_FLOAT32_INT(-1) && x <= TO_FLOAT32_INT(1)); - - if (x != TO_FLOAT32_INT(0)) { - y := x * x; - assert(y != TO_FLOAT32_INT(0)); - z := TO_FLOAT32_INT(1) / y; - } -} - -procedure main() returns () { - var x : float32; - var y : float32; - var z : float32; - - havoc x; - assume(x >= TO_FLOAT32_INT(-1) && x <= TO_FLOAT32_INT(1)); - - if (x <= TO_FLOAT32_REAL(-1e-20) || x >= TO_FLOAT32_REAL(1e-20)) { - y := x * x; - assert(y != TO_FLOAT32_INT(0)); - z := TO_FLOAT32_INT(1) / y; - } -} \ No newline at end of file diff --git a/Test/floats/float22.bpl b/Test/floats/float22.bpl deleted file mode 100644 index 1505c361..00000000 --- a/Test/floats/float22.bpl +++ /dev/null @@ -1,20 +0,0 @@ -//Translation from inv_square_true-unreach-call.c -//Should Verify - -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_INT(int) returns (float32); -function {:builtin "(_ to_fp 8 24) RNE"} TO_FLOAT32_REAL(real) returns (float32); - -procedure main() returns () { - var x : float32; - var y : float32; - var z : float32; - - havoc x; - assume(x >= TO_FLOAT32_INT(-1) && x <= TO_FLOAT32_INT(1)); - - if (x <= TO_FLOAT32_REAL(-1e-20) || x >= TO_FLOAT32_REAL(1e-20)) { - y := x * x; - assert(y != TO_FLOAT32_INT(0)); - z := TO_FLOAT32_INT(1) / y; - } -} \ No newline at end of file diff --git a/Test/floats/float23.bpl b/Test/floats/float23.bpl deleted file mode 100644 index 69ae243d..00000000 --- a/Test/floats/float23.bpl +++ /dev/null @@ -1,8 +0,0 @@ -//Translation from nan_double_false-unreach-call.c -//Should return an error - -procedure main() returns () { - var x : float(11 53); - havoc x; - assert(x==x); -} \ No newline at end of file diff --git a/Test/floats/modpath.py b/Test/floats/modpath.py deleted file mode 100644 index 90707701..00000000 --- a/Test/floats/modpath.py +++ /dev/null @@ -1,13 +0,0 @@ -import sys - -f = open(sys.argv[1], 'r') -to_write = "" - -for i in f: - to_write += i.replace("..\\Test\\floats\\", "") - -f.close() - -f = open(sys.argv[1], 'w') - -f.write(to_write) \ No newline at end of file -- cgit v1.2.3 From 29544b322eec0a0e630e2c7f8fe472793cf8f405 Mon Sep 17 00:00:00 2001 From: Checkmate50 Date: Mon, 6 Jun 2016 21:17:59 -0600 Subject: removed an unnecessary text file --- fp_documentation.txt | 88 ---------------------------------------------------- 1 file changed, 88 deletions(-) delete mode 100644 fp_documentation.txt diff --git a/fp_documentation.txt b/fp_documentation.txt deleted file mode 100644 index d3fafdcb..00000000 --- a/fp_documentation.txt +++ /dev/null @@ -1,88 +0,0 @@ -Floating Point Documentation for Boogie -Written by Dietrich Geisler -Contact: dgeisler50@gmail.com - -This document aims to describe the syntax for declaring and using floating points in Boogie - --------------------------------------------------------------------------------- -Declaring Variables: - -The syntax for declaring a floating point variable is as follows: -var name: float(exp man); -Where exp is the size of the float exponent and man is the size of the float mantissa -Please note that - -**REMOVE THIS SYNTAX** -It is also acceptable to use the following syntax: -var name: float(); -This syntax assumes the float exponent to be size 8 and the mantissa to be size 24 - -example: -var x: float(11 53) -Declares a variable called x with a exponent sized 11 and mantissa sized 53 - --------------------------------------------------------------------------------- -Declaring Constants: - -All of the following syntax are viable for declaring a floating point constant: -**REMOVE THE FIRST OF THESE TWO SYNTAXES** -fp(dec) -fp(exp_val man_val) -fp(dec exp man) -fp(exp_val man_val exp man) - -Where dec is the decimal value of the constant, -exp_val/man_value are the integer values of their respective fields, -And exp/man are the sizes of their respective fields. -Note that when exp and man are not specified, they are given sizes 8 and 24 respectively - --------------------------------------------------------------------------------- -Defined Operations: - -Given two floating point values x and y with the same size of exponent and mantissa -The following operations operate as defined in Operators section of this document: -http://smtlib.cs.uiowa.edu/theories-FloatingPoint.shtml -(Note that rounding mode is always assumed to be Round to Nearest Even (RNE)) -(Also note that operations not listed here are undefined) - -operatation boogie syntax -neg(x) -x -add(x, y) x + y -sub(x, y) x - y -mul(x, y) x * y -div(x, y) x / y -leq(x, y) x <= y -lt(x, y) x < y -geq(x, y) x >= y -gt(x, y) x > y -eq(x, y) x == y - --------------------------------------------------------------------------------- -Other: - -The following special values can be declared with the following syntax: -Value Declaration -NaN fp(nan exp man) -+oo fp(oo exp man) OR fp(INF exp man) --oo fp(-oo exp man) OR fp(INF exp man) --zero fp(-zero exp man) -Where exp and man are the sizes of the exponent and mantissa respectively - --------------------------------------------------------------------------------- -Known Issues: - -float16, float32, float64, and float128 still need to be added - -There is currently no way to convert from a floating point to any other data type - -There is currently no way to convert the value of a variable to a floating point type -For example, the following statements fails: -var x : real; -fp(x); - -Statements of the following form cause a parser error (parenthesis followed by fp constant) -... (fp(1) + fp(1)); - -Attempts by Boogie to infer the behavior of loops fail when floating points are involved - -Describing loop behavior manually is untested (using loop unroll appears to work) \ No newline at end of file -- cgit v1.2.3 From d7fc0deb2ca6d7ebee094b6ea5430d9b41f163ec Mon Sep 17 00:00:00 2001 From: Checkmate50 Date: Mon, 6 Jun 2016 23:09:10 -0600 Subject: spacing change --- Test/z3api/bar1.bpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/z3api/bar1.bpl b/Test/z3api/bar1.bpl index 22d87f90..845954d5 100644 --- a/Test/z3api/bar1.bpl +++ b/Test/z3api/bar1.bpl @@ -1,4 +1,4 @@ - var x: int; +var x: int; var y: int; procedure {:inline 1} bar() -- cgit v1.2.3 From d652155ae013f36a1ee17653a8e458baad2d9c2c Mon Sep 17 00:00:00 2001 From: Checkmate50 Date: Mon, 6 Jun 2016 23:14:18 -0600 Subject: Merging complete. Everything looks good *crosses fingers* --- .gitattributes | 42 + .travis.yml | 16 +- Binaries/PrepareBoogieZip.bat | 32 +- Build/CodePlex.Tools.MsBuild.dll | Bin 131072 -> 0 bytes Build/CodePlex.Tools.Wiki.dll | Bin 45056 -> 0 bytes Build/updateVersionFile.xml | 19 - README.md | 21 +- Source/AIFramework/AIFramework.csproj | 406 +- Source/AIFramework/CommonFunctionSymbols.cs | 2464 +- Source/AIFramework/Expr.cs | 1280 +- Source/AIFramework/Functional.cs | 860 +- Source/AIFramework/Lattice.cs | 1918 +- Source/AIFramework/Logger.cs | 112 +- Source/AIFramework/MultiLattice.cs | 1294 +- Source/AIFramework/Mutable.cs | 274 +- Source/AIFramework/Polyhedra/LinearConstraint.cs | 1088 +- .../Polyhedra/LinearConstraintSystem.cs | 3510 +- .../AIFramework/Polyhedra/PolyhedraAbstraction.cs | 1524 +- Source/AIFramework/Polyhedra/SimplexTableau.cs | 1260 +- .../AIFramework/VariableMap/ConstantAbstraction.cs | 502 +- .../AIFramework/VariableMap/ConstantExpressions.cs | 1056 +- .../AIFramework/VariableMap/DynamicTypeLattice.cs | 1022 +- Source/AIFramework/VariableMap/Intervals.cs | 1742 +- Source/AIFramework/VariableMap/MicroLattice.cs | 208 +- Source/AIFramework/VariableMap/Nullness.cs | 520 +- .../AIFramework/VariableMap/VariableMapLattice.cs | 1708 +- Source/AIFramework/cce.cs | 384 +- Source/AbsInt/AbsInt.csproj | 590 +- Source/AbsInt/IntervalDomain.cs | 2428 +- Source/AbsInt/NativeLattice.cs | 670 +- Source/AbsInt/Traverse.cs | 338 +- Source/AbsInt/TrivialDomain.cs | 158 +- Source/AbsInt/cce.cs | 124 +- Source/BVD/App.config | 10 +- Source/BVD/BVD.csproj | 212 +- Source/BVD/Program.cs | 56 +- Source/BVD/Properties/AssemblyInfo.cs | 72 +- Source/Basetypes/Basetypes.csproj | 406 +- Source/Basetypes/BigDec.cs | 760 +- Source/Basetypes/BigNum.cs | 722 +- Source/Basetypes/Rational.cs | 496 +- Source/Basetypes/Set.cs | 570 +- Source/Basetypes/cce.cs | 384 +- Source/Boogie.sln | 1286 +- Source/BoogieDriver/BoogieDriver.cs | 212 +- Source/BoogieDriver/BoogieDriver.csproj | 646 +- Source/BoogieDriver/cce.cs | 210 +- .../CodeContractsExtender.csproj | 404 +- Source/CodeContractsExtender/cce.cs | 366 +- Source/Concurrency/App.config | 12 +- Source/Concurrency/CivlRefinement.cs | 1230 + Source/Concurrency/CivlTypeChecker.cs | 1160 + Source/Concurrency/Concurrency.csproj | 228 +- Source/Concurrency/LinearSets.cs | 2007 +- Source/Concurrency/MoverCheck.cs | 1320 +- Source/Concurrency/OwickiGries.cs | 1188 - Source/Concurrency/Program.cs | 88 +- Source/Concurrency/Properties/AssemblyInfo.cs | 72 +- Source/Concurrency/SimulationRelation.cs | 394 +- Source/Concurrency/TypeCheck.cs | 724 - Source/Concurrency/YieldTypeChecker.cs | 731 +- Source/Core/Absy.cs | 8985 +- Source/Core/AbsyCmd.cs | 6996 +- Source/Core/AbsyExpr.cs | 6671 +- Source/Core/AbsyQuant.cs | 1883 +- Source/Core/AbsyType.cs | 7812 +- Source/Core/AlphaEquality.cs | 324 +- Source/Core/BoogiePL.atg | 3022 +- Source/Core/CommandLineOptions.cs | 4328 +- Source/Core/Core.csproj | 470 +- Source/Core/DeadVarElim.cs | 3513 +- Source/Core/Duplicator.cs | 1623 +- Source/Core/Graph.as | 352 - Source/Core/Inline.cs | 1538 +- Source/Core/InterProceduralReachabilityGraph.cs | 612 +- Source/Core/LambdaHelper.cs | 518 +- Source/Core/LoopUnroll.cs | 572 +- Source/Core/Makefile | 40 +- Source/Core/OOLongUtil.cs | 420 +- Source/Core/Parser.cs | 4848 +- Source/Core/Readme.txt | 122 +- Source/Core/ResolutionContext.cs | 1270 +- Source/Core/Scanner.cs | 1644 +- Source/Core/StandardVisitor.cs | 2334 +- Source/Core/TypeAmbiguitySeeker.cs | 244 +- Source/Core/Util.cs | 1376 +- Source/Core/VCExp.cs | 476 +- Source/Core/VariableDependenceAnalyser.cs | 1292 +- Source/Core/Xml.cs | 630 +- Source/Core/cce.cs | 384 +- Source/Doomed/DoomCheck.cs | 814 +- Source/Doomed/DoomErrorHandler.cs | 170 +- Source/Doomed/Doomed.csproj | 378 +- Source/Doomed/DoomedLoopUnrolling.cs | 1298 +- Source/Doomed/DoomedStrategy.cs | 1054 +- Source/Doomed/HasseDiagram.cs | 846 +- Source/Doomed/VCDoomed.cs | 1652 +- Source/ExecutionEngine/ExecutionEngine.cs | 3586 +- Source/ExecutionEngine/ExecutionEngine.csproj | 386 +- Source/ExecutionEngine/Properties/AssemblyInfo.cs | 72 +- Source/ExecutionEngine/VerificationResultCache.cs | 1332 +- Source/Forro.sln | 40 +- Source/Forro/Ast.fs | 76 +- Source/Forro/BoogieAst.fs | 80 +- Source/Forro/BoogiePrinter.fs | 224 +- Source/Forro/Forro.fsproj | 164 +- Source/Forro/Lexer.fsl | 120 +- Source/Forro/Main.fs | 114 +- Source/Forro/Parser.fsy | 244 +- Source/Forro/Printer.fs | 214 +- Source/Forro/Resolver.fs | 246 +- Source/Forro/Translator.fs | 434 +- Source/Graph/Graph.cs | 2894 +- Source/Graph/Graph.csproj | 398 +- Source/Graph/cce.cs | 384 +- Source/Houdini/AbstractHoudini.cs | 9323 +- Source/Houdini/AnnotationDependenceAnalyser.cs | 1756 +- Source/Houdini/Checker.cs | 911 +- Source/Houdini/ConcurrentHoudini.cs | 208 +- Source/Houdini/Houdini.cs | 2658 +- Source/Houdini/Houdini.csproj | 306 +- Source/Houdini/StagedHoudini.cs | 854 +- Source/Model/Model.cs | 1412 +- Source/Model/Model.csproj | 218 +- Source/Model/ModelParser.cs | 4 +- Source/Model/Properties/AssemblyInfo.cs | 46 +- Source/ModelViewer/BCTProvider.cs | 294 +- Source/ModelViewer/BaseProvider.cs | 272 +- Source/ModelViewer/DafnyProvider.cs | 776 +- Source/ModelViewer/DataModel.cs | 594 +- Source/ModelViewer/Main.Designer.cs | 998 +- Source/ModelViewer/Main.cs | 1740 +- Source/ModelViewer/Main.resx | 4382 +- Source/ModelViewer/ModelViewer.csproj | 422 +- Source/ModelViewer/Namer.cs | 1160 +- Source/ModelViewer/Properties/AssemblyInfo.cs | 50 +- .../ModelViewer/Properties/Resources.Designer.cs | 126 +- Source/ModelViewer/Properties/Resources.resx | 232 +- Source/ModelViewer/Properties/Settings.Designer.cs | 52 +- Source/ModelViewer/Properties/Settings.settings | 14 +- Source/ModelViewer/SourceView.Designer.cs | 124 +- Source/ModelViewer/SourceView.cs | 104 +- Source/ModelViewer/SourceView.resx | 238 +- Source/ModelViewer/TreeSkeleton.cs | 410 +- Source/ModelViewer/VccProvider.cs | 3052 +- Source/ParserHelper/ParserHelper.cs | 486 +- Source/ParserHelper/ParserHelper.csproj | 284 +- Source/Predication/Predication.csproj | 348 +- Source/Predication/SmartBlockPredicator.cs | 1274 +- Source/Predication/UniformityAnalyser.cs | 1082 +- Source/Provers/SMTLib/CVC4.cs | 142 +- Source/Provers/SMTLib/Inspector.cs | 314 +- Source/Provers/SMTLib/ProverInterface.cs | 5075 +- Source/Provers/SMTLib/SExpr.cs | 526 +- Source/Provers/SMTLib/SMTLib.csproj | 474 +- Source/Provers/SMTLib/SMTLibLineariser.cs | 1885 +- Source/Provers/SMTLib/SMTLibNamer.cs | 289 +- Source/Provers/SMTLib/SMTLibProcess.cs | 787 +- Source/Provers/SMTLib/SMTLibProverOptions.cs | 316 +- Source/Provers/SMTLib/TypeDeclCollector.cs | 803 +- Source/Provers/SMTLib/Z3.cs | 772 +- Source/Provers/SMTLib/cce.cs | 384 +- Source/Provers/TPTP/ProverInterface.cs | 702 +- Source/Provers/TPTP/TPTP.csproj | 260 +- Source/Provers/TPTP/TPTPLineariser.cs | 1480 +- Source/Provers/TPTP/TypeDeclCollector.cs | 270 +- Source/Provers/Z3api/ContextLayer.cs | 1454 +- Source/Provers/Z3api/ProverLayer.cs | 706 +- Source/Provers/Z3api/SafeContext.cs | 30 +- Source/Provers/Z3api/StubContext.cs | 148 +- Source/Provers/Z3api/TypeAdapter.cs | 392 +- Source/Provers/Z3api/VCExprVisitor.cs | 1298 +- Source/Provers/Z3api/Z3api.csproj | 376 +- Source/Provers/Z3api/cce.cs | 384 +- .../UnitTests/BasetypesTests/BasetypesTests.csproj | 136 +- .../BasetypesTests/Properties/AssemblyInfo.cs | 72 +- Source/UnitTests/BasetypesTests/packages.config | 6 +- Source/UnitTests/CoreTests/CoreTests.csproj | 166 +- Source/UnitTests/CoreTests/Duplicator.cs | 8 +- .../UnitTests/CoreTests/Properties/AssemblyInfo.cs | 72 +- Source/UnitTests/CoreTests/packages.config | 6 +- .../UnitTests/TestUtil/Properties/AssemblyInfo.cs | 72 +- Source/UnitTests/TestUtil/TestUtil.csproj | 140 +- Source/UnitTests/TestUtil/packages.config | 6 +- Source/VCExpr/BigLiteralAbstracter.cs | 462 +- Source/VCExpr/Boogie2VCExpr.cs | 2478 +- Source/VCExpr/Clustering.cs | 1042 +- Source/VCExpr/LetBindingSorter.cs | 322 +- Source/VCExpr/NameClashResolver.cs | 392 +- Source/VCExpr/SimplifyLikeLineariser.cs | 2444 +- Source/VCExpr/TermFormulaFlattening.cs | 494 +- Source/VCExpr/TypeErasure.cs | 3420 +- Source/VCExpr/TypeErasureArguments.cs | 1506 +- Source/VCExpr/TypeErasurePremisses.cs | 2674 +- Source/VCExpr/VCExpr.csproj | 446 +- Source/VCExpr/VCExprAST.cs | 4536 +- Source/VCExpr/VCExprASTPrinter.cs | 864 +- Source/VCExpr/VCExprASTVisitors.cs | 3360 +- Source/VCExpr/cce.cs | 384 +- Source/VCGeneration/Check.cs | 1381 +- Source/VCGeneration/ConditionGeneration.cs | 4026 +- Source/VCGeneration/Context.cs | 510 +- Source/VCGeneration/ExprExtensions.cs | 706 +- Source/VCGeneration/FixedpointVC.cs | 4474 +- Source/VCGeneration/OrderingAxioms.cs | 676 +- Source/VCGeneration/RPFP.cs | 1218 +- Source/VCGeneration/StratifiedVC.cs | 5820 +- Source/VCGeneration/VC.cs | 8027 +- Source/VCGeneration/VCGeneration.csproj | 448 +- Source/VCGeneration/Wlp.cs | 530 +- Source/VCGeneration/cce.cs | 210 +- Source/version.cs | 8 +- Source/version.ssc | 12 - Test/AbsHoudini/Answer | 978 +- Test/AbsHoudini/f1.bpl | 64 +- Test/AbsHoudini/fail1.bpl | 36 +- Test/AbsHoudini/houd1.bpl | 38 +- Test/AbsHoudini/houd10.bpl | 48 +- Test/AbsHoudini/houd11.bpl | 30 +- Test/AbsHoudini/houd12.bpl | 120 +- Test/AbsHoudini/houd2.bpl | 58 +- Test/AbsHoudini/houd3.bpl | 58 +- Test/AbsHoudini/houd4.bpl | 58 +- Test/AbsHoudini/houd5.bpl | 62 +- Test/AbsHoudini/houd6.bpl | 92 +- Test/AbsHoudini/houd7.bpl | 74 +- Test/AbsHoudini/houd8.bpl | 62 +- Test/AbsHoudini/imp1.bpl | 42 +- Test/AbsHoudini/int1.bpl | 52 +- Test/AbsHoudini/multi.bpl | 134 +- Test/AbsHoudini/pred1.bpl | 50 +- Test/AbsHoudini/pred2.bpl | 28 +- Test/AbsHoudini/pred3.bpl | 52 +- Test/AbsHoudini/pred4.bpl | 46 +- Test/AbsHoudini/pred5.bpl | 52 +- Test/AbsHoudini/quant1.bpl | 18 +- Test/AbsHoudini/quant2.bpl | 52 +- Test/AbsHoudini/quant3.bpl | 18 +- Test/AbsHoudini/quant4.bpl | 18 +- Test/AbsHoudini/quant5.bpl | 26 +- Test/AbsHoudini/runtest.bat | 56 +- Test/AbsHoudini/test1.bpl | 80 +- Test/AbsHoudini/test10.bpl | 104 +- Test/AbsHoudini/test2.bpl | 84 +- Test/AbsHoudini/test7.bpl | 42 +- Test/AbsHoudini/test8.bpl | 54 +- Test/AbsHoudini/test9.bpl | 184 +- Test/README.md | 348 +- Test/aitest0/Intervals.bpl | 683 +- Test/aitest0/Intervals.bpl.expect | 2 +- Test/aitest0/Issue25.bpl | 14 + Test/aitest0/Issue25.bpl.expect | 8 + Test/aitest0/constants.bpl | 142 +- Test/aitest1/Bound.bpl | 60 +- Test/aitest1/Linear0.bpl | 24 +- Test/aitest1/Linear1.bpl | 26 +- Test/aitest1/Linear2.bpl | 26 +- Test/aitest1/Linear3.bpl | 26 +- Test/aitest1/Linear4.bpl | 38 +- Test/aitest1/Linear5.bpl | 50 +- Test/aitest1/Linear6.bpl | 46 +- Test/aitest1/Linear7.bpl | 42 +- Test/aitest1/Linear8.bpl | 88 +- Test/aitest1/Linear9.bpl | 62 +- Test/aitest1/ineq.bpl | 166 +- Test/aitest9/TestIntervals.bpl | 144 +- Test/aitest9/VarMapFixpoint.bpl | 120 +- Test/bitvectors/arrays.bpl | 84 +- Test/bitvectors/bv0.bpl | 30 +- Test/bitvectors/bv1.bpl | 38 +- Test/bitvectors/bv10.bpl | 24 +- Test/bitvectors/bv2.bpl | 26 +- Test/bitvectors/bv3.bpl | 10 +- Test/bitvectors/bv4.bpl | 50 +- Test/bitvectors/bv5.bpl | 26 +- Test/bitvectors/bv6.bpl | 22 +- Test/bitvectors/bv7.bpl | 22 +- Test/bitvectors/bv8.bpl | 50 +- Test/bitvectors/bv9.bpl | 50 +- Test/civl/DeviceCache.bpl | 210 + Test/civl/DeviceCache.bpl.expect | 2 + Test/civl/FlanaganQadeer.bpl | 75 + Test/civl/FlanaganQadeer.bpl.expect | 2 + Test/civl/Program1.bpl | 33 + Test/civl/Program1.bpl.expect | 2 + Test/civl/Program2.bpl | 37 + Test/civl/Program2.bpl.expect | 2 + Test/civl/Program3.bpl | 36 + Test/civl/Program3.bpl.expect | 2 + Test/civl/Program4.bpl | 139 + Test/civl/Program4.bpl.expect | 2 + Test/civl/Program5.bpl | 84 + Test/civl/Program5.bpl.expect | 2 + Test/civl/StoreBuffer.bpl | 187 + Test/civl/StoreBuffer.bpl.expect | 2 + Test/civl/akash.bpl | 106 + Test/civl/akash.bpl.expect | 2 + Test/civl/alloc.bpl | 175 + Test/civl/alloc.bpl.expect | 2 + Test/civl/bar.bpl | 57 + Test/civl/bar.bpl.expect | 13 + Test/civl/chris.bpl | 28 + Test/civl/chris.bpl.expect | 2 + Test/civl/chris2.bpl | 34 + Test/civl/chris2.bpl.expect | 18 + Test/civl/chris3.bpl | 19 + Test/civl/chris3.bpl.expect | 2 + Test/civl/chris4.bpl | 16 + Test/civl/chris4.bpl.expect | 5 + Test/civl/chris5.bpl | 19 + Test/civl/chris5.bpl.expect | 7 + Test/civl/chris6.bpl | 14 + Test/civl/chris6.bpl.expect | 5 + Test/civl/chris7.bpl | 14 + Test/civl/chris7.bpl.expect | 2 + Test/civl/chris8.bpl | 15 + Test/civl/chris8.bpl.expect | 2 + Test/civl/civl-paper.bpl | 175 + Test/civl/civl-paper.bpl.expect | 2 + Test/civl/foo.bpl | 57 + Test/civl/foo.bpl.expect | 8 + Test/civl/funky.bpl | 133 + Test/civl/funky.bpl.expect | 2 + Test/civl/ghost.bpl | 45 + Test/civl/ghost.bpl.expect | 2 + Test/civl/linear-set.bpl | 105 + Test/civl/linear-set.bpl.expect | 2 + Test/civl/linear-set2.bpl | 106 + Test/civl/linear-set2.bpl.expect | 2 + Test/civl/lock-introduced.bpl | 110 + Test/civl/lock-introduced.bpl.expect | 2 + Test/civl/lock.bpl | 57 + Test/civl/lock.bpl.expect | 2 + Test/civl/lock2.bpl | 63 + Test/civl/lock2.bpl.expect | 2 + Test/civl/multiset.bpl | 324 + Test/civl/multiset.bpl.expect | 2 + Test/civl/new1.bpl | 42 + Test/civl/new1.bpl.expect | 2 + Test/civl/nocollector.bpl | 8 + Test/civl/nocollector.bpl.expect | 2 + Test/civl/one.bpl | 18 + Test/civl/one.bpl.expect | 2 + Test/civl/par-incr.bpl | 31 + Test/civl/par-incr.bpl.expect | 2 + Test/civl/parallel1.bpl | 48 + Test/civl/parallel1.bpl.expect | 8 + Test/civl/parallel2.bpl | 59 + Test/civl/parallel2.bpl.expect | 2 + Test/civl/parallel4.bpl | 45 + Test/civl/parallel4.bpl.expect | 6 + Test/civl/parallel5.bpl | 59 + Test/civl/parallel5.bpl.expect | 2 + Test/civl/perm.bpl | 49 + Test/civl/perm.bpl.expect | 2 + Test/civl/t1.bpl | 103 + Test/civl/t1.bpl.expect | 9 + Test/civl/termination.bpl | 18 + Test/civl/termination.bpl.expect | 3 + Test/civl/termination2.bpl | 19 + Test/civl/termination2.bpl.expect | 2 + Test/civl/ticket.bpl | 146 + Test/civl/ticket.bpl.expect | 2 + Test/civl/treiber-stack.bpl | 207 + Test/civl/treiber-stack.bpl.expect | 2 + Test/civl/wsq.bpl | 544 + Test/civl/wsq.bpl.expect | 2 + Test/codeexpr/CodeExpr0.bpl | 110 +- Test/codeexpr/CodeExpr1.bpl | 138 +- Test/codeexpr/CodeExpr2.bpl | 104 +- Test/codeexpr/codeExprBug.bpl | 30 +- Test/codeexpr/codeExprBug.bpl.expect | 4 +- .../multiple_procs_unusual_identifiers.bpl | 75 + ...ultiple_procs_verify_four_asterisk_wildcard.bpl | 28 + Test/commandline/multiple_procs_verify_one.bpl | 22 + .../multiple_procs_verify_one_request_twice.bpl | 20 + Test/commandline/multiple_procs_verify_two.bpl | 17 + ...le_procs_verify_two_asterisk_wildcard_begin.bpl | 17 + ...iple_procs_verify_two_asterisk_wildcard_end.bpl | 17 + ...rocs_verify_two_asterisk_wildcard_inbetween.bpl | 23 + Test/datatypes/ex.bpl | 26 +- Test/datatypes/t1.bpl | 50 +- Test/datatypes/t2.bpl | 50 +- Test/doomed/doomdebug.bpl | 88 +- Test/doomed/doomed.bpl | 174 +- Test/doomed/notdoomed.bpl | 116 +- Test/doomed/runtest.bat | 32 +- Test/doomed/smoke0.bpl | 158 +- Test/extractloops/detLoopExtract.bpl | 4 +- Test/extractloops/detLoopExtract2.bpl | 27 + Test/extractloops/detLoopExtract2.bpl.expect | 2 + Test/extractloops/detLoopExtractNested.bpl | 23 + Test/extractloops/detLoopExtractNested.bpl.expect | 19 + Test/extractloops/t1.bpl | 86 +- Test/extractloops/t2.bpl | 108 +- Test/extractloops/t3.bpl | 86 +- Test/forro/prog0.forro | 78 +- Test/generalizedarray/Maps.bpl | 120 +- Test/havoc0/KbdCreateClassObject.bpl | 10314 +- Test/havoc0/KeyboardClassFindMorePorts.bpl | 7564 +- Test/havoc0/KeyboardClassUnload.bpl | 6670 +- Test/havoc0/MouCreateClassObject.bpl | 9840 +- Test/havoc0/MouseClassFindMorePorts.bpl | 7678 +- Test/havoc0/MouseClassUnload.bpl | 6742 +- Test/houdini/deterministic.bpl | 54 +- Test/houdini/deterministic.bpl.expect | 6 +- Test/houdini/houd1.bpl | 42 +- Test/houdini/houd10.bpl | 50 +- Test/houdini/houd11.bpl | 30 +- Test/houdini/houd12.bpl | 118 +- Test/houdini/houd2.bpl | 58 +- Test/houdini/houd3.bpl | 58 +- Test/houdini/houd4.bpl | 58 +- Test/houdini/houd5.bpl | 62 +- Test/houdini/houd6.bpl | 92 +- Test/houdini/houd7.bpl | 74 +- Test/houdini/houd8.bpl | 64 +- Test/houdini/houd9.bpl | 68 +- Test/houdini/mergedProgSingle_dac.bpl | 15232 +- Test/houdini/mergedProgSingle_dac.bpl.expect | 380 +- Test/houdini/mergedProgSingle_res_ex1.bpl | 1242 +- Test/houdini/mergedProgSingle_res_ex1.bpl.expect | 16 +- Test/houdini/mergedProgSingle_res_ex2.bpl | 1242 +- Test/houdini/mergedProgSingle_res_ex2.bpl.expect | 16 +- Test/houdini/test1.bpl | 76 +- Test/houdini/test10.bpl | 98 +- Test/houdini/test10.bpl.expect | 14 +- Test/houdini/test2.bpl | 80 +- Test/houdini/test7.bpl | 34 +- Test/houdini/test8.bpl | 46 +- Test/houdini/test9.bpl | 150 +- Test/houdini/testUnsatCore.bpl | 72 +- Test/houdini/testUnsatCore.bpl.expect | 14 +- Test/inline/Elevator.asml | 110 +- Test/inline/Elevator.bpl | 312 +- Test/inline/InliningAndLoops.bpl | 44 +- Test/inline/codeexpr.bpl | 124 +- Test/inline/expansion2.bpl | 38 +- Test/inline/expansion3.bpl | 26 +- Test/inline/expansion4.bpl | 22 +- Test/inline/fundef.bpl | 16 +- Test/inline/fundef2.bpl | 18 +- Test/inline/polyInline.bpl | 86 +- Test/inline/test0.bpl | 100 +- Test/inline/test1.bpl | 92 +- Test/inline/test2.bpl | 66 +- Test/inline/test3.bpl | 58 +- Test/inline/test4.bpl | 108 +- Test/inline/test5.bpl | 162 +- Test/inline/test6.bpl | 78 +- Test/linear/allocator.bpl | 24 +- Test/linear/async-bug.bpl | 72 +- Test/linear/async-bug.bpl.expect | 6 +- Test/linear/bug.bpl | 32 +- Test/linear/f1.bpl | 96 +- Test/linear/f2.bpl | 44 +- Test/linear/f3.bpl | 20 +- Test/linear/list.bpl | 100 +- Test/linear/typecheck.bpl | 233 +- Test/linear/typecheck.bpl.expect | 32 +- Test/livevars/NestedOneDimensionalMap.bpl | 62 +- Test/livevars/TwoDimensionalMap.bpl | 62 +- Test/livevars/bla1.bpl | 4204 +- Test/livevars/daytona_bug2_ioctl_example_1.bpl | 8024 +- Test/livevars/daytona_bug2_ioctl_example_2.bpl | 9720 +- .../daytona_bug2_ioctl_example_2.bpl.expect | 3 +- Test/livevars/stack_overflow.bpl | 195938 +++++++++--------- Test/lock/Lock.bpl | 248 +- Test/lock/LockIncorrect.bpl | 106 +- Test/og/DeviceCache.bpl | 210 - Test/og/DeviceCache.bpl.expect | 2 - Test/og/FlanaganQadeer.bpl | 75 - Test/og/FlanaganQadeer.bpl.expect | 2 - Test/og/Program1.bpl | 33 - Test/og/Program1.bpl.expect | 2 - Test/og/Program2.bpl | 37 - Test/og/Program2.bpl.expect | 2 - Test/og/Program3.bpl | 36 - Test/og/Program3.bpl.expect | 2 - Test/og/Program4.bpl | 68 - Test/og/Program4.bpl.expect | 2 - Test/og/Program5.bpl | 79 - Test/og/Program5.bpl.expect | 2 - Test/og/akash.bpl | 106 - Test/og/akash.bpl.expect | 2 - Test/og/bar.bpl | 57 - Test/og/bar.bpl.expect | 13 - Test/og/chris.bpl | 28 - Test/og/chris.bpl.expect | 2 - Test/og/chris2.bpl | 34 - Test/og/chris2.bpl.expect | 18 - Test/og/civl-paper.bpl | 175 - Test/og/civl-paper.bpl.expect | 2 - Test/og/foo.bpl | 57 - Test/og/foo.bpl.expect | 8 - Test/og/linear-set.bpl | 105 - Test/og/linear-set.bpl.expect | 2 - Test/og/linear-set2.bpl | 106 - Test/og/linear-set2.bpl.expect | 2 - Test/og/lock-introduced.bpl | 100 - Test/og/lock-introduced.bpl.expect | 2 - Test/og/lock.bpl | 57 - Test/og/lock.bpl.expect | 2 - Test/og/lock2.bpl | 63 - Test/og/lock2.bpl.expect | 2 - Test/og/multiset.bpl | 324 - Test/og/multiset.bpl.expect | 2 - Test/og/new1.bpl | 42 - Test/og/new1.bpl.expect | 2 - Test/og/one.bpl | 18 - Test/og/one.bpl.expect | 2 - Test/og/parallel1.bpl | 48 - Test/og/parallel1.bpl.expect | 8 - Test/og/parallel2.bpl | 59 - Test/og/parallel2.bpl.expect | 2 - Test/og/parallel4.bpl | 45 - Test/og/parallel4.bpl.expect | 6 - Test/og/parallel5.bpl | 59 - Test/og/parallel5.bpl.expect | 2 - Test/og/perm.bpl | 49 - Test/og/perm.bpl.expect | 2 - Test/og/t1.bpl | 103 - Test/og/t1.bpl.expect | 9 - Test/og/termination.bpl | 18 - Test/og/termination.bpl.expect | 3 - Test/og/termination2.bpl | 19 - Test/og/termination2.bpl.expect | 2 - Test/og/ticket.bpl | 147 - Test/og/ticket.bpl.expect | 2 - Test/og/treiber-stack.bpl | 202 - Test/og/treiber-stack.bpl.expect | 2 - Test/og/wsq.bpl | 560 - Test/og/wsq.bpl.expect | 2 - Test/optimization/Optimization0.bpl | 84 + Test/optimization/Optimization0.bpl.expect | 135 + Test/optimization/Optimization1.bpl | 32 + Test/optimization/Optimization1.bpl.expect | 5 + Test/optimization/Optimization2.bpl | 12 + Test/optimization/Optimization2.bpl.expect | 3 + Test/optimization/Optimization3.bpl | 20 + Test/optimization/Optimization3.bpl.expect | 31 + Test/optimization/lit.local.cfg | 3 + Test/prover/EQ_v2.Eval__v4.Eval_out.bpl | 4514 +- Test/prover/usedot.bpl | 9 + Test/prover/z3mutl.bpl | 46 +- Test/secure/tworound.bpl | 116 + Test/smoke/smoke0.bpl | 110 +- Test/snapshots/Snapshots0.v0.bpl | 84 +- Test/snapshots/Snapshots0.v1.bpl | 84 +- Test/snapshots/Snapshots0.v2.bpl | 62 +- Test/snapshots/Snapshots1.v0.bpl | 28 +- Test/snapshots/Snapshots1.v1.bpl | 28 +- Test/snapshots/Snapshots1.v2.bpl | 30 +- Test/snapshots/Snapshots10.v0.bpl | 40 +- Test/snapshots/Snapshots10.v1.bpl | 42 +- Test/snapshots/Snapshots11.v0.bpl | 28 +- Test/snapshots/Snapshots11.v1.bpl | 30 +- Test/snapshots/Snapshots12.v0.bpl | 32 +- Test/snapshots/Snapshots12.v1.bpl | 32 +- Test/snapshots/Snapshots13.v0.bpl | 42 +- Test/snapshots/Snapshots13.v1.bpl | 32 +- Test/snapshots/Snapshots14.v0.bpl | 42 +- Test/snapshots/Snapshots14.v1.bpl | 42 +- Test/snapshots/Snapshots15.v0.bpl | 34 +- Test/snapshots/Snapshots15.v1.bpl | 34 +- Test/snapshots/Snapshots16.v0.bpl | 30 +- Test/snapshots/Snapshots16.v1.bpl | 30 +- Test/snapshots/Snapshots17.v0.bpl | 64 +- Test/snapshots/Snapshots17.v1.bpl | 64 +- Test/snapshots/Snapshots18.v0.bpl | 48 +- Test/snapshots/Snapshots18.v1.bpl | 48 +- Test/snapshots/Snapshots19.v0.bpl | 22 +- Test/snapshots/Snapshots19.v1.bpl | 22 +- Test/snapshots/Snapshots2.v0.bpl | 24 +- Test/snapshots/Snapshots2.v1.bpl | 24 +- Test/snapshots/Snapshots2.v2.bpl | 26 +- Test/snapshots/Snapshots2.v3.bpl | 26 +- Test/snapshots/Snapshots2.v4.bpl | 26 +- Test/snapshots/Snapshots2.v5.bpl | 28 +- Test/snapshots/Snapshots20.v0.bpl | 40 +- Test/snapshots/Snapshots20.v1.bpl | 40 +- Test/snapshots/Snapshots21.v0.bpl | 30 +- Test/snapshots/Snapshots21.v1.bpl | 30 +- Test/snapshots/Snapshots22.v0.bpl | 30 +- Test/snapshots/Snapshots22.v1.bpl | 30 +- Test/snapshots/Snapshots23.v0.bpl | 44 +- Test/snapshots/Snapshots23.v1.bpl | 46 +- Test/snapshots/Snapshots23.v2.bpl | 44 +- Test/snapshots/Snapshots24.v0.bpl | 50 +- Test/snapshots/Snapshots24.v1.bpl | 50 +- Test/snapshots/Snapshots25.v0.bpl | 28 +- Test/snapshots/Snapshots25.v1.bpl | 28 +- Test/snapshots/Snapshots26.v0.bpl | 28 +- Test/snapshots/Snapshots26.v1.bpl | 30 +- Test/snapshots/Snapshots27.v0.bpl | 28 +- Test/snapshots/Snapshots27.v1.bpl | 32 +- Test/snapshots/Snapshots28.v0.bpl | 30 +- Test/snapshots/Snapshots28.v1.bpl | 32 +- Test/snapshots/Snapshots29.v0.bpl | 30 +- Test/snapshots/Snapshots29.v1.bpl | 30 +- Test/snapshots/Snapshots3.v0.bpl | 36 +- Test/snapshots/Snapshots3.v1.bpl | 36 +- Test/snapshots/Snapshots30.v0.bpl | 26 +- Test/snapshots/Snapshots30.v1.bpl | 28 +- Test/snapshots/Snapshots31.v0.bpl | 30 +- Test/snapshots/Snapshots31.v1.bpl | 28 +- Test/snapshots/Snapshots32.v0.bpl | 30 +- Test/snapshots/Snapshots32.v1.bpl | 24 +- Test/snapshots/Snapshots33.v0.bpl | 30 +- Test/snapshots/Snapshots33.v1.bpl | 16 +- Test/snapshots/Snapshots34.v0.bpl | 7 + Test/snapshots/Snapshots34.v1.bpl | 6 + Test/snapshots/Snapshots35.v0.bpl | 7 + Test/snapshots/Snapshots35.v1.bpl | 6 + Test/snapshots/Snapshots36.v0.bpl | 14 + Test/snapshots/Snapshots36.v1.bpl | 14 + Test/snapshots/Snapshots37.v0.bpl | 9 + Test/snapshots/Snapshots37.v1.bpl | 9 + Test/snapshots/Snapshots38.v0.bpl | 13 + Test/snapshots/Snapshots38.v1.bpl | 14 + Test/snapshots/Snapshots38.v2.bpl | 14 + Test/snapshots/Snapshots39.v0.bpl | 13 + Test/snapshots/Snapshots39.v1.bpl | 14 + Test/snapshots/Snapshots39.v2.bpl | 14 + Test/snapshots/Snapshots4.v0.bpl | 72 +- Test/snapshots/Snapshots4.v1.bpl | 90 +- Test/snapshots/Snapshots40.v0.bpl | 14 + Test/snapshots/Snapshots40.v1.bpl | 15 + Test/snapshots/Snapshots40.v2.bpl | 15 + Test/snapshots/Snapshots41.v0.bpl | 35 + Test/snapshots/Snapshots41.v1.bpl | 39 + Test/snapshots/Snapshots5.v0.bpl | 22 +- Test/snapshots/Snapshots5.v1.bpl | 22 +- Test/snapshots/Snapshots6.v0.bpl | 34 +- Test/snapshots/Snapshots6.v1.bpl | 36 +- Test/snapshots/Snapshots7.v0.bpl | 38 +- Test/snapshots/Snapshots7.v1.bpl | 40 +- Test/snapshots/Snapshots8.v0.bpl | 30 +- Test/snapshots/Snapshots8.v1.bpl | 32 +- Test/snapshots/Snapshots9.v0.bpl | 34 +- Test/snapshots/Snapshots9.v1.bpl | 32 +- Test/snapshots/runtest.AI.snapshot | 4 +- Test/snapshots/runtest.AI.snapshot.expect | 18 +- Test/snapshots/runtest.snapshot | 5 +- Test/snapshots/runtest.snapshot.expect | 1410 +- Test/stratifiedinline/bar1.bpl | 56 +- Test/stratifiedinline/bar10.bpl | 86 +- Test/stratifiedinline/bar11.bpl | 66 +- Test/stratifiedinline/bar12.bpl | 20 +- Test/stratifiedinline/bar13.bpl | 72 +- Test/stratifiedinline/bar2.bpl | 50 +- Test/stratifiedinline/bar3.bpl | 82 +- Test/stratifiedinline/bar4.bpl | 78 +- Test/stratifiedinline/bar6.bpl | 76 +- Test/stratifiedinline/bar7.bpl | 90 +- Test/stratifiedinline/bar8.bpl | 88 +- Test/stratifiedinline/bar9.bpl | 94 +- Test/stratifiedinline/large.bpl | 33522 +-- Test/symdiff/foo.bpl | 38 +- Test/test0/Arrays0.bpl | 10 +- Test/test0/Arrays1.bpl | 44 +- Test/test0/AssertVerifiedUnder0.bpl | 8 + Test/test0/AssertVerifiedUnder0.bpl.expect | 3 + Test/test0/AttributeParsing.bpl | 80 +- Test/test0/AttributeParsingErr.bpl | 50 +- Test/test0/AttributeResolution.bpl | 80 +- Test/test0/BadLabels0.bpl | 30 +- Test/test0/BadLabels1.bpl | 166 +- Test/test0/BadQuantifier.bpl | 10 +- Test/test0/EmptyCallArgs.bpl | 44 +- Test/test0/LargeLiterals0.bpl | 18 +- Test/test0/LineParse.bpl | 28 +- Test/test0/LineResolve.bpl | 90 +- Test/test0/MapsResolutionErrors.bpl | 60 +- Test/test0/ModifiedBag.bpl | 746 +- Test/test0/Orderings.bpl | 42 +- Test/test0/PrettyPrint.bpl | 134 +- Test/test0/Prog0.bpl | 106 +- Test/test0/Quoting.bpl | 36 +- Test/test0/SeparateVerification0.bpl | 54 +- Test/test0/SeparateVerification1.bpl | 42 +- Test/test0/Triggers0.bpl | 34 +- Test/test0/Triggers1.bpl | 258 +- Test/test0/Types0.bpl | 20 +- Test/test0/Types1.bpl | 18 +- Test/test0/WhereParsing.bpl | 72 +- Test/test0/WhereParsing0.bpl | 68 +- Test/test0/WhereParsing1.bpl | 34 +- Test/test0/WhereParsing2.bpl | 8 +- Test/test0/WhereResolution.bpl | 128 +- Test/test1/Arrays.bpl | 452 +- Test/test1/AssertVerifiedUnder0.bpl | 8 + Test/test1/AssertVerifiedUnder0.bpl.expect | 3 + Test/test1/AssumptionVariables0.bpl | 114 +- Test/test1/AssumptionVariables1.bpl | 12 +- Test/test1/AssumptionVariables1.bpl.expect | 4 +- Test/test1/AttributeTyping.bpl | 74 +- Test/test1/EmptyCallArgs.bpl | 42 +- Test/test1/Family.bpl | 98 +- Test/test1/Frame0.bpl | 34 +- Test/test1/Frame1.bpl | 198 +- Test/test1/FunBody.bpl | 30 +- Test/test1/IfThenElse0.bpl | 4 +- Test/test1/IntReal.bpl | 100 +- Test/test1/Lambda.bpl | 4 +- Test/test1/LogicalExprs.bpl | 16 +- Test/test1/MapsTypeErrors.bpl | 258 +- Test/test1/Orderings.bpl | 20 +- Test/test1/StatementIds0.bpl | 24 + Test/test1/StatementIds0.bpl.expect | 5 + Test/test1/UpdateExprTyping.bpl | 90 +- Test/test1/WhereTyping.bpl | 94 +- Test/test13/ErrorTraceTestLoopInvViolationBPL.bpl | 64 +- Test/test15/CaptureState.bpl | 58 +- Test/test15/CaptureState.bpl.expect | 18 +- Test/test15/IntInModel.bpl | 10 +- Test/test15/InterpretedFunctionTests.bpl | 38 +- Test/test15/ModelTest.bpl | 24 +- Test/test15/NullInModel.bpl | 14 +- Test/test16/LoopUnroll.bpl | 170 +- Test/test17/Answer | 16 +- Test/test17/contractinfer.bpl | 46 +- Test/test17/flpydisk.bpl | 4590 +- Test/test17/runtest.bat | 24 +- Test/test2/Arrays.bpl | 368 +- Test/test2/AssertVerifiedUnder0.bpl | 78 +- Test/test2/AssertVerifiedUnder0.bpl.expect | 22 +- Test/test2/AssumeEnsures.bpl | 142 +- Test/test2/AssumptionVariables0.bpl | 113 +- Test/test2/AssumptionVariables0.bpl.expect | 4 +- Test/test2/Axioms.bpl | 62 +- Test/test2/B.bpl | 176 +- Test/test2/BadLineNumber.bpl | 15 + Test/test2/BadLineNumber.bpl.expect | 7 + Test/test2/BoundedTypeParameterQuantifier.bpl | 14 + .../BoundedTypeParameterQuantifier.bpl.expect | 2 + Test/test2/Call.bpl | 124 +- Test/test2/CallVerifiedUnder0.bpl | 42 + Test/test2/CallVerifiedUnder0.bpl.expect | 14 + Test/test2/ContractEvaluationOrder.bpl | 72 +- Test/test2/CutBackEdge.bpl | 84 +- Test/test2/Ensures.bpl | 154 +- Test/test2/False.bpl | 36 +- Test/test2/FormulaTerm.bpl | 282 +- Test/test2/FormulaTerm2.bpl | 102 +- Test/test2/FreeCall.bpl | 168 +- Test/test2/IfThenElse1.bpl | 4 +- Test/test2/Implies.bpl | 76 +- Test/test2/InvariantVerifiedUnder0.bpl | 54 + Test/test2/InvariantVerifiedUnder0.bpl.expect | 23 + Test/test2/LambdaOldExpressions.bpl | 126 +- Test/test2/LambdaPoly.bpl | 4 +- Test/test2/LoopInvAssume.bpl | 44 +- Test/test2/NeverPattern.bpl | 140 +- Test/test2/NullaryMaps.bpl | 118 +- Test/test2/Old.bpl | 268 +- Test/test2/OldIllegal.bpl | 36 +- Test/test2/Passification.bpl | 342 +- Test/test2/Quantifiers.bpl | 312 +- Test/test2/SelectiveChecking.bpl | 4 +- Test/test2/Structured.bpl | 692 +- Test/test2/Timeouts0.bpl | 170 +- Test/test2/TypeEncodingM.bpl | 4 +- Test/test2/UpdateExpr.bpl | 166 +- Test/test2/Where.bpl | 330 +- Test/test2/sk_hack.bpl | 68 +- Test/test2/strings-no-where.bpl | 1994 +- Test/test2/strings-where.bpl | 1994 +- Test/test20/Coercions.bpl | 38 +- Test/test20/EmptySeq.bpl | 16 +- Test/test20/ParallelAssignment.bpl | 48 +- Test/test20/ParallelAssignment2.bpl | 24 +- Test/test20/PolyFuns0.bpl | 114 +- Test/test20/PolyFuns1.bpl | 122 +- Test/test20/PolyPolyPoly.bpl | 48 +- Test/test20/PolyPolyPoly2.bpl | 70 +- Test/test20/PolyProcs0.bpl | 70 +- Test/test20/ProcParamReordering.bpl | 32 +- Test/test20/Prog0.bpl | 74 +- Test/test20/Prog1.bpl | 56 +- Test/test20/Prog2.bpl | 36 +- Test/test20/TypeDecls0.bpl | 94 +- Test/test20/TypeDecls1.bpl | 50 +- Test/test20/TypeSynonyms0.bpl | 66 +- Test/test20/TypeSynonyms1.bpl | 98 +- Test/test20/TypeSynonyms2.bpl | 48 +- Test/test21/BooleanQuantification.bpl | 74 +- Test/test21/BooleanQuantification2.bpl | 38 +- Test/test21/Boxing.bpl | 52 +- Test/test21/Casts.bpl | 32 +- Test/test21/Coercions2.bpl | 58 +- Test/test21/Colors.bpl | 52 +- Test/test21/DisjointDomains.bpl | 72 +- Test/test21/DisjointDomains2.bpl | 140 +- Test/test21/EmptyList.bpl | 104 +- Test/test21/EmptySetBug.bpl | 72 +- Test/test21/Flattening.bpl | 36 +- Test/test21/FunAxioms.bpl | 90 +- Test/test21/FunAxioms2.bpl | 52 +- Test/test21/HeapAbstraction.bpl | 50 +- Test/test21/HeapAxiom.bpl | 66 +- Test/test21/InterestingExamples0.bpl | 26 +- Test/test21/InterestingExamples1.bpl | 66 +- Test/test21/InterestingExamples2.bpl | 40 +- Test/test21/InterestingExamples3.bpl | 66 +- Test/test21/InterestingExamples4.bpl | 96 +- Test/test21/InterestingExamples5.bpl | 42 +- Test/test21/Keywords.bpl | 28 +- Test/test21/LargeLiterals0.bpl | 50 +- Test/test21/LetSorting.bpl | 42 +- Test/test21/MapAxiomsConsistency.bpl | 206 +- Test/test21/MapOutputTypeParams.bpl | 76 +- Test/test21/Maps0.bpl | 124 +- Test/test21/Maps1.bpl | 84 +- Test/test21/Maps2.bpl | 62 +- Test/test21/NameClash.bpl | 26 +- Test/test21/Orderings.bpl | 50 +- Test/test21/Orderings2.bpl | 46 +- Test/test21/Orderings3.bpl | 86 +- Test/test21/Orderings4.bpl | 32 +- Test/test21/ParallelAssignment.bpl | 122 +- Test/test21/PolyList.bpl | 134 +- Test/test21/Real.bpl | 132 +- Test/test21/Triggers0.bpl | 98 +- Test/test21/Triggers1.bpl | 44 +- Test/test21/test3_AddMethod_conv.bpl | 3654 +- Test/test7/MultipleErrors.bpl | 76 +- Test/test7/NestedVC.bpl | 46 +- Test/test7/UnreachableBlocks.bpl | 84 +- Test/textbook/BQueue.bpl | 864 +- Test/textbook/Bubble.bpl | 164 +- Test/textbook/DivMod.bpl | 130 +- Test/textbook/DutchFlag.bpl | 142 +- Test/textbook/Find.bpl | 80 +- Test/textbook/McCarthy-91.bpl | 28 +- Test/textbook/TuringFactorial.bpl | 70 +- Test/unnecessaryassumes/unnecessaryassumes0.bpl | 13 + .../unnecessaryassumes0.bpl.expect | 3 + Test/unnecessaryassumes/unnecessaryassumes1.bpl | 23 + .../unnecessaryassumes1.bpl.expect | 3 + Test/z3api/Answer | 518 +- Test/z3api/Boog24.bpl | 34 +- Test/z3api/bar1.bpl | 52 +- Test/z3api/bar2.bpl | 48 +- Test/z3api/bar3.bpl | 82 +- Test/z3api/bar4.bpl | 76 +- Test/z3api/bar6.bpl | 72 +- Test/z3api/boog0.bpl | 98 +- Test/z3api/boog1.bpl | 34 +- Test/z3api/boog10.bpl | 48 +- Test/z3api/boog11.bpl | 36 +- Test/z3api/boog12.bpl | 44 +- Test/z3api/boog13.bpl | 56 +- Test/z3api/boog14.bpl | 22 +- Test/z3api/boog15.bpl | 20 +- Test/z3api/boog16.bpl | 22 +- Test/z3api/boog17.bpl | 52 +- Test/z3api/boog18.bpl | 30 +- Test/z3api/boog19.bpl | 460 +- Test/z3api/boog2.bpl | 46 +- Test/z3api/boog20.bpl | 36 +- Test/z3api/boog21.bpl | 38 +- Test/z3api/boog22.bpl | 20 +- Test/z3api/boog23.bpl | 824 +- Test/z3api/boog25.bpl | 568 +- Test/z3api/boog28.bpl | 34 +- Test/z3api/boog29.bpl | 40 +- Test/z3api/boog3.bpl | 14 +- Test/z3api/boog30.bpl | 28 +- Test/z3api/boog31.bpl | 30 +- Test/z3api/boog34.bpl | 20 +- Test/z3api/boog35.bpl | 32 +- Test/z3api/boog4.bpl | 86 +- Test/z3api/boog5.bpl | 86 +- Test/z3api/boog6.bpl | 48 +- Test/z3api/boog7.bpl | 42 +- Test/z3api/boog8.bpl | 52 +- Test/z3api/boog9.bpl | 46 +- Test/z3api/runtest.bat | 30 +- Util/BoogieBuildAndTest.cmd | 52 +- Util/Code Snippets/contractassertnonnull.snippet | 62 +- .../contractassertnonnullelem.snippet | 62 +- .../contractensuresnonnullelem.snippet | 60 +- Util/Code Snippets/contractensuresvalret.snippet | 60 +- .../contractensuresvalretNonNullElem.snippet | 60 +- Util/Code Snippets/contractinvnonnullelem.snippet | 62 +- .../contractrequiresnonnullelem.snippet | 62 +- Util/Emacs/boogie-mode.el | 240 +- Util/VS2010/Boogie/BoogieLanguageService.sln | 40 +- .../BoogieLanguageService.csproj | 356 +- .../Boogie/BoogieLanguageService/Configuration.cs | 48 +- .../BoogieLanguageService/GlobalSuppressions.cs | 22 +- .../VS2010/Boogie/BoogieLanguageService/Grammar.cs | 794 +- Util/VS2010/Boogie/BoogieLanguageService/Guids.cs | 24 +- .../Integration/AuthoringScope.cs | 130 +- .../Integration/Configuration.cs | 230 +- .../Integration/Declaration.cs | 58 +- .../Integration/Declarations.cs | 110 +- .../Integration/IASTResolver.cs | 24 +- .../Integration/IronyLanguageService.cs | 686 +- .../Integration/IronyViewFilter.cs | 84 +- .../Integration/LineScanner.cs | 116 +- .../BoogieLanguageService/Integration/Method.cs | 38 +- .../BoogieLanguageService/Integration/Methods.cs | 98 +- .../BoogieLanguageService/Integration/Package.cs | 258 +- .../BoogieLanguageService/Integration/Resolver.cs | 100 +- .../BoogieLanguageService/Integration/Source.cs | 80 +- .../IronyLanguageServicePackage.cs | 180 +- .../Properties/AssemblyInfo.cs | 72 +- .../BoogieLanguageService/Resources.Designer.cs | 126 +- .../Boogie/BoogieLanguageService/Resources.resx | 258 +- .../Boogie/BoogieLanguageService/VSPackage.resx | 256 +- .../source.extension.vsixmanifest | 54 +- Util/latex/boogie.sty | 242 +- 914 files changed, 310935 insertions(+), 307289 deletions(-) create mode 100644 .gitattributes delete mode 100644 Build/CodePlex.Tools.MsBuild.dll delete mode 100644 Build/CodePlex.Tools.Wiki.dll delete mode 100644 Build/updateVersionFile.xml create mode 100644 Source/Concurrency/CivlRefinement.cs create mode 100644 Source/Concurrency/CivlTypeChecker.cs delete mode 100644 Source/Concurrency/OwickiGries.cs delete mode 100644 Source/Concurrency/TypeCheck.cs delete mode 100644 Source/Core/Graph.as delete mode 100644 Source/version.ssc create mode 100644 Test/aitest0/Issue25.bpl create mode 100644 Test/aitest0/Issue25.bpl.expect create mode 100644 Test/civl/DeviceCache.bpl create mode 100644 Test/civl/DeviceCache.bpl.expect create mode 100644 Test/civl/FlanaganQadeer.bpl create mode 100644 Test/civl/FlanaganQadeer.bpl.expect create mode 100644 Test/civl/Program1.bpl create mode 100644 Test/civl/Program1.bpl.expect create mode 100644 Test/civl/Program2.bpl create mode 100644 Test/civl/Program2.bpl.expect create mode 100644 Test/civl/Program3.bpl create mode 100644 Test/civl/Program3.bpl.expect create mode 100644 Test/civl/Program4.bpl create mode 100644 Test/civl/Program4.bpl.expect create mode 100644 Test/civl/Program5.bpl create mode 100644 Test/civl/Program5.bpl.expect create mode 100644 Test/civl/StoreBuffer.bpl create mode 100644 Test/civl/StoreBuffer.bpl.expect create mode 100644 Test/civl/akash.bpl create mode 100644 Test/civl/akash.bpl.expect create mode 100644 Test/civl/alloc.bpl create mode 100644 Test/civl/alloc.bpl.expect create mode 100644 Test/civl/bar.bpl create mode 100644 Test/civl/bar.bpl.expect create mode 100644 Test/civl/chris.bpl create mode 100644 Test/civl/chris.bpl.expect create mode 100644 Test/civl/chris2.bpl create mode 100644 Test/civl/chris2.bpl.expect create mode 100644 Test/civl/chris3.bpl create mode 100644 Test/civl/chris3.bpl.expect create mode 100644 Test/civl/chris4.bpl create mode 100644 Test/civl/chris4.bpl.expect create mode 100644 Test/civl/chris5.bpl create mode 100644 Test/civl/chris5.bpl.expect create mode 100644 Test/civl/chris6.bpl create mode 100644 Test/civl/chris6.bpl.expect create mode 100644 Test/civl/chris7.bpl create mode 100644 Test/civl/chris7.bpl.expect create mode 100644 Test/civl/chris8.bpl create mode 100644 Test/civl/chris8.bpl.expect create mode 100644 Test/civl/civl-paper.bpl create mode 100644 Test/civl/civl-paper.bpl.expect create mode 100644 Test/civl/foo.bpl create mode 100644 Test/civl/foo.bpl.expect create mode 100644 Test/civl/funky.bpl create mode 100644 Test/civl/funky.bpl.expect create mode 100644 Test/civl/ghost.bpl create mode 100644 Test/civl/ghost.bpl.expect create mode 100644 Test/civl/linear-set.bpl create mode 100644 Test/civl/linear-set.bpl.expect create mode 100644 Test/civl/linear-set2.bpl create mode 100644 Test/civl/linear-set2.bpl.expect create mode 100644 Test/civl/lock-introduced.bpl create mode 100644 Test/civl/lock-introduced.bpl.expect create mode 100644 Test/civl/lock.bpl create mode 100644 Test/civl/lock.bpl.expect create mode 100644 Test/civl/lock2.bpl create mode 100644 Test/civl/lock2.bpl.expect create mode 100644 Test/civl/multiset.bpl create mode 100644 Test/civl/multiset.bpl.expect create mode 100644 Test/civl/new1.bpl create mode 100644 Test/civl/new1.bpl.expect create mode 100644 Test/civl/nocollector.bpl create mode 100644 Test/civl/nocollector.bpl.expect create mode 100644 Test/civl/one.bpl create mode 100644 Test/civl/one.bpl.expect create mode 100644 Test/civl/par-incr.bpl create mode 100644 Test/civl/par-incr.bpl.expect create mode 100644 Test/civl/parallel1.bpl create mode 100644 Test/civl/parallel1.bpl.expect create mode 100644 Test/civl/parallel2.bpl create mode 100644 Test/civl/parallel2.bpl.expect create mode 100644 Test/civl/parallel4.bpl create mode 100644 Test/civl/parallel4.bpl.expect create mode 100644 Test/civl/parallel5.bpl create mode 100644 Test/civl/parallel5.bpl.expect create mode 100644 Test/civl/perm.bpl create mode 100644 Test/civl/perm.bpl.expect create mode 100644 Test/civl/t1.bpl create mode 100644 Test/civl/t1.bpl.expect create mode 100644 Test/civl/termination.bpl create mode 100644 Test/civl/termination.bpl.expect create mode 100644 Test/civl/termination2.bpl create mode 100644 Test/civl/termination2.bpl.expect create mode 100644 Test/civl/ticket.bpl create mode 100644 Test/civl/ticket.bpl.expect create mode 100644 Test/civl/treiber-stack.bpl create mode 100644 Test/civl/treiber-stack.bpl.expect create mode 100644 Test/civl/wsq.bpl create mode 100644 Test/civl/wsq.bpl.expect create mode 100644 Test/commandline/multiple_procs_unusual_identifiers.bpl create mode 100644 Test/commandline/multiple_procs_verify_four_asterisk_wildcard.bpl create mode 100644 Test/commandline/multiple_procs_verify_one.bpl create mode 100644 Test/commandline/multiple_procs_verify_one_request_twice.bpl create mode 100644 Test/commandline/multiple_procs_verify_two.bpl create mode 100644 Test/commandline/multiple_procs_verify_two_asterisk_wildcard_begin.bpl create mode 100644 Test/commandline/multiple_procs_verify_two_asterisk_wildcard_end.bpl create mode 100644 Test/commandline/multiple_procs_verify_two_asterisk_wildcard_inbetween.bpl create mode 100644 Test/extractloops/detLoopExtract2.bpl create mode 100644 Test/extractloops/detLoopExtract2.bpl.expect create mode 100644 Test/extractloops/detLoopExtractNested.bpl create mode 100644 Test/extractloops/detLoopExtractNested.bpl.expect delete mode 100644 Test/og/DeviceCache.bpl delete mode 100644 Test/og/DeviceCache.bpl.expect delete mode 100644 Test/og/FlanaganQadeer.bpl delete mode 100644 Test/og/FlanaganQadeer.bpl.expect delete mode 100644 Test/og/Program1.bpl delete mode 100644 Test/og/Program1.bpl.expect delete mode 100644 Test/og/Program2.bpl delete mode 100644 Test/og/Program2.bpl.expect delete mode 100644 Test/og/Program3.bpl delete mode 100644 Test/og/Program3.bpl.expect delete mode 100644 Test/og/Program4.bpl delete mode 100644 Test/og/Program4.bpl.expect delete mode 100644 Test/og/Program5.bpl delete mode 100644 Test/og/Program5.bpl.expect delete mode 100644 Test/og/akash.bpl delete mode 100644 Test/og/akash.bpl.expect delete mode 100644 Test/og/bar.bpl delete mode 100644 Test/og/bar.bpl.expect delete mode 100644 Test/og/chris.bpl delete mode 100644 Test/og/chris.bpl.expect delete mode 100644 Test/og/chris2.bpl delete mode 100644 Test/og/chris2.bpl.expect delete mode 100644 Test/og/civl-paper.bpl delete mode 100644 Test/og/civl-paper.bpl.expect delete mode 100644 Test/og/foo.bpl delete mode 100644 Test/og/foo.bpl.expect delete mode 100644 Test/og/linear-set.bpl delete mode 100644 Test/og/linear-set.bpl.expect delete mode 100644 Test/og/linear-set2.bpl delete mode 100644 Test/og/linear-set2.bpl.expect delete mode 100644 Test/og/lock-introduced.bpl delete mode 100644 Test/og/lock-introduced.bpl.expect delete mode 100644 Test/og/lock.bpl delete mode 100644 Test/og/lock.bpl.expect delete mode 100644 Test/og/lock2.bpl delete mode 100644 Test/og/lock2.bpl.expect delete mode 100644 Test/og/multiset.bpl delete mode 100644 Test/og/multiset.bpl.expect delete mode 100644 Test/og/new1.bpl delete mode 100644 Test/og/new1.bpl.expect delete mode 100644 Test/og/one.bpl delete mode 100644 Test/og/one.bpl.expect delete mode 100644 Test/og/parallel1.bpl delete mode 100644 Test/og/parallel1.bpl.expect delete mode 100644 Test/og/parallel2.bpl delete mode 100644 Test/og/parallel2.bpl.expect delete mode 100644 Test/og/parallel4.bpl delete mode 100644 Test/og/parallel4.bpl.expect delete mode 100644 Test/og/parallel5.bpl delete mode 100644 Test/og/parallel5.bpl.expect delete mode 100644 Test/og/perm.bpl delete mode 100644 Test/og/perm.bpl.expect delete mode 100644 Test/og/t1.bpl delete mode 100644 Test/og/t1.bpl.expect delete mode 100644 Test/og/termination.bpl delete mode 100644 Test/og/termination.bpl.expect delete mode 100644 Test/og/termination2.bpl delete mode 100644 Test/og/termination2.bpl.expect delete mode 100644 Test/og/ticket.bpl delete mode 100644 Test/og/ticket.bpl.expect delete mode 100644 Test/og/treiber-stack.bpl delete mode 100644 Test/og/treiber-stack.bpl.expect delete mode 100644 Test/og/wsq.bpl delete mode 100644 Test/og/wsq.bpl.expect create mode 100644 Test/optimization/Optimization0.bpl create mode 100644 Test/optimization/Optimization0.bpl.expect create mode 100644 Test/optimization/Optimization1.bpl create mode 100644 Test/optimization/Optimization1.bpl.expect create mode 100644 Test/optimization/Optimization2.bpl create mode 100644 Test/optimization/Optimization2.bpl.expect create mode 100644 Test/optimization/Optimization3.bpl create mode 100644 Test/optimization/Optimization3.bpl.expect create mode 100644 Test/optimization/lit.local.cfg create mode 100644 Test/prover/usedot.bpl create mode 100644 Test/secure/tworound.bpl create mode 100644 Test/snapshots/Snapshots34.v0.bpl create mode 100644 Test/snapshots/Snapshots34.v1.bpl create mode 100644 Test/snapshots/Snapshots35.v0.bpl create mode 100644 Test/snapshots/Snapshots35.v1.bpl create mode 100644 Test/snapshots/Snapshots36.v0.bpl create mode 100644 Test/snapshots/Snapshots36.v1.bpl create mode 100644 Test/snapshots/Snapshots37.v0.bpl create mode 100644 Test/snapshots/Snapshots37.v1.bpl create mode 100644 Test/snapshots/Snapshots38.v0.bpl create mode 100644 Test/snapshots/Snapshots38.v1.bpl create mode 100644 Test/snapshots/Snapshots38.v2.bpl create mode 100644 Test/snapshots/Snapshots39.v0.bpl create mode 100644 Test/snapshots/Snapshots39.v1.bpl create mode 100644 Test/snapshots/Snapshots39.v2.bpl create mode 100644 Test/snapshots/Snapshots40.v0.bpl create mode 100644 Test/snapshots/Snapshots40.v1.bpl create mode 100644 Test/snapshots/Snapshots40.v2.bpl create mode 100644 Test/snapshots/Snapshots41.v0.bpl create mode 100644 Test/snapshots/Snapshots41.v1.bpl create mode 100644 Test/test0/AssertVerifiedUnder0.bpl create mode 100644 Test/test0/AssertVerifiedUnder0.bpl.expect create mode 100644 Test/test1/AssertVerifiedUnder0.bpl create mode 100644 Test/test1/AssertVerifiedUnder0.bpl.expect create mode 100644 Test/test1/StatementIds0.bpl create mode 100644 Test/test1/StatementIds0.bpl.expect create mode 100644 Test/test2/BadLineNumber.bpl create mode 100644 Test/test2/BadLineNumber.bpl.expect create mode 100644 Test/test2/BoundedTypeParameterQuantifier.bpl create mode 100644 Test/test2/BoundedTypeParameterQuantifier.bpl.expect create mode 100644 Test/test2/CallVerifiedUnder0.bpl create mode 100644 Test/test2/CallVerifiedUnder0.bpl.expect create mode 100644 Test/test2/InvariantVerifiedUnder0.bpl create mode 100644 Test/test2/InvariantVerifiedUnder0.bpl.expect create mode 100644 Test/unnecessaryassumes/unnecessaryassumes0.bpl create mode 100644 Test/unnecessaryassumes/unnecessaryassumes0.bpl.expect create mode 100644 Test/unnecessaryassumes/unnecessaryassumes1.bpl create mode 100644 Test/unnecessaryassumes/unnecessaryassumes1.bpl.expect diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..295e1dc8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,42 @@ +# Autodetect text files and ensure that we normalise their +# line endings to lf internally. When checked out they may +# use different line endings. +* text=auto + +# Check out with crlf (Windows) line endings +*.sln text eol=crlf +*.csproj text eol=crlf +*.cs text diff=csharp eol=crlf +*.fs text eol=crlf +*.fsproj text eol=crlf +*.fsy text eol=crlf +*.fsl text eol=crlf +*.resx text eol=crlf +*.vsixmanifest text eol=crlf +*.atg text eol=crlf +version.ssc text eol=crlf +packages.config text eol=crlf +App.config text eol=crlf +Build/updateVersionFile.xml text eol=crlf +*.bat text eol=crlf +*.cmd text eol=crlf +*.snippet text eol=crlf + +# Check out with lf (UNIX) line endings +*.sh text eol=lf +*.py text eol=lf +Makefile text eol=lf +.gitignore text eol=lf +.gitattributes text eol=lf +*.el text eol=lf +*.sty text eol=lf +*.vim text eol=lf +lit.site.cfg text eol=lf +lit.local.cfg text eol=lf +*.expect text eol=lf +*.md text eol=lf +.travis.yml text eol=lf + +# For the remaining files the line endings of checked out +# files is defined by the ``core.eol`` git config variable. +# By default this is the native line ending for the platform. diff --git a/.travis.yml b/.travis.yml index c5d0c21d..41ee569f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,16 +6,18 @@ env: - BOOGIE_CONFIG=Debug - BOOGIE_CONFIG=Release install: - - sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com C504E590 - # FIXME: We should not be using GPUVerify's repo for Z3 - - sudo sh -c 'echo "deb http://ppa.launchpad.net/delcypher/gpuverify-smt/ubuntu precise main" > /etc/apt/sources.list.d/smt.list' + - wget http://download.opensuse.org/repositories/home:delcypher:z3/xUbuntu_12.04/Release.key + - sudo apt-key add - < Release.key + # Use Z3 package built by the OpenSUSE build service https://build.opensuse.org/package/show/home:delcypher:z3/z3 + - sudo sh -c "echo 'deb http://download.opensuse.org/repositories/home:/delcypher:/z3/xUbuntu_12.04/ /' >> /etc/apt/sources.list.d/z3.list" - sudo apt-get update - - nuget restore ${TRAVIS_SOLUTION} - # Install Z3 - - sudo apt-get -y install z3=4.3.2-0~precise2 + # NuGet is a little flakey in legacy TravisCI, use travis_retry command to retry the command if it fails + - travis_retry nuget restore ${TRAVIS_SOLUTION} + # Install Z3 executable + - sudo apt-get -y install 'z3=4.4.1-*' # Install needed python tools - sudo pip install lit OutputCheck pyyaml - - mkdir -p Source/packages && cd Source/packages && nuget install NUnit.Runners -Version 2.6.3 + - mkdir -p Source/packages && cd Source/packages && travis_retry nuget install NUnit.Runners -Version 2.6.3 - cd ../../ script: - xbuild /p:Configuration=${BOOGIE_CONFIG} ${TRAVIS_SOLUTION} diff --git a/Binaries/PrepareBoogieZip.bat b/Binaries/PrepareBoogieZip.bat index 5a1b267f..99a7a0a6 100644 --- a/Binaries/PrepareBoogieZip.bat +++ b/Binaries/PrepareBoogieZip.bat @@ -7,22 +7,22 @@ if exist %DEST_DIR% del /q %DEST_DIR%\* if not exist %DEST_DIR% mkdir %DEST_DIR% for %%f in ( - AbsInt.dll AbsInt.pdb - Basetypes.dll Basetypes.pdb - Boogie.exe Boogie.pdb - BVD.exe BVD.pdb - CodeContractsExtender.dll CodeContractsExtender.pdb - Core.dll Core.pdb - Doomed.dll Doomed.pdb - Graph.dll Graph.pdb - Houdini.dll Houdini.pdb - Model.dll Model.pdb - ParserHelper.dll ParserHelper.pdb - Predication.dll Predication.pdb - Provers.SMTLib.dll Provers.SMTLib.pdb - UnivBackPred2.smt UnivBackPred2.smt2 - VCExpr.dll VCExpr.pdb - VCGeneration.dll VCGeneration.pdb + BoogieAbsInt.dll BoogieAbsInt.pdb + BoogieBasetypes.dll BoogieBasetypes.pdb + Boogie.exe Boogie.pdb + BVD.exe BVD.pdb + BoogieCodeContractsExtender.dll BoogieCodeContractsExtender.pdb + BoogieCore.dll BoogieCore.pdb + BoogieDoomed.dll BoogieDoomed.pdb + BoogieGraph.dll BoogieGraph.pdb + BoogieHoudini.dll BoogieHoudini.pdb + BoogieModel.dll BoogieModel.pdb + BoogieParserHelper.dll BoogieParserHelper.pdb + BoogiePredication.dll BoogiePredication.pdb + Provers.SMTLib.dll Provers.SMTLib.pdb + UnivBackPred2.smt UnivBackPred2.smt2 + BoogieVCExpr.dll BoogieVCExpr.pdb + BoogieVCGeneration.dll BoogieVCGeneration.pdb ) do ( copy %%f %DEST_DIR% ) diff --git a/Build/CodePlex.Tools.MsBuild.dll b/Build/CodePlex.Tools.MsBuild.dll deleted file mode 100644 index 2e400e8e..00000000 Binary files a/Build/CodePlex.Tools.MsBuild.dll and /dev/null differ diff --git a/Build/CodePlex.Tools.Wiki.dll b/Build/CodePlex.Tools.Wiki.dll deleted file mode 100644 index 9ea2bea8..00000000 Binary files a/Build/CodePlex.Tools.Wiki.dll and /dev/null differ diff --git a/Build/updateVersionFile.xml b/Build/updateVersionFile.xml deleted file mode 100644 index 6435133c..00000000 --- a/Build/updateVersionFile.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - diff --git a/README.md b/README.md index e86eb187..beb217fd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,17 @@ # Boogie -[![Build Status](https://travis-ci.org/boogie-org/boogie.svg)](https://travis-ci.org/boogie-org/boogie) +## Build Status + +| Linux | Windows | +|-------------------------------|---------------------------------| +| [![linux build status][1]][2] | [![windows_build_status][3]][4] | + +[1]: https://travis-ci.org/boogie-org/boogie.svg?branch=master +[2]: https://travis-ci.org/boogie-org/boogie +[3]: https://pmbuilds.inf.ethz.ch/buildStatus/icon?job=boogie +[4]: #FIXME + +## About Boogie is an intermediate verification language (IVL), intended as a layer on which to build program verifiers for other languages. Several program verifiers have @@ -22,9 +33,13 @@ several other institutions make the open-source Boogie tool what it is. ![boogie architecture](http://research.microsoft.com/en-us/projects/boogie/boogie.png) +More documentation can be found at http://boogie-docs.readthedocs.org/en/latest/ . + ## Language Reference -[This is Boogie2](http://research.microsoft.com/en-us/um/people/leino/papers/krml178.pdf) details +See [Language reference](http://boogie-docs.readthedocs.org/en/latest/LangRef.html). + +Note: [This is Boogie2](http://research.microsoft.com/en-us/um/people/leino/papers/krml178.pdf) details many aspects of the Boogie IVL but is slightly out of date. ## Getting help @@ -37,7 +52,7 @@ You can also report issues on our [issue tracker](https://github.com/boogie-org/ ### Requirements - [NuGet](https://www.nuget.org/) -- [Z3](https://github.com/Z3Prover/z3) 4.3.2 or [CVC4](http://cvc4.cs.nyu.edu/web/) **FIXME_VERSION** (note +- [Z3](https://github.com/Z3Prover/z3) 4.4.1 or [CVC4](http://cvc4.cs.nyu.edu/web/) **FIXME_VERSION** (note CVC4 support is experimental) #### Windows specific diff --git a/Source/AIFramework/AIFramework.csproj b/Source/AIFramework/AIFramework.csproj index a809b8bf..a04074a6 100644 --- a/Source/AIFramework/AIFramework.csproj +++ b/Source/AIFramework/AIFramework.csproj @@ -1,204 +1,204 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {39B0658D-C955-41C5-9A43-48C97A1EF5FD} - Library - Properties - AIFramework - AIFramework - v4.0 - 512 - 1 - true - ..\InterimKey.snk - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - Client - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - False - False - True - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - - - - - - - Full - %28none%29 - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - true - bin\z3apidebug\ - DEBUG;TRACE - full - AnyCPU - - - true - GlobalSuppressions.cs - prompt - Migrated rules for AIFramework.ruleset - true - - - true - bin\Checked\ - DEBUG;TRACE - full - AnyCPU - bin\Debug\AIFramework.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - True - False - True - False - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - False - Full - Build - 0 - - - - - - - version.cs - - - - - - - - - - - - - - - - - - - - - - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} - Basetypes - - - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} - CodeContractsExtender - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - + + + + Debug + AnyCPU + 9.0.21022 + 2.0 + {39B0658D-C955-41C5-9A43-48C97A1EF5FD} + Library + Properties + AIFramework + AIFramework + v4.0 + 512 + 1 + true + ..\InterimKey.snk + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + False + False + True + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + + + + + + + Full + %28none%29 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + true + bin\z3apidebug\ + DEBUG;TRACE + full + AnyCPU + + + true + GlobalSuppressions.cs + prompt + Migrated rules for AIFramework.ruleset + true + + + true + bin\Checked\ + DEBUG;TRACE + full + AnyCPU + bin\Debug\AIFramework.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + True + False + True + False + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + False + Full + Build + 0 + + + + + + + version.cs + + + + + + + + + + + + + + + + + + + + + + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} + Basetypes + + + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} + CodeContractsExtender + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + \ No newline at end of file diff --git a/Source/AIFramework/CommonFunctionSymbols.cs b/Source/AIFramework/CommonFunctionSymbols.cs index 6f7a9f93..6a287810 100644 --- a/Source/AIFramework/CommonFunctionSymbols.cs +++ b/Source/AIFramework/CommonFunctionSymbols.cs @@ -1,1232 +1,1232 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework -{ - using System.Diagnostics.Contracts; - using System.Collections; - using System.Collections.Generic; - //using Microsoft.SpecSharp.Collections; - using Microsoft.Basetypes; - - /// - /// A basic class for function symbols. - /// - public class FunctionSymbol : IFunctionSymbol - { - private readonly string/*!*/ display; - private readonly AIType/*!*/ typ; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(display != null); - Contract.Invariant(typ != null); - } - - - public FunctionSymbol(AIType/*!*/ typ) - : this("FunctionSymbol", typ) { - Contract.Requires(typ != null); - } - - internal FunctionSymbol(string/*!*/ display, AIType/*!*/ typ) { - Contract.Requires(typ != null); - Contract.Requires(display != null); - this.display = display; - this.typ = typ; - // base(); - } - - public AIType/*!*/ AIType { get { Contract.Ensures(Contract.Result() != null); return typ; } } - - [NoDefaultContract] - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return display; - } - - } - - /// - /// A class for integer constants. - /// - public class IntSymbol : FunctionSymbol - { - public readonly BigNum Value; - - /// - /// The intention is that this constructor be called only from the Int.Const method. - /// - internal IntSymbol(BigNum x) - : base(cce.NonNull(x.ToString()), Int.Type) { - this.Value = x; - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object other) { - IntSymbol isym = other as IntSymbol; - return isym != null && isym.Value.Equals(this.Value); - } - - [Pure] - public override int GetHashCode() { - return Value.GetHashCode(); - } - } - - /// - /// A class for bitvector constants. - /// - public class BvSymbol : FunctionSymbol - { - public readonly BigNum Value; - public readonly int Bits; - - /// - /// The intention is that this constructor be called only from the Int.Const method. - /// - internal BvSymbol(BigNum x, int y) - : base(x + "bv" + y, Bv.Type) { - this.Value = x; - this.Bits = y; - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object other) { - BvSymbol isym = other as BvSymbol; - return isym != null && isym.Value == this.Value && isym.Bits == this.Bits; - } - - [Pure] - public override int GetHashCode() { - unchecked { - return Value.GetHashCode() ^ Bits; - } - } - } - - public class DoubleSymbol : FunctionSymbol - { - public readonly double Value; - - /// - /// The intention is that this constructor be called only from the Double.Const method. - /// - internal DoubleSymbol(double x) - : base(cce.NonNull(x.ToString()), Double.Type) { - this.Value = x; - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object other) { - DoubleSymbol dsym = other as DoubleSymbol; - return dsym != null && dsym.Value == this.Value; - } - - [Pure] - public override int GetHashCode() { - return Value.GetHashCode(); - } - } - - /// - /// Function symbol based on a string. Uses the string equality for determining equality - /// of symbol. - /// - public class NamedSymbol : FunctionSymbol - { - public string/*!*/ Value { [NoDefaultContract] get { Contract.Ensures(Contract.Result() != null); return cce.NonNull(this.ToString()); } } - - public NamedSymbol(string/*!*/ symbol, AIType/*!*/ typ) - : base(symbol, typ) { - Contract.Requires(typ != null); - Contract.Requires(symbol != null); - } - - [NoDefaultContract] - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object other) { - NamedSymbol nsym = other as NamedSymbol; - return nsym != null && this.Value.Equals(nsym.Value); - } - - [NoDefaultContract] - [Pure] - public override int GetHashCode() { - return Value.GetHashCode(); - } - } - - // - // In the following, the classes like Value and Prop serve two - // roles. The primary role is to be the base types for AIType. - // The only objects of these classes are the representative - // objects that denote an AIType, which are given by the - // "Type" property. Subtypes in the AIType language are - // encoded by subclassing. This yields some "higher-orderness" - // for checking subtyping in the AIType language, by using - // the Spec#/C# subclassing checks. - // - // The other role is simply as a module for collecting like function - // symbols. - // - - //-------------------------- Terms ---------------------------------- - - /// - /// A class with the equality symbol and the ValueType.Type. - /// - public class Value : AIType - { - private static readonly AIType/*!*/ valtype = new Value(); - public static AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return valtype; } } - - private static readonly FunctionType[]/*!*/ funtypeCache = new FunctionType[5]; - public static FunctionType/*!*/ FunctionType(int inParameterCount) { - Contract.Requires((0 <= inParameterCount)); - Contract.Ensures(Contract.Result() != null); - // Contract.Ensures(Contract.Result<>().Arity == inParameterCount); - FunctionType result; - if (inParameterCount < funtypeCache.Length) { - result = funtypeCache[inParameterCount]; - if (result != null) { - return result; - } - } - AIType[] signature = new AIType[1 + inParameterCount]; - for (int i = 0; i < signature.Length; i++) { - signature[i] = valtype; - } - result = new FunctionType(signature); - if (inParameterCount < funtypeCache.Length) { - funtypeCache[inParameterCount] = result; - } - return result; - } - - [Once] - private static AIType/*!*/ binreltype; - - private static AIType/*!*/ BinrelType { - get { - Contract.Ensures(Contract.Result() != null); - if (binreltype == null) { - binreltype = new FunctionType(Type, Type, Prop.Type); - } - return binreltype; - } - } - - [Once] - private static FunctionSymbol/*!*/ _eq; - public static FunctionSymbol/*!*/ Eq { - get { - Contract.Ensures(Contract.Result() != null); - if (_eq == null) { - _eq = new FunctionSymbol("=", BinrelType); - } - return _eq; - } - } - [Once] - private static FunctionSymbol/*!*/ _neq; - public static FunctionSymbol/*!*/ Neq { - get { - Contract.Ensures(Contract.Result() != null); - if (_neq == null) { - _neq = new FunctionSymbol("!=", BinrelType); - } - return _neq; - } - } - [Once] - private static FunctionSymbol/*!*/ _subtype; - public static FunctionSymbol/*!*/ Subtype { - get { - Contract.Ensures(Contract.Result() != null); - if (_subtype == null) { - _subtype = new FunctionSymbol("<:", BinrelType); - } - return _subtype; - } - } - - [Once] - private static AIType/*!*/ typeof_type; - private static AIType/*!*/ TypeofType { - get { - Contract.Ensures(Contract.Result() != null); - if (typeof_type == null) { - typeof_type = new FunctionType(Ref.Type, Type); - } - return typeof_type; - } - } - [Once] - private static FunctionSymbol/*!*/ _typeof; - public static FunctionSymbol/*!*/ Typeof { - get { - Contract.Ensures(Contract.Result() != null); - if (_typeof == null) { - _typeof = new FunctionSymbol("typeof", TypeofType); - } - return _typeof; - } - } - - /// - /// Value should not be instantiated from the outside, except perhaps in - /// subclasses. - /// - protected Value() { } - - } - - public class Int : Value - { - private static readonly AIType/*!*/ inttype = new Int(); - public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return inttype; } } - - private static readonly AIType/*!*/ unaryinttype = new FunctionType(Type, Type); - private static readonly AIType/*!*/ bininttype = new FunctionType(Type, Type, Type); - private static readonly AIType/*!*/ relationtype = new FunctionType(Type, Type, Prop.Type); - - private static readonly FunctionSymbol/*!*/ _negate = new FunctionSymbol("~", unaryinttype); - private static readonly FunctionSymbol/*!*/ _add = new FunctionSymbol("+", bininttype); - private static readonly FunctionSymbol/*!*/ _sub = new FunctionSymbol("-", bininttype); - private static readonly FunctionSymbol/*!*/ _mul = new FunctionSymbol("*", bininttype); - private static readonly FunctionSymbol/*!*/ _div = new FunctionSymbol("/", bininttype); - private static readonly FunctionSymbol/*!*/ _mod = new FunctionSymbol("%", bininttype); - private static readonly FunctionSymbol/*!*/ _atmost = new FunctionSymbol("<=", relationtype); - private static readonly FunctionSymbol/*!*/ _less = new FunctionSymbol("<", relationtype); - private static readonly FunctionSymbol/*!*/ _greater = new FunctionSymbol(">", relationtype); - private static readonly FunctionSymbol/*!*/ _atleast = new FunctionSymbol(">=", relationtype); - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Negate { get { Contract.Ensures(Contract.Result() != null); return _negate; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Add { get { Contract.Ensures(Contract.Result() != null); return _add; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Sub { get { Contract.Ensures(Contract.Result() != null); return _sub; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Mul { get { Contract.Ensures(Contract.Result() != null); return _mul; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Div { get { Contract.Ensures(Contract.Result() != null); return _div; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Mod { get { Contract.Ensures(Contract.Result() != null); return _mod; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ AtMost { get { Contract.Ensures(Contract.Result() != null); return _atmost; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Less { get { Contract.Ensures(Contract.Result() != null); return _less; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Greater { get { Contract.Ensures(Contract.Result() != null); return _greater; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ AtLeast { get { Contract.Ensures(Contract.Result() != null); return _atleast; } } - - public static IntSymbol/*!*/ Const(BigNum x) { - Contract.Ensures(Contract.Result() != null); - // We could cache things here, but for now we don't. - return new IntSymbol(x); - } - - /// - /// Int should not be instantiated from the outside, except perhaps in - /// subclasses. - /// - private Int() { } - } - - public class Double : Value - { - private static readonly AIType/*!*/ doubletype = new Double(); - public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return doubletype; } } - - public static DoubleSymbol/*!*/ Const(double x) { - Contract.Ensures(Contract.Result() != null); - // We could cache things here, but for now we don't. - return new DoubleSymbol(x); - } - - /// - /// Double should not be instantiated from the outside, except perhaps in - /// subclasses. - /// - private Double() { } - } - - public class Bv : Value - { - private static readonly AIType/*!*/ bvtype = new Bv(); - public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return bvtype; } } - - private static readonly AIType/*!*/ unaryinttype = new FunctionType(Type, Type); - private static readonly AIType/*!*/ bininttype = new FunctionType(Type, Type, Type); - private static readonly AIType/*!*/ relationtype = new FunctionType(Type, Type, Prop.Type); - - private static readonly FunctionSymbol/*!*/ _negate = new FunctionSymbol("~", unaryinttype); - private static readonly FunctionSymbol/*!*/ _add = new FunctionSymbol("+", bininttype); - private static readonly FunctionSymbol/*!*/ _sub = new FunctionSymbol("-", bininttype); - private static readonly FunctionSymbol/*!*/ _mul = new FunctionSymbol("*", bininttype); - private static readonly FunctionSymbol/*!*/ _div = new FunctionSymbol("/", bininttype); - private static readonly FunctionSymbol/*!*/ _mod = new FunctionSymbol("%", bininttype); - private static readonly FunctionSymbol/*!*/ _concat = new FunctionSymbol("$concat", bininttype); - private static readonly FunctionSymbol/*!*/ _extract = new FunctionSymbol("$extract", unaryinttype); - private static readonly FunctionSymbol/*!*/ _atmost = new FunctionSymbol("<=", relationtype); - private static readonly FunctionSymbol/*!*/ _less = new FunctionSymbol("<", relationtype); - private static readonly FunctionSymbol/*!*/ _greater = new FunctionSymbol(">", relationtype); - private static readonly FunctionSymbol/*!*/ _atleast = new FunctionSymbol(">=", relationtype); - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Negate { get { Contract.Ensures(Contract.Result() != null); return _negate; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Add { get { Contract.Ensures(Contract.Result() != null); return _add; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Sub { get { Contract.Ensures(Contract.Result() != null); return _sub; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Mul { get { Contract.Ensures(Contract.Result() != null); return _mul; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Div { get { Contract.Ensures(Contract.Result() != null); return _div; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Mod { get { Contract.Ensures(Contract.Result() != null); return _mod; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ AtMost { get { Contract.Ensures(Contract.Result() != null); return _atmost; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Less { get { Contract.Ensures(Contract.Result() != null); return _less; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Greater { get { Contract.Ensures(Contract.Result() != null); return _greater; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ AtLeast { get { Contract.Ensures(Contract.Result() != null); return _atleast; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Extract { get { Contract.Ensures(Contract.Result() != null); return _extract; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Concat { get { Contract.Ensures(Contract.Result() != null); return _concat; } } - - public static BvSymbol/*!*/ Const(BigNum x, int y) { - Contract.Ensures(Contract.Result() != null); - // We could cache things here, but for now we don't. - return new BvSymbol(x, y); - } - - /// - /// Int should not be instantiated from the outside, except perhaps in - /// subclasses. - /// - private Bv() { } - } - - public class Ref : Value - { - private static readonly AIType/*!*/ reftype = new Ref(); - public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return reftype; } } - - private static readonly FunctionSymbol/*!*/ _null = new FunctionSymbol("null", Type); - - public static FunctionSymbol/*!*/ Null { get { Contract.Ensures(Contract.Result() != null); return _null; } } - - /// - /// Ref should not be instantiated from the outside, except perhaps in - /// subclasses. - /// - private Ref() { } - } - - public class HeapStructure : Value - { - private static readonly AIType/*!*/ reftype = new HeapStructure(); - public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return reftype; } } - - - - /// - /// HeapStructure should not be instantiated from the outside, except perhaps in - /// subclasses. - /// - private HeapStructure() { } - } - - public class FieldName : Value - { - private static readonly AIType/*!*/ fieldnametype = new FieldName(); - public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return fieldnametype; } } - - private static readonly FunctionSymbol/*!*/ _allocated = new FunctionSymbol("$allocated", FieldName.Type); - public static FunctionSymbol/*!*/ Allocated { get { Contract.Ensures(Contract.Result() != null); return _allocated; } } - - /// - /// Is this a boolean field that monotonically goes from false to true? - /// - public static bool IsBooleanMonotonicallyWeakening(IFunctionSymbol/*!*/ f) { - Contract.Requires(f != null); - return f.Equals(Allocated); - } - - /// - /// FieldName should not be instantiated from the outside, except perhaps in - /// subclasses. - /// - private FieldName() { } - } - - public class Heap : Value - { - private static readonly AIType/*!*/ heaptype = new Heap(); - public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return heaptype; } } - - // the types in the following, select1, select2, are hard-coded; - // these types may not always be appropriate - private static readonly FunctionSymbol/*!*/ _select1 = new FunctionSymbol("sel1", - // Heap x FieldName -> Prop - new FunctionType(Type, FieldName.Type, Prop.Type) - ); - public static FunctionSymbol/*!*/ Select1 { get { Contract.Ensures(Contract.Result() != null); return _select1; } } - - private static readonly FunctionSymbol/*!*/ _select2 = new FunctionSymbol("sel2", - // Heap x Ref x FieldName -> Value - new FunctionType(Type, Ref.Type, FieldName.Type, Value.Type) - ); - public static FunctionSymbol/*!*/ Select2 { get { Contract.Ensures(Contract.Result() != null); return _select2; } } - - // the types in the following, store1, store2, are hard-coded; - // these types may not always be appropriate - private static readonly FunctionSymbol/*!*/ _update1 = new FunctionSymbol("upd1", - // Heap x FieldName x Value -> Heap - new FunctionType(Type, FieldName.Type, Value.Type, Type) - ); - public static FunctionSymbol/*!*/ Update1 { get { Contract.Ensures(Contract.Result() != null); return _update1; } } - - private static readonly FunctionSymbol/*!*/ _update2 = new FunctionSymbol("upd2", - // Heap x Ref x FieldName x Value -> Heap - new FunctionType(Type, Ref.Type, FieldName.Type, Value.Type, Type) - ); - public static FunctionSymbol/*!*/ Update2 { get { Contract.Ensures(Contract.Result() != null); return _update2; } } - - private static readonly FunctionSymbol/*!*/ _unsupportedHeapOp = - new FunctionSymbol("UnsupportedHeapOp", - // Heap x FieldName -> Prop - new FunctionType(Type, FieldName.Type, Prop.Type) - ); - public static FunctionSymbol/*!*/ UnsupportedHeapOp { get { Contract.Ensures(Contract.Result() != null); return _unsupportedHeapOp; } } - - /// - /// Heap should not be instantiated from the outside, except perhaps in - /// subclasses. - /// - private Heap() { } - } - - // public class List : Value - // { - // private static IDictionary/**/! lists = new Hashtable(); - // public static AIType! Type(AIType! typeParameter) - // { - // if (lists.Contains(typeParameter)) - // return lists[typeParameter]; - // else - // { - // AIType! result = new List(typeParameter); - // lists[typeParameter] = result; - // return result; - // } - // } - // - // private static IDictionary/**/! nils = new Hashtable(); - // public static FunctionSymbol! Nil(AIType! typeParameter) - // { - // if (nils.Contains(typeParameter)) - // return nils[typeParameter]; - // else - // { - // FunctionSymbol! result = new FunctionSymbol(Type(typeParameter)); - // nils[typeParameter] = result; - // return result; - // } - // } - // - // private static IDictionary/**/! cons = new Hashtable(); - // public static FunctionSymbol! Cons(AIType! typeParameter) - // { - // if (cons.Contains(typeParameter)) - // return cons[typeParameter]; - // else - // { - // FunctionSymbol! result = new FunctionSymbol( - // new FunctionType(typeParameter, Type(typeParameter), Type(typeParameter)) - // ); - // cons[typeParameter] = result; - // return result; - // } - // } - // - // private AIType! typeParameter; - // public AIType(TypeParameter/*!*/ ){ - //Contract.Requires( != null); - //return typeParameter; } } - // - // /// - // /// List should not be instantiated from the outside. - // /// - // private List(AIType! typeParameter) - // { - // this.typeParameter = typeParameter; - // } - // } - // - // public class Pair : Value - // { - // private static IDictionary! pairs = new Hashtable(); - // public static AIType! Type(AIType! type1, AIType! type2) - // { - // Microsoft.AbstractInterpretationFramework.Collections.Pair typpair - // = new Microsoft.AbstractInterpretationFramework.Collections.Pair(type1, type2); - // - // if (pairs.Contains(typpair)) - // return pairs[typpair]; - // else - // { - // AIType! result = new Pair(type1, type2); - // pairs[typpair] = result; - // return result; - // } - // } - // - // private static IDictionary! constructs = new Hashtable(); - // public static FunctionSymbol! Pair(AIType! type1, AIType! type2) - // { - // Microsoft.AbstractInterpretationFramework.Collections.Pair typpair - // = new Microsoft.AbstractInterpretationFramework.Collections.Pair(type1, type2); - // - // if (constructs.Contains(typpair)) - // return constructs[typpair]; - // else - // { - // FunctionSymbol! result = new FunctionSymbol( - // new FunctionType(type1, type2, Type(type1, type2)) - // ); - // constructs[typpair] = result; - // return result; - // } - // } - // - // protected AIType! type1; - // protected AIType! type2; - // - // public AIType(Type1/*!*/ ){ - //Contract.Requires( != null); - // return type1; } } - // public AIType(Type2/*!*/ ){ - //Contract.Requires( != null); - // return type2; } } - // - // /// - // /// Pair should not be instantiated from the outside, except by subclasses. - // /// - // protected Pair(AIType! type1, AIType! type2) - // { - // this.type1 = type1; - // this.type2 = type2; - // } - // } - - //-------------------------- Propositions --------------------------- - - - /// - /// A class with global propositional symbols and the Prop.Type. - /// - public sealed class Prop : AIType - { - private static readonly AIType/*!*/ proptype = new Prop(); - - public static AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return proptype; } } - - private static readonly AIType/*!*/ unaryproptype = new FunctionType(Type, Type); - private static readonly AIType/*!*/ binproptype = new FunctionType(Type, Type, Type); - private static readonly AIType/*!*/ quantifiertype = - new FunctionType(new FunctionType(Value.Type, Type), Type); - - private static readonly FunctionSymbol/*!*/ _false = new FunctionSymbol("false", Type); - private static readonly FunctionSymbol/*!*/ _true = new FunctionSymbol("true", Type); - private static readonly FunctionSymbol/*!*/ _not = new FunctionSymbol("!", unaryproptype); - private static readonly FunctionSymbol/*!*/ _and = new FunctionSymbol("/\\", binproptype); - private static readonly FunctionSymbol/*!*/ _or = new FunctionSymbol("\\/", binproptype); - private static readonly FunctionSymbol/*!*/ _implies = new FunctionSymbol("==>", binproptype); - private static readonly FunctionSymbol/*!*/ _exists = new FunctionSymbol("Exists", quantifiertype); - private static readonly FunctionSymbol/*!*/ _forall = new FunctionSymbol("Forall", quantifiertype); - private static readonly FunctionSymbol/*!*/ _lambda = new FunctionSymbol("Lambda", quantifiertype); - - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ False { get { Contract.Ensures(Contract.Result() != null); return _false; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ True { get { Contract.Ensures(Contract.Result() != null); return _true; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Not { get { Contract.Ensures(Contract.Result() != null); return _not; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ And { [Pure] get { Contract.Ensures(Contract.Result() != null); return _and; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Or { get { Contract.Ensures(Contract.Result() != null); return _or; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Implies { get { Contract.Ensures(Contract.Result() != null); return _implies; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Exists { get { Contract.Ensures(Contract.Result() != null); return _exists; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Forall { get { Contract.Ensures(Contract.Result() != null); return _forall; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Lambda { get { Contract.Ensures(Contract.Result() != null); return _lambda; } } - - - /// - /// Prop should not be instantiated from the outside. - /// - private Prop() { } - - - - // - // Utility Methods - // - - public static IExpr/*!*/ SimplifiedAnd(IPropExprFactory/*!*/ factory, IExpr/*!*/ e0, IExpr/*!*/ e1) { - Contract.Requires(e1 != null); - Contract.Requires(e0 != null); - Contract.Requires(factory != null); - Contract.Ensures(Contract.Result() != null); - IFunApp fun0 = e0 as IFunApp; - if (fun0 != null) { - if (fun0.FunctionSymbol.Equals(Prop.True)) { - return e1; - } else if (fun0.FunctionSymbol.Equals(Prop.False)) { - return e0; - } - } - - IFunApp fun1 = e1 as IFunApp; - if (fun1 != null) { - if (fun1.FunctionSymbol.Equals(Prop.True)) { - return e0; - } else if (fun1.FunctionSymbol.Equals(Prop.False)) { - return e1; - } - } - - return factory.And(e0, e1); - } - - public static IExpr/*!*/ SimplifiedAnd(IPropExprFactory/*!*/ factory, IEnumerable/**//*!*/ exprs) { - Contract.Requires(exprs != null); - Contract.Requires(factory != null); - Contract.Ensures(Contract.Result() != null); - IExpr/*!*/ result = factory.True; - Contract.Assert(result != null); - foreach (IExpr/*!*/ conjunct in exprs) { - Contract.Assert(conjunct != null); - result = SimplifiedAnd(factory, result, conjunct); - } - return result; - } - - public static IExpr/*!*/ SimplifiedOr(IPropExprFactory/*!*/ factory, IExpr/*!*/ e0, IExpr/*!*/ e1) { - Contract.Requires(e1 != null); - Contract.Requires(e0 != null); - Contract.Requires(factory != null); - Contract.Ensures(Contract.Result() != null); - IFunApp fun0 = e0 as IFunApp; - if (fun0 != null) { - if (fun0.FunctionSymbol.Equals(Prop.False)) { - return e1; - } else if (fun0.FunctionSymbol.Equals(Prop.True)) { - return e0; - } - } - - IFunApp fun1 = e1 as IFunApp; - if (fun1 != null) { - if (fun1.FunctionSymbol.Equals(Prop.False)) { - return e0; - } else if (fun1.FunctionSymbol.Equals(Prop.True)) { - return e1; - } - } - - return factory.Or(e0, e1); - } - - public static IExpr/*!*/ SimplifiedOr(IPropExprFactory/*!*/ factory, IEnumerable/**//*!*/ exprs) { - Contract.Requires(exprs != null); - Contract.Requires(factory != null); - Contract.Ensures(Contract.Result() != null); - IExpr/*!*/ result = factory.False; - Contract.Assert(result != null); - foreach (IExpr/*!*/ disj in exprs) { - Contract.Assert(disj != null); - result = SimplifiedOr(factory, result, disj); - } - return result; - } - - - - /// - /// Break top-level conjuncts into a list of sub-expressions. - /// - /// The expression to examine. - /// A list of conjuncts. - internal static IList/**//*!*/ BreakConjuncts(IExpr/*!*/ e) { - Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - Contract.Ensures(Contract.ForAll(0, Contract.Result().Count, i => { - var sub = Contract.Result()[i]; - return !(sub is IFunApp) || !((IFunApp)sub).FunctionSymbol.Equals(Prop.And); - })); - return BreakJuncts(e, Prop.And); - } - - /// - /// Break top-level disjuncts into a list of sub-expressions. - /// - /// The expression to examine. - /// A list of conjuncts. - internal static IList/**//*!*/ BreakDisjuncts(IExpr/*!*/ e) { - Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - Contract.Ensures(Contract.ForAll(0, Contract.Result().Count, i => { - var sub = Contract.Result()[i]; - return !(sub is IFunApp) || !((IFunApp)sub).FunctionSymbol.Equals(Prop.Or); - })); - return BreakJuncts(e, Prop.Or); - } - - private static IList/**//*!*/ BreakJuncts(IExpr/*!*/ e, IFunctionSymbol/*!*/ sym) { - Contract.Requires(sym != null); - Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - Contract.Ensures(Contract.ForAll(0, Contract.Result().Count, i => { - var sub = Contract.Result()[i]; - return (sub is IFunApp) || !((IFunApp)sub).FunctionSymbol.Equals(sym); - })); - ArrayList/**//*!*/ result = new ArrayList(); - - IFunApp f = e as IFunApp; - if (f != null) { - // If it is a sym, go down into sub-expressions. - if (f.FunctionSymbol.Equals(sym)) { - foreach (IExpr/*!*/ arg in f.Arguments) { - Contract.Assert(arg != null); - result.AddRange(BreakJuncts(arg, sym)); - } - } - // Otherwise, stop. - else { - result.Add(e); - } - } else { - result.Add(e); - } - - return result; - } - } - - /// - /// A callback to produce a function body given the bound variable. - /// - /// The bound variable to use. - /// The function body. - public delegate IExpr/*!*/ FunctionBody(IVariable/*!*/ var); - - /// - /// An interface for constructing propositional expressions. - /// - /// This interface should be implemented by the client. An implementation of - /// of this class should generally be used as a singleton object. - /// - /// - [ContractClass(typeof(IPropExprFactoryContracts))] - public interface IPropExprFactory - { - IFunApp/*!*/ False { get /*ensures result.FunctionSymbol.Equals(Prop.False);*/; } - IFunApp/*!*/ True { get /*ensures result.FunctionSymbol.Equals(Prop.True);*/; } - - IFunApp/*!*/ Not(IExpr/*!*/ p) /*ensures result.FunctionSymbol.Equals(Prop.Not);*/; - - IFunApp/*!*/ And(IExpr/*!*/ p, IExpr/*!*/ q) /*ensures result.FunctionSymbol.Equals(Prop.And);*/; - IFunApp/*!*/ Or(IExpr/*!*/ p, IExpr/*!*/ q) /*ensures result.FunctionSymbol.Equals(Prop.Or);*/; - - IFunApp/*!*/ Implies(IExpr/*!*/ p, IExpr/*!*/ q) /*ensures result.FunctionSymbol.Equals(Prop.Implies);*/; - } - [ContractClassFor(typeof(IPropExprFactory))] - public abstract class IPropExprFactoryContracts : IPropExprFactory - { - #region IPropExprFactory Members - IFunApp IPropExprFactory.Implies(IExpr p, IExpr q) { - Contract.Requires(p != null); - Contract.Requires(q != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp IPropExprFactory.False { - - get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } - } - - IFunApp IPropExprFactory.True { - get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } - } - - IFunApp IPropExprFactory.Not(IExpr p) { - Contract.Requires(p != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp IPropExprFactory.And(IExpr p, IExpr q) { - Contract.Requires(p != null); - Contract.Requires(q != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp IPropExprFactory.Or(IExpr p, IExpr q) { - Contract.Requires(p != null); - Contract.Requires(q != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - - - #endregion - } - - /// - /// An interface for constructing value expressions. - /// - /// This interface should be implemented by the client. An implementation of - /// of this class should generally be used as a singleton object. - /// - /// - [ContractClass(typeof(IValueExprFactoryContracts))] - public interface IValueExprFactory - { - IFunApp/*!*/ Eq(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Eq);*/; - IFunApp/*!*/ Neq(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Neq);*/; - } - [ContractClassFor(typeof(IValueExprFactory))] - public abstract class IValueExprFactoryContracts : IValueExprFactory - { - #region IValueExprFactory Members - - IFunApp IValueExprFactory.Eq(IExpr e0, IExpr e1) { - Contract.Requires(e0 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp IValueExprFactory.Neq(IExpr e0, IExpr e1) { - Contract.Requires(e0 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - #endregion - } - - /// - /// An interface for constructing value expressions having to with null. - /// - /// This interface should be implemented by the client. An implementation of - /// of this class should generally be used as a singleton object. - /// - /// - [ContractClass(typeof(INullnessFactoryContracts))] - public interface INullnessFactory - { - IFunApp/*!*/ Eq(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Eq);*/; - IFunApp/*!*/ Neq(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Neq);*/; - IFunApp/*!*/ Null { get; /*ensures result.FunctionSymbol.Equals(Ref.Null);*/ } - } - [ContractClassFor(typeof(INullnessFactory))] - public abstract class INullnessFactoryContracts : INullnessFactory - { - #region INullnessFactory Members - - IFunApp INullnessFactory.Eq(IExpr e0, IExpr e1) { - Contract.Requires(e0 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp INullnessFactory.Neq(IExpr e0, IExpr e1) { - Contract.Requires(e0 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp INullnessFactory.Null { - get { - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - } - - #endregion - } - - /// - /// An interface for constructing integer expressions. - /// - /// This interface should be implemented by the client. An implementation of - /// of this class should generally be used as a singleton object. - /// - /// - [ContractClass(typeof(IIntExprFactoryContracts))] - public interface IIntExprFactory : IValueExprFactory - { - IFunApp/*!*/ Const(BigNum i) /*ensures result.FunctionSymbol.Equals(new IntSymbol(i));*/; - } - [ContractClassFor(typeof(IIntExprFactory))] - public abstract class IIntExprFactoryContracts : IIntExprFactory - { - - #region IIntExprFactory Members - - IFunApp IIntExprFactory.Const(BigNum i) { - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - #endregion - - #region IValueExprFactory Members - - IFunApp IValueExprFactory.Eq(IExpr e0, IExpr e1) { - throw new System.NotImplementedException(); - } - - IFunApp IValueExprFactory.Neq(IExpr e0, IExpr e1) { - throw new System.NotImplementedException(); - } - - #endregion - } - - /// - /// An interface for constructing linear integer expressions. - /// - /// This interface should be implemented by the client. An implementation of - /// of this class should generally be used as a singleton object. - /// - /// - [ContractClass(typeof(ILinearExprFactoryContracts))] - public interface ILinearExprFactory : IIntExprFactory - { - IFunApp/*!*/ AtMost(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.AtMost);*/; - IFunApp/*!*/ Add(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Add);*/; - /// - /// If "var" is null, returns an expression representing r. - /// Otherwise, returns an expression representing r*var. - /// - IExpr/*!*/ Term(Microsoft.Basetypes.Rational r, IVariable var); - - IFunApp/*!*/ False { get /*ensures result.FunctionSymbol.Equals(Prop.False);*/; } - IFunApp/*!*/ True { get /*ensures result.FunctionSymbol.Equals(Prop.True);*/; } - IFunApp/*!*/ And(IExpr/*!*/ p, IExpr/*!*/ q) /*ensures result.FunctionSymbol.Equals(Prop.And);*/; - } - [ContractClassFor(typeof(ILinearExprFactory))] - public abstract class ILinearExprFactoryContracts : ILinearExprFactory - { - - #region ILinearExprFactory Members - - IFunApp ILinearExprFactory.AtMost(IExpr e0, IExpr e1) { - Contract.Requires(e0 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp ILinearExprFactory.Add(IExpr e0, IExpr e1) { - Contract.Requires(e0 != null); - Contract.Requires(e1 != null); Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IExpr ILinearExprFactory.Term(Rational r, IVariable var) { - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp ILinearExprFactory.False { - get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } - } - - IFunApp ILinearExprFactory.True { - get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } - } - - IFunApp ILinearExprFactory.And(IExpr p, IExpr q) { - Contract.Requires(p != null); - Contract.Requires(q != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - #endregion - - #region IIntExprFactory Members - - IFunApp IIntExprFactory.Const(BigNum i) { - throw new System.NotImplementedException(); - } - - #endregion - - #region IValueExprFactory Members - - IFunApp IValueExprFactory.Eq(IExpr e0, IExpr e1) { - throw new System.NotImplementedException(); - } - - IFunApp IValueExprFactory.Neq(IExpr e0, IExpr e1) { - throw new System.NotImplementedException(); - } - - #endregion - } - - /// - /// An interface for constructing type expressions and performing some type operations. - /// The types are assumed to be arranged in a rooted tree. - /// - /// This interface should be implemented by the client. An implementation of - /// of this class should generally be used as a singleton object. - /// - /// - [ContractClass(typeof(ITypeExprFactoryContracts))] - public interface ITypeExprFactory - { - /// - /// Returns an expression denoting the top of the type hierarchy. - /// - IExpr/*!*/ RootType { get; } - - /// - /// Returns true iff "t" denotes a type constant. - /// - [Pure] - bool IsTypeConstant(IExpr/*!*/ t); - - /// - /// Returns true iff t0 and t1 are types such that t0 and t1 are equal. - /// - [Pure] - bool IsTypeEqual(IExpr/*!*/ t0, IExpr/*!*/ t1); - - /// - /// Returns true iff t0 and t1 are types such that t0 is a subtype of t1. - /// - [Pure] - bool IsSubType(IExpr/*!*/ t0, IExpr/*!*/ t1); - - /// - /// Returns the most derived supertype of both "t0" and "t1". A precondition is - /// that "t0" and "t1" both represent types. - /// - IExpr/*!*/ JoinTypes(IExpr/*!*/ t0, IExpr/*!*/ t1); - - IFunApp/*!*/ IsExactlyA(IExpr/*!*/ e, IExpr/*!*/ type) /*requires IsTypeConstant(type); ensures result.FunctionSymbol.Equals(Value.Eq);*/; - IFunApp/*!*/ IsA(IExpr/*!*/ e, IExpr/*!*/ type) /*requires IsTypeConstant(type); ensures result.FunctionSymbol.Equals(Value.Subtype);*/; - } - [ContractClassFor(typeof(ITypeExprFactory))] - public abstract class ITypeExprFactoryContracts : ITypeExprFactory - { - - #region ITypeExprFactory Members - - IExpr ITypeExprFactory.RootType { - get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } - } - - bool ITypeExprFactory.IsTypeConstant(IExpr t) { - Contract.Requires(t != null); - throw new System.NotImplementedException(); - } - - bool ITypeExprFactory.IsTypeEqual(IExpr t0, IExpr t1) { - Contract.Requires(t0 != null); - Contract.Requires(t1 != null); - throw new System.NotImplementedException(); - } - - bool ITypeExprFactory.IsSubType(IExpr t0, IExpr t1) { - Contract.Requires(t0 != null); - Contract.Requires(t1 != null); - throw new System.NotImplementedException(); - } - - IExpr ITypeExprFactory.JoinTypes(IExpr t0, IExpr t1) { - Contract.Requires(t0 != null); - Contract.Requires(t1 != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp ITypeExprFactory.IsExactlyA(IExpr e, IExpr type) { - Contract.Requires(e != null); - Contract.Requires(type != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp ITypeExprFactory.IsA(IExpr e, IExpr type) { - Contract.Requires(e != null); - Contract.Requires(type != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - #endregion - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework +{ + using System.Diagnostics.Contracts; + using System.Collections; + using System.Collections.Generic; + //using Microsoft.SpecSharp.Collections; + using Microsoft.Basetypes; + + /// + /// A basic class for function symbols. + /// + public class FunctionSymbol : IFunctionSymbol + { + private readonly string/*!*/ display; + private readonly AIType/*!*/ typ; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(display != null); + Contract.Invariant(typ != null); + } + + + public FunctionSymbol(AIType/*!*/ typ) + : this("FunctionSymbol", typ) { + Contract.Requires(typ != null); + } + + internal FunctionSymbol(string/*!*/ display, AIType/*!*/ typ) { + Contract.Requires(typ != null); + Contract.Requires(display != null); + this.display = display; + this.typ = typ; + // base(); + } + + public AIType/*!*/ AIType { get { Contract.Ensures(Contract.Result() != null); return typ; } } + + [NoDefaultContract] + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return display; + } + + } + + /// + /// A class for integer constants. + /// + public class IntSymbol : FunctionSymbol + { + public readonly BigNum Value; + + /// + /// The intention is that this constructor be called only from the Int.Const method. + /// + internal IntSymbol(BigNum x) + : base(cce.NonNull(x.ToString()), Int.Type) { + this.Value = x; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object other) { + IntSymbol isym = other as IntSymbol; + return isym != null && isym.Value.Equals(this.Value); + } + + [Pure] + public override int GetHashCode() { + return Value.GetHashCode(); + } + } + + /// + /// A class for bitvector constants. + /// + public class BvSymbol : FunctionSymbol + { + public readonly BigNum Value; + public readonly int Bits; + + /// + /// The intention is that this constructor be called only from the Int.Const method. + /// + internal BvSymbol(BigNum x, int y) + : base(x + "bv" + y, Bv.Type) { + this.Value = x; + this.Bits = y; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object other) { + BvSymbol isym = other as BvSymbol; + return isym != null && isym.Value == this.Value && isym.Bits == this.Bits; + } + + [Pure] + public override int GetHashCode() { + unchecked { + return Value.GetHashCode() ^ Bits; + } + } + } + + public class DoubleSymbol : FunctionSymbol + { + public readonly double Value; + + /// + /// The intention is that this constructor be called only from the Double.Const method. + /// + internal DoubleSymbol(double x) + : base(cce.NonNull(x.ToString()), Double.Type) { + this.Value = x; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object other) { + DoubleSymbol dsym = other as DoubleSymbol; + return dsym != null && dsym.Value == this.Value; + } + + [Pure] + public override int GetHashCode() { + return Value.GetHashCode(); + } + } + + /// + /// Function symbol based on a string. Uses the string equality for determining equality + /// of symbol. + /// + public class NamedSymbol : FunctionSymbol + { + public string/*!*/ Value { [NoDefaultContract] get { Contract.Ensures(Contract.Result() != null); return cce.NonNull(this.ToString()); } } + + public NamedSymbol(string/*!*/ symbol, AIType/*!*/ typ) + : base(symbol, typ) { + Contract.Requires(typ != null); + Contract.Requires(symbol != null); + } + + [NoDefaultContract] + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object other) { + NamedSymbol nsym = other as NamedSymbol; + return nsym != null && this.Value.Equals(nsym.Value); + } + + [NoDefaultContract] + [Pure] + public override int GetHashCode() { + return Value.GetHashCode(); + } + } + + // + // In the following, the classes like Value and Prop serve two + // roles. The primary role is to be the base types for AIType. + // The only objects of these classes are the representative + // objects that denote an AIType, which are given by the + // "Type" property. Subtypes in the AIType language are + // encoded by subclassing. This yields some "higher-orderness" + // for checking subtyping in the AIType language, by using + // the Spec#/C# subclassing checks. + // + // The other role is simply as a module for collecting like function + // symbols. + // + + //-------------------------- Terms ---------------------------------- + + /// + /// A class with the equality symbol and the ValueType.Type. + /// + public class Value : AIType + { + private static readonly AIType/*!*/ valtype = new Value(); + public static AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return valtype; } } + + private static readonly FunctionType[]/*!*/ funtypeCache = new FunctionType[5]; + public static FunctionType/*!*/ FunctionType(int inParameterCount) { + Contract.Requires((0 <= inParameterCount)); + Contract.Ensures(Contract.Result() != null); + // Contract.Ensures(Contract.Result<>().Arity == inParameterCount); + FunctionType result; + if (inParameterCount < funtypeCache.Length) { + result = funtypeCache[inParameterCount]; + if (result != null) { + return result; + } + } + AIType[] signature = new AIType[1 + inParameterCount]; + for (int i = 0; i < signature.Length; i++) { + signature[i] = valtype; + } + result = new FunctionType(signature); + if (inParameterCount < funtypeCache.Length) { + funtypeCache[inParameterCount] = result; + } + return result; + } + + [Once] + private static AIType/*!*/ binreltype; + + private static AIType/*!*/ BinrelType { + get { + Contract.Ensures(Contract.Result() != null); + if (binreltype == null) { + binreltype = new FunctionType(Type, Type, Prop.Type); + } + return binreltype; + } + } + + [Once] + private static FunctionSymbol/*!*/ _eq; + public static FunctionSymbol/*!*/ Eq { + get { + Contract.Ensures(Contract.Result() != null); + if (_eq == null) { + _eq = new FunctionSymbol("=", BinrelType); + } + return _eq; + } + } + [Once] + private static FunctionSymbol/*!*/ _neq; + public static FunctionSymbol/*!*/ Neq { + get { + Contract.Ensures(Contract.Result() != null); + if (_neq == null) { + _neq = new FunctionSymbol("!=", BinrelType); + } + return _neq; + } + } + [Once] + private static FunctionSymbol/*!*/ _subtype; + public static FunctionSymbol/*!*/ Subtype { + get { + Contract.Ensures(Contract.Result() != null); + if (_subtype == null) { + _subtype = new FunctionSymbol("<:", BinrelType); + } + return _subtype; + } + } + + [Once] + private static AIType/*!*/ typeof_type; + private static AIType/*!*/ TypeofType { + get { + Contract.Ensures(Contract.Result() != null); + if (typeof_type == null) { + typeof_type = new FunctionType(Ref.Type, Type); + } + return typeof_type; + } + } + [Once] + private static FunctionSymbol/*!*/ _typeof; + public static FunctionSymbol/*!*/ Typeof { + get { + Contract.Ensures(Contract.Result() != null); + if (_typeof == null) { + _typeof = new FunctionSymbol("typeof", TypeofType); + } + return _typeof; + } + } + + /// + /// Value should not be instantiated from the outside, except perhaps in + /// subclasses. + /// + protected Value() { } + + } + + public class Int : Value + { + private static readonly AIType/*!*/ inttype = new Int(); + public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return inttype; } } + + private static readonly AIType/*!*/ unaryinttype = new FunctionType(Type, Type); + private static readonly AIType/*!*/ bininttype = new FunctionType(Type, Type, Type); + private static readonly AIType/*!*/ relationtype = new FunctionType(Type, Type, Prop.Type); + + private static readonly FunctionSymbol/*!*/ _negate = new FunctionSymbol("~", unaryinttype); + private static readonly FunctionSymbol/*!*/ _add = new FunctionSymbol("+", bininttype); + private static readonly FunctionSymbol/*!*/ _sub = new FunctionSymbol("-", bininttype); + private static readonly FunctionSymbol/*!*/ _mul = new FunctionSymbol("*", bininttype); + private static readonly FunctionSymbol/*!*/ _div = new FunctionSymbol("/", bininttype); + private static readonly FunctionSymbol/*!*/ _mod = new FunctionSymbol("%", bininttype); + private static readonly FunctionSymbol/*!*/ _atmost = new FunctionSymbol("<=", relationtype); + private static readonly FunctionSymbol/*!*/ _less = new FunctionSymbol("<", relationtype); + private static readonly FunctionSymbol/*!*/ _greater = new FunctionSymbol(">", relationtype); + private static readonly FunctionSymbol/*!*/ _atleast = new FunctionSymbol(">=", relationtype); + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Negate { get { Contract.Ensures(Contract.Result() != null); return _negate; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Add { get { Contract.Ensures(Contract.Result() != null); return _add; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Sub { get { Contract.Ensures(Contract.Result() != null); return _sub; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Mul { get { Contract.Ensures(Contract.Result() != null); return _mul; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Div { get { Contract.Ensures(Contract.Result() != null); return _div; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Mod { get { Contract.Ensures(Contract.Result() != null); return _mod; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ AtMost { get { Contract.Ensures(Contract.Result() != null); return _atmost; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Less { get { Contract.Ensures(Contract.Result() != null); return _less; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Greater { get { Contract.Ensures(Contract.Result() != null); return _greater; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ AtLeast { get { Contract.Ensures(Contract.Result() != null); return _atleast; } } + + public static IntSymbol/*!*/ Const(BigNum x) { + Contract.Ensures(Contract.Result() != null); + // We could cache things here, but for now we don't. + return new IntSymbol(x); + } + + /// + /// Int should not be instantiated from the outside, except perhaps in + /// subclasses. + /// + private Int() { } + } + + public class Double : Value + { + private static readonly AIType/*!*/ doubletype = new Double(); + public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return doubletype; } } + + public static DoubleSymbol/*!*/ Const(double x) { + Contract.Ensures(Contract.Result() != null); + // We could cache things here, but for now we don't. + return new DoubleSymbol(x); + } + + /// + /// Double should not be instantiated from the outside, except perhaps in + /// subclasses. + /// + private Double() { } + } + + public class Bv : Value + { + private static readonly AIType/*!*/ bvtype = new Bv(); + public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return bvtype; } } + + private static readonly AIType/*!*/ unaryinttype = new FunctionType(Type, Type); + private static readonly AIType/*!*/ bininttype = new FunctionType(Type, Type, Type); + private static readonly AIType/*!*/ relationtype = new FunctionType(Type, Type, Prop.Type); + + private static readonly FunctionSymbol/*!*/ _negate = new FunctionSymbol("~", unaryinttype); + private static readonly FunctionSymbol/*!*/ _add = new FunctionSymbol("+", bininttype); + private static readonly FunctionSymbol/*!*/ _sub = new FunctionSymbol("-", bininttype); + private static readonly FunctionSymbol/*!*/ _mul = new FunctionSymbol("*", bininttype); + private static readonly FunctionSymbol/*!*/ _div = new FunctionSymbol("/", bininttype); + private static readonly FunctionSymbol/*!*/ _mod = new FunctionSymbol("%", bininttype); + private static readonly FunctionSymbol/*!*/ _concat = new FunctionSymbol("$concat", bininttype); + private static readonly FunctionSymbol/*!*/ _extract = new FunctionSymbol("$extract", unaryinttype); + private static readonly FunctionSymbol/*!*/ _atmost = new FunctionSymbol("<=", relationtype); + private static readonly FunctionSymbol/*!*/ _less = new FunctionSymbol("<", relationtype); + private static readonly FunctionSymbol/*!*/ _greater = new FunctionSymbol(">", relationtype); + private static readonly FunctionSymbol/*!*/ _atleast = new FunctionSymbol(">=", relationtype); + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Negate { get { Contract.Ensures(Contract.Result() != null); return _negate; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Add { get { Contract.Ensures(Contract.Result() != null); return _add; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Sub { get { Contract.Ensures(Contract.Result() != null); return _sub; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Mul { get { Contract.Ensures(Contract.Result() != null); return _mul; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Div { get { Contract.Ensures(Contract.Result() != null); return _div; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Mod { get { Contract.Ensures(Contract.Result() != null); return _mod; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ AtMost { get { Contract.Ensures(Contract.Result() != null); return _atmost; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Less { get { Contract.Ensures(Contract.Result() != null); return _less; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Greater { get { Contract.Ensures(Contract.Result() != null); return _greater; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ AtLeast { get { Contract.Ensures(Contract.Result() != null); return _atleast; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Extract { get { Contract.Ensures(Contract.Result() != null); return _extract; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Concat { get { Contract.Ensures(Contract.Result() != null); return _concat; } } + + public static BvSymbol/*!*/ Const(BigNum x, int y) { + Contract.Ensures(Contract.Result() != null); + // We could cache things here, but for now we don't. + return new BvSymbol(x, y); + } + + /// + /// Int should not be instantiated from the outside, except perhaps in + /// subclasses. + /// + private Bv() { } + } + + public class Ref : Value + { + private static readonly AIType/*!*/ reftype = new Ref(); + public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return reftype; } } + + private static readonly FunctionSymbol/*!*/ _null = new FunctionSymbol("null", Type); + + public static FunctionSymbol/*!*/ Null { get { Contract.Ensures(Contract.Result() != null); return _null; } } + + /// + /// Ref should not be instantiated from the outside, except perhaps in + /// subclasses. + /// + private Ref() { } + } + + public class HeapStructure : Value + { + private static readonly AIType/*!*/ reftype = new HeapStructure(); + public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return reftype; } } + + + + /// + /// HeapStructure should not be instantiated from the outside, except perhaps in + /// subclasses. + /// + private HeapStructure() { } + } + + public class FieldName : Value + { + private static readonly AIType/*!*/ fieldnametype = new FieldName(); + public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return fieldnametype; } } + + private static readonly FunctionSymbol/*!*/ _allocated = new FunctionSymbol("$allocated", FieldName.Type); + public static FunctionSymbol/*!*/ Allocated { get { Contract.Ensures(Contract.Result() != null); return _allocated; } } + + /// + /// Is this a boolean field that monotonically goes from false to true? + /// + public static bool IsBooleanMonotonicallyWeakening(IFunctionSymbol/*!*/ f) { + Contract.Requires(f != null); + return f.Equals(Allocated); + } + + /// + /// FieldName should not be instantiated from the outside, except perhaps in + /// subclasses. + /// + private FieldName() { } + } + + public class Heap : Value + { + private static readonly AIType/*!*/ heaptype = new Heap(); + public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return heaptype; } } + + // the types in the following, select1, select2, are hard-coded; + // these types may not always be appropriate + private static readonly FunctionSymbol/*!*/ _select1 = new FunctionSymbol("sel1", + // Heap x FieldName -> Prop + new FunctionType(Type, FieldName.Type, Prop.Type) + ); + public static FunctionSymbol/*!*/ Select1 { get { Contract.Ensures(Contract.Result() != null); return _select1; } } + + private static readonly FunctionSymbol/*!*/ _select2 = new FunctionSymbol("sel2", + // Heap x Ref x FieldName -> Value + new FunctionType(Type, Ref.Type, FieldName.Type, Value.Type) + ); + public static FunctionSymbol/*!*/ Select2 { get { Contract.Ensures(Contract.Result() != null); return _select2; } } + + // the types in the following, store1, store2, are hard-coded; + // these types may not always be appropriate + private static readonly FunctionSymbol/*!*/ _update1 = new FunctionSymbol("upd1", + // Heap x FieldName x Value -> Heap + new FunctionType(Type, FieldName.Type, Value.Type, Type) + ); + public static FunctionSymbol/*!*/ Update1 { get { Contract.Ensures(Contract.Result() != null); return _update1; } } + + private static readonly FunctionSymbol/*!*/ _update2 = new FunctionSymbol("upd2", + // Heap x Ref x FieldName x Value -> Heap + new FunctionType(Type, Ref.Type, FieldName.Type, Value.Type, Type) + ); + public static FunctionSymbol/*!*/ Update2 { get { Contract.Ensures(Contract.Result() != null); return _update2; } } + + private static readonly FunctionSymbol/*!*/ _unsupportedHeapOp = + new FunctionSymbol("UnsupportedHeapOp", + // Heap x FieldName -> Prop + new FunctionType(Type, FieldName.Type, Prop.Type) + ); + public static FunctionSymbol/*!*/ UnsupportedHeapOp { get { Contract.Ensures(Contract.Result() != null); return _unsupportedHeapOp; } } + + /// + /// Heap should not be instantiated from the outside, except perhaps in + /// subclasses. + /// + private Heap() { } + } + + // public class List : Value + // { + // private static IDictionary/**/! lists = new Hashtable(); + // public static AIType! Type(AIType! typeParameter) + // { + // if (lists.Contains(typeParameter)) + // return lists[typeParameter]; + // else + // { + // AIType! result = new List(typeParameter); + // lists[typeParameter] = result; + // return result; + // } + // } + // + // private static IDictionary/**/! nils = new Hashtable(); + // public static FunctionSymbol! Nil(AIType! typeParameter) + // { + // if (nils.Contains(typeParameter)) + // return nils[typeParameter]; + // else + // { + // FunctionSymbol! result = new FunctionSymbol(Type(typeParameter)); + // nils[typeParameter] = result; + // return result; + // } + // } + // + // private static IDictionary/**/! cons = new Hashtable(); + // public static FunctionSymbol! Cons(AIType! typeParameter) + // { + // if (cons.Contains(typeParameter)) + // return cons[typeParameter]; + // else + // { + // FunctionSymbol! result = new FunctionSymbol( + // new FunctionType(typeParameter, Type(typeParameter), Type(typeParameter)) + // ); + // cons[typeParameter] = result; + // return result; + // } + // } + // + // private AIType! typeParameter; + // public AIType(TypeParameter/*!*/ ){ + //Contract.Requires( != null); + //return typeParameter; } } + // + // /// + // /// List should not be instantiated from the outside. + // /// + // private List(AIType! typeParameter) + // { + // this.typeParameter = typeParameter; + // } + // } + // + // public class Pair : Value + // { + // private static IDictionary! pairs = new Hashtable(); + // public static AIType! Type(AIType! type1, AIType! type2) + // { + // Microsoft.AbstractInterpretationFramework.Collections.Pair typpair + // = new Microsoft.AbstractInterpretationFramework.Collections.Pair(type1, type2); + // + // if (pairs.Contains(typpair)) + // return pairs[typpair]; + // else + // { + // AIType! result = new Pair(type1, type2); + // pairs[typpair] = result; + // return result; + // } + // } + // + // private static IDictionary! constructs = new Hashtable(); + // public static FunctionSymbol! Pair(AIType! type1, AIType! type2) + // { + // Microsoft.AbstractInterpretationFramework.Collections.Pair typpair + // = new Microsoft.AbstractInterpretationFramework.Collections.Pair(type1, type2); + // + // if (constructs.Contains(typpair)) + // return constructs[typpair]; + // else + // { + // FunctionSymbol! result = new FunctionSymbol( + // new FunctionType(type1, type2, Type(type1, type2)) + // ); + // constructs[typpair] = result; + // return result; + // } + // } + // + // protected AIType! type1; + // protected AIType! type2; + // + // public AIType(Type1/*!*/ ){ + //Contract.Requires( != null); + // return type1; } } + // public AIType(Type2/*!*/ ){ + //Contract.Requires( != null); + // return type2; } } + // + // /// + // /// Pair should not be instantiated from the outside, except by subclasses. + // /// + // protected Pair(AIType! type1, AIType! type2) + // { + // this.type1 = type1; + // this.type2 = type2; + // } + // } + + //-------------------------- Propositions --------------------------- + + + /// + /// A class with global propositional symbols and the Prop.Type. + /// + public sealed class Prop : AIType + { + private static readonly AIType/*!*/ proptype = new Prop(); + + public static AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return proptype; } } + + private static readonly AIType/*!*/ unaryproptype = new FunctionType(Type, Type); + private static readonly AIType/*!*/ binproptype = new FunctionType(Type, Type, Type); + private static readonly AIType/*!*/ quantifiertype = + new FunctionType(new FunctionType(Value.Type, Type), Type); + + private static readonly FunctionSymbol/*!*/ _false = new FunctionSymbol("false", Type); + private static readonly FunctionSymbol/*!*/ _true = new FunctionSymbol("true", Type); + private static readonly FunctionSymbol/*!*/ _not = new FunctionSymbol("!", unaryproptype); + private static readonly FunctionSymbol/*!*/ _and = new FunctionSymbol("/\\", binproptype); + private static readonly FunctionSymbol/*!*/ _or = new FunctionSymbol("\\/", binproptype); + private static readonly FunctionSymbol/*!*/ _implies = new FunctionSymbol("==>", binproptype); + private static readonly FunctionSymbol/*!*/ _exists = new FunctionSymbol("Exists", quantifiertype); + private static readonly FunctionSymbol/*!*/ _forall = new FunctionSymbol("Forall", quantifiertype); + private static readonly FunctionSymbol/*!*/ _lambda = new FunctionSymbol("Lambda", quantifiertype); + + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ False { get { Contract.Ensures(Contract.Result() != null); return _false; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ True { get { Contract.Ensures(Contract.Result() != null); return _true; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Not { get { Contract.Ensures(Contract.Result() != null); return _not; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ And { [Pure] get { Contract.Ensures(Contract.Result() != null); return _and; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Or { get { Contract.Ensures(Contract.Result() != null); return _or; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Implies { get { Contract.Ensures(Contract.Result() != null); return _implies; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Exists { get { Contract.Ensures(Contract.Result() != null); return _exists; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Forall { get { Contract.Ensures(Contract.Result() != null); return _forall; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Lambda { get { Contract.Ensures(Contract.Result() != null); return _lambda; } } + + + /// + /// Prop should not be instantiated from the outside. + /// + private Prop() { } + + + + // + // Utility Methods + // + + public static IExpr/*!*/ SimplifiedAnd(IPropExprFactory/*!*/ factory, IExpr/*!*/ e0, IExpr/*!*/ e1) { + Contract.Requires(e1 != null); + Contract.Requires(e0 != null); + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result() != null); + IFunApp fun0 = e0 as IFunApp; + if (fun0 != null) { + if (fun0.FunctionSymbol.Equals(Prop.True)) { + return e1; + } else if (fun0.FunctionSymbol.Equals(Prop.False)) { + return e0; + } + } + + IFunApp fun1 = e1 as IFunApp; + if (fun1 != null) { + if (fun1.FunctionSymbol.Equals(Prop.True)) { + return e0; + } else if (fun1.FunctionSymbol.Equals(Prop.False)) { + return e1; + } + } + + return factory.And(e0, e1); + } + + public static IExpr/*!*/ SimplifiedAnd(IPropExprFactory/*!*/ factory, IEnumerable/**//*!*/ exprs) { + Contract.Requires(exprs != null); + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result() != null); + IExpr/*!*/ result = factory.True; + Contract.Assert(result != null); + foreach (IExpr/*!*/ conjunct in exprs) { + Contract.Assert(conjunct != null); + result = SimplifiedAnd(factory, result, conjunct); + } + return result; + } + + public static IExpr/*!*/ SimplifiedOr(IPropExprFactory/*!*/ factory, IExpr/*!*/ e0, IExpr/*!*/ e1) { + Contract.Requires(e1 != null); + Contract.Requires(e0 != null); + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result() != null); + IFunApp fun0 = e0 as IFunApp; + if (fun0 != null) { + if (fun0.FunctionSymbol.Equals(Prop.False)) { + return e1; + } else if (fun0.FunctionSymbol.Equals(Prop.True)) { + return e0; + } + } + + IFunApp fun1 = e1 as IFunApp; + if (fun1 != null) { + if (fun1.FunctionSymbol.Equals(Prop.False)) { + return e0; + } else if (fun1.FunctionSymbol.Equals(Prop.True)) { + return e1; + } + } + + return factory.Or(e0, e1); + } + + public static IExpr/*!*/ SimplifiedOr(IPropExprFactory/*!*/ factory, IEnumerable/**//*!*/ exprs) { + Contract.Requires(exprs != null); + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result() != null); + IExpr/*!*/ result = factory.False; + Contract.Assert(result != null); + foreach (IExpr/*!*/ disj in exprs) { + Contract.Assert(disj != null); + result = SimplifiedOr(factory, result, disj); + } + return result; + } + + + + /// + /// Break top-level conjuncts into a list of sub-expressions. + /// + /// The expression to examine. + /// A list of conjuncts. + internal static IList/**//*!*/ BreakConjuncts(IExpr/*!*/ e) { + Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.ForAll(0, Contract.Result().Count, i => { + var sub = Contract.Result()[i]; + return !(sub is IFunApp) || !((IFunApp)sub).FunctionSymbol.Equals(Prop.And); + })); + return BreakJuncts(e, Prop.And); + } + + /// + /// Break top-level disjuncts into a list of sub-expressions. + /// + /// The expression to examine. + /// A list of conjuncts. + internal static IList/**//*!*/ BreakDisjuncts(IExpr/*!*/ e) { + Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.ForAll(0, Contract.Result().Count, i => { + var sub = Contract.Result()[i]; + return !(sub is IFunApp) || !((IFunApp)sub).FunctionSymbol.Equals(Prop.Or); + })); + return BreakJuncts(e, Prop.Or); + } + + private static IList/**//*!*/ BreakJuncts(IExpr/*!*/ e, IFunctionSymbol/*!*/ sym) { + Contract.Requires(sym != null); + Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.ForAll(0, Contract.Result().Count, i => { + var sub = Contract.Result()[i]; + return (sub is IFunApp) || !((IFunApp)sub).FunctionSymbol.Equals(sym); + })); + ArrayList/**//*!*/ result = new ArrayList(); + + IFunApp f = e as IFunApp; + if (f != null) { + // If it is a sym, go down into sub-expressions. + if (f.FunctionSymbol.Equals(sym)) { + foreach (IExpr/*!*/ arg in f.Arguments) { + Contract.Assert(arg != null); + result.AddRange(BreakJuncts(arg, sym)); + } + } + // Otherwise, stop. + else { + result.Add(e); + } + } else { + result.Add(e); + } + + return result; + } + } + + /// + /// A callback to produce a function body given the bound variable. + /// + /// The bound variable to use. + /// The function body. + public delegate IExpr/*!*/ FunctionBody(IVariable/*!*/ var); + + /// + /// An interface for constructing propositional expressions. + /// + /// This interface should be implemented by the client. An implementation of + /// of this class should generally be used as a singleton object. + /// + /// + [ContractClass(typeof(IPropExprFactoryContracts))] + public interface IPropExprFactory + { + IFunApp/*!*/ False { get /*ensures result.FunctionSymbol.Equals(Prop.False);*/; } + IFunApp/*!*/ True { get /*ensures result.FunctionSymbol.Equals(Prop.True);*/; } + + IFunApp/*!*/ Not(IExpr/*!*/ p) /*ensures result.FunctionSymbol.Equals(Prop.Not);*/; + + IFunApp/*!*/ And(IExpr/*!*/ p, IExpr/*!*/ q) /*ensures result.FunctionSymbol.Equals(Prop.And);*/; + IFunApp/*!*/ Or(IExpr/*!*/ p, IExpr/*!*/ q) /*ensures result.FunctionSymbol.Equals(Prop.Or);*/; + + IFunApp/*!*/ Implies(IExpr/*!*/ p, IExpr/*!*/ q) /*ensures result.FunctionSymbol.Equals(Prop.Implies);*/; + } + [ContractClassFor(typeof(IPropExprFactory))] + public abstract class IPropExprFactoryContracts : IPropExprFactory + { + #region IPropExprFactory Members + IFunApp IPropExprFactory.Implies(IExpr p, IExpr q) { + Contract.Requires(p != null); + Contract.Requires(q != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp IPropExprFactory.False { + + get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } + } + + IFunApp IPropExprFactory.True { + get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } + } + + IFunApp IPropExprFactory.Not(IExpr p) { + Contract.Requires(p != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp IPropExprFactory.And(IExpr p, IExpr q) { + Contract.Requires(p != null); + Contract.Requires(q != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp IPropExprFactory.Or(IExpr p, IExpr q) { + Contract.Requires(p != null); + Contract.Requires(q != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + + + #endregion + } + + /// + /// An interface for constructing value expressions. + /// + /// This interface should be implemented by the client. An implementation of + /// of this class should generally be used as a singleton object. + /// + /// + [ContractClass(typeof(IValueExprFactoryContracts))] + public interface IValueExprFactory + { + IFunApp/*!*/ Eq(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Eq);*/; + IFunApp/*!*/ Neq(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Neq);*/; + } + [ContractClassFor(typeof(IValueExprFactory))] + public abstract class IValueExprFactoryContracts : IValueExprFactory + { + #region IValueExprFactory Members + + IFunApp IValueExprFactory.Eq(IExpr e0, IExpr e1) { + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp IValueExprFactory.Neq(IExpr e0, IExpr e1) { + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + #endregion + } + + /// + /// An interface for constructing value expressions having to with null. + /// + /// This interface should be implemented by the client. An implementation of + /// of this class should generally be used as a singleton object. + /// + /// + [ContractClass(typeof(INullnessFactoryContracts))] + public interface INullnessFactory + { + IFunApp/*!*/ Eq(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Eq);*/; + IFunApp/*!*/ Neq(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Neq);*/; + IFunApp/*!*/ Null { get; /*ensures result.FunctionSymbol.Equals(Ref.Null);*/ } + } + [ContractClassFor(typeof(INullnessFactory))] + public abstract class INullnessFactoryContracts : INullnessFactory + { + #region INullnessFactory Members + + IFunApp INullnessFactory.Eq(IExpr e0, IExpr e1) { + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp INullnessFactory.Neq(IExpr e0, IExpr e1) { + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp INullnessFactory.Null { + get { + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + } + + #endregion + } + + /// + /// An interface for constructing integer expressions. + /// + /// This interface should be implemented by the client. An implementation of + /// of this class should generally be used as a singleton object. + /// + /// + [ContractClass(typeof(IIntExprFactoryContracts))] + public interface IIntExprFactory : IValueExprFactory + { + IFunApp/*!*/ Const(BigNum i) /*ensures result.FunctionSymbol.Equals(new IntSymbol(i));*/; + } + [ContractClassFor(typeof(IIntExprFactory))] + public abstract class IIntExprFactoryContracts : IIntExprFactory + { + + #region IIntExprFactory Members + + IFunApp IIntExprFactory.Const(BigNum i) { + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + #endregion + + #region IValueExprFactory Members + + IFunApp IValueExprFactory.Eq(IExpr e0, IExpr e1) { + throw new System.NotImplementedException(); + } + + IFunApp IValueExprFactory.Neq(IExpr e0, IExpr e1) { + throw new System.NotImplementedException(); + } + + #endregion + } + + /// + /// An interface for constructing linear integer expressions. + /// + /// This interface should be implemented by the client. An implementation of + /// of this class should generally be used as a singleton object. + /// + /// + [ContractClass(typeof(ILinearExprFactoryContracts))] + public interface ILinearExprFactory : IIntExprFactory + { + IFunApp/*!*/ AtMost(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.AtMost);*/; + IFunApp/*!*/ Add(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Add);*/; + /// + /// If "var" is null, returns an expression representing r. + /// Otherwise, returns an expression representing r*var. + /// + IExpr/*!*/ Term(Microsoft.Basetypes.Rational r, IVariable var); + + IFunApp/*!*/ False { get /*ensures result.FunctionSymbol.Equals(Prop.False);*/; } + IFunApp/*!*/ True { get /*ensures result.FunctionSymbol.Equals(Prop.True);*/; } + IFunApp/*!*/ And(IExpr/*!*/ p, IExpr/*!*/ q) /*ensures result.FunctionSymbol.Equals(Prop.And);*/; + } + [ContractClassFor(typeof(ILinearExprFactory))] + public abstract class ILinearExprFactoryContracts : ILinearExprFactory + { + + #region ILinearExprFactory Members + + IFunApp ILinearExprFactory.AtMost(IExpr e0, IExpr e1) { + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp ILinearExprFactory.Add(IExpr e0, IExpr e1) { + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IExpr ILinearExprFactory.Term(Rational r, IVariable var) { + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp ILinearExprFactory.False { + get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } + } + + IFunApp ILinearExprFactory.True { + get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } + } + + IFunApp ILinearExprFactory.And(IExpr p, IExpr q) { + Contract.Requires(p != null); + Contract.Requires(q != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + #endregion + + #region IIntExprFactory Members + + IFunApp IIntExprFactory.Const(BigNum i) { + throw new System.NotImplementedException(); + } + + #endregion + + #region IValueExprFactory Members + + IFunApp IValueExprFactory.Eq(IExpr e0, IExpr e1) { + throw new System.NotImplementedException(); + } + + IFunApp IValueExprFactory.Neq(IExpr e0, IExpr e1) { + throw new System.NotImplementedException(); + } + + #endregion + } + + /// + /// An interface for constructing type expressions and performing some type operations. + /// The types are assumed to be arranged in a rooted tree. + /// + /// This interface should be implemented by the client. An implementation of + /// of this class should generally be used as a singleton object. + /// + /// + [ContractClass(typeof(ITypeExprFactoryContracts))] + public interface ITypeExprFactory + { + /// + /// Returns an expression denoting the top of the type hierarchy. + /// + IExpr/*!*/ RootType { get; } + + /// + /// Returns true iff "t" denotes a type constant. + /// + [Pure] + bool IsTypeConstant(IExpr/*!*/ t); + + /// + /// Returns true iff t0 and t1 are types such that t0 and t1 are equal. + /// + [Pure] + bool IsTypeEqual(IExpr/*!*/ t0, IExpr/*!*/ t1); + + /// + /// Returns true iff t0 and t1 are types such that t0 is a subtype of t1. + /// + [Pure] + bool IsSubType(IExpr/*!*/ t0, IExpr/*!*/ t1); + + /// + /// Returns the most derived supertype of both "t0" and "t1". A precondition is + /// that "t0" and "t1" both represent types. + /// + IExpr/*!*/ JoinTypes(IExpr/*!*/ t0, IExpr/*!*/ t1); + + IFunApp/*!*/ IsExactlyA(IExpr/*!*/ e, IExpr/*!*/ type) /*requires IsTypeConstant(type); ensures result.FunctionSymbol.Equals(Value.Eq);*/; + IFunApp/*!*/ IsA(IExpr/*!*/ e, IExpr/*!*/ type) /*requires IsTypeConstant(type); ensures result.FunctionSymbol.Equals(Value.Subtype);*/; + } + [ContractClassFor(typeof(ITypeExprFactory))] + public abstract class ITypeExprFactoryContracts : ITypeExprFactory + { + + #region ITypeExprFactory Members + + IExpr ITypeExprFactory.RootType { + get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } + } + + bool ITypeExprFactory.IsTypeConstant(IExpr t) { + Contract.Requires(t != null); + throw new System.NotImplementedException(); + } + + bool ITypeExprFactory.IsTypeEqual(IExpr t0, IExpr t1) { + Contract.Requires(t0 != null); + Contract.Requires(t1 != null); + throw new System.NotImplementedException(); + } + + bool ITypeExprFactory.IsSubType(IExpr t0, IExpr t1) { + Contract.Requires(t0 != null); + Contract.Requires(t1 != null); + throw new System.NotImplementedException(); + } + + IExpr ITypeExprFactory.JoinTypes(IExpr t0, IExpr t1) { + Contract.Requires(t0 != null); + Contract.Requires(t1 != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp ITypeExprFactory.IsExactlyA(IExpr e, IExpr type) { + Contract.Requires(e != null); + Contract.Requires(type != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp ITypeExprFactory.IsA(IExpr e, IExpr type) { + Contract.Requires(e != null); + Contract.Requires(type != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + #endregion + } +} diff --git a/Source/AIFramework/Expr.cs b/Source/AIFramework/Expr.cs index 58473592..ae2bd4b7 100644 --- a/Source/AIFramework/Expr.cs +++ b/Source/AIFramework/Expr.cs @@ -1,640 +1,640 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -// This file specifies the expression language used by the Abstract -// Interpretation Framework. -// -// expressions e ::= x variables -// | f(e1,...,en) uninterpreted functions -// | \x:t.e lambda expressions -// -// types t ::= b user-defined/built-in base types -// | t1 * ... * tn -> t' function type - -namespace Microsoft.AbstractInterpretationFramework -{ - using System.Collections; - using System; - using System.Diagnostics.Contracts; - - //----------------------------- Expressions ----------------------------- - - /// - /// An interface for expressions. This expression language is specified - /// by interfaces to allow the client to be able to use their existing - /// AST nodes as AIF expressions. - /// - /// This only serves as a place for operations on expressions. Clients - /// should implement directly IVariable, IFunApp, ... - /// - [ContractClass(typeof(IExprContracts))] - public interface IExpr - { - /// - /// Execute a visit over the expression. - /// - /// The expression visitor. - /// The result of the visit. - [Pure] object DoVisit(ExprVisitor/*!*/ visitor); - - // TODO: Type checking of the expressions. - } - [ContractClassFor(typeof(IExpr))] - public abstract class IExprContracts:IExpr{ - #region IExpr Members - -public object DoVisit(ExprVisitor visitor) -{ - Contract.Requires(visitor != null); - throw new System.NotImplementedException(); -} - -#endregion -} - - /// - /// An interface for variables. - /// - /// This interface should be implemented by the client. - /// - [ContractClass(typeof(IVariableContracts))] - public interface IVariable : IExpr - { - string/*!*/ Name { get; } // Each client must define the name for variables - } - [ContractClassFor(typeof(IVariable))] - public abstract class IVariableContracts:IVariable{ - string IVariable.Name{get{Contract.Ensures(Contract.Result() != null);throw new NotImplementedException();} - - } - - #region IExpr Members - - object IExpr.DoVisit(ExprVisitor visitor) { - throw new NotImplementedException(); - } - - #endregion - } - - /// - /// An interface for function applications. - /// - /// This interface should be implemented by the client. - /// - /// - [ContractClass(typeof(IFunAppContracts))] - public interface IFunApp : IExpr - { - IFunctionSymbol/*!*/ FunctionSymbol { get; } - IList/**//*!*/ Arguments - { - [Pure][Rep] get; - - } - - /// - /// Provides a method to create a new uninterpreted function - /// with the same function symbol but with the arguments with - /// args. - /// - /// The new arguments. - /// A copy of the function with the new arguments. - IFunApp/*!*/ CloneWithArguments(IList/**//*!*/ args) - //TODO Contract.Requires(this.Arguments.Count == args.Count); - ; - } - [ContractClassFor(typeof(IFunApp))] -public abstract class IFunAppContracts:IFunApp{ - -#region IFunApp Members - -public IFunctionSymbol FunctionSymbol -{ - get {Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); } -} - -public IList Arguments -{ - get {Contract.Ensures(Contract.Result() != null); - Contract.Ensures(Contract.Result().IsReadOnly); - throw new System.NotImplementedException(); } -} - -public IFunApp CloneWithArguments(IList args) -{ - Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - - - throw new System.NotImplementedException(); -} - -#endregion - -#region IExpr Members - -object IExpr.DoVisit(ExprVisitor visitor) { - throw new NotImplementedException(); -} - -#endregion -} - - /// - /// An interface for anonymous functions (i.e., lambda expressions) - /// - [ContractClass(typeof(IFunctionContracts))] - public interface IFunction : IExpr - { - IVariable/*!*/ Param { get; } - AIType/*!*/ ParamType { get; } - IExpr/*!*/ Body { get; } - - IFunction/*!*/ CloneWithBody(IExpr/*!*/ body); - } - [ContractClassFor(typeof(IFunction))] - public abstract class IFunctionContracts:IFunction{ - - #region IFunction Members - - IVariable IFunction.Param { - get { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - - AIType IFunction.ParamType { - get { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - - IExpr IFunction.Body { - get { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - - IFunction IFunction.CloneWithBody(IExpr body) { - Contract.Requires(body != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - - #endregion - - #region IExpr Members - - object IExpr.DoVisit(ExprVisitor visitor) { - throw new NotImplementedException(); - } - - #endregion - } - - /// - /// An interface representing an expression that at any moment could, in principle, evaluate - /// to a different value. That is, the abstract interpreter should treat these IExpr's - /// as unknown values. They are used when there is no other IExpr corresponding to the - /// expression to be modeled. - /// - public interface IUnknown : IExpr {} - - /// - /// An abstract class that provides an interface for expression visitors. - /// - [ContractClass(typeof(ExprVisitorContracts))] - public abstract class ExprVisitor - { - public abstract object Default(IExpr/*!*/ expr); - - public virtual object VisitVariable(IVariable/*!*/ var){ -Contract.Requires(var != null); - return Default(var); - } - - public virtual object VisitFunApp(IFunApp/*!*/ funapp){ -Contract.Requires(funapp != null); - return Default(funapp); - } - - public virtual object VisitFunction(IFunction/*!*/ fun){ -Contract.Requires(fun != null); - return Default(fun); - } - } - [ContractClassFor(typeof(ExprVisitor))] - public abstract class ExprVisitorContracts:ExprVisitor{ - public override object Default(IExpr expr) -{ - Contract.Requires(expr != null); throw new NotImplementedException(); -}} - - /// - /// A utility class for dealing with expressions. - /// - public sealed class ExprUtil - { - /// - /// Yield an expression that is 'inexpr' with 'var' replaced by 'subst'. - /// - /// The expression to substitute. - /// The variable to substitute for. - /// The expression to substitute into. - public static IExpr/*!*/ Substitute(IExpr/*!*/ subst, IVariable/*!*/ var, IExpr/*!*/ inexpr){ -Contract.Requires(inexpr != null); -Contract.Requires(var != null); -Contract.Requires(subst != null); -Contract.Ensures(Contract.Result() != null); - IExpr result = null; - - if (inexpr is IVariable) - { - result = inexpr.Equals(var) ? subst : inexpr; - } - else if (inexpr is IFunApp) - { - IFunApp/*!*/ funapp = (IFunApp/*!*/)cce.NonNull(inexpr); - IList newargs = null; - - var x = new System.Collections.Generic.List(); - foreach (IExpr arg in funapp.Arguments){ - x.Add(Substitute(subst,var, arg)); - } - newargs = new ArrayList(x); - //newargs = new ArrayList{ IExpr/*!*/ arg in funapp.Arguments; Substitute(subst, var, arg) }; - result = funapp.CloneWithArguments(newargs); - } - else if (inexpr is IFunction) - { - IFunction/*!*/ fun = (IFunction/*!*/)cce.NonNull(inexpr); - - if (fun.Param.Equals(var)) - result = fun; - else - result = fun.CloneWithBody(Substitute(subst, var, fun.Body)); - } - else if (inexpr is IUnknown) - { - result = inexpr; - } - else - { - {Contract.Assert(false);throw new cce.UnreachableException();} - } - - return result; - } - - - // - // Poor man's pattern matching. - // - // The methods below implement pattern matching for AI expressions. - // - // Example Usage: - // Match(e, Prop.Imp, - // (Matcher)delegate (IExpr e) { return Match(e, Prop.And, out x, out y); } - // out z) - // which sees if 'e' matches Prop.Imp(Prop.And(x,y),z) binding x,y,z to the subtrees. - // - public delegate bool Matcher(IExpr/*!*/ expr); - - private static IFunApp/*?*/ MatchFunctionSymbol(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f){ -Contract.Requires(f != null); -Contract.Requires(expr != null); - IFunApp app = expr as IFunApp; - if (app != null) - { - if (app.FunctionSymbol.Equals(f)) - return app; - else - return null; - } - else - return null; - } - - public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, params Matcher[]/*!*/ subs){ -Contract.Requires(subs != null); -Contract.Requires(f != null); -Contract.Requires(expr != null); - IFunApp app = MatchFunctionSymbol(expr,f); - if (app != null) - { - int i = 0; // Note ***0*** - foreach(Matcher/*!*/ s in subs){ -Contract.Assert(s != null); - if (!s(cce.NonNull((IExpr)app.Arguments[i]))) { return false; } - i++; - } - return true; - } - else { return false; } - } - - // Unary Binding - public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, out IExpr arg0, params Matcher[]/*!*/ subs){ -Contract.Requires(subs != null); -Contract.Requires(f != null); -Contract.Requires(expr != null); - arg0 = null; - - IFunApp app = MatchFunctionSymbol(expr,f); - if (app != null) - { - arg0 = (IExpr/*!*/)cce.NonNull(app.Arguments[0]); - - int i = 1; // Note ***1*** - foreach(Matcher/*!*/ s in subs){ -Contract.Assert(s != null); - if (!s(cce.NonNull((IExpr/*!*/)app.Arguments[i]))) { return false; } - i++; - } - return true; - } - else { return false; } - } - - // Binary Binding - public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, Matcher/*!*/ sub0, out IExpr arg1, params Matcher[]/*!*/ subs){ -Contract.Requires(subs != null); -Contract.Requires(sub0 != null); -Contract.Requires(f != null); -Contract.Requires(expr != null); - arg1 = null; - - IFunApp app = MatchFunctionSymbol(expr,f); - if (app != null) - { - if (!sub0(cce.NonNull((IExpr/*!*/)app.Arguments[0]))) { return false; } - - arg1 = (IExpr/*!*/)cce.NonNull(app.Arguments[1]); - - int i = 2; // Note ***2*** - foreach(Matcher/*!*/ s in subs){ -Contract.Assert(s != null); - if (!s(cce.NonNull((IExpr)app.Arguments[i]))) { return false; } - i++; - } - return true; - } - else { return false; } - } - - public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, out IExpr arg0, out IExpr arg1, params Matcher[]/*!*/ subs){ -Contract.Requires(subs != null); -Contract.Requires(f != null); -Contract.Requires(expr != null); - arg0 = null; - arg1 = null; - - IFunApp app = MatchFunctionSymbol(expr,f); - if (app != null) - { - arg0 = (IExpr/*!*/)cce.NonNull(app.Arguments[0]); - arg1 = (IExpr/*!*/)cce.NonNull(app.Arguments[1]); - - int i = 2; // Note ***2*** - foreach(Matcher/*!*/ s in subs){ -Contract.Assert(s != null); - if (!s(cce.NonNull((IExpr/*!*/)app.Arguments[i]))) { return false; } - i++; - } - return true; - } - else { return false; } - } - - // Ternary Binding - public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, out IExpr arg0, out IExpr arg1, out IExpr arg2, params Matcher[]/*!*/ subs){ -Contract.Requires(subs != null); -Contract.Requires(f != null); -Contract.Requires(expr != null); - arg0 = null; - arg1 = null; - arg2 = null; - - IFunApp app = MatchFunctionSymbol(expr,f); - if (app != null) - { - arg0 = (IExpr/*!*/)cce.NonNull(app.Arguments[0]); - arg1 = (IExpr/*!*/)cce.NonNull(app.Arguments[1]); - arg2 = (IExpr/*!*/)cce.NonNull(app.Arguments[2]); - - int i = 3; // Note ***3*** - foreach(Matcher/*!*/ s in subs){ -Contract.Assert(s != null); - if (!s(cce.NonNull((IExpr/*!*/)app.Arguments[i]))) { return false; } - i++; - } - return true; - } - else { return false; } - } - - /// - /// Not intended to be instantiated. - /// - private ExprUtil() { } - } - - //------------------------------ Symbols -------------------------------- - - /// - /// An interface for function symbols. Constants are represented by - /// 0-ary function symbols. - /// - /// This interface should be implemented by abstract domains, but client - /// expressions need keep track of function symbols. - /// - [ContractClass(typeof(IFunctionSymbolContracts))] - public interface IFunctionSymbol - { - AIType/*!*/ AIType { [Rep][ResultNotNewlyAllocated] - get; } - } - [ContractClassFor(typeof(IFunctionSymbol))] - public abstract class IFunctionSymbolContracts:IFunctionSymbol{ - #region IFunctionSymbol Members - - AIType IFunctionSymbol.AIType { - get { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - - #endregion - } - - /// - /// The type of the arguments to ExprUtil.Match, a poor man's pattern - /// matching. - /// - public interface IMatchable - { - } - - //-------------------------------- Types -------------------------------- - - /// - /// Types. - /// - public interface AIType - { - } - - /// - /// Function type constructor. - /// - public sealed class FunctionType : AIType - { - /*[Own]*/ private readonly IList/**//*!*/ argTypes; - /*[Own]*/ private readonly AIType/*!*/ retType; - [ContractInvariantMethod] -void ObjectInvariant() -{ - Contract.Invariant(argTypes != null); - Contract.Invariant(retType != null); -} - - - public FunctionType(params AIType[]/*!*/ types){ -Contract.Requires(types != null); - Contract.Requires(types.Length >= 2); - AIType type = types[types.Length-1]; - Contract.Assume(type != null); - this.retType = type; - ArrayList argTypes = new ArrayList(); - for (int i = 0; i < types.Length-1; i++) - { - type = types[i]; - Contract.Assume(type != null); - argTypes.Add(types); - } - this.argTypes = ArrayList.ReadOnly(argTypes); - } - - public IList/**//*!*/ Arguments - { - [Pure][Rep] - get - { - Contract.Ensures(Contract.Result() != null); - Contract.Ensures(Contract.Result().IsReadOnly); - return argTypes; - } - } - - public int Arity - { - get { return argTypes.Count; } - } - - public AIType/*!*/ ReturnType - { - get {Contract.Ensures(Contract.Result() != null); return retType; } - } - - /* TODO Do we have the invariant that two functions are equal iff they're the same object. - public override bool Equals(object o) - { - if (o != null && o is FunctionType) - { - FunctionType other = (FunctionType) o; - - if (Arity == other.Arity - && ReturnType.Equals(other.ReturnType)) - { - for (int i = 0; i < Arity; i++) - { - if (!argTypes[i].Equals(other.argTypes[i])) - return false; - } - return true; - } - else - return false; - } - else - return false; - } - */ - } - - //------------------------------ Queries ------------------------------- - - public enum Answer { Yes, No, Maybe }; - - /// - /// An interface that specifies a queryable object that can answer - /// whether a predicate holds. - /// - /// - [ContractClass(typeof(IQueryableContracts))] - public interface IQueryable - { - /// - /// Answers the query whether the given predicate holds. - /// - /// The given predicate. - /// Yes, No, or Maybe. - Answer CheckPredicate(IExpr/*!*/ pred); - - /// - /// A simplified interface for disequalities. One can always - /// implement this by calling CheckPredicate, but it may be - /// more efficient with this method. - /// - Answer CheckVariableDisequality(IVariable/*!*/ var1, IVariable/*!*/ var2); - } - [ContractClassFor(typeof(IQueryable))] - public abstract class IQueryableContracts : IQueryable { - #region IQueryable Members - - public Answer CheckPredicate(IExpr pred) { - Contract.Requires(pred != null); - throw new NotImplementedException(); - } - - public Answer CheckVariableDisequality(IVariable var1, IVariable var2) { - Contract.Requires(var1 != null); - Contract.Requires(var2 != null); - throw new NotImplementedException(); - } - - #endregion - } - - public static class QueryUtil - { - public static Answer Negate(Answer ans) - { - switch (ans) - { - case Answer.Yes: - return Answer.No; - case Answer.No: - return Answer.Yes; - default: - return Answer.Maybe; - } - } - } - - //----------------------------- Exceptions ----------------------------- - - public class CheckedException : System.Exception { - } - public class TypeError : CheckedException - { - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +// This file specifies the expression language used by the Abstract +// Interpretation Framework. +// +// expressions e ::= x variables +// | f(e1,...,en) uninterpreted functions +// | \x:t.e lambda expressions +// +// types t ::= b user-defined/built-in base types +// | t1 * ... * tn -> t' function type + +namespace Microsoft.AbstractInterpretationFramework +{ + using System.Collections; + using System; + using System.Diagnostics.Contracts; + + //----------------------------- Expressions ----------------------------- + + /// + /// An interface for expressions. This expression language is specified + /// by interfaces to allow the client to be able to use their existing + /// AST nodes as AIF expressions. + /// + /// This only serves as a place for operations on expressions. Clients + /// should implement directly IVariable, IFunApp, ... + /// + [ContractClass(typeof(IExprContracts))] + public interface IExpr + { + /// + /// Execute a visit over the expression. + /// + /// The expression visitor. + /// The result of the visit. + [Pure] object DoVisit(ExprVisitor/*!*/ visitor); + + // TODO: Type checking of the expressions. + } + [ContractClassFor(typeof(IExpr))] + public abstract class IExprContracts:IExpr{ + #region IExpr Members + +public object DoVisit(ExprVisitor visitor) +{ + Contract.Requires(visitor != null); + throw new System.NotImplementedException(); +} + +#endregion +} + + /// + /// An interface for variables. + /// + /// This interface should be implemented by the client. + /// + [ContractClass(typeof(IVariableContracts))] + public interface IVariable : IExpr + { + string/*!*/ Name { get; } // Each client must define the name for variables + } + [ContractClassFor(typeof(IVariable))] + public abstract class IVariableContracts:IVariable{ + string IVariable.Name{get{Contract.Ensures(Contract.Result() != null);throw new NotImplementedException();} + + } + + #region IExpr Members + + object IExpr.DoVisit(ExprVisitor visitor) { + throw new NotImplementedException(); + } + + #endregion + } + + /// + /// An interface for function applications. + /// + /// This interface should be implemented by the client. + /// + /// + [ContractClass(typeof(IFunAppContracts))] + public interface IFunApp : IExpr + { + IFunctionSymbol/*!*/ FunctionSymbol { get; } + IList/**//*!*/ Arguments + { + [Pure][Rep] get; + + } + + /// + /// Provides a method to create a new uninterpreted function + /// with the same function symbol but with the arguments with + /// args. + /// + /// The new arguments. + /// A copy of the function with the new arguments. + IFunApp/*!*/ CloneWithArguments(IList/**//*!*/ args) + //TODO Contract.Requires(this.Arguments.Count == args.Count); + ; + } + [ContractClassFor(typeof(IFunApp))] +public abstract class IFunAppContracts:IFunApp{ + +#region IFunApp Members + +public IFunctionSymbol FunctionSymbol +{ + get {Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); } +} + +public IList Arguments +{ + get {Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.Result().IsReadOnly); + throw new System.NotImplementedException(); } +} + +public IFunApp CloneWithArguments(IList args) +{ + Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + + + throw new System.NotImplementedException(); +} + +#endregion + +#region IExpr Members + +object IExpr.DoVisit(ExprVisitor visitor) { + throw new NotImplementedException(); +} + +#endregion +} + + /// + /// An interface for anonymous functions (i.e., lambda expressions) + /// + [ContractClass(typeof(IFunctionContracts))] + public interface IFunction : IExpr + { + IVariable/*!*/ Param { get; } + AIType/*!*/ ParamType { get; } + IExpr/*!*/ Body { get; } + + IFunction/*!*/ CloneWithBody(IExpr/*!*/ body); + } + [ContractClassFor(typeof(IFunction))] + public abstract class IFunctionContracts:IFunction{ + + #region IFunction Members + + IVariable IFunction.Param { + get { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + + AIType IFunction.ParamType { + get { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + + IExpr IFunction.Body { + get { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + + IFunction IFunction.CloneWithBody(IExpr body) { + Contract.Requires(body != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + + #endregion + + #region IExpr Members + + object IExpr.DoVisit(ExprVisitor visitor) { + throw new NotImplementedException(); + } + + #endregion + } + + /// + /// An interface representing an expression that at any moment could, in principle, evaluate + /// to a different value. That is, the abstract interpreter should treat these IExpr's + /// as unknown values. They are used when there is no other IExpr corresponding to the + /// expression to be modeled. + /// + public interface IUnknown : IExpr {} + + /// + /// An abstract class that provides an interface for expression visitors. + /// + [ContractClass(typeof(ExprVisitorContracts))] + public abstract class ExprVisitor + { + public abstract object Default(IExpr/*!*/ expr); + + public virtual object VisitVariable(IVariable/*!*/ var){ +Contract.Requires(var != null); + return Default(var); + } + + public virtual object VisitFunApp(IFunApp/*!*/ funapp){ +Contract.Requires(funapp != null); + return Default(funapp); + } + + public virtual object VisitFunction(IFunction/*!*/ fun){ +Contract.Requires(fun != null); + return Default(fun); + } + } + [ContractClassFor(typeof(ExprVisitor))] + public abstract class ExprVisitorContracts:ExprVisitor{ + public override object Default(IExpr expr) +{ + Contract.Requires(expr != null); throw new NotImplementedException(); +}} + + /// + /// A utility class for dealing with expressions. + /// + public sealed class ExprUtil + { + /// + /// Yield an expression that is 'inexpr' with 'var' replaced by 'subst'. + /// + /// The expression to substitute. + /// The variable to substitute for. + /// The expression to substitute into. + public static IExpr/*!*/ Substitute(IExpr/*!*/ subst, IVariable/*!*/ var, IExpr/*!*/ inexpr){ +Contract.Requires(inexpr != null); +Contract.Requires(var != null); +Contract.Requires(subst != null); +Contract.Ensures(Contract.Result() != null); + IExpr result = null; + + if (inexpr is IVariable) + { + result = inexpr.Equals(var) ? subst : inexpr; + } + else if (inexpr is IFunApp) + { + IFunApp/*!*/ funapp = (IFunApp/*!*/)cce.NonNull(inexpr); + IList newargs = null; + + var x = new System.Collections.Generic.List(); + foreach (IExpr arg in funapp.Arguments){ + x.Add(Substitute(subst,var, arg)); + } + newargs = new ArrayList(x); + //newargs = new ArrayList{ IExpr/*!*/ arg in funapp.Arguments; Substitute(subst, var, arg) }; + result = funapp.CloneWithArguments(newargs); + } + else if (inexpr is IFunction) + { + IFunction/*!*/ fun = (IFunction/*!*/)cce.NonNull(inexpr); + + if (fun.Param.Equals(var)) + result = fun; + else + result = fun.CloneWithBody(Substitute(subst, var, fun.Body)); + } + else if (inexpr is IUnknown) + { + result = inexpr; + } + else + { + {Contract.Assert(false);throw new cce.UnreachableException();} + } + + return result; + } + + + // + // Poor man's pattern matching. + // + // The methods below implement pattern matching for AI expressions. + // + // Example Usage: + // Match(e, Prop.Imp, + // (Matcher)delegate (IExpr e) { return Match(e, Prop.And, out x, out y); } + // out z) + // which sees if 'e' matches Prop.Imp(Prop.And(x,y),z) binding x,y,z to the subtrees. + // + public delegate bool Matcher(IExpr/*!*/ expr); + + private static IFunApp/*?*/ MatchFunctionSymbol(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f){ +Contract.Requires(f != null); +Contract.Requires(expr != null); + IFunApp app = expr as IFunApp; + if (app != null) + { + if (app.FunctionSymbol.Equals(f)) + return app; + else + return null; + } + else + return null; + } + + public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, params Matcher[]/*!*/ subs){ +Contract.Requires(subs != null); +Contract.Requires(f != null); +Contract.Requires(expr != null); + IFunApp app = MatchFunctionSymbol(expr,f); + if (app != null) + { + int i = 0; // Note ***0*** + foreach(Matcher/*!*/ s in subs){ +Contract.Assert(s != null); + if (!s(cce.NonNull((IExpr)app.Arguments[i]))) { return false; } + i++; + } + return true; + } + else { return false; } + } + + // Unary Binding + public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, out IExpr arg0, params Matcher[]/*!*/ subs){ +Contract.Requires(subs != null); +Contract.Requires(f != null); +Contract.Requires(expr != null); + arg0 = null; + + IFunApp app = MatchFunctionSymbol(expr,f); + if (app != null) + { + arg0 = (IExpr/*!*/)cce.NonNull(app.Arguments[0]); + + int i = 1; // Note ***1*** + foreach(Matcher/*!*/ s in subs){ +Contract.Assert(s != null); + if (!s(cce.NonNull((IExpr/*!*/)app.Arguments[i]))) { return false; } + i++; + } + return true; + } + else { return false; } + } + + // Binary Binding + public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, Matcher/*!*/ sub0, out IExpr arg1, params Matcher[]/*!*/ subs){ +Contract.Requires(subs != null); +Contract.Requires(sub0 != null); +Contract.Requires(f != null); +Contract.Requires(expr != null); + arg1 = null; + + IFunApp app = MatchFunctionSymbol(expr,f); + if (app != null) + { + if (!sub0(cce.NonNull((IExpr/*!*/)app.Arguments[0]))) { return false; } + + arg1 = (IExpr/*!*/)cce.NonNull(app.Arguments[1]); + + int i = 2; // Note ***2*** + foreach(Matcher/*!*/ s in subs){ +Contract.Assert(s != null); + if (!s(cce.NonNull((IExpr)app.Arguments[i]))) { return false; } + i++; + } + return true; + } + else { return false; } + } + + public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, out IExpr arg0, out IExpr arg1, params Matcher[]/*!*/ subs){ +Contract.Requires(subs != null); +Contract.Requires(f != null); +Contract.Requires(expr != null); + arg0 = null; + arg1 = null; + + IFunApp app = MatchFunctionSymbol(expr,f); + if (app != null) + { + arg0 = (IExpr/*!*/)cce.NonNull(app.Arguments[0]); + arg1 = (IExpr/*!*/)cce.NonNull(app.Arguments[1]); + + int i = 2; // Note ***2*** + foreach(Matcher/*!*/ s in subs){ +Contract.Assert(s != null); + if (!s(cce.NonNull((IExpr/*!*/)app.Arguments[i]))) { return false; } + i++; + } + return true; + } + else { return false; } + } + + // Ternary Binding + public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, out IExpr arg0, out IExpr arg1, out IExpr arg2, params Matcher[]/*!*/ subs){ +Contract.Requires(subs != null); +Contract.Requires(f != null); +Contract.Requires(expr != null); + arg0 = null; + arg1 = null; + arg2 = null; + + IFunApp app = MatchFunctionSymbol(expr,f); + if (app != null) + { + arg0 = (IExpr/*!*/)cce.NonNull(app.Arguments[0]); + arg1 = (IExpr/*!*/)cce.NonNull(app.Arguments[1]); + arg2 = (IExpr/*!*/)cce.NonNull(app.Arguments[2]); + + int i = 3; // Note ***3*** + foreach(Matcher/*!*/ s in subs){ +Contract.Assert(s != null); + if (!s(cce.NonNull((IExpr/*!*/)app.Arguments[i]))) { return false; } + i++; + } + return true; + } + else { return false; } + } + + /// + /// Not intended to be instantiated. + /// + private ExprUtil() { } + } + + //------------------------------ Symbols -------------------------------- + + /// + /// An interface for function symbols. Constants are represented by + /// 0-ary function symbols. + /// + /// This interface should be implemented by abstract domains, but client + /// expressions need keep track of function symbols. + /// + [ContractClass(typeof(IFunctionSymbolContracts))] + public interface IFunctionSymbol + { + AIType/*!*/ AIType { [Rep][ResultNotNewlyAllocated] + get; } + } + [ContractClassFor(typeof(IFunctionSymbol))] + public abstract class IFunctionSymbolContracts:IFunctionSymbol{ + #region IFunctionSymbol Members + + AIType IFunctionSymbol.AIType { + get { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + + #endregion + } + + /// + /// The type of the arguments to ExprUtil.Match, a poor man's pattern + /// matching. + /// + public interface IMatchable + { + } + + //-------------------------------- Types -------------------------------- + + /// + /// Types. + /// + public interface AIType + { + } + + /// + /// Function type constructor. + /// + public sealed class FunctionType : AIType + { + /*[Own]*/ private readonly IList/**//*!*/ argTypes; + /*[Own]*/ private readonly AIType/*!*/ retType; + [ContractInvariantMethod] +void ObjectInvariant() +{ + Contract.Invariant(argTypes != null); + Contract.Invariant(retType != null); +} + + + public FunctionType(params AIType[]/*!*/ types){ +Contract.Requires(types != null); + Contract.Requires(types.Length >= 2); + AIType type = types[types.Length-1]; + Contract.Assume(type != null); + this.retType = type; + ArrayList argTypes = new ArrayList(); + for (int i = 0; i < types.Length-1; i++) + { + type = types[i]; + Contract.Assume(type != null); + argTypes.Add(types); + } + this.argTypes = ArrayList.ReadOnly(argTypes); + } + + public IList/**//*!*/ Arguments + { + [Pure][Rep] + get + { + Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.Result().IsReadOnly); + return argTypes; + } + } + + public int Arity + { + get { return argTypes.Count; } + } + + public AIType/*!*/ ReturnType + { + get {Contract.Ensures(Contract.Result() != null); return retType; } + } + + /* TODO Do we have the invariant that two functions are equal iff they're the same object. + public override bool Equals(object o) + { + if (o != null && o is FunctionType) + { + FunctionType other = (FunctionType) o; + + if (Arity == other.Arity + && ReturnType.Equals(other.ReturnType)) + { + for (int i = 0; i < Arity; i++) + { + if (!argTypes[i].Equals(other.argTypes[i])) + return false; + } + return true; + } + else + return false; + } + else + return false; + } + */ + } + + //------------------------------ Queries ------------------------------- + + public enum Answer { Yes, No, Maybe }; + + /// + /// An interface that specifies a queryable object that can answer + /// whether a predicate holds. + /// + /// + [ContractClass(typeof(IQueryableContracts))] + public interface IQueryable + { + /// + /// Answers the query whether the given predicate holds. + /// + /// The given predicate. + /// Yes, No, or Maybe. + Answer CheckPredicate(IExpr/*!*/ pred); + + /// + /// A simplified interface for disequalities. One can always + /// implement this by calling CheckPredicate, but it may be + /// more efficient with this method. + /// + Answer CheckVariableDisequality(IVariable/*!*/ var1, IVariable/*!*/ var2); + } + [ContractClassFor(typeof(IQueryable))] + public abstract class IQueryableContracts : IQueryable { + #region IQueryable Members + + public Answer CheckPredicate(IExpr pred) { + Contract.Requires(pred != null); + throw new NotImplementedException(); + } + + public Answer CheckVariableDisequality(IVariable var1, IVariable var2) { + Contract.Requires(var1 != null); + Contract.Requires(var2 != null); + throw new NotImplementedException(); + } + + #endregion + } + + public static class QueryUtil + { + public static Answer Negate(Answer ans) + { + switch (ans) + { + case Answer.Yes: + return Answer.No; + case Answer.No: + return Answer.Yes; + default: + return Answer.Maybe; + } + } + } + + //----------------------------- Exceptions ----------------------------- + + public class CheckedException : System.Exception { + } + public class TypeError : CheckedException + { + } +} diff --git a/Source/AIFramework/Functional.cs b/Source/AIFramework/Functional.cs index 3b8237bf..51d8562a 100644 --- a/Source/AIFramework/Functional.cs +++ b/Source/AIFramework/Functional.cs @@ -1,430 +1,430 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System.Diagnostics.Contracts; - -namespace Microsoft.AbstractInterpretationFramework.Collections { - using System.Collections; - - /// Represents a functional collection of key/value pairs. - /// 2 - [ContractClass(typeof(IFunctionalMapContracts))] - public interface IFunctionalMap : System.Collections.ICollection, System.Collections.IEnumerable { - /// Adds an element with the provided key and value to the . - /// The to use as the value of the element to add. - /// The to use as the key of the element to add. - /// 2 - IFunctionalMap/*!*/ Add(object/*!*/ key, object value); - - /// - /// Set the value of the key (that is already in the map) - /// - IFunctionalMap/*!*/ Set(object/*!*/ key, object value); - - /// Determines whether the contains an element with the specified key. - /// true if the contains an element with the key; otherwise, false. - /// The key to locate in the . - /// 2 - [Pure] - bool Contains(object/*!*/ key); - - /// Returns an for the . - /// An for the . - /// 2 - [Pure] - [GlobalAccess(false)] - [Escapes(true, false)] - new System.Collections.IDictionaryEnumerator GetEnumerator(); - - /// Gets an containing the keys of the . - /// An containing the keys of the . - /// 2 - System.Collections.ICollection Keys { - get; - } - - /// Removes the element with the specified key from the . - /// The key of the element to remove. - /// 2 - IFunctionalMap/*!*/ Remove(object/*!*/ key); - - /// Gets an containing the values in the . - /// An containing the values in the . - /// 2 - System.Collections.ICollection Values { - get; - } - - object this[object/*!*/ key] { - get; /*set;*/ - } - } - [ContractClassFor(typeof(IFunctionalMap))] - public abstract class IFunctionalMapContracts : IFunctionalMap { - - #region IFunctionalMap Members - - IFunctionalMap IFunctionalMap.Add(object key, object value) { - Contract.Requires(key != null); - Contract.Ensures(Contract.Result() != null); - - throw new System.NotImplementedException(); - } - - IFunctionalMap IFunctionalMap.Set(object key, object value) { - Contract.Requires(key != null); - Contract.Ensures(Contract.Result() != null); - - throw new System.NotImplementedException(); - } - - bool IFunctionalMap.Contains(object key) { - Contract.Requires(key != null); - - throw new System.NotImplementedException(); - } - - IDictionaryEnumerator IFunctionalMap.GetEnumerator() { - throw new System.NotImplementedException(); - } - - ICollection IFunctionalMap.Keys { - get { - throw new System.NotImplementedException(); - } - } - - IFunctionalMap IFunctionalMap.Remove(object key) { - Contract.Requires(key != null); - Contract.Ensures(Contract.Result() != null); - - throw new System.NotImplementedException(); - } - - ICollection IFunctionalMap.Values { - get { - throw new System.NotImplementedException(); - } - } - - object IFunctionalMap.this[object key] { - get { - Contract.Requires(key != null); - throw new System.NotImplementedException(); - } - } - - #endregion - - #region ICollection Members - - void ICollection.CopyTo(System.Array array, int index) { - throw new System.NotImplementedException(); - } - - int ICollection.Count { - get { - throw new System.NotImplementedException(); - } - } - - bool ICollection.IsSynchronized { - get { - throw new System.NotImplementedException(); - } - } - - object ICollection.SyncRoot { - get { - throw new System.NotImplementedException(); - } - } - - #endregion - - #region IEnumerable Members - - IEnumerator IEnumerable.GetEnumerator() { - throw new System.NotImplementedException(); - } - - #endregion - } - - - - /// - /// An implementation of the - /// - /// interface with a as the backing store. - /// - class FunctionalHashtable : IFunctionalMap { - private readonly Hashtable/*!*/ h; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(h != null); - } - - - /// - /// Cannot directly construct an instance of a FunctionalHashtbl. - /// - private FunctionalHashtable() { - this.h = new Hashtable(); - // base(); - } - - /// - /// Cannot directly construct an instance of a FunctionalHashtbl. - /// - private FunctionalHashtable(Hashtable/*!*/ h) { - Contract.Requires(h != null); - this.h = h; - // base(); - } - - private static readonly IFunctionalMap/*!*/ empty = new FunctionalHashtable(); - public static IFunctionalMap/*!*/ Empty { - get { - Contract.Ensures(Contract.Result() != null); - return empty; - } - } - - public IFunctionalMap/*!*/ Add(object/*!*/ key, object value) { - //Contract.Requires(key != null); - Contract.Ensures(Contract.Result() != null); - Hashtable r = h.Clone() as Hashtable; - Contract.Assume(r != null); - r.Add(key, value); - return new FunctionalHashtable(r); - } - - public IFunctionalMap/*!*/ Set(object/*!*/ key, object value) { - //Contract.Requires(key != null); - Contract.Ensures(Contract.Result() != null); - Hashtable r = h.Clone() as Hashtable; - - Contract.Assume(r != null); - Contract.Assert(this.Contains(key)); // The entry must be defined - - r[key] = value; - return new FunctionalHashtable(r); - } - - [Pure] - public bool Contains(object/*!*/ key) { - //Contract.Requires(key != null); - return h.Contains(key); - } - - [Pure] - [GlobalAccess(false)] - [Escapes(true, false)] - IEnumerator/*!*/ IEnumerable.GetEnumerator() { - Contract.Ensures(Contract.Result() != null); - - return h.GetEnumerator(); - } - - [Pure] - [GlobalAccess(false)] - [Escapes(true, false)] - IDictionaryEnumerator IFunctionalMap.GetEnumerator() { - return h.GetEnumerator(); - } - - public ICollection Keys { - get { - return h.Keys; - } - } - - public IFunctionalMap/*!*/ Remove(object/*!*/ key) { - //Contract.Requires(key != null); - Contract.Ensures(Contract.Result() != null); - Hashtable r = h.Clone() as Hashtable; - Contract.Assume(r != null); - r.Remove(key); - return new FunctionalHashtable(r); - } - - public ICollection Values { - get { - return h.Values; - } - } - - - public object this[object/*!*/ key] { - get { - //Contract.Requires(key != null); - return h[key]; - } - } - - public int Count { - [Pure] - get { - return h.Count; - } - } - - public bool IsSynchronized { - [Pure] - get { - return h.IsSynchronized; - } - } - - public object/*!*/ SyncRoot { - [Pure] - get { - Contract.Ensures(Contract.Result() != null); - return h.SyncRoot; - } - } - - public void CopyTo(System.Array/*!*/ a, int index) { - //Contract.Requires(a != null); - h.CopyTo(a, index); - } - } - - public struct Pair/**/ - { - private object first; - private object second; - - public object First { - get { - return first; - } - } - public object Second { - get { - return second; - } - } - - public Pair(object first, object second) { - this.first = first; - this.second = second; - } - - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is Pair)) - return false; - - Pair other = (Pair)obj; - return object.Equals(this.first, other.first) && object.Equals(this.second, other.second); - } - - public override int GetHashCode() { - int h = this.first == null ? 0 : this.first.GetHashCode(); - h ^= this.second == null ? 0 : this.second.GetHashCode(); - return h; - } - } -} - - -namespace Microsoft.AbstractInterpretationFramework.Collections.Generic { - using System.Collections.Generic; - - public struct Pair { - private T1 first; - private T2 second; - - public T1 First { - get { - return first; - } - } - public T2 Second { - get { - return second; - } - } - - public Pair(T1 first, T2 second) { - this.first = first; - this.second = second; - } - - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is Pair)) - return false; - - Pair other = (Pair)obj; - return object.Equals(this.first, other.first) && object.Equals(this.second, other.second); - } - - public override int GetHashCode() { - int h = this.first == null ? 0 : this.first.GetHashCode(); - h ^= this.second == null ? 0 : this.second.GetHashCode(); - return h; - } - - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return string.Format("({0},{1})", first, second); - } - } - - public struct Triple { - private T1 first; - private T2 second; - private T3 third; - - public T1 First { - get { - return first; - } - } - public T2 Second { - get { - return second; - } - } - public T3 Third { - get { - return third; - } - } - - public Triple(T1 first, T2 second, T3 third) { - this.first = first; - this.second = second; - this.third = third; - } - - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is Triple)) - return false; - - Triple other = (Triple)obj; - return object.Equals(this.first, other.first) && object.Equals(this.second, other.second) && object.Equals(this.third, other.third); - } - - public override int GetHashCode() { - int h = this.first == null ? 0 : this.first.GetHashCode(); - h ^= this.second == null ? 0 : this.second.GetHashCode(); - h ^= this.third == null ? 0 : this.third.GetHashCode(); - return h; - } - - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return string.Format("({0},{1},{2})", first, second, third); - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System.Diagnostics.Contracts; + +namespace Microsoft.AbstractInterpretationFramework.Collections { + using System.Collections; + + /// Represents a functional collection of key/value pairs. + /// 2 + [ContractClass(typeof(IFunctionalMapContracts))] + public interface IFunctionalMap : System.Collections.ICollection, System.Collections.IEnumerable { + /// Adds an element with the provided key and value to the . + /// The to use as the value of the element to add. + /// The to use as the key of the element to add. + /// 2 + IFunctionalMap/*!*/ Add(object/*!*/ key, object value); + + /// + /// Set the value of the key (that is already in the map) + /// + IFunctionalMap/*!*/ Set(object/*!*/ key, object value); + + /// Determines whether the contains an element with the specified key. + /// true if the contains an element with the key; otherwise, false. + /// The key to locate in the . + /// 2 + [Pure] + bool Contains(object/*!*/ key); + + /// Returns an for the . + /// An for the . + /// 2 + [Pure] + [GlobalAccess(false)] + [Escapes(true, false)] + new System.Collections.IDictionaryEnumerator GetEnumerator(); + + /// Gets an containing the keys of the . + /// An containing the keys of the . + /// 2 + System.Collections.ICollection Keys { + get; + } + + /// Removes the element with the specified key from the . + /// The key of the element to remove. + /// 2 + IFunctionalMap/*!*/ Remove(object/*!*/ key); + + /// Gets an containing the values in the . + /// An containing the values in the . + /// 2 + System.Collections.ICollection Values { + get; + } + + object this[object/*!*/ key] { + get; /*set;*/ + } + } + [ContractClassFor(typeof(IFunctionalMap))] + public abstract class IFunctionalMapContracts : IFunctionalMap { + + #region IFunctionalMap Members + + IFunctionalMap IFunctionalMap.Add(object key, object value) { + Contract.Requires(key != null); + Contract.Ensures(Contract.Result() != null); + + throw new System.NotImplementedException(); + } + + IFunctionalMap IFunctionalMap.Set(object key, object value) { + Contract.Requires(key != null); + Contract.Ensures(Contract.Result() != null); + + throw new System.NotImplementedException(); + } + + bool IFunctionalMap.Contains(object key) { + Contract.Requires(key != null); + + throw new System.NotImplementedException(); + } + + IDictionaryEnumerator IFunctionalMap.GetEnumerator() { + throw new System.NotImplementedException(); + } + + ICollection IFunctionalMap.Keys { + get { + throw new System.NotImplementedException(); + } + } + + IFunctionalMap IFunctionalMap.Remove(object key) { + Contract.Requires(key != null); + Contract.Ensures(Contract.Result() != null); + + throw new System.NotImplementedException(); + } + + ICollection IFunctionalMap.Values { + get { + throw new System.NotImplementedException(); + } + } + + object IFunctionalMap.this[object key] { + get { + Contract.Requires(key != null); + throw new System.NotImplementedException(); + } + } + + #endregion + + #region ICollection Members + + void ICollection.CopyTo(System.Array array, int index) { + throw new System.NotImplementedException(); + } + + int ICollection.Count { + get { + throw new System.NotImplementedException(); + } + } + + bool ICollection.IsSynchronized { + get { + throw new System.NotImplementedException(); + } + } + + object ICollection.SyncRoot { + get { + throw new System.NotImplementedException(); + } + } + + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() { + throw new System.NotImplementedException(); + } + + #endregion + } + + + + /// + /// An implementation of the + /// + /// interface with a as the backing store. + /// + class FunctionalHashtable : IFunctionalMap { + private readonly Hashtable/*!*/ h; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(h != null); + } + + + /// + /// Cannot directly construct an instance of a FunctionalHashtbl. + /// + private FunctionalHashtable() { + this.h = new Hashtable(); + // base(); + } + + /// + /// Cannot directly construct an instance of a FunctionalHashtbl. + /// + private FunctionalHashtable(Hashtable/*!*/ h) { + Contract.Requires(h != null); + this.h = h; + // base(); + } + + private static readonly IFunctionalMap/*!*/ empty = new FunctionalHashtable(); + public static IFunctionalMap/*!*/ Empty { + get { + Contract.Ensures(Contract.Result() != null); + return empty; + } + } + + public IFunctionalMap/*!*/ Add(object/*!*/ key, object value) { + //Contract.Requires(key != null); + Contract.Ensures(Contract.Result() != null); + Hashtable r = h.Clone() as Hashtable; + Contract.Assume(r != null); + r.Add(key, value); + return new FunctionalHashtable(r); + } + + public IFunctionalMap/*!*/ Set(object/*!*/ key, object value) { + //Contract.Requires(key != null); + Contract.Ensures(Contract.Result() != null); + Hashtable r = h.Clone() as Hashtable; + + Contract.Assume(r != null); + Contract.Assert(this.Contains(key)); // The entry must be defined + + r[key] = value; + return new FunctionalHashtable(r); + } + + [Pure] + public bool Contains(object/*!*/ key) { + //Contract.Requires(key != null); + return h.Contains(key); + } + + [Pure] + [GlobalAccess(false)] + [Escapes(true, false)] + IEnumerator/*!*/ IEnumerable.GetEnumerator() { + Contract.Ensures(Contract.Result() != null); + + return h.GetEnumerator(); + } + + [Pure] + [GlobalAccess(false)] + [Escapes(true, false)] + IDictionaryEnumerator IFunctionalMap.GetEnumerator() { + return h.GetEnumerator(); + } + + public ICollection Keys { + get { + return h.Keys; + } + } + + public IFunctionalMap/*!*/ Remove(object/*!*/ key) { + //Contract.Requires(key != null); + Contract.Ensures(Contract.Result() != null); + Hashtable r = h.Clone() as Hashtable; + Contract.Assume(r != null); + r.Remove(key); + return new FunctionalHashtable(r); + } + + public ICollection Values { + get { + return h.Values; + } + } + + + public object this[object/*!*/ key] { + get { + //Contract.Requires(key != null); + return h[key]; + } + } + + public int Count { + [Pure] + get { + return h.Count; + } + } + + public bool IsSynchronized { + [Pure] + get { + return h.IsSynchronized; + } + } + + public object/*!*/ SyncRoot { + [Pure] + get { + Contract.Ensures(Contract.Result() != null); + return h.SyncRoot; + } + } + + public void CopyTo(System.Array/*!*/ a, int index) { + //Contract.Requires(a != null); + h.CopyTo(a, index); + } + } + + public struct Pair/**/ + { + private object first; + private object second; + + public object First { + get { + return first; + } + } + public object Second { + get { + return second; + } + } + + public Pair(object first, object second) { + this.first = first; + this.second = second; + } + + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is Pair)) + return false; + + Pair other = (Pair)obj; + return object.Equals(this.first, other.first) && object.Equals(this.second, other.second); + } + + public override int GetHashCode() { + int h = this.first == null ? 0 : this.first.GetHashCode(); + h ^= this.second == null ? 0 : this.second.GetHashCode(); + return h; + } + } +} + + +namespace Microsoft.AbstractInterpretationFramework.Collections.Generic { + using System.Collections.Generic; + + public struct Pair { + private T1 first; + private T2 second; + + public T1 First { + get { + return first; + } + } + public T2 Second { + get { + return second; + } + } + + public Pair(T1 first, T2 second) { + this.first = first; + this.second = second; + } + + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is Pair)) + return false; + + Pair other = (Pair)obj; + return object.Equals(this.first, other.first) && object.Equals(this.second, other.second); + } + + public override int GetHashCode() { + int h = this.first == null ? 0 : this.first.GetHashCode(); + h ^= this.second == null ? 0 : this.second.GetHashCode(); + return h; + } + + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return string.Format("({0},{1})", first, second); + } + } + + public struct Triple { + private T1 first; + private T2 second; + private T3 third; + + public T1 First { + get { + return first; + } + } + public T2 Second { + get { + return second; + } + } + public T3 Third { + get { + return third; + } + } + + public Triple(T1 first, T2 second, T3 third) { + this.first = first; + this.second = second; + this.third = third; + } + + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is Triple)) + return false; + + Triple other = (Triple)obj; + return object.Equals(this.first, other.first) && object.Equals(this.second, other.second) && object.Equals(this.third, other.third); + } + + public override int GetHashCode() { + int h = this.first == null ? 0 : this.first.GetHashCode(); + h ^= this.second == null ? 0 : this.second.GetHashCode(); + h ^= this.third == null ? 0 : this.third.GetHashCode(); + return h; + } + + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return string.Format("({0},{1},{2})", first, second, third); + } + } +} diff --git a/Source/AIFramework/Lattice.cs b/Source/AIFramework/Lattice.cs index ab10be9a..1796f1f6 100644 --- a/Source/AIFramework/Lattice.cs +++ b/Source/AIFramework/Lattice.cs @@ -1,960 +1,960 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework { - using System; - using System.Diagnostics.Contracts; - using System.Collections; - using G = System.Collections.Generic; - using System.Diagnostics; - using Microsoft.AbstractInterpretationFramework.Collections; - using Microsoft.Boogie; - +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System; + using System.Diagnostics.Contracts; + using System.Collections; + using G = System.Collections.Generic; + using System.Diagnostics; + using Microsoft.AbstractInterpretationFramework.Collections; + using Microsoft.Boogie; + using ArraySet = Microsoft.Boogie.GSet; - using IMutableSet = Microsoft.Boogie.GSet; - using HashSet = Microsoft.Boogie.GSet; - using ISet = Microsoft.Boogie.GSet; - using Set = Microsoft.Boogie.GSet; - - - /// - /// Specifies the operations (e.g., join) on a mathematical lattice that depend - /// only on the elements of the lattice. - /// - [ContractClass(typeof(MathematicalLatticeContracts))] - public abstract class MathematicalLattice { - #region Element - /// - /// An element of the lattice. This class should be derived from in any - /// implementation of MathematicalLattice. - /// - [ContractClass(typeof(ElementContracts))] - public abstract class Element : System.ICloneable { - /// - /// Print out a debug-useful representation of the internal data structure of the lattice element. - /// - public virtual void Dump(string/*!*/ msg) { - Contract.Requires(msg != null); - System.Console.WriteLine("Dump({0}) = {1}", msg, this); - } - - public abstract Element/*!*/ Clone(); - object/*!*/ System.ICloneable.Clone() { - return this.Clone(); - } - - public abstract G.ICollection/*!*/ FreeVariables(); - - } - [ContractClassFor(typeof(Element))] - public abstract class ElementContracts : Element { - public override Element Clone() { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - - } - - public override System.Collections.Generic.ICollection FreeVariables() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - Contract.Ensures(Contract.Result>().IsReadOnly); - throw new System.NotImplementedException(); - } - } - #endregion - - public abstract Element/*!*/ Top { - get; - } - public abstract Element/*!*/ Bottom { - get; - } - - public abstract bool IsTop(Element/*!*/ e); - public abstract bool IsBottom(Element/*!*/ e); - - /// - /// Returns true if a <= this. - /// - protected abstract bool AtMost(Element/*!*/ a, Element/*!*/ b); - /* The following cases are handled elsewhere and need not be considered in subclass. */ - // requires a.GetType() == b.GetType(); - // requires ! a.IsTop; - // requires ! a.IsBottom; - // requires ! b.IsTop; - // requires ! b.IsBottom; - - - protected Answer TrivialLowerThan(Element/*!*/ a, Element/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - if (a.GetType() != b.GetType()) { - throw new System.InvalidOperationException( - "operands to <= must be of same Element type" - ); - } - if (IsBottom(a)) { - return Answer.Yes; - } - if (IsTop(b)) { - return Answer.Yes; - } - if (IsTop(a)) { - return Answer.No; - } - if (IsBottom(b)) { - return Answer.No; - } - - return Answer.Maybe; - } - - // Is 'a' better information than 'b'? - // - public bool LowerThan(Element/*!*/ a, Element/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Answer ans = TrivialLowerThan(a, b); - return ans != Answer.Maybe ? ans == Answer.Yes : AtMost(a, b); - } - - // Is 'a' worse information than 'b'? - // - public bool HigherThan(Element/*!*/ a, Element/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - return LowerThan(b, a); - } - - // Are 'a' and 'b' equivalent? - // - public bool Equivalent(Element/*!*/ a, Element/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - return LowerThan(a, b) && LowerThan(b, a); - } - - public abstract Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b); - /* The following cases are handled elsewhere and need not be considered in subclass. */ - // requires a.GetType() == b.GetType(); - // requires ! a.IsTop; - // requires ! a.IsBottom; - // requires ! b.IsTop; - // requires ! b.IsBottom; - - - protected Element/*?*/ TrivialJoin(Element/*!*/ a, Element/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - if (a.GetType() != b.GetType()) { - throw new System.InvalidOperationException( - "operands to Join must be of same Lattice.Element type" - ); - } - if (IsTop(a)) { - return a; - } - if (IsTop(b)) { - return b; - } - if (IsBottom(a)) { - return b; - } - if (IsBottom(b)) { - return a; - } - - return null; - } - - public Element/*!*/ Join(Element/*!*/ a, Element/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - Element/*?*/ r = TrivialJoin(a, b); - return r != null ? r : NontrivialJoin(a, b); - } - - public abstract Element/*!*/ NontrivialMeet(Element/*!*/ a, Element/*!*/ b) - /* The following cases are handled elsewhere and need not be considered in subclass. */ - // requires a.GetType() == b.GetType(); - // requires ! a.IsTop; - // requires ! a.IsBottom; - // requires ! b.IsTop; - // requires ! b.IsBottom; - ; - - protected Element/*?*/ TrivialMeet(Element/*!*/ a, Element/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - if (a.GetType() != b.GetType()) { - throw new System.InvalidOperationException( - "operands to Meet must be of same Lattice.Element type" - ); - } - if (IsTop(a)) { - return b; - } - if (IsTop(b)) { - return a; - } - if (IsBottom(a)) { - return a; - } - if (IsBottom(b)) { - return b; - } - - return null; - } - - public Element/*!*/ Meet(Element/*!*/ a, Element/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - Element/*?*/ r = TrivialMeet(a, b); - return r != null ? r : NontrivialMeet(a, b); - } - - public abstract Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b); - - public virtual void Validate() { - Debug.Assert(IsTop(Top)); - Debug.Assert(IsBottom(Bottom)); - Debug.Assert(!IsBottom(Top)); - Debug.Assert(!IsTop(Bottom)); - - Debug.Assert(LowerThan(Top, Top)); - Debug.Assert(LowerThan(Bottom, Top)); - Debug.Assert(LowerThan(Bottom, Bottom)); - - Debug.Assert(IsTop(Join(Top, Top))); - Debug.Assert(IsBottom(Join(Bottom, Bottom))); - } - } - [ContractClassFor(typeof(MathematicalLattice))] - public abstract class MathematicalLatticeContracts : MathematicalLattice { - public override MathematicalLattice.Element Top { - get { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - - public override MathematicalLattice.Element Bottom { - get { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - - public override bool IsTop(MathematicalLattice.Element e) { - Contract.Requires(e != null); - throw new NotImplementedException(); - } - - public override bool IsBottom(MathematicalLattice.Element e) { - Contract.Requires(e != null); - throw new NotImplementedException(); - } - - protected override bool AtMost(MathematicalLattice.Element a, MathematicalLattice.Element b) { - Contract.Requires(a != null); - Contract.Requires(b != null); - throw new NotImplementedException(); - } - - public override MathematicalLattice.Element NontrivialJoin(MathematicalLattice.Element a, MathematicalLattice.Element b) { - Contract.Requires(a != null); - Contract.Requires(b != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - - public override MathematicalLattice.Element NontrivialMeet(MathematicalLattice.Element a, MathematicalLattice.Element b) { - Contract.Requires(a != null); - Contract.Requires(b != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - - public override MathematicalLattice.Element Widen(MathematicalLattice.Element a, MathematicalLattice.Element b) { - Contract.Requires(a != null); - Contract.Requires(b != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - - - /// - /// Provides an abstract interface for the operations of a lattice specific - /// to abstract interpretation (i.e., that deals with the expression language). - /// - [ContractClass(typeof(LatticeContracts))] - public abstract class Lattice : MathematicalLattice { - internal readonly IValueExprFactory/*!*/ valueExprFactory; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(valueExprFactory != null); - } - - - public Lattice(IValueExprFactory/*!*/ valueExprFactory) { - Contract.Requires(valueExprFactory != null); - this.valueExprFactory = valueExprFactory; - // base(); - } - - #region Primitives that commands translate into - - public abstract Element/*!*/ Eliminate(Element/*!*/ e, IVariable/*!*/ variable); - - public abstract Element/*!*/ Rename(Element/*!*/ e, IVariable/*!*/ oldName, IVariable/*!*/ newName); - - public abstract Element/*!*/ Constrain(Element/*!*/ e, IExpr/*!*/ expr); - - #endregion - - - // TODO keep this? - // public Element! Eliminate(Element! e, VariableSeq! variables) - // { - // Lattice.Element result = e; - // foreach (IVariable var in variables) - // { - // result = this.Eliminate(result, var); - // } - // return result; - // } - - - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // Note! - // - // Concrete classes that implement Lattice must implement one of the AtMost - // overloads. We provide here a default implementation for one given a "real" - // implementation of the other. Otherwise, there will be an infinite loop! - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - protected override bool AtMost(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires(b != null); - //Contract.Requires(a != null); - return AtMost(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map); - } - - protected virtual bool AtMost(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { - Contract.Requires(bToResult != null); - Contract.Requires(b != null); - Contract.Requires(aToResult != null); - Contract.Requires(a != null); - return AtMost(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult)); - } - - public bool LowerThan(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { - Contract.Requires(bToResult != null); - Contract.Requires(b != null); - Contract.Requires(aToResult != null); - Contract.Requires(a != null); - Answer ans = TrivialLowerThan(a, b); - return ans != Answer.Maybe ? ans == Answer.Yes : AtMost(a, aToResult, b, bToResult); - } - - public bool HigherThan(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { - Contract.Requires(bToResult != null); - Contract.Requires(b != null); - Contract.Requires(aToResult != null); - Contract.Requires(a != null); - return LowerThan(b, bToResult, a, aToResult); - } - - - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // Note! - // - // Concrete classes that implement Lattice must implement one of the NontrivialJoin - // overloads. We provide here a default implementation for one given a "real" - // implementation of the other. Otherwise, there will be an infinite loop! - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - public override Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires(b != null); - //Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - return NontrivialJoin(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map); - } - - public virtual Element/*!*/ NontrivialJoin(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { - Contract.Requires(bToResult != null); - Contract.Requires(b != null); - Contract.Requires(aToResult != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - return NontrivialJoin(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult)); - } - - public Element/*!*/ Join(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { - Contract.Requires(bToResult != null); - Contract.Requires(b != null); - Contract.Requires(aToResult != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - Element/*?*/ r = TrivialJoin(a, b); - return r != null ? r : NontrivialJoin(a, aToResult, b, bToResult); - } - - - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // Note! - // - // Concrete classes that implement Lattice must implement one of the Widen - // overloads. We provide here a default implementation for one given a "real" - // implementation of the other. Otherwise, there will be an infinite loop! - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - public override Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires(b != null); - //Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - return Widen(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map); - } - - public virtual Element/*!*/ Widen(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { - Contract.Requires(bToResult != null); - Contract.Requires(b != null); - Contract.Requires(aToResult != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - return Widen(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult)); - } - - - - /// - /// A default implementation of the given - /// the appropriate expression factories by calling CheckPredicate. - /// - protected Answer DefaultCheckVariableDisequality(IPropExprFactory/*!*/ propExprFactory, IValueExprFactory/*!*/ valExprFactory, Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2) { - Contract.Requires(propExprFactory != null); - Contract.Requires(valExprFactory != null); - Contract.Requires(e != null); - Contract.Requires(var1 != null); - Contract.Requires(var2 != null); - return this.CheckPredicate(e, propExprFactory.Not(valExprFactory.Eq(var1, var2))); - } - - private Element/*!*/ ApplyCombineNameMap(Element/*!*/ e, ICombineNameMap/*!*/ eToResult) { - Contract.Requires(eToResult != null); - Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - Element/*!*/ result = e; - - foreach (G.KeyValuePair*//*!*/> entry in eToResult.GetSourceToResult()) { - IVariable/*!*/ sourceName = entry.Key; - Contract.Assert(sourceName != null); - ISet/**//*!*/>/*!*/ emptyDictionary1 = new G.Dictionary*//*!*/>(); - private static readonly G.Dictionary/*!*/ emptyDictionary2 = new G.Dictionary(); - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Map != null); - Contract.Invariant(cce.NonNullDictionaryAndValues(emptyDictionary1) && Contract.ForAll(emptyDictionary1.Values, set =>/*cce.NonNullElements(set)*/set != null)); - Contract.Invariant(cce.NonNullDictionaryAndValues(emptyDictionary2)); - Contract.Invariant(indexMap != null); - Contract.Invariant(reverseIndexMap != null); - - } - - - public ISet/**//*?*/ GetResultNames(IVariable/*!*/ srcname) { - //Contract.Requires(srcname != null); - ArraySet a = new ArraySet(); - a.Add(srcname); - return a; - } - - public IVariable/*?*/ GetSourceName(IVariable/*!*/ resname) { - //Contract.Requires(resname != null); - return resname; - } - - //TODO: uncomment when works in compiler - //public G.IEnumerable*/!>> GetSourceToResult() - public IEnumerable/*!*/ GetSourceToResult() { - Contract.Ensures(Contract.Result() != null); - return emptyDictionary1; - } - - //public G.IEnumerable> GetResultToSource() - public IEnumerable/*!*/ GetResultToSource() { - Contract.Ensures(Contract.Result() != null); - return emptyDictionary2; - } - - private IdentityCombineNameMap() { - } - } - - #region Support for MultiLattice to uniquely number every subclass of Lattice - - - private static Hashtable/**//*!*/ indexMap = new Hashtable(); - private static Hashtable/**//*!*/ reverseIndexMap = new Hashtable(); - private static int globalCount = 0; - - protected virtual object/*!*/ UniqueId { - get { - Contract.Ensures(Contract.Result() != null); - return cce.NonNull(this.GetType()); - } - } - - public int Index { - get { - object unique = this.UniqueId; - if (indexMap.ContainsKey(unique)) { - object index = indexMap[unique]; - Contract.Assert(index != null); // this does nothing for nonnull analysis - if (index != null) { - return (int)index; - } - return 0; - } else { - int myIndex = globalCount++; - indexMap[unique] = myIndex; - reverseIndexMap[myIndex] = this; - return myIndex; - } - } - } - - public static Lattice GetGlobalLattice(int i) { - return reverseIndexMap[i] as Lattice; - } - #endregion - - public static bool LogSwitch = false; - /// - /// Returns the predicate that corresponds to the given lattice element. - /// - public abstract IExpr/*!*/ ToPredicate(Element/*!*/ e); - - /// - /// Allows the lattice to specify whether it understands a particular function symbol. - /// - /// The lattice is always allowed to return "true" even when it really can't do anything - /// with such functions; however, it is advantageous to say "false" when possible to - /// avoid being called to do certain things. - /// - /// The arguments to a function are provided for context so that the lattice can say - /// true or false for the same function symbol in different situations. For example, - /// a lattice may understand the multiplication of a variable and a constant but not - /// of two variables. The implementation of a lattice should not hold on to the - /// arguments. - /// - /// The function symbol. - /// The argument context. - /// True if it may understand f, false if it does not understand f. - public abstract bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args); - - /// - /// Return an expression that is equivalent to the given expression that does not - /// contain the given variable according to the lattice element and queryable. - /// - /// The lattice element. - /// A queryable for asking addtional information. - /// The expression to find an equivalent expression. - /// The variable to eliminate. - /// The set of variables that can't be used in the resulting expression. - /// - /// An equivalent expression to without - /// or null if not possible. - /// - public abstract IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, Set/**//*!*/ prohibitedVars); - - /// - /// Answers a query about whether the given predicate holds given the lattice element. - /// - /// The lattice element. - /// The predicate. - /// Yes, No, or Maybe. - public abstract Answer CheckPredicate(Element/*!*/ e, IExpr/*!*/ pred); - - /// - /// Answers a disequality about two variables. The same information could be obtained - /// by asking CheckPredicate, but a different implementation may be simpler and more - /// efficient. - /// - /// The lattice element. - /// The first variable. - /// The second variable. - /// Yes, No, or Maybe. - public abstract Answer CheckVariableDisequality(Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2); - - public abstract string/*!*/ ToString(Element/*!*/ e); // for debugging - - } - [ContractClassFor(typeof(Lattice))] - abstract class LatticeContracts : Lattice { - public LatticeContracts() - : base(null) { - } - public override IExpr ToPredicate(MathematicalLattice.Element e) { - Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - public override bool Understands(IFunctionSymbol f, IList args) { - Contract.Requires(f != null); - Contract.Requires(args != null); - throw new NotImplementedException(); - } - public override IExpr EquivalentExpr(MathematicalLattice.Element e, IQueryable q, IExpr expr, IVariable var, Set prohibitedVars) { - Contract.Requires(e != null); - Contract.Requires(q != null); - Contract.Requires(expr != null); - Contract.Requires(var != null); - Contract.Requires(prohibitedVars != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - public override Answer CheckPredicate(MathematicalLattice.Element e, IExpr pred) { - Contract.Requires(e != null); - Contract.Requires(pred != null); - throw new NotImplementedException(); - } - public override Answer CheckVariableDisequality(MathematicalLattice.Element e, IVariable var1, IVariable var2) { - Contract.Requires(e != null); - Contract.Requires(var1 != null); - Contract.Requires(var2 != null); - throw new NotImplementedException(); - } - public override string ToString(Element e) { - Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - public override MathematicalLattice.Element Eliminate(MathematicalLattice.Element e, IVariable variable) { - Contract.Requires(e != null); - Contract.Requires(variable != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - public override MathematicalLattice.Element Rename(MathematicalLattice.Element e, IVariable oldName, IVariable newName) { - Contract.Requires(e != null); - Contract.Requires(oldName != null); - Contract.Requires(newName != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - public override MathematicalLattice.Element Constrain(MathematicalLattice.Element e, IExpr expr) { - Contract.Requires(e != null); - Contract.Requires(expr != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - - /// - /// Defines the relation between names used in the respective input lattice elements to the - /// various combination operators (Join,Widen,Meet,AtMost) and the names that should be used - /// in the resulting lattice element. - /// - [ContractClass(typeof(ICombineNameMapContracts))] - public interface ICombineNameMap { - ISet/**//*?*/ GetResultNames(IVariable/*!*/ srcname); - IVariable/*?*/ GetSourceName(IVariable/*!*/ resname); - - //TODO: uncommet when works in compiler - //G.IEnumerable*/!>> GetSourceToResult(); - IEnumerable/*!*/ GetSourceToResult(); - //G.IEnumerable> GetResultToSource(); - IEnumerable/*!*/ GetResultToSource(); - } - [ContractClassFor(typeof(ICombineNameMap))] - public abstract class ICombineNameMapContracts : ICombineNameMap { - #region ICombineNameMap Members - - public Set GetResultNames(IVariable srcname) { - Contract.Requires(srcname != null); - throw new NotImplementedException(); - } - - public IVariable GetSourceName(IVariable resname) { - Contract.Requires(resname != null); - throw new NotImplementedException(); - } - - public IEnumerable GetSourceToResult() { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - - public IEnumerable GetResultToSource() { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - - #endregion - } - - /// - /// Provides statistics on the number of times an operation is performed - /// and forwards the real operations to the given lattice in the constructor. - /// - public class StatisticsLattice : Lattice { - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(lattice != null); - } - - readonly Lattice/*!*/ lattice; - int eliminateCount; - int renameCount; - int constrainCount; - int toPredicateCount; - int atMostCount; - int topCount; - int bottomCount; - int isTopCount; - int isBottomCount; - int joinCount; - int meetCount; - int widenCount; - int understandsCount; - int equivalentExprCount; - int checkPredicateCount; - int checkVariableDisequalityCount; - - public StatisticsLattice(Lattice/*!*/ lattice) - : base(lattice.valueExprFactory) { - Contract.Requires(lattice != null); - this.lattice = lattice; - // base(lattice.valueExprFactory); - } - - public override Element/*!*/ Eliminate(Element/*!*/ e, IVariable/*!*/ variable) { - //Contract.Requires(variable != null); - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - eliminateCount++; - return lattice.Eliminate(e, variable); - } - - public override Element/*!*/ Rename(Element/*!*/ e, IVariable/*!*/ oldName, IVariable/*!*/ newName) { - //Contract.Requires(newName != null); - //Contract.Requires(oldName != null); - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - renameCount++; - return lattice.Rename(e, oldName, newName); - } - - public override Element/*!*/ Constrain(Element/*!*/ e, IExpr/*!*/ expr) { - //Contract.Requires(expr != null); - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - constrainCount++; - return lattice.Constrain(e, expr); - } - - - public override bool Understands(IFunctionSymbol/*!*/ f, IList/*!*/ args) { - //Contract.Requires(args != null); - //Contract.Requires(f != null); - understandsCount++; - return lattice.Understands(f, args); - } - - - public override IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, ISet/**//*!*/ prohibitedVars) { - //Contract.Requires(prohibitedVars != null); - //Contract.Requires(var != null); - //Contract.Requires(expr != null); - //Contract.Requires(q != null); - //Contract.Requires(e != null); - equivalentExprCount++; - return lattice.EquivalentExpr(e, q, expr, var, prohibitedVars); - } - - - public override Answer CheckPredicate(Element/*!*/ e, IExpr/*!*/ pred) { - //Contract.Requires(pred != null); - //Contract.Requires(e != null); - checkPredicateCount++; - return lattice.CheckPredicate(e, pred); - } - - - public override Answer CheckVariableDisequality(Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2) { - //Contract.Requires(var2 != null); - //Contract.Requires(var1 != null); - //Contract.Requires(e != null); - checkVariableDisequalityCount++; - return lattice.CheckVariableDisequality(e, var1, var2); - } - - - - public override IExpr/*!*/ ToPredicate(Element/*!*/ e) { - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - toPredicateCount++; - return lattice.ToPredicate(e); - } - - public override string/*!*/ ToString(Element/*!*/ e) { - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - return lattice.ToString(e); - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return string.Format( - "StatisticsLattice: #Eliminate={0} #Rename={1} #Constrain={2} #ToPredicate={3} " + - "#Understands={4} #EquivalentExpr={5} #CheckPredicate={6} #CheckVariableDisequality={7} " + - "#AtMost={8} #Top={9} #Bottom={9} #IsTop={10} #IsBottom={11} " + - "#NonTrivialJoin={12} #NonTrivialMeet={13} #Widen={14}", - eliminateCount, renameCount, constrainCount, toPredicateCount, - understandsCount, equivalentExprCount, checkPredicateCount, checkVariableDisequalityCount, - atMostCount, topCount, bottomCount, isTopCount, isBottomCount, - joinCount, meetCount, widenCount); - } - - protected override bool AtMost(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires(b != null); - //Contract.Requires(a != null); - atMostCount++; - return lattice.LowerThan(a, b); - } - - public override Element/*!*/ Top { - get { - Contract.Ensures(Contract.Result() != null); - topCount++; - return lattice.Top; - } - } - public override Element/*!*/ Bottom { - get { - Contract.Ensures(Contract.Result() != null); - bottomCount++; - return lattice.Bottom; - } - } - - public override bool IsTop(Element/*!*/ e) { - //Contract.Requires(e != null); - isTopCount++; - return lattice.IsTop(e); - } - - public override bool IsBottom(Element/*!*/ e) { - //Contract.Requires(e != null); - isBottomCount++; - return lattice.IsBottom(e); - } - - public override Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires(b != null); - //Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - joinCount++; - return lattice.NontrivialJoin(a, b); - } - - public override Element/*!*/ NontrivialMeet(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires(b != null); - //Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - meetCount++; - return lattice.NontrivialMeet(a, b); - } - - public override Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires(b != null); - //Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - widenCount++; - return lattice.Widen(a, b); - } - - public override void Validate() { - base.Validate(); - lattice.Validate(); - } - - protected override object/*!*/ UniqueId { - get { - Contract.Ensures(Contract.Result() != null); - // use the base id, not the underlying-lattice id (is that the right thing to do?) - return base.UniqueId; - } - } - } - - - public sealed class LatticeQueryable : IQueryable { - private Lattice/*!*/ lattice; - private Lattice.Element/*!*/ element; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(lattice != null); - Contract.Invariant(element != null); - } - - - public LatticeQueryable(Lattice/*!*/ lattice, Lattice.Element/*!*/ element) { - Contract.Requires(element != null); - Contract.Requires(lattice != null); - this.lattice = lattice; - this.element = element; - // base(); - } - - public Answer CheckPredicate(IExpr/*!*/ pred) { - //Contract.Requires(pred != null); - return lattice.CheckPredicate(element, pred); - } - - public Answer CheckVariableDisequality(IVariable/*!*/ var1, IVariable/*!*/ var2) { - //Contract.Requires(var2 != null); - //Contract.Requires(var1 != null); - return lattice.CheckVariableDisequality(element, var1, var2); - } - } -} + using IMutableSet = Microsoft.Boogie.GSet; + using HashSet = Microsoft.Boogie.GSet; + using ISet = Microsoft.Boogie.GSet; + using Set = Microsoft.Boogie.GSet; + + + /// + /// Specifies the operations (e.g., join) on a mathematical lattice that depend + /// only on the elements of the lattice. + /// + [ContractClass(typeof(MathematicalLatticeContracts))] + public abstract class MathematicalLattice { + #region Element + /// + /// An element of the lattice. This class should be derived from in any + /// implementation of MathematicalLattice. + /// + [ContractClass(typeof(ElementContracts))] + public abstract class Element : System.ICloneable { + /// + /// Print out a debug-useful representation of the internal data structure of the lattice element. + /// + public virtual void Dump(string/*!*/ msg) { + Contract.Requires(msg != null); + System.Console.WriteLine("Dump({0}) = {1}", msg, this); + } + + public abstract Element/*!*/ Clone(); + object/*!*/ System.ICloneable.Clone() { + return this.Clone(); + } + + public abstract G.ICollection/*!*/ FreeVariables(); + + } + [ContractClassFor(typeof(Element))] + public abstract class ElementContracts : Element { + public override Element Clone() { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + + } + + public override System.Collections.Generic.ICollection FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + Contract.Ensures(Contract.Result>().IsReadOnly); + throw new System.NotImplementedException(); + } + } + #endregion + + public abstract Element/*!*/ Top { + get; + } + public abstract Element/*!*/ Bottom { + get; + } + + public abstract bool IsTop(Element/*!*/ e); + public abstract bool IsBottom(Element/*!*/ e); + + /// + /// Returns true if a <= this. + /// + protected abstract bool AtMost(Element/*!*/ a, Element/*!*/ b); + /* The following cases are handled elsewhere and need not be considered in subclass. */ + // requires a.GetType() == b.GetType(); + // requires ! a.IsTop; + // requires ! a.IsBottom; + // requires ! b.IsTop; + // requires ! b.IsBottom; + + + protected Answer TrivialLowerThan(Element/*!*/ a, Element/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + if (a.GetType() != b.GetType()) { + throw new System.InvalidOperationException( + "operands to <= must be of same Element type" + ); + } + if (IsBottom(a)) { + return Answer.Yes; + } + if (IsTop(b)) { + return Answer.Yes; + } + if (IsTop(a)) { + return Answer.No; + } + if (IsBottom(b)) { + return Answer.No; + } + + return Answer.Maybe; + } + + // Is 'a' better information than 'b'? + // + public bool LowerThan(Element/*!*/ a, Element/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Answer ans = TrivialLowerThan(a, b); + return ans != Answer.Maybe ? ans == Answer.Yes : AtMost(a, b); + } + + // Is 'a' worse information than 'b'? + // + public bool HigherThan(Element/*!*/ a, Element/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + return LowerThan(b, a); + } + + // Are 'a' and 'b' equivalent? + // + public bool Equivalent(Element/*!*/ a, Element/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + return LowerThan(a, b) && LowerThan(b, a); + } + + public abstract Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b); + /* The following cases are handled elsewhere and need not be considered in subclass. */ + // requires a.GetType() == b.GetType(); + // requires ! a.IsTop; + // requires ! a.IsBottom; + // requires ! b.IsTop; + // requires ! b.IsBottom; + + + protected Element/*?*/ TrivialJoin(Element/*!*/ a, Element/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + if (a.GetType() != b.GetType()) { + throw new System.InvalidOperationException( + "operands to Join must be of same Lattice.Element type" + ); + } + if (IsTop(a)) { + return a; + } + if (IsTop(b)) { + return b; + } + if (IsBottom(a)) { + return b; + } + if (IsBottom(b)) { + return a; + } + + return null; + } + + public Element/*!*/ Join(Element/*!*/ a, Element/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + Element/*?*/ r = TrivialJoin(a, b); + return r != null ? r : NontrivialJoin(a, b); + } + + public abstract Element/*!*/ NontrivialMeet(Element/*!*/ a, Element/*!*/ b) + /* The following cases are handled elsewhere and need not be considered in subclass. */ + // requires a.GetType() == b.GetType(); + // requires ! a.IsTop; + // requires ! a.IsBottom; + // requires ! b.IsTop; + // requires ! b.IsBottom; + ; + + protected Element/*?*/ TrivialMeet(Element/*!*/ a, Element/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + if (a.GetType() != b.GetType()) { + throw new System.InvalidOperationException( + "operands to Meet must be of same Lattice.Element type" + ); + } + if (IsTop(a)) { + return b; + } + if (IsTop(b)) { + return a; + } + if (IsBottom(a)) { + return a; + } + if (IsBottom(b)) { + return b; + } + + return null; + } + + public Element/*!*/ Meet(Element/*!*/ a, Element/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + Element/*?*/ r = TrivialMeet(a, b); + return r != null ? r : NontrivialMeet(a, b); + } + + public abstract Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b); + + public virtual void Validate() { + Debug.Assert(IsTop(Top)); + Debug.Assert(IsBottom(Bottom)); + Debug.Assert(!IsBottom(Top)); + Debug.Assert(!IsTop(Bottom)); + + Debug.Assert(LowerThan(Top, Top)); + Debug.Assert(LowerThan(Bottom, Top)); + Debug.Assert(LowerThan(Bottom, Bottom)); + + Debug.Assert(IsTop(Join(Top, Top))); + Debug.Assert(IsBottom(Join(Bottom, Bottom))); + } + } + [ContractClassFor(typeof(MathematicalLattice))] + public abstract class MathematicalLatticeContracts : MathematicalLattice { + public override MathematicalLattice.Element Top { + get { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + + public override MathematicalLattice.Element Bottom { + get { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + + public override bool IsTop(MathematicalLattice.Element e) { + Contract.Requires(e != null); + throw new NotImplementedException(); + } + + public override bool IsBottom(MathematicalLattice.Element e) { + Contract.Requires(e != null); + throw new NotImplementedException(); + } + + protected override bool AtMost(MathematicalLattice.Element a, MathematicalLattice.Element b) { + Contract.Requires(a != null); + Contract.Requires(b != null); + throw new NotImplementedException(); + } + + public override MathematicalLattice.Element NontrivialJoin(MathematicalLattice.Element a, MathematicalLattice.Element b) { + Contract.Requires(a != null); + Contract.Requires(b != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + + public override MathematicalLattice.Element NontrivialMeet(MathematicalLattice.Element a, MathematicalLattice.Element b) { + Contract.Requires(a != null); + Contract.Requires(b != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + + public override MathematicalLattice.Element Widen(MathematicalLattice.Element a, MathematicalLattice.Element b) { + Contract.Requires(a != null); + Contract.Requires(b != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + + + /// + /// Provides an abstract interface for the operations of a lattice specific + /// to abstract interpretation (i.e., that deals with the expression language). + /// + [ContractClass(typeof(LatticeContracts))] + public abstract class Lattice : MathematicalLattice { + internal readonly IValueExprFactory/*!*/ valueExprFactory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(valueExprFactory != null); + } + + + public Lattice(IValueExprFactory/*!*/ valueExprFactory) { + Contract.Requires(valueExprFactory != null); + this.valueExprFactory = valueExprFactory; + // base(); + } + + #region Primitives that commands translate into + + public abstract Element/*!*/ Eliminate(Element/*!*/ e, IVariable/*!*/ variable); + + public abstract Element/*!*/ Rename(Element/*!*/ e, IVariable/*!*/ oldName, IVariable/*!*/ newName); + + public abstract Element/*!*/ Constrain(Element/*!*/ e, IExpr/*!*/ expr); + + #endregion + + + // TODO keep this? + // public Element! Eliminate(Element! e, VariableSeq! variables) + // { + // Lattice.Element result = e; + // foreach (IVariable var in variables) + // { + // result = this.Eliminate(result, var); + // } + // return result; + // } + + + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // Note! + // + // Concrete classes that implement Lattice must implement one of the AtMost + // overloads. We provide here a default implementation for one given a "real" + // implementation of the other. Otherwise, there will be an infinite loop! + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + protected override bool AtMost(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + return AtMost(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map); + } + + protected virtual bool AtMost(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + Contract.Requires(bToResult != null); + Contract.Requires(b != null); + Contract.Requires(aToResult != null); + Contract.Requires(a != null); + return AtMost(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult)); + } + + public bool LowerThan(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + Contract.Requires(bToResult != null); + Contract.Requires(b != null); + Contract.Requires(aToResult != null); + Contract.Requires(a != null); + Answer ans = TrivialLowerThan(a, b); + return ans != Answer.Maybe ? ans == Answer.Yes : AtMost(a, aToResult, b, bToResult); + } + + public bool HigherThan(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + Contract.Requires(bToResult != null); + Contract.Requires(b != null); + Contract.Requires(aToResult != null); + Contract.Requires(a != null); + return LowerThan(b, bToResult, a, aToResult); + } + + + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // Note! + // + // Concrete classes that implement Lattice must implement one of the NontrivialJoin + // overloads. We provide here a default implementation for one given a "real" + // implementation of the other. Otherwise, there will be an infinite loop! + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + public override Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + return NontrivialJoin(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map); + } + + public virtual Element/*!*/ NontrivialJoin(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + Contract.Requires(bToResult != null); + Contract.Requires(b != null); + Contract.Requires(aToResult != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + return NontrivialJoin(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult)); + } + + public Element/*!*/ Join(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + Contract.Requires(bToResult != null); + Contract.Requires(b != null); + Contract.Requires(aToResult != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + Element/*?*/ r = TrivialJoin(a, b); + return r != null ? r : NontrivialJoin(a, aToResult, b, bToResult); + } + + + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // Note! + // + // Concrete classes that implement Lattice must implement one of the Widen + // overloads. We provide here a default implementation for one given a "real" + // implementation of the other. Otherwise, there will be an infinite loop! + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + public override Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + return Widen(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map); + } + + public virtual Element/*!*/ Widen(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + Contract.Requires(bToResult != null); + Contract.Requires(b != null); + Contract.Requires(aToResult != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + return Widen(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult)); + } + + + + /// + /// A default implementation of the given + /// the appropriate expression factories by calling CheckPredicate. + /// + protected Answer DefaultCheckVariableDisequality(IPropExprFactory/*!*/ propExprFactory, IValueExprFactory/*!*/ valExprFactory, Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2) { + Contract.Requires(propExprFactory != null); + Contract.Requires(valExprFactory != null); + Contract.Requires(e != null); + Contract.Requires(var1 != null); + Contract.Requires(var2 != null); + return this.CheckPredicate(e, propExprFactory.Not(valExprFactory.Eq(var1, var2))); + } + + private Element/*!*/ ApplyCombineNameMap(Element/*!*/ e, ICombineNameMap/*!*/ eToResult) { + Contract.Requires(eToResult != null); + Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + Element/*!*/ result = e; + + foreach (G.KeyValuePair*//*!*/> entry in eToResult.GetSourceToResult()) { + IVariable/*!*/ sourceName = entry.Key; + Contract.Assert(sourceName != null); + ISet/**//*!*/>/*!*/ emptyDictionary1 = new G.Dictionary*//*!*/>(); + private static readonly G.Dictionary/*!*/ emptyDictionary2 = new G.Dictionary(); + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Map != null); + Contract.Invariant(cce.NonNullDictionaryAndValues(emptyDictionary1) && Contract.ForAll(emptyDictionary1.Values, set =>/*cce.NonNullElements(set)*/set != null)); + Contract.Invariant(cce.NonNullDictionaryAndValues(emptyDictionary2)); + Contract.Invariant(indexMap != null); + Contract.Invariant(reverseIndexMap != null); + + } + + + public ISet/**//*?*/ GetResultNames(IVariable/*!*/ srcname) { + //Contract.Requires(srcname != null); + ArraySet a = new ArraySet(); + a.Add(srcname); + return a; + } + + public IVariable/*?*/ GetSourceName(IVariable/*!*/ resname) { + //Contract.Requires(resname != null); + return resname; + } + + //TODO: uncomment when works in compiler + //public G.IEnumerable*/!>> GetSourceToResult() + public IEnumerable/*!*/ GetSourceToResult() { + Contract.Ensures(Contract.Result() != null); + return emptyDictionary1; + } + + //public G.IEnumerable> GetResultToSource() + public IEnumerable/*!*/ GetResultToSource() { + Contract.Ensures(Contract.Result() != null); + return emptyDictionary2; + } + + private IdentityCombineNameMap() { + } + } + + #region Support for MultiLattice to uniquely number every subclass of Lattice + + + private static Hashtable/**//*!*/ indexMap = new Hashtable(); + private static Hashtable/**//*!*/ reverseIndexMap = new Hashtable(); + private static int globalCount = 0; + + protected virtual object/*!*/ UniqueId { + get { + Contract.Ensures(Contract.Result() != null); + return cce.NonNull(this.GetType()); + } + } + + public int Index { + get { + object unique = this.UniqueId; + if (indexMap.ContainsKey(unique)) { + object index = indexMap[unique]; + Contract.Assert(index != null); // this does nothing for nonnull analysis + if (index != null) { + return (int)index; + } + return 0; + } else { + int myIndex = globalCount++; + indexMap[unique] = myIndex; + reverseIndexMap[myIndex] = this; + return myIndex; + } + } + } + + public static Lattice GetGlobalLattice(int i) { + return reverseIndexMap[i] as Lattice; + } + #endregion + + public static bool LogSwitch = false; + /// + /// Returns the predicate that corresponds to the given lattice element. + /// + public abstract IExpr/*!*/ ToPredicate(Element/*!*/ e); + + /// + /// Allows the lattice to specify whether it understands a particular function symbol. + /// + /// The lattice is always allowed to return "true" even when it really can't do anything + /// with such functions; however, it is advantageous to say "false" when possible to + /// avoid being called to do certain things. + /// + /// The arguments to a function are provided for context so that the lattice can say + /// true or false for the same function symbol in different situations. For example, + /// a lattice may understand the multiplication of a variable and a constant but not + /// of two variables. The implementation of a lattice should not hold on to the + /// arguments. + /// + /// The function symbol. + /// The argument context. + /// True if it may understand f, false if it does not understand f. + public abstract bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args); + + /// + /// Return an expression that is equivalent to the given expression that does not + /// contain the given variable according to the lattice element and queryable. + /// + /// The lattice element. + /// A queryable for asking addtional information. + /// The expression to find an equivalent expression. + /// The variable to eliminate. + /// The set of variables that can't be used in the resulting expression. + /// + /// An equivalent expression to without + /// or null if not possible. + /// + public abstract IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, Set/**//*!*/ prohibitedVars); + + /// + /// Answers a query about whether the given predicate holds given the lattice element. + /// + /// The lattice element. + /// The predicate. + /// Yes, No, or Maybe. + public abstract Answer CheckPredicate(Element/*!*/ e, IExpr/*!*/ pred); + + /// + /// Answers a disequality about two variables. The same information could be obtained + /// by asking CheckPredicate, but a different implementation may be simpler and more + /// efficient. + /// + /// The lattice element. + /// The first variable. + /// The second variable. + /// Yes, No, or Maybe. + public abstract Answer CheckVariableDisequality(Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2); + + public abstract string/*!*/ ToString(Element/*!*/ e); // for debugging + + } + [ContractClassFor(typeof(Lattice))] + abstract class LatticeContracts : Lattice { + public LatticeContracts() + : base(null) { + } + public override IExpr ToPredicate(MathematicalLattice.Element e) { + Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + public override bool Understands(IFunctionSymbol f, IList args) { + Contract.Requires(f != null); + Contract.Requires(args != null); + throw new NotImplementedException(); + } + public override IExpr EquivalentExpr(MathematicalLattice.Element e, IQueryable q, IExpr expr, IVariable var, Set prohibitedVars) { + Contract.Requires(e != null); + Contract.Requires(q != null); + Contract.Requires(expr != null); + Contract.Requires(var != null); + Contract.Requires(prohibitedVars != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + public override Answer CheckPredicate(MathematicalLattice.Element e, IExpr pred) { + Contract.Requires(e != null); + Contract.Requires(pred != null); + throw new NotImplementedException(); + } + public override Answer CheckVariableDisequality(MathematicalLattice.Element e, IVariable var1, IVariable var2) { + Contract.Requires(e != null); + Contract.Requires(var1 != null); + Contract.Requires(var2 != null); + throw new NotImplementedException(); + } + public override string ToString(Element e) { + Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + public override MathematicalLattice.Element Eliminate(MathematicalLattice.Element e, IVariable variable) { + Contract.Requires(e != null); + Contract.Requires(variable != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + public override MathematicalLattice.Element Rename(MathematicalLattice.Element e, IVariable oldName, IVariable newName) { + Contract.Requires(e != null); + Contract.Requires(oldName != null); + Contract.Requires(newName != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + public override MathematicalLattice.Element Constrain(MathematicalLattice.Element e, IExpr expr) { + Contract.Requires(e != null); + Contract.Requires(expr != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + + /// + /// Defines the relation between names used in the respective input lattice elements to the + /// various combination operators (Join,Widen,Meet,AtMost) and the names that should be used + /// in the resulting lattice element. + /// + [ContractClass(typeof(ICombineNameMapContracts))] + public interface ICombineNameMap { + ISet/**//*?*/ GetResultNames(IVariable/*!*/ srcname); + IVariable/*?*/ GetSourceName(IVariable/*!*/ resname); + + //TODO: uncommet when works in compiler + //G.IEnumerable*/!>> GetSourceToResult(); + IEnumerable/*!*/ GetSourceToResult(); + //G.IEnumerable> GetResultToSource(); + IEnumerable/*!*/ GetResultToSource(); + } + [ContractClassFor(typeof(ICombineNameMap))] + public abstract class ICombineNameMapContracts : ICombineNameMap { + #region ICombineNameMap Members + + public Set GetResultNames(IVariable srcname) { + Contract.Requires(srcname != null); + throw new NotImplementedException(); + } + + public IVariable GetSourceName(IVariable resname) { + Contract.Requires(resname != null); + throw new NotImplementedException(); + } + + public IEnumerable GetSourceToResult() { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + + public IEnumerable GetResultToSource() { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + + #endregion + } + + /// + /// Provides statistics on the number of times an operation is performed + /// and forwards the real operations to the given lattice in the constructor. + /// + public class StatisticsLattice : Lattice { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(lattice != null); + } + + readonly Lattice/*!*/ lattice; + int eliminateCount; + int renameCount; + int constrainCount; + int toPredicateCount; + int atMostCount; + int topCount; + int bottomCount; + int isTopCount; + int isBottomCount; + int joinCount; + int meetCount; + int widenCount; + int understandsCount; + int equivalentExprCount; + int checkPredicateCount; + int checkVariableDisequalityCount; + + public StatisticsLattice(Lattice/*!*/ lattice) + : base(lattice.valueExprFactory) { + Contract.Requires(lattice != null); + this.lattice = lattice; + // base(lattice.valueExprFactory); + } + + public override Element/*!*/ Eliminate(Element/*!*/ e, IVariable/*!*/ variable) { + //Contract.Requires(variable != null); + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + eliminateCount++; + return lattice.Eliminate(e, variable); + } + + public override Element/*!*/ Rename(Element/*!*/ e, IVariable/*!*/ oldName, IVariable/*!*/ newName) { + //Contract.Requires(newName != null); + //Contract.Requires(oldName != null); + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + renameCount++; + return lattice.Rename(e, oldName, newName); + } + + public override Element/*!*/ Constrain(Element/*!*/ e, IExpr/*!*/ expr) { + //Contract.Requires(expr != null); + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + constrainCount++; + return lattice.Constrain(e, expr); + } + + + public override bool Understands(IFunctionSymbol/*!*/ f, IList/*!*/ args) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + understandsCount++; + return lattice.Understands(f, args); + } + + + public override IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, ISet/**//*!*/ prohibitedVars) { + //Contract.Requires(prohibitedVars != null); + //Contract.Requires(var != null); + //Contract.Requires(expr != null); + //Contract.Requires(q != null); + //Contract.Requires(e != null); + equivalentExprCount++; + return lattice.EquivalentExpr(e, q, expr, var, prohibitedVars); + } + + + public override Answer CheckPredicate(Element/*!*/ e, IExpr/*!*/ pred) { + //Contract.Requires(pred != null); + //Contract.Requires(e != null); + checkPredicateCount++; + return lattice.CheckPredicate(e, pred); + } + + + public override Answer CheckVariableDisequality(Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2) { + //Contract.Requires(var2 != null); + //Contract.Requires(var1 != null); + //Contract.Requires(e != null); + checkVariableDisequalityCount++; + return lattice.CheckVariableDisequality(e, var1, var2); + } + + + + public override IExpr/*!*/ ToPredicate(Element/*!*/ e) { + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + toPredicateCount++; + return lattice.ToPredicate(e); + } + + public override string/*!*/ ToString(Element/*!*/ e) { + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + return lattice.ToString(e); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return string.Format( + "StatisticsLattice: #Eliminate={0} #Rename={1} #Constrain={2} #ToPredicate={3} " + + "#Understands={4} #EquivalentExpr={5} #CheckPredicate={6} #CheckVariableDisequality={7} " + + "#AtMost={8} #Top={9} #Bottom={9} #IsTop={10} #IsBottom={11} " + + "#NonTrivialJoin={12} #NonTrivialMeet={13} #Widen={14}", + eliminateCount, renameCount, constrainCount, toPredicateCount, + understandsCount, equivalentExprCount, checkPredicateCount, checkVariableDisequalityCount, + atMostCount, topCount, bottomCount, isTopCount, isBottomCount, + joinCount, meetCount, widenCount); + } + + protected override bool AtMost(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + atMostCount++; + return lattice.LowerThan(a, b); + } + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result() != null); + topCount++; + return lattice.Top; + } + } + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result() != null); + bottomCount++; + return lattice.Bottom; + } + } + + public override bool IsTop(Element/*!*/ e) { + //Contract.Requires(e != null); + isTopCount++; + return lattice.IsTop(e); + } + + public override bool IsBottom(Element/*!*/ e) { + //Contract.Requires(e != null); + isBottomCount++; + return lattice.IsBottom(e); + } + + public override Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + joinCount++; + return lattice.NontrivialJoin(a, b); + } + + public override Element/*!*/ NontrivialMeet(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + meetCount++; + return lattice.NontrivialMeet(a, b); + } + + public override Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + widenCount++; + return lattice.Widen(a, b); + } + + public override void Validate() { + base.Validate(); + lattice.Validate(); + } + + protected override object/*!*/ UniqueId { + get { + Contract.Ensures(Contract.Result() != null); + // use the base id, not the underlying-lattice id (is that the right thing to do?) + return base.UniqueId; + } + } + } + + + public sealed class LatticeQueryable : IQueryable { + private Lattice/*!*/ lattice; + private Lattice.Element/*!*/ element; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(lattice != null); + Contract.Invariant(element != null); + } + + + public LatticeQueryable(Lattice/*!*/ lattice, Lattice.Element/*!*/ element) { + Contract.Requires(element != null); + Contract.Requires(lattice != null); + this.lattice = lattice; + this.element = element; + // base(); + } + + public Answer CheckPredicate(IExpr/*!*/ pred) { + //Contract.Requires(pred != null); + return lattice.CheckPredicate(element, pred); + } + + public Answer CheckVariableDisequality(IVariable/*!*/ var1, IVariable/*!*/ var2) { + //Contract.Requires(var2 != null); + //Contract.Requires(var1 != null); + return lattice.CheckVariableDisequality(element, var1, var2); + } + } +} diff --git a/Source/AIFramework/Logger.cs b/Source/AIFramework/Logger.cs index aa7c5979..5b455ab0 100644 --- a/Source/AIFramework/Logger.cs +++ b/Source/AIFramework/Logger.cs @@ -1,56 +1,56 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework { - using System; - using System.Diagnostics; - using System.Diagnostics.Contracts; - - public class Logger { - private string/*!*/ dbgmsgContext; - private static int contextWidth = 0; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(dbgmsgContext != null); - Contract.Invariant(dbgmsgIndent != null); - } - - - public bool Enabled = false; - - public Logger(string/*!*/ contextMsg) { - Contract.Requires(contextMsg != null); - this.dbgmsgContext = "[" + contextMsg + "] "; - contextWidth = Math.Max(contextWidth, contextMsg.Length + 3); - // base(); - } - - private static System.Text.StringBuilder/*!*/ dbgmsgIndent = new System.Text.StringBuilder(); - - public void DbgMsgIndent() { - dbgmsgIndent.Append(' ', 2); - } - public void DbgMsgUnindent() { - if (dbgmsgIndent.Length >= 2) - dbgmsgIndent.Remove(0, 2); - } - - [ConditionalAttribute("DEBUG")] - public void DbgMsg(string msg) { - if (Enabled) - Debug.WriteLine(dbgmsgContext.PadRight(contextWidth) + dbgmsgIndent + msg); - } - [ConditionalAttribute("DEBUG")] - public void DbgMsgNoLine(string msg) { - if (Enabled) - Debug.Write(dbgmsgContext.PadRight(contextWidth) + dbgmsgIndent + msg); - } - [ConditionalAttribute("DEBUG")] - public void DbgMsgPlain(string msg) { - if (Enabled) - Debug.Write(msg); - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System; + using System.Diagnostics; + using System.Diagnostics.Contracts; + + public class Logger { + private string/*!*/ dbgmsgContext; + private static int contextWidth = 0; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(dbgmsgContext != null); + Contract.Invariant(dbgmsgIndent != null); + } + + + public bool Enabled = false; + + public Logger(string/*!*/ contextMsg) { + Contract.Requires(contextMsg != null); + this.dbgmsgContext = "[" + contextMsg + "] "; + contextWidth = Math.Max(contextWidth, contextMsg.Length + 3); + // base(); + } + + private static System.Text.StringBuilder/*!*/ dbgmsgIndent = new System.Text.StringBuilder(); + + public void DbgMsgIndent() { + dbgmsgIndent.Append(' ', 2); + } + public void DbgMsgUnindent() { + if (dbgmsgIndent.Length >= 2) + dbgmsgIndent.Remove(0, 2); + } + + [ConditionalAttribute("DEBUG")] + public void DbgMsg(string msg) { + if (Enabled) + Debug.WriteLine(dbgmsgContext.PadRight(contextWidth) + dbgmsgIndent + msg); + } + [ConditionalAttribute("DEBUG")] + public void DbgMsgNoLine(string msg) { + if (Enabled) + Debug.Write(dbgmsgContext.PadRight(contextWidth) + dbgmsgIndent + msg); + } + [ConditionalAttribute("DEBUG")] + public void DbgMsgPlain(string msg) { + if (Enabled) + Debug.Write(msg); + } + } +} diff --git a/Source/AIFramework/MultiLattice.cs b/Source/AIFramework/MultiLattice.cs index ba9aa752..4c9de5f0 100644 --- a/Source/AIFramework/MultiLattice.cs +++ b/Source/AIFramework/MultiLattice.cs @@ -1,647 +1,647 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework { - using System.Diagnostics.Contracts; - using System.Collections; - using System.Collections.Generic; - using System.Diagnostics; - using Microsoft.AbstractInterpretationFramework.Collections; - - using Microsoft.Boogie; - - using ISet = Microsoft.Boogie.GSet; - using Set = Microsoft.Boogie.GSet; - - - /// - /// The cartesian product lattice. - /// - public class MultiLattice : Lattice, IEnumerable { - internal class Elt : Element { - public /*MaybeNull*/Element[] elementPerLattice; - - public Elt(int domainCount, bool isBottom) { - this.elementPerLattice = (domainCount == 0 && isBottom) ? null : new Element[domainCount]; - } - - private Elt(Elt/*!*/ other) { - Contract.Requires(other != null); - Element[] otherEPL = other.elementPerLattice; - if (otherEPL != null) { - Element[] newEPL = new Element[otherEPL.Length]; - for (int i = 0; i < newEPL.Length; i++) { - newEPL[i] = (Element)(cce.NonNull(otherEPL[i])).Clone(); - } - this.elementPerLattice = newEPL; - } - } - - public override Element/*!*/ Clone() { - Contract.Ensures(Contract.Result() != null); - return new Elt(this); - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - // string s = "MultiLattice+Elt{"; - // string sep = ""; - // Element[] epl = this.elementPerLattice; - // if (epl != null) - // { - // foreach (Element! e in epl) - // { - // s += sep + e.ToString(); - // sep = ", "; - // } - // } - // return s + "}"; - if (elementPerLattice == null) - return ""; - System.Text.StringBuilder buffer = new System.Text.StringBuilder(); - for (int i = 0; i < this.Count; i++) { - if (i > 0) - buffer.Append("; "); - buffer.AppendFormat("{0}", elementPerLattice[i]); - } - return buffer.ToString(); - } - - public override void Dump(string/*!*/ msg) { - //Contract.Requires(msg != null); - System.Console.WriteLine("MultiLattice.Elt.Dump({0})", msg); - Element[] epl = this.elementPerLattice; - if (epl != null) { - foreach (Element/*!*/ e in epl) { - Contract.Assert(e != null); - e.Dump(msg); - } - } - } - - [Pure] - public override ICollection/*!*/ FreeVariables() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - List/*!*/ list = new List(); - for (int i = 0; i < this.Count; i++) { - list.AddRange(cce.NonNull(this[i]).FreeVariables()); - } - return cce.NonNull(list.AsReadOnly()); - } - - public static Elt/*!*/ Top(ArrayList/**//*!*/ lattices) { - Contract.Requires(lattices != null); - Contract.Ensures(Contract.Result() != null); - Elt multiValue = new Elt(lattices.Count, false); - for (int i = 0; i < lattices.Count; i++) { - Lattice d = (Lattice/*!*/)cce.NonNull(lattices[i]); - multiValue[d.Index] = d.Top; - } - Debug.Assert(multiValue.IsValid); - return multiValue; - } - - - public static Elt/*!*/ Bottom(ArrayList/**//*!*/ lattices) { - Contract.Requires(lattices != null); - Contract.Ensures(Contract.Result() != null); - Elt multiValue = new Elt(lattices.Count, true); - for (int i = 0; i < lattices.Count; i++) { - Lattice d = (Lattice/*!*/)cce.NonNull(lattices[i]); - multiValue[d.Index] = d.Bottom; - } - Debug.Assert(multiValue.IsValid); - return multiValue; - } - - public bool IsValid { - get { - if (this.elementPerLattice == null) { - return true; /*bottom*/ - } - - Element[] epl = this.elementPerLattice; - for (int i = 0; i < epl.Length; i++) { - if (epl[i] == null) { - return false; - } - } - return true; - } - } - - public int Count { - get { - return this.elementPerLattice == null ? 0 : this.elementPerLattice.Length; - } - } - - public bool Contains(int i) { - return 0 <= i && i < this.Count; - } - - public Element this[int i] // just syntactic sugar - { - get { - Element[] epl = this.elementPerLattice; - return epl == null ? null : epl[i]; - } - set { - Element[] epl = this.elementPerLattice; - if (epl == null) - return; - epl[i] = value; - } - } - - } // class - - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(lattices != null); - Contract.Invariant(propExprFactory != null); - } - - ArrayList/**//*!*/ lattices = new ArrayList(); - - private readonly IPropExprFactory/*!*/ propExprFactory; - - - public MultiLattice(IPropExprFactory/*!*/ propExprFactory, IValueExprFactory/*!*/ valueExprFactory) - : base(valueExprFactory) { - Contract.Requires(valueExprFactory != null); - Contract.Requires(propExprFactory != null); - this.propExprFactory = propExprFactory; - // base(valueExprFactory); - } - - - - public void AddLattice(Lattice lattice) { - this.lattices.Add(lattice); - } - - private Lattice/*!*/ SubLattice(int i) { - Contract.Ensures(Contract.Result() != null); - return (Lattice/*!*/)cce.NonNull(this.lattices[i]); - } - - - public override Element/*!*/ Top { - get { - Contract.Ensures(Contract.Result() != null); - return Elt.Top(this.lattices); - } - } - - public override Element/*!*/ Bottom { - get { - Contract.Ensures(Contract.Result() != null); - return Elt.Bottom(this.lattices); - } - } - - - - - public override bool IsBottom(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - // The program is errorneous/nonterminating if any subdomain knows it is. - // - if (e.elementPerLattice == null) { - return true; - } - for (int i = 0; i < e.Count; i++) { - if (SubLattice(i).IsBottom(cce.NonNull(e[i]))) { - return true; - } - } - return false; - } - - public override bool IsTop(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - if (e.elementPerLattice == null) { - return false; - } - // The multidomain knows nothing about the program only if no subdomain - // knows anything about it. - // - for (int i = 0; i < e.Count; i++) { - if (!SubLattice(i).IsTop(cce.NonNull(e[i]))) { - return false; - } - } - return true; - } - - protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - - for (int i = 0; i < a.Count; i++) { - Element thisElement = cce.NonNull(a[i]); - Element thatElement = cce.NonNull(b[i]); - if (thisElement.GetType() != thatElement.GetType()) { - throw new System.InvalidOperationException( - "AtMost called on MultiDomain objects with different lattices" - ); - } - if (!SubLattice(i).LowerThan(thisElement, thatElement)) { - return false; - } - } - return true; - } - - protected override bool AtMost(Element/*!*/ first, ICombineNameMap/*!*/ firstToResult, Element/*!*/ second, ICombineNameMap/*!*/ secondToResult) { - //Contract.Requires(secondToResult != null); - //Contract.Requires(second != null); - //Contract.Requires(firstToResult != null); - //Contract.Requires(first != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - - for (int i = 0; i < a.Count; i++) { - Element thisElement = cce.NonNull(a[i]); - Element thatElement = cce.NonNull(b[i]); - if (thisElement.GetType() != thatElement.GetType()) { - throw new System.InvalidOperationException( - "AtMost called on MultiDomain objects with different lattices" - ); - } - if (!SubLattice(i).LowerThan(thisElement, firstToResult, thatElement, secondToResult)) { - return false; - } - } - return true; - } - - - private enum CombineOp { - Meet, - Join, - Widen - } - - private Element/*!*/ Combine(Element/*!*/ first, ICombineNameMap/*?*/ firstToResult, Element/*!*/ second, ICombineNameMap/*?*/ secondToResult, CombineOp c) { - Contract.Requires(second != null); - Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - - int unionCount = System.Math.Max(a.Count, b.Count); - Elt combined = new Elt(unionCount, IsBottom(a) && IsBottom(b)); - for (int i = 0; i < unionCount; i++) { - bool thisExists = a.Contains(i); - bool thatExists = b.Contains(i); - - if (thisExists && thatExists) { - Lattice.Element suba = a[i]; - Lattice.Element subb = b[i]; - Contract.Assert(suba != null && subb != null); - - switch (c) { - case CombineOp.Meet: - combined[i] = SubLattice(i).Meet(suba, subb); - break; - case CombineOp.Join: - if (firstToResult != null && secondToResult != null) - combined[i] = SubLattice(i).Join(suba, firstToResult, subb, secondToResult); - else - combined[i] = SubLattice(i).Join(suba, subb); - break; - case CombineOp.Widen: - if (firstToResult != null && secondToResult != null) - combined[i] = SubLattice(i).Widen(suba, firstToResult, subb, secondToResult); - else - combined[i] = SubLattice(i).Widen(suba, subb); - break; - } - } else if (thisExists) { - combined[i] = a[i]; - } else { - combined[i] = b[i]; - } - } - Debug.Assert(combined.IsValid); - return combined; - } - - public override Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires((b != null)); - //Contract.Requires((a != null)); - Contract.Ensures(Contract.Result() != null); - return this.Combine(a, null, b, null, CombineOp.Join); - } - - public override Element/*!*/ NontrivialJoin(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { - //Contract.Requires((bToResult != null)); - //Contract.Requires((b != null)); - //Contract.Requires((aToResult != null)); - //Contract.Requires((a != null)); - Contract.Ensures(Contract.Result() != null); - return this.Combine(a, aToResult, b, bToResult, CombineOp.Join); - } - - public override Element/*!*/ NontrivialMeet(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires((b != null)); - //Contract.Requires((a != null)); - Contract.Ensures(Contract.Result() != null); - return this.Combine(a, null, b, null, CombineOp.Meet); - } - - public override Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires((b != null)); - //Contract.Requires((a != null)); - Contract.Ensures(Contract.Result() != null); - return this.Combine(a, null, b, null, CombineOp.Widen); - } - - public override Element/*!*/ Widen(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { - //Contract.Requires((bToResult != null)); - //Contract.Requires((b != null)); - //Contract.Requires((aToResult != null)); - - //Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - return this.Combine(a, aToResult, b, bToResult, CombineOp.Widen); - } - - public override Element/*!*/ Eliminate(Element/*!*/ element, IVariable/*!*/ variable) { - //Contract.Requires(variable != null); - //Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - Elt e = (Elt)element; - if (IsBottom(e)) { - return e; - } - Elt newValue = new Elt(e.Count, false); - for (int i = 0; i < this.lattices.Count; i++) { - newValue[i] = SubLattice(i).Eliminate(cce.NonNull(e[i]), variable); - } - return newValue; - } - - - public override Element/*!*/ Constrain(Element/*!*/ element, IExpr/*!*/ expr) { - //Contract.Requires(expr != null); - //Contract.Requires(element != null); - //Contract.Ensures(Contract.Result() != null); - Elt e = (Elt)element; - if (IsBottom(e)) { - return e; - } - Elt newValue = new Elt(e.Count, false); - for (int i = 0; i < this.lattices.Count; i++) { - newValue[i] = SubLattice(i).Constrain(cce.NonNull(e[i]), expr); - } - return newValue; - } - - - public override Element/*!*/ Rename(Element/*!*/ element, IVariable/*!*/ oldName, IVariable/*!*/ newName) { - //Contract.Requires(newName != null); - //Contract.Requires(oldName != null); - //Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - Elt e = (Elt)element; - if (IsBottom(e)) { - return e; - } - Elt newValue = new Elt(e.Count, false); - for (int i = 0; i < this.lattices.Count; i++) { - newValue[i] = SubLattice(i).Rename(cce.NonNull(e[i]), oldName, newName); - } - return newValue; - } - - - public override bool Understands(IFunctionSymbol/*!*/ f, IList/*!*/ args) { - //Contract.Requires(args != null); - //Contract.Requires(f != null); - bool result = false; - - for (int i = 0; i < this.lattices.Count; i++) { - result = (result || SubLattice(i).Understands(f, args)); - } - - return result; - } - - - public override string/*!*/ ToString(Element/*!*/ element) { - //Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - Elt e = (Elt)element; - return e.ToString(); - } - - - public override IExpr/*!*/ ToPredicate(Element/*!*/ element) { - //Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - Elt e = (Elt)element; - - IExpr result = propExprFactory.True; - for (int i = 0; i < e.Count; i++) { - IExpr conjunct = SubLattice(i).ToPredicate(cce.NonNull(e[i])); - Contract.Assert(conjunct != null); - - result = Prop.SimplifiedAnd(propExprFactory, conjunct, result); - } - return result; - } - - /// - /// Return an expression that is equivalent to the given expression that does not - /// contain the given variable according to the lattice element and queryable. - /// - /// Simply asks each sublattice to try to generate an equivalent expression. We - /// do not try to combine information to infer new equivalences here. - /// - /// The lattice element. - /// A queryable for asking addtional information. - /// The expression to find an equivalent expression. - /// The variable to eliminate. - /// - /// An equivalent expression to without - /// or null if not possible. - /// - public override IExpr/*?*/ EquivalentExpr(Element/*!*/ element, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, Set/**//*!*/ prohibitedVars) { - //Contract.Requires(prohibitedVars != null); - //Contract.Requires(var != null); - //Contract.Requires(expr != null); - //Contract.Requires(q != null); - //Contract.Requires(element != null); - Elt/*!*/ e = (Elt/*!*/)cce.NonNull(element); - - for (int i = 0; i < e.Count; i++) { - IExpr equivexpr = SubLattice(i).EquivalentExpr(cce.NonNull(e[i]), q, expr, var, prohibitedVars); - - if (equivexpr != null) - return equivexpr; - } - - return null; - } - - - public override Answer CheckPredicate(Element/*!*/ element, IExpr/*!*/ pred) { - //Contract.Requires(pred != null); - //Contract.Requires(element != null); - Elt/*!*/ e = (Elt/*!*/)cce.NonNull(element); - - for (int i = 0; i < e.Count; i++) { - Answer ans = SubLattice(i).CheckPredicate(cce.NonNull(e[i]), pred); - - if (ans == Answer.Yes || ans == Answer.No) - return ans; - } - - return Answer.Maybe; - } - - - public override Answer CheckVariableDisequality(Element/*!*/ element, IVariable/*!*/ var1, IVariable/*!*/ var2) { - //Contract.Requires(var2 != null); - //Contract.Requires(var1 != null); - //Contract.Requires(element != null); - Elt/*!*/ e = (Elt/*!*/)cce.NonNull(element); - - for (int i = 0; i < e.Count; i++) { - Answer ans = SubLattice(i).CheckVariableDisequality(cce.NonNull(e[i]), var1, var2); - - if (ans == Answer.Yes || ans == Answer.No) - return ans; - } - - return Answer.Maybe; - } - - - - public override void Validate() { - base.Validate(); - foreach (Lattice/*!*/ l in lattices) { - Contract.Assert(l != null); - l.Validate(); - } - } - - /// - /// The enumeration over a MultiLattice is its sublattices. - /// - /// An enumerator over the sublattices. - [Pure] - [GlobalAccess(false)] - [Escapes(true, false)] - public IEnumerator/**//*!*/ GetEnumerator() { - Contract.Ensures(Contract.Result() != null); - return lattices.GetEnumerator(); - } - - /// - /// Return an enumerable over a mapping of sublattices to the their corresponding - /// lattice elements given a MultiLattice element. - /// - /// The MultiLattice element. - /// - /// An enumerable that yields an IDictionaryEnumerator over the - /// (Lattice, Lattice.Element) pairs. - /// - public IEnumerable/*!*/ Subelements(Element/*!*/ element) { - Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - return new SubelementsEnumerable(this, (Elt/*!*/)cce.NonNull(element)); - } - - /// - /// An enumerator over the sublattices and elements. - /// - private sealed class SubelementsEnumerable : IEnumerable { - private sealed class SubelementsEnumerator : IDictionaryEnumerator { - private readonly IEnumerator/**//*!*/ multiLatticeIter; - private readonly IEnumerator/**//*!*/ multiElementIter; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(multiElementIter != null); - Contract.Invariant(multiLatticeIter != null); - } - - - public SubelementsEnumerator(MultiLattice/*!*/ multiLattice, Elt/*!*/ multiElement) { - Contract.Requires(multiElement != null); - Contract.Requires(multiLattice != null); - Contract.Requires(multiElement.elementPerLattice != null); - this.multiLatticeIter = multiLattice.lattices.GetEnumerator(); - this.multiElementIter = multiElement.elementPerLattice.GetEnumerator(); - // base(); - } - - public DictionaryEntry Entry { - get { - return new DictionaryEntry(cce.NonNull(multiLatticeIter.Current), multiElementIter.Current); - } - } - - public object Key { - get { - return multiLatticeIter.Current; - } - } - - public object Value { - get { - return multiElementIter.Current; - } - } - - public object Current { - get { - return this.Entry; - } - } - - public bool MoveNext() { - return multiLatticeIter.MoveNext() && multiElementIter.MoveNext(); - } - - public void Reset() { - multiLatticeIter.Reset(); - multiElementIter.Reset(); - } - } - - private MultiLattice/*!*/ multiLattice; - private Elt/*!*/ multiElement; - - public SubelementsEnumerable(MultiLattice/*!*/ multiLattice, Elt/*!*/ multiElement) { - Contract.Requires(multiElement != null); - Contract.Requires(multiLattice != null); - this.multiLattice = multiLattice; - this.multiElement = multiElement; - // base(); - } - - [Pure] - [GlobalAccess(false)] - [Escapes(true, false)] - public IEnumerator/*!*/ GetEnumerator() { - Contract.Ensures(Contract.Result() != null); - return new SubelementsEnumerator(multiLattice, multiElement); - } - } - - - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System.Diagnostics.Contracts; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + using Microsoft.AbstractInterpretationFramework.Collections; + + using Microsoft.Boogie; + + using ISet = Microsoft.Boogie.GSet; + using Set = Microsoft.Boogie.GSet; + + + /// + /// The cartesian product lattice. + /// + public class MultiLattice : Lattice, IEnumerable { + internal class Elt : Element { + public /*MaybeNull*/Element[] elementPerLattice; + + public Elt(int domainCount, bool isBottom) { + this.elementPerLattice = (domainCount == 0 && isBottom) ? null : new Element[domainCount]; + } + + private Elt(Elt/*!*/ other) { + Contract.Requires(other != null); + Element[] otherEPL = other.elementPerLattice; + if (otherEPL != null) { + Element[] newEPL = new Element[otherEPL.Length]; + for (int i = 0; i < newEPL.Length; i++) { + newEPL[i] = (Element)(cce.NonNull(otherEPL[i])).Clone(); + } + this.elementPerLattice = newEPL; + } + } + + public override Element/*!*/ Clone() { + Contract.Ensures(Contract.Result() != null); + return new Elt(this); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + // string s = "MultiLattice+Elt{"; + // string sep = ""; + // Element[] epl = this.elementPerLattice; + // if (epl != null) + // { + // foreach (Element! e in epl) + // { + // s += sep + e.ToString(); + // sep = ", "; + // } + // } + // return s + "}"; + if (elementPerLattice == null) + return ""; + System.Text.StringBuilder buffer = new System.Text.StringBuilder(); + for (int i = 0; i < this.Count; i++) { + if (i > 0) + buffer.Append("; "); + buffer.AppendFormat("{0}", elementPerLattice[i]); + } + return buffer.ToString(); + } + + public override void Dump(string/*!*/ msg) { + //Contract.Requires(msg != null); + System.Console.WriteLine("MultiLattice.Elt.Dump({0})", msg); + Element[] epl = this.elementPerLattice; + if (epl != null) { + foreach (Element/*!*/ e in epl) { + Contract.Assert(e != null); + e.Dump(msg); + } + } + } + + [Pure] + public override ICollection/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + List/*!*/ list = new List(); + for (int i = 0; i < this.Count; i++) { + list.AddRange(cce.NonNull(this[i]).FreeVariables()); + } + return cce.NonNull(list.AsReadOnly()); + } + + public static Elt/*!*/ Top(ArrayList/**//*!*/ lattices) { + Contract.Requires(lattices != null); + Contract.Ensures(Contract.Result() != null); + Elt multiValue = new Elt(lattices.Count, false); + for (int i = 0; i < lattices.Count; i++) { + Lattice d = (Lattice/*!*/)cce.NonNull(lattices[i]); + multiValue[d.Index] = d.Top; + } + Debug.Assert(multiValue.IsValid); + return multiValue; + } + + + public static Elt/*!*/ Bottom(ArrayList/**//*!*/ lattices) { + Contract.Requires(lattices != null); + Contract.Ensures(Contract.Result() != null); + Elt multiValue = new Elt(lattices.Count, true); + for (int i = 0; i < lattices.Count; i++) { + Lattice d = (Lattice/*!*/)cce.NonNull(lattices[i]); + multiValue[d.Index] = d.Bottom; + } + Debug.Assert(multiValue.IsValid); + return multiValue; + } + + public bool IsValid { + get { + if (this.elementPerLattice == null) { + return true; /*bottom*/ + } + + Element[] epl = this.elementPerLattice; + for (int i = 0; i < epl.Length; i++) { + if (epl[i] == null) { + return false; + } + } + return true; + } + } + + public int Count { + get { + return this.elementPerLattice == null ? 0 : this.elementPerLattice.Length; + } + } + + public bool Contains(int i) { + return 0 <= i && i < this.Count; + } + + public Element this[int i] // just syntactic sugar + { + get { + Element[] epl = this.elementPerLattice; + return epl == null ? null : epl[i]; + } + set { + Element[] epl = this.elementPerLattice; + if (epl == null) + return; + epl[i] = value; + } + } + + } // class + + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(lattices != null); + Contract.Invariant(propExprFactory != null); + } + + ArrayList/**//*!*/ lattices = new ArrayList(); + + private readonly IPropExprFactory/*!*/ propExprFactory; + + + public MultiLattice(IPropExprFactory/*!*/ propExprFactory, IValueExprFactory/*!*/ valueExprFactory) + : base(valueExprFactory) { + Contract.Requires(valueExprFactory != null); + Contract.Requires(propExprFactory != null); + this.propExprFactory = propExprFactory; + // base(valueExprFactory); + } + + + + public void AddLattice(Lattice lattice) { + this.lattices.Add(lattice); + } + + private Lattice/*!*/ SubLattice(int i) { + Contract.Ensures(Contract.Result() != null); + return (Lattice/*!*/)cce.NonNull(this.lattices[i]); + } + + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result() != null); + return Elt.Top(this.lattices); + } + } + + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result() != null); + return Elt.Bottom(this.lattices); + } + } + + + + + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + // The program is errorneous/nonterminating if any subdomain knows it is. + // + if (e.elementPerLattice == null) { + return true; + } + for (int i = 0; i < e.Count; i++) { + if (SubLattice(i).IsBottom(cce.NonNull(e[i]))) { + return true; + } + } + return false; + } + + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + if (e.elementPerLattice == null) { + return false; + } + // The multidomain knows nothing about the program only if no subdomain + // knows anything about it. + // + for (int i = 0; i < e.Count; i++) { + if (!SubLattice(i).IsTop(cce.NonNull(e[i]))) { + return false; + } + } + return true; + } + + protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + + for (int i = 0; i < a.Count; i++) { + Element thisElement = cce.NonNull(a[i]); + Element thatElement = cce.NonNull(b[i]); + if (thisElement.GetType() != thatElement.GetType()) { + throw new System.InvalidOperationException( + "AtMost called on MultiDomain objects with different lattices" + ); + } + if (!SubLattice(i).LowerThan(thisElement, thatElement)) { + return false; + } + } + return true; + } + + protected override bool AtMost(Element/*!*/ first, ICombineNameMap/*!*/ firstToResult, Element/*!*/ second, ICombineNameMap/*!*/ secondToResult) { + //Contract.Requires(secondToResult != null); + //Contract.Requires(second != null); + //Contract.Requires(firstToResult != null); + //Contract.Requires(first != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + + for (int i = 0; i < a.Count; i++) { + Element thisElement = cce.NonNull(a[i]); + Element thatElement = cce.NonNull(b[i]); + if (thisElement.GetType() != thatElement.GetType()) { + throw new System.InvalidOperationException( + "AtMost called on MultiDomain objects with different lattices" + ); + } + if (!SubLattice(i).LowerThan(thisElement, firstToResult, thatElement, secondToResult)) { + return false; + } + } + return true; + } + + + private enum CombineOp { + Meet, + Join, + Widen + } + + private Element/*!*/ Combine(Element/*!*/ first, ICombineNameMap/*?*/ firstToResult, Element/*!*/ second, ICombineNameMap/*?*/ secondToResult, CombineOp c) { + Contract.Requires(second != null); + Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + + int unionCount = System.Math.Max(a.Count, b.Count); + Elt combined = new Elt(unionCount, IsBottom(a) && IsBottom(b)); + for (int i = 0; i < unionCount; i++) { + bool thisExists = a.Contains(i); + bool thatExists = b.Contains(i); + + if (thisExists && thatExists) { + Lattice.Element suba = a[i]; + Lattice.Element subb = b[i]; + Contract.Assert(suba != null && subb != null); + + switch (c) { + case CombineOp.Meet: + combined[i] = SubLattice(i).Meet(suba, subb); + break; + case CombineOp.Join: + if (firstToResult != null && secondToResult != null) + combined[i] = SubLattice(i).Join(suba, firstToResult, subb, secondToResult); + else + combined[i] = SubLattice(i).Join(suba, subb); + break; + case CombineOp.Widen: + if (firstToResult != null && secondToResult != null) + combined[i] = SubLattice(i).Widen(suba, firstToResult, subb, secondToResult); + else + combined[i] = SubLattice(i).Widen(suba, subb); + break; + } + } else if (thisExists) { + combined[i] = a[i]; + } else { + combined[i] = b[i]; + } + } + Debug.Assert(combined.IsValid); + return combined; + } + + public override Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires((b != null)); + //Contract.Requires((a != null)); + Contract.Ensures(Contract.Result() != null); + return this.Combine(a, null, b, null, CombineOp.Join); + } + + public override Element/*!*/ NontrivialJoin(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + //Contract.Requires((bToResult != null)); + //Contract.Requires((b != null)); + //Contract.Requires((aToResult != null)); + //Contract.Requires((a != null)); + Contract.Ensures(Contract.Result() != null); + return this.Combine(a, aToResult, b, bToResult, CombineOp.Join); + } + + public override Element/*!*/ NontrivialMeet(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires((b != null)); + //Contract.Requires((a != null)); + Contract.Ensures(Contract.Result() != null); + return this.Combine(a, null, b, null, CombineOp.Meet); + } + + public override Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires((b != null)); + //Contract.Requires((a != null)); + Contract.Ensures(Contract.Result() != null); + return this.Combine(a, null, b, null, CombineOp.Widen); + } + + public override Element/*!*/ Widen(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + //Contract.Requires((bToResult != null)); + //Contract.Requires((b != null)); + //Contract.Requires((aToResult != null)); + + //Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + return this.Combine(a, aToResult, b, bToResult, CombineOp.Widen); + } + + public override Element/*!*/ Eliminate(Element/*!*/ element, IVariable/*!*/ variable) { + //Contract.Requires(variable != null); + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + Elt e = (Elt)element; + if (IsBottom(e)) { + return e; + } + Elt newValue = new Elt(e.Count, false); + for (int i = 0; i < this.lattices.Count; i++) { + newValue[i] = SubLattice(i).Eliminate(cce.NonNull(e[i]), variable); + } + return newValue; + } + + + public override Element/*!*/ Constrain(Element/*!*/ element, IExpr/*!*/ expr) { + //Contract.Requires(expr != null); + //Contract.Requires(element != null); + //Contract.Ensures(Contract.Result() != null); + Elt e = (Elt)element; + if (IsBottom(e)) { + return e; + } + Elt newValue = new Elt(e.Count, false); + for (int i = 0; i < this.lattices.Count; i++) { + newValue[i] = SubLattice(i).Constrain(cce.NonNull(e[i]), expr); + } + return newValue; + } + + + public override Element/*!*/ Rename(Element/*!*/ element, IVariable/*!*/ oldName, IVariable/*!*/ newName) { + //Contract.Requires(newName != null); + //Contract.Requires(oldName != null); + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + Elt e = (Elt)element; + if (IsBottom(e)) { + return e; + } + Elt newValue = new Elt(e.Count, false); + for (int i = 0; i < this.lattices.Count; i++) { + newValue[i] = SubLattice(i).Rename(cce.NonNull(e[i]), oldName, newName); + } + return newValue; + } + + + public override bool Understands(IFunctionSymbol/*!*/ f, IList/*!*/ args) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + bool result = false; + + for (int i = 0; i < this.lattices.Count; i++) { + result = (result || SubLattice(i).Understands(f, args)); + } + + return result; + } + + + public override string/*!*/ ToString(Element/*!*/ element) { + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + Elt e = (Elt)element; + return e.ToString(); + } + + + public override IExpr/*!*/ ToPredicate(Element/*!*/ element) { + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + Elt e = (Elt)element; + + IExpr result = propExprFactory.True; + for (int i = 0; i < e.Count; i++) { + IExpr conjunct = SubLattice(i).ToPredicate(cce.NonNull(e[i])); + Contract.Assert(conjunct != null); + + result = Prop.SimplifiedAnd(propExprFactory, conjunct, result); + } + return result; + } + + /// + /// Return an expression that is equivalent to the given expression that does not + /// contain the given variable according to the lattice element and queryable. + /// + /// Simply asks each sublattice to try to generate an equivalent expression. We + /// do not try to combine information to infer new equivalences here. + /// + /// The lattice element. + /// A queryable for asking addtional information. + /// The expression to find an equivalent expression. + /// The variable to eliminate. + /// + /// An equivalent expression to without + /// or null if not possible. + /// + public override IExpr/*?*/ EquivalentExpr(Element/*!*/ element, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, Set/**//*!*/ prohibitedVars) { + //Contract.Requires(prohibitedVars != null); + //Contract.Requires(var != null); + //Contract.Requires(expr != null); + //Contract.Requires(q != null); + //Contract.Requires(element != null); + Elt/*!*/ e = (Elt/*!*/)cce.NonNull(element); + + for (int i = 0; i < e.Count; i++) { + IExpr equivexpr = SubLattice(i).EquivalentExpr(cce.NonNull(e[i]), q, expr, var, prohibitedVars); + + if (equivexpr != null) + return equivexpr; + } + + return null; + } + + + public override Answer CheckPredicate(Element/*!*/ element, IExpr/*!*/ pred) { + //Contract.Requires(pred != null); + //Contract.Requires(element != null); + Elt/*!*/ e = (Elt/*!*/)cce.NonNull(element); + + for (int i = 0; i < e.Count; i++) { + Answer ans = SubLattice(i).CheckPredicate(cce.NonNull(e[i]), pred); + + if (ans == Answer.Yes || ans == Answer.No) + return ans; + } + + return Answer.Maybe; + } + + + public override Answer CheckVariableDisequality(Element/*!*/ element, IVariable/*!*/ var1, IVariable/*!*/ var2) { + //Contract.Requires(var2 != null); + //Contract.Requires(var1 != null); + //Contract.Requires(element != null); + Elt/*!*/ e = (Elt/*!*/)cce.NonNull(element); + + for (int i = 0; i < e.Count; i++) { + Answer ans = SubLattice(i).CheckVariableDisequality(cce.NonNull(e[i]), var1, var2); + + if (ans == Answer.Yes || ans == Answer.No) + return ans; + } + + return Answer.Maybe; + } + + + + public override void Validate() { + base.Validate(); + foreach (Lattice/*!*/ l in lattices) { + Contract.Assert(l != null); + l.Validate(); + } + } + + /// + /// The enumeration over a MultiLattice is its sublattices. + /// + /// An enumerator over the sublattices. + [Pure] + [GlobalAccess(false)] + [Escapes(true, false)] + public IEnumerator/**//*!*/ GetEnumerator() { + Contract.Ensures(Contract.Result() != null); + return lattices.GetEnumerator(); + } + + /// + /// Return an enumerable over a mapping of sublattices to the their corresponding + /// lattice elements given a MultiLattice element. + /// + /// The MultiLattice element. + /// + /// An enumerable that yields an IDictionaryEnumerator over the + /// (Lattice, Lattice.Element) pairs. + /// + public IEnumerable/*!*/ Subelements(Element/*!*/ element) { + Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + return new SubelementsEnumerable(this, (Elt/*!*/)cce.NonNull(element)); + } + + /// + /// An enumerator over the sublattices and elements. + /// + private sealed class SubelementsEnumerable : IEnumerable { + private sealed class SubelementsEnumerator : IDictionaryEnumerator { + private readonly IEnumerator/**//*!*/ multiLatticeIter; + private readonly IEnumerator/**//*!*/ multiElementIter; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(multiElementIter != null); + Contract.Invariant(multiLatticeIter != null); + } + + + public SubelementsEnumerator(MultiLattice/*!*/ multiLattice, Elt/*!*/ multiElement) { + Contract.Requires(multiElement != null); + Contract.Requires(multiLattice != null); + Contract.Requires(multiElement.elementPerLattice != null); + this.multiLatticeIter = multiLattice.lattices.GetEnumerator(); + this.multiElementIter = multiElement.elementPerLattice.GetEnumerator(); + // base(); + } + + public DictionaryEntry Entry { + get { + return new DictionaryEntry(cce.NonNull(multiLatticeIter.Current), multiElementIter.Current); + } + } + + public object Key { + get { + return multiLatticeIter.Current; + } + } + + public object Value { + get { + return multiElementIter.Current; + } + } + + public object Current { + get { + return this.Entry; + } + } + + public bool MoveNext() { + return multiLatticeIter.MoveNext() && multiElementIter.MoveNext(); + } + + public void Reset() { + multiLatticeIter.Reset(); + multiElementIter.Reset(); + } + } + + private MultiLattice/*!*/ multiLattice; + private Elt/*!*/ multiElement; + + public SubelementsEnumerable(MultiLattice/*!*/ multiLattice, Elt/*!*/ multiElement) { + Contract.Requires(multiElement != null); + Contract.Requires(multiLattice != null); + this.multiLattice = multiLattice; + this.multiElement = multiElement; + // base(); + } + + [Pure] + [GlobalAccess(false)] + [Escapes(true, false)] + public IEnumerator/*!*/ GetEnumerator() { + Contract.Ensures(Contract.Result() != null); + return new SubelementsEnumerator(multiLattice, multiElement); + } + } + + + } +} diff --git a/Source/AIFramework/Mutable.cs b/Source/AIFramework/Mutable.cs index 7592aa6a..fff0476e 100644 --- a/Source/AIFramework/Mutable.cs +++ b/Source/AIFramework/Mutable.cs @@ -1,137 +1,137 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System.Diagnostics.Contracts; -namespace Microsoft.AbstractInterpretationFramework.Collections { - using System.Collections; - using System.Diagnostics.Contracts; - - /// - /// Extend sets for using as a IWorkList. - /// - public class WorkSet : Microsoft.Boogie.GSet, Microsoft.Boogie.IWorkList { - - // See Bug #148 for an explanation of why this is here. - // Without it, the contract inheritance rules will complain since it - // has nowhere to attach the out-of-band contract it gets from - // ICollection.Count that it gets from IWorkList. - public override int Count { - get { - return base.Count; - } - } - - [Pure] - public bool IsEmpty() { - return Count == 0; - } - - /// - /// Pull an element out of the workset. - /// - public object Pull() { - IEnumerator iter = GetEnumerator(); - iter.MoveNext(); - - object result = cce.NonNull(iter.Current); - Remove(result); - - return result; - } - - bool Microsoft.Boogie.IWorkList.Add(object o) { - if (o == null) - throw new System.ArgumentNullException(); - this.Add(o); - return true; - } - bool Microsoft.Boogie.IWorkList.AddAll(IEnumerable objs) { - if (objs == null) - throw new System.ArgumentNullException(); - return this.AddAll(objs); - } - - // ICollection members - public void CopyTo(System.Array/*!*/ a, int i) { - //Contract.Requires(a != null); - if (this.Count > a.Length - i) - throw new System.ArgumentException(); - int j = i; - foreach (object o in this) { - a.SetValue(o, j++); - } - return; - } - object/*!*/ ICollection.SyncRoot { - [Pure] - get { - Contract.Ensures(Contract.Result() != null); - return this; - } - } - public bool IsSynchronized { - get { - return false; - } - } - - } -} - -namespace Microsoft.AbstractInterpretationFramework.Collections.Generic { - using System.Collections.Generic; - - public class HashMultiset { - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(dict != null); - } - - private readonly IDictionary/*!*/ dict; - - //Contract.Invariant(Contract.ForAll(dict , entry => entry.Value >= 1)); - - public HashMultiset() { - this.dict = new Dictionary(); - // base(); - } - - public HashMultiset(int size) { - this.dict = new Dictionary(size); - // base(); - } - - public void Add(T t) { - cce.BeginExpose(this); - { - if (dict.ContainsKey(t)) { - dict[t] = dict[t] + 1; - } else { - dict.Add(t, 1); - } - } - cce.EndExpose(); - } - - public void Remove(T t) { - if (dict.ContainsKey(t)) { - cce.BeginExpose(this); - { - int count = dict[t]; - if (count == 1) { - dict.Remove(t); - } else { - dict[t] = count - 1; - } - } - cce.EndExpose(); - } - } - - public bool Contains(T t) { - return dict.ContainsKey(t); - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System.Diagnostics.Contracts; +namespace Microsoft.AbstractInterpretationFramework.Collections { + using System.Collections; + using System.Diagnostics.Contracts; + + /// + /// Extend sets for using as a IWorkList. + /// + public class WorkSet : Microsoft.Boogie.GSet, Microsoft.Boogie.IWorkList { + + // See Bug #148 for an explanation of why this is here. + // Without it, the contract inheritance rules will complain since it + // has nowhere to attach the out-of-band contract it gets from + // ICollection.Count that it gets from IWorkList. + public override int Count { + get { + return base.Count; + } + } + + [Pure] + public bool IsEmpty() { + return Count == 0; + } + + /// + /// Pull an element out of the workset. + /// + public object Pull() { + IEnumerator iter = GetEnumerator(); + iter.MoveNext(); + + object result = cce.NonNull(iter.Current); + Remove(result); + + return result; + } + + bool Microsoft.Boogie.IWorkList.Add(object o) { + if (o == null) + throw new System.ArgumentNullException(); + this.Add(o); + return true; + } + bool Microsoft.Boogie.IWorkList.AddAll(IEnumerable objs) { + if (objs == null) + throw new System.ArgumentNullException(); + return this.AddAll(objs); + } + + // ICollection members + public void CopyTo(System.Array/*!*/ a, int i) { + //Contract.Requires(a != null); + if (this.Count > a.Length - i) + throw new System.ArgumentException(); + int j = i; + foreach (object o in this) { + a.SetValue(o, j++); + } + return; + } + object/*!*/ ICollection.SyncRoot { + [Pure] + get { + Contract.Ensures(Contract.Result() != null); + return this; + } + } + public bool IsSynchronized { + get { + return false; + } + } + + } +} + +namespace Microsoft.AbstractInterpretationFramework.Collections.Generic { + using System.Collections.Generic; + + public class HashMultiset { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(dict != null); + } + + private readonly IDictionary/*!*/ dict; + + //Contract.Invariant(Contract.ForAll(dict , entry => entry.Value >= 1)); + + public HashMultiset() { + this.dict = new Dictionary(); + // base(); + } + + public HashMultiset(int size) { + this.dict = new Dictionary(size); + // base(); + } + + public void Add(T t) { + cce.BeginExpose(this); + { + if (dict.ContainsKey(t)) { + dict[t] = dict[t] + 1; + } else { + dict.Add(t, 1); + } + } + cce.EndExpose(); + } + + public void Remove(T t) { + if (dict.ContainsKey(t)) { + cce.BeginExpose(this); + { + int count = dict[t]; + if (count == 1) { + dict.Remove(t); + } else { + dict[t] = count - 1; + } + } + cce.EndExpose(); + } + } + + public bool Contains(T t) { + return dict.ContainsKey(t); + } + } +} diff --git a/Source/AIFramework/Polyhedra/LinearConstraint.cs b/Source/AIFramework/Polyhedra/LinearConstraint.cs index ab5e14f8..82264364 100644 --- a/Source/AIFramework/Polyhedra/LinearConstraint.cs +++ b/Source/AIFramework/Polyhedra/LinearConstraint.cs @@ -1,545 +1,545 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System.Diagnostics.Contracts; -namespace Microsoft.AbstractInterpretationFramework { - using System; - //using System.Compiler; - using System.Collections; - using Microsoft.Basetypes; +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System.Diagnostics.Contracts; +namespace Microsoft.AbstractInterpretationFramework { + using System; + //using System.Compiler; + using System.Collections; + using Microsoft.Basetypes; using Set = Microsoft.Boogie.GSet; - using IMutableSet = Microsoft.Boogie.GSet; - using HashSet = Microsoft.Boogie.GSet; - using ISet = Microsoft.Boogie.GSet; - - - /// - /// Represents a single linear constraint, coefficients are stored as Rationals. - /// - public class LinearConstraint { - - public enum ConstraintRelation { - EQ, // equal - LE, // less-than or equal - } - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(coefficients != null); - } - - public readonly ConstraintRelation Relation; - internal Hashtable /*IVariable->Rational*//*!*/ coefficients = new Hashtable /*IVariable->Rational*/ (); - internal Rational rhs; - - public LinearConstraint(ConstraintRelation rel) { - Relation = rel; - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - string s = null; - foreach (DictionaryEntry /*IVariable->Rational*/ entry in coefficients) { - if (s == null) { - s = ""; - } else { - s += " + "; - } - s += String.Format("{0}*{1}", entry.Value, entry.Key); - } - System.Diagnostics.Debug.Assert(s != null, "malformed LinearConstraint: no variables"); - s += String.Format(" {0} {1}", Relation == ConstraintRelation.EQ ? "==" : "<=", rhs); - return s; - } - - -#if DONT_KNOW_HOW_TO_TAKE_THE_TYPE_OF_AN_IVARIABLE_YET - public bool IsOverIntegers - { - get - { - foreach (DictionaryEntry /*IVariable->Rational*/ entry in coefficients) - { - IVariable var = (IVariable)entry.Key; - if ( ! var.TypedIdent.Type.IsInt) { return false; } - } - return true; - } - } -#endif - - - /// - /// Note: This method requires that all dimensions are of type Variable, something that's - /// not required elsewhere in this class. - /// - /// - public IExpr/*!*/ ConvertToExpression(ILinearExprFactory/*!*/ factory) { - Contract.Requires(factory != null); - Contract.Ensures(Contract.Result() != null); - IExpr leftSum = null; - IExpr rightSum = null; - foreach (DictionaryEntry /*object->Rational*/ entry in coefficients) { - IVariable var = (IVariable)entry.Key; - Rational coeff = (Rational)(cce.NonNull(entry.Value)); - if (coeff.IsPositive) { - leftSum = AddTerm(factory, leftSum, coeff, var); - } else if (coeff.IsNegative) { - rightSum = AddTerm(factory, rightSum, -coeff, var); - } else { - // ignore the term is coeff==0 - } - } - - if (leftSum == null && rightSum == null) { - // there are no variables in this constraint - if (Relation == ConstraintRelation.EQ ? rhs.IsZero : rhs.IsNonNegative) { - return factory.True; - } else { - return factory.False; - } - } - - if (leftSum == null || (rightSum != null && rhs.IsNegative)) { - // show the constant on the left side - leftSum = AddTerm(factory, leftSum, -rhs, null); - } else if (rightSum == null || rhs.IsPositive) { - // show the constant on the right side - rightSum = AddTerm(factory, rightSum, rhs, null); - } - - Contract.Assert(leftSum != null); - Contract.Assert(rightSum != null); - return Relation == ConstraintRelation.EQ ? factory.Eq(leftSum, rightSum) : factory.AtMost(leftSum, rightSum); - } - - /// - /// Returns an expression that denotes sum + r*x. - /// If sum==null, drops the "sum +". - /// If x==null, drops the "*x". - /// if x!=null and r==1, drops the "r*". - /// - /// - /// - /// - /// - static IExpr/*!*/ AddTerm(ILinearExprFactory/*!*/ factory, /*MayBeNull*/ IExpr sum, Rational r, /*MayBeNull*/ IVariable x) { - Contract.Requires(factory != null); - Contract.Ensures(Contract.Result() != null); - IExpr/*!*/ product = factory.Term(r, x); - Contract.Assert(product != null); - if (sum == null) { - return product; - } else { - return factory.Add(sum, product); - } - } - public System.Collections.Generic.IEnumerable GetDefinedDimensionsGeneric() { - Contract.Ensures(Contract.Result>() != null); - foreach (IVariable/*!*/ dim in coefficients.Keys) { - Contract.Assert(dim != null); - yield return dim; - } - } - public ISet /*IVariable!*//*!*/ GetDefinedDimensions() { - Contract.Ensures(Contract.Result() != null); - HashSet /*IVariable!*/ dims = new HashSet /*IVariable!*/ (coefficients.Count); - int j = 0; - foreach (IVariable/*!*/ dim in coefficients.Keys) { - Contract.Assert(dim != null); - dims.Add(dim); - j++; - } - System.Diagnostics.Debug.Assert(j == coefficients.Count); - return dims; - } - - /// - /// Returns true iff all of the coefficients in the constraint are 0. In that - /// case, the constraint has the form 0 <= C for some constant C; hence, the - /// constraint is either unsatisfiable or trivially satisfiable. - /// - /// - public bool IsConstant() { - foreach (Rational coeff in coefficients.Values) { - if (coeff.IsNonZero) { - return false; - } - } - return true; - } - - /// - /// For an equality constraint, returns 0 == rhs. - /// For an inequality constraint, returns 0 <= rhs. - /// - public bool IsConstantSatisfiable() { - if (Relation == ConstraintRelation.EQ) { - return rhs.IsZero; - } else { - return rhs.IsNonNegative; - } - } - - /// - /// Returns 0 if "this" and "c" are not equivalent constraints. If "this" and "c" - /// are equivalent constraints, the non-0 return value "m" satisfies "this == m*c". - /// - /// - /// - public Rational IsEquivalent(LinearConstraint/*!*/ c) { - Contract.Requires(c != null); - // "m" is the scale factor. If it is 0, it hasn't been used yet. If it - // is non-0, it will remain that value throughout, and it then says that - // for every dimension "d", "this[d] == m * c[d]". - Rational m = Rational.ZERO; - - ArrayList /*IVariable*/ dd = new ArrayList /*IVariable*/ (); - foreach (IVariable/*!*/ d in this.GetDefinedDimensions()) { - Contract.Assert(d != null); - if (!dd.Contains(d)) { - dd.Add(d); - } - } - foreach (IVariable/*!*/ d in c.GetDefinedDimensions()) { - Contract.Assert(d != null); - if (!dd.Contains(d)) { - dd.Add(d); - } - } - - foreach (IVariable/*!*/ d in dd) { - Contract.Assert(d != null); - Rational a = this[d]; - Rational b = c[d]; - - if (a.IsZero || b.IsZero) { - if (a.IsNonZero || b.IsNonZero) { - return Rational.ZERO; // not equivalent - } - } else if (m.IsZero) { - m = a / b; - } else if (a != m * b) { - return Rational.ZERO; // not equivalent - } - } - - // we expect there to have been some non-zero coefficient, so "m" should have been used by now - System.Diagnostics.Debug.Assert(m.IsNonZero); - - // finally, check the rhs - if (this.rhs == m * c.rhs) { - return m; // equivalent - } else { - return Rational.ZERO; // not equivalent - } - } - - /// - /// Splits an equality constraint into two inequality constraints, the conjunction of - /// which equals the equality constraint. Assumes "this" is a equality constraint. - /// - /// - /// - public void GenerateInequalityConstraints(out LinearConstraint a, out LinearConstraint b) { - System.Diagnostics.Debug.Assert(this.Relation == ConstraintRelation.EQ); - - a = new LinearConstraint(ConstraintRelation.LE); - a.coefficients = (Hashtable)this.coefficients.Clone(); - a.rhs = this.rhs; - - b = new LinearConstraint(ConstraintRelation.LE); - b.coefficients = new Hashtable /*IVariable->Rational*/ (); - foreach (DictionaryEntry entry in this.coefficients) { - b.coefficients[entry.Key] = -(Rational)(cce.NonNull(entry.Value)); - } - b.rhs = -this.rhs; - } - - public void SetCoefficient(IVariable/*!*/ dimension, Rational coefficient) { - Contract.Requires(dimension != null); - coefficients[dimension] = coefficient; - } - - /// - /// Removes dimension "dim" from the constraint. Only dimensions with coefficient 0 can - /// be removed. - /// - /// - public void RemoveDimension(IVariable/*!*/ dim) { - Contract.Requires(dim != null); - object val = coefficients[dim]; - if (val != null) { -#if FIXED_SERIALIZER - Contract.Assert(((Rational)val).IsZero); -#endif - coefficients.Remove(dim); - } - } - - /// - /// The getter returns 0 if the dimension is not present. - /// - public Rational this[IVariable/*!*/ dimension] { - get { - Contract.Requires(dimension != null); - - - object z = coefficients[dimension]; - if (z == null) { - return Rational.ZERO; - } else { - return (Rational)z; - } - } - set { - SetCoefficient(dimension, value); - } - } - - public LinearConstraint Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName) { - Contract.Requires(newName != null); - Contract.Requires(oldName != null); - object /*Rational*/ z = coefficients[oldName]; - if (z == null) { - return this; - } else { - System.Diagnostics.Debug.Assert(z is Rational); - Hashtable /*IVariable->Rational*/ newCoeffs = (Hashtable/*!*/ /*IVariable->Rational*/)cce.NonNull(coefficients.Clone()); - newCoeffs.Remove(oldName); - newCoeffs.Add(newName, z); - - LinearConstraint lc = new LinearConstraint(this.Relation); - lc.coefficients = newCoeffs; - lc.rhs = this.rhs; - return lc; - } - } - - public LinearConstraint Clone() { - LinearConstraint z = new LinearConstraint(Relation); - z.coefficients = (Hashtable /*IVariable->Rational*/)this.coefficients.Clone(); - z.rhs = this.rhs; - return z; - } - - /// - /// Returns a constraint like "this", but with the given relation "r". - /// - /// - public LinearConstraint/*!*/ ChangeRelation(ConstraintRelation rel) { - Contract.Ensures(Contract.Result() != null); - if (Relation == rel) { - return this; - } else { - LinearConstraint z = new LinearConstraint(rel); - z.coefficients = (Hashtable)this.coefficients.Clone(); - z.rhs = this.rhs; - return z; - } - } - - /// - /// Returns a constraint like "this", but, conceptually, with the inequality relation >=. - /// - /// - public LinearConstraint/*!*/ ChangeRelationToAtLeast() { - Contract.Ensures(Contract.Result() != null); - LinearConstraint z = new LinearConstraint(ConstraintRelation.LE); - foreach (DictionaryEntry /*IVariable->Rational*/ entry in this.coefficients) { - z.coefficients.Add(entry.Key, -(Rational)(cce.NonNull(entry.Value))); - } - z.rhs = -this.rhs; - return z; - } - - /// - /// Returns the left-hand side of the constraint evaluated at the point "v". - /// Any coordinate not present in "v" is treated as if it were 0. - /// Stated differently, this routine treats the left-hand side of the constraint - /// as a row vector and "v" as a column vector, and then returns the dot-product - /// of the two. - /// - /// - /// - public Rational EvaluateLhs(FrameElement/*!*/ v) { - Contract.Requires(v != null); - Rational q = Rational.ZERO; - foreach (DictionaryEntry /*IVariable,Rational*/ term in coefficients) { - IVariable dim = (IVariable/*!*/)cce.NonNull(term.Key); - Rational a = (Rational)(cce.NonNull(term.Value)); - Rational x = v[dim]; - q += a * x; - } - return q; - } - - /// - /// Determines whether or not a given vertex or ray saturates the constraint. - /// - /// - /// true if "fe" is a vertex; false if "fe" is a ray - /// - public bool IsSaturatedBy(FrameElement/*!*/ fe, bool vertex) { - Contract.Requires(fe != null); - Rational lhs = EvaluateLhs(fe); - Rational rhs = vertex ? this.rhs : Rational.ZERO; - return lhs == rhs; - } - - /// - /// Changes the current constraint A*X <= B into (A + m*aa)*X <= B + m*bb, - /// where "cc" is the constraint aa*X <= bb. - /// - /// - /// - /// - public void AddMultiple(Rational m, LinearConstraint/*!*/ cc) { - Contract.Requires(cc != null); - foreach (DictionaryEntry /*IVariable->Rational*/ entry in cc.coefficients) { - IVariable dim = (IVariable)entry.Key; - Rational d = m * (Rational)(cce.NonNull(entry.Value)); - if (d.IsNonZero) { - object prev = coefficients[dim]; - if (prev == null) { - coefficients[dim] = d; - } else { - coefficients[dim] = (Rational)prev + d; - } - } - } - rhs += m * cc.rhs; - } - - /// - /// Try to reduce the magnitude of the coefficients used. - /// Has a side effect on the coefficients, but leaves the meaning of the linear constraint - /// unchanged. - /// - public void Normalize() { - // compute the gcd of the numerators and the gcd of the denominators - Rational gcd = rhs; - foreach (Rational r in coefficients.Values) { - gcd = Rational.Gcd(gcd, r); - } - // Change all coefficients, to divide their numerators with gcdNum and to - // divide their denominators with gcdDen. - Hashtable /*IVariable->Rational*/ newCoefficients = new Hashtable /*IVariable->Rational*/ (coefficients.Count); - foreach (DictionaryEntry /*IVarianble->Rational*/ e in coefficients) { - Rational r = (Rational)(cce.NonNull(e.Value)); - if (r.IsNonZero) { - newCoefficients.Add(e.Key, Rational.FromBignums(r.Numerator / gcd.Numerator, r.Denominator / gcd.Denominator)); - } else { - newCoefficients.Add(e.Key, r); - } - } - - coefficients = newCoefficients; - rhs = rhs.IsNonZero ? Rational.FromBignums(rhs.Numerator / gcd.Numerator, rhs.Denominator / gcd.Denominator) : rhs; - } - } - - /// - /// Represents a frame element (vector of dimension/value tuples). Used only - /// internally in class LinearConstraintSystem and its communication with class - /// LinearConstraint. - /// - public class FrameElement { - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(terms != null); - } - - Hashtable /*IVariable->Rational*//*!*/ terms = new Hashtable /*IVariable->Rational*/ (); - - /// - /// Constructs an empty FrameElement. To add dimensions, call AddCoordinate after construction. - /// - public FrameElement() { - } - - /// - /// This method is to be thought of as being part of the FrameElement object's construction process. - /// Assumes "dimension" is not already in FrameElement. - /// - /// - /// - public void AddCoordinate(IVariable/*!*/ dimension, Rational value) { - Contract.Requires(dimension != null); - terms.Add(dimension, value); - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - string s = null; - foreach (DictionaryEntry item in terms) { - if (s == null) { - s = "("; - } else { - s += ", "; - } - s += String.Format("<{0},{1}>", item.Key, (Rational)(cce.NonNull(item.Value))); - } - if (s == null) { - s = "("; - } - return s + ")"; - } - - public IMutableSet /*IVariable!*//*!*/ GetDefinedDimensions() { - Contract.Ensures(Contract.Result() != null); - HashSet /*IVariable!*//*!*/ dims = new HashSet /*IVariable!*/ (terms.Count); - foreach (IVariable/*!*/ dim in terms.Keys) { - Contract.Assert(dim != null); - dims.Add(dim); - } - System.Diagnostics.Debug.Assert(dims.Count == terms.Count); - return dims; - } - - /// - /// The getter returns the value at the given dimension, or 0 if that dimension is not defined. - /// - public Rational this[IVariable/*!*/ dimension] { - get { - //Contract.Ensures(Contract.Result() != null); - object z = terms[dimension]; - if (z == null) { - return Rational.ZERO; - } else { - return (Rational)z; - } - } - set { - terms[dimension] = value; - } - } - - public FrameElement Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName) { - Contract.Requires(newName != null); - Contract.Requires(oldName != null); - object /*Rational*/ z = terms[oldName]; - if (z == null) { - return this; - } else { - System.Diagnostics.Debug.Assert(z is Rational); - Hashtable /*IVariable->Rational*/ newTerms = (Hashtable/*!*/ /*IVariable->Rational*/)cce.NonNull(terms.Clone()); - newTerms.Remove(oldName); - newTerms.Add(newName, z); - - FrameElement fe = new FrameElement(); - fe.terms = newTerms; - return fe; - } - } - - public FrameElement Clone() { - FrameElement z = new FrameElement(); - z.terms = (Hashtable /*IVariable->Rational*/)this.terms.Clone(); - return z; - } - } -} + using IMutableSet = Microsoft.Boogie.GSet; + using HashSet = Microsoft.Boogie.GSet; + using ISet = Microsoft.Boogie.GSet; + + + /// + /// Represents a single linear constraint, coefficients are stored as Rationals. + /// + public class LinearConstraint { + + public enum ConstraintRelation { + EQ, // equal + LE, // less-than or equal + } + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(coefficients != null); + } + + public readonly ConstraintRelation Relation; + internal Hashtable /*IVariable->Rational*//*!*/ coefficients = new Hashtable /*IVariable->Rational*/ (); + internal Rational rhs; + + public LinearConstraint(ConstraintRelation rel) { + Relation = rel; + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + string s = null; + foreach (DictionaryEntry /*IVariable->Rational*/ entry in coefficients) { + if (s == null) { + s = ""; + } else { + s += " + "; + } + s += String.Format("{0}*{1}", entry.Value, entry.Key); + } + System.Diagnostics.Debug.Assert(s != null, "malformed LinearConstraint: no variables"); + s += String.Format(" {0} {1}", Relation == ConstraintRelation.EQ ? "==" : "<=", rhs); + return s; + } + + +#if DONT_KNOW_HOW_TO_TAKE_THE_TYPE_OF_AN_IVARIABLE_YET + public bool IsOverIntegers + { + get + { + foreach (DictionaryEntry /*IVariable->Rational*/ entry in coefficients) + { + IVariable var = (IVariable)entry.Key; + if ( ! var.TypedIdent.Type.IsInt) { return false; } + } + return true; + } + } +#endif + + + /// + /// Note: This method requires that all dimensions are of type Variable, something that's + /// not required elsewhere in this class. + /// + /// + public IExpr/*!*/ ConvertToExpression(ILinearExprFactory/*!*/ factory) { + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result() != null); + IExpr leftSum = null; + IExpr rightSum = null; + foreach (DictionaryEntry /*object->Rational*/ entry in coefficients) { + IVariable var = (IVariable)entry.Key; + Rational coeff = (Rational)(cce.NonNull(entry.Value)); + if (coeff.IsPositive) { + leftSum = AddTerm(factory, leftSum, coeff, var); + } else if (coeff.IsNegative) { + rightSum = AddTerm(factory, rightSum, -coeff, var); + } else { + // ignore the term is coeff==0 + } + } + + if (leftSum == null && rightSum == null) { + // there are no variables in this constraint + if (Relation == ConstraintRelation.EQ ? rhs.IsZero : rhs.IsNonNegative) { + return factory.True; + } else { + return factory.False; + } + } + + if (leftSum == null || (rightSum != null && rhs.IsNegative)) { + // show the constant on the left side + leftSum = AddTerm(factory, leftSum, -rhs, null); + } else if (rightSum == null || rhs.IsPositive) { + // show the constant on the right side + rightSum = AddTerm(factory, rightSum, rhs, null); + } + + Contract.Assert(leftSum != null); + Contract.Assert(rightSum != null); + return Relation == ConstraintRelation.EQ ? factory.Eq(leftSum, rightSum) : factory.AtMost(leftSum, rightSum); + } + + /// + /// Returns an expression that denotes sum + r*x. + /// If sum==null, drops the "sum +". + /// If x==null, drops the "*x". + /// if x!=null and r==1, drops the "r*". + /// + /// + /// + /// + /// + static IExpr/*!*/ AddTerm(ILinearExprFactory/*!*/ factory, /*MayBeNull*/ IExpr sum, Rational r, /*MayBeNull*/ IVariable x) { + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result() != null); + IExpr/*!*/ product = factory.Term(r, x); + Contract.Assert(product != null); + if (sum == null) { + return product; + } else { + return factory.Add(sum, product); + } + } + public System.Collections.Generic.IEnumerable GetDefinedDimensionsGeneric() { + Contract.Ensures(Contract.Result>() != null); + foreach (IVariable/*!*/ dim in coefficients.Keys) { + Contract.Assert(dim != null); + yield return dim; + } + } + public ISet /*IVariable!*//*!*/ GetDefinedDimensions() { + Contract.Ensures(Contract.Result() != null); + HashSet /*IVariable!*/ dims = new HashSet /*IVariable!*/ (coefficients.Count); + int j = 0; + foreach (IVariable/*!*/ dim in coefficients.Keys) { + Contract.Assert(dim != null); + dims.Add(dim); + j++; + } + System.Diagnostics.Debug.Assert(j == coefficients.Count); + return dims; + } + + /// + /// Returns true iff all of the coefficients in the constraint are 0. In that + /// case, the constraint has the form 0 <= C for some constant C; hence, the + /// constraint is either unsatisfiable or trivially satisfiable. + /// + /// + public bool IsConstant() { + foreach (Rational coeff in coefficients.Values) { + if (coeff.IsNonZero) { + return false; + } + } + return true; + } + + /// + /// For an equality constraint, returns 0 == rhs. + /// For an inequality constraint, returns 0 <= rhs. + /// + public bool IsConstantSatisfiable() { + if (Relation == ConstraintRelation.EQ) { + return rhs.IsZero; + } else { + return rhs.IsNonNegative; + } + } + + /// + /// Returns 0 if "this" and "c" are not equivalent constraints. If "this" and "c" + /// are equivalent constraints, the non-0 return value "m" satisfies "this == m*c". + /// + /// + /// + public Rational IsEquivalent(LinearConstraint/*!*/ c) { + Contract.Requires(c != null); + // "m" is the scale factor. If it is 0, it hasn't been used yet. If it + // is non-0, it will remain that value throughout, and it then says that + // for every dimension "d", "this[d] == m * c[d]". + Rational m = Rational.ZERO; + + ArrayList /*IVariable*/ dd = new ArrayList /*IVariable*/ (); + foreach (IVariable/*!*/ d in this.GetDefinedDimensions()) { + Contract.Assert(d != null); + if (!dd.Contains(d)) { + dd.Add(d); + } + } + foreach (IVariable/*!*/ d in c.GetDefinedDimensions()) { + Contract.Assert(d != null); + if (!dd.Contains(d)) { + dd.Add(d); + } + } + + foreach (IVariable/*!*/ d in dd) { + Contract.Assert(d != null); + Rational a = this[d]; + Rational b = c[d]; + + if (a.IsZero || b.IsZero) { + if (a.IsNonZero || b.IsNonZero) { + return Rational.ZERO; // not equivalent + } + } else if (m.IsZero) { + m = a / b; + } else if (a != m * b) { + return Rational.ZERO; // not equivalent + } + } + + // we expect there to have been some non-zero coefficient, so "m" should have been used by now + System.Diagnostics.Debug.Assert(m.IsNonZero); + + // finally, check the rhs + if (this.rhs == m * c.rhs) { + return m; // equivalent + } else { + return Rational.ZERO; // not equivalent + } + } + + /// + /// Splits an equality constraint into two inequality constraints, the conjunction of + /// which equals the equality constraint. Assumes "this" is a equality constraint. + /// + /// + /// + public void GenerateInequalityConstraints(out LinearConstraint a, out LinearConstraint b) { + System.Diagnostics.Debug.Assert(this.Relation == ConstraintRelation.EQ); + + a = new LinearConstraint(ConstraintRelation.LE); + a.coefficients = (Hashtable)this.coefficients.Clone(); + a.rhs = this.rhs; + + b = new LinearConstraint(ConstraintRelation.LE); + b.coefficients = new Hashtable /*IVariable->Rational*/ (); + foreach (DictionaryEntry entry in this.coefficients) { + b.coefficients[entry.Key] = -(Rational)(cce.NonNull(entry.Value)); + } + b.rhs = -this.rhs; + } + + public void SetCoefficient(IVariable/*!*/ dimension, Rational coefficient) { + Contract.Requires(dimension != null); + coefficients[dimension] = coefficient; + } + + /// + /// Removes dimension "dim" from the constraint. Only dimensions with coefficient 0 can + /// be removed. + /// + /// + public void RemoveDimension(IVariable/*!*/ dim) { + Contract.Requires(dim != null); + object val = coefficients[dim]; + if (val != null) { +#if FIXED_SERIALIZER + Contract.Assert(((Rational)val).IsZero); +#endif + coefficients.Remove(dim); + } + } + + /// + /// The getter returns 0 if the dimension is not present. + /// + public Rational this[IVariable/*!*/ dimension] { + get { + Contract.Requires(dimension != null); + + + object z = coefficients[dimension]; + if (z == null) { + return Rational.ZERO; + } else { + return (Rational)z; + } + } + set { + SetCoefficient(dimension, value); + } + } + + public LinearConstraint Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName) { + Contract.Requires(newName != null); + Contract.Requires(oldName != null); + object /*Rational*/ z = coefficients[oldName]; + if (z == null) { + return this; + } else { + System.Diagnostics.Debug.Assert(z is Rational); + Hashtable /*IVariable->Rational*/ newCoeffs = (Hashtable/*!*/ /*IVariable->Rational*/)cce.NonNull(coefficients.Clone()); + newCoeffs.Remove(oldName); + newCoeffs.Add(newName, z); + + LinearConstraint lc = new LinearConstraint(this.Relation); + lc.coefficients = newCoeffs; + lc.rhs = this.rhs; + return lc; + } + } + + public LinearConstraint Clone() { + LinearConstraint z = new LinearConstraint(Relation); + z.coefficients = (Hashtable /*IVariable->Rational*/)this.coefficients.Clone(); + z.rhs = this.rhs; + return z; + } + + /// + /// Returns a constraint like "this", but with the given relation "r". + /// + /// + public LinearConstraint/*!*/ ChangeRelation(ConstraintRelation rel) { + Contract.Ensures(Contract.Result() != null); + if (Relation == rel) { + return this; + } else { + LinearConstraint z = new LinearConstraint(rel); + z.coefficients = (Hashtable)this.coefficients.Clone(); + z.rhs = this.rhs; + return z; + } + } + + /// + /// Returns a constraint like "this", but, conceptually, with the inequality relation >=. + /// + /// + public LinearConstraint/*!*/ ChangeRelationToAtLeast() { + Contract.Ensures(Contract.Result() != null); + LinearConstraint z = new LinearConstraint(ConstraintRelation.LE); + foreach (DictionaryEntry /*IVariable->Rational*/ entry in this.coefficients) { + z.coefficients.Add(entry.Key, -(Rational)(cce.NonNull(entry.Value))); + } + z.rhs = -this.rhs; + return z; + } + + /// + /// Returns the left-hand side of the constraint evaluated at the point "v". + /// Any coordinate not present in "v" is treated as if it were 0. + /// Stated differently, this routine treats the left-hand side of the constraint + /// as a row vector and "v" as a column vector, and then returns the dot-product + /// of the two. + /// + /// + /// + public Rational EvaluateLhs(FrameElement/*!*/ v) { + Contract.Requires(v != null); + Rational q = Rational.ZERO; + foreach (DictionaryEntry /*IVariable,Rational*/ term in coefficients) { + IVariable dim = (IVariable/*!*/)cce.NonNull(term.Key); + Rational a = (Rational)(cce.NonNull(term.Value)); + Rational x = v[dim]; + q += a * x; + } + return q; + } + + /// + /// Determines whether or not a given vertex or ray saturates the constraint. + /// + /// + /// true if "fe" is a vertex; false if "fe" is a ray + /// + public bool IsSaturatedBy(FrameElement/*!*/ fe, bool vertex) { + Contract.Requires(fe != null); + Rational lhs = EvaluateLhs(fe); + Rational rhs = vertex ? this.rhs : Rational.ZERO; + return lhs == rhs; + } + + /// + /// Changes the current constraint A*X <= B into (A + m*aa)*X <= B + m*bb, + /// where "cc" is the constraint aa*X <= bb. + /// + /// + /// + /// + public void AddMultiple(Rational m, LinearConstraint/*!*/ cc) { + Contract.Requires(cc != null); + foreach (DictionaryEntry /*IVariable->Rational*/ entry in cc.coefficients) { + IVariable dim = (IVariable)entry.Key; + Rational d = m * (Rational)(cce.NonNull(entry.Value)); + if (d.IsNonZero) { + object prev = coefficients[dim]; + if (prev == null) { + coefficients[dim] = d; + } else { + coefficients[dim] = (Rational)prev + d; + } + } + } + rhs += m * cc.rhs; + } + + /// + /// Try to reduce the magnitude of the coefficients used. + /// Has a side effect on the coefficients, but leaves the meaning of the linear constraint + /// unchanged. + /// + public void Normalize() { + // compute the gcd of the numerators and the gcd of the denominators + Rational gcd = rhs; + foreach (Rational r in coefficients.Values) { + gcd = Rational.Gcd(gcd, r); + } + // Change all coefficients, to divide their numerators with gcdNum and to + // divide their denominators with gcdDen. + Hashtable /*IVariable->Rational*/ newCoefficients = new Hashtable /*IVariable->Rational*/ (coefficients.Count); + foreach (DictionaryEntry /*IVarianble->Rational*/ e in coefficients) { + Rational r = (Rational)(cce.NonNull(e.Value)); + if (r.IsNonZero) { + newCoefficients.Add(e.Key, Rational.FromBignums(r.Numerator / gcd.Numerator, r.Denominator / gcd.Denominator)); + } else { + newCoefficients.Add(e.Key, r); + } + } + + coefficients = newCoefficients; + rhs = rhs.IsNonZero ? Rational.FromBignums(rhs.Numerator / gcd.Numerator, rhs.Denominator / gcd.Denominator) : rhs; + } + } + + /// + /// Represents a frame element (vector of dimension/value tuples). Used only + /// internally in class LinearConstraintSystem and its communication with class + /// LinearConstraint. + /// + public class FrameElement { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(terms != null); + } + + Hashtable /*IVariable->Rational*//*!*/ terms = new Hashtable /*IVariable->Rational*/ (); + + /// + /// Constructs an empty FrameElement. To add dimensions, call AddCoordinate after construction. + /// + public FrameElement() { + } + + /// + /// This method is to be thought of as being part of the FrameElement object's construction process. + /// Assumes "dimension" is not already in FrameElement. + /// + /// + /// + public void AddCoordinate(IVariable/*!*/ dimension, Rational value) { + Contract.Requires(dimension != null); + terms.Add(dimension, value); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + string s = null; + foreach (DictionaryEntry item in terms) { + if (s == null) { + s = "("; + } else { + s += ", "; + } + s += String.Format("<{0},{1}>", item.Key, (Rational)(cce.NonNull(item.Value))); + } + if (s == null) { + s = "("; + } + return s + ")"; + } + + public IMutableSet /*IVariable!*//*!*/ GetDefinedDimensions() { + Contract.Ensures(Contract.Result() != null); + HashSet /*IVariable!*//*!*/ dims = new HashSet /*IVariable!*/ (terms.Count); + foreach (IVariable/*!*/ dim in terms.Keys) { + Contract.Assert(dim != null); + dims.Add(dim); + } + System.Diagnostics.Debug.Assert(dims.Count == terms.Count); + return dims; + } + + /// + /// The getter returns the value at the given dimension, or 0 if that dimension is not defined. + /// + public Rational this[IVariable/*!*/ dimension] { + get { + //Contract.Ensures(Contract.Result() != null); + object z = terms[dimension]; + if (z == null) { + return Rational.ZERO; + } else { + return (Rational)z; + } + } + set { + terms[dimension] = value; + } + } + + public FrameElement Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName) { + Contract.Requires(newName != null); + Contract.Requires(oldName != null); + object /*Rational*/ z = terms[oldName]; + if (z == null) { + return this; + } else { + System.Diagnostics.Debug.Assert(z is Rational); + Hashtable /*IVariable->Rational*/ newTerms = (Hashtable/*!*/ /*IVariable->Rational*/)cce.NonNull(terms.Clone()); + newTerms.Remove(oldName); + newTerms.Add(newName, z); + + FrameElement fe = new FrameElement(); + fe.terms = newTerms; + return fe; + } + } + + public FrameElement Clone() { + FrameElement z = new FrameElement(); + z.terms = (Hashtable /*IVariable->Rational*/)this.terms.Clone(); + return z; + } + } +} diff --git a/Source/AIFramework/Polyhedra/LinearConstraintSystem.cs b/Source/AIFramework/Polyhedra/LinearConstraintSystem.cs index 74e36eae..59aadb86 100644 --- a/Source/AIFramework/Polyhedra/LinearConstraintSystem.cs +++ b/Source/AIFramework/Polyhedra/LinearConstraintSystem.cs @@ -1,1756 +1,1756 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework { - using System.Collections; - using System.Collections.Generic; - using System.Diagnostics; - using System; - //using Microsoft.SpecSharp.Collections; - using System.Diagnostics.Contracts; - using Microsoft.Basetypes; - - using IMutableSet = Microsoft.Boogie.GSet; - using ISet = Microsoft.Boogie.GSet; - using HashSet = Microsoft.Boogie.GSet; - - /// - /// Represents a system of linear constraints (constraint/frame representations). - /// - public class LinearConstraintSystem { - // -------------------------------------------------------------------------------------------------------- - // ------------------ Data structure ---------------------------------------------------------------------- - // -------------------------------------------------------------------------------------------------------- - - public /*maybe null*/ ArrayList /*LinearConstraint!*/ Constraints; - /*maybe null*/ - ArrayList /*FrameElement!*/ FrameVertices; - /*maybe null*/ - ArrayList /*FrameElement!*/ FrameRays; - IMutableSet/*IVariable!*//*!*/ FrameDimensions; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(FrameDimensions != null); - } - - /*maybe null*/ - ArrayList /*FrameElement!*/ FrameLines; - // Invariant: Either all of Constraints, FrameVertices, FrameRays, and FrameLines are - // null, or all are non-null. - // Invariant: Any dimension mentioned in Constraints, FrameVertices, FrameRays, or - // FrameLines is mentioned in FrameDimensions. - // The meaning of FrameDimensions is that for any dimension x not in FrameDimensions, - // there is an implicit line along dimension x (that is, ()). - - void CheckInvariant() { - if (Constraints == null) { - System.Diagnostics.Debug.Assert(FrameVertices == null); - System.Diagnostics.Debug.Assert(FrameRays == null); - System.Diagnostics.Debug.Assert(FrameLines == null); - System.Diagnostics.Debug.Assert(FrameDimensions.Count == 0); - } else { - System.Diagnostics.Debug.Assert(FrameVertices != null); - System.Diagnostics.Debug.Assert(FrameRays != null); - System.Diagnostics.Debug.Assert(FrameLines != null); - - foreach (LinearConstraint/*!*/ cc in Constraints) { - Contract.Assert(cc != null); -#if FIXED_DESERIALIZER - Contract.Assert(Contract.ForAll(cc.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); -#endif - Contract.Assert(cc.coefficients.Count != 0); - } - foreach (ArrayList /*FrameElement*//*!*/ FrameComponent in new ArrayList /*FrameElement*/ [] { FrameVertices, FrameRays, FrameLines }) { - Contract.Assert(FrameComponent != null); - foreach (FrameElement fe in FrameComponent) { - if (fe == null) - continue; -#if FIXED_DESERIALIZER - Contract.Assert(Contract.ForAll(fe.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); -#endif - } - } - } - } - - // -------------------------------------------------------------------------------------------------------- - // ------------------ Constructors ------------------------------------------------------------------------ - // -------------------------------------------------------------------------------------------------------- - - /// - /// Creates a LinearConstraintSystem representing the bottom element, that is, representing - /// an unsatisfiable system of constraints. - /// - [NotDelayed] - public LinearConstraintSystem() { - FrameDimensions = new HashSet /*IVariable!*/ (); - //:base(); - CheckInvariant(); - } - - /// - /// Constructs a linear constraint system with constraints "cs". - /// The constructor captures all constraints in "cs". - /// - /// - [NotDelayed] - public LinearConstraintSystem(ArrayList /*LinearConstraint!*//*!*/ cs) { - Contract.Requires(cs != null); -#if BUG_159_HAS_BEEN_FIXED - Contract.Requires(Contract.ForAll(cs) , cc=> cc.coefficients.Count != 0); -#endif - - ArrayList constraints = new ArrayList /*LinearConstraint!*/ (cs.Count); - foreach (LinearConstraint/*!*/ cc in cs) { - Contract.Assert(cc != null); - constraints.Add(cc); - } - Constraints = constraints; - FrameDimensions = new HashSet /*IVariable!*/ (); // to please compiler; this value will be overridden in the call to GenerateFrameConstraints below - //:base(); - - GenerateFrameFromConstraints(); - SimplifyConstraints(); - CheckInvariant(); -#if DEBUG_PRINT - Console.WriteLine("LinearConstraintSystem: constructor produced:"); - Dump(); -#endif - } - - /// - /// Constructs a linear constraint system corresponding to given vertex. This constructor - /// is only used in the test harness--it is not needed for abstract interpretation. - /// - /// - [NotDelayed] - LinearConstraintSystem(FrameElement/*!*/ v) { - Contract.Requires(v != null); - IMutableSet/*!*/ frameDims = v.GetDefinedDimensions(); - Contract.Assert(frameDims != null); - ArrayList /*LinearConstraint!*/ constraints = new ArrayList /*LinearConstraint!*/ (); - foreach (IVariable/*!*/ dim in frameDims) { - Contract.Assert(dim != null); - LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ); - lc.SetCoefficient(dim, Rational.ONE); - lc.rhs = v[dim]; - constraints.Add(lc); - } - FrameDimensions = frameDims; - Constraints = constraints; - - ArrayList /*FrameElement*/ frameVertices = new ArrayList /*FrameElement*/ (); - frameVertices.Add(v); - FrameVertices = frameVertices; - - FrameRays = new ArrayList /*FrameElement*/ (); - FrameLines = new ArrayList /*FrameElement*/ (); - - //:base(); - CheckInvariant(); - } - - void ChangeIntoBottom() { - Constraints = null; - FrameVertices = null; - FrameRays = null; - FrameLines = null; - FrameDimensions.Clear(); // no implicit lines - } - - // -------------------------------------------------------------------------------------------------------- - // ------------------ Public operations and their support routines ---------------------------------------- - // -------------------------------------------------------------------------------------------------------- - - public bool IsBottom() { - return Constraints == null; - } - - public bool IsTop() { - return Constraints != null && Constraints.Count == 0; - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - if (Constraints == null) { - return ""; - } else if (Constraints.Count == 0) { - return ""; - } else { - string z = null; - foreach (LinearConstraint/*!*/ lc in Constraints) { - Contract.Assert(lc != null); - string s = lc.ToString(); - if (z == null) { - z = s; - } else { - z += " AND " + s; - } - } - Contract.Assert(z != null); - return z; - } - } - - - public ICollection/*!*/ FreeVariables() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - Contract.Ensures(Contract.Result>().IsReadOnly); - List list = new List(); - foreach (IVariable/*!*/ v in FrameDimensions) { - Contract.Assert(v != null); - list.Add(v); - } - return cce.NonNull(list.AsReadOnly()); - } - - /// - /// Note: This method requires that all dimensions are of type Variable, something that's - /// not required elsewhere in this class. - /// - /// - public IExpr/*!*/ ConvertToExpression(ILinearExprFactory/*!*/ factory) { - Contract.Requires(factory != null); - Contract.Ensures(Contract.Result() != null); - if (this.Constraints == null) { - return factory.False; - } - if (this.Constraints.Count == 0) { - return factory.True; - } - - IExpr result = null; - foreach (LinearConstraint/*!*/ lc in Constraints) { - Contract.Assert(lc != null); - IExpr conjunct = lc.ConvertToExpression(factory); - result = (result == null) ? conjunct : (IExpr)factory.And(conjunct, result); - } - Contract.Assert(result != null); - return result; - } - - - /* IsSubset(): determines if 'lcs' is a subset of 'this' - * -- See Cousot/Halbwachs 1978, section - */ - public bool IsSubset(LinearConstraintSystem/*!*/ lcs) { - Contract.Requires(lcs != null); - if (lcs.IsBottom()) { - return true; - } else if (this.IsBottom()) { - return false; -#if DEBUG -#else - } else if (this.IsTop()) { // optimization -- this case not needed for correctness - return true; - } else if (lcs.IsTop()) { // optimization -- this case not needed for correctness - return false; -#endif - } else { - // phase 0: check if frame dimensions are a superset of the constraint dimensions - ISet /*IVariable!*//*!*/ frameDims = lcs.GetDefinedDimensions(); - Contract.Assert(frameDims != null); -#if DEBUG_PRINT - Console.WriteLine("DEBUG: IsSubset:"); - Console.WriteLine(" --- this:"); - this.Dump(); - Console.WriteLine(" --- lcs:"); - lcs.Dump(); - Console.WriteLine(" ---"); -#endif - foreach (LinearConstraint/*!*/ cc in cce.NonNull(this.Constraints)) { - Contract.Assert(cc != null); -#if DEBUG_PRINT - Console.WriteLine(" cc: {0}", cc); - Console.WriteLine(" cc.GetDefinedDimensions(): {0}", cc.GetDefinedDimensions()); -#endif - - if (!Contract.ForAll(cc.GetDefinedDimensionsGeneric(), var => frameDims.Contains(var))) { -#if DEBUG_PRINT - Console.WriteLine(" ---> phase 0 subset violated, return false from IsSubset"); -#endif - return false; - } - } - } - - // phase 1: check frame vertices against each constraint... - foreach (FrameElement/*!*/ v in cce.NonNull(lcs.FrameVertices)) { - Contract.Assert(v != null); - foreach (LinearConstraint/*!*/ cc in this.Constraints) { - Contract.Assert(cc != null); - Rational q = cc.EvaluateLhs(v); - if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { - if (!(q <= cc.rhs)) { -#if DEBUG_PRINT - Console.WriteLine(" ---> phase 1a subset violated, return false from IsSubset"); -#endif - return false; - } - } else { - if (!(q == cc.rhs)) { -#if DEBUG_PRINT - Console.WriteLine(" ---> phase 1b subset violated, return false from IsSubset"); -#endif - return false; - } - } - } - } - - // phase 2: check frame rays against each constraint... - // To check if a ray "r" falls within a constraint "cc", we add the vector "r" to - // any point "p" on the side of the half-space or plane described by constraint, and - // then check if the resulting point satisfies the constraint. That is, we check (for - // an inequality constraint with coefficients a1,a2,...,an and right-hand side - // constant C): - // a1*(r1+p1) + a2*(r2+p2) + ... + an*(rn+pn) <= C - // Equivalently: - // a1*r1 + a2*r2 + ... + an*rn + a1*p1 + a2*p2 + ... + an*pn <= C - // To find a point "p", we can pick out a coordinate, call it 1, with a non-zero - // coefficient in the constraint, and then choose "p" as the point that has the - // value C/a1 in coordinate 1 and has 0 in all other coordinates. We then check: - // a1*r1 + a2*r2 + ... + an*rn + a1*(C/a1) + a2*0 + ... + an*0 <= C - // which simplifies to: - // a1*r1 + a2*r2 + ... + an*rn + C <= C - // which in turn simplifies to: - // a1*r1 + a2*r2 + ... + an*rn <= 0 - // If the constraint is an equality constraint, we simply replace "<=" with "==" - // above. - foreach (FrameElement/*!*/ r in cce.NonNull(lcs.FrameRays)) { - Contract.Assert(r != null); - System.Diagnostics.Debug.Assert(r != null, "encountered a null ray..."); - foreach (LinearConstraint/*!*/ cc in this.Constraints) { - Contract.Assert(cc != null); - System.Diagnostics.Debug.Assert(cc != null, "encountered an null constraint..."); - Rational q = cc.EvaluateLhs(r); - if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { - if (q.IsPositive) { -#if DEBUG_PRINT - Console.WriteLine(" ---> phase 2a subset violated, return false from IsSubset"); -#endif - return false; - } - } else { - if (q.IsNonZero) { -#if DEBUG_PRINT - Console.WriteLine(" ---> phase 2b subset violated, return false from IsSubset"); -#endif - return false; - } - } - } - } - - // phase 3: check frame lines against each constraint... - // To check if a line "L" falls within a constraint "cc", we check if both the - // vector "L" and "-L", interpreted as rays, fall within the constraint. From - // the discussion above, this means we check the following two properties: - // a1*L1 + a2*L2 + ... + an*Ln <= 0 (*) - // a1*(-L1) + a2*(-L2) + ... + an*(-Ln) <= 0 - // The second of these lines can be rewritten as: - // - a1*L1 - a2*L2 - ... - an*Ln <= 0 - // which is equivalent to: - // -1 * (a1*L1 + a2*L2 + ... + an*Ln) <= 0 - // Multiplying both sides by -1 and flipping the direction of the inequality, - // we have: - // a1*L1 + a2*L2 + ... + an*Ln >= 0 (**) - // Putting (*) and (**) together, we conclude that we need to check: - // a1*L1 + a2*L2 + ... + an*Ln == 0 - // If the constraint is an equality constraint, we end up with the same equation. - foreach (FrameElement/*!*/ line in cce.NonNull(lcs.FrameLines)) { - Contract.Assert(line != null); - System.Diagnostics.Debug.Assert(line != null, "encountered a null line..."); - foreach (LinearConstraint/*!*/ cc in this.Constraints) { - Contract.Assert(cc != null); - System.Diagnostics.Debug.Assert(cc != null, "encountered an null constraint..."); - Rational q = cc.EvaluateLhs(line); - if (q.IsNonZero) { -#if DEBUG_PRINT - Console.WriteLine(" ---> phase 3 subset violated, return false from IsSubset"); -#endif - return false; - } - } - } - -#if DEBUG_PRINT - Console.WriteLine(" ---> IsSubset returns true"); -#endif - return true; - } - - public LinearConstraintSystem/*!*/ Meet(LinearConstraintSystem/*!*/ lcs) { - Contract.Requires(lcs != null); - Contract.Requires((this.Constraints != null)); - Contract.Requires((lcs.Constraints != null)); - Contract.Ensures(Contract.Result() != null); - ArrayList /*LinearConstraint*/ clist = new ArrayList(this.Constraints.Count + lcs.Constraints.Count); - clist.AddRange(this.Constraints); - clist.AddRange(lcs.Constraints); - return new LinearConstraintSystem(clist); - } - -#if DEBUG_PRINT - public LinearConstraintSystem Join(LinearConstraintSystem lcs) - { - Console.WriteLine("==================================================================================="); - Console.WriteLine("DEBUG: Join"); - Console.WriteLine("Join: this="); - Dump(); - Console.WriteLine("Join: lcs="); - lcs.Dump(); - LinearConstraintSystem z = JoinX(lcs); - Console.WriteLine("----------Join------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); - Console.WriteLine("Join: result="); - z.Dump(); - Console.WriteLine("==================================================================================="); - return z; - } -#endif - - /// - /// The join is computed as described in section 4.4 in Cousot and Halbwachs. - /// - /// - /// -#if DEBUG_PRINT - public LinearConstraintSystem JoinX(LinearConstraintSystem lcs) { -#else - public LinearConstraintSystem/*!*/ Join(LinearConstraintSystem/*!*/ lcs) { - Contract.Requires(lcs != null); - Contract.Ensures(Contract.Result() != null); -#endif - - if (this.IsBottom()) { - return cce.NonNull(lcs.Clone()); - } else if (lcs.IsBottom()) { - return cce.NonNull(this.Clone()); - } else if (this.IsTop() || lcs.IsTop()) { - return new LinearConstraintSystem(new ArrayList /*LinearConstraint*/ ()); - } else { - LinearConstraintSystem/*!*/ z; - // Start from the "larger" of the two frames (this is just a heuristic measure intended - // to save work). - Contract.Assume(this.FrameVertices != null); - Contract.Assume(this.FrameRays != null); - Contract.Assume(this.FrameLines != null); - Contract.Assume(lcs.FrameVertices != null); - Contract.Assume(lcs.FrameRays != null); - Contract.Assume(lcs.FrameLines != null); - if (this.FrameVertices.Count + this.FrameRays.Count + this.FrameLines.Count - this.FrameDimensions.Count < - lcs.FrameVertices.Count + lcs.FrameRays.Count + lcs.FrameLines.Count - lcs.FrameDimensions.Count) { - z = cce.NonNull(lcs.Clone()); - lcs = this; - } else { - z = cce.NonNull(this.Clone()); - } -#if DEBUG_PRINT - Console.WriteLine("DEBUG: LinearConstraintSystem.Join ---------------"); - Console.WriteLine("z:"); - z.Dump(); - Console.WriteLine("lcs:"); - lcs.Dump(); -#endif - - // Start by explicating the implicit lines of z for the dimensions dims(lcs)-dims(z). - foreach (IVariable/*!*/ dim in lcs.FrameDimensions) { - Contract.Assert(dim != null); - if (!z.FrameDimensions.Contains(dim)) { - z.FrameDimensions.Add(dim); - FrameElement line = new FrameElement(); - line.AddCoordinate(dim, Rational.ONE); - // Note: AddLine is not called (because the line already exists in z--it's just that - // it was represented implicitly). Instead, just tack the explicit representation onto - // FrameLines. - Contract.Assume(z.FrameLines != null); - z.FrameLines.Add(line); -#if DEBUG_PRINT - Console.WriteLine("Join: After explicating line: {0}", line); - z.Dump(); -#endif - } - } - - // Now, the vertices, rays, and lines can be added. - foreach (FrameElement/*!*/ v in lcs.FrameVertices) { - Contract.Assert(v != null); - z.AddVertex(v); -#if DEBUG_PRINT - Console.WriteLine("Join: After adding vertex: {0}", v); - z.Dump(); -#endif - } - foreach (FrameElement/*!*/ r in lcs.FrameRays) { - Contract.Assert(r != null); - z.AddRay(r); -#if DEBUG_PRINT - Console.WriteLine("Join: After adding ray: {0}", r); - z.Dump(); -#endif - } - foreach (FrameElement/*!*/ l in lcs.FrameLines) { - Contract.Assert(l != null); - z.AddLine(l); -#if DEBUG_PRINT - Console.WriteLine("Join: After adding line: {0}", l); - z.Dump(); -#endif - } - // also add to z the implicit lines of lcs - foreach (IVariable/*!*/ dim in z.FrameDimensions) { - Contract.Assert(dim != null); - if (!lcs.FrameDimensions.Contains(dim)) { - // "dim" is a dimension that's explicit in "z" but implicit in "lcs" - FrameElement line = new FrameElement(); - line.AddCoordinate(dim, Rational.ONE); - z.AddLine(line); -#if DEBUG_PRINT - Console.WriteLine("Join: After adding lcs's implicit line: {0}", line); - z.Dump(); -#endif - } - } - - z.SimplifyFrame(); - z.SimplifyConstraints(); - z.CheckInvariant(); -#if DEBUG_PRINT - Console.WriteLine("Join: Returning z:"); - z.Dump(); - Console.WriteLine("----------------------------------------"); -#endif - return z; - } - } - -#if DEBUG_PRINT - public LinearConstraintSystem Widen(LinearConstraintSystem lcs) - { - Console.WriteLine("==================================================================================="); - Console.WriteLine("DEBUG: Widen"); - Console.WriteLine("Widen: this="); - Dump(); - Console.WriteLine("Widen: lcs="); - lcs.Dump(); - LinearConstraintSystem z = WidenX(lcs); - Console.WriteLine("----------Widen------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); - Console.WriteLine("Widen: result="); - z.Dump(); - Console.WriteLine("==================================================================================="); - return z; - } -#endif - -#if DEBUG_PRINT - public LinearConstraintSystem WidenX(LinearConstraintSystem lcs){ -#else - public LinearConstraintSystem/*!*/ Widen(LinearConstraintSystem/*!*/ lcs) { - Contract.Requires(lcs != null); - Contract.Ensures(Contract.Result() != null); -#endif - if (this.IsBottom()) { - return cce.NonNull(lcs.Clone()); - } else if (lcs.IsBottom()) { - return cce.NonNull(this.Clone()); - } else if (this.IsTop() || lcs.IsTop()) { - return new LinearConstraintSystem(new ArrayList /*LinearConstraint*/ ()); - } - - // create new LCS, we will add only verified constraints to this... - ArrayList /*LinearConstraint*/ newConstraints = new ArrayList /*LinearConstraint*/ (); - Contract.Assume(this.Constraints != null); - foreach (LinearConstraint/*!*/ ccX in this.Constraints) { - Contract.Assert(ccX != null); - LinearConstraint cc = ccX; -#if DEBUG_PRINT - Console.WriteLine("Widen checking: Starting to check constraint: {0}", cc); -#endif - if (cc.IsConstant()) { - // (Can this ever occur in the stable state of a LinearConstraintSystem? --KRML) - // constraint is unaffected by the frame components -#if DEBUG_PRINT - Console.WriteLine("Widen checking: --Adding it!"); -#endif - newConstraints.Add(cc); - continue; - } - - // PHASE I: verify constraints against all frame vertices... - - foreach (FrameElement/*!*/ vertex in cce.NonNull(lcs.FrameVertices)) { - Contract.Assert(vertex != null); - Rational lhs = cc.EvaluateLhs(vertex); - if (lhs > cc.rhs) { - // the vertex does not satisfy the inequality <= - if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { -#if DEBUG_PRINT - Console.WriteLine("Widen checking: throwing out because of vertex: {0}", vertex); -#endif - goto CHECK_NEXT_CONSTRAINT; - } else { - // ... but it does satisfy the inequality >= -#if DEBUG_PRINT - Console.WriteLine("Widen checking: throwing out <= because of vertex: {0}", vertex); -#endif - cc = cc.ChangeRelationToAtLeast(); -#if DEBUG_PRINT - Console.WriteLine("Widen checking: left with constraint: {0}", cc); -#endif - } - } else if (cc.Relation == LinearConstraint.ConstraintRelation.EQ && lhs < cc.rhs) { - // the vertex does not satisfy the inequality >=, and the constraint is an equality constraint -#if DEBUG_PRINT - Console.WriteLine("Widen checking: throwing out >= because of vertex: {0}", vertex); -#endif - cc = cc.ChangeRelation(LinearConstraint.ConstraintRelation.LE); -#if DEBUG_PRINT - Console.WriteLine("Widen checking: left with contraint: {0}", cc); -#endif - } - } - - // PHASE II: verify constraints against all frame rays... - - foreach (FrameElement/*!*/ ray in cce.NonNull(lcs.FrameRays)) { - Contract.Assert(ray != null); - // The following assumes the constraint to have some dimension with a non-zero coefficient - Rational lhs = cc.EvaluateLhs(ray); - if (lhs.IsPositive) { - // the ray does not satisfy the inequality <= - if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { -#if DEBUG_PRINT - Console.WriteLine("Widen checking: throwing out because of ray: {0}", ray); -#endif - goto CHECK_NEXT_CONSTRAINT; - } else { - // ... but it does satisfy the inequality >= -#if DEBUG_PRINT - Console.WriteLine("Widen checking: throwing out <= because of ray: {0}", ray); -#endif - cc = cc.ChangeRelationToAtLeast(); -#if DEBUG_PRINT - Console.WriteLine("Widen checking: left with contraint: {0}", cc); -#endif - } - } else if (cc.Relation == LinearConstraint.ConstraintRelation.EQ && lhs.IsNegative) { - // the ray does not satisfy the inequality >=, and the constraint is an equality constraint -#if DEBUG_PRINT - Console.WriteLine("Widen checking: throwing out >= because of ray: {0}", ray); -#endif - cc = cc.ChangeRelation(LinearConstraint.ConstraintRelation.LE); -#if DEBUG_PRINT - Console.WriteLine("Widen checking: left with constraint: {0}", cc); -#endif - } - } - - // PHASE III: verify constraints against all frame lines... - - foreach (FrameElement/*!*/ line in cce.NonNull(lcs.FrameLines)) { - Contract.Assert(line != null); - // The following assumes the constraint to have some dimension with a non-zero coefficient - Rational lhs = cc.EvaluateLhs(line); - if (!lhs.IsZero) { - // The line satisfies neither the inequality <= nor the equality == -#if DEBUG_PRINT - Console.WriteLine("Widen checking: throwing out because of line: {0}", line); -#endif - goto CHECK_NEXT_CONSTRAINT; - } - } - - // constraint has been verified, so add to new constraint system -#if DEBUG_PRINT - Console.WriteLine("Widen checking: --Adding it!"); -#endif - newConstraints.Add(cc); - - CHECK_NEXT_CONSTRAINT: { - } -#if DEBUG_PRINT - Console.WriteLine("Widen checking: done with that constraint"); -#endif - } - - return new LinearConstraintSystem(newConstraints); - } - -#if DEBUG_PRINT - public LinearConstraintSystem Project(IVariable/*!*/ dim){ -Contract.Requires(dim != null); - Console.WriteLine("==================================================================================="); - Console.WriteLine("DEBUG: Project(dim={0})", dim); - Console.WriteLine("Project: this="); - Dump(); - LinearConstraintSystem z = ProjectX(dim); - Console.WriteLine("----------Project------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); - Console.WriteLine("Project: result="); - z.Dump(); - Console.WriteLine("==================================================================================="); - return z; - } -#endif - -#if DEBUG_PRINT - public LinearConstraintSystem ProjectX(IVariable/*!*/ dim){Contract.Requires(dim != null);Contract.Requires(this.Constraints != null); -#else - public LinearConstraintSystem/*!*/ Project(IVariable/*!*/ dim) { - Contract.Requires(dim != null); - Contract.Requires(this.Constraints != null); - Contract.Ensures(Contract.Result() != null); -#endif - - - ArrayList /*LinearConstraint!*//*!*/ cc = Project(dim, Constraints); - Contract.Assert(cc != null); - return new LinearConstraintSystem(cc); - } - -#if DEBUG_PRINT - public LinearConstraintSystem Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName){ -Contract.Requires(newName != null); -Contract.Requires(oldName != null); - Console.WriteLine("==================================================================================="); - Console.WriteLine("DEBUG: Rename(oldName={0}, newName={1})", oldName, newName); - Console.WriteLine("Rename: this="); - Dump(); - LinearConstraintSystem z = RenameX(oldName, newName); - Console.WriteLine("----------Rename------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); - Console.WriteLine("Rename: result="); - z.Dump(); - Console.WriteLine("==================================================================================="); - return z; - } -#endif - -#if DEBUG_PRINT - public LinearConstraintSystem RenameX(IVariable/*!*/ oldName, IVariable/*!*/ newName){Contract.Requires(oldName != null);Contract.Requires(newName != null); -#else - public LinearConstraintSystem/*!*/ Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName) { - Contract.Requires(oldName != null); - Contract.Requires(newName != null); - Contract.Ensures(Contract.Result() != null); -#endif - if (this.Constraints == null) { - System.Diagnostics.Debug.Assert(this.FrameVertices == null); - System.Diagnostics.Debug.Assert(this.FrameRays == null); - System.Diagnostics.Debug.Assert(this.FrameLines == null); - return this; - } - IMutableSet /*IVariable!*//*!*/ dims = this.FrameDimensions; - Contract.Assert(dims != null); - if (!dims.Contains(oldName)) { - return this; - } - - LinearConstraintSystem z = new LinearConstraintSystem(); - z.FrameDimensions = cce.NonNull((HashSet/*!*/ /*IVariable!*/)dims.Clone()); - z.FrameDimensions.Remove(oldName); - z.FrameDimensions.Add(newName); - - z.Constraints = new ArrayList /*LinearConstraint!*/ (this.Constraints.Count); - foreach (LinearConstraint/*!*/ lc in cce.NonNull(this.Constraints)) { - Contract.Assert(lc != null); - z.Constraints.Add(lc.Rename(oldName, newName)); - } - z.FrameVertices = RenameInFE(cce.NonNull(this.FrameVertices), oldName, newName); - z.FrameRays = RenameInFE(cce.NonNull(this.FrameRays), oldName, newName); - z.FrameLines = RenameInFE(cce.NonNull(this.FrameLines), oldName, newName); - return z; - } - - static ArrayList /*FrameElement*/ RenameInFE(ArrayList/*!*/ /*FrameElement*/ list, IVariable/*!*/ oldName, IVariable/*!*/ newName) { - Contract.Requires(list != null); - Contract.Requires(newName != null); - Contract.Requires(oldName != null); - ArrayList/*FrameElement!*//*!*/ z = new ArrayList/*FrameElement!*/ (list.Count); - Contract.Assert(z != null); - foreach (FrameElement/*!*/ fe in list) { - Contract.Assert(fe != null); - z.Add(fe.Rename(oldName, newName)); - } - System.Diagnostics.Debug.Assert(z.Count == list.Count); - return z; - } - - // -------------------------------------------------------------------------------------------------------- - // ------------------ support routines -------------------------------------------------------------------- - // -------------------------------------------------------------------------------------------------------- - - /// - /// Returns a set of constraints that is the given set of constraints with dimension "dim" - /// projected out. See Cousot and Halbwachs, section 3.3.1.1. - /// - /// - /// - /// - static ArrayList /*LinearConstraint!*//*!*/ Project(IVariable/*!*/ dim, ArrayList /*LinearConstraint!*//*!*/ constraints) { - Contract.Requires(constraints != null); - Contract.Requires(dim != null); - Contract.Ensures(Contract.Result() != null); - // Sort the inequality constaints into ones where dimension "dim" is 0, negative, and - // positive, respectively. Put equality constraints with a non-0 "dim" into "eq". - ArrayList /*LinearConstraint!*//*!*/ final = new ArrayList /*LinearConstraint!*/ (); - ArrayList /*LinearConstraint!*//*!*/ negative = new ArrayList /*LinearConstraint!*/ (); - ArrayList /*LinearConstraint!*//*!*/ positive = new ArrayList /*LinearConstraint!*/ (); - ArrayList /*LinearConstraint!*//*!*/ eq = new ArrayList /*LinearConstraint!*/ (); - foreach (LinearConstraint/*!*/ cc in constraints) { - Contract.Assert(cc != null); - Rational coeff = cc[dim]; - if (coeff.IsZero) { - LinearConstraint lc = cce.NonNull(cc.Clone()); - if (!lc.IsConstant()) { - lc.RemoveDimension(dim); - final.Add(lc); - } - } else if (cc.Relation == LinearConstraint.ConstraintRelation.EQ) { - eq.Add(cc); - } else if (coeff.IsNegative) { - negative.Add(cc); - } else { - System.Diagnostics.Debug.Assert(coeff.IsPositive); - positive.Add(cc); - } - } - - if (eq.Count != 0) { - LinearConstraint eqConstraint = (LinearConstraint/*!*/)cce.NonNull(eq[eq.Count - 1]); - eq.RemoveAt(eq.Count - 1); - Rational eqC = -eqConstraint[dim]; - - foreach (ArrayList /*LinearConstraint!*/ list in new ArrayList[] { eq, negative, positive }) { - Contract.Assert(list != null); - foreach (LinearConstraint/*!*/ lcX in list) { - Contract.Assert(lcX != null); - LinearConstraint lc = cce.NonNull(lcX.Clone()); - lc.AddMultiple(lc[dim] / eqC, eqConstraint); - System.Diagnostics.Debug.Assert(lc[dim].IsZero); - if (!lc.IsConstant()) { - lc.RemoveDimension(dim); - final.Add(lc); - } else { - System.Diagnostics.Debug.Assert(lc.IsConstantSatisfiable()); - } - } - } - } else { - // Consider all pairs of constraints with (negative,positive) coefficients of "dim". - foreach (LinearConstraint/*!*/ cn in negative) { - Contract.Assert(cn != null); - Rational dn = -cn[dim]; - System.Diagnostics.Debug.Assert(dn.IsNonNegative); - foreach (LinearConstraint/*!*/ cp in positive) { - Contract.Assert(cp != null); - Rational dp = cp[dim]; - - LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); - lc.AddMultiple(dn, cp); - lc.AddMultiple(dp, cn); - System.Diagnostics.Debug.Assert(lc[dim].IsZero); - if (!lc.IsConstant()) { - lc.RemoveDimension(dim); - final.Add(lc); - } else { - System.Diagnostics.Debug.Assert(lc.IsConstantSatisfiable()); - } - } - } - } - - return final; - } - - /// - /// Initializes FrameVertices, FrameRays, FrameLines, and FrameDimensions, see - /// Cousot and Halbwachs, section 3.4. Any previous values of these fields are - /// ignored and overwritten. - /// - /// If the set of Constraints is unsatisfiable, then "this" is changed into Bottom. - /// - void GenerateFrameFromConstraints() { - if (Constraints == null) { - FrameVertices = null; - FrameRays = null; - FrameLines = null; - FrameDimensions = new HashSet /*IVariable!*/ (); - return; - } - - // Step 1 (see Cousot and Halbwachs, section 3.4.3): create a Simplex Tableau. -#if DEBUG_PRINT - Console.WriteLine("DEBUG: --- GenerateFrameFromConstraint ---"); - Console.WriteLine("Constraints:"); - foreach (LinearConstraint cc in Constraints) - { - Console.WriteLine(" {0}", cc); - } -#endif - SimplexTableau tableau = new SimplexTableau(Constraints); -#if DEBUG_PRINT - Console.WriteLine("Initial tableau:"); - tableau.Dump(); -#endif - FrameDimensions = tableau.GetDimensions(); -#if DEBUG_PRINT - Console.WriteLine("Dimensions:"); - foreach (object dim in FrameDimensions) - { - Console.Write(" {0}", dim); - } - Console.WriteLine(); -#endif - - // Step 3 and 2: Put as many initial variables as possible into basis, then check if - // we reached a feasible basis - tableau.AddInitialVarsToBasis(); -#if DEBUG_PRINT - Console.WriteLine("Tableau after Step 3:"); - tableau.Dump(); -#endif - if (!tableau.IsFeasibleBasis) { - // The polyhedron is empty (according to Cousot and Halbwachs) - ChangeIntoBottom(); - return; - } - - FrameVertices = new ArrayList /*FrameElement*/ (); - FrameRays = new ArrayList /*FrameElement*/ (); - FrameLines = new ArrayList /*FrameElement*/ (); - if (FrameDimensions.Count == 0) { - // top element - return; - } - - if (tableau.AllInitialVarsInBasis) { - // All initial variables are in basis; there are no lines. -#if DEBUG_PRINT - Console.WriteLine("Tableau after Steps 2 and 3 (all initial variables in basis):"); - tableau.Dump(); -#endif - } else { - // There are lines -#if DEBUG_PRINT - Console.WriteLine("Tableau after Steps 2 and 3 (NOT all initial variables in basis--there are lines):"); - tableau.Dump(); -#endif - // Step 4.2: Pick out the lines, then produce the tableau for a new polyhedron without those lines. - ArrayList /*LinearConstraint*/ moreConstraints = cce.NonNull((ArrayList/*!*/ /*LinearConstraint*/)Constraints.Clone()); - tableau.ProduceLines(FrameLines, moreConstraints); - tableau = new SimplexTableau(moreConstraints); -#if DEBUG_PRINT - Console.WriteLine("Lines produced:"); - foreach (FrameElement line in FrameLines) - { - Console.WriteLine(" {0}", line); - } - Console.WriteLine("The new list of constraints is:"); - foreach (LinearConstraint c in moreConstraints) - { - Console.WriteLine(" {0}", c); - } - Console.WriteLine("Tableau after producing lines in Step 4.2:"); - tableau.Dump(); -#endif - - // Repeat step 3 for the new tableau. - // Since the new tableau contains no lines, the following call should cause all initial - // variables to be in basis (see step 4.2 in section 3.4.3 of Cousot and Halbwachs). - tableau.AddInitialVarsToBasis(); - System.Diagnostics.Debug.Assert(tableau.AllInitialVarsInBasis); - System.Diagnostics.Debug.Assert(tableau.IsFeasibleBasis); // the new tableau represents a set of feasible constraints, so this basis should be found to be feasible -#if DEBUG_PRINT - Console.WriteLine("Tableau after all initial variables have been moved into basis:"); - tableau.Dump(); -#endif - } - - // Step 4.1: One vertex has been found. Find all others, too. - tableau.TraverseVertices(FrameVertices, FrameRays); -#if DEBUG_PRINT - Console.WriteLine("Tableau after vertex traversal:"); - tableau.Dump(); -#endif - } - - class LambdaDimension : IVariable { - readonly int id; - static int count = 0; - - /// - /// Return the name of the variable - /// - public string Name { - get { - Contract.Ensures(Contract.Result() != null); - - return this.ToString(); - } - } - - public LambdaDimension() { - id = count; - count++; - } - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return "lambda" + id; - } - [Pure] - public object DoVisit(ExprVisitor/*!*/ visitor) { - //Contract.Requires(visitor != null); - return visitor.VisitVariable(this); - } - } - - /// - /// Adds a vertex to the frame of "this" and updates Constraints accordingly, see - /// Cousot and Halbwachs, section 3.3.1.1. However, this method does not simplify - /// Constraints after the operation; that remains the caller's responsibility (which - /// gives the caller the opportunity to make multiple calls to AddVertex, AddRay, - /// and AddLine before calling SimplifyConstraints). - /// Assumes Constraints (and the frame fields) to be non-null. - /// - /// - void AddVertex(FrameElement/*!*/ vertex) { - Contract.Requires(vertex != null); - Contract.Requires(this.FrameVertices != null); -#if DEBUG_PRINT - Console.WriteLine("DEBUG: AddVertex called on {0}", vertex); - Console.WriteLine(" Initial constraints:"); - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } -#endif - - FrameVertices.Add(vertex.Clone()); -#if FIXED_DESERIALIZER - Contract.Assert(Contract.ForAll(vertex.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); -#endif - - // We use a new temporary dimension. - IVariable/*!*/ lambda = new LambdaDimension(); - - // We change the constraints A*X <= B into - // A*X + (A*vector - B)*lambda <= A*vector. - // That means that each row k in A (which corresponds to one LinearConstraint - // in Constraints) is changed by adding - // (A*vector - B)[k] * lambda - // to row k and changing the right-hand side of row k to - // (A*vector)[k] - // Note: - // (A*vector - B)[k] - // = { vector subtraction is pointwise } - // (A*vector)[k] - B[k] - // = { A*vector is a row vector whose every row i is the dot-product of - // row i of A with the column vector "vector" } - // A[k]*vector - B[k] - foreach (LinearConstraint/*!*/ cc in cce.NonNull(Constraints)) { - Contract.Assert(cc != null); - Rational d = cc.EvaluateLhs(vertex); - cc.SetCoefficient(lambda, d - cc.rhs); - cc.rhs = d; - } - - // We also add the constraints that lambda lies between 0 ... - LinearConstraint la = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); - la.SetCoefficient(lambda, Rational.MINUS_ONE); - la.rhs = Rational.ZERO; - Constraints.Add(la); - // ... and 1. - la = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); - la.SetCoefficient(lambda, Rational.ONE); - la.rhs = Rational.ONE; - Constraints.Add(la); -#if DEBUG_PRINT - Console.WriteLine(" Constraints after addition:"); - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } -#endif - - // Finally, project out the dummy dimension. - Constraints = Project(lambda, Constraints); - -#if DEBUG_PRINT - Console.WriteLine(" Resulting constraints:"); - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } -#endif - } - - /// - /// Adds a ray to the frame of "this" and updates Constraints accordingly, see - /// Cousot and Halbwachs, section 3.3.1.1. However, this method does not simplify - /// Constraints after the operation; that remains the caller's responsibility (which - /// gives the caller the opportunity to make multiple calls to AddVertex, AddRay, - /// and AddLine before calling SimplifyConstraints). - /// Assumes Constraints (and the frame fields) to be non-null. - /// - /// - void AddRay(FrameElement/*!*/ ray) { - Contract.Requires(ray != null); - Contract.Requires(this.FrameRays != null); -#if DEBUG_PRINT - Console.WriteLine("DEBUG: AddRay called on {0}", ray); - Console.WriteLine(" Initial constraints:"); - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } -#endif - - FrameRays.Add(ray.Clone()); -#if FIXED_DESERIALIZER - Contract.Assert(Contract.ForAll(ray.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); -#endif - - // We use a new temporary dimension. - IVariable/*!*/ lambda = new LambdaDimension(); - - // We change the constraints A*X <= B into - // A*X - (A*ray)*lambda <= B. - // That means that each row k in A (which corresponds to one LinearConstraint - // in Constraints) is changed by subtracting - // (A*ray)[k] * lambda - // from row k. - // Note: - // (A*ray)[k] - // = { A*ray is a row vector whose every row i is the dot-product of - // row i of A with the column vector "ray" } - // A[k]*ray - foreach (LinearConstraint/*!*/ cc in cce.NonNull(Constraints)) { - Contract.Assert(cc != null); - Rational d = cc.EvaluateLhs(ray); - cc.SetCoefficient(lambda, -d); - } - - // We also add the constraints that lambda is at least 0. - LinearConstraint la = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); - la.SetCoefficient(lambda, Rational.MINUS_ONE); - la.rhs = Rational.ZERO; - Constraints.Add(la); -#if DEBUG_PRINT - Console.WriteLine(" Constraints after addition:"); - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } -#endif - - // Finally, project out the dummy dimension. - Constraints = Project(lambda, Constraints); - -#if DEBUG_PRINT - Console.WriteLine(" Resulting constraints:"); - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } -#endif - } - - /// - /// Adds a line to the frame of "this" and updates Constraints accordingly, see - /// Cousot and Halbwachs, section 3.3.1.1. However, this method does not simplify - /// Constraints after the operation; that remains the caller's responsibility (which - /// gives the caller the opportunity to make multiple calls to AddVertex, AddRay, - /// and AddLine before calling SimplifyConstraints). - /// Assumes Constraints (and the frame fields) to be non-null. - /// - /// - void AddLine(FrameElement/*!*/ line) { - Contract.Requires(line != null); - Contract.Requires(this.FrameLines != null); - // Note: The code for AddLine is identical to that of AddRay, except the AddLine - // does not introduce the constraint 0 <= lambda. (One could imagine sharing the - // code between AddRay and AddLine.) -#if DEBUG_PRINT - Console.WriteLine("DEBUG: AddLine called on {0}", line); - Console.WriteLine(" Initial constraints:"); - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } -#endif - - FrameLines.Add(line.Clone()); -#if FIXED_DESERIALIZER - Contract.Assert(Contract.ForAll(line.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); -#endif - - // We use a new temporary dimension. - IVariable/*!*/ lambda = new LambdaDimension(); - - // We change the constraints A*X <= B into - // A*X - (A*line)*lambda <= B. - // That means that each row k in A (which corresponds to one LinearConstraint - // in Constraints) is changed by subtracting - // (A*line)[k] * lambda - // from row k. - // Note: - // (A*line)[k] - // = { A*line is a row vector whose every row i is the dot-product of - // row i of A with the column vector "line" } - // A[k]*line - foreach (LinearConstraint/*!*/ cc in cce.NonNull(Constraints)) { - Contract.Assert(cc != null); - Rational d = cc.EvaluateLhs(line); - cc.SetCoefficient(lambda, -d); - } - -#if DEBUG_PRINT - Console.WriteLine(" Constraints after addition:"); - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } -#endif - - // Finally, project out the dummy dimension. - Constraints = Project(lambda, Constraints); - -#if DEBUG_PRINT - Console.WriteLine(" Resulting constraints:"); - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } -#endif - } - - ISet /*IVariable!*//*!*/ GetDefinedDimensions() { - Contract.Ensures(Contract.Result() != null); - HashSet /*IVariable!*//*!*/ dims = new HashSet /*IVariable!*/ (); - foreach (ArrayList p in new ArrayList[] { FrameVertices, FrameRays, FrameLines }) { - if (p != null) { - foreach (FrameElement/*!*/ element in p) { - Contract.Assert(element != null); - foreach (IVariable/*!*/ dim in element.GetDefinedDimensions()) { - Contract.Assert(dim != null); - dims.Add(dim); - } - } - } - } - return dims; - } - - // -------------------------------------------------------------------------------------------------------- - // ------------------ Simplification routines ------------------------------------------------------------- - // -------------------------------------------------------------------------------------------------------- - - /// - /// Uses the Constraints to simplify the frame. See section 3.4.4 of Cousot and Halbwachs. - /// - void SimplifyFrame() { - Contract.Requires(this.Constraints != null); - SimplificationStatus[]/*!*/ status; - - SimplifyFrameElements(cce.NonNull(FrameVertices), true, Constraints, out status); - RemoveIrrelevantFrameElements(FrameVertices, status, null); - - SimplifyFrameElements(cce.NonNull(FrameRays), false, Constraints, out status); - RemoveIrrelevantFrameElements(FrameRays, status, FrameLines); - } - - enum SimplificationStatus { - Irrelevant, - Relevant, - More - }; - - /// - /// For each i, sets status[i] to: - ///
    - ///
  • Irrelevant if ff[i] is irrelevant
  • - ///
  • Relevant if ff[i] is irrelevant
  • - ///
  • More if vertices is true and ray ff[i] can be replaced by a line ff[i]
  • - ///
- ///
- /// - /// true if "ff" contains vertices; false if "ff" contains rays - /// - /// - static void SimplifyFrameElements(ArrayList/*!*/ /*FrameElement*/ ff, bool vertices, ArrayList/*!*/ /*LinearConstraint*/ constraints, out SimplificationStatus[]/*!*/ status) { - Contract.Requires(ff != null); - Contract.Requires(constraints != null); - Contract.Ensures(Contract.ValueAtReturn(out status) != null); - status = new SimplificationStatus[ff.Count]; - bool[,] sat = new bool[ff.Count, constraints.Count]; - for (int i = 0; i < ff.Count; i++) { - FrameElement f = (FrameElement/*!*/)cce.NonNull(ff[i]); - int cnt = 0; - for (int c = 0; c < constraints.Count; c++) { - LinearConstraint lc = (LinearConstraint/*!*/)cce.NonNull(constraints[c]); - bool s = lc.IsSaturatedBy(f, vertices); - if (s) { - sat[i, c] = true; - cnt++; - } - } - if (!vertices && cnt == constraints.Count) { - status[i] = SimplificationStatus.More; - } else { - status[i] = SimplificationStatus.Relevant; - } - } - - CheckPairSimplifications(sat, status); - } - - /// - /// Requires sat.GetLength(0) == status.Length. - /// - /// - /// - static void CheckPairSimplifications(bool[,]/*!*/ sat, SimplificationStatus[]/*!*/ status) { - Contract.Requires(status != null); - Contract.Requires(sat != null); - Contract.Requires(sat.GetLength(0) == status.Length); - int M = sat.GetLength(0); - int N = sat.GetLength(1); - - for (int i = 0; i < M - 1; i++) { - if (status[i] != SimplificationStatus.Relevant) { - continue; - } - for (int j = i + 1; j < M; j++) { - if (status[j] != SimplificationStatus.Relevant) { - continue; - } - // check (sat[i,*] <= sat[j,*]) and (sat[i,*] >= sat[j,*]) - int cmp = 0; // -1: (sat[i,*] <= sat[j,*]), 0: equal, 1: (sat[i,*] >= sat[j,*]) - for (int c = 0; c < N; c++) { - if (cmp < 0) { - if (sat[i, c] && !sat[j, c]) { - // incomparable - goto NEXT_PAIR; - } - } else if (0 < cmp) { - if (!sat[i, c] && sat[j, c]) { - // incomparable - goto NEXT_PAIR; - } - } else if (sat[i, c] != sat[j, c]) { - if (!sat[i, c]) { - cmp = -1; - } else { - cmp = 1; - } - } - } - if (cmp <= 0) { - // sat[i,*] <= sat[j,*] holds, so mark i as irrelevant - status[i] = SimplificationStatus.Irrelevant; - goto NEXT_OUTER; - } else { - // sat[i,*] >= sat[j,*] holds, so mark j as irrelevant - status[j] = SimplificationStatus.Irrelevant; - } - NEXT_PAIR: { - } - } - NEXT_OUTER: { - } - } - } - - static void RemoveIrrelevantFrameElements(ArrayList/*!*/ /*FrameElement*/ ff, SimplificationStatus[]/*!*/ status, - /*maybe null*/ ArrayList /*FrameElement*/ lines) { - Contract.Requires(ff != null); - Contract.Requires(status != null); - Contract.Requires(ff.Count == status.Length); - for (int j = ff.Count - 1; 0 <= j; j--) { - switch (status[j]) { - case SimplificationStatus.Relevant: - break; - case SimplificationStatus.Irrelevant: -#if DEBUG_PRINT - Console.WriteLine("Removing irrelevant {0}: {1}", lines == null ? "vertex" : "ray", ff[j]); -#endif - ff.RemoveAt(j); - break; - case SimplificationStatus.More: - System.Diagnostics.Debug.Assert(lines != null); - FrameElement f = (FrameElement)ff[j]; -#if DEBUG_PRINT - Console.WriteLine("Changing ray into line: {0}", f); -#endif - ff.RemoveAt(j); - Contract.Assert(lines != null); - lines.Add(f); - break; - } - } - } - - /// - /// Uses the frame to simplify Constraints. See section 3.3.1.2 of Cousot and Halbwachs. - /// - /// Note: This code does not necessarily eliminate all irrelevant equalities; Cousot and - /// Halbwachs only claim that the technique eliminates all irrelevant inequalities. - /// - void SimplifyConstraints() { - if (Constraints == null) { - return; - } - Contract.Assume(this.FrameVertices != null); - Contract.Assume(this.FrameRays != null); - - SimplificationStatus[] status = new SimplificationStatus[Constraints.Count]; - /*readonly*/ - int feCount = FrameVertices.Count + FrameRays.Count; - - // Create a table that keeps track of which constraints are satisfied by which vertices and rays - bool[,] sat = new bool[Constraints.Count, FrameVertices.Count + FrameRays.Count]; - for (int i = 0; i < Constraints.Count; i++) { - status[i] = SimplificationStatus.Relevant; - LinearConstraint lc = (LinearConstraint/*!*/)cce.NonNull(Constraints[i]); - int cnt = 0; // number of vertices and rays that saturate lc - for (int j = 0; j < FrameVertices.Count; j++) { - FrameElement vertex = (FrameElement/*!*/)cce.NonNull(FrameVertices[j]); - if (lc.IsSaturatedBy(vertex, true)) { - sat[i, j] = true; - cnt++; - } - } - if (cnt == 0) { - // no vertex saturates the constraint, so the constraint is irrelevant - status[i] = SimplificationStatus.Irrelevant; - continue; - } - for (int j = 0; j < FrameRays.Count; j++) { - FrameElement ray = (FrameElement/*!*/)cce.NonNull(FrameRays[j]); - if (lc.IsSaturatedBy(ray, false)) { - sat[i, FrameVertices.Count + j] = true; - cnt++; - } - } - if (cnt == feCount) { - status[i] = SimplificationStatus.More; - } else { - // Cousot and Halbwachs says that all equalities are found in the way we just tested. - // If I understand that right, then we should not get here if the constraint is an - // equality constraint. The following assertion tests my understanding. --KRML - System.Diagnostics.Debug.Assert(lc.Relation == LinearConstraint.ConstraintRelation.LE); - } - } - - CheckPairSimplifications(sat, status); - - // Finally, make the changes to the list of constraints - for (int i = Constraints.Count - 1; 0 <= i; i--) { - switch (status[i]) { - case SimplificationStatus.Relevant: - break; - case SimplificationStatus.Irrelevant: -#if DEBUG_PRINT - Console.WriteLine("Removing irrelevant constraint: {0}", Constraints[i]); -#endif - Constraints.RemoveAt(i); - break; - case SimplificationStatus.More: - LinearConstraint lc = (LinearConstraint/*!*/)cce.NonNull(Constraints[i]); - if (lc.Relation == LinearConstraint.ConstraintRelation.LE) { -#if DEBUG_PRINT - Console.WriteLine("Converting the following constraint into an equality: {0}", lc); -#endif - LinearConstraint lcEq = lc.ChangeRelation(LinearConstraint.ConstraintRelation.EQ); - Constraints[i] = lcEq; - } - break; - } - } - - foreach (LinearConstraint/*!*/ lc in Constraints) { - Contract.Assert(lc != null); - lc.Normalize(); - } - } - - // -------------------------------------------------------------------------------------------------------- - // ------------------ Cloning routines -------------------------------------------------------------------- - // -------------------------------------------------------------------------------------------------------- - - public LinearConstraintSystem/*!*/ Clone() { - Contract.Ensures(Contract.Result() != null); - LinearConstraintSystem z = new LinearConstraintSystem(); - z.FrameDimensions = (IMutableSet /*IVariable!*//*!*/)cce.NonNull(this.FrameDimensions.Clone()); - if (this.Constraints != null) { - z.Constraints = DeeperListCopy_LC(this.Constraints); - z.FrameVertices = DeeperListCopy_FE(cce.NonNull(this.FrameVertices)); - z.FrameRays = DeeperListCopy_FE(cce.NonNull(this.FrameRays)); - z.FrameLines = DeeperListCopy_FE(cce.NonNull(this.FrameLines)); - } else { - System.Diagnostics.Debug.Assert(this.FrameVertices == null); - System.Diagnostics.Debug.Assert(this.FrameRays == null); - System.Diagnostics.Debug.Assert(this.FrameLines == null); - // the constructor should already have set these fields of z to null - System.Diagnostics.Debug.Assert(z.Constraints == null); - System.Diagnostics.Debug.Assert(z.FrameVertices == null); - System.Diagnostics.Debug.Assert(z.FrameRays == null); - System.Diagnostics.Debug.Assert(z.FrameLines == null); - } - return z; - } - - /// - /// Clones "list" and the elements of "list". - /// - /// - /// - ArrayList /*LinearConstraint*/ DeeperListCopy_LC(ArrayList/*!*/ /*LinearConstraint*/ list) { - Contract.Requires(list != null); - ArrayList /*LinearConstraint*/ z = new ArrayList /*LinearConstraint*/ (list.Count); - foreach (LinearConstraint/*!*/ lc in list) { - Contract.Assert(lc != null); - z.Add(lc.Clone()); - } - System.Diagnostics.Debug.Assert(z.Count == list.Count); - return z; - } - - /// - /// Clones "list" and the elements of "list". - /// - /// - /// - ArrayList /*FrameElement*/ DeeperListCopy_FE(ArrayList/*!*/ /*FrameElement*/ list) { - Contract.Requires(list != null); - ArrayList /*FrameElement*/ z = new ArrayList /*FrameElement*/ (list.Count); - foreach (FrameElement/*!*/ fe in list) { - Contract.Assert(fe != null); - z.Add(fe.Clone()); - } - System.Diagnostics.Debug.Assert(z.Count == list.Count); - return z; - } - - // -------------------------------------------------------------------------------------------------------- - // ------------------ Debugging and unit test routines ---------------------------------------------------- - // -------------------------------------------------------------------------------------------------------- - - public void Dump() { - Console.WriteLine(" Constraints:"); - if (Constraints == null) { - Console.WriteLine(" "); - } else { - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } - } - - Console.WriteLine(" FrameDimensions: {0}", FrameDimensions); - - Console.WriteLine(" FrameVerticies:"); - if (FrameVertices == null) { - Console.WriteLine(" "); - } else { - foreach (FrameElement fe in FrameVertices) { - Console.WriteLine(" {0}", fe); - } - } - - Console.WriteLine(" FrameRays:"); - if (FrameRays == null) { - Console.WriteLine(" "); - } else { - foreach (FrameElement fe in FrameRays) { - Console.WriteLine(" {0}", fe); - } - } - - Console.WriteLine(" FrameLines:"); - if (FrameLines == null) { - Console.WriteLine(" "); - } else { - foreach (FrameElement fe in FrameLines) { - Console.WriteLine(" {0}", fe); - } - } - } - - class TestVariable : IVariable { - readonly string/*!*/ name; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(name != null); - } - - - public string/*!*/ Name { - get { - Contract.Ensures(Contract.Result() != null); - - return name; - } - } - - public TestVariable(string/*!*/ name) { - Contract.Requires(name != null); - this.name = name; - } - [Pure] - public object DoVisit(ExprVisitor/*!*/ visitor) { - //Contract.Requires(visitor != null); - return visitor.VisitVariable(this); - } - } - - public static void RunValidationA() { - IVariable/*!*/ dim1 = new TestVariable("X"); - IVariable/*!*/ dim2 = new TestVariable("Y"); - IVariable/*!*/ dim3 = new TestVariable("Z"); - Contract.Assert(dim1 != null); - Contract.Assert(dim2 != null); - Contract.Assert(dim3 != null); - - FrameElement s1 = new FrameElement(); - s1.AddCoordinate(dim1, Rational.ONE); - s1.AddCoordinate(dim2, Rational.MINUS_ONE); - s1.AddCoordinate(dim3, Rational.ZERO); - FrameElement s2 = new FrameElement(); - s2.AddCoordinate(dim1, Rational.MINUS_ONE); - s2.AddCoordinate(dim2, Rational.ONE); - s2.AddCoordinate(dim3, Rational.ZERO); - FrameElement r1 = new FrameElement(); - r1.AddCoordinate(dim1, Rational.ZERO); - r1.AddCoordinate(dim2, Rational.ZERO); - r1.AddCoordinate(dim3, Rational.ONE); - FrameElement d1 = new FrameElement(); - d1.AddCoordinate(dim1, Rational.ONE); - d1.AddCoordinate(dim2, Rational.ONE); - d1.AddCoordinate(dim3, Rational.ZERO); - - // create lcs from frame -- cf. Cousot/Halbwachs 1978, section 3.3.1.1 - LinearConstraintSystem lcs = new LinearConstraintSystem(s1); - lcs.Dump(); - - lcs.AddVertex(s2); - lcs.Dump(); - - lcs.AddRay(r1); - lcs.Dump(); - - lcs.AddLine(d1); - lcs.Dump(); - - lcs.SimplifyConstraints(); - lcs.Dump(); - -#if LATER - lcs.GenerateFrameFromConstraints(); // should give us back the original frame... -#endif - Console.WriteLine("IsSubset? {0}", lcs.IsSubset(lcs.Clone())); - lcs.Dump(); - } - - /// - /// Tests the example in section 3.4.3 of Cousot and Halbwachs. - /// - public static void RunValidationB() { - IVariable/*!*/ X = new TestVariable("X"); - IVariable/*!*/ Y = new TestVariable("Y"); - IVariable/*!*/ Z = new TestVariable("Z"); - Contract.Assert(X != null); - Contract.Assert(Y != null); - Contract.Assert(Z != null); - ArrayList /*LinearConstraint*/ cs = new ArrayList /*LinearConstraint*/ (); - - LinearConstraint c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); - c.SetCoefficient(X, Rational.MINUS_ONE); - c.SetCoefficient(Y, Rational.ONE); - c.SetCoefficient(Z, Rational.MINUS_ONE); - c.rhs = Rational.ZERO; - cs.Add(c); - - c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); - c.SetCoefficient(X, Rational.MINUS_ONE); - c.rhs = Rational.MINUS_ONE; - cs.Add(c); - - c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); - c.SetCoefficient(X, Rational.MINUS_ONE); - c.SetCoefficient(Y, Rational.MINUS_ONE); - c.SetCoefficient(Z, Rational.ONE); - c.rhs = Rational.ZERO; - cs.Add(c); - - c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); - c.SetCoefficient(Y, Rational.MINUS_ONE); - c.SetCoefficient(Z, Rational.ONE); - c.rhs = Rational.FromInt(3); - cs.Add(c); - - LinearConstraintSystem lcs = new LinearConstraintSystem(cs); - Console.WriteLine("==================== The final linear constraint system ===================="); - lcs.Dump(); - } - - public static void RunValidationC() { - // Run the example in section 3.4.3 of Cousot and Halbwachs backwards, that is, from - // from to constraints. - IVariable/*!*/ dim1 = new TestVariable("X"); - IVariable/*!*/ dim2 = new TestVariable("Y"); - IVariable/*!*/ dim3 = new TestVariable("Z"); - Contract.Assert(dim1 != null); - Contract.Assert(dim2 != null); - Contract.Assert(dim3 != null); - - FrameElement s0 = new FrameElement(); - s0.AddCoordinate(dim1, Rational.ONE); - s0.AddCoordinate(dim2, Rational.FromInts(1, 2)); - s0.AddCoordinate(dim3, Rational.FromInts(-1, 2)); - - FrameElement s1 = new FrameElement(); - s1.AddCoordinate(dim1, Rational.ONE); - s1.AddCoordinate(dim2, Rational.FromInts(-1, 2)); - s1.AddCoordinate(dim3, Rational.FromInts(1, 2)); - - FrameElement s2 = new FrameElement(); - s2.AddCoordinate(dim1, Rational.FromInt(3)); - s2.AddCoordinate(dim2, Rational.FromInts(-3, 2)); - s2.AddCoordinate(dim3, Rational.FromInts(3, 2)); - - FrameElement r0 = new FrameElement(); - r0.AddCoordinate(dim1, Rational.ONE); - r0.AddCoordinate(dim2, Rational.FromInts(1, 2)); - r0.AddCoordinate(dim3, Rational.FromInts(-1, 2)); - - FrameElement r1 = new FrameElement(); - r1.AddCoordinate(dim1, Rational.ONE); - r1.AddCoordinate(dim2, Rational.ZERO); - r1.AddCoordinate(dim3, Rational.ZERO); - - FrameElement d0 = new FrameElement(); - d0.AddCoordinate(dim1, Rational.ZERO); - d0.AddCoordinate(dim2, Rational.ONE); - d0.AddCoordinate(dim3, Rational.ONE); - - LinearConstraintSystem lcs = new LinearConstraintSystem(s0); - lcs.Dump(); - - lcs.AddVertex(s1); - lcs.Dump(); - - lcs.AddVertex(s2); - lcs.Dump(); - - lcs.AddRay(r0); - lcs.Dump(); - - lcs.AddRay(r1); - lcs.Dump(); - - lcs.AddLine(d0); - lcs.Dump(); - - lcs.SimplifyConstraints(); - lcs.Dump(); - -#if LATER - lcs.GenerateFrameFromConstraints(); // should give us back the original frame... -#endif - } - } +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + using System; + //using Microsoft.SpecSharp.Collections; + using System.Diagnostics.Contracts; + using Microsoft.Basetypes; + + using IMutableSet = Microsoft.Boogie.GSet; + using ISet = Microsoft.Boogie.GSet; + using HashSet = Microsoft.Boogie.GSet; + + /// + /// Represents a system of linear constraints (constraint/frame representations). + /// + public class LinearConstraintSystem { + // -------------------------------------------------------------------------------------------------------- + // ------------------ Data structure ---------------------------------------------------------------------- + // -------------------------------------------------------------------------------------------------------- + + public /*maybe null*/ ArrayList /*LinearConstraint!*/ Constraints; + /*maybe null*/ + ArrayList /*FrameElement!*/ FrameVertices; + /*maybe null*/ + ArrayList /*FrameElement!*/ FrameRays; + IMutableSet/*IVariable!*//*!*/ FrameDimensions; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(FrameDimensions != null); + } + + /*maybe null*/ + ArrayList /*FrameElement!*/ FrameLines; + // Invariant: Either all of Constraints, FrameVertices, FrameRays, and FrameLines are + // null, or all are non-null. + // Invariant: Any dimension mentioned in Constraints, FrameVertices, FrameRays, or + // FrameLines is mentioned in FrameDimensions. + // The meaning of FrameDimensions is that for any dimension x not in FrameDimensions, + // there is an implicit line along dimension x (that is, ()). + + void CheckInvariant() { + if (Constraints == null) { + System.Diagnostics.Debug.Assert(FrameVertices == null); + System.Diagnostics.Debug.Assert(FrameRays == null); + System.Diagnostics.Debug.Assert(FrameLines == null); + System.Diagnostics.Debug.Assert(FrameDimensions.Count == 0); + } else { + System.Diagnostics.Debug.Assert(FrameVertices != null); + System.Diagnostics.Debug.Assert(FrameRays != null); + System.Diagnostics.Debug.Assert(FrameLines != null); + + foreach (LinearConstraint/*!*/ cc in Constraints) { + Contract.Assert(cc != null); +#if FIXED_DESERIALIZER + Contract.Assert(Contract.ForAll(cc.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); +#endif + Contract.Assert(cc.coefficients.Count != 0); + } + foreach (ArrayList /*FrameElement*//*!*/ FrameComponent in new ArrayList /*FrameElement*/ [] { FrameVertices, FrameRays, FrameLines }) { + Contract.Assert(FrameComponent != null); + foreach (FrameElement fe in FrameComponent) { + if (fe == null) + continue; +#if FIXED_DESERIALIZER + Contract.Assert(Contract.ForAll(fe.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); +#endif + } + } + } + } + + // -------------------------------------------------------------------------------------------------------- + // ------------------ Constructors ------------------------------------------------------------------------ + // -------------------------------------------------------------------------------------------------------- + + /// + /// Creates a LinearConstraintSystem representing the bottom element, that is, representing + /// an unsatisfiable system of constraints. + /// + [NotDelayed] + public LinearConstraintSystem() { + FrameDimensions = new HashSet /*IVariable!*/ (); + //:base(); + CheckInvariant(); + } + + /// + /// Constructs a linear constraint system with constraints "cs". + /// The constructor captures all constraints in "cs". + /// + /// + [NotDelayed] + public LinearConstraintSystem(ArrayList /*LinearConstraint!*//*!*/ cs) { + Contract.Requires(cs != null); +#if BUG_159_HAS_BEEN_FIXED + Contract.Requires(Contract.ForAll(cs) , cc=> cc.coefficients.Count != 0); +#endif + + ArrayList constraints = new ArrayList /*LinearConstraint!*/ (cs.Count); + foreach (LinearConstraint/*!*/ cc in cs) { + Contract.Assert(cc != null); + constraints.Add(cc); + } + Constraints = constraints; + FrameDimensions = new HashSet /*IVariable!*/ (); // to please compiler; this value will be overridden in the call to GenerateFrameConstraints below + //:base(); + + GenerateFrameFromConstraints(); + SimplifyConstraints(); + CheckInvariant(); +#if DEBUG_PRINT + Console.WriteLine("LinearConstraintSystem: constructor produced:"); + Dump(); +#endif + } + + /// + /// Constructs a linear constraint system corresponding to given vertex. This constructor + /// is only used in the test harness--it is not needed for abstract interpretation. + /// + /// + [NotDelayed] + LinearConstraintSystem(FrameElement/*!*/ v) { + Contract.Requires(v != null); + IMutableSet/*!*/ frameDims = v.GetDefinedDimensions(); + Contract.Assert(frameDims != null); + ArrayList /*LinearConstraint!*/ constraints = new ArrayList /*LinearConstraint!*/ (); + foreach (IVariable/*!*/ dim in frameDims) { + Contract.Assert(dim != null); + LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ); + lc.SetCoefficient(dim, Rational.ONE); + lc.rhs = v[dim]; + constraints.Add(lc); + } + FrameDimensions = frameDims; + Constraints = constraints; + + ArrayList /*FrameElement*/ frameVertices = new ArrayList /*FrameElement*/ (); + frameVertices.Add(v); + FrameVertices = frameVertices; + + FrameRays = new ArrayList /*FrameElement*/ (); + FrameLines = new ArrayList /*FrameElement*/ (); + + //:base(); + CheckInvariant(); + } + + void ChangeIntoBottom() { + Constraints = null; + FrameVertices = null; + FrameRays = null; + FrameLines = null; + FrameDimensions.Clear(); // no implicit lines + } + + // -------------------------------------------------------------------------------------------------------- + // ------------------ Public operations and their support routines ---------------------------------------- + // -------------------------------------------------------------------------------------------------------- + + public bool IsBottom() { + return Constraints == null; + } + + public bool IsTop() { + return Constraints != null && Constraints.Count == 0; + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + if (Constraints == null) { + return ""; + } else if (Constraints.Count == 0) { + return ""; + } else { + string z = null; + foreach (LinearConstraint/*!*/ lc in Constraints) { + Contract.Assert(lc != null); + string s = lc.ToString(); + if (z == null) { + z = s; + } else { + z += " AND " + s; + } + } + Contract.Assert(z != null); + return z; + } + } + + + public ICollection/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + Contract.Ensures(Contract.Result>().IsReadOnly); + List list = new List(); + foreach (IVariable/*!*/ v in FrameDimensions) { + Contract.Assert(v != null); + list.Add(v); + } + return cce.NonNull(list.AsReadOnly()); + } + + /// + /// Note: This method requires that all dimensions are of type Variable, something that's + /// not required elsewhere in this class. + /// + /// + public IExpr/*!*/ ConvertToExpression(ILinearExprFactory/*!*/ factory) { + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result() != null); + if (this.Constraints == null) { + return factory.False; + } + if (this.Constraints.Count == 0) { + return factory.True; + } + + IExpr result = null; + foreach (LinearConstraint/*!*/ lc in Constraints) { + Contract.Assert(lc != null); + IExpr conjunct = lc.ConvertToExpression(factory); + result = (result == null) ? conjunct : (IExpr)factory.And(conjunct, result); + } + Contract.Assert(result != null); + return result; + } + + + /* IsSubset(): determines if 'lcs' is a subset of 'this' + * -- See Cousot/Halbwachs 1978, section + */ + public bool IsSubset(LinearConstraintSystem/*!*/ lcs) { + Contract.Requires(lcs != null); + if (lcs.IsBottom()) { + return true; + } else if (this.IsBottom()) { + return false; +#if DEBUG +#else + } else if (this.IsTop()) { // optimization -- this case not needed for correctness + return true; + } else if (lcs.IsTop()) { // optimization -- this case not needed for correctness + return false; +#endif + } else { + // phase 0: check if frame dimensions are a superset of the constraint dimensions + ISet /*IVariable!*//*!*/ frameDims = lcs.GetDefinedDimensions(); + Contract.Assert(frameDims != null); +#if DEBUG_PRINT + Console.WriteLine("DEBUG: IsSubset:"); + Console.WriteLine(" --- this:"); + this.Dump(); + Console.WriteLine(" --- lcs:"); + lcs.Dump(); + Console.WriteLine(" ---"); +#endif + foreach (LinearConstraint/*!*/ cc in cce.NonNull(this.Constraints)) { + Contract.Assert(cc != null); +#if DEBUG_PRINT + Console.WriteLine(" cc: {0}", cc); + Console.WriteLine(" cc.GetDefinedDimensions(): {0}", cc.GetDefinedDimensions()); +#endif + + if (!Contract.ForAll(cc.GetDefinedDimensionsGeneric(), var => frameDims.Contains(var))) { +#if DEBUG_PRINT + Console.WriteLine(" ---> phase 0 subset violated, return false from IsSubset"); +#endif + return false; + } + } + } + + // phase 1: check frame vertices against each constraint... + foreach (FrameElement/*!*/ v in cce.NonNull(lcs.FrameVertices)) { + Contract.Assert(v != null); + foreach (LinearConstraint/*!*/ cc in this.Constraints) { + Contract.Assert(cc != null); + Rational q = cc.EvaluateLhs(v); + if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { + if (!(q <= cc.rhs)) { +#if DEBUG_PRINT + Console.WriteLine(" ---> phase 1a subset violated, return false from IsSubset"); +#endif + return false; + } + } else { + if (!(q == cc.rhs)) { +#if DEBUG_PRINT + Console.WriteLine(" ---> phase 1b subset violated, return false from IsSubset"); +#endif + return false; + } + } + } + } + + // phase 2: check frame rays against each constraint... + // To check if a ray "r" falls within a constraint "cc", we add the vector "r" to + // any point "p" on the side of the half-space or plane described by constraint, and + // then check if the resulting point satisfies the constraint. That is, we check (for + // an inequality constraint with coefficients a1,a2,...,an and right-hand side + // constant C): + // a1*(r1+p1) + a2*(r2+p2) + ... + an*(rn+pn) <= C + // Equivalently: + // a1*r1 + a2*r2 + ... + an*rn + a1*p1 + a2*p2 + ... + an*pn <= C + // To find a point "p", we can pick out a coordinate, call it 1, with a non-zero + // coefficient in the constraint, and then choose "p" as the point that has the + // value C/a1 in coordinate 1 and has 0 in all other coordinates. We then check: + // a1*r1 + a2*r2 + ... + an*rn + a1*(C/a1) + a2*0 + ... + an*0 <= C + // which simplifies to: + // a1*r1 + a2*r2 + ... + an*rn + C <= C + // which in turn simplifies to: + // a1*r1 + a2*r2 + ... + an*rn <= 0 + // If the constraint is an equality constraint, we simply replace "<=" with "==" + // above. + foreach (FrameElement/*!*/ r in cce.NonNull(lcs.FrameRays)) { + Contract.Assert(r != null); + System.Diagnostics.Debug.Assert(r != null, "encountered a null ray..."); + foreach (LinearConstraint/*!*/ cc in this.Constraints) { + Contract.Assert(cc != null); + System.Diagnostics.Debug.Assert(cc != null, "encountered an null constraint..."); + Rational q = cc.EvaluateLhs(r); + if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { + if (q.IsPositive) { +#if DEBUG_PRINT + Console.WriteLine(" ---> phase 2a subset violated, return false from IsSubset"); +#endif + return false; + } + } else { + if (q.IsNonZero) { +#if DEBUG_PRINT + Console.WriteLine(" ---> phase 2b subset violated, return false from IsSubset"); +#endif + return false; + } + } + } + } + + // phase 3: check frame lines against each constraint... + // To check if a line "L" falls within a constraint "cc", we check if both the + // vector "L" and "-L", interpreted as rays, fall within the constraint. From + // the discussion above, this means we check the following two properties: + // a1*L1 + a2*L2 + ... + an*Ln <= 0 (*) + // a1*(-L1) + a2*(-L2) + ... + an*(-Ln) <= 0 + // The second of these lines can be rewritten as: + // - a1*L1 - a2*L2 - ... - an*Ln <= 0 + // which is equivalent to: + // -1 * (a1*L1 + a2*L2 + ... + an*Ln) <= 0 + // Multiplying both sides by -1 and flipping the direction of the inequality, + // we have: + // a1*L1 + a2*L2 + ... + an*Ln >= 0 (**) + // Putting (*) and (**) together, we conclude that we need to check: + // a1*L1 + a2*L2 + ... + an*Ln == 0 + // If the constraint is an equality constraint, we end up with the same equation. + foreach (FrameElement/*!*/ line in cce.NonNull(lcs.FrameLines)) { + Contract.Assert(line != null); + System.Diagnostics.Debug.Assert(line != null, "encountered a null line..."); + foreach (LinearConstraint/*!*/ cc in this.Constraints) { + Contract.Assert(cc != null); + System.Diagnostics.Debug.Assert(cc != null, "encountered an null constraint..."); + Rational q = cc.EvaluateLhs(line); + if (q.IsNonZero) { +#if DEBUG_PRINT + Console.WriteLine(" ---> phase 3 subset violated, return false from IsSubset"); +#endif + return false; + } + } + } + +#if DEBUG_PRINT + Console.WriteLine(" ---> IsSubset returns true"); +#endif + return true; + } + + public LinearConstraintSystem/*!*/ Meet(LinearConstraintSystem/*!*/ lcs) { + Contract.Requires(lcs != null); + Contract.Requires((this.Constraints != null)); + Contract.Requires((lcs.Constraints != null)); + Contract.Ensures(Contract.Result() != null); + ArrayList /*LinearConstraint*/ clist = new ArrayList(this.Constraints.Count + lcs.Constraints.Count); + clist.AddRange(this.Constraints); + clist.AddRange(lcs.Constraints); + return new LinearConstraintSystem(clist); + } + +#if DEBUG_PRINT + public LinearConstraintSystem Join(LinearConstraintSystem lcs) + { + Console.WriteLine("==================================================================================="); + Console.WriteLine("DEBUG: Join"); + Console.WriteLine("Join: this="); + Dump(); + Console.WriteLine("Join: lcs="); + lcs.Dump(); + LinearConstraintSystem z = JoinX(lcs); + Console.WriteLine("----------Join------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); + Console.WriteLine("Join: result="); + z.Dump(); + Console.WriteLine("==================================================================================="); + return z; + } +#endif + + /// + /// The join is computed as described in section 4.4 in Cousot and Halbwachs. + /// + /// + /// +#if DEBUG_PRINT + public LinearConstraintSystem JoinX(LinearConstraintSystem lcs) { +#else + public LinearConstraintSystem/*!*/ Join(LinearConstraintSystem/*!*/ lcs) { + Contract.Requires(lcs != null); + Contract.Ensures(Contract.Result() != null); +#endif + + if (this.IsBottom()) { + return cce.NonNull(lcs.Clone()); + } else if (lcs.IsBottom()) { + return cce.NonNull(this.Clone()); + } else if (this.IsTop() || lcs.IsTop()) { + return new LinearConstraintSystem(new ArrayList /*LinearConstraint*/ ()); + } else { + LinearConstraintSystem/*!*/ z; + // Start from the "larger" of the two frames (this is just a heuristic measure intended + // to save work). + Contract.Assume(this.FrameVertices != null); + Contract.Assume(this.FrameRays != null); + Contract.Assume(this.FrameLines != null); + Contract.Assume(lcs.FrameVertices != null); + Contract.Assume(lcs.FrameRays != null); + Contract.Assume(lcs.FrameLines != null); + if (this.FrameVertices.Count + this.FrameRays.Count + this.FrameLines.Count - this.FrameDimensions.Count < + lcs.FrameVertices.Count + lcs.FrameRays.Count + lcs.FrameLines.Count - lcs.FrameDimensions.Count) { + z = cce.NonNull(lcs.Clone()); + lcs = this; + } else { + z = cce.NonNull(this.Clone()); + } +#if DEBUG_PRINT + Console.WriteLine("DEBUG: LinearConstraintSystem.Join ---------------"); + Console.WriteLine("z:"); + z.Dump(); + Console.WriteLine("lcs:"); + lcs.Dump(); +#endif + + // Start by explicating the implicit lines of z for the dimensions dims(lcs)-dims(z). + foreach (IVariable/*!*/ dim in lcs.FrameDimensions) { + Contract.Assert(dim != null); + if (!z.FrameDimensions.Contains(dim)) { + z.FrameDimensions.Add(dim); + FrameElement line = new FrameElement(); + line.AddCoordinate(dim, Rational.ONE); + // Note: AddLine is not called (because the line already exists in z--it's just that + // it was represented implicitly). Instead, just tack the explicit representation onto + // FrameLines. + Contract.Assume(z.FrameLines != null); + z.FrameLines.Add(line); +#if DEBUG_PRINT + Console.WriteLine("Join: After explicating line: {0}", line); + z.Dump(); +#endif + } + } + + // Now, the vertices, rays, and lines can be added. + foreach (FrameElement/*!*/ v in lcs.FrameVertices) { + Contract.Assert(v != null); + z.AddVertex(v); +#if DEBUG_PRINT + Console.WriteLine("Join: After adding vertex: {0}", v); + z.Dump(); +#endif + } + foreach (FrameElement/*!*/ r in lcs.FrameRays) { + Contract.Assert(r != null); + z.AddRay(r); +#if DEBUG_PRINT + Console.WriteLine("Join: After adding ray: {0}", r); + z.Dump(); +#endif + } + foreach (FrameElement/*!*/ l in lcs.FrameLines) { + Contract.Assert(l != null); + z.AddLine(l); +#if DEBUG_PRINT + Console.WriteLine("Join: After adding line: {0}", l); + z.Dump(); +#endif + } + // also add to z the implicit lines of lcs + foreach (IVariable/*!*/ dim in z.FrameDimensions) { + Contract.Assert(dim != null); + if (!lcs.FrameDimensions.Contains(dim)) { + // "dim" is a dimension that's explicit in "z" but implicit in "lcs" + FrameElement line = new FrameElement(); + line.AddCoordinate(dim, Rational.ONE); + z.AddLine(line); +#if DEBUG_PRINT + Console.WriteLine("Join: After adding lcs's implicit line: {0}", line); + z.Dump(); +#endif + } + } + + z.SimplifyFrame(); + z.SimplifyConstraints(); + z.CheckInvariant(); +#if DEBUG_PRINT + Console.WriteLine("Join: Returning z:"); + z.Dump(); + Console.WriteLine("----------------------------------------"); +#endif + return z; + } + } + +#if DEBUG_PRINT + public LinearConstraintSystem Widen(LinearConstraintSystem lcs) + { + Console.WriteLine("==================================================================================="); + Console.WriteLine("DEBUG: Widen"); + Console.WriteLine("Widen: this="); + Dump(); + Console.WriteLine("Widen: lcs="); + lcs.Dump(); + LinearConstraintSystem z = WidenX(lcs); + Console.WriteLine("----------Widen------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); + Console.WriteLine("Widen: result="); + z.Dump(); + Console.WriteLine("==================================================================================="); + return z; + } +#endif + +#if DEBUG_PRINT + public LinearConstraintSystem WidenX(LinearConstraintSystem lcs){ +#else + public LinearConstraintSystem/*!*/ Widen(LinearConstraintSystem/*!*/ lcs) { + Contract.Requires(lcs != null); + Contract.Ensures(Contract.Result() != null); +#endif + if (this.IsBottom()) { + return cce.NonNull(lcs.Clone()); + } else if (lcs.IsBottom()) { + return cce.NonNull(this.Clone()); + } else if (this.IsTop() || lcs.IsTop()) { + return new LinearConstraintSystem(new ArrayList /*LinearConstraint*/ ()); + } + + // create new LCS, we will add only verified constraints to this... + ArrayList /*LinearConstraint*/ newConstraints = new ArrayList /*LinearConstraint*/ (); + Contract.Assume(this.Constraints != null); + foreach (LinearConstraint/*!*/ ccX in this.Constraints) { + Contract.Assert(ccX != null); + LinearConstraint cc = ccX; +#if DEBUG_PRINT + Console.WriteLine("Widen checking: Starting to check constraint: {0}", cc); +#endif + if (cc.IsConstant()) { + // (Can this ever occur in the stable state of a LinearConstraintSystem? --KRML) + // constraint is unaffected by the frame components +#if DEBUG_PRINT + Console.WriteLine("Widen checking: --Adding it!"); +#endif + newConstraints.Add(cc); + continue; + } + + // PHASE I: verify constraints against all frame vertices... + + foreach (FrameElement/*!*/ vertex in cce.NonNull(lcs.FrameVertices)) { + Contract.Assert(vertex != null); + Rational lhs = cc.EvaluateLhs(vertex); + if (lhs > cc.rhs) { + // the vertex does not satisfy the inequality <= + if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { +#if DEBUG_PRINT + Console.WriteLine("Widen checking: throwing out because of vertex: {0}", vertex); +#endif + goto CHECK_NEXT_CONSTRAINT; + } else { + // ... but it does satisfy the inequality >= +#if DEBUG_PRINT + Console.WriteLine("Widen checking: throwing out <= because of vertex: {0}", vertex); +#endif + cc = cc.ChangeRelationToAtLeast(); +#if DEBUG_PRINT + Console.WriteLine("Widen checking: left with constraint: {0}", cc); +#endif + } + } else if (cc.Relation == LinearConstraint.ConstraintRelation.EQ && lhs < cc.rhs) { + // the vertex does not satisfy the inequality >=, and the constraint is an equality constraint +#if DEBUG_PRINT + Console.WriteLine("Widen checking: throwing out >= because of vertex: {0}", vertex); +#endif + cc = cc.ChangeRelation(LinearConstraint.ConstraintRelation.LE); +#if DEBUG_PRINT + Console.WriteLine("Widen checking: left with contraint: {0}", cc); +#endif + } + } + + // PHASE II: verify constraints against all frame rays... + + foreach (FrameElement/*!*/ ray in cce.NonNull(lcs.FrameRays)) { + Contract.Assert(ray != null); + // The following assumes the constraint to have some dimension with a non-zero coefficient + Rational lhs = cc.EvaluateLhs(ray); + if (lhs.IsPositive) { + // the ray does not satisfy the inequality <= + if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { +#if DEBUG_PRINT + Console.WriteLine("Widen checking: throwing out because of ray: {0}", ray); +#endif + goto CHECK_NEXT_CONSTRAINT; + } else { + // ... but it does satisfy the inequality >= +#if DEBUG_PRINT + Console.WriteLine("Widen checking: throwing out <= because of ray: {0}", ray); +#endif + cc = cc.ChangeRelationToAtLeast(); +#if DEBUG_PRINT + Console.WriteLine("Widen checking: left with contraint: {0}", cc); +#endif + } + } else if (cc.Relation == LinearConstraint.ConstraintRelation.EQ && lhs.IsNegative) { + // the ray does not satisfy the inequality >=, and the constraint is an equality constraint +#if DEBUG_PRINT + Console.WriteLine("Widen checking: throwing out >= because of ray: {0}", ray); +#endif + cc = cc.ChangeRelation(LinearConstraint.ConstraintRelation.LE); +#if DEBUG_PRINT + Console.WriteLine("Widen checking: left with constraint: {0}", cc); +#endif + } + } + + // PHASE III: verify constraints against all frame lines... + + foreach (FrameElement/*!*/ line in cce.NonNull(lcs.FrameLines)) { + Contract.Assert(line != null); + // The following assumes the constraint to have some dimension with a non-zero coefficient + Rational lhs = cc.EvaluateLhs(line); + if (!lhs.IsZero) { + // The line satisfies neither the inequality <= nor the equality == +#if DEBUG_PRINT + Console.WriteLine("Widen checking: throwing out because of line: {0}", line); +#endif + goto CHECK_NEXT_CONSTRAINT; + } + } + + // constraint has been verified, so add to new constraint system +#if DEBUG_PRINT + Console.WriteLine("Widen checking: --Adding it!"); +#endif + newConstraints.Add(cc); + + CHECK_NEXT_CONSTRAINT: { + } +#if DEBUG_PRINT + Console.WriteLine("Widen checking: done with that constraint"); +#endif + } + + return new LinearConstraintSystem(newConstraints); + } + +#if DEBUG_PRINT + public LinearConstraintSystem Project(IVariable/*!*/ dim){ +Contract.Requires(dim != null); + Console.WriteLine("==================================================================================="); + Console.WriteLine("DEBUG: Project(dim={0})", dim); + Console.WriteLine("Project: this="); + Dump(); + LinearConstraintSystem z = ProjectX(dim); + Console.WriteLine("----------Project------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); + Console.WriteLine("Project: result="); + z.Dump(); + Console.WriteLine("==================================================================================="); + return z; + } +#endif + +#if DEBUG_PRINT + public LinearConstraintSystem ProjectX(IVariable/*!*/ dim){Contract.Requires(dim != null);Contract.Requires(this.Constraints != null); +#else + public LinearConstraintSystem/*!*/ Project(IVariable/*!*/ dim) { + Contract.Requires(dim != null); + Contract.Requires(this.Constraints != null); + Contract.Ensures(Contract.Result() != null); +#endif + + + ArrayList /*LinearConstraint!*//*!*/ cc = Project(dim, Constraints); + Contract.Assert(cc != null); + return new LinearConstraintSystem(cc); + } + +#if DEBUG_PRINT + public LinearConstraintSystem Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName){ +Contract.Requires(newName != null); +Contract.Requires(oldName != null); + Console.WriteLine("==================================================================================="); + Console.WriteLine("DEBUG: Rename(oldName={0}, newName={1})", oldName, newName); + Console.WriteLine("Rename: this="); + Dump(); + LinearConstraintSystem z = RenameX(oldName, newName); + Console.WriteLine("----------Rename------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); + Console.WriteLine("Rename: result="); + z.Dump(); + Console.WriteLine("==================================================================================="); + return z; + } +#endif + +#if DEBUG_PRINT + public LinearConstraintSystem RenameX(IVariable/*!*/ oldName, IVariable/*!*/ newName){Contract.Requires(oldName != null);Contract.Requires(newName != null); +#else + public LinearConstraintSystem/*!*/ Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName) { + Contract.Requires(oldName != null); + Contract.Requires(newName != null); + Contract.Ensures(Contract.Result() != null); +#endif + if (this.Constraints == null) { + System.Diagnostics.Debug.Assert(this.FrameVertices == null); + System.Diagnostics.Debug.Assert(this.FrameRays == null); + System.Diagnostics.Debug.Assert(this.FrameLines == null); + return this; + } + IMutableSet /*IVariable!*//*!*/ dims = this.FrameDimensions; + Contract.Assert(dims != null); + if (!dims.Contains(oldName)) { + return this; + } + + LinearConstraintSystem z = new LinearConstraintSystem(); + z.FrameDimensions = cce.NonNull((HashSet/*!*/ /*IVariable!*/)dims.Clone()); + z.FrameDimensions.Remove(oldName); + z.FrameDimensions.Add(newName); + + z.Constraints = new ArrayList /*LinearConstraint!*/ (this.Constraints.Count); + foreach (LinearConstraint/*!*/ lc in cce.NonNull(this.Constraints)) { + Contract.Assert(lc != null); + z.Constraints.Add(lc.Rename(oldName, newName)); + } + z.FrameVertices = RenameInFE(cce.NonNull(this.FrameVertices), oldName, newName); + z.FrameRays = RenameInFE(cce.NonNull(this.FrameRays), oldName, newName); + z.FrameLines = RenameInFE(cce.NonNull(this.FrameLines), oldName, newName); + return z; + } + + static ArrayList /*FrameElement*/ RenameInFE(ArrayList/*!*/ /*FrameElement*/ list, IVariable/*!*/ oldName, IVariable/*!*/ newName) { + Contract.Requires(list != null); + Contract.Requires(newName != null); + Contract.Requires(oldName != null); + ArrayList/*FrameElement!*//*!*/ z = new ArrayList/*FrameElement!*/ (list.Count); + Contract.Assert(z != null); + foreach (FrameElement/*!*/ fe in list) { + Contract.Assert(fe != null); + z.Add(fe.Rename(oldName, newName)); + } + System.Diagnostics.Debug.Assert(z.Count == list.Count); + return z; + } + + // -------------------------------------------------------------------------------------------------------- + // ------------------ support routines -------------------------------------------------------------------- + // -------------------------------------------------------------------------------------------------------- + + /// + /// Returns a set of constraints that is the given set of constraints with dimension "dim" + /// projected out. See Cousot and Halbwachs, section 3.3.1.1. + /// + /// + /// + /// + static ArrayList /*LinearConstraint!*//*!*/ Project(IVariable/*!*/ dim, ArrayList /*LinearConstraint!*//*!*/ constraints) { + Contract.Requires(constraints != null); + Contract.Requires(dim != null); + Contract.Ensures(Contract.Result() != null); + // Sort the inequality constaints into ones where dimension "dim" is 0, negative, and + // positive, respectively. Put equality constraints with a non-0 "dim" into "eq". + ArrayList /*LinearConstraint!*//*!*/ final = new ArrayList /*LinearConstraint!*/ (); + ArrayList /*LinearConstraint!*//*!*/ negative = new ArrayList /*LinearConstraint!*/ (); + ArrayList /*LinearConstraint!*//*!*/ positive = new ArrayList /*LinearConstraint!*/ (); + ArrayList /*LinearConstraint!*//*!*/ eq = new ArrayList /*LinearConstraint!*/ (); + foreach (LinearConstraint/*!*/ cc in constraints) { + Contract.Assert(cc != null); + Rational coeff = cc[dim]; + if (coeff.IsZero) { + LinearConstraint lc = cce.NonNull(cc.Clone()); + if (!lc.IsConstant()) { + lc.RemoveDimension(dim); + final.Add(lc); + } + } else if (cc.Relation == LinearConstraint.ConstraintRelation.EQ) { + eq.Add(cc); + } else if (coeff.IsNegative) { + negative.Add(cc); + } else { + System.Diagnostics.Debug.Assert(coeff.IsPositive); + positive.Add(cc); + } + } + + if (eq.Count != 0) { + LinearConstraint eqConstraint = (LinearConstraint/*!*/)cce.NonNull(eq[eq.Count - 1]); + eq.RemoveAt(eq.Count - 1); + Rational eqC = -eqConstraint[dim]; + + foreach (ArrayList /*LinearConstraint!*/ list in new ArrayList[] { eq, negative, positive }) { + Contract.Assert(list != null); + foreach (LinearConstraint/*!*/ lcX in list) { + Contract.Assert(lcX != null); + LinearConstraint lc = cce.NonNull(lcX.Clone()); + lc.AddMultiple(lc[dim] / eqC, eqConstraint); + System.Diagnostics.Debug.Assert(lc[dim].IsZero); + if (!lc.IsConstant()) { + lc.RemoveDimension(dim); + final.Add(lc); + } else { + System.Diagnostics.Debug.Assert(lc.IsConstantSatisfiable()); + } + } + } + } else { + // Consider all pairs of constraints with (negative,positive) coefficients of "dim". + foreach (LinearConstraint/*!*/ cn in negative) { + Contract.Assert(cn != null); + Rational dn = -cn[dim]; + System.Diagnostics.Debug.Assert(dn.IsNonNegative); + foreach (LinearConstraint/*!*/ cp in positive) { + Contract.Assert(cp != null); + Rational dp = cp[dim]; + + LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); + lc.AddMultiple(dn, cp); + lc.AddMultiple(dp, cn); + System.Diagnostics.Debug.Assert(lc[dim].IsZero); + if (!lc.IsConstant()) { + lc.RemoveDimension(dim); + final.Add(lc); + } else { + System.Diagnostics.Debug.Assert(lc.IsConstantSatisfiable()); + } + } + } + } + + return final; + } + + /// + /// Initializes FrameVertices, FrameRays, FrameLines, and FrameDimensions, see + /// Cousot and Halbwachs, section 3.4. Any previous values of these fields are + /// ignored and overwritten. + /// + /// If the set of Constraints is unsatisfiable, then "this" is changed into Bottom. + /// + void GenerateFrameFromConstraints() { + if (Constraints == null) { + FrameVertices = null; + FrameRays = null; + FrameLines = null; + FrameDimensions = new HashSet /*IVariable!*/ (); + return; + } + + // Step 1 (see Cousot and Halbwachs, section 3.4.3): create a Simplex Tableau. +#if DEBUG_PRINT + Console.WriteLine("DEBUG: --- GenerateFrameFromConstraint ---"); + Console.WriteLine("Constraints:"); + foreach (LinearConstraint cc in Constraints) + { + Console.WriteLine(" {0}", cc); + } +#endif + SimplexTableau tableau = new SimplexTableau(Constraints); +#if DEBUG_PRINT + Console.WriteLine("Initial tableau:"); + tableau.Dump(); +#endif + FrameDimensions = tableau.GetDimensions(); +#if DEBUG_PRINT + Console.WriteLine("Dimensions:"); + foreach (object dim in FrameDimensions) + { + Console.Write(" {0}", dim); + } + Console.WriteLine(); +#endif + + // Step 3 and 2: Put as many initial variables as possible into basis, then check if + // we reached a feasible basis + tableau.AddInitialVarsToBasis(); +#if DEBUG_PRINT + Console.WriteLine("Tableau after Step 3:"); + tableau.Dump(); +#endif + if (!tableau.IsFeasibleBasis) { + // The polyhedron is empty (according to Cousot and Halbwachs) + ChangeIntoBottom(); + return; + } + + FrameVertices = new ArrayList /*FrameElement*/ (); + FrameRays = new ArrayList /*FrameElement*/ (); + FrameLines = new ArrayList /*FrameElement*/ (); + if (FrameDimensions.Count == 0) { + // top element + return; + } + + if (tableau.AllInitialVarsInBasis) { + // All initial variables are in basis; there are no lines. +#if DEBUG_PRINT + Console.WriteLine("Tableau after Steps 2 and 3 (all initial variables in basis):"); + tableau.Dump(); +#endif + } else { + // There are lines +#if DEBUG_PRINT + Console.WriteLine("Tableau after Steps 2 and 3 (NOT all initial variables in basis--there are lines):"); + tableau.Dump(); +#endif + // Step 4.2: Pick out the lines, then produce the tableau for a new polyhedron without those lines. + ArrayList /*LinearConstraint*/ moreConstraints = cce.NonNull((ArrayList/*!*/ /*LinearConstraint*/)Constraints.Clone()); + tableau.ProduceLines(FrameLines, moreConstraints); + tableau = new SimplexTableau(moreConstraints); +#if DEBUG_PRINT + Console.WriteLine("Lines produced:"); + foreach (FrameElement line in FrameLines) + { + Console.WriteLine(" {0}", line); + } + Console.WriteLine("The new list of constraints is:"); + foreach (LinearConstraint c in moreConstraints) + { + Console.WriteLine(" {0}", c); + } + Console.WriteLine("Tableau after producing lines in Step 4.2:"); + tableau.Dump(); +#endif + + // Repeat step 3 for the new tableau. + // Since the new tableau contains no lines, the following call should cause all initial + // variables to be in basis (see step 4.2 in section 3.4.3 of Cousot and Halbwachs). + tableau.AddInitialVarsToBasis(); + System.Diagnostics.Debug.Assert(tableau.AllInitialVarsInBasis); + System.Diagnostics.Debug.Assert(tableau.IsFeasibleBasis); // the new tableau represents a set of feasible constraints, so this basis should be found to be feasible +#if DEBUG_PRINT + Console.WriteLine("Tableau after all initial variables have been moved into basis:"); + tableau.Dump(); +#endif + } + + // Step 4.1: One vertex has been found. Find all others, too. + tableau.TraverseVertices(FrameVertices, FrameRays); +#if DEBUG_PRINT + Console.WriteLine("Tableau after vertex traversal:"); + tableau.Dump(); +#endif + } + + class LambdaDimension : IVariable { + readonly int id; + static int count = 0; + + /// + /// Return the name of the variable + /// + public string Name { + get { + Contract.Ensures(Contract.Result() != null); + + return this.ToString(); + } + } + + public LambdaDimension() { + id = count; + count++; + } + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return "lambda" + id; + } + [Pure] + public object DoVisit(ExprVisitor/*!*/ visitor) { + //Contract.Requires(visitor != null); + return visitor.VisitVariable(this); + } + } + + /// + /// Adds a vertex to the frame of "this" and updates Constraints accordingly, see + /// Cousot and Halbwachs, section 3.3.1.1. However, this method does not simplify + /// Constraints after the operation; that remains the caller's responsibility (which + /// gives the caller the opportunity to make multiple calls to AddVertex, AddRay, + /// and AddLine before calling SimplifyConstraints). + /// Assumes Constraints (and the frame fields) to be non-null. + /// + /// + void AddVertex(FrameElement/*!*/ vertex) { + Contract.Requires(vertex != null); + Contract.Requires(this.FrameVertices != null); +#if DEBUG_PRINT + Console.WriteLine("DEBUG: AddVertex called on {0}", vertex); + Console.WriteLine(" Initial constraints:"); + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } +#endif + + FrameVertices.Add(vertex.Clone()); +#if FIXED_DESERIALIZER + Contract.Assert(Contract.ForAll(vertex.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); +#endif + + // We use a new temporary dimension. + IVariable/*!*/ lambda = new LambdaDimension(); + + // We change the constraints A*X <= B into + // A*X + (A*vector - B)*lambda <= A*vector. + // That means that each row k in A (which corresponds to one LinearConstraint + // in Constraints) is changed by adding + // (A*vector - B)[k] * lambda + // to row k and changing the right-hand side of row k to + // (A*vector)[k] + // Note: + // (A*vector - B)[k] + // = { vector subtraction is pointwise } + // (A*vector)[k] - B[k] + // = { A*vector is a row vector whose every row i is the dot-product of + // row i of A with the column vector "vector" } + // A[k]*vector - B[k] + foreach (LinearConstraint/*!*/ cc in cce.NonNull(Constraints)) { + Contract.Assert(cc != null); + Rational d = cc.EvaluateLhs(vertex); + cc.SetCoefficient(lambda, d - cc.rhs); + cc.rhs = d; + } + + // We also add the constraints that lambda lies between 0 ... + LinearConstraint la = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); + la.SetCoefficient(lambda, Rational.MINUS_ONE); + la.rhs = Rational.ZERO; + Constraints.Add(la); + // ... and 1. + la = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); + la.SetCoefficient(lambda, Rational.ONE); + la.rhs = Rational.ONE; + Constraints.Add(la); +#if DEBUG_PRINT + Console.WriteLine(" Constraints after addition:"); + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } +#endif + + // Finally, project out the dummy dimension. + Constraints = Project(lambda, Constraints); + +#if DEBUG_PRINT + Console.WriteLine(" Resulting constraints:"); + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } +#endif + } + + /// + /// Adds a ray to the frame of "this" and updates Constraints accordingly, see + /// Cousot and Halbwachs, section 3.3.1.1. However, this method does not simplify + /// Constraints after the operation; that remains the caller's responsibility (which + /// gives the caller the opportunity to make multiple calls to AddVertex, AddRay, + /// and AddLine before calling SimplifyConstraints). + /// Assumes Constraints (and the frame fields) to be non-null. + /// + /// + void AddRay(FrameElement/*!*/ ray) { + Contract.Requires(ray != null); + Contract.Requires(this.FrameRays != null); +#if DEBUG_PRINT + Console.WriteLine("DEBUG: AddRay called on {0}", ray); + Console.WriteLine(" Initial constraints:"); + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } +#endif + + FrameRays.Add(ray.Clone()); +#if FIXED_DESERIALIZER + Contract.Assert(Contract.ForAll(ray.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); +#endif + + // We use a new temporary dimension. + IVariable/*!*/ lambda = new LambdaDimension(); + + // We change the constraints A*X <= B into + // A*X - (A*ray)*lambda <= B. + // That means that each row k in A (which corresponds to one LinearConstraint + // in Constraints) is changed by subtracting + // (A*ray)[k] * lambda + // from row k. + // Note: + // (A*ray)[k] + // = { A*ray is a row vector whose every row i is the dot-product of + // row i of A with the column vector "ray" } + // A[k]*ray + foreach (LinearConstraint/*!*/ cc in cce.NonNull(Constraints)) { + Contract.Assert(cc != null); + Rational d = cc.EvaluateLhs(ray); + cc.SetCoefficient(lambda, -d); + } + + // We also add the constraints that lambda is at least 0. + LinearConstraint la = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); + la.SetCoefficient(lambda, Rational.MINUS_ONE); + la.rhs = Rational.ZERO; + Constraints.Add(la); +#if DEBUG_PRINT + Console.WriteLine(" Constraints after addition:"); + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } +#endif + + // Finally, project out the dummy dimension. + Constraints = Project(lambda, Constraints); + +#if DEBUG_PRINT + Console.WriteLine(" Resulting constraints:"); + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } +#endif + } + + /// + /// Adds a line to the frame of "this" and updates Constraints accordingly, see + /// Cousot and Halbwachs, section 3.3.1.1. However, this method does not simplify + /// Constraints after the operation; that remains the caller's responsibility (which + /// gives the caller the opportunity to make multiple calls to AddVertex, AddRay, + /// and AddLine before calling SimplifyConstraints). + /// Assumes Constraints (and the frame fields) to be non-null. + /// + /// + void AddLine(FrameElement/*!*/ line) { + Contract.Requires(line != null); + Contract.Requires(this.FrameLines != null); + // Note: The code for AddLine is identical to that of AddRay, except the AddLine + // does not introduce the constraint 0 <= lambda. (One could imagine sharing the + // code between AddRay and AddLine.) +#if DEBUG_PRINT + Console.WriteLine("DEBUG: AddLine called on {0}", line); + Console.WriteLine(" Initial constraints:"); + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } +#endif + + FrameLines.Add(line.Clone()); +#if FIXED_DESERIALIZER + Contract.Assert(Contract.ForAll(line.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); +#endif + + // We use a new temporary dimension. + IVariable/*!*/ lambda = new LambdaDimension(); + + // We change the constraints A*X <= B into + // A*X - (A*line)*lambda <= B. + // That means that each row k in A (which corresponds to one LinearConstraint + // in Constraints) is changed by subtracting + // (A*line)[k] * lambda + // from row k. + // Note: + // (A*line)[k] + // = { A*line is a row vector whose every row i is the dot-product of + // row i of A with the column vector "line" } + // A[k]*line + foreach (LinearConstraint/*!*/ cc in cce.NonNull(Constraints)) { + Contract.Assert(cc != null); + Rational d = cc.EvaluateLhs(line); + cc.SetCoefficient(lambda, -d); + } + +#if DEBUG_PRINT + Console.WriteLine(" Constraints after addition:"); + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } +#endif + + // Finally, project out the dummy dimension. + Constraints = Project(lambda, Constraints); + +#if DEBUG_PRINT + Console.WriteLine(" Resulting constraints:"); + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } +#endif + } + + ISet /*IVariable!*//*!*/ GetDefinedDimensions() { + Contract.Ensures(Contract.Result() != null); + HashSet /*IVariable!*//*!*/ dims = new HashSet /*IVariable!*/ (); + foreach (ArrayList p in new ArrayList[] { FrameVertices, FrameRays, FrameLines }) { + if (p != null) { + foreach (FrameElement/*!*/ element in p) { + Contract.Assert(element != null); + foreach (IVariable/*!*/ dim in element.GetDefinedDimensions()) { + Contract.Assert(dim != null); + dims.Add(dim); + } + } + } + } + return dims; + } + + // -------------------------------------------------------------------------------------------------------- + // ------------------ Simplification routines ------------------------------------------------------------- + // -------------------------------------------------------------------------------------------------------- + + /// + /// Uses the Constraints to simplify the frame. See section 3.4.4 of Cousot and Halbwachs. + /// + void SimplifyFrame() { + Contract.Requires(this.Constraints != null); + SimplificationStatus[]/*!*/ status; + + SimplifyFrameElements(cce.NonNull(FrameVertices), true, Constraints, out status); + RemoveIrrelevantFrameElements(FrameVertices, status, null); + + SimplifyFrameElements(cce.NonNull(FrameRays), false, Constraints, out status); + RemoveIrrelevantFrameElements(FrameRays, status, FrameLines); + } + + enum SimplificationStatus { + Irrelevant, + Relevant, + More + }; + + /// + /// For each i, sets status[i] to: + ///
    + ///
  • Irrelevant if ff[i] is irrelevant
  • + ///
  • Relevant if ff[i] is irrelevant
  • + ///
  • More if vertices is true and ray ff[i] can be replaced by a line ff[i]
  • + ///
+ ///
+ /// + /// true if "ff" contains vertices; false if "ff" contains rays + /// + /// + static void SimplifyFrameElements(ArrayList/*!*/ /*FrameElement*/ ff, bool vertices, ArrayList/*!*/ /*LinearConstraint*/ constraints, out SimplificationStatus[]/*!*/ status) { + Contract.Requires(ff != null); + Contract.Requires(constraints != null); + Contract.Ensures(Contract.ValueAtReturn(out status) != null); + status = new SimplificationStatus[ff.Count]; + bool[,] sat = new bool[ff.Count, constraints.Count]; + for (int i = 0; i < ff.Count; i++) { + FrameElement f = (FrameElement/*!*/)cce.NonNull(ff[i]); + int cnt = 0; + for (int c = 0; c < constraints.Count; c++) { + LinearConstraint lc = (LinearConstraint/*!*/)cce.NonNull(constraints[c]); + bool s = lc.IsSaturatedBy(f, vertices); + if (s) { + sat[i, c] = true; + cnt++; + } + } + if (!vertices && cnt == constraints.Count) { + status[i] = SimplificationStatus.More; + } else { + status[i] = SimplificationStatus.Relevant; + } + } + + CheckPairSimplifications(sat, status); + } + + /// + /// Requires sat.GetLength(0) == status.Length. + /// + /// + /// + static void CheckPairSimplifications(bool[,]/*!*/ sat, SimplificationStatus[]/*!*/ status) { + Contract.Requires(status != null); + Contract.Requires(sat != null); + Contract.Requires(sat.GetLength(0) == status.Length); + int M = sat.GetLength(0); + int N = sat.GetLength(1); + + for (int i = 0; i < M - 1; i++) { + if (status[i] != SimplificationStatus.Relevant) { + continue; + } + for (int j = i + 1; j < M; j++) { + if (status[j] != SimplificationStatus.Relevant) { + continue; + } + // check (sat[i,*] <= sat[j,*]) and (sat[i,*] >= sat[j,*]) + int cmp = 0; // -1: (sat[i,*] <= sat[j,*]), 0: equal, 1: (sat[i,*] >= sat[j,*]) + for (int c = 0; c < N; c++) { + if (cmp < 0) { + if (sat[i, c] && !sat[j, c]) { + // incomparable + goto NEXT_PAIR; + } + } else if (0 < cmp) { + if (!sat[i, c] && sat[j, c]) { + // incomparable + goto NEXT_PAIR; + } + } else if (sat[i, c] != sat[j, c]) { + if (!sat[i, c]) { + cmp = -1; + } else { + cmp = 1; + } + } + } + if (cmp <= 0) { + // sat[i,*] <= sat[j,*] holds, so mark i as irrelevant + status[i] = SimplificationStatus.Irrelevant; + goto NEXT_OUTER; + } else { + // sat[i,*] >= sat[j,*] holds, so mark j as irrelevant + status[j] = SimplificationStatus.Irrelevant; + } + NEXT_PAIR: { + } + } + NEXT_OUTER: { + } + } + } + + static void RemoveIrrelevantFrameElements(ArrayList/*!*/ /*FrameElement*/ ff, SimplificationStatus[]/*!*/ status, + /*maybe null*/ ArrayList /*FrameElement*/ lines) { + Contract.Requires(ff != null); + Contract.Requires(status != null); + Contract.Requires(ff.Count == status.Length); + for (int j = ff.Count - 1; 0 <= j; j--) { + switch (status[j]) { + case SimplificationStatus.Relevant: + break; + case SimplificationStatus.Irrelevant: +#if DEBUG_PRINT + Console.WriteLine("Removing irrelevant {0}: {1}", lines == null ? "vertex" : "ray", ff[j]); +#endif + ff.RemoveAt(j); + break; + case SimplificationStatus.More: + System.Diagnostics.Debug.Assert(lines != null); + FrameElement f = (FrameElement)ff[j]; +#if DEBUG_PRINT + Console.WriteLine("Changing ray into line: {0}", f); +#endif + ff.RemoveAt(j); + Contract.Assert(lines != null); + lines.Add(f); + break; + } + } + } + + /// + /// Uses the frame to simplify Constraints. See section 3.3.1.2 of Cousot and Halbwachs. + /// + /// Note: This code does not necessarily eliminate all irrelevant equalities; Cousot and + /// Halbwachs only claim that the technique eliminates all irrelevant inequalities. + /// + void SimplifyConstraints() { + if (Constraints == null) { + return; + } + Contract.Assume(this.FrameVertices != null); + Contract.Assume(this.FrameRays != null); + + SimplificationStatus[] status = new SimplificationStatus[Constraints.Count]; + /*readonly*/ + int feCount = FrameVertices.Count + FrameRays.Count; + + // Create a table that keeps track of which constraints are satisfied by which vertices and rays + bool[,] sat = new bool[Constraints.Count, FrameVertices.Count + FrameRays.Count]; + for (int i = 0; i < Constraints.Count; i++) { + status[i] = SimplificationStatus.Relevant; + LinearConstraint lc = (LinearConstraint/*!*/)cce.NonNull(Constraints[i]); + int cnt = 0; // number of vertices and rays that saturate lc + for (int j = 0; j < FrameVertices.Count; j++) { + FrameElement vertex = (FrameElement/*!*/)cce.NonNull(FrameVertices[j]); + if (lc.IsSaturatedBy(vertex, true)) { + sat[i, j] = true; + cnt++; + } + } + if (cnt == 0) { + // no vertex saturates the constraint, so the constraint is irrelevant + status[i] = SimplificationStatus.Irrelevant; + continue; + } + for (int j = 0; j < FrameRays.Count; j++) { + FrameElement ray = (FrameElement/*!*/)cce.NonNull(FrameRays[j]); + if (lc.IsSaturatedBy(ray, false)) { + sat[i, FrameVertices.Count + j] = true; + cnt++; + } + } + if (cnt == feCount) { + status[i] = SimplificationStatus.More; + } else { + // Cousot and Halbwachs says that all equalities are found in the way we just tested. + // If I understand that right, then we should not get here if the constraint is an + // equality constraint. The following assertion tests my understanding. --KRML + System.Diagnostics.Debug.Assert(lc.Relation == LinearConstraint.ConstraintRelation.LE); + } + } + + CheckPairSimplifications(sat, status); + + // Finally, make the changes to the list of constraints + for (int i = Constraints.Count - 1; 0 <= i; i--) { + switch (status[i]) { + case SimplificationStatus.Relevant: + break; + case SimplificationStatus.Irrelevant: +#if DEBUG_PRINT + Console.WriteLine("Removing irrelevant constraint: {0}", Constraints[i]); +#endif + Constraints.RemoveAt(i); + break; + case SimplificationStatus.More: + LinearConstraint lc = (LinearConstraint/*!*/)cce.NonNull(Constraints[i]); + if (lc.Relation == LinearConstraint.ConstraintRelation.LE) { +#if DEBUG_PRINT + Console.WriteLine("Converting the following constraint into an equality: {0}", lc); +#endif + LinearConstraint lcEq = lc.ChangeRelation(LinearConstraint.ConstraintRelation.EQ); + Constraints[i] = lcEq; + } + break; + } + } + + foreach (LinearConstraint/*!*/ lc in Constraints) { + Contract.Assert(lc != null); + lc.Normalize(); + } + } + + // -------------------------------------------------------------------------------------------------------- + // ------------------ Cloning routines -------------------------------------------------------------------- + // -------------------------------------------------------------------------------------------------------- + + public LinearConstraintSystem/*!*/ Clone() { + Contract.Ensures(Contract.Result() != null); + LinearConstraintSystem z = new LinearConstraintSystem(); + z.FrameDimensions = (IMutableSet /*IVariable!*//*!*/)cce.NonNull(this.FrameDimensions.Clone()); + if (this.Constraints != null) { + z.Constraints = DeeperListCopy_LC(this.Constraints); + z.FrameVertices = DeeperListCopy_FE(cce.NonNull(this.FrameVertices)); + z.FrameRays = DeeperListCopy_FE(cce.NonNull(this.FrameRays)); + z.FrameLines = DeeperListCopy_FE(cce.NonNull(this.FrameLines)); + } else { + System.Diagnostics.Debug.Assert(this.FrameVertices == null); + System.Diagnostics.Debug.Assert(this.FrameRays == null); + System.Diagnostics.Debug.Assert(this.FrameLines == null); + // the constructor should already have set these fields of z to null + System.Diagnostics.Debug.Assert(z.Constraints == null); + System.Diagnostics.Debug.Assert(z.FrameVertices == null); + System.Diagnostics.Debug.Assert(z.FrameRays == null); + System.Diagnostics.Debug.Assert(z.FrameLines == null); + } + return z; + } + + /// + /// Clones "list" and the elements of "list". + /// + /// + /// + ArrayList /*LinearConstraint*/ DeeperListCopy_LC(ArrayList/*!*/ /*LinearConstraint*/ list) { + Contract.Requires(list != null); + ArrayList /*LinearConstraint*/ z = new ArrayList /*LinearConstraint*/ (list.Count); + foreach (LinearConstraint/*!*/ lc in list) { + Contract.Assert(lc != null); + z.Add(lc.Clone()); + } + System.Diagnostics.Debug.Assert(z.Count == list.Count); + return z; + } + + /// + /// Clones "list" and the elements of "list". + /// + /// + /// + ArrayList /*FrameElement*/ DeeperListCopy_FE(ArrayList/*!*/ /*FrameElement*/ list) { + Contract.Requires(list != null); + ArrayList /*FrameElement*/ z = new ArrayList /*FrameElement*/ (list.Count); + foreach (FrameElement/*!*/ fe in list) { + Contract.Assert(fe != null); + z.Add(fe.Clone()); + } + System.Diagnostics.Debug.Assert(z.Count == list.Count); + return z; + } + + // -------------------------------------------------------------------------------------------------------- + // ------------------ Debugging and unit test routines ---------------------------------------------------- + // -------------------------------------------------------------------------------------------------------- + + public void Dump() { + Console.WriteLine(" Constraints:"); + if (Constraints == null) { + Console.WriteLine(" "); + } else { + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } + } + + Console.WriteLine(" FrameDimensions: {0}", FrameDimensions); + + Console.WriteLine(" FrameVerticies:"); + if (FrameVertices == null) { + Console.WriteLine(" "); + } else { + foreach (FrameElement fe in FrameVertices) { + Console.WriteLine(" {0}", fe); + } + } + + Console.WriteLine(" FrameRays:"); + if (FrameRays == null) { + Console.WriteLine(" "); + } else { + foreach (FrameElement fe in FrameRays) { + Console.WriteLine(" {0}", fe); + } + } + + Console.WriteLine(" FrameLines:"); + if (FrameLines == null) { + Console.WriteLine(" "); + } else { + foreach (FrameElement fe in FrameLines) { + Console.WriteLine(" {0}", fe); + } + } + } + + class TestVariable : IVariable { + readonly string/*!*/ name; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(name != null); + } + + + public string/*!*/ Name { + get { + Contract.Ensures(Contract.Result() != null); + + return name; + } + } + + public TestVariable(string/*!*/ name) { + Contract.Requires(name != null); + this.name = name; + } + [Pure] + public object DoVisit(ExprVisitor/*!*/ visitor) { + //Contract.Requires(visitor != null); + return visitor.VisitVariable(this); + } + } + + public static void RunValidationA() { + IVariable/*!*/ dim1 = new TestVariable("X"); + IVariable/*!*/ dim2 = new TestVariable("Y"); + IVariable/*!*/ dim3 = new TestVariable("Z"); + Contract.Assert(dim1 != null); + Contract.Assert(dim2 != null); + Contract.Assert(dim3 != null); + + FrameElement s1 = new FrameElement(); + s1.AddCoordinate(dim1, Rational.ONE); + s1.AddCoordinate(dim2, Rational.MINUS_ONE); + s1.AddCoordinate(dim3, Rational.ZERO); + FrameElement s2 = new FrameElement(); + s2.AddCoordinate(dim1, Rational.MINUS_ONE); + s2.AddCoordinate(dim2, Rational.ONE); + s2.AddCoordinate(dim3, Rational.ZERO); + FrameElement r1 = new FrameElement(); + r1.AddCoordinate(dim1, Rational.ZERO); + r1.AddCoordinate(dim2, Rational.ZERO); + r1.AddCoordinate(dim3, Rational.ONE); + FrameElement d1 = new FrameElement(); + d1.AddCoordinate(dim1, Rational.ONE); + d1.AddCoordinate(dim2, Rational.ONE); + d1.AddCoordinate(dim3, Rational.ZERO); + + // create lcs from frame -- cf. Cousot/Halbwachs 1978, section 3.3.1.1 + LinearConstraintSystem lcs = new LinearConstraintSystem(s1); + lcs.Dump(); + + lcs.AddVertex(s2); + lcs.Dump(); + + lcs.AddRay(r1); + lcs.Dump(); + + lcs.AddLine(d1); + lcs.Dump(); + + lcs.SimplifyConstraints(); + lcs.Dump(); + +#if LATER + lcs.GenerateFrameFromConstraints(); // should give us back the original frame... +#endif + Console.WriteLine("IsSubset? {0}", lcs.IsSubset(lcs.Clone())); + lcs.Dump(); + } + + /// + /// Tests the example in section 3.4.3 of Cousot and Halbwachs. + /// + public static void RunValidationB() { + IVariable/*!*/ X = new TestVariable("X"); + IVariable/*!*/ Y = new TestVariable("Y"); + IVariable/*!*/ Z = new TestVariable("Z"); + Contract.Assert(X != null); + Contract.Assert(Y != null); + Contract.Assert(Z != null); + ArrayList /*LinearConstraint*/ cs = new ArrayList /*LinearConstraint*/ (); + + LinearConstraint c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); + c.SetCoefficient(X, Rational.MINUS_ONE); + c.SetCoefficient(Y, Rational.ONE); + c.SetCoefficient(Z, Rational.MINUS_ONE); + c.rhs = Rational.ZERO; + cs.Add(c); + + c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); + c.SetCoefficient(X, Rational.MINUS_ONE); + c.rhs = Rational.MINUS_ONE; + cs.Add(c); + + c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); + c.SetCoefficient(X, Rational.MINUS_ONE); + c.SetCoefficient(Y, Rational.MINUS_ONE); + c.SetCoefficient(Z, Rational.ONE); + c.rhs = Rational.ZERO; + cs.Add(c); + + c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); + c.SetCoefficient(Y, Rational.MINUS_ONE); + c.SetCoefficient(Z, Rational.ONE); + c.rhs = Rational.FromInt(3); + cs.Add(c); + + LinearConstraintSystem lcs = new LinearConstraintSystem(cs); + Console.WriteLine("==================== The final linear constraint system ===================="); + lcs.Dump(); + } + + public static void RunValidationC() { + // Run the example in section 3.4.3 of Cousot and Halbwachs backwards, that is, from + // from to constraints. + IVariable/*!*/ dim1 = new TestVariable("X"); + IVariable/*!*/ dim2 = new TestVariable("Y"); + IVariable/*!*/ dim3 = new TestVariable("Z"); + Contract.Assert(dim1 != null); + Contract.Assert(dim2 != null); + Contract.Assert(dim3 != null); + + FrameElement s0 = new FrameElement(); + s0.AddCoordinate(dim1, Rational.ONE); + s0.AddCoordinate(dim2, Rational.FromInts(1, 2)); + s0.AddCoordinate(dim3, Rational.FromInts(-1, 2)); + + FrameElement s1 = new FrameElement(); + s1.AddCoordinate(dim1, Rational.ONE); + s1.AddCoordinate(dim2, Rational.FromInts(-1, 2)); + s1.AddCoordinate(dim3, Rational.FromInts(1, 2)); + + FrameElement s2 = new FrameElement(); + s2.AddCoordinate(dim1, Rational.FromInt(3)); + s2.AddCoordinate(dim2, Rational.FromInts(-3, 2)); + s2.AddCoordinate(dim3, Rational.FromInts(3, 2)); + + FrameElement r0 = new FrameElement(); + r0.AddCoordinate(dim1, Rational.ONE); + r0.AddCoordinate(dim2, Rational.FromInts(1, 2)); + r0.AddCoordinate(dim3, Rational.FromInts(-1, 2)); + + FrameElement r1 = new FrameElement(); + r1.AddCoordinate(dim1, Rational.ONE); + r1.AddCoordinate(dim2, Rational.ZERO); + r1.AddCoordinate(dim3, Rational.ZERO); + + FrameElement d0 = new FrameElement(); + d0.AddCoordinate(dim1, Rational.ZERO); + d0.AddCoordinate(dim2, Rational.ONE); + d0.AddCoordinate(dim3, Rational.ONE); + + LinearConstraintSystem lcs = new LinearConstraintSystem(s0); + lcs.Dump(); + + lcs.AddVertex(s1); + lcs.Dump(); + + lcs.AddVertex(s2); + lcs.Dump(); + + lcs.AddRay(r0); + lcs.Dump(); + + lcs.AddRay(r1); + lcs.Dump(); + + lcs.AddLine(d0); + lcs.Dump(); + + lcs.SimplifyConstraints(); + lcs.Dump(); + +#if LATER + lcs.GenerateFrameFromConstraints(); // should give us back the original frame... +#endif + } + } } \ No newline at end of file diff --git a/Source/AIFramework/Polyhedra/PolyhedraAbstraction.cs b/Source/AIFramework/Polyhedra/PolyhedraAbstraction.cs index 06c0f483..6c914a54 100644 --- a/Source/AIFramework/Polyhedra/PolyhedraAbstraction.cs +++ b/Source/AIFramework/Polyhedra/PolyhedraAbstraction.cs @@ -1,762 +1,762 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework { - using System; - using System.Collections; - using System.Collections.Generic; - using System.Diagnostics; - using System.Diagnostics.Contracts; - using Microsoft.Basetypes; - - using ISet = Microsoft.Boogie.GSet; - using HashSet = Microsoft.Boogie.GSet; - - /// - /// Represents an invariant over linear variable constraints, represented by a polyhedron. - /// - public class PolyhedraLattice : Lattice { - private static readonly Logger/*!*/ log = new Logger("Polyhedra"); - - private class PolyhedraLatticeElement : Element { - - public LinearConstraintSystem/*!*/ lcs; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(lcs != null); - } - - - /// - /// Creates a top or bottom elements, according to parameter "top". - /// - public PolyhedraLatticeElement(bool top) { - if (top) { - lcs = new LinearConstraintSystem(new ArrayList /*LinearConstraint*/ ()); - } else { - lcs = new LinearConstraintSystem(); - } - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return lcs.ToString(); - } - - public override void Dump(string/*!*/ msg) { - //Contract.Requires(msg != null); - System.Console.WriteLine("PolyhedraLatticeElement.Dump({0}):", msg); - lcs.Dump(); - } - - [Pure] - public override ICollection/*!*/ FreeVariables() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return lcs.FreeVariables(); - } - - public PolyhedraLatticeElement(LinearConstraintSystem/*!*/ lcs) { - Contract.Requires(lcs != null); - this.lcs = lcs; - } - - public override Element/*!*/ Clone() { - Contract.Ensures(Contract.Result() != null); - return new PolyhedraLatticeElement(cce.NonNull(lcs.Clone())); - } - - } // class - - readonly ILinearExprFactory/*!*/ factory; - readonly IPropExprFactory/*!*/ propFactory; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(log != null); - Contract.Invariant(factory != null); - Contract.Invariant(propFactory != null); - } - - - public PolyhedraLattice(ILinearExprFactory/*!*/ linearFactory, IPropExprFactory/*!*/ propFactory) - : base(linearFactory) { - Contract.Requires(propFactory != null); - Contract.Requires(linearFactory != null); - log.Enabled = Lattice.LogSwitch; - this.factory = linearFactory; - this.propFactory = propFactory; - // base(linearFactory); - } - - public override Element/*!*/ Top { - get { - Contract.Ensures(Contract.Result() != null); - return new PolyhedraLatticeElement(true); - } - } - - public override Element/*!*/ Bottom { - get { - Contract.Ensures(Contract.Result() != null); - - return new PolyhedraLatticeElement(false); - } - } - - public override bool IsBottom(Element/*!*/ element) { - //Contract.Requires(element != null); - PolyhedraLatticeElement e = (PolyhedraLatticeElement)element; - return e.lcs.IsBottom(); - } - - public override bool IsTop(Element/*!*/ element) { - //Contract.Requires(element != null); - PolyhedraLatticeElement e = (PolyhedraLatticeElement)element; - return e.lcs.IsTop(); - } - - - /// - /// Returns true iff a is a subset of this. - /// - /// - /// - protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that - { - //Contract.Requires(first != null); - //Contract.Requires(second != null); - PolyhedraLatticeElement a = (PolyhedraLatticeElement)first; - PolyhedraLatticeElement b = (PolyhedraLatticeElement)second; - return b.lcs.IsSubset(a.lcs); - } - - - public override string/*!*/ ToString(Element/*!*/ e) { - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - return ((PolyhedraLatticeElement)e).lcs.ToString(); - } - - public override IExpr/*!*/ ToPredicate(Element/*!*/ element) { - //Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - PolyhedraLatticeElement e = (PolyhedraLatticeElement)element; - return e.lcs.ConvertToExpression(factory); - } - - - - public override Lattice.Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - log.DbgMsg("Joining ..."); - log.DbgMsgIndent(); - PolyhedraLatticeElement aa = (PolyhedraLatticeElement)first; - PolyhedraLatticeElement bb = (PolyhedraLatticeElement)second; - PolyhedraLatticeElement result = new PolyhedraLatticeElement(aa.lcs.Join(bb.lcs)); - log.DbgMsg(string.Format("{0} |_| {1} --> {2}", this.ToString(first), this.ToString(second), this.ToString(result))); - log.DbgMsgUnindent(); - return result; - } - - - public override Lattice.Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - PolyhedraLatticeElement aa = (PolyhedraLatticeElement)first; - PolyhedraLatticeElement bb = (PolyhedraLatticeElement)second; - return new PolyhedraLatticeElement(aa.lcs.Meet(bb.lcs)); - } - - - public override Lattice.Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - log.DbgMsg("Widening ..."); - log.DbgMsgIndent(); - PolyhedraLatticeElement aa = (PolyhedraLatticeElement)first; - PolyhedraLatticeElement bb = (PolyhedraLatticeElement)second; - - LinearConstraintSystem lcs = aa.lcs.Widen(bb.lcs); - PolyhedraLatticeElement result = new PolyhedraLatticeElement(lcs); - log.DbgMsg(string.Format("{0} |_| {1} --> {2}", this.ToString(first), this.ToString(second), this.ToString(result))); - log.DbgMsgUnindent(); - return result; - } - - - public override Element/*!*/ Eliminate(Element/*!*/ e, IVariable/*!*/ variable) { - //Contract.Requires(variable != null); - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - log.DbgMsg(string.Format("Eliminating {0} ...", variable)); - - PolyhedraLatticeElement ple = (PolyhedraLatticeElement)e; - if (ple.lcs.IsBottom()) { - return ple; - } - return new PolyhedraLatticeElement(ple.lcs.Project(variable)); - } - - - public override Element/*!*/ Rename(Element/*!*/ e, IVariable/*!*/ oldName, IVariable/*!*/ newName) { - //Contract.Requires(newName != null); - //Contract.Requires(oldName != null); - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - log.DbgMsg(string.Format("Renaming {0} to {1} in {2} ...", oldName, newName, this.ToString(e))); - - PolyhedraLatticeElement ple = (PolyhedraLatticeElement)e; - if (ple.lcs.IsBottom()) { - return ple; - } - return new PolyhedraLatticeElement(ple.lcs.Rename(oldName, newName)); - } - - public override bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args) { - //Contract.Requires(args != null); - //Contract.Requires(f != null); - return f is IntSymbol || - f.Equals(Int.Add) || - f.Equals(Int.Sub) || - f.Equals(Int.Negate) || - f.Equals(Int.Mul) || - f.Equals(Int.Eq) || - f.Equals(Int.Neq) || - f.Equals(Prop.Not) || - f.Equals(Int.AtMost) || - f.Equals(Int.Less) || - f.Equals(Int.Greater) || - f.Equals(Int.AtLeast); - } - - public override Answer CheckVariableDisequality(Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2) { - //Contract.Requires(var2 != null); - //Contract.Requires(var1 != null); - //Contract.Requires(e != null); - PolyhedraLatticeElement/*!*/ ple = (PolyhedraLatticeElement)cce.NonNull(e); - Contract.Assume(ple.lcs.Constraints != null); - ArrayList /*LinearConstraint!*//*!*/ clist = (ArrayList /*LinearConstraint!*/)cce.NonNull(ple.lcs.Constraints.Clone()); - LinearConstraint/*!*/ lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ); - Contract.Assert(lc != null); - lc.SetCoefficient(var1, Rational.ONE); - lc.SetCoefficient(var2, Rational.MINUS_ONE); - clist.Add(lc); - LinearConstraintSystem newLcs = new LinearConstraintSystem(clist); - if (newLcs.IsBottom()) { - return Answer.Yes; - } else { - return Answer.Maybe; - } - } - - public override Answer CheckPredicate(Element/*!*/ e, IExpr/*!*/ pred) { - //Contract.Requires(pred != null); - //Contract.Requires(e != null); - PolyhedraLatticeElement/*!*/ ple = (PolyhedraLatticeElement)Constrain(e, pred); - Contract.Assert(ple != null); - if (ple.lcs.IsBottom()) { - return Answer.No; - } - - // Note, "pred" may contain expressions that are not understood by the propFactory (in - // particular, this may happen because--currently, and perhaps is a design we'll want - // to change in the future--propFactory deals with BoogiePL expressions whereas "pred" - // may also refer to Equivalences.UninterpFun expressions). Thus, we cannot just - // call propFactory.Not(pred) to get the negation of "pred". - pred = new PolyhedraLatticeNegation(pred); - ple = (PolyhedraLatticeElement)Constrain(e, pred); - if (ple.lcs.IsBottom()) { - return Answer.Yes; - } else { - return Answer.Maybe; - } - } - - class PolyhedraLatticeNegation : IFunApp { - IExpr/*!*/ arg; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(arg != null); - } - - - public PolyhedraLatticeNegation(IExpr/*!*/ arg) { - Contract.Requires(arg != null); - this.arg = arg; - // base(); - } - - [Pure] - public object DoVisit(ExprVisitor/*!*/ visitor) { - //Contract.Requires(visitor != null); - return visitor.VisitFunApp(this); - } - - public IFunctionSymbol/*!*/ FunctionSymbol { - get { - Contract.Ensures(Contract.Result() != null); - return Prop.Not; - } - } - - public IList/**//*!*/ Arguments { - get { - Contract.Ensures(Contract.Result() != null); - - IExpr[] args = new IExpr[] { arg }; - return ArrayList.ReadOnly(args); - } - } - - public IFunApp/*!*/ CloneWithArguments(IList/**//*!*/ args) { - //Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - Contract.Assert(args.Count == 1); - return new PolyhedraLatticeNegation((IExpr/*!*/)cce.NonNull(args[0])); - } - } - - public override IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, ISet/**//*!*/ prohibitedVars) { - //Contract.Requires(prohibitedVars != null); - //Contract.Requires(var != null); - //Contract.Requires(expr != null); - //Contract.Requires(q != null); - //Contract.Requires(e != null); - // BUGBUG: TODO: this method can be implemented in a more precise way - return null; - } - - - public override Element/*!*/ Constrain(Element/*!*/ e, IExpr/*!*/ expr) { - //Contract.Requires(expr != null); - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - log.DbgMsg(string.Format("Constraining with {0} into {1} ...", expr, this.ToString(e))); - - PolyhedraLatticeElement ple = (PolyhedraLatticeElement)e; - if (ple.lcs.IsBottom()) { - return ple; - } - LinearCondition le = LinearExpressionBuilder.AsCondition(expr); - if (le != null) { - // update the polyhedron according to the linear expression - Contract.Assume(ple.lcs.Constraints != null); - ArrayList /*LinearConstraint*/ clist = (ArrayList/*!*/ /*LinearConstraint*/)cce.NonNull(ple.lcs.Constraints.Clone()); - le.AddToConstraintSystem(clist); - LinearConstraintSystem newLcs = new LinearConstraintSystem(clist); - - return new PolyhedraLatticeElement(newLcs); - } - return ple; - } - - } // class - - - /// - /// A LinearCondition follows this grammar: - /// LinearCondition ::= unsatisfiable - /// | LinearConstraint - /// | ! LinearConstraint - /// Note that negations are distributed to the leaves. - /// - /// - [ContractClass(typeof(LinearConditionContracts))] - abstract class LinearCondition { - /// - /// Adds constraints to the list "clist". If "this" - /// entails some disjunctive constraints, they may not be added. - /// - /// - public abstract void AddToConstraintSystem(ArrayList/*!*/ /*LinearConstraint*/ clist); - } - [ContractClassFor(typeof(LinearCondition))] - abstract class LinearConditionContracts : LinearCondition { - public override void AddToConstraintSystem(ArrayList clist) { - Contract.Requires(clist != null); - throw new NotImplementedException(); - } - } - - class LCBottom : LinearCondition { - public override void AddToConstraintSystem(ArrayList/*!*/ /*LinearConstraint*/ clist) { - //Contract.Requires(clist != null); - // make an unsatisfiable constraint - LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ); - lc.rhs = Rational.FromInt(1); - clist.Add(lc); - } - } - - class LinearConditionLiteral : LinearCondition { - public readonly bool positive; - public readonly LinearConstraint/*!*/ constraint; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(constraint != null); - } - - /// - /// Precondition: positive || constraint.Relation == LinearConstraint.ConstraintRelation.EQ - /// - /// - /// - public LinearConditionLiteral(bool positive, LinearConstraint/*!*/ constraint) { - Contract.Requires(constraint != null); - Contract.Requires(positive || constraint.Relation == LinearConstraint.ConstraintRelation.EQ); - this.positive = positive; - this.constraint = constraint; - } - public override void AddToConstraintSystem(ArrayList/*!*/ /*LinearConstraint*/ clist) { - //Contract.Requires(clist != null); - if (positive) { - clist.Add(constraint); - } else { - Contract.Assert(constraint.Relation == LinearConstraint.ConstraintRelation.EQ); - // the constraint is disjunctive, so just ignore it - } - } - } - - class LinearExpressionBuilder { - /// - /// Builds a linear condition from "e", if possible; returns null if not possible. - /// - /// - /// - public static /*maybe null*/ LinearCondition AsCondition(IExpr e) /* throws ArithmeticException */ - { - return GetCond(e, true); - } - - static /*maybe null*/ LinearCondition GetCond(IExpr e, bool positive) /* throws ArithmeticException */ - { - IFunApp funapp = e as IFunApp; - if (funapp == null) { - return null; - } - IFunctionSymbol/*!*/ s = funapp.FunctionSymbol; - Contract.Assert(s != null); - if ((positive && s.Equals(Prop.False)) || - (!positive && s.Equals(Prop.True))) { - return new LCBottom(); - } else if (s.Equals(Prop.Not)) { - Contract.Assert(funapp.Arguments.Count == 1); - return GetCond((IExpr/*!*/)cce.NonNull(funapp.Arguments[0]), !positive); - } else if (funapp.Arguments.Count == 2) { - IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[0]); - IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[1]); - LinearExpr le0 = AsExpr(arg0); - if (le0 == null) { - return null; - } - LinearExpr le1 = AsExpr(arg1); - if (le1 == null) { - return null; - } - - LinearConstraint constraint = null; - bool sense = true; - if ((positive && s.Equals(Int.Less)) || (!positive && s.Equals(Int.AtLeast))) { - constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.LE, BigNum.ONE); - } else if ((positive && s.Equals(Int.AtMost)) || (!positive && s.Equals(Int.Greater))) { - constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.LE, BigNum.ZERO); - } else if ((positive && s.Equals(Int.AtLeast)) || (!positive && s.Equals(Int.Less))) { - constraint = MakeConstraint(le1, le0, LinearConstraint.ConstraintRelation.LE, BigNum.ZERO); - } else if ((positive && s.Equals(Int.Greater)) || (!positive && s.Equals(Int.AtMost))) { - constraint = MakeConstraint(le1, le0, LinearConstraint.ConstraintRelation.LE, BigNum.ONE); - } else if (s.Equals(Int.Eq)) { - constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.EQ, BigNum.ZERO); - sense = positive; - } else if (s.Equals(Int.Neq)) { - constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.EQ, BigNum.ZERO); - sense = !positive; - } - if (constraint != null) { - if (constraint.coefficients.Count != 0) { - return new LinearConditionLiteral(sense, constraint); - } else if (constraint.IsConstantSatisfiable()) { - return null; - } else { - return new LCBottom(); - } - } - } - return null; - } - - public static LinearConstraint MakeConstraint(LinearExpr/*!*/ le0, LinearExpr/*!*/ le1, - LinearConstraint.ConstraintRelation rel, BigNum constantOffset) /* throws ArithmeticException */ - { - Contract.Requires(le0 != null); - Contract.Requires(le1 != null); - le1.Negate(); - le0.Add(le1); - le0.AddConstant(constantOffset); - return le0.ToConstraint(rel); - } - - /// - /// Builds a linear expression from "e", if possible; returns null if not possible. - /// - /// - /// - public static /*maybe null*/ LinearExpr AsExpr(IExpr/*!*/ e) /* throws ArithmeticException */ - { - Contract.Requires(e != null); - if (e is IVariable) { - // Note, without a type for the variable, we don't know if the identifier is intended to hold an integer value. - // However, it seems that no harm can be caused by here treating the identifier as if it held an - // integer value, because other parts of this method will reject the expression as a linear expression - // if non-numeric operations other than equality are applied to the identifier. - return new LinearExpr((IVariable)e); - } else if (e is IFunApp) { - IFunApp/*!*/ funapp = (IFunApp)e; - Contract.Assert(funapp != null); - IFunctionSymbol/*!*/ s = funapp.FunctionSymbol; - Contract.Assert(s != null); - - if (s is IntSymbol) { - return new LinearExpr(((IntSymbol)s).Value); - } else if (s.Equals(Int.Negate)) { - Contract.Assert(funapp.Arguments.Count == 1); - LinearExpr le = AsExpr((IExpr/*!*/)cce.NonNull(funapp.Arguments[0])); - if (le != null) { - le.Negate(); - return le; - } - } else if (s.Equals(Int.Add) || s.Equals(Int.Sub) || s.Equals(Int.Mul)) { - Contract.Assert(funapp.Arguments.Count == 2); - IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[0]); - IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[1]); - LinearExpr le0 = AsExpr(arg0); - if (le0 == null) { - return null; - } - LinearExpr le1 = AsExpr(arg1); - if (le1 == null) { - return null; - } - - if (s.Equals(Int.Add)) { - le0.Add(le1); - return le0; - } else if (s.Equals(Int.Sub)) { - le1.Negate(); - le0.Add(le1); - return le0; - } else if (s.Equals(Int.Mul)) { - BigNum x; - if (le0.AsConstant(out x)) { - le1.Multiply(x); - return le1; - } else if (le1.AsConstant(out x)) { - le0.Multiply(x); - return le0; - } - } - } - } - return null; - } - } - - class LinearExpr { - BigNum constant; - Term terms; - - class Term { - public BigNum coeff; // non-0, if the node is used - public IVariable/*!*/ var; - public Term next; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(var != null); - } - - public Term(BigNum coeff, IVariable/*!*/ var) { - Contract.Requires(var != null); - this.coeff = coeff; - this.var = var; - // base(); - } - } - - public LinearExpr(BigNum x) { - constant = x; - } - - public LinearExpr(IVariable/*!*/ var) { - Contract.Requires(var != null); - constant = BigNum.ZERO; - terms = new Term(BigNum.ONE, var); - } - - public ISet /*IVariable!*/ GetDefinedDimensions() { - HashSet /*IVariable!*//*!*/ dims = new HashSet /*IVariable!*/ (); - for (Term current = terms; current != null; current = current.next) { - dims.Add(current.var); - } - return dims; - } - - public BigNum TermCoefficient(/*MayBeNull*/ IVariable/*!*/ var) { - Contract.Requires(var != null); - BigNum z = BigNum.ZERO; - if (var == null) { - z = this.constant; - } else if (terms != null) { - Term current = terms; - while (current != null) { - if (current.var == var) { - break; - } - current = current.next; - } - if (current != null) { - z = current.coeff; - } - } - return z; - } - - public bool AsConstant(out BigNum x) { - if (terms == null) { - x = constant; - return true; - } else { - x = BigNum.FromInt(-70022); // to please complier - return false; - } - } - - public void Negate() /* throws ArithmeticException */ - { - checked { - constant = -constant; - } - - for (Term t = terms; t != null; t = t.next) { - checked { - t.coeff = -t.coeff; - } - } - } - - /// - /// Adds "x" to "this". - /// - /// - public void AddConstant(BigNum x) /* throws ArithmeticException */ - { - checked { - constant += x; - } - } - - /// - /// Adds "le" to "this". Afterwards, "le" should not be used, because it will have been destroyed. - /// - /// - public void Add(LinearExpr/*!*/ le) /* throws ArithmeticException */ - { - Contract.Requires(le != null); - Contract.Requires(le != this); - checked { - constant += le.constant; - } - le.constant = BigNum.FromInt(-70029); // "le" should no longer be used; assign it a strange value so that misuse is perhaps more easily detected - - // optimization: - if (le.terms == null) { - return; - } else if (terms == null) { - terms = le.terms; - le.terms = null; - return; - } - - // merge the two term lists - // Use a nested loop, which is quadratic in time complexity, but we hope the lists will be small - Term newTerms = null; - while (le.terms != null) { - // take off next term from "le" - Term t = le.terms; - le.terms = t.next; - t.next = null; - - for (Term u = terms; u != null; u = u.next) { - if (u.var == t.var) { - checked { - u.coeff += t.coeff; - } - goto NextOuter; - } - } - t.next = newTerms; - newTerms = t; - - NextOuter: - ; - } - - // finally, include all non-0 terms - while (terms != null) { - // take off next term from "this" - Term t = terms; - terms = t.next; - - if (!t.coeff.IsZero) { - t.next = newTerms; - newTerms = t; - } - } - terms = newTerms; - } - - public void Multiply(BigNum x) /* throws ArithmeticException */ - { - if (x.IsZero) { - constant = BigNum.ZERO; - terms = null; - } else { - for (Term t = terms; t != null; t = t.next) { - checked { - t.coeff *= x; - } - } - checked { - constant *= x; - } - } - } - - public bool IsInvertible(IVariable/*!*/ var) { - Contract.Requires(var != null); - for (Term t = terms; t != null; t = t.next) { - if (t.var == var) { - System.Diagnostics.Debug.Assert(!t.coeff.IsZero); - return true; - } - } - return false; - } - - public LinearConstraint ToConstraint(LinearConstraint.ConstraintRelation rel) /* throws ArithmeticException */ - { - LinearConstraint constraint = new LinearConstraint(rel); - for (Term t = terms; t != null; t = t.next) { - constraint.SetCoefficient(t.var, t.coeff.ToRational); - } - BigNum rhs = -constant; - constraint.rhs = rhs.ToRational; - return constraint; - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + using System.Diagnostics.Contracts; + using Microsoft.Basetypes; + + using ISet = Microsoft.Boogie.GSet; + using HashSet = Microsoft.Boogie.GSet; + + /// + /// Represents an invariant over linear variable constraints, represented by a polyhedron. + /// + public class PolyhedraLattice : Lattice { + private static readonly Logger/*!*/ log = new Logger("Polyhedra"); + + private class PolyhedraLatticeElement : Element { + + public LinearConstraintSystem/*!*/ lcs; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(lcs != null); + } + + + /// + /// Creates a top or bottom elements, according to parameter "top". + /// + public PolyhedraLatticeElement(bool top) { + if (top) { + lcs = new LinearConstraintSystem(new ArrayList /*LinearConstraint*/ ()); + } else { + lcs = new LinearConstraintSystem(); + } + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return lcs.ToString(); + } + + public override void Dump(string/*!*/ msg) { + //Contract.Requires(msg != null); + System.Console.WriteLine("PolyhedraLatticeElement.Dump({0}):", msg); + lcs.Dump(); + } + + [Pure] + public override ICollection/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return lcs.FreeVariables(); + } + + public PolyhedraLatticeElement(LinearConstraintSystem/*!*/ lcs) { + Contract.Requires(lcs != null); + this.lcs = lcs; + } + + public override Element/*!*/ Clone() { + Contract.Ensures(Contract.Result() != null); + return new PolyhedraLatticeElement(cce.NonNull(lcs.Clone())); + } + + } // class + + readonly ILinearExprFactory/*!*/ factory; + readonly IPropExprFactory/*!*/ propFactory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(log != null); + Contract.Invariant(factory != null); + Contract.Invariant(propFactory != null); + } + + + public PolyhedraLattice(ILinearExprFactory/*!*/ linearFactory, IPropExprFactory/*!*/ propFactory) + : base(linearFactory) { + Contract.Requires(propFactory != null); + Contract.Requires(linearFactory != null); + log.Enabled = Lattice.LogSwitch; + this.factory = linearFactory; + this.propFactory = propFactory; + // base(linearFactory); + } + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result() != null); + return new PolyhedraLatticeElement(true); + } + } + + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result() != null); + + return new PolyhedraLatticeElement(false); + } + } + + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + PolyhedraLatticeElement e = (PolyhedraLatticeElement)element; + return e.lcs.IsBottom(); + } + + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + PolyhedraLatticeElement e = (PolyhedraLatticeElement)element; + return e.lcs.IsTop(); + } + + + /// + /// Returns true iff a is a subset of this. + /// + /// + /// + protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that + { + //Contract.Requires(first != null); + //Contract.Requires(second != null); + PolyhedraLatticeElement a = (PolyhedraLatticeElement)first; + PolyhedraLatticeElement b = (PolyhedraLatticeElement)second; + return b.lcs.IsSubset(a.lcs); + } + + + public override string/*!*/ ToString(Element/*!*/ e) { + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + return ((PolyhedraLatticeElement)e).lcs.ToString(); + } + + public override IExpr/*!*/ ToPredicate(Element/*!*/ element) { + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + PolyhedraLatticeElement e = (PolyhedraLatticeElement)element; + return e.lcs.ConvertToExpression(factory); + } + + + + public override Lattice.Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + log.DbgMsg("Joining ..."); + log.DbgMsgIndent(); + PolyhedraLatticeElement aa = (PolyhedraLatticeElement)first; + PolyhedraLatticeElement bb = (PolyhedraLatticeElement)second; + PolyhedraLatticeElement result = new PolyhedraLatticeElement(aa.lcs.Join(bb.lcs)); + log.DbgMsg(string.Format("{0} |_| {1} --> {2}", this.ToString(first), this.ToString(second), this.ToString(result))); + log.DbgMsgUnindent(); + return result; + } + + + public override Lattice.Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + PolyhedraLatticeElement aa = (PolyhedraLatticeElement)first; + PolyhedraLatticeElement bb = (PolyhedraLatticeElement)second; + return new PolyhedraLatticeElement(aa.lcs.Meet(bb.lcs)); + } + + + public override Lattice.Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + log.DbgMsg("Widening ..."); + log.DbgMsgIndent(); + PolyhedraLatticeElement aa = (PolyhedraLatticeElement)first; + PolyhedraLatticeElement bb = (PolyhedraLatticeElement)second; + + LinearConstraintSystem lcs = aa.lcs.Widen(bb.lcs); + PolyhedraLatticeElement result = new PolyhedraLatticeElement(lcs); + log.DbgMsg(string.Format("{0} |_| {1} --> {2}", this.ToString(first), this.ToString(second), this.ToString(result))); + log.DbgMsgUnindent(); + return result; + } + + + public override Element/*!*/ Eliminate(Element/*!*/ e, IVariable/*!*/ variable) { + //Contract.Requires(variable != null); + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + log.DbgMsg(string.Format("Eliminating {0} ...", variable)); + + PolyhedraLatticeElement ple = (PolyhedraLatticeElement)e; + if (ple.lcs.IsBottom()) { + return ple; + } + return new PolyhedraLatticeElement(ple.lcs.Project(variable)); + } + + + public override Element/*!*/ Rename(Element/*!*/ e, IVariable/*!*/ oldName, IVariable/*!*/ newName) { + //Contract.Requires(newName != null); + //Contract.Requires(oldName != null); + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + log.DbgMsg(string.Format("Renaming {0} to {1} in {2} ...", oldName, newName, this.ToString(e))); + + PolyhedraLatticeElement ple = (PolyhedraLatticeElement)e; + if (ple.lcs.IsBottom()) { + return ple; + } + return new PolyhedraLatticeElement(ple.lcs.Rename(oldName, newName)); + } + + public override bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + return f is IntSymbol || + f.Equals(Int.Add) || + f.Equals(Int.Sub) || + f.Equals(Int.Negate) || + f.Equals(Int.Mul) || + f.Equals(Int.Eq) || + f.Equals(Int.Neq) || + f.Equals(Prop.Not) || + f.Equals(Int.AtMost) || + f.Equals(Int.Less) || + f.Equals(Int.Greater) || + f.Equals(Int.AtLeast); + } + + public override Answer CheckVariableDisequality(Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2) { + //Contract.Requires(var2 != null); + //Contract.Requires(var1 != null); + //Contract.Requires(e != null); + PolyhedraLatticeElement/*!*/ ple = (PolyhedraLatticeElement)cce.NonNull(e); + Contract.Assume(ple.lcs.Constraints != null); + ArrayList /*LinearConstraint!*//*!*/ clist = (ArrayList /*LinearConstraint!*/)cce.NonNull(ple.lcs.Constraints.Clone()); + LinearConstraint/*!*/ lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ); + Contract.Assert(lc != null); + lc.SetCoefficient(var1, Rational.ONE); + lc.SetCoefficient(var2, Rational.MINUS_ONE); + clist.Add(lc); + LinearConstraintSystem newLcs = new LinearConstraintSystem(clist); + if (newLcs.IsBottom()) { + return Answer.Yes; + } else { + return Answer.Maybe; + } + } + + public override Answer CheckPredicate(Element/*!*/ e, IExpr/*!*/ pred) { + //Contract.Requires(pred != null); + //Contract.Requires(e != null); + PolyhedraLatticeElement/*!*/ ple = (PolyhedraLatticeElement)Constrain(e, pred); + Contract.Assert(ple != null); + if (ple.lcs.IsBottom()) { + return Answer.No; + } + + // Note, "pred" may contain expressions that are not understood by the propFactory (in + // particular, this may happen because--currently, and perhaps is a design we'll want + // to change in the future--propFactory deals with BoogiePL expressions whereas "pred" + // may also refer to Equivalences.UninterpFun expressions). Thus, we cannot just + // call propFactory.Not(pred) to get the negation of "pred". + pred = new PolyhedraLatticeNegation(pred); + ple = (PolyhedraLatticeElement)Constrain(e, pred); + if (ple.lcs.IsBottom()) { + return Answer.Yes; + } else { + return Answer.Maybe; + } + } + + class PolyhedraLatticeNegation : IFunApp { + IExpr/*!*/ arg; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(arg != null); + } + + + public PolyhedraLatticeNegation(IExpr/*!*/ arg) { + Contract.Requires(arg != null); + this.arg = arg; + // base(); + } + + [Pure] + public object DoVisit(ExprVisitor/*!*/ visitor) { + //Contract.Requires(visitor != null); + return visitor.VisitFunApp(this); + } + + public IFunctionSymbol/*!*/ FunctionSymbol { + get { + Contract.Ensures(Contract.Result() != null); + return Prop.Not; + } + } + + public IList/**//*!*/ Arguments { + get { + Contract.Ensures(Contract.Result() != null); + + IExpr[] args = new IExpr[] { arg }; + return ArrayList.ReadOnly(args); + } + } + + public IFunApp/*!*/ CloneWithArguments(IList/**//*!*/ args) { + //Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + Contract.Assert(args.Count == 1); + return new PolyhedraLatticeNegation((IExpr/*!*/)cce.NonNull(args[0])); + } + } + + public override IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, ISet/**//*!*/ prohibitedVars) { + //Contract.Requires(prohibitedVars != null); + //Contract.Requires(var != null); + //Contract.Requires(expr != null); + //Contract.Requires(q != null); + //Contract.Requires(e != null); + // BUGBUG: TODO: this method can be implemented in a more precise way + return null; + } + + + public override Element/*!*/ Constrain(Element/*!*/ e, IExpr/*!*/ expr) { + //Contract.Requires(expr != null); + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + log.DbgMsg(string.Format("Constraining with {0} into {1} ...", expr, this.ToString(e))); + + PolyhedraLatticeElement ple = (PolyhedraLatticeElement)e; + if (ple.lcs.IsBottom()) { + return ple; + } + LinearCondition le = LinearExpressionBuilder.AsCondition(expr); + if (le != null) { + // update the polyhedron according to the linear expression + Contract.Assume(ple.lcs.Constraints != null); + ArrayList /*LinearConstraint*/ clist = (ArrayList/*!*/ /*LinearConstraint*/)cce.NonNull(ple.lcs.Constraints.Clone()); + le.AddToConstraintSystem(clist); + LinearConstraintSystem newLcs = new LinearConstraintSystem(clist); + + return new PolyhedraLatticeElement(newLcs); + } + return ple; + } + + } // class + + + /// + /// A LinearCondition follows this grammar: + /// LinearCondition ::= unsatisfiable + /// | LinearConstraint + /// | ! LinearConstraint + /// Note that negations are distributed to the leaves. + /// + /// + [ContractClass(typeof(LinearConditionContracts))] + abstract class LinearCondition { + /// + /// Adds constraints to the list "clist". If "this" + /// entails some disjunctive constraints, they may not be added. + /// + /// + public abstract void AddToConstraintSystem(ArrayList/*!*/ /*LinearConstraint*/ clist); + } + [ContractClassFor(typeof(LinearCondition))] + abstract class LinearConditionContracts : LinearCondition { + public override void AddToConstraintSystem(ArrayList clist) { + Contract.Requires(clist != null); + throw new NotImplementedException(); + } + } + + class LCBottom : LinearCondition { + public override void AddToConstraintSystem(ArrayList/*!*/ /*LinearConstraint*/ clist) { + //Contract.Requires(clist != null); + // make an unsatisfiable constraint + LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ); + lc.rhs = Rational.FromInt(1); + clist.Add(lc); + } + } + + class LinearConditionLiteral : LinearCondition { + public readonly bool positive; + public readonly LinearConstraint/*!*/ constraint; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(constraint != null); + } + + /// + /// Precondition: positive || constraint.Relation == LinearConstraint.ConstraintRelation.EQ + /// + /// + /// + public LinearConditionLiteral(bool positive, LinearConstraint/*!*/ constraint) { + Contract.Requires(constraint != null); + Contract.Requires(positive || constraint.Relation == LinearConstraint.ConstraintRelation.EQ); + this.positive = positive; + this.constraint = constraint; + } + public override void AddToConstraintSystem(ArrayList/*!*/ /*LinearConstraint*/ clist) { + //Contract.Requires(clist != null); + if (positive) { + clist.Add(constraint); + } else { + Contract.Assert(constraint.Relation == LinearConstraint.ConstraintRelation.EQ); + // the constraint is disjunctive, so just ignore it + } + } + } + + class LinearExpressionBuilder { + /// + /// Builds a linear condition from "e", if possible; returns null if not possible. + /// + /// + /// + public static /*maybe null*/ LinearCondition AsCondition(IExpr e) /* throws ArithmeticException */ + { + return GetCond(e, true); + } + + static /*maybe null*/ LinearCondition GetCond(IExpr e, bool positive) /* throws ArithmeticException */ + { + IFunApp funapp = e as IFunApp; + if (funapp == null) { + return null; + } + IFunctionSymbol/*!*/ s = funapp.FunctionSymbol; + Contract.Assert(s != null); + if ((positive && s.Equals(Prop.False)) || + (!positive && s.Equals(Prop.True))) { + return new LCBottom(); + } else if (s.Equals(Prop.Not)) { + Contract.Assert(funapp.Arguments.Count == 1); + return GetCond((IExpr/*!*/)cce.NonNull(funapp.Arguments[0]), !positive); + } else if (funapp.Arguments.Count == 2) { + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[1]); + LinearExpr le0 = AsExpr(arg0); + if (le0 == null) { + return null; + } + LinearExpr le1 = AsExpr(arg1); + if (le1 == null) { + return null; + } + + LinearConstraint constraint = null; + bool sense = true; + if ((positive && s.Equals(Int.Less)) || (!positive && s.Equals(Int.AtLeast))) { + constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.LE, BigNum.ONE); + } else if ((positive && s.Equals(Int.AtMost)) || (!positive && s.Equals(Int.Greater))) { + constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.LE, BigNum.ZERO); + } else if ((positive && s.Equals(Int.AtLeast)) || (!positive && s.Equals(Int.Less))) { + constraint = MakeConstraint(le1, le0, LinearConstraint.ConstraintRelation.LE, BigNum.ZERO); + } else if ((positive && s.Equals(Int.Greater)) || (!positive && s.Equals(Int.AtMost))) { + constraint = MakeConstraint(le1, le0, LinearConstraint.ConstraintRelation.LE, BigNum.ONE); + } else if (s.Equals(Int.Eq)) { + constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.EQ, BigNum.ZERO); + sense = positive; + } else if (s.Equals(Int.Neq)) { + constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.EQ, BigNum.ZERO); + sense = !positive; + } + if (constraint != null) { + if (constraint.coefficients.Count != 0) { + return new LinearConditionLiteral(sense, constraint); + } else if (constraint.IsConstantSatisfiable()) { + return null; + } else { + return new LCBottom(); + } + } + } + return null; + } + + public static LinearConstraint MakeConstraint(LinearExpr/*!*/ le0, LinearExpr/*!*/ le1, + LinearConstraint.ConstraintRelation rel, BigNum constantOffset) /* throws ArithmeticException */ + { + Contract.Requires(le0 != null); + Contract.Requires(le1 != null); + le1.Negate(); + le0.Add(le1); + le0.AddConstant(constantOffset); + return le0.ToConstraint(rel); + } + + /// + /// Builds a linear expression from "e", if possible; returns null if not possible. + /// + /// + /// + public static /*maybe null*/ LinearExpr AsExpr(IExpr/*!*/ e) /* throws ArithmeticException */ + { + Contract.Requires(e != null); + if (e is IVariable) { + // Note, without a type for the variable, we don't know if the identifier is intended to hold an integer value. + // However, it seems that no harm can be caused by here treating the identifier as if it held an + // integer value, because other parts of this method will reject the expression as a linear expression + // if non-numeric operations other than equality are applied to the identifier. + return new LinearExpr((IVariable)e); + } else if (e is IFunApp) { + IFunApp/*!*/ funapp = (IFunApp)e; + Contract.Assert(funapp != null); + IFunctionSymbol/*!*/ s = funapp.FunctionSymbol; + Contract.Assert(s != null); + + if (s is IntSymbol) { + return new LinearExpr(((IntSymbol)s).Value); + } else if (s.Equals(Int.Negate)) { + Contract.Assert(funapp.Arguments.Count == 1); + LinearExpr le = AsExpr((IExpr/*!*/)cce.NonNull(funapp.Arguments[0])); + if (le != null) { + le.Negate(); + return le; + } + } else if (s.Equals(Int.Add) || s.Equals(Int.Sub) || s.Equals(Int.Mul)) { + Contract.Assert(funapp.Arguments.Count == 2); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[1]); + LinearExpr le0 = AsExpr(arg0); + if (le0 == null) { + return null; + } + LinearExpr le1 = AsExpr(arg1); + if (le1 == null) { + return null; + } + + if (s.Equals(Int.Add)) { + le0.Add(le1); + return le0; + } else if (s.Equals(Int.Sub)) { + le1.Negate(); + le0.Add(le1); + return le0; + } else if (s.Equals(Int.Mul)) { + BigNum x; + if (le0.AsConstant(out x)) { + le1.Multiply(x); + return le1; + } else if (le1.AsConstant(out x)) { + le0.Multiply(x); + return le0; + } + } + } + } + return null; + } + } + + class LinearExpr { + BigNum constant; + Term terms; + + class Term { + public BigNum coeff; // non-0, if the node is used + public IVariable/*!*/ var; + public Term next; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(var != null); + } + + public Term(BigNum coeff, IVariable/*!*/ var) { + Contract.Requires(var != null); + this.coeff = coeff; + this.var = var; + // base(); + } + } + + public LinearExpr(BigNum x) { + constant = x; + } + + public LinearExpr(IVariable/*!*/ var) { + Contract.Requires(var != null); + constant = BigNum.ZERO; + terms = new Term(BigNum.ONE, var); + } + + public ISet /*IVariable!*/ GetDefinedDimensions() { + HashSet /*IVariable!*//*!*/ dims = new HashSet /*IVariable!*/ (); + for (Term current = terms; current != null; current = current.next) { + dims.Add(current.var); + } + return dims; + } + + public BigNum TermCoefficient(/*MayBeNull*/ IVariable/*!*/ var) { + Contract.Requires(var != null); + BigNum z = BigNum.ZERO; + if (var == null) { + z = this.constant; + } else if (terms != null) { + Term current = terms; + while (current != null) { + if (current.var == var) { + break; + } + current = current.next; + } + if (current != null) { + z = current.coeff; + } + } + return z; + } + + public bool AsConstant(out BigNum x) { + if (terms == null) { + x = constant; + return true; + } else { + x = BigNum.FromInt(-70022); // to please complier + return false; + } + } + + public void Negate() /* throws ArithmeticException */ + { + checked { + constant = -constant; + } + + for (Term t = terms; t != null; t = t.next) { + checked { + t.coeff = -t.coeff; + } + } + } + + /// + /// Adds "x" to "this". + /// + /// + public void AddConstant(BigNum x) /* throws ArithmeticException */ + { + checked { + constant += x; + } + } + + /// + /// Adds "le" to "this". Afterwards, "le" should not be used, because it will have been destroyed. + /// + /// + public void Add(LinearExpr/*!*/ le) /* throws ArithmeticException */ + { + Contract.Requires(le != null); + Contract.Requires(le != this); + checked { + constant += le.constant; + } + le.constant = BigNum.FromInt(-70029); // "le" should no longer be used; assign it a strange value so that misuse is perhaps more easily detected + + // optimization: + if (le.terms == null) { + return; + } else if (terms == null) { + terms = le.terms; + le.terms = null; + return; + } + + // merge the two term lists + // Use a nested loop, which is quadratic in time complexity, but we hope the lists will be small + Term newTerms = null; + while (le.terms != null) { + // take off next term from "le" + Term t = le.terms; + le.terms = t.next; + t.next = null; + + for (Term u = terms; u != null; u = u.next) { + if (u.var == t.var) { + checked { + u.coeff += t.coeff; + } + goto NextOuter; + } + } + t.next = newTerms; + newTerms = t; + + NextOuter: + ; + } + + // finally, include all non-0 terms + while (terms != null) { + // take off next term from "this" + Term t = terms; + terms = t.next; + + if (!t.coeff.IsZero) { + t.next = newTerms; + newTerms = t; + } + } + terms = newTerms; + } + + public void Multiply(BigNum x) /* throws ArithmeticException */ + { + if (x.IsZero) { + constant = BigNum.ZERO; + terms = null; + } else { + for (Term t = terms; t != null; t = t.next) { + checked { + t.coeff *= x; + } + } + checked { + constant *= x; + } + } + } + + public bool IsInvertible(IVariable/*!*/ var) { + Contract.Requires(var != null); + for (Term t = terms; t != null; t = t.next) { + if (t.var == var) { + System.Diagnostics.Debug.Assert(!t.coeff.IsZero); + return true; + } + } + return false; + } + + public LinearConstraint ToConstraint(LinearConstraint.ConstraintRelation rel) /* throws ArithmeticException */ + { + LinearConstraint constraint = new LinearConstraint(rel); + for (Term t = terms; t != null; t = t.next) { + constraint.SetCoefficient(t.var, t.coeff.ToRational); + } + BigNum rhs = -constant; + constraint.rhs = rhs.ToRational; + return constraint; + } + } +} diff --git a/Source/AIFramework/Polyhedra/SimplexTableau.cs b/Source/AIFramework/Polyhedra/SimplexTableau.cs index 4d734c27..347c7c45 100644 --- a/Source/AIFramework/Polyhedra/SimplexTableau.cs +++ b/Source/AIFramework/Polyhedra/SimplexTableau.cs @@ -1,630 +1,630 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework { - using System.Collections; - using System; - using System.Diagnostics.Contracts; - using Microsoft.Basetypes; - using IMutableSet = Microsoft.Boogie.GSet; - using HashSet = Microsoft.Boogie.GSet; - - - /// - /// Used by LinearConstraintSystem.GenerateFrameFromConstraints. - /// - public class SimplexTableau { - readonly int rows; - readonly int columns; - readonly Rational[,]/*!*/ m; - - readonly int numInitialVars; - readonly int numSlackVars; - readonly int rhsColumn; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(m != null); - Contract.Invariant(inBasis != null); - Contract.Invariant(basisColumns != null); - } - - readonly ArrayList /*IVariable!*//*!*/ dims; - readonly int[]/*!*/ basisColumns; - readonly int[]/*!*/ inBasis; - bool constructionDone = false; - - void CheckInvariant() { - Contract.Assert(rows == m.GetLength(0)); - Contract.Assert(1 <= columns && columns == m.GetLength(1)); - Contract.Assert(0 <= numInitialVars); - Contract.Assert(0 <= numSlackVars && numSlackVars <= rows); - Contract.Assert(numInitialVars + numSlackVars + 1 == columns); - Contract.Assert(rhsColumn == columns - 1); - Contract.Assert(dims.Count == numInitialVars); - Contract.Assert(basisColumns.Length == rows); - Contract.Assert(inBasis.Length == numInitialVars + numSlackVars); - - bool[] b = new bool[numInitialVars + numSlackVars]; - int numColumnsInBasis = 0; - int numUninitializedRowInfo = 0; - for (int i = 0; i < rows; i++) { - int c = basisColumns[i]; - if (c == rhsColumn) { - // all coefficients in this row are 0 (but the right-hand side may be non-0) - for (int j = 0; j < rhsColumn; j++) { - Contract.Assert(m[i, j].IsZero); - } - numColumnsInBasis++; - } else if (c == -1) { - Contract.Assert(!constructionDone); - numUninitializedRowInfo++; - } else { - // basis column is a column - Contract.Assert(0 <= c && c < numInitialVars + numSlackVars); - // basis column is unique - Contract.Assert(!b[c]); - b[c] = true; - // column is marked as being in basis - Contract.Assert(inBasis[c] == i); - // basis column really is a basis column - for (int j = 0; j < rows; j++) { - if (j == i) { - Contract.Assert(m[j, c].HasValue(1));// == (Rational)new Rational(1))); - } else { - Contract.Assert(m[j, c].IsZero); - } - } - } - } - // no other columns are marked as being in basis - foreach (int i in inBasis) { - if (0 <= i) { - Contract.Assert(i < rows); - numColumnsInBasis++; - } else { - Contract.Assert(i == -1); - } - } - Contract.Assert(rows - numUninitializedRowInfo <= numColumnsInBasis && numColumnsInBasis <= rows); - Contract.Assert(!constructionDone || numUninitializedRowInfo == 0); - } - - /// - /// Constructs a matrix that represents the constraints "constraints", adding slack - /// variables for the inequalities among "constraints". Puts the matrix in canonical - /// form. - /// - /// - [NotDelayed] - public SimplexTableau(ArrayList /*LinearConstraint*//*!*/ constraints) { - Contract.Requires(constraints != null); -#if DEBUG_PRINT - Console.WriteLine("DEBUG: SimplexTableau constructor called with:"); - foreach (LinearConstraint lc in constraints) - { - Console.WriteLine(" {0}", lc); - } -#endif - // Note: This implementation is not particularly efficient, but it'll do for now. - - ArrayList dims = this.dims = new ArrayList /*IVariable!*/ (); - int slacks = 0; - foreach (LinearConstraint/*!*/ cc in constraints) { - Contract.Assert(cc != null); - foreach (IVariable/*!*/ dim in cc.coefficients.Keys) { - Contract.Assert(dim != null); - if (!dims.Contains(dim)) { - dims.Add(dim); - } - } - if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { - slacks++; - } - } - - int numInitialVars = this.numInitialVars = dims.Count; - int numSlackVars = this.numSlackVars = slacks; - int rows = this.rows = constraints.Count; - int columns = this.columns = numInitialVars + numSlackVars + 1; - this.m = new Rational[rows, columns]; - this.rhsColumn = columns - 1; - this.basisColumns = new int[rows]; - this.inBasis = new int[columns - 1]; - - //:base(); - - for (int i = 0; i < inBasis.Length; i++) { - inBasis[i] = -1; - } - - // Fill in the matrix - int r = 0; - int iSlack = 0; - foreach (LinearConstraint/*!*/ cc in constraints) { - Contract.Assert(cc != null); - for (int i = 0; i < dims.Count; i++) { - m[r, i] = cc[(IVariable)cce.NonNull(dims[i])]; - } - if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { - m[r, numInitialVars + iSlack] = Rational.ONE; - basisColumns[r] = numInitialVars + iSlack; - inBasis[numInitialVars + iSlack] = r; - iSlack++; - } else { - basisColumns[r] = -1; // special value to communicate to Pivot that basis column i hasn't been set up yet - } - m[r, rhsColumn] = cc.rhs; - r++; - } - Contract.Assert(r == constraints.Count); - Contract.Assert(iSlack == numSlackVars); -#if DEBUG_PRINT - Console.WriteLine("DEBUG: Intermediate tableau state in SimplexTableau constructor:"); - Dump(); -#endif - - // Go through the rows with uninitialized basis columns. These correspond to equality constraints. - // For each one, find an initial variable (non-slack variable) whose column we can make the basis - // column of the row. - for (int i = 0; i < rows; i++) { - if (basisColumns[i] != -1) { - continue; - } - // Find a non-0 column in row i that we can make a basis column. Since rows corresponding - // to equality constraints don't have slack variables and since the pivot operations performed - // by iterations of this loop don't introduce any non-0 coefficients in the slack-variable - // columns of these rows, we only need to look through the columns corresponding to initial - // variables. - for (int j = 0; j < numInitialVars; j++) { - if (m[i, j].IsNonZero) { -#if DEBUG_PRINT - Console.WriteLine("-- About to Pivot({0},{1})", i, j); -#endif - Contract.Assert(inBasis[j] == -1); - Pivot(i, j); -#if DEBUG_PRINT - Console.WriteLine("Tableau after Pivot:"); - Dump(); -#endif - goto SET_UP_NEXT_INBASIS_COLUMN; - } - } - // Check the assertion in the comment above, that is, that columns corresponding to slack variables - // are 0 in this row. - for (int j = numInitialVars; j < rhsColumn; j++) { - Contract.Assert(m[i, j].IsZero); - } - // There is no column in this row that we can put into basis. - basisColumns[i] = rhsColumn; - SET_UP_NEXT_INBASIS_COLUMN: { - } - } - - constructionDone = true; - CheckInvariant(); - } - - public IMutableSet/*!*/ /*IVariable!*/ GetDimensions() { - Contract.Ensures(Contract.Result() != null); - HashSet /*IVariable!*/ z = new HashSet /*IVariable!*/ (); - foreach (IVariable/*!*/ dim in dims) { - Contract.Assert(dim != null); - z.Add(dim); - } - return z; - } - - public Rational this[int r, int c] { - get { - return m[r, c]; - } - set { - m[r, c] = value; - } - } - - /// - /// Applies the Pivot Operation on row "r" and column "c". - /// - /// This method can be called when !constructionDone, that is, at a time when not all basis - /// columns have been set up (indicated by -1 in basisColumns). This method helps set up - /// those basis columns. - /// - /// The return value is an undo record that can be used with UnPivot. - /// - /// - /// - public Rational[]/*!*/ Pivot(int r, int c) { - Contract.Ensures(Contract.Result() != null); - Contract.Assert(0 <= r && r < rows); - Contract.Assert(0 <= c && c < columns - 1); - Contract.Assert(m[r, c].IsNonZero); - Contract.Assert(inBasis[c] == -1); // follows from invariant and m[r,c] != 0 - Contract.Assert(basisColumns[r] != rhsColumn); // follows from invariant and m[r,c] != 0 - - Rational[] undo = new Rational[rows + 1]; - for (int i = 0; i < rows; i++) { - undo[i] = m[i, c]; - } - - // scale the pivot row - Rational q = m[r, c]; - if (q != Rational.ONE) { - for (int j = 0; j < columns; j++) { - m[r, j] /= q; - } - } - - // subtract a multiple of the pivot row from all other rows - for (int i = 0; i < rows; i++) { - if (i != r) { - q = m[i, c]; - if (q.IsNonZero) { - for (int j = 0; j < columns; j++) { - m[i, j] -= q * m[r, j]; - } - } - } - } - - // update basis information - int prevCol = basisColumns[r]; - undo[rows] = Rational.FromInt(prevCol); - basisColumns[r] = c; - if (prevCol != -1) { - inBasis[prevCol] = -1; - } - inBasis[c] = r; - - return undo; - } - - /// - /// If the last operation applied to the tableau was: - /// undo = Pivot(i,j); - /// then UnPivot(i, j, undo) undoes the pivot operation. - /// Note: This operation is not supported for any call to Pivot before constructionDone - /// is set to true. - /// - /// - /// - /// - void UnPivot(int r, int c, Rational[]/*!*/ undo) { - Contract.Requires(undo != null); - Contract.Assert(0 <= r && r < rows); - Contract.Assert(0 <= c && c < columns - 1); - Contract.Assert(m[r, c].HasValue(1)); - Contract.Assert(undo.Length == rows + 1); - - // add a multiple of the pivot row to all other rows - for (int i = 0; i < rows; i++) { - if (i != r) { - Rational q = undo[i]; - if (q.IsNonZero) { - for (int j = 0; j < columns; j++) { - m[i, j] += q * m[r, j]; - } - } - } - } - - // scale the pivot row - Rational p = undo[r]; - for (int j = 0; j < columns; j++) { - m[r, j] *= p; - } - - // update basis information - int prevCol = undo[rows].AsInteger; - Contract.Assert(prevCol != -1); - basisColumns[r] = prevCol; - inBasis[c] = -1; - inBasis[prevCol] = r; - } - - /// - /// Returns true iff the current basis of the system of constraints modeled by the simplex tableau - /// is feasible. May have a side effect of performing a number of pivot operations on the tableau, - /// but any such pivot operation will be in the columns of slack variables (that is, this routine - /// does not change the set of initial-variable columns in basis). - /// - /// CAVEAT: I have no particular reason to believe that the algorithm used here will terminate. --KRML - /// - /// - public bool IsFeasibleBasis { - get { - // while there is a slack variable in basis whose row has a negative right-hand side - while (true) { - bool feasibleBasis = true; - for (int c = numInitialVars; c < rhsColumn; c++) { - int k = inBasis[c]; - if (0 <= k && k < rhsColumn && m[k, rhsColumn].IsNegative) { - Contract.Assert(m[k, c].HasValue(1)); // c is in basis - // Try to pivot on a different slack variable in this row - for (int i = numInitialVars; i < rhsColumn; i++) { - if (m[k, i].IsNegative) { - Contract.Assert(c != i); // c is in basis, so m[k,c]==1, which is not negative - Pivot(k, i); -#if DEBUG_PRINT - Console.WriteLine("Tableau after Pivot operation on ({0},{1}) in IsFeasibleBasis:", k, i); - Dump(); -#endif - Contract.Assert(inBasis[c] == -1); - Contract.Assert(inBasis[i] == k); - Contract.Assert(m[k, rhsColumn].IsNonNegative); - goto START_ANEW; - } - } - feasibleBasis = false; - } - } - return feasibleBasis; - START_ANEW: - ; - } - } - } - - /// - /// Whether or not all initial variables (the non-slack variables) are in basis) - /// - public bool AllInitialVarsInBasis { - get { - for (int i = 0; i < numInitialVars; i++) { - if (inBasis[i] == -1) { - return false; - } - } - return true; - } - } - - /// - /// Adds as many initial variables as possible to the basis. - /// - /// - public void AddInitialVarsToBasis() { - // while there exists an initial variable not in the basis and not satisfying - // condition 3.4.2.2 in Cousot and Halbwachs, perform a pivot operation - while (true) { - for (int i = 0; i < numInitialVars; i++) { - if (inBasis[i] == -1) { - // initial variable i is not in the basis - for (int j = 0; j < rows; j++) { - if (m[j, i].IsNonZero) { - int k = basisColumns[j]; - if (numInitialVars <= k && k < rhsColumn) { - // slack variable k is in basis for row j - Pivot(j, i); - Contract.Assert(inBasis[k] == -1); - Contract.Assert(inBasis[i] == j && basisColumns[j] == i); - goto START_ANEW; - } - } - } - } - } - // No more initial variables can be moved into basis. - return; - START_ANEW: { - } - } - } - - /// - /// Adds to "lines" the lines implied by initial-variable columns not in basis - /// (see section 3.4.2 of Cousot and Halbwachs), and adds to "constraints" the - /// constraints to exclude those lines (see step 4.2 of section 3.4.3 of - /// Cousot and Halbwachs). - /// - /// - /// - public void ProduceLines(ArrayList /*FrameElement*//*!*/ lines, ArrayList /*LinearConstraint*//*!*/ constraints) { - Contract.Requires(constraints != null); - Contract.Requires(lines != null); - // for every initial variable not in basis - for (int i0 = 0; i0 < numInitialVars; i0++) { - if (inBasis[i0] == -1) { - FrameElement fe = new FrameElement(); - LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ); - for (int i = 0; i < numInitialVars; i++) { - if (i == i0) { - fe.AddCoordinate((IVariable)cce.NonNull(dims[i]), Rational.ONE); - lc.SetCoefficient((IVariable)cce.NonNull(dims[i]), Rational.ONE); - } else if (inBasis[i] != -1) { - // i is a basis column - Contract.Assert(m[inBasis[i], i].HasValue(1)); - Rational val = -m[inBasis[i], i0]; - fe.AddCoordinate((IVariable)cce.NonNull(dims[i]), val); - lc.SetCoefficient((IVariable)cce.NonNull(dims[i]), val); - } - } - lines.Add(fe); - constraints.Add(lc); - } - } - } - - /// - /// From a feasible point where all initial variables are in the basis, traverses - /// all feasible bases containing all initial variables. For each such basis, adds - /// the vertices to "vertices" and adds to "rays" the extreme rays. See step 4.2 - /// in section 3.4.3 of Cousot and Halbwachs. - /// A more efficient algorithm is found in the paper "An algorithm for - /// determining all extreme points of a convex polytope" by N. E. Dyer and L. G. Proll, - /// Mathematical Programming, 12, 1977. - /// Assumes that the tableau is in a state where all initial variables are in the basis. - /// This method has no net effect on the tableau. - /// Note: Duplicate vertices and rays may be added. - /// - /// - /// - public void TraverseVertices(ArrayList/*!*/ /*FrameElement*/ vertices, ArrayList/*!*/ /*FrameElement*/ rays) { - Contract.Requires(vertices != null); - Contract.Requires(rays != null); - ArrayList /*bool[]*/ basesSeenSoFar = new ArrayList /*bool[]*/ (); - TraverseBases(basesSeenSoFar, vertices, rays); - } - - /// - /// Worker method of TraverseVertices. - /// This method has no net effect on the tableau. - /// - /// - /// - /// - void TraverseBases(ArrayList /*bool[]*//*!*/ basesSeenSoFar, ArrayList /*FrameElement*//*!*/ vertices, ArrayList /*FrameElement*//*!*/ rays) { - Contract.Requires(rays != null); - Contract.Requires(vertices != null); - Contract.Requires(basesSeenSoFar != null); - CheckInvariant(); - - bool[] thisBasis = new bool[numSlackVars]; - for (int i = numInitialVars; i < rhsColumn; i++) { - if (inBasis[i] != -1) { - thisBasis[i - numInitialVars] = true; - } - } - foreach (bool[]/*!*/ basis in basesSeenSoFar) { - Contract.Assert(basis != null); - Contract.Assert(basis.Length == numSlackVars); - for (int i = 0; i < numSlackVars; i++) { - if (basis[i] != thisBasis[i]) { - goto COMPARE_WITH_NEXT_BASIS; - } - } - // thisBasis and basis are the same--that is, basisColumns has been visited before--so - // we don't traverse anything from here - return; - COMPARE_WITH_NEXT_BASIS: { - } - } - // basisColumns has not been seen before; record thisBasis and continue with the traversal here - basesSeenSoFar.Add(thisBasis); - -#if DEBUG_PRINT - Console.Write("TraverseBases, new basis: "); - foreach (bool t in thisBasis) { - Console.Write("{0}", t ? "*" : "."); - } - Console.WriteLine(); - Dump(); -#endif - // Add vertex - FrameElement v = new FrameElement(); - for (int i = 0; i < rows; i++) { - int j = basisColumns[i]; - if (j < numInitialVars) { - v.AddCoordinate((IVariable)cce.NonNull(dims[j]), m[i, rhsColumn]); - } - } -#if DEBUG_PRINT - Console.WriteLine(" Adding vertex: {0}", v); -#endif - vertices.Add(v); - - // Add rays. Traverse all columns corresponding to slack variables that - // are not in basis (see second bullet of section 3.4.2 of Cousot and Halbwachs). - for (int i0 = numInitialVars; i0 < rhsColumn; i0++) { - if (inBasis[i0] != -1) { - // skip those slack-variable columns that are in basis - continue; - } - // check if slack-variable, non-basis column i corresponds to an extreme ray - for (int row = 0; row < rows; row++) { - if (m[row, i0].IsPositive) { - for (int k = numInitialVars; k < rhsColumn; k++) { - if (inBasis[k] != -1 && m[row, k].IsNonZero) { - // does not correspond to an extreme ray - goto CHECK_NEXT_SLACK_VAR; - } - } - } - } - // corresponds to an extreme ray - FrameElement ray = new FrameElement(); - for (int i = 0; i < numInitialVars; i++) { - int j0 = inBasis[i]; - Rational val = -m[j0, i0]; - ray.AddCoordinate((IVariable)cce.NonNull(dims[i]), val); - } -#if DEBUG_PRINT - Console.WriteLine(" Adding ray: {0}", ray); -#endif - rays.Add(ray); - CHECK_NEXT_SLACK_VAR: { - } - } - - // Continue traversal - for (int i = numInitialVars; i < rhsColumn; i++) { - int j = inBasis[i]; - if (j != -1) { - // try moving i out of basis and some other slack-variable column into basis - for (int k = numInitialVars; k < rhsColumn; k++) { - if (inBasis[k] == -1 && m[j, k].IsPositive) { - Rational[] undo = Pivot(j, k); - // check if the new basis is feasible - for (int p = 0; p < rows; p++) { - int c = basisColumns[p]; - if (numInitialVars <= c && c < rhsColumn && m[p, rhsColumn].IsNegative) { - // not feasible - goto AFTER_TRAVERSE; - } - } - TraverseBases(basesSeenSoFar, vertices, rays); - AFTER_TRAVERSE: - UnPivot(j, k, undo); - } - } - } - } - } - - public void Dump() { - // names - Console.Write(" "); - for (int i = 0; i < numInitialVars; i++) { - Console.Write(" {0,4} ", dims[i]); - } - Console.WriteLine(); - // numbers - Console.Write(" "); - for (int i = 0; i < columns; i++) { - if (i == numInitialVars || i == rhsColumn) { - Console.Write("|"); - } - Console.Write(" {0,4}", i); - if (i < rhsColumn && inBasis[i] != -1) { - Console.Write("* "); - Contract.Assert(basisColumns[inBasis[i]] == i); - } else { - Console.Write(" "); - } - } - Console.WriteLine(); - // line - Console.Write(" "); - for (int i = 0; i < columns; i++) { - if (i == numInitialVars || i == rhsColumn) { - Console.Write("+"); - } - Console.Write("---------"); - } - Console.WriteLine(); - - for (int j = 0; j < rows; j++) { - Console.Write("{0,4}: ", basisColumns[j]); - for (int i = 0; i < columns; i++) { - if (i == numInitialVars || i == rhsColumn) { - Console.Write("|"); - } - Console.Write(" {0,4:n1} ", m[j, i]); - } - Console.WriteLine(); - } - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System.Collections; + using System; + using System.Diagnostics.Contracts; + using Microsoft.Basetypes; + using IMutableSet = Microsoft.Boogie.GSet; + using HashSet = Microsoft.Boogie.GSet; + + + /// + /// Used by LinearConstraintSystem.GenerateFrameFromConstraints. + /// + public class SimplexTableau { + readonly int rows; + readonly int columns; + readonly Rational[,]/*!*/ m; + + readonly int numInitialVars; + readonly int numSlackVars; + readonly int rhsColumn; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(m != null); + Contract.Invariant(inBasis != null); + Contract.Invariant(basisColumns != null); + } + + readonly ArrayList /*IVariable!*//*!*/ dims; + readonly int[]/*!*/ basisColumns; + readonly int[]/*!*/ inBasis; + bool constructionDone = false; + + void CheckInvariant() { + Contract.Assert(rows == m.GetLength(0)); + Contract.Assert(1 <= columns && columns == m.GetLength(1)); + Contract.Assert(0 <= numInitialVars); + Contract.Assert(0 <= numSlackVars && numSlackVars <= rows); + Contract.Assert(numInitialVars + numSlackVars + 1 == columns); + Contract.Assert(rhsColumn == columns - 1); + Contract.Assert(dims.Count == numInitialVars); + Contract.Assert(basisColumns.Length == rows); + Contract.Assert(inBasis.Length == numInitialVars + numSlackVars); + + bool[] b = new bool[numInitialVars + numSlackVars]; + int numColumnsInBasis = 0; + int numUninitializedRowInfo = 0; + for (int i = 0; i < rows; i++) { + int c = basisColumns[i]; + if (c == rhsColumn) { + // all coefficients in this row are 0 (but the right-hand side may be non-0) + for (int j = 0; j < rhsColumn; j++) { + Contract.Assert(m[i, j].IsZero); + } + numColumnsInBasis++; + } else if (c == -1) { + Contract.Assert(!constructionDone); + numUninitializedRowInfo++; + } else { + // basis column is a column + Contract.Assert(0 <= c && c < numInitialVars + numSlackVars); + // basis column is unique + Contract.Assert(!b[c]); + b[c] = true; + // column is marked as being in basis + Contract.Assert(inBasis[c] == i); + // basis column really is a basis column + for (int j = 0; j < rows; j++) { + if (j == i) { + Contract.Assert(m[j, c].HasValue(1));// == (Rational)new Rational(1))); + } else { + Contract.Assert(m[j, c].IsZero); + } + } + } + } + // no other columns are marked as being in basis + foreach (int i in inBasis) { + if (0 <= i) { + Contract.Assert(i < rows); + numColumnsInBasis++; + } else { + Contract.Assert(i == -1); + } + } + Contract.Assert(rows - numUninitializedRowInfo <= numColumnsInBasis && numColumnsInBasis <= rows); + Contract.Assert(!constructionDone || numUninitializedRowInfo == 0); + } + + /// + /// Constructs a matrix that represents the constraints "constraints", adding slack + /// variables for the inequalities among "constraints". Puts the matrix in canonical + /// form. + /// + /// + [NotDelayed] + public SimplexTableau(ArrayList /*LinearConstraint*//*!*/ constraints) { + Contract.Requires(constraints != null); +#if DEBUG_PRINT + Console.WriteLine("DEBUG: SimplexTableau constructor called with:"); + foreach (LinearConstraint lc in constraints) + { + Console.WriteLine(" {0}", lc); + } +#endif + // Note: This implementation is not particularly efficient, but it'll do for now. + + ArrayList dims = this.dims = new ArrayList /*IVariable!*/ (); + int slacks = 0; + foreach (LinearConstraint/*!*/ cc in constraints) { + Contract.Assert(cc != null); + foreach (IVariable/*!*/ dim in cc.coefficients.Keys) { + Contract.Assert(dim != null); + if (!dims.Contains(dim)) { + dims.Add(dim); + } + } + if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { + slacks++; + } + } + + int numInitialVars = this.numInitialVars = dims.Count; + int numSlackVars = this.numSlackVars = slacks; + int rows = this.rows = constraints.Count; + int columns = this.columns = numInitialVars + numSlackVars + 1; + this.m = new Rational[rows, columns]; + this.rhsColumn = columns - 1; + this.basisColumns = new int[rows]; + this.inBasis = new int[columns - 1]; + + //:base(); + + for (int i = 0; i < inBasis.Length; i++) { + inBasis[i] = -1; + } + + // Fill in the matrix + int r = 0; + int iSlack = 0; + foreach (LinearConstraint/*!*/ cc in constraints) { + Contract.Assert(cc != null); + for (int i = 0; i < dims.Count; i++) { + m[r, i] = cc[(IVariable)cce.NonNull(dims[i])]; + } + if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { + m[r, numInitialVars + iSlack] = Rational.ONE; + basisColumns[r] = numInitialVars + iSlack; + inBasis[numInitialVars + iSlack] = r; + iSlack++; + } else { + basisColumns[r] = -1; // special value to communicate to Pivot that basis column i hasn't been set up yet + } + m[r, rhsColumn] = cc.rhs; + r++; + } + Contract.Assert(r == constraints.Count); + Contract.Assert(iSlack == numSlackVars); +#if DEBUG_PRINT + Console.WriteLine("DEBUG: Intermediate tableau state in SimplexTableau constructor:"); + Dump(); +#endif + + // Go through the rows with uninitialized basis columns. These correspond to equality constraints. + // For each one, find an initial variable (non-slack variable) whose column we can make the basis + // column of the row. + for (int i = 0; i < rows; i++) { + if (basisColumns[i] != -1) { + continue; + } + // Find a non-0 column in row i that we can make a basis column. Since rows corresponding + // to equality constraints don't have slack variables and since the pivot operations performed + // by iterations of this loop don't introduce any non-0 coefficients in the slack-variable + // columns of these rows, we only need to look through the columns corresponding to initial + // variables. + for (int j = 0; j < numInitialVars; j++) { + if (m[i, j].IsNonZero) { +#if DEBUG_PRINT + Console.WriteLine("-- About to Pivot({0},{1})", i, j); +#endif + Contract.Assert(inBasis[j] == -1); + Pivot(i, j); +#if DEBUG_PRINT + Console.WriteLine("Tableau after Pivot:"); + Dump(); +#endif + goto SET_UP_NEXT_INBASIS_COLUMN; + } + } + // Check the assertion in the comment above, that is, that columns corresponding to slack variables + // are 0 in this row. + for (int j = numInitialVars; j < rhsColumn; j++) { + Contract.Assert(m[i, j].IsZero); + } + // There is no column in this row that we can put into basis. + basisColumns[i] = rhsColumn; + SET_UP_NEXT_INBASIS_COLUMN: { + } + } + + constructionDone = true; + CheckInvariant(); + } + + public IMutableSet/*!*/ /*IVariable!*/ GetDimensions() { + Contract.Ensures(Contract.Result() != null); + HashSet /*IVariable!*/ z = new HashSet /*IVariable!*/ (); + foreach (IVariable/*!*/ dim in dims) { + Contract.Assert(dim != null); + z.Add(dim); + } + return z; + } + + public Rational this[int r, int c] { + get { + return m[r, c]; + } + set { + m[r, c] = value; + } + } + + /// + /// Applies the Pivot Operation on row "r" and column "c". + /// + /// This method can be called when !constructionDone, that is, at a time when not all basis + /// columns have been set up (indicated by -1 in basisColumns). This method helps set up + /// those basis columns. + /// + /// The return value is an undo record that can be used with UnPivot. + /// + /// + /// + public Rational[]/*!*/ Pivot(int r, int c) { + Contract.Ensures(Contract.Result() != null); + Contract.Assert(0 <= r && r < rows); + Contract.Assert(0 <= c && c < columns - 1); + Contract.Assert(m[r, c].IsNonZero); + Contract.Assert(inBasis[c] == -1); // follows from invariant and m[r,c] != 0 + Contract.Assert(basisColumns[r] != rhsColumn); // follows from invariant and m[r,c] != 0 + + Rational[] undo = new Rational[rows + 1]; + for (int i = 0; i < rows; i++) { + undo[i] = m[i, c]; + } + + // scale the pivot row + Rational q = m[r, c]; + if (q != Rational.ONE) { + for (int j = 0; j < columns; j++) { + m[r, j] /= q; + } + } + + // subtract a multiple of the pivot row from all other rows + for (int i = 0; i < rows; i++) { + if (i != r) { + q = m[i, c]; + if (q.IsNonZero) { + for (int j = 0; j < columns; j++) { + m[i, j] -= q * m[r, j]; + } + } + } + } + + // update basis information + int prevCol = basisColumns[r]; + undo[rows] = Rational.FromInt(prevCol); + basisColumns[r] = c; + if (prevCol != -1) { + inBasis[prevCol] = -1; + } + inBasis[c] = r; + + return undo; + } + + /// + /// If the last operation applied to the tableau was: + /// undo = Pivot(i,j); + /// then UnPivot(i, j, undo) undoes the pivot operation. + /// Note: This operation is not supported for any call to Pivot before constructionDone + /// is set to true. + /// + /// + /// + /// + void UnPivot(int r, int c, Rational[]/*!*/ undo) { + Contract.Requires(undo != null); + Contract.Assert(0 <= r && r < rows); + Contract.Assert(0 <= c && c < columns - 1); + Contract.Assert(m[r, c].HasValue(1)); + Contract.Assert(undo.Length == rows + 1); + + // add a multiple of the pivot row to all other rows + for (int i = 0; i < rows; i++) { + if (i != r) { + Rational q = undo[i]; + if (q.IsNonZero) { + for (int j = 0; j < columns; j++) { + m[i, j] += q * m[r, j]; + } + } + } + } + + // scale the pivot row + Rational p = undo[r]; + for (int j = 0; j < columns; j++) { + m[r, j] *= p; + } + + // update basis information + int prevCol = undo[rows].AsInteger; + Contract.Assert(prevCol != -1); + basisColumns[r] = prevCol; + inBasis[c] = -1; + inBasis[prevCol] = r; + } + + /// + /// Returns true iff the current basis of the system of constraints modeled by the simplex tableau + /// is feasible. May have a side effect of performing a number of pivot operations on the tableau, + /// but any such pivot operation will be in the columns of slack variables (that is, this routine + /// does not change the set of initial-variable columns in basis). + /// + /// CAVEAT: I have no particular reason to believe that the algorithm used here will terminate. --KRML + /// + /// + public bool IsFeasibleBasis { + get { + // while there is a slack variable in basis whose row has a negative right-hand side + while (true) { + bool feasibleBasis = true; + for (int c = numInitialVars; c < rhsColumn; c++) { + int k = inBasis[c]; + if (0 <= k && k < rhsColumn && m[k, rhsColumn].IsNegative) { + Contract.Assert(m[k, c].HasValue(1)); // c is in basis + // Try to pivot on a different slack variable in this row + for (int i = numInitialVars; i < rhsColumn; i++) { + if (m[k, i].IsNegative) { + Contract.Assert(c != i); // c is in basis, so m[k,c]==1, which is not negative + Pivot(k, i); +#if DEBUG_PRINT + Console.WriteLine("Tableau after Pivot operation on ({0},{1}) in IsFeasibleBasis:", k, i); + Dump(); +#endif + Contract.Assert(inBasis[c] == -1); + Contract.Assert(inBasis[i] == k); + Contract.Assert(m[k, rhsColumn].IsNonNegative); + goto START_ANEW; + } + } + feasibleBasis = false; + } + } + return feasibleBasis; + START_ANEW: + ; + } + } + } + + /// + /// Whether or not all initial variables (the non-slack variables) are in basis) + /// + public bool AllInitialVarsInBasis { + get { + for (int i = 0; i < numInitialVars; i++) { + if (inBasis[i] == -1) { + return false; + } + } + return true; + } + } + + /// + /// Adds as many initial variables as possible to the basis. + /// + /// + public void AddInitialVarsToBasis() { + // while there exists an initial variable not in the basis and not satisfying + // condition 3.4.2.2 in Cousot and Halbwachs, perform a pivot operation + while (true) { + for (int i = 0; i < numInitialVars; i++) { + if (inBasis[i] == -1) { + // initial variable i is not in the basis + for (int j = 0; j < rows; j++) { + if (m[j, i].IsNonZero) { + int k = basisColumns[j]; + if (numInitialVars <= k && k < rhsColumn) { + // slack variable k is in basis for row j + Pivot(j, i); + Contract.Assert(inBasis[k] == -1); + Contract.Assert(inBasis[i] == j && basisColumns[j] == i); + goto START_ANEW; + } + } + } + } + } + // No more initial variables can be moved into basis. + return; + START_ANEW: { + } + } + } + + /// + /// Adds to "lines" the lines implied by initial-variable columns not in basis + /// (see section 3.4.2 of Cousot and Halbwachs), and adds to "constraints" the + /// constraints to exclude those lines (see step 4.2 of section 3.4.3 of + /// Cousot and Halbwachs). + /// + /// + /// + public void ProduceLines(ArrayList /*FrameElement*//*!*/ lines, ArrayList /*LinearConstraint*//*!*/ constraints) { + Contract.Requires(constraints != null); + Contract.Requires(lines != null); + // for every initial variable not in basis + for (int i0 = 0; i0 < numInitialVars; i0++) { + if (inBasis[i0] == -1) { + FrameElement fe = new FrameElement(); + LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ); + for (int i = 0; i < numInitialVars; i++) { + if (i == i0) { + fe.AddCoordinate((IVariable)cce.NonNull(dims[i]), Rational.ONE); + lc.SetCoefficient((IVariable)cce.NonNull(dims[i]), Rational.ONE); + } else if (inBasis[i] != -1) { + // i is a basis column + Contract.Assert(m[inBasis[i], i].HasValue(1)); + Rational val = -m[inBasis[i], i0]; + fe.AddCoordinate((IVariable)cce.NonNull(dims[i]), val); + lc.SetCoefficient((IVariable)cce.NonNull(dims[i]), val); + } + } + lines.Add(fe); + constraints.Add(lc); + } + } + } + + /// + /// From a feasible point where all initial variables are in the basis, traverses + /// all feasible bases containing all initial variables. For each such basis, adds + /// the vertices to "vertices" and adds to "rays" the extreme rays. See step 4.2 + /// in section 3.4.3 of Cousot and Halbwachs. + /// A more efficient algorithm is found in the paper "An algorithm for + /// determining all extreme points of a convex polytope" by N. E. Dyer and L. G. Proll, + /// Mathematical Programming, 12, 1977. + /// Assumes that the tableau is in a state where all initial variables are in the basis. + /// This method has no net effect on the tableau. + /// Note: Duplicate vertices and rays may be added. + /// + /// + /// + public void TraverseVertices(ArrayList/*!*/ /*FrameElement*/ vertices, ArrayList/*!*/ /*FrameElement*/ rays) { + Contract.Requires(vertices != null); + Contract.Requires(rays != null); + ArrayList /*bool[]*/ basesSeenSoFar = new ArrayList /*bool[]*/ (); + TraverseBases(basesSeenSoFar, vertices, rays); + } + + /// + /// Worker method of TraverseVertices. + /// This method has no net effect on the tableau. + /// + /// + /// + /// + void TraverseBases(ArrayList /*bool[]*//*!*/ basesSeenSoFar, ArrayList /*FrameElement*//*!*/ vertices, ArrayList /*FrameElement*//*!*/ rays) { + Contract.Requires(rays != null); + Contract.Requires(vertices != null); + Contract.Requires(basesSeenSoFar != null); + CheckInvariant(); + + bool[] thisBasis = new bool[numSlackVars]; + for (int i = numInitialVars; i < rhsColumn; i++) { + if (inBasis[i] != -1) { + thisBasis[i - numInitialVars] = true; + } + } + foreach (bool[]/*!*/ basis in basesSeenSoFar) { + Contract.Assert(basis != null); + Contract.Assert(basis.Length == numSlackVars); + for (int i = 0; i < numSlackVars; i++) { + if (basis[i] != thisBasis[i]) { + goto COMPARE_WITH_NEXT_BASIS; + } + } + // thisBasis and basis are the same--that is, basisColumns has been visited before--so + // we don't traverse anything from here + return; + COMPARE_WITH_NEXT_BASIS: { + } + } + // basisColumns has not been seen before; record thisBasis and continue with the traversal here + basesSeenSoFar.Add(thisBasis); + +#if DEBUG_PRINT + Console.Write("TraverseBases, new basis: "); + foreach (bool t in thisBasis) { + Console.Write("{0}", t ? "*" : "."); + } + Console.WriteLine(); + Dump(); +#endif + // Add vertex + FrameElement v = new FrameElement(); + for (int i = 0; i < rows; i++) { + int j = basisColumns[i]; + if (j < numInitialVars) { + v.AddCoordinate((IVariable)cce.NonNull(dims[j]), m[i, rhsColumn]); + } + } +#if DEBUG_PRINT + Console.WriteLine(" Adding vertex: {0}", v); +#endif + vertices.Add(v); + + // Add rays. Traverse all columns corresponding to slack variables that + // are not in basis (see second bullet of section 3.4.2 of Cousot and Halbwachs). + for (int i0 = numInitialVars; i0 < rhsColumn; i0++) { + if (inBasis[i0] != -1) { + // skip those slack-variable columns that are in basis + continue; + } + // check if slack-variable, non-basis column i corresponds to an extreme ray + for (int row = 0; row < rows; row++) { + if (m[row, i0].IsPositive) { + for (int k = numInitialVars; k < rhsColumn; k++) { + if (inBasis[k] != -1 && m[row, k].IsNonZero) { + // does not correspond to an extreme ray + goto CHECK_NEXT_SLACK_VAR; + } + } + } + } + // corresponds to an extreme ray + FrameElement ray = new FrameElement(); + for (int i = 0; i < numInitialVars; i++) { + int j0 = inBasis[i]; + Rational val = -m[j0, i0]; + ray.AddCoordinate((IVariable)cce.NonNull(dims[i]), val); + } +#if DEBUG_PRINT + Console.WriteLine(" Adding ray: {0}", ray); +#endif + rays.Add(ray); + CHECK_NEXT_SLACK_VAR: { + } + } + + // Continue traversal + for (int i = numInitialVars; i < rhsColumn; i++) { + int j = inBasis[i]; + if (j != -1) { + // try moving i out of basis and some other slack-variable column into basis + for (int k = numInitialVars; k < rhsColumn; k++) { + if (inBasis[k] == -1 && m[j, k].IsPositive) { + Rational[] undo = Pivot(j, k); + // check if the new basis is feasible + for (int p = 0; p < rows; p++) { + int c = basisColumns[p]; + if (numInitialVars <= c && c < rhsColumn && m[p, rhsColumn].IsNegative) { + // not feasible + goto AFTER_TRAVERSE; + } + } + TraverseBases(basesSeenSoFar, vertices, rays); + AFTER_TRAVERSE: + UnPivot(j, k, undo); + } + } + } + } + } + + public void Dump() { + // names + Console.Write(" "); + for (int i = 0; i < numInitialVars; i++) { + Console.Write(" {0,4} ", dims[i]); + } + Console.WriteLine(); + // numbers + Console.Write(" "); + for (int i = 0; i < columns; i++) { + if (i == numInitialVars || i == rhsColumn) { + Console.Write("|"); + } + Console.Write(" {0,4}", i); + if (i < rhsColumn && inBasis[i] != -1) { + Console.Write("* "); + Contract.Assert(basisColumns[inBasis[i]] == i); + } else { + Console.Write(" "); + } + } + Console.WriteLine(); + // line + Console.Write(" "); + for (int i = 0; i < columns; i++) { + if (i == numInitialVars || i == rhsColumn) { + Console.Write("+"); + } + Console.Write("---------"); + } + Console.WriteLine(); + + for (int j = 0; j < rows; j++) { + Console.Write("{0,4}: ", basisColumns[j]); + for (int i = 0; i < columns; i++) { + if (i == numInitialVars || i == rhsColumn) { + Console.Write("|"); + } + Console.Write(" {0,4:n1} ", m[j, i]); + } + Console.WriteLine(); + } + } + } +} diff --git a/Source/AIFramework/VariableMap/ConstantAbstraction.cs b/Source/AIFramework/VariableMap/ConstantAbstraction.cs index d8f17a3c..d73fc28b 100644 --- a/Source/AIFramework/VariableMap/ConstantAbstraction.cs +++ b/Source/AIFramework/VariableMap/ConstantAbstraction.cs @@ -1,251 +1,251 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System.Diagnostics.Contracts; -namespace Microsoft.AbstractInterpretationFramework { - using System.Collections; - using System.Diagnostics; - //using System.Compiler.Analysis; - using Microsoft.Basetypes; - - /// - /// Represents an invariant over constant variable assignments. - /// - public class ConstantLattice : MicroLattice { - enum Value { - Top, - Bottom, - Constant - } - - private class Elt : Element { - public Value domainValue; - public BigNum constantValue; // valid iff domainValue == Value.Constant - - public Elt(Value v) { - this.domainValue = v; - } - - public Elt(BigNum i) { - this.domainValue = Value.Constant; - this.constantValue = i; - } - - public bool IsConstant { - get { - return this.domainValue == Value.Constant; - } - } - - public BigNum Constant { - get { - return this.constantValue; - } - } // only when IsConstant - - [Pure] - public override System.Collections.Generic.ICollection/*!*/ FreeVariables() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return cce.NonNull(new System.Collections.Generic.List()).AsReadOnly(); - } - - public override Element/*!*/ Clone() { - Contract.Ensures(Contract.Result() != null); - if (this.IsConstant) - return new Elt(constantValue); - else - return new Elt(domainValue); - } - } - - readonly IIntExprFactory/*!*/ factory; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(factory != null); - } - - - public ConstantLattice(IIntExprFactory/*!*/ factory) { - Contract.Requires(factory != null); - this.factory = factory; - // base(); - } - - public override Element/*!*/ Top { - get { - Contract.Ensures(Contract.Result() != null); - return new Elt(Value.Top); - } - } - - public override Element/*!*/ Bottom { - get { - Contract.Ensures(Contract.Result() != null); - return new Elt(Value.Bottom); - } - } - - public override bool IsTop(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - return e.domainValue == Value.Top; - } - - public override bool IsBottom(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - return e.domainValue == Value.Bottom; - } - - public override Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - Debug.Assert(a.domainValue == Value.Constant && b.domainValue == Value.Constant); - return (a.constantValue.Equals(b.constantValue)) ? a : (Elt)Top; - } - - public override Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - Debug.Assert(a.domainValue == Value.Constant && b.domainValue == Value.Constant); - return (a.constantValue.Equals(b.constantValue)) ? a : (Elt)Bottom; - } - - public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - return Join(first, second); - } - - protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that - { - //Contract.Requires(first!= null); - //Contract.Requires(second != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - return a.Constant.Equals(b.Constant); - } - - public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { - //Contract.Requires(element != null); - //Contract.Requires(var != null); - Contract.Ensures(Contract.Result() != null); - return factory.Eq(var, cce.NonNull(GetFoldExpr(element))); - } - - public override IExpr GetFoldExpr(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - Contract.Assert(e.domainValue == Value.Constant); - return factory.Const(e.constantValue); - } - - public override bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args) { - //Contract.Requires(args != null); - //Contract.Requires(f != null); - return f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq); - } - - public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ e) { - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - - IFunApp nary = e as IFunApp; - if (nary != null) { - if (nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq)) { - IList/**//*!*/ args = nary.Arguments; - Contract.Assert(args != null); - Contract.Assert(args.Count == 2); - IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); - IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); - - // Look for "x == const" or "const == x". - try { - if (arg0 is IVariable) { - BigNum z; - if (Fold(arg1, out z)) { - return new Elt(z); - } - } else if (arg1 is IVariable) { - BigNum z; - if (Fold(arg0, out z)) { - return new Elt(z); - } - } - } catch (System.ArithmeticException) { - // fall through and return Top. (Note, an alternative design may - // consider returning Bottom.) - } - } - } - return Top; - } - - /// - /// Returns true if "expr" represents a constant integer expressions, in which case - /// "z" returns as that integer. Otherwise, returns false, in which case "z" should - /// not be used by the caller. - /// - /// This method throws an System.ArithmeticException in the event that folding the - /// constant expression results in an arithmetic overflow or division by zero. - /// - private bool Fold(IExpr/*!*/ expr, out BigNum z) { - Contract.Requires(expr != null); - IFunApp e = expr as IFunApp; - if (e == null) { - z = BigNum.ZERO; - return false; - } - - if (e.FunctionSymbol is IntSymbol) { - z = ((IntSymbol)e.FunctionSymbol).Value; - return true; - - } else if (e.FunctionSymbol.Equals(Int.Negate)) { - IList/**//*!*/ args = e.Arguments; - Contract.Assert(args != null); - Contract.Assert(args.Count == 1); - IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); - - if (Fold(arg0, out z)) { - z = z.Neg; - return true; - } - - } else if (e.Arguments.Count == 2) { - IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(e.Arguments[0]); - IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(e.Arguments[1]); - BigNum z0, z1; - if (Fold(arg0, out z0) && Fold(arg1, out z1)) { - if (e.FunctionSymbol.Equals(Int.Add)) { - z = z0 + z1; - } else if (e.FunctionSymbol.Equals(Int.Sub)) { - z = z0 - z1; - } else if (e.FunctionSymbol.Equals(Int.Mul)) { - z = z0 * z1; - } else if (e.FunctionSymbol.Equals(Int.Div)) { - z = z0 / z1; - } else if (e.FunctionSymbol.Equals(Int.Mod)) { - z = z0 % z1; - } else { - z = BigNum.ZERO; - return false; - } - return true; - } - } - - z = BigNum.ZERO; - return false; - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System.Diagnostics.Contracts; +namespace Microsoft.AbstractInterpretationFramework { + using System.Collections; + using System.Diagnostics; + //using System.Compiler.Analysis; + using Microsoft.Basetypes; + + /// + /// Represents an invariant over constant variable assignments. + /// + public class ConstantLattice : MicroLattice { + enum Value { + Top, + Bottom, + Constant + } + + private class Elt : Element { + public Value domainValue; + public BigNum constantValue; // valid iff domainValue == Value.Constant + + public Elt(Value v) { + this.domainValue = v; + } + + public Elt(BigNum i) { + this.domainValue = Value.Constant; + this.constantValue = i; + } + + public bool IsConstant { + get { + return this.domainValue == Value.Constant; + } + } + + public BigNum Constant { + get { + return this.constantValue; + } + } // only when IsConstant + + [Pure] + public override System.Collections.Generic.ICollection/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return cce.NonNull(new System.Collections.Generic.List()).AsReadOnly(); + } + + public override Element/*!*/ Clone() { + Contract.Ensures(Contract.Result() != null); + if (this.IsConstant) + return new Elt(constantValue); + else + return new Elt(domainValue); + } + } + + readonly IIntExprFactory/*!*/ factory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(factory != null); + } + + + public ConstantLattice(IIntExprFactory/*!*/ factory) { + Contract.Requires(factory != null); + this.factory = factory; + // base(); + } + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result() != null); + return new Elt(Value.Top); + } + } + + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result() != null); + return new Elt(Value.Bottom); + } + } + + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return e.domainValue == Value.Top; + } + + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return e.domainValue == Value.Bottom; + } + + public override Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + Debug.Assert(a.domainValue == Value.Constant && b.domainValue == Value.Constant); + return (a.constantValue.Equals(b.constantValue)) ? a : (Elt)Top; + } + + public override Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + Debug.Assert(a.domainValue == Value.Constant && b.domainValue == Value.Constant); + return (a.constantValue.Equals(b.constantValue)) ? a : (Elt)Bottom; + } + + public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + return Join(first, second); + } + + protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that + { + //Contract.Requires(first!= null); + //Contract.Requires(second != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + return a.Constant.Equals(b.Constant); + } + + public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { + //Contract.Requires(element != null); + //Contract.Requires(var != null); + Contract.Ensures(Contract.Result() != null); + return factory.Eq(var, cce.NonNull(GetFoldExpr(element))); + } + + public override IExpr GetFoldExpr(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + Contract.Assert(e.domainValue == Value.Constant); + return factory.Const(e.constantValue); + } + + public override bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + return f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq); + } + + public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ e) { + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + + IFunApp nary = e as IFunApp; + if (nary != null) { + if (nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq)) { + IList/**//*!*/ args = nary.Arguments; + Contract.Assert(args != null); + Contract.Assert(args.Count == 2); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); + + // Look for "x == const" or "const == x". + try { + if (arg0 is IVariable) { + BigNum z; + if (Fold(arg1, out z)) { + return new Elt(z); + } + } else if (arg1 is IVariable) { + BigNum z; + if (Fold(arg0, out z)) { + return new Elt(z); + } + } + } catch (System.ArithmeticException) { + // fall through and return Top. (Note, an alternative design may + // consider returning Bottom.) + } + } + } + return Top; + } + + /// + /// Returns true if "expr" represents a constant integer expressions, in which case + /// "z" returns as that integer. Otherwise, returns false, in which case "z" should + /// not be used by the caller. + /// + /// This method throws an System.ArithmeticException in the event that folding the + /// constant expression results in an arithmetic overflow or division by zero. + /// + private bool Fold(IExpr/*!*/ expr, out BigNum z) { + Contract.Requires(expr != null); + IFunApp e = expr as IFunApp; + if (e == null) { + z = BigNum.ZERO; + return false; + } + + if (e.FunctionSymbol is IntSymbol) { + z = ((IntSymbol)e.FunctionSymbol).Value; + return true; + + } else if (e.FunctionSymbol.Equals(Int.Negate)) { + IList/**//*!*/ args = e.Arguments; + Contract.Assert(args != null); + Contract.Assert(args.Count == 1); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); + + if (Fold(arg0, out z)) { + z = z.Neg; + return true; + } + + } else if (e.Arguments.Count == 2) { + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(e.Arguments[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(e.Arguments[1]); + BigNum z0, z1; + if (Fold(arg0, out z0) && Fold(arg1, out z1)) { + if (e.FunctionSymbol.Equals(Int.Add)) { + z = z0 + z1; + } else if (e.FunctionSymbol.Equals(Int.Sub)) { + z = z0 - z1; + } else if (e.FunctionSymbol.Equals(Int.Mul)) { + z = z0 * z1; + } else if (e.FunctionSymbol.Equals(Int.Div)) { + z = z0 / z1; + } else if (e.FunctionSymbol.Equals(Int.Mod)) { + z = z0 % z1; + } else { + z = BigNum.ZERO; + return false; + } + return true; + } + } + + z = BigNum.ZERO; + return false; + } + } +} diff --git a/Source/AIFramework/VariableMap/ConstantExpressions.cs b/Source/AIFramework/VariableMap/ConstantExpressions.cs index fcf49b25..185c700e 100644 --- a/Source/AIFramework/VariableMap/ConstantExpressions.cs +++ b/Source/AIFramework/VariableMap/ConstantExpressions.cs @@ -1,538 +1,538 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- - - ///////////////////////////////////////////////////////////////////////////////// - // The Abstract domain for determining "constant" expressions - // i.e. It determines which expression are statically binded - ///////////////////////////////////////////////////////////////////////////////// -/* -using System; - -namespace Microsoft.AbstractInterpretationFramework -{ - using Microsoft.Contracts; - using System.Collections.Generic; - using Microsoft.AbstractInterpretationFramework; - - /// - /// This is an abstract domain for inferring constant expressions - /// - - public class ConstantExpressions : Lattice - { - /// - /// An abstract element is made of two maps: - /// + A map from variables to expressions \cup top ( i.e. for each variable, the expression it is binded ) - /// + A map from variables to set of variabes ( i.e. for each variable, the set of variables that depends on its value ) - /// - private class AbstractElement: Element - { - private Dictionary variableBindings; - private Dictionary> variableDependences; - - static private AbstractElement! bottom; - static public Element! Bottom - { - get - { - if(bottom == null) - { - bottom = new AbstractElement(); - bottom.variableBindings = null; - bottom.variableDependences = null; - } - assert bottom.variableBindings == null && bottom.variableDependences == null; - return bottom; - } - } - - static public Element! Top - { - get - { - return new AbstractElement(); - } - } - - AbstractElement() - { - this.variableBindings = new Dictionary(); - this.variableDependences = new Dictionary>(); - } - - /// - /// Our abstract element is top if and only if it has any constraint on variables - /// - public bool IsTop - { - get - { - return this.variableBindings.Keys.Count == 0 && this.variableDependences.Keys.Count == 0; - } - } - - /// - /// Our abstract element is bottom if and only if the maps are null - /// - public bool IsBottom - { - get - { - assert (this.variableBindings == null) <==> (this.variableDependences == null); +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- + + ///////////////////////////////////////////////////////////////////////////////// + // The Abstract domain for determining "constant" expressions + // i.e. It determines which expression are statically binded + ///////////////////////////////////////////////////////////////////////////////// +/* +using System; + +namespace Microsoft.AbstractInterpretationFramework +{ + using Microsoft.Contracts; + using System.Collections.Generic; + using Microsoft.AbstractInterpretationFramework; + + /// + /// This is an abstract domain for inferring constant expressions + /// + + public class ConstantExpressions : Lattice + { + /// + /// An abstract element is made of two maps: + /// + A map from variables to expressions \cup top ( i.e. for each variable, the expression it is binded ) + /// + A map from variables to set of variabes ( i.e. for each variable, the set of variables that depends on its value ) + /// + private class AbstractElement: Element + { + private Dictionary variableBindings; + private Dictionary> variableDependences; + + static private AbstractElement! bottom; + static public Element! Bottom + { + get + { + if(bottom == null) + { + bottom = new AbstractElement(); + bottom.variableBindings = null; + bottom.variableDependences = null; + } + assert bottom.variableBindings == null && bottom.variableDependences == null; + return bottom; + } + } + + static public Element! Top + { + get + { + return new AbstractElement(); + } + } + + AbstractElement() + { + this.variableBindings = new Dictionary(); + this.variableDependences = new Dictionary>(); + } + + /// + /// Our abstract element is top if and only if it has any constraint on variables + /// + public bool IsTop + { + get + { + return this.variableBindings.Keys.Count == 0 && this.variableDependences.Keys.Count == 0; + } + } + + /// + /// Our abstract element is bottom if and only if the maps are null + /// + public bool IsBottom + { + get + { + assert (this.variableBindings == null) <==> (this.variableDependences == null); return this.variableBindings == null && this.variableDependences == null; - } - } - - /// - /// The pointwise join... - /// - public static AbstractElement! Join(AbstractElement! left, AbstractElement! right) - { + } + } + + /// + /// The pointwise join... + /// + public static AbstractElement! Join(AbstractElement! left, AbstractElement! right) + { AbstractElement! result = new AbstractElement(); - - // Put all the variables in the left - foreach(IVariable! var in left.variableBindings.Keys) - { - BindExpr leftVal = left.variableBindings[var]; - assert leftVal != null; - - BindExpr rightVal = right.variableBindings[var]; - - if(rightVal== null) // the expression is not there - { + + // Put all the variables in the left + foreach(IVariable! var in left.variableBindings.Keys) + { + BindExpr leftVal = left.variableBindings[var]; + assert leftVal != null; + + BindExpr rightVal = right.variableBindings[var]; + + if(rightVal== null) // the expression is not there + { result.variableBindings.Add(var, leftVal); - } - else // both abstract elements have a definition for the variable.... - { - result.variableBindings.Add(var, BindExpr.Join(leftVal, rightVal)); - } - } - - // Put all the variables in the right - foreach(IVariable! var in right.variableBindings.Keys) - { - BindExpr rightVal = right.variableBindings[var]; - assert rightVal != null; - - BindExpr leftVal = left.variableBindings[var]; - - if(rightVal== null) // the expression is not there - { + } + else // both abstract elements have a definition for the variable.... + { + result.variableBindings.Add(var, BindExpr.Join(leftVal, rightVal)); + } + } + + // Put all the variables in the right + foreach(IVariable! var in right.variableBindings.Keys) + { + BindExpr rightVal = right.variableBindings[var]; + assert rightVal != null; + + BindExpr leftVal = left.variableBindings[var]; + + if(rightVal== null) // the expression is not there + { result.variableBindings.Add(var, rightVal); - } - else // both abstract elements have a definition for the variable.... - { - result.variableBindings.Add(var, BindExpr.Join(rightVal, leftVal)); - } - } - - // Join the dependencies... - foreach(IVariable! var in left.variableDependences.Keys) - { - List dependencies = left.variableDependences[var]; - List dup = new List(dependencies); - - result.variableDependences.Add(var, dup); - } - - foreach(IVariable! var in right.variableDependences.Keys) - { - if(result.variableDependences.ContainsKey(var)) - { - List dependencies = result.variableDependences[var]; - dependencies.AddRange(right.variableDependences[var]); - } - else - { - List dependencies = right.variableDependences[var]; - List dup = new List(dependencies); - - result.variableDependences.Add(var, dup); - } - } - - // Normalize... i.e. for the variables such thas they point to an unknown expression (top) we have to update also their values - result.Normalize(); - - return result; - } - - - /// - /// Normalize the current abstract element, in that it propagetes the "dynamic" information throughtout the abstract element - /// - public void Normalize() - { - if(this.IsBottom) - return; - if(this.IsTop) - return; - assert this.variableBindings != null; - - bool atFixpoint = false; - - while(!atFixpoint) - { - atFixpoint = true; // guess that we've got the fixpoint... - - foreach(IVariable x in this.variableBindings.Keys) - { - if(this.variableBindings[x].IsTop) // It means that the variable is tied to a dynamic expression - { - foreach(IVariable y in this.variableDependences[x]) // The all the variables that depend on x are also dynamic... - { - assert x != y; // A variable cannot depend on itself... - if(!this.variableBindings[y].IsTop) - { - this.variableBindings[y] = BindExpr.Top; - atFixpoint = false; // the assumption that we were at the fixpoint was false, we have still to propagate some information... - } - } - } - } - } - } - - /// - /// The pointwise meet... - /// - public static AbstractElement! Meet(AbstractElement! left, AbstractElement! right) - { - AbstractElement! result = new AbstractElement(); - - // Put the variables that are both in left and right - foreach(IVariable var in left.variableBindings.Keys) - { - if(right.variableBindings.ContainsKey(var)) - { - result.variableBindings.Add(var, BindExpr.Meet(left.variableBindings[var], right.variableBindings[var])); - } - } - - // Intersect the dependencies - foreach(IVariable var in result.variableBindings.Keys) - { - List depLeft = left.variableDependences[var]; - List depRight = right.variableDependences[var]; - - // Intersect the two sets + } + else // both abstract elements have a definition for the variable.... + { + result.variableBindings.Add(var, BindExpr.Join(rightVal, leftVal)); + } + } + + // Join the dependencies... + foreach(IVariable! var in left.variableDependences.Keys) + { + List dependencies = left.variableDependences[var]; + List dup = new List(dependencies); + + result.variableDependences.Add(var, dup); + } + + foreach(IVariable! var in right.variableDependences.Keys) + { + if(result.variableDependences.ContainsKey(var)) + { + List dependencies = result.variableDependences[var]; + dependencies.AddRange(right.variableDependences[var]); + } + else + { + List dependencies = right.variableDependences[var]; + List dup = new List(dependencies); + + result.variableDependences.Add(var, dup); + } + } + + // Normalize... i.e. for the variables such thas they point to an unknown expression (top) we have to update also their values + result.Normalize(); + + return result; + } + + + /// + /// Normalize the current abstract element, in that it propagetes the "dynamic" information throughtout the abstract element + /// + public void Normalize() + { + if(this.IsBottom) + return; + if(this.IsTop) + return; + assert this.variableBindings != null; + + bool atFixpoint = false; + + while(!atFixpoint) + { + atFixpoint = true; // guess that we've got the fixpoint... + + foreach(IVariable x in this.variableBindings.Keys) + { + if(this.variableBindings[x].IsTop) // It means that the variable is tied to a dynamic expression + { + foreach(IVariable y in this.variableDependences[x]) // The all the variables that depend on x are also dynamic... + { + assert x != y; // A variable cannot depend on itself... + if(!this.variableBindings[y].IsTop) + { + this.variableBindings[y] = BindExpr.Top; + atFixpoint = false; // the assumption that we were at the fixpoint was false, we have still to propagate some information... + } + } + } + } + } + } + + /// + /// The pointwise meet... + /// + public static AbstractElement! Meet(AbstractElement! left, AbstractElement! right) + { + AbstractElement! result = new AbstractElement(); + + // Put the variables that are both in left and right + foreach(IVariable var in left.variableBindings.Keys) + { + if(right.variableBindings.ContainsKey(var)) + { + result.variableBindings.Add(var, BindExpr.Meet(left.variableBindings[var], right.variableBindings[var])); + } + } + + // Intersect the dependencies + foreach(IVariable var in result.variableBindings.Keys) + { + List depLeft = left.variableDependences[var]; + List depRight = right.variableDependences[var]; + + // Intersect the two sets result.variableDependences.Add(var, depLeft); - foreach(IVariable v in depRight) - { - if(!result.variableDependences.ContainsKey(v)) - { + foreach(IVariable v in depRight) + { + if(!result.variableDependences.ContainsKey(v)) + { result.variableDependences.Remove(v); - } - } - } - - // Now we remove the dependencies with variables not in variableBindings + } + } + } + + // Now we remove the dependencies with variables not in variableBindings List! varsToRemove = new List(); - - foreach(IVariable var in result. - - - } - - /// - /// Clone the current abstract element - /// - public override Element! Clone() - { - AbstractElement cloned = new AbstractElement(); - foreach(IVariable var in this.variableBindings.Keys) - { - cloned.variableBindings.Add(var, this.variableBindings[var]); - } - - foreach(IVariable var in this.variableDependences.Keys) - { - List dependingVars = this.variableDependences[var]; - List clonedDependingVars = new List(dependingVars); + + foreach(IVariable var in result. + + + } + + /// + /// Clone the current abstract element + /// + public override Element! Clone() + { + AbstractElement cloned = new AbstractElement(); + foreach(IVariable var in this.variableBindings.Keys) + { + cloned.variableBindings.Add(var, this.variableBindings[var]); + } + + foreach(IVariable var in this.variableDependences.Keys) + { + List dependingVars = this.variableDependences[var]; + List clonedDependingVars = new List(dependingVars); cloned.variableDependences.Add(var, clonedDependingVars); - } - } - - /// - /// Return the variables that have a binding - /// - public override ICollection! FreeVariables() - { - List vars = new List(this.variableBindings.Keys); - - return vars; - } - - public override string! ToString() - { + } + } + + /// + /// Return the variables that have a binding + /// + public override ICollection! FreeVariables() + { + List vars = new List(this.variableBindings.Keys); + + return vars; + } + + public override string! ToString() + { string! retString = ""; - retString += "Bindings"; - - foreach(IVariable var in this.variableBindings.Keys) - { - string! toAdd = var.ToString() + " -> " + this.variableBindings[var]; - retString += toAdd + ","; - } - - retString += "\nDependencies"; - foreach(IVariable var in this.variableDependences.Keys) - { - string! toAdd = var.ToString() + " -> " + this.variableDependences[var]; - retString += toAdd + ","; - } - - return retString; - } - } - - public override Element! Top - { - get - { - return AbstractElement.Top; - } - } - - public override Element! Bottom - { - get - { - return AbstractElement.Bottom; - } - } - - public override bool IsTop(Element! e) - { - assert e is AbstractElement; - AbstractElement! absElement = (AbstractElement) e; - - return absElement.IsTop; - } - - public override bool IsBottom(Element! e) - { - assert e is AbstractElement; - AbstractElement absElement = (AbstractElement) e; - return absElement.IsBottom; - } - - /// - /// Perform the pointwise join of the two abstract elements - /// - public override Element! NontrivialJoin(Element! a, Element! b) - { - assert a is AbstractElement; - assert b is AbstractElement; - - AbstractElement! left = (AbstractElement!) a; - AbstractElement! right = (AbstractElement!) b; - - return AbstractElement.Join(left, right); - } - - /// - /// Perform the pointwise meet of two abstract elements - /// - public override Element! NontrivialMeet(Element! a, Element!b) - { - assert a is AbstractElement; - assert b is AbstractElement; - - AbstractElement! left = (AbstractElement!) a; - AbstractElement! right = (AbstractElement!) b; - - return AbstractElement.Meet(left, right); - } - - - } - - /// - /// A wrapper in order to have the algebraic datatype BindExpr := IExpr | Top - /// - abstract class BindExpr - { - /// - /// True iff this expression is instance of BindExprTop - /// - public bool IsTop - { - get - { - return this is BindExprTop; - } - } - - static public BindExpr Top - { - get - { - return BindExprTop.UniqueTop; - } - } - - /// - /// True iff this expression is instance of BindExprBottom - /// - public bool IsBottom - { - get - { - return this is BindExprBottom; - } - } - - static public BindExpr Bottom - { - get - { - return BindExprBottom.UniqueBottom; - } - } - - public static BindExpr! Join(BindExpr! left, BindExpr! right) - { - if(left.IsTop || right.IsTop) - { - return BindExpr.Top; - } - else if(left.IsBottom) - { - return right; - } - else if(right.IsBottom) - { - return left; - } - else if(left.EmbeddedExpr != right.EmbeddedExpr) - { - return BindExpr.Top; - } - else // left.EmbeddedExpr == right.EmbeddedExpr - { - return left; - } - } - - public static BindExpr! Meet(BindExpr! left, BindExpr! right) - { - if(left.IsTop) - { - return right; - } - else if(right.IsTop) - { - return right; - } - else if(left.IsBottom || right.IsBottom) - { - return BindExpr.Bottom; - } - else if(left.EmbeddedExpr != right.EmbeddedExpr) - { - return BindExpr.Bottom; - } - else // left.EmbeddedExpr == right.EmbeddedExpr - { - return left; - } - } - - abstract public IExpr! EmbeddedExpr - { - get; - } - - } - - /// - /// A wrapper for an integer - /// - class Expr : BindExpr - { - private IExpr! exp; - - public Expr(IExpr! exp) - { - this.exp = exp; - } - - override public IExpr! EmbeddedExpr - { - get - { - return this.exp; - } - } - - public override string! ToString() - { - return this.exp.ToString(); - } - } - - /// - /// The dynamic expression - /// - class BindExprTop : BindExpr - { - private BindExprTop top = new BindExprTop(); - static public BindExprTop! UniqueTop - { - get - { - return this.top; - } - } - - private BindExprTop() {} - - override public IExpr! EmbeddedExpr - { - get - { - assert false; // If we get there, we have an error - } - } - - public override string! ToString() - { - return ""; - } - } - - /// - /// The unreachable expression - /// - class BindExprBottom : BindExpr - { - private BindExprBottom! bottom = new BindExprBottom(); - static public BindExprBottom! UniqueBottom - { - get - { - return this.bottom; - } - } - - private BindExprBottom() {} - - override public IExpr! EmbeddedExpr - { - get - { - assert false; - } - } - - public override string! ToString() - { - return ""; - } - } - -} // end namespace Microsoft.AbstractInterpretationFramework + retString += "Bindings"; + + foreach(IVariable var in this.variableBindings.Keys) + { + string! toAdd = var.ToString() + " -> " + this.variableBindings[var]; + retString += toAdd + ","; + } + + retString += "\nDependencies"; + foreach(IVariable var in this.variableDependences.Keys) + { + string! toAdd = var.ToString() + " -> " + this.variableDependences[var]; + retString += toAdd + ","; + } + + return retString; + } + } + + public override Element! Top + { + get + { + return AbstractElement.Top; + } + } + + public override Element! Bottom + { + get + { + return AbstractElement.Bottom; + } + } + + public override bool IsTop(Element! e) + { + assert e is AbstractElement; + AbstractElement! absElement = (AbstractElement) e; + + return absElement.IsTop; + } + + public override bool IsBottom(Element! e) + { + assert e is AbstractElement; + AbstractElement absElement = (AbstractElement) e; + return absElement.IsBottom; + } + + /// + /// Perform the pointwise join of the two abstract elements + /// + public override Element! NontrivialJoin(Element! a, Element! b) + { + assert a is AbstractElement; + assert b is AbstractElement; + + AbstractElement! left = (AbstractElement!) a; + AbstractElement! right = (AbstractElement!) b; + + return AbstractElement.Join(left, right); + } + + /// + /// Perform the pointwise meet of two abstract elements + /// + public override Element! NontrivialMeet(Element! a, Element!b) + { + assert a is AbstractElement; + assert b is AbstractElement; + + AbstractElement! left = (AbstractElement!) a; + AbstractElement! right = (AbstractElement!) b; + + return AbstractElement.Meet(left, right); + } + + + } + + /// + /// A wrapper in order to have the algebraic datatype BindExpr := IExpr | Top + /// + abstract class BindExpr + { + /// + /// True iff this expression is instance of BindExprTop + /// + public bool IsTop + { + get + { + return this is BindExprTop; + } + } + + static public BindExpr Top + { + get + { + return BindExprTop.UniqueTop; + } + } + + /// + /// True iff this expression is instance of BindExprBottom + /// + public bool IsBottom + { + get + { + return this is BindExprBottom; + } + } + + static public BindExpr Bottom + { + get + { + return BindExprBottom.UniqueBottom; + } + } + + public static BindExpr! Join(BindExpr! left, BindExpr! right) + { + if(left.IsTop || right.IsTop) + { + return BindExpr.Top; + } + else if(left.IsBottom) + { + return right; + } + else if(right.IsBottom) + { + return left; + } + else if(left.EmbeddedExpr != right.EmbeddedExpr) + { + return BindExpr.Top; + } + else // left.EmbeddedExpr == right.EmbeddedExpr + { + return left; + } + } + + public static BindExpr! Meet(BindExpr! left, BindExpr! right) + { + if(left.IsTop) + { + return right; + } + else if(right.IsTop) + { + return right; + } + else if(left.IsBottom || right.IsBottom) + { + return BindExpr.Bottom; + } + else if(left.EmbeddedExpr != right.EmbeddedExpr) + { + return BindExpr.Bottom; + } + else // left.EmbeddedExpr == right.EmbeddedExpr + { + return left; + } + } + + abstract public IExpr! EmbeddedExpr + { + get; + } + + } + + /// + /// A wrapper for an integer + /// + class Expr : BindExpr + { + private IExpr! exp; + + public Expr(IExpr! exp) + { + this.exp = exp; + } + + override public IExpr! EmbeddedExpr + { + get + { + return this.exp; + } + } + + public override string! ToString() + { + return this.exp.ToString(); + } + } + + /// + /// The dynamic expression + /// + class BindExprTop : BindExpr + { + private BindExprTop top = new BindExprTop(); + static public BindExprTop! UniqueTop + { + get + { + return this.top; + } + } + + private BindExprTop() {} + + override public IExpr! EmbeddedExpr + { + get + { + assert false; // If we get there, we have an error + } + } + + public override string! ToString() + { + return ""; + } + } + + /// + /// The unreachable expression + /// + class BindExprBottom : BindExpr + { + private BindExprBottom! bottom = new BindExprBottom(); + static public BindExprBottom! UniqueBottom + { + get + { + return this.bottom; + } + } + + private BindExprBottom() {} + + override public IExpr! EmbeddedExpr + { + get + { + assert false; + } + } + + public override string! ToString() + { + return ""; + } + } + +} // end namespace Microsoft.AbstractInterpretationFramework */ \ No newline at end of file diff --git a/Source/AIFramework/VariableMap/DynamicTypeLattice.cs b/Source/AIFramework/VariableMap/DynamicTypeLattice.cs index 78bd61a0..edda7c1e 100644 --- a/Source/AIFramework/VariableMap/DynamicTypeLattice.cs +++ b/Source/AIFramework/VariableMap/DynamicTypeLattice.cs @@ -1,511 +1,511 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework { - using System.Collections; - using System.Diagnostics; - //using System.Compiler.Analysis; - //using Microsoft.SpecSharp.Collections; - using System.Diagnostics.Contracts; - - /// - /// Represents information about the dynamic type of a variable. In particular, for a - /// variable "v", represents either Bottom, "typeof(v)==T" for some type T, or a set - /// of constraints "typeof(v) subtype of T_i for some number of T_i's. - /// - public class DynamicTypeLattice : MicroLattice { - enum What { - Bottom, - Exact, - Bounds - } - - private class Elt : Element { - // Representation: - // - Bottom is represented by: what==What.Bottom - // - An exact type T is represented by: what==What.Exact && ty==T - // - A set of type constraints T0, T1, T2, ..., T{n-1} is represented by: - // -- if n==0: what==What.Bounds && ty==null && manyBounds==null - // -- if n==1: what==What.Bounds && ty==T0 && manyBounds==null - // -- if n>=2: what==What.Bounds && ty==null && - // manyBounds!=null && manyBounds.Length==n && - // manyBounds[0]==T0 && manyBounds[1]==T1 && ... && manyBounds[n-1]==T{n-1} - // The reason for keeping the one-and-only bound in "ty" in case n==1 is to try - // to prevent the need for allocating a whole array of bounds, since 1 bound is - // bound to be common. - // In the representation, there are no redundant bounds in manyBounds. - // It is assumed that the types can can occur as exact bounds form a single-inheritance - // hierarchy. That is, if T0 and T1 are types that can occur as exact types, then - // there is no v such that typeof(v) is a subtype of both T0 and T1, unless T0 and T1 are - // the same type. - public readonly What what; - public readonly IExpr ty; - [Rep] - public readonly IExpr[] manyBounds; - [ContractInvariantMethod] - void ObjectInvariant() { - - Contract.Invariant(what != What.Bottom || ty == null && manyBounds == null); - Contract.Invariant(manyBounds == null || what == What.Bounds); - Contract.Invariant(manyBounds == null || Contract.ForAll(0, manyBounds.Length, i => manyBounds[i] != null)); - } - public Elt(What what, IExpr ty) { - Contract.Requires(what != What.Bottom || ty == null); - Contract.Requires(what != What.Exact || ty != null); - this.what = what; - this.ty = ty; - this.manyBounds = null; - } - - public Elt(IExpr[]/*!*/ bounds) { - Contract.Requires(bounds != null); - Contract.Requires(Contract.ForAll(0, bounds.Length, i => bounds[i] != null)); - this.what = What.Bounds; - if (bounds.Length == 0) { - this.ty = null; - this.manyBounds = null; - } else if (bounds.Length == 1) { - this.ty = bounds[0]; - this.manyBounds = null; - } else { - this.ty = null; - this.manyBounds = bounds; - } - } - - /// - /// Constructs an Elt with "n" bounds, namely the n non-null values of the "bounds" list. - /// - [NotDelayed] - public Elt(ArrayList /*IExpr*//*!*/ bounds, int n) { - Contract.Requires(bounds != null); - Contract.Requires(0 <= n && n <= bounds.Count); - this.what = What.Bounds; - if (n > 1) { - this.manyBounds = new IExpr[n]; - } - int k = 0; - foreach (IExpr bound in bounds) { - if (bound != null) { - Contract.Assert(k != n); - if (n == 1) { - Contract.Assert(this.ty == null); - this.ty = bound; - } else { - Contract.Assume(manyBounds != null); - manyBounds[k] = bound; - } - k++; - } - } - Contract.Assert(k == n); - } - - public int BoundsCount { - get { - Contract.Ensures(0 <= Contract.Result()); - if (manyBounds != null) { - return manyBounds.Length; - } else if (ty != null) { - return 1; - } else { - return 0; - } - } - } - - [Pure] - public override System.Collections.Generic.ICollection/*!*/ FreeVariables() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return cce.NonNull(new System.Collections.Generic.List()).AsReadOnly(); - } - - public override Element/*!*/ Clone() { - Contract.Ensures(Contract.Result() != null); - if (this.manyBounds != null) - return new Elt(this.manyBounds); - else - return new Elt(this.what, this.ty); - } - } - - readonly ITypeExprFactory/*!*/ factory; - readonly IPropExprFactory/*!*/ propFactory; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(factory != null); - Contract.Invariant(propFactory != null); - } - - - public DynamicTypeLattice(ITypeExprFactory/*!*/ factory, IPropExprFactory/*!*/ propFactory) { - Contract.Requires(propFactory != null); - Contract.Requires(factory != null); - this.factory = factory; - this.propFactory = propFactory; - // base(); - } - - public override Element/*!*/ Top { - get { - Contract.Ensures(Contract.Result() != null); - return new Elt(What.Bounds, null); - } - } - - public override Element/*!*/ Bottom { - get { - Contract.Ensures(Contract.Result() != null); - return new Elt(What.Bottom, null); - } - } - - public override bool IsTop(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - return e.what == What.Bounds && e.ty == null && e.manyBounds == null; - } - - public override bool IsBottom(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - return e.what == What.Bottom; - } - - public override Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - Contract.Assert(a.what != What.Bottom && b.what != What.Bottom); - if (a.what == What.Exact && b.what == What.Exact) { - Contract.Assert(a.ty != null && b.ty != null); - if (factory.IsTypeEqual(a.ty, b.ty)) { - return a; - } else { - return new Elt(What.Bounds, factory.JoinTypes(a.ty, b.ty)); - } - } - - // The result is going to be a Bounds, since at least one of the operands is a Bounds. - Contract.Assert(1 <= a.BoundsCount && 1 <= b.BoundsCount); // a preconditions is that neither operand is Top - int n = a.BoundsCount + b.BoundsCount; - - // Special case: a and b each has exactly one bound - if (n == 2) { - Contract.Assert(a.ty != null && b.ty != null); - IExpr join = factory.JoinTypes(a.ty, b.ty); - Contract.Assert(join != null); - if (join == a.ty && a.what == What.Bounds) { - return a; - } else if (join == b.ty && b.what == What.Bounds) { - return b; - } else { - return new Elt(What.Bounds, join); - } - } - - // General case - ArrayList /*IExpr*/ allBounds = new ArrayList /*IExpr*/ (n); // final size - ArrayList /*IExpr!*/ result = new ArrayList /*IExpr!*/ (n); // a guess at the size, but could be as big as size(a)*size(b) - if (a.ty != null) { - allBounds.Add(a.ty); - } else { - allBounds.AddRange(cce.NonNull(a.manyBounds)); - } - int bStart = allBounds.Count; - if (b.ty != null) { - allBounds.Add(b.ty); - } else { - allBounds.AddRange(cce.NonNull(b.manyBounds)); - } - // compute the join of each pair, putting non-redundant joins into "result" - for (int i = 0; i < bStart; i++) { - IExpr/*!*/ aBound = cce.NonNull((IExpr/*!*/)allBounds[i]); - for (int j = bStart; j < allBounds.Count; j++) { - IExpr/*!*/ bBound = (IExpr/*!*/)cce.NonNull(allBounds[j]); - - IExpr/*!*/ join = factory.JoinTypes(aBound, bBound); - Contract.Assert(join != null); - - int k = 0; - while (k < result.Count) { - IExpr/*!*/ r = (IExpr/*!*/)cce.NonNull(result[k]); - if (factory.IsSubType(join, r)) { - // "join" is more restrictive than a bound already placed in "result", - // so toss out "join" and compute the join of the next pair - goto NEXT_PAIR; - } else if (factory.IsSubType(r, join)) { - // "join" is less restrictive than a bound already placed in "result", - // so toss out that old bound - result.RemoveAt(k); - } else { - k++; - } - } - result.Add(join); - NEXT_PAIR: { - } - } - } - return new Elt(result, result.Count); - } - - - public override Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - Contract.Assert(a.what != What.Bottom && b.what != What.Bottom); - - if (a.what == What.Exact && b.what == What.Exact) { - Contract.Assert(a.ty != null && b.ty != null); - if (factory.IsTypeEqual(a.ty, b.ty)) { - return a; - } else { - return Bottom; - } - - } else if (a.what == What.Exact || b.what == What.Exact) { - // One is Bounds, the other Exact. Make b be the Bounds one. - if (a.what == What.Bounds) { - Elt tmp = a; - a = b; - b = tmp; - } - Contract.Assert(a.what == What.Exact && b.what == What.Bounds); - // Check the exact type against all bounds. If the exact type is more restrictive - // than all bounds, then return it. If some bound is not met by the exact type, return - // bottom. - Contract.Assert(a.ty != null); - if (b.ty != null && !factory.IsSubType(a.ty, b.ty)) { - return Bottom; - } - if (b.manyBounds != null) { - foreach (IExpr/*!*/ bound in b.manyBounds) { - Contract.Assert(bound != null); - if (!factory.IsSubType(a.ty, bound)) { - return Bottom; - } - } - } - return a; - } else { - // Both operands are Bounds. - Contract.Assert(a.what == What.Bounds && b.what == What.Bounds); - - // Take all the bounds, but prune those bounds that follow from others. - Contract.Assert(1 <= a.BoundsCount && 1 <= b.BoundsCount); // a preconditions is that neither operand is Top - int n = a.BoundsCount + b.BoundsCount; - // Special case: a and b each has exactly one bound - if (n == 2) { - Contract.Assert(a.ty != null && b.ty != null); - if (factory.IsSubType(a.ty, b.ty)) { - // a is more restrictive - return a; - } else if (factory.IsSubType(b.ty, a.ty)) { - // b is more restrictive - return b; - } else { - IExpr[]/*!*/ bounds = new IExpr[2]; - bounds[0] = a.ty; - bounds[1] = b.ty; - return new Elt(bounds); - } - } - - // General case - ArrayList /*IExpr*/ allBounds = new ArrayList /*IExpr*/ (n); - if (a.ty != null) { - allBounds.Add(a.ty); - } else { - allBounds.AddRange(cce.NonNull(a.manyBounds)); - } - int bStart = allBounds.Count; - if (b.ty != null) { - allBounds.Add(b.ty); - } else { - allBounds.AddRange(cce.NonNull(b.manyBounds)); - } - for (int i = 0; i < bStart; i++) { - IExpr/*!*/ aBound = cce.NonNull((IExpr)allBounds[i]); - for (int j = bStart; j < allBounds.Count; j++) { - IExpr bBound = (IExpr/*! Wouldn't the non-null typing in the original Spec# code had made bBound never null, - * thus negating the need for the continue statement?*/ - )allBounds[j]; - if (bBound == null) { - continue; - } else if (factory.IsSubType(aBound, bBound)) { - // a is more restrictive, so blot out the b bound - allBounds[j] = null; - n--; - } else if (factory.IsSubType(bBound, aBound)) { - // b is more restrictive, so blot out the a bound - allBounds[i] = null; - n--; - goto CONTINUE_OUTER_LOOP; - } - } - CONTINUE_OUTER_LOOP: { - } - } - Contract.Assert(1 <= n); - return new Elt(allBounds, n); - } - } - - public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - return Join(first, second); - } - - protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that - { - //Contract.Requires(first != null); - //Contract.Requires(second != null); - Elt/*!*/ a = (Elt/*!*/)cce.NonNull(first); - Elt/*!*/ b = (Elt/*!*/)cce.NonNull(second); - Contract.Assert(a.what != What.Bottom && b.what != What.Bottom); - - if (a.what == What.Exact && b.what == What.Exact) { - Contract.Assert(a.ty != null && b.ty != null); - return factory.IsTypeEqual(a.ty, b.ty); - } else if (b.what == What.Exact) { - return false; - } else if (a.what == What.Exact) { - Contract.Assert(a.ty != null); - if (b.ty != null) { - return factory.IsSubType(a.ty, b.ty); - } else { - return Contract.ForAll(b.manyBounds, bound => factory.IsSubType(a.ty, bound)); - } - } else { - Contract.Assert(a.what == What.Bounds && b.what == What.Bounds); - Contract.Assert(a.ty != null || a.manyBounds != null); // a precondition is that a is not Top - Contract.Assert(b.ty != null || b.manyBounds != null); // a precondition is that b is not Top - // Return true iff: for each constraint in b, there is a stricter constraint in a. - if (a.ty != null && b.ty != null) { - return factory.IsSubType(a.ty, b.ty); - } else if (a.ty != null) { - return Contract.ForAll(b.manyBounds, bound => factory.IsSubType(a.ty, bound)); - } else if (b.ty != null) { - return Contract.Exists(a.manyBounds, bound => factory.IsSubType(bound, b.ty)); - } else { - return Contract.ForAll(b.manyBounds, bBound => Contract.Exists(a.manyBounds, aBound => factory.IsSubType(aBound, bBound))); - } - } - } - - public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { - //Contract.Requires(element != null); - //Contract.Requires(var != null); - Contract.Ensures(Contract.Result() != null); - Elt e = (Elt)element; - switch (e.what) { - case What.Bottom: - return propFactory.False; - case What.Exact: - return factory.IsExactlyA(var, cce.NonNull(e.ty)); - case What.Bounds: - if (e.ty == null && e.manyBounds == null) { - return propFactory.True; - } else if (e.ty != null) { - return factory.IsA(var, e.ty); - } else { - IExpr/*!*/ p = factory.IsA(var, (IExpr/*!*/)cce.NonNull(e.manyBounds)[0]); - for (int i = 1; i < e.manyBounds.Length; i++) { - p = propFactory.And(p, factory.IsA(var, (IExpr/*!*/)cce.NonNull(e.manyBounds[i]))); - } - return p; - } - default: { - Contract.Assert(false); - throw new cce.UnreachableException(); - } - throw new System.Exception(); - } - } - - public override IExpr GetFoldExpr(Element/*!*/ e) { - //Contract.Requires(e != null); - // cannot fold into an expression that can be substituted for the variable - return null; - } - - public override bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args) { - //Contract.Requires(args != null); - //Contract.Requires(f != null); - bool isEq = f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq); - if (isEq || f.Equals(Microsoft.AbstractInterpretationFramework.Value.Subtype)) { - Contract.Assert(args.Count == 2); - IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); - IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); - - // Look for $typeof(var) == t or t == $typeof(var) or $typeof(var) <: t - if (isEq && factory.IsTypeConstant(arg0)) { - // swap the arguments - IExpr/*!*/ tmp = arg0; - arg0 = arg1; - arg1 = tmp; - } else if (!factory.IsTypeConstant(arg1)) { - return false; - } - IFunApp typeofExpr = arg0 as IFunApp; - if (typeofExpr != null && - typeofExpr.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Typeof)) { - Contract.Assert(typeofExpr.Arguments.Count == 1); - if (typeofExpr.Arguments[0] is IVariable) { - // we have a match - return true; - } - } - } - return false; - } - - public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ e) { - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - IFunApp nary = e as IFunApp; - if (nary != null) { - - bool isEq = nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq); - if (isEq || nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Subtype)) { - IList/**//*!*/ args = nary.Arguments; - Contract.Assert(args != null); - Contract.Assert(args.Count == 2); - IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); - IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); - - // Look for $typeof(var) == t or t == $typeof(var) or $typeof(var) <: t - if (isEq && factory.IsTypeConstant(arg0)) { - // swap the arguments - IExpr/*!*/ tmp = arg0; - arg0 = arg1; - arg1 = tmp; - } else if (!factory.IsTypeConstant(arg1)) { - return Top; - } - IFunApp typeofExpr = arg0 as IFunApp; - if (typeofExpr != null && - typeofExpr.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Typeof)) { - Contract.Assert(typeofExpr.Arguments.Count == 1); - if (typeofExpr.Arguments[0] is IVariable) { - // we have a match - return new Elt(isEq ? What.Exact : What.Bounds, arg1); - } - } - } - } - return Top; - } - - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System.Collections; + using System.Diagnostics; + //using System.Compiler.Analysis; + //using Microsoft.SpecSharp.Collections; + using System.Diagnostics.Contracts; + + /// + /// Represents information about the dynamic type of a variable. In particular, for a + /// variable "v", represents either Bottom, "typeof(v)==T" for some type T, or a set + /// of constraints "typeof(v) subtype of T_i for some number of T_i's. + /// + public class DynamicTypeLattice : MicroLattice { + enum What { + Bottom, + Exact, + Bounds + } + + private class Elt : Element { + // Representation: + // - Bottom is represented by: what==What.Bottom + // - An exact type T is represented by: what==What.Exact && ty==T + // - A set of type constraints T0, T1, T2, ..., T{n-1} is represented by: + // -- if n==0: what==What.Bounds && ty==null && manyBounds==null + // -- if n==1: what==What.Bounds && ty==T0 && manyBounds==null + // -- if n>=2: what==What.Bounds && ty==null && + // manyBounds!=null && manyBounds.Length==n && + // manyBounds[0]==T0 && manyBounds[1]==T1 && ... && manyBounds[n-1]==T{n-1} + // The reason for keeping the one-and-only bound in "ty" in case n==1 is to try + // to prevent the need for allocating a whole array of bounds, since 1 bound is + // bound to be common. + // In the representation, there are no redundant bounds in manyBounds. + // It is assumed that the types can can occur as exact bounds form a single-inheritance + // hierarchy. That is, if T0 and T1 are types that can occur as exact types, then + // there is no v such that typeof(v) is a subtype of both T0 and T1, unless T0 and T1 are + // the same type. + public readonly What what; + public readonly IExpr ty; + [Rep] + public readonly IExpr[] manyBounds; + [ContractInvariantMethod] + void ObjectInvariant() { + + Contract.Invariant(what != What.Bottom || ty == null && manyBounds == null); + Contract.Invariant(manyBounds == null || what == What.Bounds); + Contract.Invariant(manyBounds == null || Contract.ForAll(0, manyBounds.Length, i => manyBounds[i] != null)); + } + public Elt(What what, IExpr ty) { + Contract.Requires(what != What.Bottom || ty == null); + Contract.Requires(what != What.Exact || ty != null); + this.what = what; + this.ty = ty; + this.manyBounds = null; + } + + public Elt(IExpr[]/*!*/ bounds) { + Contract.Requires(bounds != null); + Contract.Requires(Contract.ForAll(0, bounds.Length, i => bounds[i] != null)); + this.what = What.Bounds; + if (bounds.Length == 0) { + this.ty = null; + this.manyBounds = null; + } else if (bounds.Length == 1) { + this.ty = bounds[0]; + this.manyBounds = null; + } else { + this.ty = null; + this.manyBounds = bounds; + } + } + + /// + /// Constructs an Elt with "n" bounds, namely the n non-null values of the "bounds" list. + /// + [NotDelayed] + public Elt(ArrayList /*IExpr*//*!*/ bounds, int n) { + Contract.Requires(bounds != null); + Contract.Requires(0 <= n && n <= bounds.Count); + this.what = What.Bounds; + if (n > 1) { + this.manyBounds = new IExpr[n]; + } + int k = 0; + foreach (IExpr bound in bounds) { + if (bound != null) { + Contract.Assert(k != n); + if (n == 1) { + Contract.Assert(this.ty == null); + this.ty = bound; + } else { + Contract.Assume(manyBounds != null); + manyBounds[k] = bound; + } + k++; + } + } + Contract.Assert(k == n); + } + + public int BoundsCount { + get { + Contract.Ensures(0 <= Contract.Result()); + if (manyBounds != null) { + return manyBounds.Length; + } else if (ty != null) { + return 1; + } else { + return 0; + } + } + } + + [Pure] + public override System.Collections.Generic.ICollection/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return cce.NonNull(new System.Collections.Generic.List()).AsReadOnly(); + } + + public override Element/*!*/ Clone() { + Contract.Ensures(Contract.Result() != null); + if (this.manyBounds != null) + return new Elt(this.manyBounds); + else + return new Elt(this.what, this.ty); + } + } + + readonly ITypeExprFactory/*!*/ factory; + readonly IPropExprFactory/*!*/ propFactory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(factory != null); + Contract.Invariant(propFactory != null); + } + + + public DynamicTypeLattice(ITypeExprFactory/*!*/ factory, IPropExprFactory/*!*/ propFactory) { + Contract.Requires(propFactory != null); + Contract.Requires(factory != null); + this.factory = factory; + this.propFactory = propFactory; + // base(); + } + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result() != null); + return new Elt(What.Bounds, null); + } + } + + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result() != null); + return new Elt(What.Bottom, null); + } + } + + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return e.what == What.Bounds && e.ty == null && e.manyBounds == null; + } + + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return e.what == What.Bottom; + } + + public override Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + Contract.Assert(a.what != What.Bottom && b.what != What.Bottom); + if (a.what == What.Exact && b.what == What.Exact) { + Contract.Assert(a.ty != null && b.ty != null); + if (factory.IsTypeEqual(a.ty, b.ty)) { + return a; + } else { + return new Elt(What.Bounds, factory.JoinTypes(a.ty, b.ty)); + } + } + + // The result is going to be a Bounds, since at least one of the operands is a Bounds. + Contract.Assert(1 <= a.BoundsCount && 1 <= b.BoundsCount); // a preconditions is that neither operand is Top + int n = a.BoundsCount + b.BoundsCount; + + // Special case: a and b each has exactly one bound + if (n == 2) { + Contract.Assert(a.ty != null && b.ty != null); + IExpr join = factory.JoinTypes(a.ty, b.ty); + Contract.Assert(join != null); + if (join == a.ty && a.what == What.Bounds) { + return a; + } else if (join == b.ty && b.what == What.Bounds) { + return b; + } else { + return new Elt(What.Bounds, join); + } + } + + // General case + ArrayList /*IExpr*/ allBounds = new ArrayList /*IExpr*/ (n); // final size + ArrayList /*IExpr!*/ result = new ArrayList /*IExpr!*/ (n); // a guess at the size, but could be as big as size(a)*size(b) + if (a.ty != null) { + allBounds.Add(a.ty); + } else { + allBounds.AddRange(cce.NonNull(a.manyBounds)); + } + int bStart = allBounds.Count; + if (b.ty != null) { + allBounds.Add(b.ty); + } else { + allBounds.AddRange(cce.NonNull(b.manyBounds)); + } + // compute the join of each pair, putting non-redundant joins into "result" + for (int i = 0; i < bStart; i++) { + IExpr/*!*/ aBound = cce.NonNull((IExpr/*!*/)allBounds[i]); + for (int j = bStart; j < allBounds.Count; j++) { + IExpr/*!*/ bBound = (IExpr/*!*/)cce.NonNull(allBounds[j]); + + IExpr/*!*/ join = factory.JoinTypes(aBound, bBound); + Contract.Assert(join != null); + + int k = 0; + while (k < result.Count) { + IExpr/*!*/ r = (IExpr/*!*/)cce.NonNull(result[k]); + if (factory.IsSubType(join, r)) { + // "join" is more restrictive than a bound already placed in "result", + // so toss out "join" and compute the join of the next pair + goto NEXT_PAIR; + } else if (factory.IsSubType(r, join)) { + // "join" is less restrictive than a bound already placed in "result", + // so toss out that old bound + result.RemoveAt(k); + } else { + k++; + } + } + result.Add(join); + NEXT_PAIR: { + } + } + } + return new Elt(result, result.Count); + } + + + public override Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + Contract.Assert(a.what != What.Bottom && b.what != What.Bottom); + + if (a.what == What.Exact && b.what == What.Exact) { + Contract.Assert(a.ty != null && b.ty != null); + if (factory.IsTypeEqual(a.ty, b.ty)) { + return a; + } else { + return Bottom; + } + + } else if (a.what == What.Exact || b.what == What.Exact) { + // One is Bounds, the other Exact. Make b be the Bounds one. + if (a.what == What.Bounds) { + Elt tmp = a; + a = b; + b = tmp; + } + Contract.Assert(a.what == What.Exact && b.what == What.Bounds); + // Check the exact type against all bounds. If the exact type is more restrictive + // than all bounds, then return it. If some bound is not met by the exact type, return + // bottom. + Contract.Assert(a.ty != null); + if (b.ty != null && !factory.IsSubType(a.ty, b.ty)) { + return Bottom; + } + if (b.manyBounds != null) { + foreach (IExpr/*!*/ bound in b.manyBounds) { + Contract.Assert(bound != null); + if (!factory.IsSubType(a.ty, bound)) { + return Bottom; + } + } + } + return a; + } else { + // Both operands are Bounds. + Contract.Assert(a.what == What.Bounds && b.what == What.Bounds); + + // Take all the bounds, but prune those bounds that follow from others. + Contract.Assert(1 <= a.BoundsCount && 1 <= b.BoundsCount); // a preconditions is that neither operand is Top + int n = a.BoundsCount + b.BoundsCount; + // Special case: a and b each has exactly one bound + if (n == 2) { + Contract.Assert(a.ty != null && b.ty != null); + if (factory.IsSubType(a.ty, b.ty)) { + // a is more restrictive + return a; + } else if (factory.IsSubType(b.ty, a.ty)) { + // b is more restrictive + return b; + } else { + IExpr[]/*!*/ bounds = new IExpr[2]; + bounds[0] = a.ty; + bounds[1] = b.ty; + return new Elt(bounds); + } + } + + // General case + ArrayList /*IExpr*/ allBounds = new ArrayList /*IExpr*/ (n); + if (a.ty != null) { + allBounds.Add(a.ty); + } else { + allBounds.AddRange(cce.NonNull(a.manyBounds)); + } + int bStart = allBounds.Count; + if (b.ty != null) { + allBounds.Add(b.ty); + } else { + allBounds.AddRange(cce.NonNull(b.manyBounds)); + } + for (int i = 0; i < bStart; i++) { + IExpr/*!*/ aBound = cce.NonNull((IExpr)allBounds[i]); + for (int j = bStart; j < allBounds.Count; j++) { + IExpr bBound = (IExpr/*! Wouldn't the non-null typing in the original Spec# code had made bBound never null, + * thus negating the need for the continue statement?*/ + )allBounds[j]; + if (bBound == null) { + continue; + } else if (factory.IsSubType(aBound, bBound)) { + // a is more restrictive, so blot out the b bound + allBounds[j] = null; + n--; + } else if (factory.IsSubType(bBound, aBound)) { + // b is more restrictive, so blot out the a bound + allBounds[i] = null; + n--; + goto CONTINUE_OUTER_LOOP; + } + } + CONTINUE_OUTER_LOOP: { + } + } + Contract.Assert(1 <= n); + return new Elt(allBounds, n); + } + } + + public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + return Join(first, second); + } + + protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that + { + //Contract.Requires(first != null); + //Contract.Requires(second != null); + Elt/*!*/ a = (Elt/*!*/)cce.NonNull(first); + Elt/*!*/ b = (Elt/*!*/)cce.NonNull(second); + Contract.Assert(a.what != What.Bottom && b.what != What.Bottom); + + if (a.what == What.Exact && b.what == What.Exact) { + Contract.Assert(a.ty != null && b.ty != null); + return factory.IsTypeEqual(a.ty, b.ty); + } else if (b.what == What.Exact) { + return false; + } else if (a.what == What.Exact) { + Contract.Assert(a.ty != null); + if (b.ty != null) { + return factory.IsSubType(a.ty, b.ty); + } else { + return Contract.ForAll(b.manyBounds, bound => factory.IsSubType(a.ty, bound)); + } + } else { + Contract.Assert(a.what == What.Bounds && b.what == What.Bounds); + Contract.Assert(a.ty != null || a.manyBounds != null); // a precondition is that a is not Top + Contract.Assert(b.ty != null || b.manyBounds != null); // a precondition is that b is not Top + // Return true iff: for each constraint in b, there is a stricter constraint in a. + if (a.ty != null && b.ty != null) { + return factory.IsSubType(a.ty, b.ty); + } else if (a.ty != null) { + return Contract.ForAll(b.manyBounds, bound => factory.IsSubType(a.ty, bound)); + } else if (b.ty != null) { + return Contract.Exists(a.manyBounds, bound => factory.IsSubType(bound, b.ty)); + } else { + return Contract.ForAll(b.manyBounds, bBound => Contract.Exists(a.manyBounds, aBound => factory.IsSubType(aBound, bBound))); + } + } + } + + public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { + //Contract.Requires(element != null); + //Contract.Requires(var != null); + Contract.Ensures(Contract.Result() != null); + Elt e = (Elt)element; + switch (e.what) { + case What.Bottom: + return propFactory.False; + case What.Exact: + return factory.IsExactlyA(var, cce.NonNull(e.ty)); + case What.Bounds: + if (e.ty == null && e.manyBounds == null) { + return propFactory.True; + } else if (e.ty != null) { + return factory.IsA(var, e.ty); + } else { + IExpr/*!*/ p = factory.IsA(var, (IExpr/*!*/)cce.NonNull(e.manyBounds)[0]); + for (int i = 1; i < e.manyBounds.Length; i++) { + p = propFactory.And(p, factory.IsA(var, (IExpr/*!*/)cce.NonNull(e.manyBounds[i]))); + } + return p; + } + default: { + Contract.Assert(false); + throw new cce.UnreachableException(); + } + throw new System.Exception(); + } + } + + public override IExpr GetFoldExpr(Element/*!*/ e) { + //Contract.Requires(e != null); + // cannot fold into an expression that can be substituted for the variable + return null; + } + + public override bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + bool isEq = f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq); + if (isEq || f.Equals(Microsoft.AbstractInterpretationFramework.Value.Subtype)) { + Contract.Assert(args.Count == 2); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); + + // Look for $typeof(var) == t or t == $typeof(var) or $typeof(var) <: t + if (isEq && factory.IsTypeConstant(arg0)) { + // swap the arguments + IExpr/*!*/ tmp = arg0; + arg0 = arg1; + arg1 = tmp; + } else if (!factory.IsTypeConstant(arg1)) { + return false; + } + IFunApp typeofExpr = arg0 as IFunApp; + if (typeofExpr != null && + typeofExpr.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Typeof)) { + Contract.Assert(typeofExpr.Arguments.Count == 1); + if (typeofExpr.Arguments[0] is IVariable) { + // we have a match + return true; + } + } + } + return false; + } + + public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ e) { + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + IFunApp nary = e as IFunApp; + if (nary != null) { + + bool isEq = nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq); + if (isEq || nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Subtype)) { + IList/**//*!*/ args = nary.Arguments; + Contract.Assert(args != null); + Contract.Assert(args.Count == 2); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); + + // Look for $typeof(var) == t or t == $typeof(var) or $typeof(var) <: t + if (isEq && factory.IsTypeConstant(arg0)) { + // swap the arguments + IExpr/*!*/ tmp = arg0; + arg0 = arg1; + arg1 = tmp; + } else if (!factory.IsTypeConstant(arg1)) { + return Top; + } + IFunApp typeofExpr = arg0 as IFunApp; + if (typeofExpr != null && + typeofExpr.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Typeof)) { + Contract.Assert(typeofExpr.Arguments.Count == 1); + if (typeofExpr.Arguments[0] is IVariable) { + // we have a match + return new Elt(isEq ? What.Exact : What.Bounds, arg1); + } + } + } + } + return Top; + } + + } +} diff --git a/Source/AIFramework/VariableMap/Intervals.cs b/Source/AIFramework/VariableMap/Intervals.cs index 0bf82cf4..98bf9007 100644 --- a/Source/AIFramework/VariableMap/Intervals.cs +++ b/Source/AIFramework/VariableMap/Intervals.cs @@ -1,871 +1,871 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Collections; -//using System.Compiler.Analysis; -using Microsoft.AbstractInterpretationFramework.Collections; -using System.Diagnostics.Contracts; -using Microsoft.Basetypes; - -///////////////////////////////////////////////////////////////////////////////// -// An implementation of the interval abstract domain -///////////////////////////////////////////////////////////////////////////////// - -namespace Microsoft.AbstractInterpretationFramework { - public class IntervalLattice : MicroLattice { - readonly ILinearExprFactory/*!*/ factory; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(factory != null); - } - - - public IntervalLattice(ILinearExprFactory/*!*/ factory) { - Contract.Requires(factory != null); - this.factory = factory; - // base(); - } - - public override bool UnderstandsBasicArithmetics { - get { - return true; - } - } - - public override Element/*!*/ Top { - get { - Contract.Ensures(Contract.Result() != null); - - return IntervalElement.Top; - } - } - - public override Element/*!*/ Bottom { - get { - Contract.Ensures(Contract.Result() != null); - - return IntervalElement.Bottom; - } - } - - /// - /// The paramter is the top? - /// - public override bool IsTop(Element/*!*/ element) { - //Contract.Requires(element != null); - IntervalElement interval = (IntervalElement)element; - - return interval.IsTop(); - } - - /// - /// The parameter is the bottom? - /// - public override bool IsBottom(Element/*!*/ element) { - //Contract.Requires(element != null); - IntervalElement interval = (IntervalElement)element; - - return interval.IsBottom(); - } - - /// - /// The classic, pointwise, join of intervals - /// - public override Element/*!*/ NontrivialJoin(Element/*!*/ left, Element/*!*/ right) { - //Contract.Requires(right != null); - //Contract.Requires(left != null); - Contract.Ensures(Contract.Result() != null); - IntervalElement/*!*/ leftInterval = (IntervalElement/*!*/)cce.NonNull(left); - IntervalElement/*!*/ rightInterval = (IntervalElement/*!*/)cce.NonNull(right); - - ExtendedInt inf = ExtendedInt.Inf(leftInterval.Inf, rightInterval.Inf); - ExtendedInt sup = ExtendedInt.Sup(leftInterval.Sup, rightInterval.Sup); - - IntervalElement/*!*/ join = IntervalElement.Factory(inf, sup); - - return join; - } - - /// - /// The classic, pointwise, meet of intervals - /// - public override Element/*!*/ NontrivialMeet(Element/*!*/ left, Element/*!*/ right) { - //Contract.Requires(right != null); - //Contract.Requires(left != null); - Contract.Ensures(Contract.Result() != null); - IntervalElement/*!*/ leftInterval = (IntervalElement/*!*/)cce.NonNull(left); - IntervalElement/*!*/ rightInterval = (IntervalElement/*!*/)cce.NonNull(right); - - ExtendedInt inf = ExtendedInt.Sup(leftInterval.Inf, rightInterval.Inf); - ExtendedInt sup = ExtendedInt.Inf(leftInterval.Sup, rightInterval.Sup); - - return IntervalElement.Factory(inf, sup); - } - - - /// - /// The very simple widening of intervals, to be improved with thresholds - /// left is the PREVIOUS value in the iterations and right is the NEW one - /// - public override Element/*!*/ Widen(Element/*!*/ left, Element/*!*/ right) { - //Contract.Requires(right != null); - //Contract.Requires(left != null); - Contract.Ensures(Contract.Result() != null); - IntervalElement/*!*/ prevInterval = (IntervalElement/*!*/)cce.NonNull(left); - IntervalElement/*!*/ nextInterval = (IntervalElement/*!*/)cce.NonNull(right); - - ExtendedInt inf = nextInterval.Inf < prevInterval.Inf ? ExtendedInt.MinusInfinity : prevInterval.Inf; - ExtendedInt sup = nextInterval.Sup > prevInterval.Sup ? ExtendedInt.PlusInfinity : prevInterval.Sup; - - IntervalElement widening = IntervalElement.Factory(inf, sup); - - return widening; - } - - - /// - /// Return true iff the interval left is containted in right - /// - protected override bool AtMost(Element/*!*/ left, Element/*!*/ right) { - //Contract.Requires(right != null); - //Contract.Requires(left != null); - IntervalElement/*!*/ leftInterval = (IntervalElement/*!*/)cce.NonNull(left); - IntervalElement/*!*/ rightInterval = (IntervalElement/*!*/)cce.NonNull(right); - - if (leftInterval.IsBottom() || rightInterval.IsTop()) - return true; - - return rightInterval.Inf <= leftInterval.Inf && leftInterval.Sup <= rightInterval.Sup; - } - - /// - /// Return just null - /// - public override IExpr GetFoldExpr(Element/*!*/ element) { - //Contract.Requires(element != null); - return null; - } - - /// - /// return a predicate inf "\leq x and x "\leq" sup (if inf [or sup] is not oo) - /// - public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { - //Contract.Requires(element != null); - //Contract.Requires(var != null); - Contract.Ensures(Contract.Result() != null); - IntervalElement/*!*/ interval = (IntervalElement/*!*/)cce.NonNull(element); - IExpr lowerBound = null; - IExpr upperBound = null; - - if (!(interval.Inf is InfinitaryInt)) { - IExpr constant = this.factory.Const(interval.Inf.Value); - lowerBound = this.factory.AtMost(constant, var); // inf <= var - } - if (!(interval.Sup is InfinitaryInt)) { - IExpr constant = this.factory.Const(interval.Sup.Value); - upperBound = this.factory.AtMost(var, constant); // var <= inf - } - - if (lowerBound != null && upperBound != null) - return this.factory.And(lowerBound, upperBound); // inf <= var && var <= sup - else - if (lowerBound != null) - return lowerBound; - else - if (upperBound != null) - return upperBound; - else // If we reach this point, both lowerBound and upperBound are null, i.e. we have no bounds on var, so we return simply true... - return this.factory.True; - } - - /// - /// For the moment consider just equalities. Other case must be considered - /// - public override bool Understands(IFunctionSymbol/*!*/ f, IList /* - /// Evaluate the predicate passed as input according the semantics of intervals - /// - public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ pred) { - //Contract.Requires(pred != null); - Contract.Ensures(Contract.Result() != null); - return this.EvaluatePredicateWithState(pred, null); - } - - /// - /// Evaluate the predicate passed as input according the semantics of intervals and the given state. - /// Right now just basic arithmetic operations are supported. A future extension may consider an implementation of boolean predicates - /// - public override Element/*!*/ EvaluatePredicateWithState(IExpr/*!*/ pred, IFunctionalMap/* Var -> Element */ state) { - //Contract.Requires(pred != null); - Contract.Ensures(Contract.Result() != null); - if (pred is IFunApp) { - IFunApp fun = (IFunApp)pred; - if (fun.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq)) // if it is a symbol of equality - { - IExpr/*!*/ leftArg = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); - IExpr/*!*/ rightArg = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]); - if (leftArg is IVariable) { - return Eval(rightArg, state); - } else if (rightArg is IVariable) { - return Eval(leftArg, state); - } - } - } - // otherwise we simply return Top - return IntervalElement.Top; - } - - /// - /// Evaluate the expression (that is assured to be an arithmetic expression, in the state passed as a parameter - /// - private IntervalElement/*!*/ Eval(IExpr/*!*/ exp, IFunctionalMap/* Var -> Element */ state) { - Contract.Requires((exp != null)); - Contract.Ensures(Contract.Result() != null); - - IntervalElement/*!*/ retVal = (IntervalElement/*!*/)cce.NonNull(Top); - - // Eval the expression by structural induction - - - if (exp is IVariable && state != null) // A variable - { - object lookup = state[exp]; - if (lookup is IntervalElement) - retVal = (IntervalElement)lookup; - else { - retVal = (IntervalElement)Top; - } - } else if (exp is IFunApp) { - IFunApp fun = (IFunApp)exp; - - if (fun.FunctionSymbol is IntSymbol) // An integer - { - IntSymbol intSymb = (IntSymbol)fun.FunctionSymbol; - BigNum val = intSymb.Value; - - retVal = IntervalElement.Factory(val); - } else if (fun.FunctionSymbol.Equals(Int.Negate)) // An unary minus - { - IExpr/*!*/ arg = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); - IntervalElement/*!*/ argEval = Eval(arg, state); - Contract.Assert(argEval != null); - IntervalElement/*!*/ zero = IntervalElement.Factory(BigNum.ZERO); - Contract.Assert(zero != null); - - retVal = zero - argEval; - } else if (fun.Arguments.Count == 2) { - IExpr/*!*/ left = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); - IExpr/*!*/ right = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]); - - IntervalElement/*!*/ leftVal = Eval(left, state); - Contract.Assert(leftVal != null); - IntervalElement/*!*/ rightVal = Eval(right, state); - Contract.Assert(rightVal != null); - - if (fun.FunctionSymbol.Equals(Int.Add)) - retVal = leftVal + rightVal; - else if (fun.FunctionSymbol.Equals(Int.Sub)) - retVal = leftVal - rightVal; - else if (fun.FunctionSymbol.Equals(Int.Mul)) - retVal = leftVal * rightVal; - else if (fun.FunctionSymbol.Equals(Int.Div)) - retVal = leftVal / rightVal; - else if (fun.FunctionSymbol.Equals(Int.Mod)) - retVal = leftVal % rightVal; - } - } - - return retVal; - } - - /// - /// Inner class standing for an interval on integers, possibly unbounded - /// - private class IntervalElement : Element { - protected static readonly IntervalElement/*!*/ TopInterval = new IntervalElement(new MinusInfinity(), new PlusInfinity()); // Top = [-oo , +oo] - protected static readonly IntervalElement/*!*/ BottomInterval = new IntervalElement(new PlusInfinity(), new MinusInfinity()); // Bottom = [+oo, -oo] - - private readonly ExtendedInt/*!*/ inf; - private readonly ExtendedInt/*!*/ sup; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(inf != null); - Contract.Invariant(sup != null); - } - - public ExtendedInt/*!*/ Inf { - get { - Contract.Ensures(Contract.Result() != null); - - return inf; - } - } - - public ExtendedInt/*!*/ Sup { - get { - Contract.Ensures(Contract.Result() != null); - - return sup; - } - } - - // Construct the inteval [val, val] - protected IntervalElement(BigNum val) { - this.inf = this.sup = ExtendedInt.Factory(val); - // base(); - } - - // Construct the interval [inf, sup] - protected IntervalElement(BigNum infInt, BigNum supInt) { - this.inf = ExtendedInt.Factory(infInt); - this.sup = ExtendedInt.Factory(supInt); - // base(); // to please the compiler... - } - - protected IntervalElement(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { - Contract.Requires(sup != null); - Contract.Requires(inf != null); - this.inf = inf; - this.sup = sup; - // base(); - } - - // Construct an Interval - public static IntervalElement/*!*/ Factory(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { - Contract.Requires((sup != null)); - Contract.Requires((inf != null)); - Contract.Ensures(Contract.Result() != null); - if (inf is MinusInfinity && sup is PlusInfinity) - return Top; - if (inf > sup) - return Bottom; - // otherwise... - return new IntervalElement(inf, sup); - } - - public static IntervalElement/*!*/ Factory(BigNum i) { - Contract.Ensures(Contract.Result() != null); - return new IntervalElement(i); - } - - public static IntervalElement/*!*/ Factory(BigNum inf, BigNum sup) { - Contract.Ensures(Contract.Result() != null); - ExtendedInt/*!*/ i = ExtendedInt.Factory(inf); - ExtendedInt/*!*/ s = ExtendedInt.Factory(sup); - - return Factory(i, s); - } - - static public IntervalElement/*!*/ Top { - get { - Contract.Ensures(Contract.Result() != null); - - return TopInterval; - } - } - - static public IntervalElement/*!*/ Bottom { - get { - Contract.Ensures(Contract.Result() != null); - - return BottomInterval; - } - } - - public bool IsTop() { - return this.inf is MinusInfinity && this.sup is PlusInfinity; - } - - public bool IsBottom() { - return this.inf > this.sup; - } - - #region Below are the arithmetic operations lifted to intervals - - // Addition - public static IntervalElement/*!*/ operator +(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - ExtendedInt/*!*/ inf = a.inf + b.inf; - Contract.Assert(inf != null); - ExtendedInt/*!*/ sup = a.sup + b.sup; - Contract.Assert(sup != null); - - return Factory(inf, sup); - } - - // Subtraction - public static IntervalElement/*!*/ operator -(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - ExtendedInt/*!*/ inf = a.inf - b.sup; - Contract.Assert(inf != null); - - ExtendedInt/*!*/ sup = a.sup - b.inf; - Contract.Assert(sup != null); - IntervalElement/*!*/ sub = Factory(inf, sup); - Contract.Assert(sub != null); - - return sub; - } - - // Multiplication - public static IntervalElement/*!*/ operator *(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - ExtendedInt/*!*/ infinf = a.inf * b.inf; - Contract.Assert(infinf != null); - ExtendedInt/*!*/ infsup = a.inf * b.sup; - Contract.Assert(infsup != null); - ExtendedInt/*!*/ supinf = a.sup * b.inf; - Contract.Assert(supinf != null); - ExtendedInt/*!*/ supsup = a.sup * b.sup; - Contract.Assert(supsup != null); - - ExtendedInt/*!*/ inf = ExtendedInt.Inf(infinf, infsup, supinf, supsup); - Contract.Assert(inf != null); - ExtendedInt/*!*/ sup = ExtendedInt.Sup(infinf, infsup, supinf, supsup); - Contract.Assert(sup != null); - - return Factory(inf, sup); - } - - // Division - public static IntervalElement/*!*/ operator /(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - if (b.inf.IsZero && b.sup.IsZero) // Check division by zero - return IntervalElement.Top; - - ExtendedInt/*!*/ infinf = a.inf / b.inf; - Contract.Assert(infinf != null); - ExtendedInt/*!*/ infsup = a.inf / b.sup; - Contract.Assert(infsup != null); - ExtendedInt/*!*/ supinf = a.sup / b.inf; - Contract.Assert(supinf != null); - ExtendedInt/*!*/ supsup = a.sup / b.sup; - Contract.Assert(supsup != null); - - ExtendedInt/*!*/ inf = ExtendedInt.Inf(infinf, infsup, supinf, supsup); - Contract.Assert(inf != null); - ExtendedInt/*!*/ sup = ExtendedInt.Sup(infinf, infsup, supinf, supsup); - Contract.Assert(sup != null); - - return Factory(inf, sup); - } - - // Division - public static IntervalElement/*!*/ operator %(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - if (b.inf.IsZero && b.sup.IsZero) // Check division by zero - return IntervalElement.Top; - - ExtendedInt/*!*/ infinf = a.inf % b.inf; - Contract.Assert(infinf != null); - ExtendedInt/*!*/ infsup = a.inf % b.sup; - Contract.Assert(infsup != null); - ExtendedInt/*!*/ supinf = a.sup % b.inf; - Contract.Assert(supinf != null); - ExtendedInt/*!*/ supsup = a.sup % b.sup; - Contract.Assert(supsup != null); - - ExtendedInt inf = ExtendedInt.Inf(infinf, infsup, supinf, supsup); - ExtendedInt sup = ExtendedInt.Sup(infinf, infsup, supinf, supsup); - - return Factory(inf, sup); - } - - #endregion - - #region Overriden methods - - public override Element/*!*/ Clone() { - Contract.Ensures(Contract.Result() != null); - // Real copying should not be needed because intervals are immutable? - return this; - /* - int valInf = this.inf.Value; - int valSup = this.sup.Value; - - ExtendedInt clonedInf = ExtendedInt.Factory(valInf); - ExtendedInt clonedSup = ExtendedInt.Factory(valSup); - - return Factory(clonedInf, clonedSup); - */ - } - - [Pure] - public override System.Collections.Generic.ICollection/*!*/ FreeVariables() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return cce.NonNull(new System.Collections.Generic.List()).AsReadOnly(); - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return "[" + this.inf + ", " + this.sup + "]"; - } - - #endregion - } - } - - - /// The interface for an extended integer - /// - [ContractClass(typeof(ExtendedIntContracts))] - abstract class ExtendedInt { - private static readonly PlusInfinity/*!*/ cachedPlusInf = new PlusInfinity(); - private static readonly MinusInfinity/*!*/ cachedMinusInf = new MinusInfinity(); - - static public ExtendedInt/*!*/ PlusInfinity { - get { - Contract.Ensures(Contract.Result() != null); - - return cachedPlusInf; - } - } - - static public ExtendedInt/*!*/ MinusInfinity { - get { - Contract.Ensures(Contract.Result() != null); - - return cachedMinusInf; - } - } - - public abstract BigNum Value { - get; - } - - public abstract int Signum { - get; - } - - public bool IsZero { - get { - return Signum == 0; - } - } - - public bool IsPositive { - get { - return Signum > 0; - } - } - - public bool IsNegative { - get { - return Signum < 0; - } - } - - - #region Below are the extensions of arithmetic operations on extended integers - - // Addition - public static ExtendedInt/*!*/ operator +(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - if (a is InfinitaryInt) { - return a; - } else if (b is InfinitaryInt) { - return b; - } else { - return ExtendedInt.Factory(a.Value + b.Value); - } - } - - // Subtraction - public static ExtendedInt/*!*/ operator -(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - if (a is InfinitaryInt) { - return a; - } else if (b is InfinitaryInt) { - return UnaryMinus(b); - } else { - return ExtendedInt.Factory(a.Value - b.Value); - } - } - - // Unary minus - public static ExtendedInt/*!*/ operator -(ExtendedInt/*!*/ a) { - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - // BUGBUG: Some compiler error prevents the unary minus operator from being used - return UnaryMinus(a); - } - - // Unary minus - public static ExtendedInt/*!*/ UnaryMinus(ExtendedInt/*!*/ a) { - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - if (a is PlusInfinity) - return cachedMinusInf; - if (a is MinusInfinity) - return cachedPlusInf; - else // a is a PureInteger - return new PureInteger(-a.Value); - } - - // Multiplication - public static ExtendedInt/*!*/ operator *(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - if (a.IsZero) { - return a; - } else if (b.IsZero) { - return b; - } else if (a is InfinitaryInt) { - if (b.IsPositive) { - return a; - } else { - return UnaryMinus(a); - } - } else if (b is InfinitaryInt) { - if (a.IsPositive) { - return b; - } else { - return UnaryMinus(b); - } - } else { - return ExtendedInt.Factory(a.Value * b.Value); - } - } - - // Division - public static ExtendedInt/*!*/ operator /(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - if (b.IsZero) { - return a.IsPositive ? (ExtendedInt)cachedPlusInf : cachedMinusInf; - } - if (a is InfinitaryInt) { - return a; - } else if (b is InfinitaryInt) { - return b; - } else { - return ExtendedInt.Factory(a.Value / b.Value); - } - } - - // Modulo - public static ExtendedInt/*!*/ operator %(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - if (b.IsZero) { - return a.IsPositive ? (ExtendedInt)cachedPlusInf : cachedMinusInf; - } - if (a is InfinitaryInt) { - return a; - } else if (b is InfinitaryInt) { - return b; - } else { - return ExtendedInt.Factory(a.Value % b.Value); - } - } - - #endregion - - #region Inf and Sup operations - - public abstract int CompareTo(ExtendedInt/*!*/ that); - - public static bool operator <(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { - Contract.Requires(sup != null); - Contract.Requires(inf != null); - return inf.CompareTo(sup) < 0; - } - - public static bool operator >(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { - Contract.Requires(sup != null); - Contract.Requires(inf != null); - return inf.CompareTo(sup) > 0; - } - - public static bool operator <=(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { - Contract.Requires(sup != null); - Contract.Requires(inf != null); - return inf.CompareTo(sup) <= 0; - } - - public static bool operator >=(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { - Contract.Requires(sup != null); - Contract.Requires(inf != null); - Contract.Requires(inf != null && sup != null); - return inf.CompareTo(sup) >= 0; - } - - public static ExtendedInt/*!*/ Inf(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { - Contract.Requires(sup != null); - Contract.Requires(inf != null); - Contract.Ensures(Contract.Result() != null); - if (inf < sup) - return inf; - else - return sup; - } - - public static ExtendedInt/*!*/ Inf(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b, ExtendedInt/*!*/ c, ExtendedInt/*!*/ d) { - Contract.Requires(d != null); - Contract.Requires(c != null); - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - ExtendedInt/*!*/ infab = Inf(a, b); - Contract.Assert(infab != null); - ExtendedInt/*!*/ infcd = Inf(c, d); - Contract.Assert(infcd != null); - - return Inf(infab, infcd); - } - - public static ExtendedInt/*!*/ Sup(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { - Contract.Requires(sup != null); - Contract.Requires(inf != null); - Contract.Ensures(Contract.Result() != null); - if (inf > sup) - return inf; - else - return sup; - } - - public static ExtendedInt/*!*/ Sup(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b, ExtendedInt/*!*/ c, ExtendedInt/*!*/ d) { - Contract.Requires(d != null); - Contract.Requires(c != null); - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - ExtendedInt/*!*/ supab = Sup(a, b); - Contract.Assert(supab != null); - ExtendedInt/*!*/ supcd = Sup(c, d); - Contract.Assert(supcd != null); - - return Sup(supab, supcd); - } - - #endregion - - // Return the ExtendedInt corresponding to the value - public static ExtendedInt/*!*/ Factory(BigNum val) { - Contract.Ensures(Contract.Result() != null); - return new PureInteger(val); - } - } - [ContractClassFor(typeof(ExtendedInt))] - abstract class ExtendedIntContracts : ExtendedInt { - public override int CompareTo(ExtendedInt that) { - Contract.Requires(that != null); - throw new NotImplementedException(); - } - } - - // Stands for a normal (finite) integer x - class PureInteger : ExtendedInt { - public PureInteger(BigNum i) { - this.val = i; - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return this.Value.ToString(); - } - - private BigNum val; - public override BigNum Value { - get { - return this.val; - } - } - - public override int Signum { - get { - return val.Signum; - } - } - - public override int CompareTo(ExtendedInt/*!*/ that) { - //Contract.Requires(that != null); - if (that is PlusInfinity) - return -1; - else if (that is PureInteger) - return this.Value.CompareTo(that.Value); - else // then that is a MinusInfinity - return 1; - } - } - - abstract class InfinitaryInt : ExtendedInt { - public override BigNum Value { - get { - throw new InvalidOperationException(); - } - } - } - - class PlusInfinity : InfinitaryInt { - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return "+oo"; - } - - public override int Signum { - get { - return 1; - } - } - - public override int CompareTo(ExtendedInt/*!*/ that) { - //Contract.Requires(that != null); - if (that is PlusInfinity) - return 0; - else - return 1; - } - } - - class MinusInfinity : InfinitaryInt { - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return "-oo"; - } - - public override int Signum { - get { - return -1; - } - } - - public override int CompareTo(ExtendedInt/*!*/ that) { - //Contract.Requires(that != null); - if (that is MinusInfinity) - return 0; - else - return -1; - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Collections; +//using System.Compiler.Analysis; +using Microsoft.AbstractInterpretationFramework.Collections; +using System.Diagnostics.Contracts; +using Microsoft.Basetypes; + +///////////////////////////////////////////////////////////////////////////////// +// An implementation of the interval abstract domain +///////////////////////////////////////////////////////////////////////////////// + +namespace Microsoft.AbstractInterpretationFramework { + public class IntervalLattice : MicroLattice { + readonly ILinearExprFactory/*!*/ factory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(factory != null); + } + + + public IntervalLattice(ILinearExprFactory/*!*/ factory) { + Contract.Requires(factory != null); + this.factory = factory; + // base(); + } + + public override bool UnderstandsBasicArithmetics { + get { + return true; + } + } + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result() != null); + + return IntervalElement.Top; + } + } + + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result() != null); + + return IntervalElement.Bottom; + } + } + + /// + /// The paramter is the top? + /// + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + IntervalElement interval = (IntervalElement)element; + + return interval.IsTop(); + } + + /// + /// The parameter is the bottom? + /// + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + IntervalElement interval = (IntervalElement)element; + + return interval.IsBottom(); + } + + /// + /// The classic, pointwise, join of intervals + /// + public override Element/*!*/ NontrivialJoin(Element/*!*/ left, Element/*!*/ right) { + //Contract.Requires(right != null); + //Contract.Requires(left != null); + Contract.Ensures(Contract.Result() != null); + IntervalElement/*!*/ leftInterval = (IntervalElement/*!*/)cce.NonNull(left); + IntervalElement/*!*/ rightInterval = (IntervalElement/*!*/)cce.NonNull(right); + + ExtendedInt inf = ExtendedInt.Inf(leftInterval.Inf, rightInterval.Inf); + ExtendedInt sup = ExtendedInt.Sup(leftInterval.Sup, rightInterval.Sup); + + IntervalElement/*!*/ join = IntervalElement.Factory(inf, sup); + + return join; + } + + /// + /// The classic, pointwise, meet of intervals + /// + public override Element/*!*/ NontrivialMeet(Element/*!*/ left, Element/*!*/ right) { + //Contract.Requires(right != null); + //Contract.Requires(left != null); + Contract.Ensures(Contract.Result() != null); + IntervalElement/*!*/ leftInterval = (IntervalElement/*!*/)cce.NonNull(left); + IntervalElement/*!*/ rightInterval = (IntervalElement/*!*/)cce.NonNull(right); + + ExtendedInt inf = ExtendedInt.Sup(leftInterval.Inf, rightInterval.Inf); + ExtendedInt sup = ExtendedInt.Inf(leftInterval.Sup, rightInterval.Sup); + + return IntervalElement.Factory(inf, sup); + } + + + /// + /// The very simple widening of intervals, to be improved with thresholds + /// left is the PREVIOUS value in the iterations and right is the NEW one + /// + public override Element/*!*/ Widen(Element/*!*/ left, Element/*!*/ right) { + //Contract.Requires(right != null); + //Contract.Requires(left != null); + Contract.Ensures(Contract.Result() != null); + IntervalElement/*!*/ prevInterval = (IntervalElement/*!*/)cce.NonNull(left); + IntervalElement/*!*/ nextInterval = (IntervalElement/*!*/)cce.NonNull(right); + + ExtendedInt inf = nextInterval.Inf < prevInterval.Inf ? ExtendedInt.MinusInfinity : prevInterval.Inf; + ExtendedInt sup = nextInterval.Sup > prevInterval.Sup ? ExtendedInt.PlusInfinity : prevInterval.Sup; + + IntervalElement widening = IntervalElement.Factory(inf, sup); + + return widening; + } + + + /// + /// Return true iff the interval left is containted in right + /// + protected override bool AtMost(Element/*!*/ left, Element/*!*/ right) { + //Contract.Requires(right != null); + //Contract.Requires(left != null); + IntervalElement/*!*/ leftInterval = (IntervalElement/*!*/)cce.NonNull(left); + IntervalElement/*!*/ rightInterval = (IntervalElement/*!*/)cce.NonNull(right); + + if (leftInterval.IsBottom() || rightInterval.IsTop()) + return true; + + return rightInterval.Inf <= leftInterval.Inf && leftInterval.Sup <= rightInterval.Sup; + } + + /// + /// Return just null + /// + public override IExpr GetFoldExpr(Element/*!*/ element) { + //Contract.Requires(element != null); + return null; + } + + /// + /// return a predicate inf "\leq x and x "\leq" sup (if inf [or sup] is not oo) + /// + public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { + //Contract.Requires(element != null); + //Contract.Requires(var != null); + Contract.Ensures(Contract.Result() != null); + IntervalElement/*!*/ interval = (IntervalElement/*!*/)cce.NonNull(element); + IExpr lowerBound = null; + IExpr upperBound = null; + + if (!(interval.Inf is InfinitaryInt)) { + IExpr constant = this.factory.Const(interval.Inf.Value); + lowerBound = this.factory.AtMost(constant, var); // inf <= var + } + if (!(interval.Sup is InfinitaryInt)) { + IExpr constant = this.factory.Const(interval.Sup.Value); + upperBound = this.factory.AtMost(var, constant); // var <= inf + } + + if (lowerBound != null && upperBound != null) + return this.factory.And(lowerBound, upperBound); // inf <= var && var <= sup + else + if (lowerBound != null) + return lowerBound; + else + if (upperBound != null) + return upperBound; + else // If we reach this point, both lowerBound and upperBound are null, i.e. we have no bounds on var, so we return simply true... + return this.factory.True; + } + + /// + /// For the moment consider just equalities. Other case must be considered + /// + public override bool Understands(IFunctionSymbol/*!*/ f, IList /* + /// Evaluate the predicate passed as input according the semantics of intervals + /// + public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ pred) { + //Contract.Requires(pred != null); + Contract.Ensures(Contract.Result() != null); + return this.EvaluatePredicateWithState(pred, null); + } + + /// + /// Evaluate the predicate passed as input according the semantics of intervals and the given state. + /// Right now just basic arithmetic operations are supported. A future extension may consider an implementation of boolean predicates + /// + public override Element/*!*/ EvaluatePredicateWithState(IExpr/*!*/ pred, IFunctionalMap/* Var -> Element */ state) { + //Contract.Requires(pred != null); + Contract.Ensures(Contract.Result() != null); + if (pred is IFunApp) { + IFunApp fun = (IFunApp)pred; + if (fun.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq)) // if it is a symbol of equality + { + IExpr/*!*/ leftArg = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); + IExpr/*!*/ rightArg = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]); + if (leftArg is IVariable) { + return Eval(rightArg, state); + } else if (rightArg is IVariable) { + return Eval(leftArg, state); + } + } + } + // otherwise we simply return Top + return IntervalElement.Top; + } + + /// + /// Evaluate the expression (that is assured to be an arithmetic expression, in the state passed as a parameter + /// + private IntervalElement/*!*/ Eval(IExpr/*!*/ exp, IFunctionalMap/* Var -> Element */ state) { + Contract.Requires((exp != null)); + Contract.Ensures(Contract.Result() != null); + + IntervalElement/*!*/ retVal = (IntervalElement/*!*/)cce.NonNull(Top); + + // Eval the expression by structural induction + + + if (exp is IVariable && state != null) // A variable + { + object lookup = state[exp]; + if (lookup is IntervalElement) + retVal = (IntervalElement)lookup; + else { + retVal = (IntervalElement)Top; + } + } else if (exp is IFunApp) { + IFunApp fun = (IFunApp)exp; + + if (fun.FunctionSymbol is IntSymbol) // An integer + { + IntSymbol intSymb = (IntSymbol)fun.FunctionSymbol; + BigNum val = intSymb.Value; + + retVal = IntervalElement.Factory(val); + } else if (fun.FunctionSymbol.Equals(Int.Negate)) // An unary minus + { + IExpr/*!*/ arg = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); + IntervalElement/*!*/ argEval = Eval(arg, state); + Contract.Assert(argEval != null); + IntervalElement/*!*/ zero = IntervalElement.Factory(BigNum.ZERO); + Contract.Assert(zero != null); + + retVal = zero - argEval; + } else if (fun.Arguments.Count == 2) { + IExpr/*!*/ left = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); + IExpr/*!*/ right = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]); + + IntervalElement/*!*/ leftVal = Eval(left, state); + Contract.Assert(leftVal != null); + IntervalElement/*!*/ rightVal = Eval(right, state); + Contract.Assert(rightVal != null); + + if (fun.FunctionSymbol.Equals(Int.Add)) + retVal = leftVal + rightVal; + else if (fun.FunctionSymbol.Equals(Int.Sub)) + retVal = leftVal - rightVal; + else if (fun.FunctionSymbol.Equals(Int.Mul)) + retVal = leftVal * rightVal; + else if (fun.FunctionSymbol.Equals(Int.Div)) + retVal = leftVal / rightVal; + else if (fun.FunctionSymbol.Equals(Int.Mod)) + retVal = leftVal % rightVal; + } + } + + return retVal; + } + + /// + /// Inner class standing for an interval on integers, possibly unbounded + /// + private class IntervalElement : Element { + protected static readonly IntervalElement/*!*/ TopInterval = new IntervalElement(new MinusInfinity(), new PlusInfinity()); // Top = [-oo , +oo] + protected static readonly IntervalElement/*!*/ BottomInterval = new IntervalElement(new PlusInfinity(), new MinusInfinity()); // Bottom = [+oo, -oo] + + private readonly ExtendedInt/*!*/ inf; + private readonly ExtendedInt/*!*/ sup; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(inf != null); + Contract.Invariant(sup != null); + } + + public ExtendedInt/*!*/ Inf { + get { + Contract.Ensures(Contract.Result() != null); + + return inf; + } + } + + public ExtendedInt/*!*/ Sup { + get { + Contract.Ensures(Contract.Result() != null); + + return sup; + } + } + + // Construct the inteval [val, val] + protected IntervalElement(BigNum val) { + this.inf = this.sup = ExtendedInt.Factory(val); + // base(); + } + + // Construct the interval [inf, sup] + protected IntervalElement(BigNum infInt, BigNum supInt) { + this.inf = ExtendedInt.Factory(infInt); + this.sup = ExtendedInt.Factory(supInt); + // base(); // to please the compiler... + } + + protected IntervalElement(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + this.inf = inf; + this.sup = sup; + // base(); + } + + // Construct an Interval + public static IntervalElement/*!*/ Factory(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires((sup != null)); + Contract.Requires((inf != null)); + Contract.Ensures(Contract.Result() != null); + if (inf is MinusInfinity && sup is PlusInfinity) + return Top; + if (inf > sup) + return Bottom; + // otherwise... + return new IntervalElement(inf, sup); + } + + public static IntervalElement/*!*/ Factory(BigNum i) { + Contract.Ensures(Contract.Result() != null); + return new IntervalElement(i); + } + + public static IntervalElement/*!*/ Factory(BigNum inf, BigNum sup) { + Contract.Ensures(Contract.Result() != null); + ExtendedInt/*!*/ i = ExtendedInt.Factory(inf); + ExtendedInt/*!*/ s = ExtendedInt.Factory(sup); + + return Factory(i, s); + } + + static public IntervalElement/*!*/ Top { + get { + Contract.Ensures(Contract.Result() != null); + + return TopInterval; + } + } + + static public IntervalElement/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result() != null); + + return BottomInterval; + } + } + + public bool IsTop() { + return this.inf is MinusInfinity && this.sup is PlusInfinity; + } + + public bool IsBottom() { + return this.inf > this.sup; + } + + #region Below are the arithmetic operations lifted to intervals + + // Addition + public static IntervalElement/*!*/ operator +(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + ExtendedInt/*!*/ inf = a.inf + b.inf; + Contract.Assert(inf != null); + ExtendedInt/*!*/ sup = a.sup + b.sup; + Contract.Assert(sup != null); + + return Factory(inf, sup); + } + + // Subtraction + public static IntervalElement/*!*/ operator -(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + ExtendedInt/*!*/ inf = a.inf - b.sup; + Contract.Assert(inf != null); + + ExtendedInt/*!*/ sup = a.sup - b.inf; + Contract.Assert(sup != null); + IntervalElement/*!*/ sub = Factory(inf, sup); + Contract.Assert(sub != null); + + return sub; + } + + // Multiplication + public static IntervalElement/*!*/ operator *(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + ExtendedInt/*!*/ infinf = a.inf * b.inf; + Contract.Assert(infinf != null); + ExtendedInt/*!*/ infsup = a.inf * b.sup; + Contract.Assert(infsup != null); + ExtendedInt/*!*/ supinf = a.sup * b.inf; + Contract.Assert(supinf != null); + ExtendedInt/*!*/ supsup = a.sup * b.sup; + Contract.Assert(supsup != null); + + ExtendedInt/*!*/ inf = ExtendedInt.Inf(infinf, infsup, supinf, supsup); + Contract.Assert(inf != null); + ExtendedInt/*!*/ sup = ExtendedInt.Sup(infinf, infsup, supinf, supsup); + Contract.Assert(sup != null); + + return Factory(inf, sup); + } + + // Division + public static IntervalElement/*!*/ operator /(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + if (b.inf.IsZero && b.sup.IsZero) // Check division by zero + return IntervalElement.Top; + + ExtendedInt/*!*/ infinf = a.inf / b.inf; + Contract.Assert(infinf != null); + ExtendedInt/*!*/ infsup = a.inf / b.sup; + Contract.Assert(infsup != null); + ExtendedInt/*!*/ supinf = a.sup / b.inf; + Contract.Assert(supinf != null); + ExtendedInt/*!*/ supsup = a.sup / b.sup; + Contract.Assert(supsup != null); + + ExtendedInt/*!*/ inf = ExtendedInt.Inf(infinf, infsup, supinf, supsup); + Contract.Assert(inf != null); + ExtendedInt/*!*/ sup = ExtendedInt.Sup(infinf, infsup, supinf, supsup); + Contract.Assert(sup != null); + + return Factory(inf, sup); + } + + // Division + public static IntervalElement/*!*/ operator %(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + if (b.inf.IsZero && b.sup.IsZero) // Check division by zero + return IntervalElement.Top; + + ExtendedInt/*!*/ infinf = a.inf % b.inf; + Contract.Assert(infinf != null); + ExtendedInt/*!*/ infsup = a.inf % b.sup; + Contract.Assert(infsup != null); + ExtendedInt/*!*/ supinf = a.sup % b.inf; + Contract.Assert(supinf != null); + ExtendedInt/*!*/ supsup = a.sup % b.sup; + Contract.Assert(supsup != null); + + ExtendedInt inf = ExtendedInt.Inf(infinf, infsup, supinf, supsup); + ExtendedInt sup = ExtendedInt.Sup(infinf, infsup, supinf, supsup); + + return Factory(inf, sup); + } + + #endregion + + #region Overriden methods + + public override Element/*!*/ Clone() { + Contract.Ensures(Contract.Result() != null); + // Real copying should not be needed because intervals are immutable? + return this; + /* + int valInf = this.inf.Value; + int valSup = this.sup.Value; + + ExtendedInt clonedInf = ExtendedInt.Factory(valInf); + ExtendedInt clonedSup = ExtendedInt.Factory(valSup); + + return Factory(clonedInf, clonedSup); + */ + } + + [Pure] + public override System.Collections.Generic.ICollection/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return cce.NonNull(new System.Collections.Generic.List()).AsReadOnly(); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return "[" + this.inf + ", " + this.sup + "]"; + } + + #endregion + } + } + + + /// The interface for an extended integer + /// + [ContractClass(typeof(ExtendedIntContracts))] + abstract class ExtendedInt { + private static readonly PlusInfinity/*!*/ cachedPlusInf = new PlusInfinity(); + private static readonly MinusInfinity/*!*/ cachedMinusInf = new MinusInfinity(); + + static public ExtendedInt/*!*/ PlusInfinity { + get { + Contract.Ensures(Contract.Result() != null); + + return cachedPlusInf; + } + } + + static public ExtendedInt/*!*/ MinusInfinity { + get { + Contract.Ensures(Contract.Result() != null); + + return cachedMinusInf; + } + } + + public abstract BigNum Value { + get; + } + + public abstract int Signum { + get; + } + + public bool IsZero { + get { + return Signum == 0; + } + } + + public bool IsPositive { + get { + return Signum > 0; + } + } + + public bool IsNegative { + get { + return Signum < 0; + } + } + + + #region Below are the extensions of arithmetic operations on extended integers + + // Addition + public static ExtendedInt/*!*/ operator +(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + if (a is InfinitaryInt) { + return a; + } else if (b is InfinitaryInt) { + return b; + } else { + return ExtendedInt.Factory(a.Value + b.Value); + } + } + + // Subtraction + public static ExtendedInt/*!*/ operator -(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + if (a is InfinitaryInt) { + return a; + } else if (b is InfinitaryInt) { + return UnaryMinus(b); + } else { + return ExtendedInt.Factory(a.Value - b.Value); + } + } + + // Unary minus + public static ExtendedInt/*!*/ operator -(ExtendedInt/*!*/ a) { + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + // BUGBUG: Some compiler error prevents the unary minus operator from being used + return UnaryMinus(a); + } + + // Unary minus + public static ExtendedInt/*!*/ UnaryMinus(ExtendedInt/*!*/ a) { + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + if (a is PlusInfinity) + return cachedMinusInf; + if (a is MinusInfinity) + return cachedPlusInf; + else // a is a PureInteger + return new PureInteger(-a.Value); + } + + // Multiplication + public static ExtendedInt/*!*/ operator *(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + if (a.IsZero) { + return a; + } else if (b.IsZero) { + return b; + } else if (a is InfinitaryInt) { + if (b.IsPositive) { + return a; + } else { + return UnaryMinus(a); + } + } else if (b is InfinitaryInt) { + if (a.IsPositive) { + return b; + } else { + return UnaryMinus(b); + } + } else { + return ExtendedInt.Factory(a.Value * b.Value); + } + } + + // Division + public static ExtendedInt/*!*/ operator /(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + if (b.IsZero) { + return a.IsPositive ? (ExtendedInt)cachedPlusInf : cachedMinusInf; + } + if (a is InfinitaryInt) { + return a; + } else if (b is InfinitaryInt) { + return b; + } else { + return ExtendedInt.Factory(a.Value / b.Value); + } + } + + // Modulo + public static ExtendedInt/*!*/ operator %(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + if (b.IsZero) { + return a.IsPositive ? (ExtendedInt)cachedPlusInf : cachedMinusInf; + } + if (a is InfinitaryInt) { + return a; + } else if (b is InfinitaryInt) { + return b; + } else { + return ExtendedInt.Factory(a.Value % b.Value); + } + } + + #endregion + + #region Inf and Sup operations + + public abstract int CompareTo(ExtendedInt/*!*/ that); + + public static bool operator <(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + return inf.CompareTo(sup) < 0; + } + + public static bool operator >(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + return inf.CompareTo(sup) > 0; + } + + public static bool operator <=(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + return inf.CompareTo(sup) <= 0; + } + + public static bool operator >=(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + Contract.Requires(inf != null && sup != null); + return inf.CompareTo(sup) >= 0; + } + + public static ExtendedInt/*!*/ Inf(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + Contract.Ensures(Contract.Result() != null); + if (inf < sup) + return inf; + else + return sup; + } + + public static ExtendedInt/*!*/ Inf(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b, ExtendedInt/*!*/ c, ExtendedInt/*!*/ d) { + Contract.Requires(d != null); + Contract.Requires(c != null); + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + ExtendedInt/*!*/ infab = Inf(a, b); + Contract.Assert(infab != null); + ExtendedInt/*!*/ infcd = Inf(c, d); + Contract.Assert(infcd != null); + + return Inf(infab, infcd); + } + + public static ExtendedInt/*!*/ Sup(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + Contract.Ensures(Contract.Result() != null); + if (inf > sup) + return inf; + else + return sup; + } + + public static ExtendedInt/*!*/ Sup(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b, ExtendedInt/*!*/ c, ExtendedInt/*!*/ d) { + Contract.Requires(d != null); + Contract.Requires(c != null); + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + ExtendedInt/*!*/ supab = Sup(a, b); + Contract.Assert(supab != null); + ExtendedInt/*!*/ supcd = Sup(c, d); + Contract.Assert(supcd != null); + + return Sup(supab, supcd); + } + + #endregion + + // Return the ExtendedInt corresponding to the value + public static ExtendedInt/*!*/ Factory(BigNum val) { + Contract.Ensures(Contract.Result() != null); + return new PureInteger(val); + } + } + [ContractClassFor(typeof(ExtendedInt))] + abstract class ExtendedIntContracts : ExtendedInt { + public override int CompareTo(ExtendedInt that) { + Contract.Requires(that != null); + throw new NotImplementedException(); + } + } + + // Stands for a normal (finite) integer x + class PureInteger : ExtendedInt { + public PureInteger(BigNum i) { + this.val = i; + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return this.Value.ToString(); + } + + private BigNum val; + public override BigNum Value { + get { + return this.val; + } + } + + public override int Signum { + get { + return val.Signum; + } + } + + public override int CompareTo(ExtendedInt/*!*/ that) { + //Contract.Requires(that != null); + if (that is PlusInfinity) + return -1; + else if (that is PureInteger) + return this.Value.CompareTo(that.Value); + else // then that is a MinusInfinity + return 1; + } + } + + abstract class InfinitaryInt : ExtendedInt { + public override BigNum Value { + get { + throw new InvalidOperationException(); + } + } + } + + class PlusInfinity : InfinitaryInt { + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return "+oo"; + } + + public override int Signum { + get { + return 1; + } + } + + public override int CompareTo(ExtendedInt/*!*/ that) { + //Contract.Requires(that != null); + if (that is PlusInfinity) + return 0; + else + return 1; + } + } + + class MinusInfinity : InfinitaryInt { + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return "-oo"; + } + + public override int Signum { + get { + return -1; + } + } + + public override int CompareTo(ExtendedInt/*!*/ that) { + //Contract.Requires(that != null); + if (that is MinusInfinity) + return 0; + else + return -1; + } + } +} diff --git a/Source/AIFramework/VariableMap/MicroLattice.cs b/Source/AIFramework/VariableMap/MicroLattice.cs index ef98f8f7..f46349b7 100644 --- a/Source/AIFramework/VariableMap/MicroLattice.cs +++ b/Source/AIFramework/VariableMap/MicroLattice.cs @@ -1,105 +1,105 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework -{ - using System.Diagnostics.Contracts; - using System.Collections; - using System.Diagnostics; - //using System.Compiler; - using Microsoft.AbstractInterpretationFramework.Collections; - - /// - /// Interface for a lattice that works on a per-variable basis. - /// - /// - [ContractClass(typeof(MicroLatticeContracts))] - public abstract class MicroLattice : MathematicalLattice - { - /// - /// Returns the predicate on the given variable for the given - /// lattice element. - /// - public abstract IExpr/*!*/ ToPredicate(IVariable/*!*/ v, Element/*!*/ e); - /* requires !e.IsBottom && !e.IsTop; */ - - /// - /// Allows the lattice to specify whether it understands a particular function symbol. - /// - /// The lattice is always allowed to "true" even when it really can't do anything with - /// such functions; however, it is advantageous to say "false" when possible to avoid - /// being called to do certain things. - /// - /// The arguments to a function are provided for context so that the lattice can say - /// true or false for the same function symbol in different situations. For example, - /// a lattice may understand the multiplication of a variable and a constant but not - /// of two variables. The implementation of a lattice should not hold on to the - /// arguments. - /// - /// The function symbol. - /// The argument context. - /// True if it may understand f, false if it does not understand f. - public abstract bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args); - - /// - /// Set this property to true if the implemented MicroLattice can handle basic arithmetic. - /// Stated otherwise this property is set to true if the MicroLattice provides a transfer function for a predicate in a given state - /// - public virtual bool UnderstandsBasicArithmetics - { - get { return false; } - } - - /// - /// Evaluate the predicate e and a yield the lattice element - /// that is implied by it. - /// - /// The predicate that is assumed to contain 1 variable. - /// The most precise lattice element that is implied by the predicate. - public abstract Element/*!*/ EvaluatePredicate(IExpr/*!*/ e); - - /// - /// Evaluate the predicate e and yield an overapproximation of the predicate under the state that is passed as a parameter - /// Note that unless the subclass implement it, the default behavior is to evaluate the predicate stateless, that implies that it - /// is evaluated in any possible context, i.e. it is an upper approximation - /// - public virtual Element/*!*/ EvaluatePredicateWithState(IExpr/*!*/ e, IFunctionalMap state){ -Contract.Requires(e != null); -Contract.Ensures(Contract.Result() != null); - return EvaluatePredicate(e); - } - - /// - /// Give an expression (often a value) that can be used to substitute for - /// the variable. - /// - /// A lattice element. - /// The null value if no such expression can be given. - public abstract IExpr GetFoldExpr(Element/*!*/ e); - } - [ContractClassFor(typeof(MicroLattice))] - public abstract class MicroLatticeContracts : MicroLattice { - public override IExpr ToPredicate(IVariable v, MathematicalLattice.Element e) { - Contract.Requires(v != null); - Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - public override bool Understands(IFunctionSymbol f, IList args) { - Contract.Requires(f != null); - Contract.Requires(args != null); - throw new System.NotImplementedException(); - } - public override Element EvaluatePredicate(IExpr e) { - Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - public override IExpr GetFoldExpr(MathematicalLattice.Element e) { - Contract.Requires(e != null); - throw new System.NotImplementedException(); - } - } +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework +{ + using System.Diagnostics.Contracts; + using System.Collections; + using System.Diagnostics; + //using System.Compiler; + using Microsoft.AbstractInterpretationFramework.Collections; + + /// + /// Interface for a lattice that works on a per-variable basis. + /// + /// + [ContractClass(typeof(MicroLatticeContracts))] + public abstract class MicroLattice : MathematicalLattice + { + /// + /// Returns the predicate on the given variable for the given + /// lattice element. + /// + public abstract IExpr/*!*/ ToPredicate(IVariable/*!*/ v, Element/*!*/ e); + /* requires !e.IsBottom && !e.IsTop; */ + + /// + /// Allows the lattice to specify whether it understands a particular function symbol. + /// + /// The lattice is always allowed to "true" even when it really can't do anything with + /// such functions; however, it is advantageous to say "false" when possible to avoid + /// being called to do certain things. + /// + /// The arguments to a function are provided for context so that the lattice can say + /// true or false for the same function symbol in different situations. For example, + /// a lattice may understand the multiplication of a variable and a constant but not + /// of two variables. The implementation of a lattice should not hold on to the + /// arguments. + /// + /// The function symbol. + /// The argument context. + /// True if it may understand f, false if it does not understand f. + public abstract bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args); + + /// + /// Set this property to true if the implemented MicroLattice can handle basic arithmetic. + /// Stated otherwise this property is set to true if the MicroLattice provides a transfer function for a predicate in a given state + /// + public virtual bool UnderstandsBasicArithmetics + { + get { return false; } + } + + /// + /// Evaluate the predicate e and a yield the lattice element + /// that is implied by it. + /// + /// The predicate that is assumed to contain 1 variable. + /// The most precise lattice element that is implied by the predicate. + public abstract Element/*!*/ EvaluatePredicate(IExpr/*!*/ e); + + /// + /// Evaluate the predicate e and yield an overapproximation of the predicate under the state that is passed as a parameter + /// Note that unless the subclass implement it, the default behavior is to evaluate the predicate stateless, that implies that it + /// is evaluated in any possible context, i.e. it is an upper approximation + /// + public virtual Element/*!*/ EvaluatePredicateWithState(IExpr/*!*/ e, IFunctionalMap state){ +Contract.Requires(e != null); +Contract.Ensures(Contract.Result() != null); + return EvaluatePredicate(e); + } + + /// + /// Give an expression (often a value) that can be used to substitute for + /// the variable. + /// + /// A lattice element. + /// The null value if no such expression can be given. + public abstract IExpr GetFoldExpr(Element/*!*/ e); + } + [ContractClassFor(typeof(MicroLattice))] + public abstract class MicroLatticeContracts : MicroLattice { + public override IExpr ToPredicate(IVariable v, MathematicalLattice.Element e) { + Contract.Requires(v != null); + Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + public override bool Understands(IFunctionSymbol f, IList args) { + Contract.Requires(f != null); + Contract.Requires(args != null); + throw new System.NotImplementedException(); + } + public override Element EvaluatePredicate(IExpr e) { + Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + public override IExpr GetFoldExpr(MathematicalLattice.Element e) { + Contract.Requires(e != null); + throw new System.NotImplementedException(); + } + } } \ No newline at end of file diff --git a/Source/AIFramework/VariableMap/Nullness.cs b/Source/AIFramework/VariableMap/Nullness.cs index 613f55e0..474792e0 100644 --- a/Source/AIFramework/VariableMap/Nullness.cs +++ b/Source/AIFramework/VariableMap/Nullness.cs @@ -1,260 +1,260 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System.Diagnostics.Contracts; -namespace Microsoft.AbstractInterpretationFramework { - using System.Collections; - using System.Diagnostics; - //using System.Compiler.Analysis; - - public class NullnessLattice : MicroLattice { - readonly INullnessFactory/*!*/ factory; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(factory != null); - } - - - public NullnessLattice(INullnessFactory/*!*/ factory) { - Contract.Requires(factory != null); - this.factory = factory; - // base(); - } - - enum Value { - Bottom, - NotNull, - Null, - MayBeNull - } - - private class Elt : Element { - public Value value; - - public Elt(Value v) { - this.value = v; - } - - [Pure] - public override System.Collections.Generic.ICollection/*!*/ FreeVariables() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return cce.NonNull(new System.Collections.Generic.List()).AsReadOnly(); - } - - public override Element/*!*/ Clone() { - Contract.Ensures(Contract.Result() != null); - return new Elt(this.value); - } - } - - - public override Element/*!*/ Top { - get { - Contract.Ensures(Contract.Result() != null); - return new Elt(Value.MayBeNull); - } - } - - public override Element/*!*/ Bottom { - get { - Contract.Ensures(Contract.Result() != null); - return new Elt(Value.Bottom); - } - } - - public static Element/*!*/ Null { - get { - Contract.Ensures(Contract.Result() != null); - return new Elt(Value.Null); - } - } - - public static Element/*!*/ NotNull { - get { - Contract.Ensures(Contract.Result() != null); - return new Elt(Value.NotNull); - } - } - - public override bool IsTop(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - return e.value == Value.MayBeNull; - } - - public override bool IsBottom(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - return e.value == Value.Bottom; - } - - public override Lattice.Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - return (a.value == b.value) ? a : (Elt)Top; - } - - public override Lattice.Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - return (a.value == b.value) ? a : (Elt)Bottom; - } - - public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - return Join(first, second); - } - - protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that - { - //Contract.Requires(first != null); - //Contract.Requires(second != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - return a.value == b.value; - } - - public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { - //Contract.Requires(element != null); - //Contract.Requires(var != null); - Contract.Ensures(Contract.Result() != null); - Elt e = (Elt)element; - - if (e.value == Value.NotNull) { - return factory.Neq(var, factory.Null); - } - if (e.value == Value.Null) { - return factory.Eq(var, factory.Null); - } - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } - throw new System.Exception(); - } - - public override IExpr GetFoldExpr(Element/*!*/ e) { - //Contract.Requires(e != null); - Elt elt = (Elt)e; - if (elt.value == Value.Null) { - return factory.Null; - } else { - // can't fold into an expression - return null; - } - } - - public override bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args) { - //Contract.Requires(args != null); - //Contract.Requires(f != null); - if (f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq) || - f.Equals(Microsoft.AbstractInterpretationFramework.Value.Neq)) { - - Contract.Assert(args.Count == 2); - IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); - IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); - - // Look for "x OP null" or "null OP x" where OP is "==" or "!=". - if (arg0 is IVariable && arg1 is IFunApp && ((IFunApp)arg1).FunctionSymbol == Ref.Null) { - return true; - } else if (arg1 is IVariable && arg0 is IFunApp && ((IFunApp)arg0).FunctionSymbol == Ref.Null) { - return true; - } - } - return false; - } - - public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ e) { - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - IFunApp nary = e as IFunApp; - if (nary != null) { - bool isEq = nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq); - if (isEq || nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Neq)) { - IList/**//*!*/ args = nary.Arguments; - Contract.Assert(args != null); - Contract.Assert(args.Count == 2); - IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); - IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); - - // Look for "x OP null" or "null OP x" where OP is "==" or "!=". - IVariable var = null; - if (arg0 is IVariable && arg1 is IFunApp && ((IFunApp)arg1).FunctionSymbol == Ref.Null) { - var = (IVariable)arg0; - } else if (arg1 is IVariable && arg0 is IFunApp && ((IFunApp)arg0).FunctionSymbol == Ref.Null) { - var = (IVariable)arg1; - } - - if (var != null) // found the pattern - { - return isEq ? Null : NotNull; - } - } - } - return Top; - } - } - -#if false - - public class NullnessMicroLattice : MicroLattice - { - public override MicroLatticeElement Top { get { return NullnessLatticeElement.Top; } } - public override MicroLatticeElement Bottom { get { return NullnessLatticeElement.Bottom; } } - - - public override MicroLatticeElement EvaluateExpression (Expr e, LookupValue lookup) - { - if (e is LiteralExpr && ((LiteralExpr)e).Val == null) - { - return NullnessLatticeElement.Null; - } - return Top; - } - - - public override MicroLatticeElement EvaluatePredicate (Expr e, LookupValue lookup) - { - NAryExpr nary = e as NAryExpr; - if (nary != null && - (nary.Fun.FunctionName.Equals("==") || nary.Fun.FunctionName.Equals("!="))) - { - Debug.Assert(nary.Args.Length == 2); - - Expr arg0 = nary.Args[0], arg1 = nary.Args[1]; - Variable var = null; - - // Look for "x OP null" or "null OP x" where OP is "==" or "!=". - if (arg0 is IdentifierExpr && arg1 is LiteralExpr && ((LiteralExpr)arg1).Val == null) - { - var = ((IdentifierExpr)arg0).Decl; - } - else if (arg1 is IdentifierExpr && arg0 is LiteralExpr && ((LiteralExpr)arg0).Val == null) - { - var = ((IdentifierExpr)arg1).Decl; - } - - if (var != null) // found the pattern - { - return nary.Fun.FunctionName.Equals("==") ? - NullnessLatticeElement.Null : - NullnessLatticeElement.NotNull; - } - } - return Top; - } - } - -#endif - -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System.Diagnostics.Contracts; +namespace Microsoft.AbstractInterpretationFramework { + using System.Collections; + using System.Diagnostics; + //using System.Compiler.Analysis; + + public class NullnessLattice : MicroLattice { + readonly INullnessFactory/*!*/ factory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(factory != null); + } + + + public NullnessLattice(INullnessFactory/*!*/ factory) { + Contract.Requires(factory != null); + this.factory = factory; + // base(); + } + + enum Value { + Bottom, + NotNull, + Null, + MayBeNull + } + + private class Elt : Element { + public Value value; + + public Elt(Value v) { + this.value = v; + } + + [Pure] + public override System.Collections.Generic.ICollection/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return cce.NonNull(new System.Collections.Generic.List()).AsReadOnly(); + } + + public override Element/*!*/ Clone() { + Contract.Ensures(Contract.Result() != null); + return new Elt(this.value); + } + } + + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result() != null); + return new Elt(Value.MayBeNull); + } + } + + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result() != null); + return new Elt(Value.Bottom); + } + } + + public static Element/*!*/ Null { + get { + Contract.Ensures(Contract.Result() != null); + return new Elt(Value.Null); + } + } + + public static Element/*!*/ NotNull { + get { + Contract.Ensures(Contract.Result() != null); + return new Elt(Value.NotNull); + } + } + + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return e.value == Value.MayBeNull; + } + + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return e.value == Value.Bottom; + } + + public override Lattice.Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + return (a.value == b.value) ? a : (Elt)Top; + } + + public override Lattice.Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + return (a.value == b.value) ? a : (Elt)Bottom; + } + + public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + return Join(first, second); + } + + protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that + { + //Contract.Requires(first != null); + //Contract.Requires(second != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + return a.value == b.value; + } + + public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { + //Contract.Requires(element != null); + //Contract.Requires(var != null); + Contract.Ensures(Contract.Result() != null); + Elt e = (Elt)element; + + if (e.value == Value.NotNull) { + return factory.Neq(var, factory.Null); + } + if (e.value == Value.Null) { + return factory.Eq(var, factory.Null); + } + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } + throw new System.Exception(); + } + + public override IExpr GetFoldExpr(Element/*!*/ e) { + //Contract.Requires(e != null); + Elt elt = (Elt)e; + if (elt.value == Value.Null) { + return factory.Null; + } else { + // can't fold into an expression + return null; + } + } + + public override bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + if (f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq) || + f.Equals(Microsoft.AbstractInterpretationFramework.Value.Neq)) { + + Contract.Assert(args.Count == 2); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); + + // Look for "x OP null" or "null OP x" where OP is "==" or "!=". + if (arg0 is IVariable && arg1 is IFunApp && ((IFunApp)arg1).FunctionSymbol == Ref.Null) { + return true; + } else if (arg1 is IVariable && arg0 is IFunApp && ((IFunApp)arg0).FunctionSymbol == Ref.Null) { + return true; + } + } + return false; + } + + public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ e) { + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + IFunApp nary = e as IFunApp; + if (nary != null) { + bool isEq = nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq); + if (isEq || nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Neq)) { + IList/**//*!*/ args = nary.Arguments; + Contract.Assert(args != null); + Contract.Assert(args.Count == 2); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); + + // Look for "x OP null" or "null OP x" where OP is "==" or "!=". + IVariable var = null; + if (arg0 is IVariable && arg1 is IFunApp && ((IFunApp)arg1).FunctionSymbol == Ref.Null) { + var = (IVariable)arg0; + } else if (arg1 is IVariable && arg0 is IFunApp && ((IFunApp)arg0).FunctionSymbol == Ref.Null) { + var = (IVariable)arg1; + } + + if (var != null) // found the pattern + { + return isEq ? Null : NotNull; + } + } + } + return Top; + } + } + +#if false + + public class NullnessMicroLattice : MicroLattice + { + public override MicroLatticeElement Top { get { return NullnessLatticeElement.Top; } } + public override MicroLatticeElement Bottom { get { return NullnessLatticeElement.Bottom; } } + + + public override MicroLatticeElement EvaluateExpression (Expr e, LookupValue lookup) + { + if (e is LiteralExpr && ((LiteralExpr)e).Val == null) + { + return NullnessLatticeElement.Null; + } + return Top; + } + + + public override MicroLatticeElement EvaluatePredicate (Expr e, LookupValue lookup) + { + NAryExpr nary = e as NAryExpr; + if (nary != null && + (nary.Fun.FunctionName.Equals("==") || nary.Fun.FunctionName.Equals("!="))) + { + Debug.Assert(nary.Args.Length == 2); + + Expr arg0 = nary.Args[0], arg1 = nary.Args[1]; + Variable var = null; + + // Look for "x OP null" or "null OP x" where OP is "==" or "!=". + if (arg0 is IdentifierExpr && arg1 is LiteralExpr && ((LiteralExpr)arg1).Val == null) + { + var = ((IdentifierExpr)arg0).Decl; + } + else if (arg1 is IdentifierExpr && arg0 is LiteralExpr && ((LiteralExpr)arg0).Val == null) + { + var = ((IdentifierExpr)arg1).Decl; + } + + if (var != null) // found the pattern + { + return nary.Fun.FunctionName.Equals("==") ? + NullnessLatticeElement.Null : + NullnessLatticeElement.NotNull; + } + } + return Top; + } + } + +#endif + +} diff --git a/Source/AIFramework/VariableMap/VariableMapLattice.cs b/Source/AIFramework/VariableMap/VariableMapLattice.cs index 172cef01..752d3f01 100644 --- a/Source/AIFramework/VariableMap/VariableMapLattice.cs +++ b/Source/AIFramework/VariableMap/VariableMapLattice.cs @@ -1,854 +1,854 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework { - using System.Diagnostics.Contracts; - using System.Collections; - using System.Collections.Generic; - using System.Diagnostics; - - using Microsoft.AbstractInterpretationFramework; - using Microsoft.AbstractInterpretationFramework.Collections; - - using Microsoft.Boogie; - - using IMutableSet = Microsoft.Boogie.GSet; - using ISet = Microsoft.Boogie.GSet; - using Set = Microsoft.Boogie.GSet; - using HashSet = Microsoft.Boogie.GSet; - - /// - /// Creates a lattice that works for several variables given a MicroLattice. Assumes - /// if one variable is bottom, then all variables are bottom. - /// - public class VariableMapLattice : Lattice { - private class Elt : Element { - /// - /// IsBottom(e) iff e.constraints == null - /// - /*MayBeNull*/ - private IFunctionalMap constraints; // of type IVariable -> LATTICE_ELEMENT - public IFunctionalMap Constraints { - get { - return this.constraints; - } - } - - private Elt(bool top) { - if (top) { - this.constraints = FunctionalHashtable.Empty; - } else { - this.constraints = null; - } - } - - public override Element/*!*/ Clone() { - Contract.Ensures(Contract.Result() != null); - return new Elt(this.constraints); - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - if (constraints == null) { - return ""; - } - string s = "["; - string sep = ""; - foreach (IVariable/*!*/ v in cce.NonNull(constraints.Keys)) { - Contract.Assert(v != null); - Element m = (Element)constraints[v]; - s += sep + v.Name + " -> " + m; - sep = ", "; - } - return s + "]"; - } - - public static readonly Elt/*!*/ Top = new Elt(true); - public static readonly Elt/*!*/ Bottom = new Elt(false); - - - public Elt(IFunctionalMap constraints) { - this.constraints = constraints; - } - - public bool IsBottom { - get { - return this.constraints == null; - } - } - - public int Count { - get { - return this.constraints == null ? 0 : this.constraints.Count; - } - } - - public IEnumerable/**//*!*/ Variables { - get { - Contract.Requires(!this.IsBottom); - Contract.Ensures(Contract.Result() != null); - Contract.Assume(this.constraints != null); - return cce.NonNull(this.constraints.Keys); - } - } - - public IEnumerable/**//*!*/ SortedVariables(/*maybe null*/ IComparer variableComparer) { - Contract.Ensures(Contract.Result() != null); - if (variableComparer == null) { - return Variables; - } else { - ArrayList /*IVariable*/ vars = new ArrayList /*IVariable*/ (Count); - foreach (IVariable variable in Variables) { - vars.Add(variable); - } - vars.Sort(variableComparer); - return vars; - } - } - - public Element Lookup(IVariable v) { - if ((v == null) || (this.constraints == null)) { - return null; - } - return (Element)this.constraints[v]; - } - - public Element this[IVariable/*!*/ key] { - get { - Contract.Requires(!this.IsBottom); - Contract.Requires(key != null); - Contract.Assume(this.constraints != null); - return (Element)constraints[key]; - } - } - - /// - /// Add a new entry in the functional map: var --> value. - /// If the variable is already there, throws an exception - /// - public Elt/*!*/ Add(IVariable/*!*/ var, Element/*!*/ value, MicroLattice/*!*/ microLattice) { - Contract.Requires(microLattice != null); - Contract.Requires(value != null); - Contract.Requires(var != null); - Contract.Requires((!this.IsBottom)); - Contract.Ensures(Contract.Result() != null); - Contract.Assume(this.constraints != null); - Contract.Assert(!this.constraints.Contains(var)); - - if (microLattice.IsBottom(value)) { - return Bottom; - } - if (microLattice.IsTop(value)) { - return this.Remove(var, microLattice); - } - - return new Elt(this.constraints.Add(var, value)); - } - - /// - /// Set the value of the variable in the functional map - /// If the variable is not already there, throws an exception - /// - public Elt/*!*/ Set(IVariable/*!*/ var, Element/*!*/ value, MicroLattice/*!*/ microLattice) { - Contract.Requires(microLattice != null); - Contract.Requires(value != null); - Contract.Requires(var != null); - Contract.Ensures(Contract.Result() != null); - if (microLattice.IsBottom(value)) { - return Bottom; - } - if (microLattice.IsTop(value)) { - return this.Remove(var, microLattice); - } - - Contract.Assume(this.constraints != null); - Contract.Assert(this.constraints.Contains(var)); - - // this.constraints[var] = value; - IFunctionalMap newMap = this.constraints.Set(var, value); - - return new Elt(newMap); - } - - public Elt/*!*/ Remove(IVariable/*!*/ var, MicroLattice microLattice) { - Contract.Requires(var != null); - Contract.Ensures(Contract.Result() != null); - if (this.IsBottom) { - return this; - } - Contract.Assume(this.constraints != null); - return new Elt(this.constraints.Remove(var)); - } - - public Elt/*!*/ Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName, MicroLattice/*!*/ microLattice) { - Contract.Requires(microLattice != null); - Contract.Requires(newName != null); - Contract.Requires(oldName != null); - Contract.Requires((!this.IsBottom)); - Contract.Ensures(Contract.Result() != null); - Element value = this[oldName]; - if (value == null) { - return this; - } // 'oldName' isn't in the map, so neither will be 'newName' - Contract.Assume(this.constraints != null); - IFunctionalMap newMap = this.constraints.Remove(oldName); - newMap = newMap.Add(newName, value); - return new Elt(newMap); - } - - [Pure] - public override ICollection/*!*/ FreeVariables() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - throw new System.NotImplementedException(); - } - - } // class - - private readonly MicroLattice/*!*/ microLattice; - - private readonly IPropExprFactory/*!*/ propExprFactory; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(microLattice != null); - Contract.Invariant(propExprFactory != null); - } - - - private readonly /*maybe null*/IComparer variableComparer; - - public VariableMapLattice(IPropExprFactory/*!*/ propExprFactory, IValueExprFactory/*!*/ valueExprFactory, MicroLattice/*!*/ microLattice, /*maybe null*/IComparer variableComparer) - : base(valueExprFactory) { - Contract.Requires(microLattice != null); - Contract.Requires(valueExprFactory != null); - Contract.Requires(propExprFactory != null); - this.propExprFactory = propExprFactory; - this.microLattice = microLattice; - this.variableComparer = variableComparer; - // base(valueExprFactory); - } - - protected override object/*!*/ UniqueId { - get { - Contract.Ensures(Contract.Result() != null); - return this.microLattice.GetType(); - } - } - - public override Element/*!*/ Top { - get { - Contract.Ensures(Contract.Result() != null); - return Elt.Top; - } - } - - public override Element Bottom { - get { - Contract.Ensures(Contract.Result() != null); - return Elt.Bottom; - } - } - - public override bool IsTop(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - return !e.IsBottom && e.Count == 0; - } - - public override bool IsBottom(Element/*!*/ element) { - //Contract.Requires(element != null); - return ((Elt)element).IsBottom; - } - - protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - - // return true iff every constraint in "this" is no weaker than the corresponding - // constraint in "that" and there are no additional constraints in "that" - foreach (IVariable/*!*/ var in a.Variables) { - Contract.Assert(var != null); - Element thisValue = cce.NonNull(a[var]); - - Element thatValue = b[var]; - if (thatValue == null) { - continue; - } // it's okay for "a" to know something "b" doesn't - - if (this.microLattice.LowerThan(thisValue, thatValue)) { - continue; - } // constraint for "var" satisfies AtMost relation - - return false; - } - foreach (IVariable/*!*/ var in b.Variables) { - Contract.Assert(var != null); - if (a.Lookup(var) != null) { - continue; - } // we checked this case in the loop above - - Element thatValue = cce.NonNull(b[var]); - if (this.microLattice.IsTop(thatValue)) { - continue; - } // this is a trivial constraint - - return false; - } - return true; - } - - private Elt/*!*/ AddConstraint(Element/*!*/ element, IVariable/*!*/ var, /*MicroLattice*/Element/*!*/ newValue) { - Contract.Requires((newValue != null)); - Contract.Requires((var != null)); - Contract.Requires((element != null)); - Contract.Ensures(Contract.Result() != null); - Elt e = (Elt)element; - - if (!e.IsBottom && !this.microLattice.IsBottom(newValue)) // if we're not at bottom - { - /*MicroLattice*/ - Element currentValue = e[var]; - - if (currentValue == null) { - // No information currently, so we just add the new info. - return e.Add(var, newValue, this.microLattice); - } else { - // Otherwise, take the meet of the new and current info. - //return e.Add(var, this.microLattice.Meet(currentValue, newValue), this.microLattice); - return e.Set(var, this.microLattice.Meet(currentValue, newValue), this.microLattice); - } - } - return e; - } - - public override string/*!*/ ToString(Element/*!*/ element) { - //Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - Elt e = (Elt)element; - - if (IsTop(e)) { - return ""; - } - if (IsBottom(e)) { - return ""; - } - - int k = 0; - System.Text.StringBuilder buffer = new System.Text.StringBuilder(); - foreach (IVariable/*!*/ key in e.SortedVariables(variableComparer)) { - Contract.Assert(key != null); - if (k++ > 0) { - buffer.Append("; "); - } - buffer.AppendFormat("{0} = {1}", key, e[key]); - } - return buffer.ToString(); - } - - public override Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - - IFunctionalMap newMap = FunctionalHashtable.Empty; - foreach (IVariable/*!*/ key in a.Variables) { - Contract.Assert(key != null); - Element aValue = a[key]; - Element bValue = b[key]; - - if (aValue != null && bValue != null) { - // Keep only the variables known to both elements. - Element newValue = this.microLattice.Join(aValue, bValue); - newMap = newMap.Add(key, newValue); - } - } - Elt/*!*/ join = new Elt(newMap); - Contract.Assert(join != null); - - // System.Console.WriteLine("{0} join {1} = {2} ", this.ToString(a), ToString(b), ToString(join)); - - return join; - } - - public override Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - - IFunctionalMap newMap = FunctionalHashtable.Empty; - foreach (IVariable/*!*/ key in a.Variables) { - Contract.Assert(key != null); - Element/*!*/ aValue = cce.NonNull(a[key]); - Element bValue = b[key]; - - Element newValue = - bValue == null ? aValue : - this.microLattice.Meet(aValue, bValue); - - newMap = newMap.Add(key, newValue); - } - foreach (IVariable/*!*/ key in b.Variables) { - Contract.Assert(key != null); - Element aValue = a[key]; - Element bValue = b[key]; - Debug.Assert(bValue != null); - - if (aValue == null) { - // It's a variable we didn't cover in the last loop. - newMap = newMap.Add(key, bValue); - } - } - return new Elt(newMap); - } - - /// - /// Perform the pointwise widening of the elements in the map - /// - public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires((second != null)); - //Contract.Requires((first != null)); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - - // Note we have to add those cases as we do not have a "NonTrivialWiden" method - if (a.IsBottom) - return new Elt(b.Constraints); - if (b.IsBottom) - return new Elt(a.Constraints); - - IFunctionalMap newMap = FunctionalHashtable.Empty; - foreach (IVariable/*!*/ key in a.Variables) { - Contract.Assert(key != null); - Element aValue = a[key]; - Element bValue = b[key]; - - if (aValue != null && bValue != null) { - // Keep only the variables known to both elements. - Element newValue = this.microLattice.Widen(aValue, bValue); - newMap = newMap.Add(key, newValue); - } - } - Element/*!*/ widen = new Elt(newMap); - Contract.Assert(widen != null); - // System.Console.WriteLine("{0} widen {1} = {2} ", this.ToString(a), ToString(b), ToString(widen)); - - return widen; - } - - internal static ISet/**//*!*/ VariablesInExpression(IExpr/*!*/ e, ISet/**//*!*/ ignoreVars) { - Contract.Requires(ignoreVars != null); - Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - HashSet s = new HashSet(); - - IFunApp f = e as IFunApp; - IFunction lambda = e as IFunction; - - if (e is IVariable) { - if (!ignoreVars.Contains(e)) - s.Add(e); - } else if (f != null) // e is IFunApp - { - foreach (IExpr/*!*/ arg in f.Arguments) { - Contract.Assert(arg != null); - s.AddAll(VariablesInExpression(arg, ignoreVars)); - } - } else if (lambda != null) { - IMutableSet x = new HashSet(1); - x.Add(lambda.Param); - - // Ignore the bound variable - s.AddAll(VariablesInExpression(lambda.Body, cce.NonNull(Set.Union(ignoreVars, x)))); - } else if (e is IUnknown) { - // skip (actually, it would be appropriate to return the universal set of all variables) - } else { - Debug.Assert(false, "case not handled: " + e); - } - return s; - } - - - private static ArrayList/**//*!*/ FindConjuncts(IExpr e) { - Contract.Ensures(Contract.Result() != null); - ArrayList result = new ArrayList(); - - IFunApp f = e as IFunApp; - if (f != null) { - if (f.FunctionSymbol.Equals(Prop.And)) { - foreach (IExpr arg in f.Arguments) { - result.AddRange(FindConjuncts(arg)); - } - } else if (f.FunctionSymbol.Equals(Prop.Or) - || f.FunctionSymbol.Equals(Prop.Implies)) { - // Do nothing. - } else { - result.Add(e); - } - } else { - result.Add(e); - } - - return result; - } - - private static bool IsSimpleEquality(IExpr expr, out IVariable left, out IVariable right) { - Contract.Ensures(!Contract.Result() || Contract.ValueAtReturn(out left) != null && Contract.ValueAtReturn(out right) != null); - left = null; - right = null; - - // See if we have an equality - IFunApp nary = expr as IFunApp; - if (nary == null || !nary.FunctionSymbol.Equals(Value.Eq)) { - return false; - } - - // See if it is an equality of two variables - IVariable idLeft = nary.Arguments[0] as IVariable; - IVariable idRight = nary.Arguments[1] as IVariable; - if (idLeft == null || idRight == null) { - return false; - } - - left = idLeft; - right = idRight; - return true; - } - - /// - /// Returns true iff the expression is in the form var == arithmeticExpr - /// - private static bool IsArithmeticExpr(IExpr/*!*/ expr) { - Contract.Requires(expr != null); - // System.Console.WriteLine("\t\tIsArithmetic called with {0} of type {1}", expr, expr.GetType().ToString()); - - if (expr is IVariable) // expr is a variable - return true; - else if (expr is IFunApp) // may be ==, +, -, /, % or an integer - { - IFunApp fun = (IFunApp)expr; - - if (fun.FunctionSymbol is IntSymbol) // it is an integer - return true; - else if (fun.FunctionSymbol.Equals(Int.Negate)) // it is an unary minus - return IsArithmeticExpr((IExpr/*!*/)cce.NonNull(fun.Arguments[0])); - else if (fun.Arguments.Count != 2) // A function of two or more operands is not arithmetic - return false; - else { - IExpr/*!*/ left = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); - IExpr/*!*/ right = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]); - - if (!(left is IVariable || right is IVariable)) // At least one of the two operands must be a variable - return false; - - if (fun.FunctionSymbol.Equals(Value.Eq) - || fun.FunctionSymbol.Equals(Int.Add) - || fun.FunctionSymbol.Equals(Int.Sub) - || fun.FunctionSymbol.Equals(Int.Mul) - || fun.FunctionSymbol.Equals(Int.Div) - || fun.FunctionSymbol.Equals(Int.Mod)) - return IsArithmeticExpr(left) && IsArithmeticExpr(right); - else - return false; - } - } else { - return false; - } - } - - public override IExpr/*!*/ ToPredicate(Element/*!*/ element) { - //Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - if (IsTop(element)) { - return propExprFactory.True; - } - if (IsBottom(element)) { - return propExprFactory.False; - } - - Elt e = (Elt)element; - IExpr truth = propExprFactory.True; - IExpr result = truth; - - foreach (IVariable/*!*/ variable in e.SortedVariables(variableComparer)) { - Contract.Assert(variable != null); - Element value = (Element)e[variable]; - - if (value == null || this.microLattice.IsTop(value)) { - continue; - } // Skip variables about which we know nothing. - if (this.microLattice.IsBottom(value)) { - return propExprFactory.False; - } - - IExpr conjunct = this.microLattice.ToPredicate(variable, value); - - result = (result == truth) ? (IExpr)conjunct : (IExpr)propExprFactory.And(result, conjunct); - } - return result; - } - - - public override Element/*!*/ Eliminate(Element/*!*/ element, IVariable/*!*/ variable) { - //Contract.Requires(variable != null); - //Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - return cce.NonNull((Elt)element).Remove(variable, this.microLattice); - } - - private delegate IExpr/*!*/ OnUnableToInline(IVariable/*!*/ var); - private IExpr/*!*/ IdentityVarToExpr(IVariable/*!*/ var) { - //Contract.Requires(var != null); - Contract.Ensures(Contract.Result() != null); - return var; - } - - /// - /// Return a new expression in which each variable has been - /// replaced by an expression representing what is known about - /// that variable. - /// - private IExpr/*!*/ InlineVariables(Elt/*!*/ element, IExpr/*!*/ expr, ISet/**//*!*/ notInlineable, - OnUnableToInline/*!*/ unableToInline) { - Contract.Requires(unableToInline != null); - Contract.Requires(notInlineable != null); - Contract.Requires(expr != null); - Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - IVariable var = expr as IVariable; - if (var != null) { - /*MicroLattice*/ - Element value = element[var]; - if (notInlineable.Contains(var) || value == null || this.microLattice.IsTop(value)) { - return unableToInline(var); // We don't know anything about this variable. - } else { - // GetFoldExpr returns null when it can yield an expression that - // can be substituted for the variable. - IExpr valueExpr = this.microLattice.GetFoldExpr(value); - return (valueExpr == null) ? var : valueExpr; - } - } - - // else - - IFunApp fun = expr as IFunApp; - if (fun != null) { - IList newargs = new ArrayList(); - foreach (IExpr/*!*/ arg in fun.Arguments) { - Contract.Assert(arg != null); - newargs.Add(InlineVariables(element, arg, notInlineable, unableToInline)); - } - return fun.CloneWithArguments(newargs); - } - - // else - - IFunction lambda = expr as IFunction; - if (lambda != null) { - IMutableSet x = new HashSet(1); - x.Add(lambda.Param); - - // Don't inline the bound variable - return lambda.CloneWithBody( - InlineVariables(element, lambda.Body, - cce.NonNull(Set.Union(notInlineable, x)), unableToInline) - ); - } - - // else - - if (expr is IUnknown) { - return expr; - } else { - throw - new System.NotImplementedException("cannot inline identifies in expression " + expr); - } - } - - - public override Element/*!*/ Constrain(Element/*!*/ element, IExpr/*!*/ expr) { - //Contract.Requires(expr != null); - //Contract.Requires(element != null); - //Contract.Ensures(Contract.Result() != null); - Elt/*!*/ result = (Elt)element; - Contract.Assert(result != null); - - if (IsBottom(element)) { - return result; // == element - } - - expr = InlineVariables(result, expr, cce.NonNull(Set.Empty), new OnUnableToInline(IdentityVarToExpr)); - - foreach (IExpr/*!*/ conjunct in FindConjuncts(expr)) { - Contract.Assert(conjunct != null); - IVariable left, right; - - if (IsSimpleEquality(conjunct, out left, out right)) { - #region The conjunct is a simple equality - - - Contract.Assert(left != null && right != null); - - Element leftValue = result[left], rightValue = result[right]; - if (leftValue == null) { - leftValue = this.microLattice.Top; - } - if (rightValue == null) { - rightValue = this.microLattice.Top; - } - Element newValue = this.microLattice.Meet(leftValue, rightValue); - result = AddConstraint(result, left, newValue); - result = AddConstraint(result, right, newValue); - - #endregion - } else { - ISet/**/ variablesInvolved = VariablesInExpression(conjunct, Set.Empty); - - if (variablesInvolved.Count == 1) { - #region We have just one variable - - IVariable var = null; - foreach (IVariable/*!*/ v in variablesInvolved) { - Contract.Assert(v != null); - var = v; - } // why is there no better way to get the elements? - Contract.Assert(var != null); - Element/*!*/ value = this.microLattice.EvaluatePredicate(conjunct); - result = AddConstraint(result, var, value); - - #endregion - } else if (IsArithmeticExpr(conjunct) && this.microLattice.UnderstandsBasicArithmetics) { - #region We evalaute an arithmetic expression - - IFunApp fun = (IFunApp)conjunct; - if (fun.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq)) // if it is a symbol of equality - { - // get the variable to be assigned - IExpr/*!*/ leftArg = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); - IExpr/*!*/ rightArg = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]); - IExpr/*!*/ var = (leftArg is IVariable) ? leftArg : rightArg; - - Element/*!*/ value = this.microLattice.EvaluatePredicateWithState(conjunct, result.Constraints); - Contract.Assert(value != null); - result = AddConstraint(result, (IVariable/*!*/)cce.NonNull(var), value); - } - #endregion - } - } - } - return result; - } - - - public override Element/*!*/ Rename(Element/*!*/ element, IVariable/*!*/ oldName, IVariable/*!*/ newName) { - //Contract.Requires(newName != null); - //Contract.Requires(oldName != null); - //Contract.Requires(element != null); - //Contract.Ensures(Contract.Result() != null); - if (IsBottom(element)) { - return element; - } else { - return ((Elt)element).Rename(oldName, newName, this.microLattice); - } - } - - - public override bool Understands(IFunctionSymbol/*!*/ f, IList/*!*/ args) { - //Contract.Requires(args != null); - //Contract.Requires(f != null); - return f.Equals(Prop.And) || - f.Equals(Value.Eq) || - microLattice.Understands(f, args); - } - - private sealed class EquivalentExprException : CheckedException { - } - private sealed class EquivalentExprInlineCallback { - private readonly IVariable/*!*/ var; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(var != null); - } - - public EquivalentExprInlineCallback(IVariable/*!*/ var) { - Contract.Requires(var != null); - this.var = var; - // base(); - } - - public IExpr/*!*/ ThrowOnUnableToInline(IVariable/*!*/ othervar) - //throws EquivalentExprException; - { - Contract.Requires(othervar != null); - Contract.Ensures(Contract.Result() != null); - Contract.EnsuresOnThrow(true); - if (othervar.Equals(var)) - throw new EquivalentExprException(); - else - return othervar; - } - } - - public override IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, ISet/**//*!*/ prohibitedVars) { - //Contract.Requires(prohibitedVars != null); - //Contract.Requires(var != null); - //Contract.Requires(expr != null); - //Contract.Requires(q != null); - //Contract.Requires(e != null); - try { - EquivalentExprInlineCallback closure = new EquivalentExprInlineCallback(var); - return InlineVariables((Elt)e, expr, cce.NonNull(Set.Empty), - new OnUnableToInline(closure.ThrowOnUnableToInline)); - } catch (EquivalentExprException) { - return null; - } - } - - - /// - /// Check to see if the given predicate holds in the given lattice element. - /// - /// TODO: We leave this unimplemented for now and just return maybe. - /// - /// The lattice element. - /// The predicate. - /// Yes, No, or Maybe - public override Answer CheckPredicate(Element/*!*/ e, IExpr/*!*/ pred) { - //Contract.Requires(pred != null); - //Contract.Requires(e != null); - return Answer.Maybe; - } - - /// - /// Answers a disequality about two variables. The same information could be obtained - /// by asking CheckPredicate, but a different implementation may be simpler and more - /// efficient. - /// - /// TODO: We leave this unimplemented for now and just return maybe. - /// - /// The lattice element. - /// The first variable. - /// The second variable. - /// Yes, No, or Maybe. - public override Answer CheckVariableDisequality(Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2) { - //Contract.Requires(var2 != null); - //Contract.Requires(var1 != null); - //Contract.Requires(e != null); - return Answer.Maybe; - } - - public override void Validate() { - base.Validate(); - microLattice.Validate(); - } - - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System.Diagnostics.Contracts; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + + using Microsoft.AbstractInterpretationFramework; + using Microsoft.AbstractInterpretationFramework.Collections; + + using Microsoft.Boogie; + + using IMutableSet = Microsoft.Boogie.GSet; + using ISet = Microsoft.Boogie.GSet; + using Set = Microsoft.Boogie.GSet; + using HashSet = Microsoft.Boogie.GSet; + + /// + /// Creates a lattice that works for several variables given a MicroLattice. Assumes + /// if one variable is bottom, then all variables are bottom. + /// + public class VariableMapLattice : Lattice { + private class Elt : Element { + /// + /// IsBottom(e) iff e.constraints == null + /// + /*MayBeNull*/ + private IFunctionalMap constraints; // of type IVariable -> LATTICE_ELEMENT + public IFunctionalMap Constraints { + get { + return this.constraints; + } + } + + private Elt(bool top) { + if (top) { + this.constraints = FunctionalHashtable.Empty; + } else { + this.constraints = null; + } + } + + public override Element/*!*/ Clone() { + Contract.Ensures(Contract.Result() != null); + return new Elt(this.constraints); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + if (constraints == null) { + return ""; + } + string s = "["; + string sep = ""; + foreach (IVariable/*!*/ v in cce.NonNull(constraints.Keys)) { + Contract.Assert(v != null); + Element m = (Element)constraints[v]; + s += sep + v.Name + " -> " + m; + sep = ", "; + } + return s + "]"; + } + + public static readonly Elt/*!*/ Top = new Elt(true); + public static readonly Elt/*!*/ Bottom = new Elt(false); + + + public Elt(IFunctionalMap constraints) { + this.constraints = constraints; + } + + public bool IsBottom { + get { + return this.constraints == null; + } + } + + public int Count { + get { + return this.constraints == null ? 0 : this.constraints.Count; + } + } + + public IEnumerable/**//*!*/ Variables { + get { + Contract.Requires(!this.IsBottom); + Contract.Ensures(Contract.Result() != null); + Contract.Assume(this.constraints != null); + return cce.NonNull(this.constraints.Keys); + } + } + + public IEnumerable/**//*!*/ SortedVariables(/*maybe null*/ IComparer variableComparer) { + Contract.Ensures(Contract.Result() != null); + if (variableComparer == null) { + return Variables; + } else { + ArrayList /*IVariable*/ vars = new ArrayList /*IVariable*/ (Count); + foreach (IVariable variable in Variables) { + vars.Add(variable); + } + vars.Sort(variableComparer); + return vars; + } + } + + public Element Lookup(IVariable v) { + if ((v == null) || (this.constraints == null)) { + return null; + } + return (Element)this.constraints[v]; + } + + public Element this[IVariable/*!*/ key] { + get { + Contract.Requires(!this.IsBottom); + Contract.Requires(key != null); + Contract.Assume(this.constraints != null); + return (Element)constraints[key]; + } + } + + /// + /// Add a new entry in the functional map: var --> value. + /// If the variable is already there, throws an exception + /// + public Elt/*!*/ Add(IVariable/*!*/ var, Element/*!*/ value, MicroLattice/*!*/ microLattice) { + Contract.Requires(microLattice != null); + Contract.Requires(value != null); + Contract.Requires(var != null); + Contract.Requires((!this.IsBottom)); + Contract.Ensures(Contract.Result() != null); + Contract.Assume(this.constraints != null); + Contract.Assert(!this.constraints.Contains(var)); + + if (microLattice.IsBottom(value)) { + return Bottom; + } + if (microLattice.IsTop(value)) { + return this.Remove(var, microLattice); + } + + return new Elt(this.constraints.Add(var, value)); + } + + /// + /// Set the value of the variable in the functional map + /// If the variable is not already there, throws an exception + /// + public Elt/*!*/ Set(IVariable/*!*/ var, Element/*!*/ value, MicroLattice/*!*/ microLattice) { + Contract.Requires(microLattice != null); + Contract.Requires(value != null); + Contract.Requires(var != null); + Contract.Ensures(Contract.Result() != null); + if (microLattice.IsBottom(value)) { + return Bottom; + } + if (microLattice.IsTop(value)) { + return this.Remove(var, microLattice); + } + + Contract.Assume(this.constraints != null); + Contract.Assert(this.constraints.Contains(var)); + + // this.constraints[var] = value; + IFunctionalMap newMap = this.constraints.Set(var, value); + + return new Elt(newMap); + } + + public Elt/*!*/ Remove(IVariable/*!*/ var, MicroLattice microLattice) { + Contract.Requires(var != null); + Contract.Ensures(Contract.Result() != null); + if (this.IsBottom) { + return this; + } + Contract.Assume(this.constraints != null); + return new Elt(this.constraints.Remove(var)); + } + + public Elt/*!*/ Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName, MicroLattice/*!*/ microLattice) { + Contract.Requires(microLattice != null); + Contract.Requires(newName != null); + Contract.Requires(oldName != null); + Contract.Requires((!this.IsBottom)); + Contract.Ensures(Contract.Result() != null); + Element value = this[oldName]; + if (value == null) { + return this; + } // 'oldName' isn't in the map, so neither will be 'newName' + Contract.Assume(this.constraints != null); + IFunctionalMap newMap = this.constraints.Remove(oldName); + newMap = newMap.Add(newName, value); + return new Elt(newMap); + } + + [Pure] + public override ICollection/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + throw new System.NotImplementedException(); + } + + } // class + + private readonly MicroLattice/*!*/ microLattice; + + private readonly IPropExprFactory/*!*/ propExprFactory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(microLattice != null); + Contract.Invariant(propExprFactory != null); + } + + + private readonly /*maybe null*/IComparer variableComparer; + + public VariableMapLattice(IPropExprFactory/*!*/ propExprFactory, IValueExprFactory/*!*/ valueExprFactory, MicroLattice/*!*/ microLattice, /*maybe null*/IComparer variableComparer) + : base(valueExprFactory) { + Contract.Requires(microLattice != null); + Contract.Requires(valueExprFactory != null); + Contract.Requires(propExprFactory != null); + this.propExprFactory = propExprFactory; + this.microLattice = microLattice; + this.variableComparer = variableComparer; + // base(valueExprFactory); + } + + protected override object/*!*/ UniqueId { + get { + Contract.Ensures(Contract.Result() != null); + return this.microLattice.GetType(); + } + } + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result() != null); + return Elt.Top; + } + } + + public override Element Bottom { + get { + Contract.Ensures(Contract.Result() != null); + return Elt.Bottom; + } + } + + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return !e.IsBottom && e.Count == 0; + } + + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + return ((Elt)element).IsBottom; + } + + protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + + // return true iff every constraint in "this" is no weaker than the corresponding + // constraint in "that" and there are no additional constraints in "that" + foreach (IVariable/*!*/ var in a.Variables) { + Contract.Assert(var != null); + Element thisValue = cce.NonNull(a[var]); + + Element thatValue = b[var]; + if (thatValue == null) { + continue; + } // it's okay for "a" to know something "b" doesn't + + if (this.microLattice.LowerThan(thisValue, thatValue)) { + continue; + } // constraint for "var" satisfies AtMost relation + + return false; + } + foreach (IVariable/*!*/ var in b.Variables) { + Contract.Assert(var != null); + if (a.Lookup(var) != null) { + continue; + } // we checked this case in the loop above + + Element thatValue = cce.NonNull(b[var]); + if (this.microLattice.IsTop(thatValue)) { + continue; + } // this is a trivial constraint + + return false; + } + return true; + } + + private Elt/*!*/ AddConstraint(Element/*!*/ element, IVariable/*!*/ var, /*MicroLattice*/Element/*!*/ newValue) { + Contract.Requires((newValue != null)); + Contract.Requires((var != null)); + Contract.Requires((element != null)); + Contract.Ensures(Contract.Result() != null); + Elt e = (Elt)element; + + if (!e.IsBottom && !this.microLattice.IsBottom(newValue)) // if we're not at bottom + { + /*MicroLattice*/ + Element currentValue = e[var]; + + if (currentValue == null) { + // No information currently, so we just add the new info. + return e.Add(var, newValue, this.microLattice); + } else { + // Otherwise, take the meet of the new and current info. + //return e.Add(var, this.microLattice.Meet(currentValue, newValue), this.microLattice); + return e.Set(var, this.microLattice.Meet(currentValue, newValue), this.microLattice); + } + } + return e; + } + + public override string/*!*/ ToString(Element/*!*/ element) { + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + Elt e = (Elt)element; + + if (IsTop(e)) { + return ""; + } + if (IsBottom(e)) { + return ""; + } + + int k = 0; + System.Text.StringBuilder buffer = new System.Text.StringBuilder(); + foreach (IVariable/*!*/ key in e.SortedVariables(variableComparer)) { + Contract.Assert(key != null); + if (k++ > 0) { + buffer.Append("; "); + } + buffer.AppendFormat("{0} = {1}", key, e[key]); + } + return buffer.ToString(); + } + + public override Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + + IFunctionalMap newMap = FunctionalHashtable.Empty; + foreach (IVariable/*!*/ key in a.Variables) { + Contract.Assert(key != null); + Element aValue = a[key]; + Element bValue = b[key]; + + if (aValue != null && bValue != null) { + // Keep only the variables known to both elements. + Element newValue = this.microLattice.Join(aValue, bValue); + newMap = newMap.Add(key, newValue); + } + } + Elt/*!*/ join = new Elt(newMap); + Contract.Assert(join != null); + + // System.Console.WriteLine("{0} join {1} = {2} ", this.ToString(a), ToString(b), ToString(join)); + + return join; + } + + public override Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + + IFunctionalMap newMap = FunctionalHashtable.Empty; + foreach (IVariable/*!*/ key in a.Variables) { + Contract.Assert(key != null); + Element/*!*/ aValue = cce.NonNull(a[key]); + Element bValue = b[key]; + + Element newValue = + bValue == null ? aValue : + this.microLattice.Meet(aValue, bValue); + + newMap = newMap.Add(key, newValue); + } + foreach (IVariable/*!*/ key in b.Variables) { + Contract.Assert(key != null); + Element aValue = a[key]; + Element bValue = b[key]; + Debug.Assert(bValue != null); + + if (aValue == null) { + // It's a variable we didn't cover in the last loop. + newMap = newMap.Add(key, bValue); + } + } + return new Elt(newMap); + } + + /// + /// Perform the pointwise widening of the elements in the map + /// + public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires((second != null)); + //Contract.Requires((first != null)); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + + // Note we have to add those cases as we do not have a "NonTrivialWiden" method + if (a.IsBottom) + return new Elt(b.Constraints); + if (b.IsBottom) + return new Elt(a.Constraints); + + IFunctionalMap newMap = FunctionalHashtable.Empty; + foreach (IVariable/*!*/ key in a.Variables) { + Contract.Assert(key != null); + Element aValue = a[key]; + Element bValue = b[key]; + + if (aValue != null && bValue != null) { + // Keep only the variables known to both elements. + Element newValue = this.microLattice.Widen(aValue, bValue); + newMap = newMap.Add(key, newValue); + } + } + Element/*!*/ widen = new Elt(newMap); + Contract.Assert(widen != null); + // System.Console.WriteLine("{0} widen {1} = {2} ", this.ToString(a), ToString(b), ToString(widen)); + + return widen; + } + + internal static ISet/**//*!*/ VariablesInExpression(IExpr/*!*/ e, ISet/**//*!*/ ignoreVars) { + Contract.Requires(ignoreVars != null); + Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + HashSet s = new HashSet(); + + IFunApp f = e as IFunApp; + IFunction lambda = e as IFunction; + + if (e is IVariable) { + if (!ignoreVars.Contains(e)) + s.Add(e); + } else if (f != null) // e is IFunApp + { + foreach (IExpr/*!*/ arg in f.Arguments) { + Contract.Assert(arg != null); + s.AddAll(VariablesInExpression(arg, ignoreVars)); + } + } else if (lambda != null) { + IMutableSet x = new HashSet(1); + x.Add(lambda.Param); + + // Ignore the bound variable + s.AddAll(VariablesInExpression(lambda.Body, cce.NonNull(Set.Union(ignoreVars, x)))); + } else if (e is IUnknown) { + // skip (actually, it would be appropriate to return the universal set of all variables) + } else { + Debug.Assert(false, "case not handled: " + e); + } + return s; + } + + + private static ArrayList/**//*!*/ FindConjuncts(IExpr e) { + Contract.Ensures(Contract.Result() != null); + ArrayList result = new ArrayList(); + + IFunApp f = e as IFunApp; + if (f != null) { + if (f.FunctionSymbol.Equals(Prop.And)) { + foreach (IExpr arg in f.Arguments) { + result.AddRange(FindConjuncts(arg)); + } + } else if (f.FunctionSymbol.Equals(Prop.Or) + || f.FunctionSymbol.Equals(Prop.Implies)) { + // Do nothing. + } else { + result.Add(e); + } + } else { + result.Add(e); + } + + return result; + } + + private static bool IsSimpleEquality(IExpr expr, out IVariable left, out IVariable right) { + Contract.Ensures(!Contract.Result() || Contract.ValueAtReturn(out left) != null && Contract.ValueAtReturn(out right) != null); + left = null; + right = null; + + // See if we have an equality + IFunApp nary = expr as IFunApp; + if (nary == null || !nary.FunctionSymbol.Equals(Value.Eq)) { + return false; + } + + // See if it is an equality of two variables + IVariable idLeft = nary.Arguments[0] as IVariable; + IVariable idRight = nary.Arguments[1] as IVariable; + if (idLeft == null || idRight == null) { + return false; + } + + left = idLeft; + right = idRight; + return true; + } + + /// + /// Returns true iff the expression is in the form var == arithmeticExpr + /// + private static bool IsArithmeticExpr(IExpr/*!*/ expr) { + Contract.Requires(expr != null); + // System.Console.WriteLine("\t\tIsArithmetic called with {0} of type {1}", expr, expr.GetType().ToString()); + + if (expr is IVariable) // expr is a variable + return true; + else if (expr is IFunApp) // may be ==, +, -, /, % or an integer + { + IFunApp fun = (IFunApp)expr; + + if (fun.FunctionSymbol is IntSymbol) // it is an integer + return true; + else if (fun.FunctionSymbol.Equals(Int.Negate)) // it is an unary minus + return IsArithmeticExpr((IExpr/*!*/)cce.NonNull(fun.Arguments[0])); + else if (fun.Arguments.Count != 2) // A function of two or more operands is not arithmetic + return false; + else { + IExpr/*!*/ left = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); + IExpr/*!*/ right = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]); + + if (!(left is IVariable || right is IVariable)) // At least one of the two operands must be a variable + return false; + + if (fun.FunctionSymbol.Equals(Value.Eq) + || fun.FunctionSymbol.Equals(Int.Add) + || fun.FunctionSymbol.Equals(Int.Sub) + || fun.FunctionSymbol.Equals(Int.Mul) + || fun.FunctionSymbol.Equals(Int.Div) + || fun.FunctionSymbol.Equals(Int.Mod)) + return IsArithmeticExpr(left) && IsArithmeticExpr(right); + else + return false; + } + } else { + return false; + } + } + + public override IExpr/*!*/ ToPredicate(Element/*!*/ element) { + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + if (IsTop(element)) { + return propExprFactory.True; + } + if (IsBottom(element)) { + return propExprFactory.False; + } + + Elt e = (Elt)element; + IExpr truth = propExprFactory.True; + IExpr result = truth; + + foreach (IVariable/*!*/ variable in e.SortedVariables(variableComparer)) { + Contract.Assert(variable != null); + Element value = (Element)e[variable]; + + if (value == null || this.microLattice.IsTop(value)) { + continue; + } // Skip variables about which we know nothing. + if (this.microLattice.IsBottom(value)) { + return propExprFactory.False; + } + + IExpr conjunct = this.microLattice.ToPredicate(variable, value); + + result = (result == truth) ? (IExpr)conjunct : (IExpr)propExprFactory.And(result, conjunct); + } + return result; + } + + + public override Element/*!*/ Eliminate(Element/*!*/ element, IVariable/*!*/ variable) { + //Contract.Requires(variable != null); + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + return cce.NonNull((Elt)element).Remove(variable, this.microLattice); + } + + private delegate IExpr/*!*/ OnUnableToInline(IVariable/*!*/ var); + private IExpr/*!*/ IdentityVarToExpr(IVariable/*!*/ var) { + //Contract.Requires(var != null); + Contract.Ensures(Contract.Result() != null); + return var; + } + + /// + /// Return a new expression in which each variable has been + /// replaced by an expression representing what is known about + /// that variable. + /// + private IExpr/*!*/ InlineVariables(Elt/*!*/ element, IExpr/*!*/ expr, ISet/**//*!*/ notInlineable, + OnUnableToInline/*!*/ unableToInline) { + Contract.Requires(unableToInline != null); + Contract.Requires(notInlineable != null); + Contract.Requires(expr != null); + Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + IVariable var = expr as IVariable; + if (var != null) { + /*MicroLattice*/ + Element value = element[var]; + if (notInlineable.Contains(var) || value == null || this.microLattice.IsTop(value)) { + return unableToInline(var); // We don't know anything about this variable. + } else { + // GetFoldExpr returns null when it can yield an expression that + // can be substituted for the variable. + IExpr valueExpr = this.microLattice.GetFoldExpr(value); + return (valueExpr == null) ? var : valueExpr; + } + } + + // else + + IFunApp fun = expr as IFunApp; + if (fun != null) { + IList newargs = new ArrayList(); + foreach (IExpr/*!*/ arg in fun.Arguments) { + Contract.Assert(arg != null); + newargs.Add(InlineVariables(element, arg, notInlineable, unableToInline)); + } + return fun.CloneWithArguments(newargs); + } + + // else + + IFunction lambda = expr as IFunction; + if (lambda != null) { + IMutableSet x = new HashSet(1); + x.Add(lambda.Param); + + // Don't inline the bound variable + return lambda.CloneWithBody( + InlineVariables(element, lambda.Body, + cce.NonNull(Set.Union(notInlineable, x)), unableToInline) + ); + } + + // else + + if (expr is IUnknown) { + return expr; + } else { + throw + new System.NotImplementedException("cannot inline identifies in expression " + expr); + } + } + + + public override Element/*!*/ Constrain(Element/*!*/ element, IExpr/*!*/ expr) { + //Contract.Requires(expr != null); + //Contract.Requires(element != null); + //Contract.Ensures(Contract.Result() != null); + Elt/*!*/ result = (Elt)element; + Contract.Assert(result != null); + + if (IsBottom(element)) { + return result; // == element + } + + expr = InlineVariables(result, expr, cce.NonNull(Set.Empty), new OnUnableToInline(IdentityVarToExpr)); + + foreach (IExpr/*!*/ conjunct in FindConjuncts(expr)) { + Contract.Assert(conjunct != null); + IVariable left, right; + + if (IsSimpleEquality(conjunct, out left, out right)) { + #region The conjunct is a simple equality + + + Contract.Assert(left != null && right != null); + + Element leftValue = result[left], rightValue = result[right]; + if (leftValue == null) { + leftValue = this.microLattice.Top; + } + if (rightValue == null) { + rightValue = this.microLattice.Top; + } + Element newValue = this.microLattice.Meet(leftValue, rightValue); + result = AddConstraint(result, left, newValue); + result = AddConstraint(result, right, newValue); + + #endregion + } else { + ISet/**/ variablesInvolved = VariablesInExpression(conjunct, Set.Empty); + + if (variablesInvolved.Count == 1) { + #region We have just one variable + + IVariable var = null; + foreach (IVariable/*!*/ v in variablesInvolved) { + Contract.Assert(v != null); + var = v; + } // why is there no better way to get the elements? + Contract.Assert(var != null); + Element/*!*/ value = this.microLattice.EvaluatePredicate(conjunct); + result = AddConstraint(result, var, value); + + #endregion + } else if (IsArithmeticExpr(conjunct) && this.microLattice.UnderstandsBasicArithmetics) { + #region We evalaute an arithmetic expression + + IFunApp fun = (IFunApp)conjunct; + if (fun.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq)) // if it is a symbol of equality + { + // get the variable to be assigned + IExpr/*!*/ leftArg = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); + IExpr/*!*/ rightArg = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]); + IExpr/*!*/ var = (leftArg is IVariable) ? leftArg : rightArg; + + Element/*!*/ value = this.microLattice.EvaluatePredicateWithState(conjunct, result.Constraints); + Contract.Assert(value != null); + result = AddConstraint(result, (IVariable/*!*/)cce.NonNull(var), value); + } + #endregion + } + } + } + return result; + } + + + public override Element/*!*/ Rename(Element/*!*/ element, IVariable/*!*/ oldName, IVariable/*!*/ newName) { + //Contract.Requires(newName != null); + //Contract.Requires(oldName != null); + //Contract.Requires(element != null); + //Contract.Ensures(Contract.Result() != null); + if (IsBottom(element)) { + return element; + } else { + return ((Elt)element).Rename(oldName, newName, this.microLattice); + } + } + + + public override bool Understands(IFunctionSymbol/*!*/ f, IList/*!*/ args) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + return f.Equals(Prop.And) || + f.Equals(Value.Eq) || + microLattice.Understands(f, args); + } + + private sealed class EquivalentExprException : CheckedException { + } + private sealed class EquivalentExprInlineCallback { + private readonly IVariable/*!*/ var; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(var != null); + } + + public EquivalentExprInlineCallback(IVariable/*!*/ var) { + Contract.Requires(var != null); + this.var = var; + // base(); + } + + public IExpr/*!*/ ThrowOnUnableToInline(IVariable/*!*/ othervar) + //throws EquivalentExprException; + { + Contract.Requires(othervar != null); + Contract.Ensures(Contract.Result() != null); + Contract.EnsuresOnThrow(true); + if (othervar.Equals(var)) + throw new EquivalentExprException(); + else + return othervar; + } + } + + public override IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, ISet/**//*!*/ prohibitedVars) { + //Contract.Requires(prohibitedVars != null); + //Contract.Requires(var != null); + //Contract.Requires(expr != null); + //Contract.Requires(q != null); + //Contract.Requires(e != null); + try { + EquivalentExprInlineCallback closure = new EquivalentExprInlineCallback(var); + return InlineVariables((Elt)e, expr, cce.NonNull(Set.Empty), + new OnUnableToInline(closure.ThrowOnUnableToInline)); + } catch (EquivalentExprException) { + return null; + } + } + + + /// + /// Check to see if the given predicate holds in the given lattice element. + /// + /// TODO: We leave this unimplemented for now and just return maybe. + /// + /// The lattice element. + /// The predicate. + /// Yes, No, or Maybe + public override Answer CheckPredicate(Element/*!*/ e, IExpr/*!*/ pred) { + //Contract.Requires(pred != null); + //Contract.Requires(e != null); + return Answer.Maybe; + } + + /// + /// Answers a disequality about two variables. The same information could be obtained + /// by asking CheckPredicate, but a different implementation may be simpler and more + /// efficient. + /// + /// TODO: We leave this unimplemented for now and just return maybe. + /// + /// The lattice element. + /// The first variable. + /// The second variable. + /// Yes, No, or Maybe. + public override Answer CheckVariableDisequality(Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2) { + //Contract.Requires(var2 != null); + //Contract.Requires(var1 != null); + //Contract.Requires(e != null); + return Answer.Maybe; + } + + public override void Validate() { + base.Validate(); + microLattice.Validate(); + } + + } +} diff --git a/Source/AIFramework/cce.cs b/Source/AIFramework/cce.cs index ef594484..1e0b12a5 100644 --- a/Source/AIFramework/cce.cs +++ b/Source/AIFramework/cce.cs @@ -1,193 +1,193 @@ -using System; -using SA=System.Attribute; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Text; -//using Microsoft.Boogie; - -/// -/// A class containing static methods to extend the functionality of Code Contracts -/// - -public static class cce { - //[Pure] - //public static bool NonNullElements(Microsoft.Dafny.Graph collection) { - // return collection != null && cce.NonNullElements(collection.TopologicallySortedComponents()); - //} - [Pure] - public static T NonNull(T t) { - Contract.Assert(t != null); - return t; - } - [Pure] - public static bool NonNullElements(IEnumerable collection) { - return collection != null && Contract.ForAll(collection, c => c != null); - } - [Pure] - public static bool NonNullElements(IDictionary collection) { - return collection != null && Contract.ForAll(collection, pair => NonNullElements(pair)); - } - //[Pure] - //public static bool NonNullElements(VariableSeq collection) { - // return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); - //} - /// - /// For possibly-null lists of non-null elements - /// - /// - /// - /// If true, the collection is treated as an IEnumerable<T!>?, rather than an IEnumerable<T!>! - /// - [Pure] - public static bool NonNullElements(IEnumerable collection, bool nullability) { - return (nullability && collection == null) || cce.NonNullElements(collection); - //Should be the same as: - /*if(nullability&&collection==null) - * return true; - * return cce.NonNullElements(collection) - */ - - } - [Pure] - public static bool NonNullElements(KeyValuePair kvp) { - return kvp.Key != null && kvp.Value != null; - } - [Pure] - public static bool NonNullElements(IEnumerator iEnumerator) { - return iEnumerator != null; - } - //[Pure] - //public static bool NonNullElements(Graphing.Graph graph) { - // return cce.NonNullElements(graph.TopologicalSort()); - //} - [Pure] - public static void BeginExpose(object o) { - } - [Pure] - public static void EndExpose() { - } - [Pure] - public static bool IsPeerConsistent(object o) { - return true; - } - [Pure] - public static bool IsConsistent(object o) { - return true; - } - [Pure] - public static bool IsExposable(object o) { - return true; - } - [Pure] - public static bool IsExposed(object o) { - return true; - } - [Pure] - public static bool IsNew(object o) { - return true; - } - public static class Owner { - [Pure] - public static bool Same(object o, object p) { - return true; - } - [Pure] - public static void AssignSame(object o, object p) { - } - [Pure] - public static object ElementProxy(object o) { - return o; - } - [Pure] - public static bool None(object o) { - return true; - } - [Pure] - public static bool Different(object o, object p) { - return true; - } - [Pure] - public static bool New(object o) { - return true; - } - } - [Pure] - public static void LoopInvariant(bool p) { - Contract.Assert(p); - } - public class UnreachableException : Exception { - public UnreachableException() { - } - } - //[Pure] - //public static bool IsValid(Microsoft.Dafny.Expression expression) { - // return true; - //} - //public static List toList(PureCollections.Sequence s) { - // List toRet = new List(); - // foreach (T t in s.elems) - // if(t!=null) - // toRet.Add(t); - // return toRet; - //} - - //internal static bool NonNullElements(Set set) { - // return set != null && Contract.ForAll(0,set.Count, i => set[i] != null); - //} -} - -public class PeerAttribute : SA { -} -public class RepAttribute : SA { -} -public class CapturedAttribute : SA { -} -public class NotDelayedAttribute : SA { -} -public class NoDefaultContractAttribute : SA { -} -public class VerifyAttribute : SA { - public VerifyAttribute(bool b) { - - } -} -public class StrictReadonlyAttribute : SA { -} -public class AdditiveAttribute : SA { -} -public class ReadsAttribute : SA { - public enum Reads { - Nothing, - Everything, - }; - public ReadsAttribute(object o) { - } -} -public class GlobalAccessAttribute : SA { - public GlobalAccessAttribute(bool b) { - } -} -public class EscapesAttribute : SA { - public EscapesAttribute(bool b, bool b_2) { - } -} -public class NeedsContractsAttribute : SA { - public NeedsContractsAttribute() { - } - public NeedsContractsAttribute(bool ret, bool parameters) { - } - public NeedsContractsAttribute(bool ret, int[] parameters) { - } -} -public class ImmutableAttribute : SA { -} -public class InsideAttribute : SA { -} -public class SpecPublicAttribute : SA { -} -public class ElementsPeerAttribute : SA { -} -public class ResultNotNewlyAllocatedAttribute : SA { -} -public class OnceAttribute : SA { +using System; +using SA=System.Attribute; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Text; +//using Microsoft.Boogie; + +/// +/// A class containing static methods to extend the functionality of Code Contracts +/// + +public static class cce { + //[Pure] + //public static bool NonNullElements(Microsoft.Dafny.Graph collection) { + // return collection != null && cce.NonNullElements(collection.TopologicallySortedComponents()); + //} + [Pure] + public static T NonNull(T t) { + Contract.Assert(t != null); + return t; + } + [Pure] + public static bool NonNullElements(IEnumerable collection) { + return collection != null && Contract.ForAll(collection, c => c != null); + } + [Pure] + public static bool NonNullElements(IDictionary collection) { + return collection != null && Contract.ForAll(collection, pair => NonNullElements(pair)); + } + //[Pure] + //public static bool NonNullElements(VariableSeq collection) { + // return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); + //} + /// + /// For possibly-null lists of non-null elements + /// + /// + /// + /// If true, the collection is treated as an IEnumerable<T!>?, rather than an IEnumerable<T!>! + /// + [Pure] + public static bool NonNullElements(IEnumerable collection, bool nullability) { + return (nullability && collection == null) || cce.NonNullElements(collection); + //Should be the same as: + /*if(nullability&&collection==null) + * return true; + * return cce.NonNullElements(collection) + */ + + } + [Pure] + public static bool NonNullElements(KeyValuePair kvp) { + return kvp.Key != null && kvp.Value != null; + } + [Pure] + public static bool NonNullElements(IEnumerator iEnumerator) { + return iEnumerator != null; + } + //[Pure] + //public static bool NonNullElements(Graphing.Graph graph) { + // return cce.NonNullElements(graph.TopologicalSort()); + //} + [Pure] + public static void BeginExpose(object o) { + } + [Pure] + public static void EndExpose() { + } + [Pure] + public static bool IsPeerConsistent(object o) { + return true; + } + [Pure] + public static bool IsConsistent(object o) { + return true; + } + [Pure] + public static bool IsExposable(object o) { + return true; + } + [Pure] + public static bool IsExposed(object o) { + return true; + } + [Pure] + public static bool IsNew(object o) { + return true; + } + public static class Owner { + [Pure] + public static bool Same(object o, object p) { + return true; + } + [Pure] + public static void AssignSame(object o, object p) { + } + [Pure] + public static object ElementProxy(object o) { + return o; + } + [Pure] + public static bool None(object o) { + return true; + } + [Pure] + public static bool Different(object o, object p) { + return true; + } + [Pure] + public static bool New(object o) { + return true; + } + } + [Pure] + public static void LoopInvariant(bool p) { + Contract.Assert(p); + } + public class UnreachableException : Exception { + public UnreachableException() { + } + } + //[Pure] + //public static bool IsValid(Microsoft.Dafny.Expression expression) { + // return true; + //} + //public static List toList(PureCollections.Sequence s) { + // List toRet = new List(); + // foreach (T t in s.elems) + // if(t!=null) + // toRet.Add(t); + // return toRet; + //} + + //internal static bool NonNullElements(Set set) { + // return set != null && Contract.ForAll(0,set.Count, i => set[i] != null); + //} +} + +public class PeerAttribute : SA { +} +public class RepAttribute : SA { +} +public class CapturedAttribute : SA { +} +public class NotDelayedAttribute : SA { +} +public class NoDefaultContractAttribute : SA { +} +public class VerifyAttribute : SA { + public VerifyAttribute(bool b) { + + } +} +public class StrictReadonlyAttribute : SA { +} +public class AdditiveAttribute : SA { +} +public class ReadsAttribute : SA { + public enum Reads { + Nothing, + Everything, + }; + public ReadsAttribute(object o) { + } +} +public class GlobalAccessAttribute : SA { + public GlobalAccessAttribute(bool b) { + } +} +public class EscapesAttribute : SA { + public EscapesAttribute(bool b, bool b_2) { + } +} +public class NeedsContractsAttribute : SA { + public NeedsContractsAttribute() { + } + public NeedsContractsAttribute(bool ret, bool parameters) { + } + public NeedsContractsAttribute(bool ret, int[] parameters) { + } +} +public class ImmutableAttribute : SA { +} +public class InsideAttribute : SA { +} +public class SpecPublicAttribute : SA { +} +public class ElementsPeerAttribute : SA { +} +public class ResultNotNewlyAllocatedAttribute : SA { +} +public class OnceAttribute : SA { } \ No newline at end of file diff --git a/Source/AbsInt/AbsInt.csproj b/Source/AbsInt/AbsInt.csproj index 69a2667c..359eb146 100644 --- a/Source/AbsInt/AbsInt.csproj +++ b/Source/AbsInt/AbsInt.csproj @@ -1,296 +1,296 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F} - Library - Properties - AbsInt - AbsInt - v4.0 - 512 - 1 - true - ..\InterimKey.snk - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - Client - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - False - False - True - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - - - - - - - Full - %28none%29 - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - true - bin\z3apidebug\ - DEBUG;TRACE - full - AnyCPU - - - true - GlobalSuppressions.cs - prompt - Migrated rules for AbsInt.ruleset - true - 4 - false - - - true - bin\Checked\ - DEBUG;TRACE - full - AnyCPU - bin\Debug\AbsInt.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - true - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - true - false - True - False - True - False - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - False - Full - Build - 0 - 4 - false - - - true - bin\x86\Debug\ - DEBUG;TRACE - full - x86 - bin\Debug\AbsInt.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - true - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - true - 4 - false - - - bin\x86\Release\ - TRACE - true - pdbonly - x86 - bin\Release\AbsInt.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - true - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - true - 4 - - - true - bin\x86\z3apidebug\ - DEBUG;TRACE - full - x86 - bin\z3apidebug\AbsInt.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - Migrated rules for AbsInt.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - false - true - 4 - false - - - true - bin\x86\Checked\ - DEBUG;TRACE - full - x86 - bin\Debug\AbsInt.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - 4 - false - - - true - bin\QED\ - DEBUG;TRACE - full - AnyCPU - prompt - AllRules.ruleset - - - true - bin\QED\ - DEBUG;TRACE - full - AnyCPU - prompt - AllRules.ruleset - - - - - 3.5 - - - - - - - - - - - - - - - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} - Basetypes - - - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} - CodeContractsExtender - - - {B230A69C-C466-4065-B9C1-84D80E76D802} - Core - - - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5} - ParserHelper - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - + + + + Debug + AnyCPU + 9.0.21022 + 2.0 + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F} + Library + Properties + AbsInt + BoogieAbsInt + v4.0 + 512 + 1 + true + ..\InterimKey.snk + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + False + False + True + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + + + + + + + Full + %28none%29 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + true + bin\z3apidebug\ + DEBUG;TRACE + full + AnyCPU + + + true + GlobalSuppressions.cs + prompt + Migrated rules for AbsInt.ruleset + true + 4 + false + + + true + bin\Checked\ + DEBUG;TRACE + full + AnyCPU + bin\Debug\AbsInt.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + true + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + true + false + True + False + True + False + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + False + Full + Build + 0 + 4 + false + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + bin\Debug\AbsInt.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + true + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + true + 4 + false + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + bin\Release\AbsInt.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + true + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + true + 4 + + + true + bin\x86\z3apidebug\ + DEBUG;TRACE + full + x86 + bin\z3apidebug\AbsInt.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + Migrated rules for AbsInt.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + false + true + 4 + false + + + true + bin\x86\Checked\ + DEBUG;TRACE + full + x86 + bin\Debug\AbsInt.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + 4 + false + + + true + bin\QED\ + DEBUG;TRACE + full + AnyCPU + prompt + AllRules.ruleset + + + true + bin\QED\ + DEBUG;TRACE + full + AnyCPU + prompt + AllRules.ruleset + + + + + 3.5 + + + + + + + + + + + + + + + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} + Basetypes + + + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} + CodeContractsExtender + + + {B230A69C-C466-4065-B9C1-84D80E76D802} + Core + + + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5} + ParserHelper + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + \ No newline at end of file diff --git a/Source/AbsInt/IntervalDomain.cs b/Source/AbsInt/IntervalDomain.cs index d5a5efc9..0dd78cbb 100644 --- a/Source/AbsInt/IntervalDomain.cs +++ b/Source/AbsInt/IntervalDomain.cs @@ -1,1210 +1,1218 @@ -using System; -using System.Numerics; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using Microsoft.Basetypes; - -namespace Microsoft.Boogie.AbstractInterpretation -{ - class NativeIntervallDomain : NativeLattice - { - abstract class E_Common : NativeLattice.Element { } - class E_Bottom : E_Common - { - public override Expr ToExpr() { - return Expr.False; - } - } - class E : E_Common - { - public readonly Node N; - public E() { } - public E(Node n) { - N = n; - } - - public override Expr ToExpr() { - Expr expr = Expr.True; - for (var n = N; n != null; n = n.Next) { - expr = BplAnd(expr, n.ToExpr()); - } - return expr; - } - } - public class Node - { - public readonly Variable V; // variable has type bool or int - // For an integer variable (Lo,Hi) indicates Lo <= V < Hi, where Lo==null means no lower bound and Hi==null means no upper bound. - // For a real variable (Lo,Hi) indicates Lo <= V <= Hi, where Lo==null means no lower bound and Hi==null means no upper bound. - // For a boolean variable, (Lo,Hi) is one of: (null,null) for {false,true}, (null,1) for {false}, and (1,null) for {true}. - public readonly BigInteger? Lo; - public readonly BigInteger? Hi; - public Node Next; // always sorted according to StrictlyBefore; readonly after full initialization - [Pure] - public static bool StrictlyBefore(Variable a, Variable b) { - Contract.Assert(a.UniqueId != b.UniqueId || a == b); - return a.UniqueId < b.UniqueId; - } - - Node(Variable v, BigInteger? lo, BigInteger? hi, Node next) { - Contract.Requires(lo != null || hi != null); // don't accept empty constraints - Contract.Requires(next == null || StrictlyBefore(v, next.V)); - V = v; - Lo = lo; - Hi = hi; - Next = next; - } - - /// - /// This constructor leaves Next as null, allowing the caller to fill in Next to finish off the construction. - /// - public Node(Variable v, BigInteger? lo, BigInteger? hi) { - Contract.Requires(lo != null || hi != null); // don't accept empty constraints - V = v; - Lo = lo; - Hi = hi; - } - - /// - /// Returns a Node that has the constraints head.{V,Lo,Hi} plus - /// all the constraints entailed by Nodes reachable from tail. - /// Requires that "head" sorts no later than anything in "tail". - /// Create either returns "head" itself or returns a new Node. - /// - public static Node Create(Node head, Node tail) { - Contract.Requires(head != null); - Contract.Requires(tail == null || !StrictlyBefore(tail.V, head.V)); - Contract.Requires(head != tail); - - if (head.Next == tail) { - return head; - } else if (tail != null && head.V == tail.V) { - // incorporate both constraints into one Node - return new Node(head.V, Max(head.Lo, tail.Lo, true), Min(head.Lo, tail.Lo, true), tail.Next); - } else { - return new Node(head.V, head.Lo, head.Hi, tail); - } - } - - public static void GetBounds(Node n, Variable v, out BigInteger? lo, out BigInteger? hi) { - for (; n != null; n = n.Next) { - if (n.V == v) { - lo = n.Lo; - hi = n.Hi; - return; - } else if (StrictlyBefore(v, n.V)) { - break; - } - } - lo = null; - hi = null; - } - - /// - /// Return the minimum of "a" and "b". If treatNullAsUnit==true, then "null" is - /// interpreted as positive infinity (the unit element of min); otherwise, it is - /// treated as negative infinity (the zero element of min). - /// - public static BigInteger? Min(BigInteger? a, BigInteger? b, bool treatNullAsUnit) { - if (a == null) { - return treatNullAsUnit ? b : a; - } else if (b == null) { - return treatNullAsUnit ? a : b; - } else { - return BigInteger.Min((BigInteger)a, (BigInteger)b); - } - } - - /// - /// Return the maximum of "a" and "b". If treatNullAsUnit==true, then "null" is - /// interpreted as negative infinity (the unit element of max); otherwise, it is - /// treated as positive infinity (the zero element of max). - /// - public static BigInteger? Max(BigInteger? a, BigInteger? b, bool treatNullAsUnit) { - if (a == null) { - return treatNullAsUnit ? b : a; - } else if (b == null) { - return treatNullAsUnit ? a : b; - } else { - return BigInteger.Max((BigInteger)a, (BigInteger)b); - } - } - - public static IEnumerable> Merge(Node a, Node b) { - while (true) { - if (a == null && b == null) { - yield break; - } else if (a == null || b == null) { - yield return new Tuple(a, b); - if (a != null) { a = a.Next; } else { b = b.Next; } - } else if (a.V == b.V) { - yield return new Tuple(a, b); - a = a.Next; b = b.Next; - } else if (StrictlyBefore(a.V, b.V)) { - yield return new Tuple(a, null); - a = a.Next; - } else { - yield return new Tuple(null, b); - b = b.Next; - } - } - } - - public Expr ToExpr() { - if (!V.IsMutable && CommandLineOptions.Clo.InstrumentInfer != CommandLineOptions.InstrumentationPlaces.Everywhere) { - // omit invariants about readonly variables - return Expr.True; - } else if (V.TypedIdent.Type.IsBool) { - if (Lo == null && Hi == null) { - return Expr.True; - } else { - Contract.Assert((Lo == null && (BigInteger)Hi == 1) || (Hi == null && (BigInteger)Lo == 1)); - var ide = new IdentifierExpr(Token.NoToken, V); - return Hi == null ? ide : Expr.Not(ide); - } - } else if (V.TypedIdent.Type.IsInt) { - Expr e = Expr.True; - if (Lo != null && Hi != null && Lo + 1 == Hi) { - // produce an equality - var ide = new IdentifierExpr(Token.NoToken, V); - e = Expr.And(e, BplEq(ide, NumberToExpr((BigInteger)Lo, V.TypedIdent.Type))); - } else { - // produce a (possibly empty) conjunction of inequalities - if (Lo != null) { - var ide = new IdentifierExpr(Token.NoToken, V); - e = Expr.And(e, BplLe(NumberToExpr((BigInteger)Lo, V.TypedIdent.Type), ide)); - } - if (Hi != null) { - var ide = new IdentifierExpr(Token.NoToken, V); - e = Expr.And(e, BplLt(ide, NumberToExpr((BigInteger)Hi, V.TypedIdent.Type))); - } - } - return e; - } else if (V.TypedIdent.Type.IsReal){ - Expr e = Expr.True; - if (Lo != null && Hi != null && Lo == Hi) { - // produce an equality - var ide = new IdentifierExpr(Token.NoToken, V); - e = Expr.And(e, BplEq(ide, NumberToExpr((BigInteger)Lo, V.TypedIdent.Type))); - } else { - // produce a (possibly empty) conjunction of inequalities - if (Lo != null) { - var ide = new IdentifierExpr(Token.NoToken, V); - e = Expr.And(e, BplLe(NumberToExpr((BigInteger)Lo, V.TypedIdent.Type), ide)); - } - if (Hi != null) { - var ide = new IdentifierExpr(Token.NoToken, V); - e = Expr.And(e, BplLe(ide, NumberToExpr((BigInteger)Hi, V.TypedIdent.Type))); - } - } - return e; - } else { - Contract.Assert(V.TypedIdent.Type.IsFloat); - Expr e = Expr.True; - if (Lo != null && Hi != null && Lo == Hi) - { - // produce an equality - var ide = new IdentifierExpr(Token.NoToken, V); - e = Expr.And(e, BplEq(ide, NumberToExpr((BigInteger)Lo, V.TypedIdent.Type))); - } - else - { - // produce a (possibly empty) conjunction of inequalities - if (Lo != null) - { - var ide = new IdentifierExpr(Token.NoToken, V); - e = Expr.And(e, BplLe(NumberToExpr((BigInteger)Lo, V.TypedIdent.Type), ide)); - } - if (Hi != null) - { - var ide = new IdentifierExpr(Token.NoToken, V); - e = Expr.And(e, BplLe(ide, NumberToExpr((BigInteger)Hi, V.TypedIdent.Type))); - } - } - return e; - } - } - } - - static Expr NumberToExpr(BigInteger n, Type ty) { - if (n == null) { - return null; - } else if (ty.IsReal) { - return Expr.Literal(Basetypes.BigDec.FromBigInt(n)); - } else if (ty.IsFloat) { - return Expr.Literal(Basetypes.BigFloat.FromBigInt(n, ty.FloatExponent, ty.FloatMantissa)); - } else { - Contract.Assume(ty.IsInt); - return Expr.Literal(Basetypes.BigNum.FromBigInt(n)); - } - } - - List upThresholds; // invariant: thresholds are sorted - List downThresholds; // invariant: thresholds are sorted - - /// - /// Requires "thresholds" to be sorted. - /// - public NativeIntervallDomain() { - upThresholds = new List(); - downThresholds = new List(); - } - - public override void Specialize(Implementation impl) { - if (impl == null) { - // remove thresholds - upThresholds = new List(); - downThresholds = new List(); - } else { - var tf = new ThresholdFinder(impl); - tf.Find(out downThresholds, out upThresholds); -#if DEBUG_PRINT - Console.Write("DEBUG: for implementation '{0}', setting downs to [", impl.Name); - foreach (var i in downThresholds) { - Console.Write(" {0}", i); - } - Console.Write(" ] and ups to ["); - foreach (var i in upThresholds) { - Console.Write(" {0}", i); - } - Console.WriteLine(" ]"); -#endif - } - base.Specialize(impl); - } - - private E_Common top = new E(); - private E_Common bottom = new E_Bottom(); - - public override Element Top { get { return top; } } - public override Element Bottom { get { return bottom; } } - - public override bool IsTop(Element element) { - var e = element as E; - return e != null && e.N == null; - } - public override bool IsBottom(Element element) { - return element is E_Bottom; - } - - public override bool Below(Element a, Element b) { - if (a is E_Bottom) { - return true; - } else if (b is E_Bottom) { - return false; - } else { - var aa = (E)a; - var bb = (E)b; - // check if every constraint in 'bb' is implied by constraints in 'aa' - foreach (var t in Node.Merge(aa.N, bb.N)) { - var x = t.Item1; - var y = t.Item2; - if (x == null) { - // bb constrains a variable that aa does not - return false; - } else if (y == null) { - // aa constrains a variable that bb does not; that's fine - } else if (y.Lo != null && (x.Lo == null || x.Lo < y.Lo)) { - // bb has a Lo constraint, and either aa has no Lo constraint or it has a weaker Lo constraint - return false; - } else if (y.Hi != null && (x.Hi == null || y.Hi < x.Hi)) { - // bb has a Hi o constraint, and either aa has no Hi constraint or it has a weaker Hi constraint - return false; - } - } - return true; - } - } - - public override Element Meet(Element a, Element b) { - if (a is E_Bottom) { - return a; - } else if (b is E_Bottom) { - return b; - } else { - var aa = (E)a; - var bb = (E)b; - Node head = null; - Node prev = null; - foreach (var t in Node.Merge(aa.N, bb.N)) { - var x = t.Item1; - var y = t.Item2; - Node n; - if (x == null) { - n = new Node(y.V, y.Lo, y.Hi); - } else if (y == null) { - n = new Node(x.V, x.Lo, x.Hi); - } else { - var lo = Node.Max(x.Lo, y.Lo, true); - var hi = Node.Min(x.Hi, y.Hi, true); - // if hi<=lo (or hi - /// For a proof of correctness of this method, see Test/dafny2/Intervals.dfy. - /// A difference is that the this method returns: - /// let d = Dafny_RoundDown(k); - /// return d == -1 ? null : downThresholds[d]; - /// - BigInteger? RoundDown(BigInteger k) - { - if (downThresholds.Count == 0 || k < downThresholds[0]) { - return null; - } - var i = 0; - var j = downThresholds.Count - 1; - while (i < j) - { - var mid = i + (j - i + 1) / 2; - if (downThresholds[mid] <= k) { - i = mid; - } else { - j = mid - 1; - } - } - return downThresholds[i]; - } - - /// - /// For a proof of correctness of this method, see Test/dafny2/Intervals.dfy. - /// A difference is that the this method returns: - /// let d = Dafny_RoundUp(k); - /// return d == thresholds.Count ? null : upThresholds[d]; - /// - BigInteger? RoundUp(BigInteger k) - { - if (upThresholds.Count == 0 || upThresholds[upThresholds.Count - 1] < k) { - return null; - } - var i = 0; - var j = upThresholds.Count - 1; - while (i < j) - { - var mid = i + (j - i) / 2; - if (upThresholds[mid] < k) { - i = mid + 1; - } else { - j = mid; - } - } - return upThresholds[i]; - } - - public override Element Constrain(Element element, Expr expr) { - if (element is E_Bottom) { - return element; - } else { - var e = (E)element; - var c = Constraint(expr, e.N); - return c == null ? element : Meet(element, c); - } - } - - /// - /// Returns an Element that corresponds to the constraints implied by "expr" in the - /// state "state". - /// Return "null" to indicate no constraints. - /// - E_Common Constraint(Expr expr, Node state) { - Variable v; - if (IsVariable(expr, out v)) { - var n = new Node(v, BigInteger.One, null); - return new E(n); - } else if (expr is LiteralExpr) { - var e = (LiteralExpr)expr; - return (bool)e.Val ? null : new E_Bottom(); - } else if (expr is NAryExpr) { - var e = (NAryExpr)expr; - if (e.Fun is UnaryOperator) { - if (((UnaryOperator)e.Fun).Op == UnaryOperator.Opcode.Not) { - if (IsVariable(e.Args[0], out v)) { - var n = new Node(v, null, BigInteger.One); - return new E(n); - } - } - } else if (e.Fun is BinaryOperator) { - var op = ((BinaryOperator)e.Fun).Op; - var arg0 = e.Args[0]; - var arg1 = e.Args[1]; - switch (op) { - case BinaryOperator.Opcode.Eq: - case BinaryOperator.Opcode.Iff: { - E_Common c = null; - if (IsVariable(arg0, out v)) { - BigInteger? lo, hi; - if (PartiallyEvaluate(arg1, state, out lo, out hi)) { - var n = new Node(v, lo, hi); - c = new E(n); - } - } - if (IsVariable(arg1, out v)) { - BigInteger? lo, hi; - if (PartiallyEvaluate(arg1, state, out lo, out hi)) { - var n = new Node(v, lo, hi); - c = c == null ? new E(n) : (E_Common)Meet(c, new E(n)); - } - } - return c; - } - case BinaryOperator.Opcode.Neq: { - E_Common c = null; - if (IsVariable(arg0, out v)) { - c = ConstrainNeq(state, v, arg1); - } - if (IsVariable(arg1, out v)) { - var cc = ConstrainNeq(state, v, arg0); - if (cc != null) { - c = c == null ? cc : (E_Common)Meet(c, cc); - } - } - return c; - } - case BinaryOperator.Opcode.Le: { - E_Common c = null; - if (IsVariable(arg1, out v)) { - BigInteger? lo, hi; - PartiallyEvaluate(arg0, state, out lo, out hi); - if (lo != null) { - var n = new Node(v, lo, null); - c = new E(n); - } - } - if (IsVariable(arg0, out v)) { - BigInteger? lo, hi; - PartiallyEvaluate(arg1, state, out lo, out hi); - if (hi != null) { - var n = new Node(v, null, hi); - c = c == null ? new E(n) : (E_Common)Meet(c, new E(n)); - } - } - return c; - } - case BinaryOperator.Opcode.Lt: { - E_Common c = null; - if (IsVariable(arg1, out v)) { - BigInteger? lo, hi; - PartiallyEvaluate(arg0, state, out lo, out hi); - if (lo != null) { - var n = new Node(v, v.TypedIdent.Type.IsReal ? lo : lo + 1, null); - c = new E(n); - } - } - if (IsVariable(arg0, out v)) { - BigInteger? lo, hi; - PartiallyEvaluate(arg1, state, out lo, out hi); - if (hi != null) { - var n = new Node(v, null, v.TypedIdent.Type.IsReal ? hi : hi - 1); - c = c == null ? new E(n) : (E_Common)Meet(c, new E(n)); - } - } - return c; - } - case BinaryOperator.Opcode.Ge: { - var tmp = arg0; arg0 = arg1; arg1 = tmp; - goto case BinaryOperator.Opcode.Le; - } - case BinaryOperator.Opcode.Gt: { - var tmp = arg0; arg0 = arg1; arg1 = tmp; - goto case BinaryOperator.Opcode.Lt; - } - default: - break; - } - } - } - return null; // approximation - } - - private E ConstrainNeq(Node state, Variable v, Expr arg) { - BigInteger? lo, hi; - if (PartiallyEvaluate(arg, state, out lo, out hi)) { - if (!v.TypedIdent.Type.IsReal && lo != null && hi != null && lo + 1 == hi) { - var exclude = lo; - // If the partially evaluated arg (whose value is "exclude") is an end-point of - // the interval known for "v", then produce a constraint that excludes that bound. - Node.GetBounds(state, v, out lo, out hi); - if (lo != null && lo == exclude) { - var n = new Node(v, lo + 1, null); - return new E(n); - } else if (hi != null && exclude + 1 == hi) { - var n = new Node(v, null, exclude); - return new E(n); - } - } - } - return null; - } - - bool IsVariable(Expr expr, out Variable v) { - var e = expr as IdentifierExpr; - if (e == null) { - v = null; - return false; - } else { - v = e.Decl; - return true; - } - } - - public override Element Update(Element element, AssignCmd cmd) { - if (element is E_Bottom) { - return element; - } - var e = (E)element; - var nn = e.N; - Contract.Assert(cmd.Lhss.Count == cmd.Rhss.Count); - for (int i = 0; i < cmd.Lhss.Count; i++) { - var lhs = cmd.Lhss[i]; - var rhs = cmd.Rhss[i]; - BigInteger? lo; - BigInteger? hi; - PartiallyEvaluate(rhs, e.N, out lo, out hi); - nn = UpdateOne(nn, lhs.DeepAssignedVariable, lo, hi); - } - return new E(nn); - } - - bool PartiallyEvaluate(Expr rhs, Node node, out BigInteger? lo, out BigInteger? hi) { - var pe = new PEVisitor(node); - pe.VisitExpr(rhs); - lo = pe.Lo; - hi = pe.Hi; - return lo != null || hi != null; - } - - class PEVisitor : ReadOnlyVisitor - { - public BigInteger? Lo; - public BigInteger? Hi; - - readonly BigInteger one = BigInteger.One; - - Node N; - public PEVisitor(Node n) { - N = n; - } - - // Override visitors for all expressions that can return a boolean, integer, or real result - - public override Expr VisitExpr(Expr node) { - Lo = Hi = null; - return base.VisitExpr(node); - } - public override Expr VisitLiteralExpr(LiteralExpr node) { - if (node.Val is BigNum) { - var n = ((BigNum)node.Val).ToBigInteger; - Lo = n; - Hi = n + 1; - } else if (node.Val is BigDec) { - BigInteger floor, ceiling; - ((BigDec)node.Val).FloorCeiling(out floor, out ceiling); - Lo = floor; - Hi = ceiling; - } else if (node.Val is BigFloat) { - BigNum floor, ceiling; - ((BigFloat)node.Val).FloorCeiling(out floor, out ceiling); - Lo = floor.ToBigInteger; - Hi = ceiling.ToBigInteger; - } else if (node.Val is bool) { - if ((bool)node.Val) { - // true - Lo = one; - Hi = null; - } else { - // false - Lo = null; - Hi = one; - } - } - return node; - } - public override Expr VisitIdentifierExpr(IdentifierExpr node) { - if (node.Type.IsBool || node.Type.IsInt || node.Type.IsReal) { - Node.GetBounds(N, node.Decl, out Lo, out Hi); - } - return node; - } - public override Expr VisitNAryExpr(NAryExpr node) { - if (node.Fun is UnaryOperator) { - var op = (UnaryOperator)node.Fun; - Contract.Assert(node.Args.Count == 1); - if (op.Op == UnaryOperator.Opcode.Neg) { - BigInteger? lo, hi; - VisitExpr(node.Args[0]); - lo = Lo; hi = Hi; - if (hi != null) { - Lo = node.Type.IsReal ? -hi : 1 - hi; - } - if (lo != null) { - Hi = node.Type.IsReal ? -lo : 1 - lo; - } - } - else if (op.Op == UnaryOperator.Opcode.Not) { - VisitExpr(node.Args[0]); - Contract.Assert((Lo == null && Hi == null) || - (Lo == null && (BigInteger)Hi == 1) || - (Hi == null && (BigInteger)Lo == 1)); - var tmp = Lo; - Lo = Hi; - Hi = tmp; - } - } else if (node.Fun is BinaryOperator) { - var op = (BinaryOperator)node.Fun; - Contract.Assert(node.Args.Count == 2); - BigInteger? lo0, hi0, lo1, hi1; - VisitExpr(node.Args[0]); - lo0 = Lo; hi0 = Hi; - VisitExpr(node.Args[1]); - lo1 = Lo; hi1 = Hi; - Lo = Hi = null; - var isReal = node.Args[0].Type.IsReal; - switch (op.Op) { - case BinaryOperator.Opcode.And: - if (hi0 != null || hi1 != null) { - // one operand is definitely false, thus so is the result - Lo = null; Hi = one; - } else if (lo0 != null && lo1 != null) { - // both operands are definitely true, thus so is the result - Lo = one; Hi = null; - } - break; - case BinaryOperator.Opcode.Or: - if (lo0 != null || lo1 != null) { - // one operand is definitely true, thus so is the result - Lo = one; Hi = null; - } else if (hi0 != null && hi1 != null) { - // both operands are definitely false, thus so is the result - Lo = null; Hi = one; - } - break; - case BinaryOperator.Opcode.Imp: - if (hi0 != null || lo1 != null) { - // either arg0 false or arg1 is true, so the result is true - Lo = one; Hi = null; - } else if (lo0 != null && hi1 != null) { - // arg0 is true and arg1 is false, so the result is false - Lo = null; Hi = one; - } - break; - case BinaryOperator.Opcode.Iff: - if (lo0 != null && lo1 != null) { - Lo = one; Hi = null; - } else if (hi0 != null && hi1 != null) { - Lo = one; Hi = null; - } else if (lo0 != null && hi1 != null) { - Lo = null; Hi = one; - } else if (hi0 != null && lo1 != null) { - Lo = null; Hi = one; - } - if (op.Op == BinaryOperator.Opcode.Neq) { - var tmp = Lo; Lo = Hi; Hi = tmp; - } - break; - case BinaryOperator.Opcode.Eq: - case BinaryOperator.Opcode.Neq: - if (node.Args[0].Type.IsBool) { - goto case BinaryOperator.Opcode.Iff; - } - // For Eq: - // If the (lo0,hi0) and (lo1,hi1) ranges do not overlap, the answer is false. - // If both ranges are the same unit range, then the answer is true. - if (hi0 != null && lo1 != null && (isReal ? hi0 < lo1 : hi0 <= lo1)) { - // no overlap - Lo = null; Hi = one; - } else if (lo0 != null && hi1 != null && (isReal ? hi1 < lo0 : hi1 <= lo0)) { - Lo = null; Hi = one; - // no overlaop - } else if (lo0 != null && hi0 != null && lo1 != null && hi1 != null && - lo0 == lo1 && hi0 == hi1 && // ranges are the same - (isReal ? lo0 == hi0 : lo0 + 1 == hi0)) { // unit range - // both ranges are the same unit range - Lo = one; Hi = null; - } - if (op.Op == BinaryOperator.Opcode.Neq) { - var tmp = Lo; Lo = Hi; Hi = tmp; - } - break; - case BinaryOperator.Opcode.Le: - if (isReal) { - // If hi0 <= lo1, then the answer is true. - // If hi1 < lo0, then the answer is false. - if (hi0 != null && lo1 != null && hi0 <= lo1) { - Lo = one; Hi = null; - } else if (hi1 != null && lo0 != null && hi1 < lo0) { - Lo = null; Hi = one; - } - } else { - // If hi0 - 1 <= lo1, then the answer is true. - // If hi1 <= lo0, then the answer is false. - if (hi0 != null && lo1 != null && hi0 - 1 <= lo1) { - Lo = one; Hi = null; - } else if (lo0 != null && hi1 != null && hi1 <= lo0) { - Lo = null; Hi = one; - } - } - break; - case BinaryOperator.Opcode.Lt: - if (isReal) { - // If hi0 < lo1, then the answer is true. - // If hi1 <= lo0, then the answer is false. - if (hi0 != null && lo1 != null && hi0 < lo1) { - Lo = one; Hi = null; - } else if (hi1 != null && lo0 != null && hi1 <= lo0) { - Lo = null; Hi = one; - } - } else { - // If hi0 <= lo1, then the answer is true. - // If hi1 - 1 <= lo0, then the answer is false. - if (hi0 != null && lo1 != null && hi0 <= lo1) { - Lo = one; Hi = null; - } else if (lo0 != null && hi1 != null && hi1 - 1 <= lo0) { - Lo = null; Hi = one; - } - } - break; - case BinaryOperator.Opcode.Gt: - // swap the operands and then continue as Lt - { - var tmp = lo0; lo0 = lo1; lo1 = tmp; - tmp = hi0; hi0 = hi1; hi1 = tmp; - } - goto case BinaryOperator.Opcode.Lt; - case BinaryOperator.Opcode.Ge: - // swap the operands and then continue as Le - { - var tmp = lo0; lo0 = lo1; lo1 = tmp; - tmp = hi0; hi0 = hi1; hi1 = tmp; - } - goto case BinaryOperator.Opcode.Le; - case BinaryOperator.Opcode.Add: - if (lo0 != null && lo1 != null) { - Lo = lo0 + lo1; - } - if (hi0 != null && hi1 != null) { - Hi = isReal ? hi0 + hi1 : hi0 + hi1 - 1; - } - break; - case BinaryOperator.Opcode.Sub: - if (lo0 != null && hi1 != null) { - Lo = isReal ? lo0 - hi1 : lo0 - hi1 + 1; - } - if (hi0 != null && lo1 != null) { - Hi = hi0 - lo1; - } - break; - case BinaryOperator.Opcode.Mul: - // this uses an incomplete approximation that could be tightened up - if (lo0 != null && lo1 != null) { - if (0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { - Lo = lo0 * lo1; - Hi = hi0 == null || hi1 == null ? null : isReal ? hi0 * hi1 : (hi0 - 1) * (hi1 - 1) + 1; - } else if ((BigInteger)lo0 < 0 && (BigInteger)lo1 < 0) { - Lo = null; // approximation - Hi = isReal ? lo0 * lo1 : lo0 * lo1 + 1; - } - } - break; - case BinaryOperator.Opcode.Div: - // this uses an incomplete approximation that could be tightened up - if (lo0 != null && lo1 != null && 0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { - Lo = BigInteger.Zero; - Hi = hi0; - } - break; - case BinaryOperator.Opcode.Mod: - // this uses an incomplete approximation that could be tightened up - if (lo0 != null && lo1 != null && 0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { - Lo = BigInteger.Zero; - Hi = hi1; - } - break; - case BinaryOperator.Opcode.RealDiv: - // this uses an incomplete approximation that could be tightened up - if (lo0 != null && lo1 != null && 0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { - Lo = BigInteger.Zero; - Hi = 1 <= (BigInteger)lo1 ? hi0 : null; - } - break; - case BinaryOperator.Opcode.Pow: - // this uses an incomplete approximation that could be tightened up - if (lo0 != null && lo1 != null && 0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { - Lo = 1 <= (BigInteger)lo1 ? BigInteger.One : BigInteger.Zero; - Hi = hi1; - } - break; - default: - break; - } - } else if (node.Fun is IfThenElse) { - var op = (IfThenElse)node.Fun; - Contract.Assert(node.Args.Count == 3); - BigInteger? guardLo, guardHi, lo0, hi0, lo1, hi1; - VisitExpr(node.Args[0]); - guardLo = Lo; guardHi = Hi; - VisitExpr(node.Args[1]); - lo0 = Lo; hi0 = Hi; - VisitExpr(node.Args[2]); - lo1 = Lo; hi1 = Hi; - Contract.Assert(guardLo == null || guardHi == null); // this is a consequence of the guard being boolean - if (guardLo != null) { - // guard is always true - Lo = lo0; Hi = hi0; - } else if (guardHi != null) { - // guard is always false - Lo = lo1; Hi = hi1; - } else { - // we don't know which branch will be taken, so join the information from the two branches - Lo = Node.Min(lo0, lo1, false); - Hi = Node.Max(hi0, hi1, false); - } - } else if (node.Fun is FunctionCall) { - var call = (FunctionCall)node.Fun; - // See if this is an identity function, which we do by checking: that the function has - // exactly one argument and the function has been marked by the user with the attribute {:identity} - bool claimsToBeIdentity = false; - if (call.ArgumentCount == 1 && call.Func.CheckBooleanAttribute("identity", ref claimsToBeIdentity) && claimsToBeIdentity && node.Args[0].Type.Equals(node.Type)) { - VisitExpr(node.Args[0]); - } - } - return node; - } - public override BinderExpr VisitBinderExpr(BinderExpr node) { - // don't recurse on subexpression - return node; - } - public override Expr VisitOldExpr(OldExpr node) { - // don't recurse on subexpression - return node; - } - public override Expr VisitCodeExpr(CodeExpr node) { - // don't recurse on subexpression - return node; - } - public override Expr VisitBvConcatExpr(BvConcatExpr node) { - // don't recurse on subexpression - return node; - } - public override Expr VisitBvExtractExpr(BvExtractExpr node) { - // don't recurse on subexpression - return node; - } - } - - public override Element Eliminate(Element element, Variable v) { - if (element is E_Bottom) { - return element; - } - var e = (E)element; - var nn = UpdateOne(e.N, v, null, null); - if (nn == e.N) { - return element; - } else { - return new E(nn); - } - } - - Node UpdateOne(Node nn, Variable v, BigInteger? lo, BigInteger? hi) { - var orig = nn; - Node head = null; - Node prev = null; - var foundV = false; - for (; nn != null && !Node.StrictlyBefore(v, nn.V); nn = nn.Next) { - if (nn.V == v) { - foundV = true; - nn = nn.Next; - break; // we found the place where the new node goes - } else { - var n = new Node(nn.V, nn.Lo, nn.Hi); // copy this Node - if (head == null) { - head = n; - } else { - prev.Next = n; - } - prev = n; - } - } - Node rest; - if (lo == null && hi == null) { - // eliminate all information about "v" - if (!foundV) { - return orig; - } - rest = nn; - } else { - rest = new Node(v, lo, hi); - rest.Next = nn; - } - if (head == null) { - head = rest; - } else { - prev.Next = rest; - } - return head; - } - - /// - /// Return a resolved/type-checked expression that represents the conjunction of a and b. - /// Requires a and b to be resolved and type checked already. - /// - public static Expr BplAnd(Expr a, Expr b) { - if (a == Expr.True) { - return b; - } else if (b == Expr.True) { - return a; - } else { - var nary = Expr.Binary(BinaryOperator.Opcode.And, a, b); - nary.Type = Type.Bool; - nary.TypeParameters = SimpleTypeParamInstantiation.EMPTY; - return nary; - } - } - - /// - /// Return a resolved/type-checked expression that represents a EQUALS b. - /// Requires a and b to be resolved and type checked already. - /// - public static Expr BplEq(Expr a, Expr b) { - var e = Expr.Eq(a, b); - e.Type = Type.Bool; - return e; - } - - /// - /// Return a resolved/type-checked expression that represents a LESS-EQUAL b. - /// Requires a and b to be resolved and type checked already. - /// - public static Expr BplLe(Expr a, Expr b) { - var e = Expr.Le(a, b); - e.Type = Type.Bool; - return e; - } - /// - /// Return a resolved/type-checked expression that represents a LESS b. - /// Requires a and b to be resolved and type checked already. - /// - public static Expr BplLt(Expr a, Expr b) { - var e = Expr.Lt(a, b); - e.Type = Type.Bool; - return e; - } - } - - public class ThresholdFinder : ReadOnlyVisitor - { - readonly Implementation Impl; - public ThresholdFinder(Implementation impl) { - Contract.Requires(impl != null); - Impl = impl; - } - HashSet downs = new HashSet(); - HashSet ups = new HashSet(); - public void Find(out List downThresholds, out List upThresholds) { - // always include -1, 0, 1 as down-thresholds - downs.Clear(); - downs.Add(-1); - downs.Add(0); - downs.Add(1); - // always include 0 and 1 as up-thresholds - ups.Clear(); - ups.Add(0); - ups.Add(1); - - foreach (Requires p in Impl.Proc.Requires) { - Visit(p.Condition); - } - foreach (Ensures p in Impl.Proc.Ensures) { - Visit(p.Condition); - } - foreach (var b in Impl.Blocks) { - foreach (Cmd c in b.Cmds) { - Visit(c); - } - } - - // convert the HashSets to sorted Lists and return - downThresholds = new List(); - foreach (var i in downs) { - downThresholds.Add(i); - } - downThresholds.Sort(); - upThresholds = new List(); - foreach (var i in ups) { - upThresholds.Add(i); - } - upThresholds.Sort(); - } - - public override Expr VisitNAryExpr(NAryExpr node) { - if (node.Fun is BinaryOperator) { - var op = (BinaryOperator)node.Fun; - Contract.Assert(node.Args.Count == 2); - var arg0 = node.Args[0]; - var arg1 = node.Args[1]; - var offset = arg0.Type.IsReal ? 0 : 1; - BigInteger? k; - switch (op.Op) { - case BinaryOperator.Opcode.Eq: - case BinaryOperator.Opcode.Neq: - k = AsIntLiteral(arg0); - if (k != null) { - var i = (BigInteger)k; - downs.Add(i - 1); - downs.Add(i); - ups.Add(i + 1); - ups.Add(i + 2); - } - k = AsIntLiteral(arg1); - if (k != null) { - var i = (BigInteger)k; - downs.Add(i - 1); - downs.Add(i); - ups.Add(i + 1); - ups.Add(i + 2); - } - break; - case BinaryOperator.Opcode.Le: - k = AsIntLiteral(arg0); - if (k != null) { - var i = (BigInteger)k; - downs.Add(i - 1); - downs.Add(i); - } - k = AsIntLiteral(arg1); - if (k != null) { - var i = (BigInteger)k; - ups.Add(i + offset); - ups.Add(i + 1 + offset); - } - break; - case BinaryOperator.Opcode.Lt: - k = AsIntLiteral(arg0); - if (k != null) { - var i = (BigInteger)k; - downs.Add(i ); - downs.Add(i + 1); - } - k = AsIntLiteral(arg1); - if (k != null) { - var i = (BigInteger)k; - ups.Add(i - 1 + offset); - ups.Add(i + offset); - } - break; - case BinaryOperator.Opcode.Ge: - { var tmp = arg0; arg0 = arg1; arg1 = tmp; } - goto case BinaryOperator.Opcode.Le; - case BinaryOperator.Opcode.Gt: - { var tmp = arg0; arg0 = arg1; arg1 = tmp; } - goto case BinaryOperator.Opcode.Lt; - default: - break; - } - } - return base.VisitNAryExpr(node); - } - - BigInteger? AsIntLiteral(Expr e) { - var lit = e as LiteralExpr; - if (lit != null && lit.isBigNum) { - BigNum bn = lit.asBigNum; - return bn.ToBigInteger; - } - return null; - } - } - -} +using System; +using System.Numerics; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using Microsoft.Basetypes; + +namespace Microsoft.Boogie.AbstractInterpretation +{ + class NativeIntervallDomain : NativeLattice + { + abstract class E_Common : NativeLattice.Element { } + class E_Bottom : E_Common + { + public override Expr ToExpr() { + return Expr.False; + } + } + class E : E_Common + { + public readonly Node N; + public E() { } + public E(Node n) { + N = n; + } + + public override Expr ToExpr() { + Expr expr = Expr.True; + for (var n = N; n != null; n = n.Next) { + expr = BplAnd(expr, n.ToExpr()); + } + return expr; + } + } + public class Node + { + public readonly Variable V; // variable has type bool or int + // For an integer variable (Lo,Hi) indicates Lo <= V < Hi, where Lo==null means no lower bound and Hi==null means no upper bound. + // For a real variable (Lo,Hi) indicates Lo <= V <= Hi, where Lo==null means no lower bound and Hi==null means no upper bound. + // For a boolean variable, (Lo,Hi) is one of: (null,null) for {false,true}, (null,1) for {false}, and (1,null) for {true}. + public readonly BigInteger? Lo; + public readonly BigInteger? Hi; + public Node Next; // always sorted according to StrictlyBefore; readonly after full initialization + [Pure] + public static bool StrictlyBefore(Variable a, Variable b) { + Contract.Assert(a.UniqueId != b.UniqueId || a == b); + return a.UniqueId < b.UniqueId; + } + + Node(Variable v, BigInteger? lo, BigInteger? hi, Node next) { + Contract.Requires(lo != null || hi != null); // don't accept empty constraints + Contract.Requires(next == null || StrictlyBefore(v, next.V)); + V = v; + Lo = lo; + Hi = hi; + Next = next; + } + + /// + /// This constructor leaves Next as null, allowing the caller to fill in Next to finish off the construction. + /// + public Node(Variable v, BigInteger? lo, BigInteger? hi) { + Contract.Requires(lo != null || hi != null); // don't accept empty constraints + V = v; + Lo = lo; + Hi = hi; + } + + /// + /// Returns a Node that has the constraints head.{V,Lo,Hi} plus + /// all the constraints entailed by Nodes reachable from tail. + /// Requires that "head" sorts no later than anything in "tail". + /// Create either returns "head" itself or returns a new Node. + /// + public static Node Create(Node head, Node tail) { + Contract.Requires(head != null); + Contract.Requires(tail == null || !StrictlyBefore(tail.V, head.V)); + Contract.Requires(head != tail); + + if (head.Next == tail) { + return head; + } else if (tail != null && head.V == tail.V) { + // incorporate both constraints into one Node + return new Node(head.V, Max(head.Lo, tail.Lo, true), Min(head.Lo, tail.Lo, true), tail.Next); + } else { + return new Node(head.V, head.Lo, head.Hi, tail); + } + } + + public static void GetBounds(Node n, Variable v, out BigInteger? lo, out BigInteger? hi) { + for (; n != null; n = n.Next) { + if (n.V == v) { + lo = n.Lo; + hi = n.Hi; + return; + } else if (StrictlyBefore(v, n.V)) { + break; + } + } + lo = null; + hi = null; + } + + /// + /// Return the minimum of "a" and "b". If treatNullAsUnit==true, then "null" is + /// interpreted as positive infinity (the unit element of min); otherwise, it is + /// treated as negative infinity (the zero element of min). + /// + public static BigInteger? Min(BigInteger? a, BigInteger? b, bool treatNullAsUnit) { + if (a == null) { + return treatNullAsUnit ? b : a; + } else if (b == null) { + return treatNullAsUnit ? a : b; + } else { + return BigInteger.Min((BigInteger)a, (BigInteger)b); + } + } + + /// + /// Return the maximum of "a" and "b". If treatNullAsUnit==true, then "null" is + /// interpreted as negative infinity (the unit element of max); otherwise, it is + /// treated as positive infinity (the zero element of max). + /// + public static BigInteger? Max(BigInteger? a, BigInteger? b, bool treatNullAsUnit) { + if (a == null) { + return treatNullAsUnit ? b : a; + } else if (b == null) { + return treatNullAsUnit ? a : b; + } else { + return BigInteger.Max((BigInteger)a, (BigInteger)b); + } + } + + public static IEnumerable> Merge(Node a, Node b) { + while (true) { + if (a == null && b == null) { + yield break; + } else if (a == null || b == null) { + yield return new Tuple(a, b); + if (a != null) { a = a.Next; } else { b = b.Next; } + } else if (a.V == b.V) { + yield return new Tuple(a, b); + a = a.Next; b = b.Next; + } else if (StrictlyBefore(a.V, b.V)) { + yield return new Tuple(a, null); + a = a.Next; + } else { + yield return new Tuple(null, b); + b = b.Next; + } + } + } + + public Expr ToExpr() { + if (!V.IsMutable && CommandLineOptions.Clo.InstrumentInfer != CommandLineOptions.InstrumentationPlaces.Everywhere) { + // omit invariants about readonly variables + return Expr.True; + } else if (V.TypedIdent.Type.IsBool) { + if (Lo == null && Hi == null) { + return Expr.True; + } else { + Contract.Assert((Lo == null && (BigInteger)Hi == 1) || (Hi == null && (BigInteger)Lo == 1)); + var ide = new IdentifierExpr(Token.NoToken, V); + return Hi == null ? ide : Expr.Not(ide); + } + } else if (V.TypedIdent.Type.IsInt) { + Expr e = Expr.True; + if (Lo != null && Hi != null && Lo + 1 == Hi) { + // produce an equality + var ide = new IdentifierExpr(Token.NoToken, V); + e = Expr.And(e, BplEq(ide, NumberToExpr((BigInteger)Lo, V.TypedIdent.Type))); + } else { + // produce a (possibly empty) conjunction of inequalities + if (Lo != null) { + var ide = new IdentifierExpr(Token.NoToken, V); + e = Expr.And(e, BplLe(NumberToExpr((BigInteger)Lo, V.TypedIdent.Type), ide)); + } + if (Hi != null) { + var ide = new IdentifierExpr(Token.NoToken, V); + e = Expr.And(e, BplLt(ide, NumberToExpr((BigInteger)Hi, V.TypedIdent.Type))); + } + } + return e; + } else if (V.TypedIdent.Type.IsReal){ + Expr e = Expr.True; + if (Lo != null && Hi != null && Lo == Hi) { + // produce an equality + var ide = new IdentifierExpr(Token.NoToken, V); + e = Expr.And(e, BplEq(ide, NumberToExpr((BigInteger)Lo, V.TypedIdent.Type))); + } else { + // produce a (possibly empty) conjunction of inequalities + if (Lo != null) { + var ide = new IdentifierExpr(Token.NoToken, V); + e = Expr.And(e, BplLe(NumberToExpr((BigInteger)Lo, V.TypedIdent.Type), ide)); + } + if (Hi != null) { + var ide = new IdentifierExpr(Token.NoToken, V); + e = Expr.And(e, BplLe(ide, NumberToExpr((BigInteger)Hi, V.TypedIdent.Type))); + } + } + return e; + } else { + Contract.Assert(V.TypedIdent.Type.IsFloat); + Expr e = Expr.True; + if (Lo != null && Hi != null && Lo == Hi) + { + // produce an equality + var ide = new IdentifierExpr(Token.NoToken, V); + e = Expr.And(e, BplEq(ide, NumberToExpr((BigInteger)Lo, V.TypedIdent.Type))); + } + else + { + // produce a (possibly empty) conjunction of inequalities + if (Lo != null) + { + var ide = new IdentifierExpr(Token.NoToken, V); + e = Expr.And(e, BplLe(NumberToExpr((BigInteger)Lo, V.TypedIdent.Type), ide)); + } + if (Hi != null) + { + var ide = new IdentifierExpr(Token.NoToken, V); + e = Expr.And(e, BplLe(ide, NumberToExpr((BigInteger)Hi, V.TypedIdent.Type))); + } + } + return e; + } + } + } + + static Expr NumberToExpr(BigInteger n, Type ty) { + if (n == null) { + return null; + } else if (ty.IsReal) { + return Expr.Literal(Basetypes.BigDec.FromBigInt(n)); + } else if (ty.IsFloat) { + return Expr.Literal(Basetypes.BigFloat.FromBigInt(n, ty.FloatExponent, ty.FloatMantissa)); + } else { + Contract.Assume(ty.IsInt); + return Expr.Literal(Basetypes.BigNum.FromBigInt(n)); + } + } + + List upThresholds; // invariant: thresholds are sorted + List downThresholds; // invariant: thresholds are sorted + + /// + /// Requires "thresholds" to be sorted. + /// + public NativeIntervallDomain() { + upThresholds = new List(); + downThresholds = new List(); + } + + public override void Specialize(Implementation impl) { + if (impl == null) { + // remove thresholds + upThresholds = new List(); + downThresholds = new List(); + } else { + var tf = new ThresholdFinder(impl); + tf.Find(out downThresholds, out upThresholds); +#if DEBUG_PRINT + Console.Write("DEBUG: for implementation '{0}', setting downs to [", impl.Name); + foreach (var i in downThresholds) { + Console.Write(" {0}", i); + } + Console.Write(" ] and ups to ["); + foreach (var i in upThresholds) { + Console.Write(" {0}", i); + } + Console.WriteLine(" ]"); +#endif + } + base.Specialize(impl); + } + + private E_Common top = new E(); + private E_Common bottom = new E_Bottom(); + + public override Element Top { get { return top; } } + public override Element Bottom { get { return bottom; } } + + public override bool IsTop(Element element) { + var e = element as E; + return e != null && e.N == null; + } + public override bool IsBottom(Element element) { + return element is E_Bottom; + } + + public override bool Below(Element a, Element b) { + if (a is E_Bottom) { + return true; + } else if (b is E_Bottom) { + return false; + } else { + var aa = (E)a; + var bb = (E)b; + // check if every constraint in 'bb' is implied by constraints in 'aa' + foreach (var t in Node.Merge(aa.N, bb.N)) { + var x = t.Item1; + var y = t.Item2; + if (x == null) { + // bb constrains a variable that aa does not + return false; + } else if (y == null) { + // aa constrains a variable that bb does not; that's fine + } else if (y.Lo != null && (x.Lo == null || x.Lo < y.Lo)) { + // bb has a Lo constraint, and either aa has no Lo constraint or it has a weaker Lo constraint + return false; + } else if (y.Hi != null && (x.Hi == null || y.Hi < x.Hi)) { + // bb has a Hi o constraint, and either aa has no Hi constraint or it has a weaker Hi constraint + return false; + } + } + return true; + } + } + + public override Element Meet(Element a, Element b) { + if (a is E_Bottom) { + return a; + } else if (b is E_Bottom) { + return b; + } else { + var aa = (E)a; + var bb = (E)b; + Node head = null; + Node prev = null; + foreach (var t in Node.Merge(aa.N, bb.N)) { + var x = t.Item1; + var y = t.Item2; + Node n; + if (x == null) { + n = new Node(y.V, y.Lo, y.Hi); + } else if (y == null) { + n = new Node(x.V, x.Lo, x.Hi); + } else { + var lo = Node.Max(x.Lo, y.Lo, true); + var hi = Node.Min(x.Hi, y.Hi, true); + // if hi<=lo (or hi + /// For a proof of correctness of this method, see Test/dafny2/Intervals.dfy. + /// A difference is that the this method returns: + /// let d = Dafny_RoundDown(k); + /// return d == -1 ? null : downThresholds[d]; + /// + BigInteger? RoundDown(BigInteger k) + { + if (downThresholds.Count == 0 || k < downThresholds[0]) { + return null; + } + var i = 0; + var j = downThresholds.Count - 1; + while (i < j) + { + var mid = i + (j - i + 1) / 2; + if (downThresholds[mid] <= k) { + i = mid; + } else { + j = mid - 1; + } + } + return downThresholds[i]; + } + + /// + /// For a proof of correctness of this method, see Test/dafny2/Intervals.dfy. + /// A difference is that the this method returns: + /// let d = Dafny_RoundUp(k); + /// return d == thresholds.Count ? null : upThresholds[d]; + /// + BigInteger? RoundUp(BigInteger k) + { + if (upThresholds.Count == 0 || upThresholds[upThresholds.Count - 1] < k) { + return null; + } + var i = 0; + var j = upThresholds.Count - 1; + while (i < j) + { + var mid = i + (j - i) / 2; + if (upThresholds[mid] < k) { + i = mid + 1; + } else { + j = mid; + } + } + return upThresholds[i]; + } + + public override Element Constrain(Element element, Expr expr) { + if (element is E_Bottom) { + return element; + } else { + var e = (E)element; + var c = Constraint(expr, e.N); + return c == null ? element : Meet(element, c); + } + } + + /// + /// Returns an Element that corresponds to the constraints implied by "expr" in the + /// state "state". + /// Return "null" to indicate no constraints. + /// + E_Common Constraint(Expr expr, Node state) { + Variable v; + if (IsVariable(expr, out v)) { + var n = new Node(v, BigInteger.One, null); + return new E(n); + } else if (expr is LiteralExpr) { + var e = (LiteralExpr)expr; + return (bool)e.Val ? null : new E_Bottom(); + } else if (expr is NAryExpr) { + var e = (NAryExpr)expr; + if (e.Fun is UnaryOperator) { + if (((UnaryOperator)e.Fun).Op == UnaryOperator.Opcode.Not) { + if (IsVariable(e.Args[0], out v)) { + var n = new Node(v, null, BigInteger.One); + return new E(n); + } + } + } else if (e.Fun is BinaryOperator) { + var op = ((BinaryOperator)e.Fun).Op; + var arg0 = e.Args[0]; + var arg1 = e.Args[1]; + switch (op) { + case BinaryOperator.Opcode.Eq: + case BinaryOperator.Opcode.Iff: { + E_Common c = null; + if (IsVariable(arg0, out v)) { + BigInteger? lo, hi; + if (PartiallyEvaluate(arg1, state, out lo, out hi)) { + var n = new Node(v, lo, hi); + c = new E(n); + } + } + if (IsVariable(arg1, out v)) { + BigInteger? lo, hi; + if (PartiallyEvaluate(arg1, state, out lo, out hi)) { + var n = new Node(v, lo, hi); + c = c == null ? new E(n) : (E_Common)Meet(c, new E(n)); + } + } + return c; + } + case BinaryOperator.Opcode.Neq: { + E_Common c = null; + if (IsVariable(arg0, out v)) { + c = ConstrainNeq(state, v, arg1); + } + if (IsVariable(arg1, out v)) { + var cc = ConstrainNeq(state, v, arg0); + if (cc != null) { + c = c == null ? cc : (E_Common)Meet(c, cc); + } + } + return c; + } + case BinaryOperator.Opcode.Le: { + E_Common c = null; + if (IsVariable(arg1, out v)) { + BigInteger? lo, hi; + PartiallyEvaluate(arg0, state, out lo, out hi); + if (lo != null) { + var n = new Node(v, lo, null); + c = new E(n); + } + } + if (IsVariable(arg0, out v)) { + BigInteger? lo, hi; + PartiallyEvaluate(arg1, state, out lo, out hi); + if (hi != null) { + var n = new Node(v, null, hi); + c = c == null ? new E(n) : (E_Common)Meet(c, new E(n)); + } + } + return c; + } + case BinaryOperator.Opcode.Lt: { + E_Common c = null; + if (IsVariable(arg1, out v)) { + BigInteger? lo, hi; + PartiallyEvaluate(arg0, state, out lo, out hi); + if (lo != null) { + var n = new Node(v, v.TypedIdent.Type.IsReal ? lo : lo + 1, null); + c = new E(n); + } + } + if (IsVariable(arg0, out v)) { + BigInteger? lo, hi; + PartiallyEvaluate(arg1, state, out lo, out hi); + if (hi != null) { + var n = new Node(v, null, v.TypedIdent.Type.IsReal ? hi : hi - 1); + c = c == null ? new E(n) : (E_Common)Meet(c, new E(n)); + } + } + return c; + } + case BinaryOperator.Opcode.Ge: { + var tmp = arg0; arg0 = arg1; arg1 = tmp; + goto case BinaryOperator.Opcode.Le; + } + case BinaryOperator.Opcode.Gt: { + var tmp = arg0; arg0 = arg1; arg1 = tmp; + goto case BinaryOperator.Opcode.Lt; + } + default: + break; + } + } + } + return null; // approximation + } + + private E ConstrainNeq(Node state, Variable v, Expr arg) { + BigInteger? lo, hi; + if (PartiallyEvaluate(arg, state, out lo, out hi)) { + if (!v.TypedIdent.Type.IsReal && lo != null && hi != null && lo + 1 == hi) { + var exclude = lo; + // If the partially evaluated arg (whose value is "exclude") is an end-point of + // the interval known for "v", then produce a constraint that excludes that bound. + Node.GetBounds(state, v, out lo, out hi); + if (lo != null && lo == exclude) { + var n = new Node(v, lo + 1, null); + return new E(n); + } else if (hi != null && exclude + 1 == hi) { + var n = new Node(v, null, exclude); + return new E(n); + } + } + } + return null; + } + + bool IsVariable(Expr expr, out Variable v) { + var e = expr as IdentifierExpr; + if (e == null) { + v = null; + return false; + } else { + v = e.Decl; + return true; + } + } + + public override Element Update(Element element, AssignCmd cmd) { + if (element is E_Bottom) { + return element; + } + var e = (E)element; + var nn = e.N; + Contract.Assert(cmd.Lhss.Count == cmd.Rhss.Count); + for (int i = 0; i < cmd.Lhss.Count; i++) { + var lhs = cmd.Lhss[i]; + var rhs = cmd.Rhss[i]; + BigInteger? lo; + BigInteger? hi; + PartiallyEvaluate(rhs, e.N, out lo, out hi); + nn = UpdateOne(nn, lhs.DeepAssignedVariable, lo, hi); + } + return new E(nn); + } + + bool PartiallyEvaluate(Expr rhs, Node node, out BigInteger? lo, out BigInteger? hi) { + var pe = new PEVisitor(node); + pe.VisitExpr(rhs); + lo = pe.Lo; + hi = pe.Hi; + return lo != null || hi != null; + } + + class PEVisitor : ReadOnlyVisitor + { + public BigInteger? Lo; + public BigInteger? Hi; + + readonly BigInteger one = BigInteger.One; + + Node N; + public PEVisitor(Node n) { + N = n; + } + + // Override visitors for all expressions that can return a boolean, integer, or real result + + public override Expr VisitExpr(Expr node) { + Lo = Hi = null; + return base.VisitExpr(node); + } + public override Expr VisitLiteralExpr(LiteralExpr node) { + if (node.Val is BigNum) { + var n = ((BigNum)node.Val).ToBigInteger; + Lo = n; + Hi = n + 1; + } else if (node.Val is BigDec) { + BigInteger floor, ceiling; + ((BigDec)node.Val).FloorCeiling(out floor, out ceiling); + Lo = floor; + Hi = ceiling; + } else if (node.Val is BigFloat) { + BigNum floor, ceiling; + ((BigFloat)node.Val).FloorCeiling(out floor, out ceiling); + Lo = floor.ToBigInteger; + Hi = ceiling.ToBigInteger; + } else if (node.Val is bool) { + if ((bool)node.Val) { + // true + Lo = one; + Hi = null; + } else { + // false + Lo = null; + Hi = one; + } + } + return node; + } + public override Expr VisitIdentifierExpr(IdentifierExpr node) { + if (node.Type.IsBool || node.Type.IsInt || node.Type.IsReal) { + Node.GetBounds(N, node.Decl, out Lo, out Hi); + } + return node; + } + public override Expr VisitNAryExpr(NAryExpr node) { + if (node.Fun is UnaryOperator) { + var op = (UnaryOperator)node.Fun; + Contract.Assert(node.Args.Count == 1); + if (op.Op == UnaryOperator.Opcode.Neg) { + BigInteger? lo, hi; + VisitExpr(node.Args[0]); + lo = Lo; hi = Hi; + if (hi != null) { + Lo = node.Type.IsReal ? -hi : 1 - hi; + } else { + Lo = null; + } + if (lo != null) { + Hi = node.Type.IsReal ? -lo : 1 - lo; + } else { + Hi = null; + } + } + else if (op.Op == UnaryOperator.Opcode.Not) { + VisitExpr(node.Args[0]); + Contract.Assert((Lo == null && Hi == null) || + (Lo == null && (BigInteger)Hi == 1) || + (Hi == null && (BigInteger)Lo == 1)); + var tmp = Lo; + Lo = Hi; + Hi = tmp; + } + } else if (node.Fun is BinaryOperator) { + var op = (BinaryOperator)node.Fun; + Contract.Assert(node.Args.Count == 2); + BigInteger? lo0, hi0, lo1, hi1; + VisitExpr(node.Args[0]); + lo0 = Lo; hi0 = Hi; + VisitExpr(node.Args[1]); + lo1 = Lo; hi1 = Hi; + Lo = Hi = null; + var isReal = node.Args[0].Type.IsReal; + switch (op.Op) { + case BinaryOperator.Opcode.And: + if (hi0 != null || hi1 != null) { + // one operand is definitely false, thus so is the result + Lo = null; Hi = one; + } else if (lo0 != null && lo1 != null) { + // both operands are definitely true, thus so is the result + Lo = one; Hi = null; + } + break; + case BinaryOperator.Opcode.Or: + if (lo0 != null || lo1 != null) { + // one operand is definitely true, thus so is the result + Lo = one; Hi = null; + } else if (hi0 != null && hi1 != null) { + // both operands are definitely false, thus so is the result + Lo = null; Hi = one; + } + break; + case BinaryOperator.Opcode.Imp: + if (hi0 != null || lo1 != null) { + // either arg0 false or arg1 is true, so the result is true + Lo = one; Hi = null; + } else if (lo0 != null && hi1 != null) { + // arg0 is true and arg1 is false, so the result is false + Lo = null; Hi = one; + } + break; + case BinaryOperator.Opcode.Iff: + if (lo0 != null && lo1 != null) { + Lo = one; Hi = null; + } else if (hi0 != null && hi1 != null) { + Lo = one; Hi = null; + } else if (lo0 != null && hi1 != null) { + Lo = null; Hi = one; + } else if (hi0 != null && lo1 != null) { + Lo = null; Hi = one; + } + if (op.Op == BinaryOperator.Opcode.Neq) { + var tmp = Lo; Lo = Hi; Hi = tmp; + } + break; + case BinaryOperator.Opcode.Eq: + case BinaryOperator.Opcode.Neq: + if (node.Args[0].Type.IsBool) { + goto case BinaryOperator.Opcode.Iff; + } + // For Eq: + // If the (lo0,hi0) and (lo1,hi1) ranges do not overlap, the answer is false. + // If both ranges are the same unit range, then the answer is true. + if (hi0 != null && lo1 != null && (isReal ? hi0 < lo1 : hi0 <= lo1)) { + // no overlap + Lo = null; Hi = one; + } else if (lo0 != null && hi1 != null && (isReal ? hi1 < lo0 : hi1 <= lo0)) { + Lo = null; Hi = one; + // no overlaop + } else if (lo0 != null && hi0 != null && lo1 != null && hi1 != null && + lo0 == lo1 && hi0 == hi1 && // ranges are the same + (isReal ? lo0 == hi0 : lo0 + 1 == hi0)) { // unit range + // both ranges are the same unit range + Lo = one; Hi = null; + } + if (op.Op == BinaryOperator.Opcode.Neq) { + var tmp = Lo; Lo = Hi; Hi = tmp; + } + break; + case BinaryOperator.Opcode.Le: + if (isReal) { + // If hi0 <= lo1, then the answer is true. + // If hi1 < lo0, then the answer is false. + if (hi0 != null && lo1 != null && hi0 <= lo1) { + Lo = one; Hi = null; + } else if (hi1 != null && lo0 != null && hi1 < lo0) { + Lo = null; Hi = one; + } + } else { + // If hi0 - 1 <= lo1, then the answer is true. + // If hi1 <= lo0, then the answer is false. + if (hi0 != null && lo1 != null && hi0 - 1 <= lo1) { + Lo = one; Hi = null; + } else if (lo0 != null && hi1 != null && hi1 <= lo0) { + Lo = null; Hi = one; + } + } + break; + case BinaryOperator.Opcode.Lt: + if (isReal) { + // If hi0 < lo1, then the answer is true. + // If hi1 <= lo0, then the answer is false. + if (hi0 != null && lo1 != null && hi0 < lo1) { + Lo = one; Hi = null; + } else if (hi1 != null && lo0 != null && hi1 <= lo0) { + Lo = null; Hi = one; + } + } else { + // If hi0 <= lo1, then the answer is true. + // If hi1 - 1 <= lo0, then the answer is false. + if (hi0 != null && lo1 != null && hi0 <= lo1) { + Lo = one; Hi = null; + } else if (lo0 != null && hi1 != null && hi1 - 1 <= lo0) { + Lo = null; Hi = one; + } + } + break; + case BinaryOperator.Opcode.Gt: + // swap the operands and then continue as Lt + { + var tmp = lo0; lo0 = lo1; lo1 = tmp; + tmp = hi0; hi0 = hi1; hi1 = tmp; + } + goto case BinaryOperator.Opcode.Lt; + case BinaryOperator.Opcode.Ge: + // swap the operands and then continue as Le + { + var tmp = lo0; lo0 = lo1; lo1 = tmp; + tmp = hi0; hi0 = hi1; hi1 = tmp; + } + goto case BinaryOperator.Opcode.Le; + case BinaryOperator.Opcode.Add: + if (lo0 != null && lo1 != null) { + Lo = lo0 + lo1; + } + if (hi0 != null && hi1 != null) { + Hi = isReal ? hi0 + hi1 : hi0 + hi1 - 1; + } + break; + case BinaryOperator.Opcode.Sub: + if (lo0 != null && hi1 != null) { + Lo = isReal ? lo0 - hi1 : lo0 - hi1 + 1; + } + if (hi0 != null && lo1 != null) { + Hi = hi0 - lo1; + } + break; + case BinaryOperator.Opcode.Mul: + // this uses an incomplete approximation that could be tightened up + if (lo0 != null && lo1 != null) { + if (0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { + Lo = lo0 * lo1; + Hi = hi0 == null || hi1 == null ? null : isReal ? hi0 * hi1 : (hi0 - 1) * (hi1 - 1) + 1; + } else if ((BigInteger)lo0 < 0 && (BigInteger)lo1 < 0) { + Lo = null; // approximation + Hi = isReal ? lo0 * lo1 : lo0 * lo1 + 1; + } + } + break; + case BinaryOperator.Opcode.Div: + // this uses an incomplete approximation that could be tightened up + if (lo0 != null && lo1 != null && 0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { + Lo = BigInteger.Zero; + Hi = hi0; + } + break; + case BinaryOperator.Opcode.Mod: + // this uses an incomplete approximation that could be tightened up + if (lo0 != null && lo1 != null && 0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { + Lo = BigInteger.Zero; + Hi = hi1; + if (lo0 < lo1 && hi0 != null && hi0 < lo1) { + Lo = lo0; + Hi = hi0; + } + } + break; + case BinaryOperator.Opcode.RealDiv: + // this uses an incomplete approximation that could be tightened up + if (lo0 != null && lo1 != null && 0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { + Lo = BigInteger.Zero; + Hi = 1 <= (BigInteger)lo1 ? hi0 : null; + } + break; + case BinaryOperator.Opcode.Pow: + // this uses an incomplete approximation that could be tightened up + if (lo0 != null && lo1 != null && 0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { + Lo = 1 <= (BigInteger)lo1 ? BigInteger.One : BigInteger.Zero; + Hi = hi1; + } + break; + default: + break; + } + } else if (node.Fun is IfThenElse) { + var op = (IfThenElse)node.Fun; + Contract.Assert(node.Args.Count == 3); + BigInteger? guardLo, guardHi, lo0, hi0, lo1, hi1; + VisitExpr(node.Args[0]); + guardLo = Lo; guardHi = Hi; + VisitExpr(node.Args[1]); + lo0 = Lo; hi0 = Hi; + VisitExpr(node.Args[2]); + lo1 = Lo; hi1 = Hi; + Contract.Assert(guardLo == null || guardHi == null); // this is a consequence of the guard being boolean + if (guardLo != null) { + // guard is always true + Lo = lo0; Hi = hi0; + } else if (guardHi != null) { + // guard is always false + Lo = lo1; Hi = hi1; + } else { + // we don't know which branch will be taken, so join the information from the two branches + Lo = Node.Min(lo0, lo1, false); + Hi = Node.Max(hi0, hi1, false); + } + } else if (node.Fun is FunctionCall) { + var call = (FunctionCall)node.Fun; + // See if this is an identity function, which we do by checking: that the function has + // exactly one argument and the function has been marked by the user with the attribute {:identity} + bool claimsToBeIdentity = false; + if (call.ArgumentCount == 1 && call.Func.CheckBooleanAttribute("identity", ref claimsToBeIdentity) && claimsToBeIdentity && node.Args[0].Type.Equals(node.Type)) { + VisitExpr(node.Args[0]); + } + } + return node; + } + public override BinderExpr VisitBinderExpr(BinderExpr node) { + // don't recurse on subexpression + return node; + } + public override Expr VisitOldExpr(OldExpr node) { + // don't recurse on subexpression + return node; + } + public override Expr VisitCodeExpr(CodeExpr node) { + // don't recurse on subexpression + return node; + } + public override Expr VisitBvConcatExpr(BvConcatExpr node) { + // don't recurse on subexpression + return node; + } + public override Expr VisitBvExtractExpr(BvExtractExpr node) { + // don't recurse on subexpression + return node; + } + } + + public override Element Eliminate(Element element, Variable v) { + if (element is E_Bottom) { + return element; + } + var e = (E)element; + var nn = UpdateOne(e.N, v, null, null); + if (nn == e.N) { + return element; + } else { + return new E(nn); + } + } + + Node UpdateOne(Node nn, Variable v, BigInteger? lo, BigInteger? hi) { + var orig = nn; + Node head = null; + Node prev = null; + var foundV = false; + for (; nn != null && !Node.StrictlyBefore(v, nn.V); nn = nn.Next) { + if (nn.V == v) { + foundV = true; + nn = nn.Next; + break; // we found the place where the new node goes + } else { + var n = new Node(nn.V, nn.Lo, nn.Hi); // copy this Node + if (head == null) { + head = n; + } else { + prev.Next = n; + } + prev = n; + } + } + Node rest; + if (lo == null && hi == null) { + // eliminate all information about "v" + if (!foundV) { + return orig; + } + rest = nn; + } else { + rest = new Node(v, lo, hi); + rest.Next = nn; + } + if (head == null) { + head = rest; + } else { + prev.Next = rest; + } + return head; + } + + /// + /// Return a resolved/type-checked expression that represents the conjunction of a and b. + /// Requires a and b to be resolved and type checked already. + /// + public static Expr BplAnd(Expr a, Expr b) { + if (a == Expr.True) { + return b; + } else if (b == Expr.True) { + return a; + } else { + var nary = Expr.Binary(BinaryOperator.Opcode.And, a, b); + nary.Type = Type.Bool; + nary.TypeParameters = SimpleTypeParamInstantiation.EMPTY; + return nary; + } + } + + /// + /// Return a resolved/type-checked expression that represents a EQUALS b. + /// Requires a and b to be resolved and type checked already. + /// + public static Expr BplEq(Expr a, Expr b) { + var e = Expr.Eq(a, b); + e.Type = Type.Bool; + return e; + } + + /// + /// Return a resolved/type-checked expression that represents a LESS-EQUAL b. + /// Requires a and b to be resolved and type checked already. + /// + public static Expr BplLe(Expr a, Expr b) { + var e = Expr.Le(a, b); + e.Type = Type.Bool; + return e; + } + /// + /// Return a resolved/type-checked expression that represents a LESS b. + /// Requires a and b to be resolved and type checked already. + /// + public static Expr BplLt(Expr a, Expr b) { + var e = Expr.Lt(a, b); + e.Type = Type.Bool; + return e; + } + } + + public class ThresholdFinder : ReadOnlyVisitor + { + readonly Implementation Impl; + public ThresholdFinder(Implementation impl) { + Contract.Requires(impl != null); + Impl = impl; + } + HashSet downs = new HashSet(); + HashSet ups = new HashSet(); + public void Find(out List downThresholds, out List upThresholds) { + // always include -1, 0, 1 as down-thresholds + downs.Clear(); + downs.Add(-1); + downs.Add(0); + downs.Add(1); + // always include 0 and 1 as up-thresholds + ups.Clear(); + ups.Add(0); + ups.Add(1); + + foreach (Requires p in Impl.Proc.Requires) { + Visit(p.Condition); + } + foreach (Ensures p in Impl.Proc.Ensures) { + Visit(p.Condition); + } + foreach (var b in Impl.Blocks) { + foreach (Cmd c in b.Cmds) { + Visit(c); + } + } + + // convert the HashSets to sorted Lists and return + downThresholds = new List(); + foreach (var i in downs) { + downThresholds.Add(i); + } + downThresholds.Sort(); + upThresholds = new List(); + foreach (var i in ups) { + upThresholds.Add(i); + } + upThresholds.Sort(); + } + + public override Expr VisitNAryExpr(NAryExpr node) { + if (node.Fun is BinaryOperator) { + var op = (BinaryOperator)node.Fun; + Contract.Assert(node.Args.Count == 2); + var arg0 = node.Args[0]; + var arg1 = node.Args[1]; + var offset = arg0.Type.IsReal ? 0 : 1; + BigInteger? k; + switch (op.Op) { + case BinaryOperator.Opcode.Eq: + case BinaryOperator.Opcode.Neq: + k = AsIntLiteral(arg0); + if (k != null) { + var i = (BigInteger)k; + downs.Add(i - 1); + downs.Add(i); + ups.Add(i + 1); + ups.Add(i + 2); + } + k = AsIntLiteral(arg1); + if (k != null) { + var i = (BigInteger)k; + downs.Add(i - 1); + downs.Add(i); + ups.Add(i + 1); + ups.Add(i + 2); + } + break; + case BinaryOperator.Opcode.Le: + k = AsIntLiteral(arg0); + if (k != null) { + var i = (BigInteger)k; + downs.Add(i - 1); + downs.Add(i); + } + k = AsIntLiteral(arg1); + if (k != null) { + var i = (BigInteger)k; + ups.Add(i + offset); + ups.Add(i + 1 + offset); + } + break; + case BinaryOperator.Opcode.Lt: + k = AsIntLiteral(arg0); + if (k != null) { + var i = (BigInteger)k; + downs.Add(i ); + downs.Add(i + 1); + } + k = AsIntLiteral(arg1); + if (k != null) { + var i = (BigInteger)k; + ups.Add(i - 1 + offset); + ups.Add(i + offset); + } + break; + case BinaryOperator.Opcode.Ge: + { var tmp = arg0; arg0 = arg1; arg1 = tmp; } + goto case BinaryOperator.Opcode.Le; + case BinaryOperator.Opcode.Gt: + { var tmp = arg0; arg0 = arg1; arg1 = tmp; } + goto case BinaryOperator.Opcode.Lt; + default: + break; + } + } + return base.VisitNAryExpr(node); + } + + BigInteger? AsIntLiteral(Expr e) { + var lit = e as LiteralExpr; + if (lit != null && lit.isBigNum) { + BigNum bn = lit.asBigNum; + return bn.ToBigInteger; + } + return null; + } + } + +} diff --git a/Source/AbsInt/NativeLattice.cs b/Source/AbsInt/NativeLattice.cs index 30014643..d1ae215a 100644 --- a/Source/AbsInt/NativeLattice.cs +++ b/Source/AbsInt/NativeLattice.cs @@ -1,335 +1,335 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Diagnostics.Contracts; -using Microsoft.Boogie; - -namespace Microsoft.Boogie.AbstractInterpretation -{ - /// - /// Specifies the operations (e.g., join) on a mathematical lattice that depend - /// only on the elements of the lattice. - /// - public abstract class NativeLattice - { - /// - /// An element of the lattice. This class should be derived from in any - /// implementation of MathematicalLattice. - /// - public abstract class Element - { - public abstract Expr ToExpr(); - } - - public abstract Element Top { get; } - public abstract Element Bottom { get; } - - public abstract bool IsTop(Element element); - public abstract bool IsBottom(Element element); - - /// - /// Is 'a' better (or equal) information than 'b'? That is, is 'a' below 'b' in the lattice? - /// - public abstract bool Below(Element a, Element b); - - public abstract Element Meet(Element a, Element b); - public abstract Element Join(Element a, Element b); - public abstract Element Widen(Element a, Element b); - - public abstract Element Constrain(Element element, Expr expr); - public abstract Element Update(Element element, AssignCmd cmd); // requiers 'cmd' to be a simple (possibly parallel) assignment command - public abstract Element Eliminate(Element element, Variable v); - - /// - /// Specialize the lattice to implementation "impl", if non-null. - /// If "impl" is null, remove specialization. - /// - public virtual void Specialize(Implementation impl) { - } - - public virtual void Validate() { - Contract.Assert(IsTop(Top)); - Contract.Assert(IsBottom(Bottom)); - Contract.Assert(!IsBottom(Top)); - Contract.Assert(!IsTop(Bottom)); - - Contract.Assert(Below(Top, Top)); - Contract.Assert(Below(Bottom, Top)); - Contract.Assert(Below(Bottom, Bottom)); - - Contract.Assert(IsTop(Join(Top, Top))); - Contract.Assert(IsBottom(Join(Bottom, Bottom))); - } - } - - public class NativeAbstractInterpretation - { - public static void RunAbstractInterpretation(Program program) { - Contract.Requires(program != null); - - if (!CommandLineOptions.Clo.UseAbstractInterpretation) { - return; - } - Helpers.ExtraTraceInformation("Starting abstract interpretation"); - - DateTime start = new DateTime(); // to please compiler's definite assignment rules - if (CommandLineOptions.Clo.Trace) { - Console.WriteLine(); - Console.WriteLine("Running abstract interpretation..."); - start = DateTime.UtcNow; - } - - WidenPoints.Compute(program); - - NativeLattice lattice = null; - if (CommandLineOptions.Clo.Ai.J_Trivial) { - lattice = new TrivialDomain(); - } else if (CommandLineOptions.Clo.Ai.J_Intervals) { - lattice = new NativeIntervallDomain(); - } - - if (lattice != null) { - Dictionary procedureImplementations = ComputeProcImplMap(program); - ComputeProgramInvariants(program, procedureImplementations, lattice); - if (CommandLineOptions.Clo.Ai.DebugStatistics) { - Console.Error.WriteLine(lattice); - } - } - - if (CommandLineOptions.Clo.Trace) { - DateTime end = DateTime.UtcNow; - TimeSpan elapsed = end - start; - Console.WriteLine(" [{0} s]", elapsed.TotalSeconds); - Console.Out.Flush(); - } - } - - private static Dictionary ComputeProcImplMap(Program program) { - Contract.Requires(program != null); - // Since implementations call procedures (impl. signatures) - // rather than directly calling other implementations, we first - // need to compute which implementations implement which - // procedures and remember which implementations call which - // procedures. - - return program - .Implementations - .GroupBy(i => i.Proc).Select(g => g.ToArray()).ToDictionary(a => a[0].Proc); - } - - /// - /// Compute and apply the invariants for the program using the underlying abstract domain. - /// - public static void ComputeProgramInvariants(Program program, Dictionary procedureImplementations, NativeLattice lattice) { - Contract.Requires(program != null); - Contract.Requires(procedureImplementations != null); - Contract.Requires(lattice != null); - - // Gather all the axioms to create the initial lattice element - // Differently stated, it is the \alpha from axioms (i.e. first order formulae) to the underlyng abstract domain - var initialElement = lattice.Top; - Contract.Assert(initialElement != null); - foreach (var ax in program.Axioms) { - initialElement = lattice.Constrain(initialElement, ax.Expr); - } - - // analyze each procedure - foreach (var proc in program.Procedures) { - if (procedureImplementations.ContainsKey(proc)) { - // analyze each implementation of the procedure - foreach (var impl in procedureImplementations[proc]) { - // add the precondition to the axioms - Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap()); - var start = initialElement; - foreach (Requires pre in proc.Requires) { - Expr e = Substituter.Apply(formalProcImplSubst, pre.Condition); - start = lattice.Constrain(start, e); - } - - lattice.Specialize(impl); - Analyze(impl, lattice, start); - lattice.Specialize(null); - } - } - } - } - - public static void Analyze(Implementation impl, NativeLattice lattice, NativeLattice.Element start) { - // We need to keep track of some information for each(some) block(s). To do that efficiently, - // we number the implementation's blocks sequentially, and then we can use arrays to store - // the additional information. - var pre = new NativeLattice.Element[impl.Blocks.Count]; // set to null if we never compute a join/widen at this block - var post = CommandLineOptions.Clo.InstrumentInfer == CommandLineOptions.InstrumentationPlaces.Everywhere ? new NativeLattice.Element[impl.Blocks.Count] : null; - var iterations = new int[impl.Blocks.Count]; - var bottom = lattice.Bottom; - int n = 0; - foreach (var block in impl.Blocks) { - block.aiId = n; - // Note: The forward analysis below will store lattice elements in pre[n] if pre[n] is non-null. - // Thus, the assignment "pre[n] = bottom;" below must be done under the following condition: - // n == 0 || block.widenBlock - // One possible strategy would be to do it only under that condition. Alternatively, - // one could do the assignment under the following condition: - // n == 0 || block.widenBlock || block.Predecessors.Length != 1 - // (which would require first setting the Predecessors field). In any case, if - // CommandLineOptions.Clo.InstrumentInfer == CommandLineOptions.InstrumentationPlaces.Everywhere - // then all pre[n] should be set. - pre[n] = bottom; - n++; - } - Contract.Assert(n == impl.Blocks.Count); - - var workItems = new Queue>(); - workItems.Enqueue(new Tuple(impl.Blocks[0], start)); - //ComputeBlockInvariantsNative(impl, ); - // compute a fixpoint here - while (workItems.Count > 0) { - var workItem = workItems.Dequeue(); - var b = workItem.Item1; - var id = b.aiId; - var e = workItem.Item2; - if (pre[id] == null) { - // no pre information stored here, so just go ahead through the block - } else if (lattice.Below(e, pre[id])) { - // no change - continue; - } else if (b.widenBlock && CommandLineOptions.Clo.StepsBeforeWidening <= iterations[id]) { - e = lattice.Widen(pre[id], e); - pre[id] = e; - iterations[id]++; - } else { - e = lattice.Join(pre[id], e); - pre[id] = e; - iterations[id]++; - } - - // propagate'e' through b.Cmds - foreach (Cmd cmd in b.Cmds) { - e = Step(lattice, cmd, e); - } - - if (post != null && pre[id] != null) { - post[id] = e; - } - - var g = b.TransferCmd as GotoCmd; - if (g != null) { // if g==null, it's a pity we didn't pay attention to that earlier, because then we could have skipped analyzing the code in this block - foreach (Block succ in g.labelTargets) { - workItems.Enqueue(new Tuple(succ, e)); - } - } - } - - Instrument(impl, pre, post); - } - - static void Instrument(Implementation impl, NativeLattice.Element[] pre, NativeLattice.Element[] post) { - Contract.Requires(impl != null); - Contract.Requires(pre != null); - - foreach (var b in impl.Blocks) { - var element = pre[b.aiId]; - if (element != null && (b.widenBlock || CommandLineOptions.Clo.InstrumentInfer == CommandLineOptions.InstrumentationPlaces.Everywhere)) { - List newCommands = new List(); - Expr inv = element.ToExpr(); - PredicateCmd cmd; - var kv = new QKeyValue(Token.NoToken, "inferred", new List(), null); - if (CommandLineOptions.Clo.InstrumentWithAsserts) { - cmd = new AssertCmd(Token.NoToken, inv, kv); - } else { - cmd = new AssumeCmd(Token.NoToken, inv, kv); - } - newCommands.Add(cmd); - newCommands.AddRange(b.Cmds); - if (post != null && post[b.aiId] != null) { - inv = post[b.aiId].ToExpr(); - kv = new QKeyValue(Token.NoToken, "inferred", new List(), null); - if (CommandLineOptions.Clo.InstrumentWithAsserts) { - cmd = new AssertCmd(Token.NoToken, inv, kv); - } else { - cmd = new AssumeCmd(Token.NoToken, inv, kv); - } - newCommands.Add(cmd); - } - b.Cmds = newCommands; // destructively replace the commands of the block - } - } - } - - /// - /// The abstract transition relation. - /// 'cmd' is allowed to be a StateCmd. - /// - static NativeLattice.Element Step(NativeLattice lattice, Cmd cmd, NativeLattice.Element elmt) { - Contract.Requires(lattice != null); - Contract.Requires(cmd != null); - Contract.Requires(elmt != null); - Contract.Ensures(Contract.Result() != null); - - if (cmd is AssignCmd) { // parallel assignment - var c = (AssignCmd)cmd; - elmt = lattice.Update(elmt, c.AsSimpleAssignCmd); - } else if (cmd is HavocCmd) { - var c = (HavocCmd)cmd; - foreach (IdentifierExpr id in c.Vars) { - Contract.Assert(id != null); - elmt = lattice.Eliminate(elmt, id.Decl); - } - } else if (cmd is PredicateCmd) { - var c = (PredicateCmd)cmd; - var conjuncts = new List(); - foreach (var ee in Conjuncts(c.Expr)) { - Contract.Assert(ee != null); - elmt = lattice.Constrain(elmt, ee); - } - } else if (cmd is StateCmd) { - var c = (StateCmd)cmd; - // Iterate the abstract transition on all the commands in the desugaring of the call - foreach (Cmd callDesug in c.Cmds) { - Contract.Assert(callDesug != null); - elmt = Step(lattice, callDesug, elmt); - } - // Project out the local variables of the StateCmd - foreach (Variable local in c.Locals) { - Contract.Assert(local != null); - elmt = lattice.Eliminate(elmt, local); - } - } else if (cmd is SugaredCmd) { - var c = (SugaredCmd)cmd; - elmt = Step(lattice, c.Desugaring, elmt); - } else if (cmd is CommentCmd) { - // skip - } else { - Contract.Assert(false); // unknown command - } - return elmt; - } - - /// - /// Yields the conjuncts of 'expr'. - /// - public static IEnumerable Conjuncts(Expr expr) { - Contract.Requires(expr != null); - - var e = expr as NAryExpr; - if (e != null && e.Fun.FunctionName == "&&") { // if it is a conjunction - foreach (Expr ee in e.Args) { - Contract.Assert(ee != null); - foreach (var c in Conjuncts(ee)) { - yield return c; - } - } - } else { - yield return expr; - } - } - - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Diagnostics.Contracts; +using Microsoft.Boogie; + +namespace Microsoft.Boogie.AbstractInterpretation +{ + /// + /// Specifies the operations (e.g., join) on a mathematical lattice that depend + /// only on the elements of the lattice. + /// + public abstract class NativeLattice + { + /// + /// An element of the lattice. This class should be derived from in any + /// implementation of MathematicalLattice. + /// + public abstract class Element + { + public abstract Expr ToExpr(); + } + + public abstract Element Top { get; } + public abstract Element Bottom { get; } + + public abstract bool IsTop(Element element); + public abstract bool IsBottom(Element element); + + /// + /// Is 'a' better (or equal) information than 'b'? That is, is 'a' below 'b' in the lattice? + /// + public abstract bool Below(Element a, Element b); + + public abstract Element Meet(Element a, Element b); + public abstract Element Join(Element a, Element b); + public abstract Element Widen(Element a, Element b); + + public abstract Element Constrain(Element element, Expr expr); + public abstract Element Update(Element element, AssignCmd cmd); // requiers 'cmd' to be a simple (possibly parallel) assignment command + public abstract Element Eliminate(Element element, Variable v); + + /// + /// Specialize the lattice to implementation "impl", if non-null. + /// If "impl" is null, remove specialization. + /// + public virtual void Specialize(Implementation impl) { + } + + public virtual void Validate() { + Contract.Assert(IsTop(Top)); + Contract.Assert(IsBottom(Bottom)); + Contract.Assert(!IsBottom(Top)); + Contract.Assert(!IsTop(Bottom)); + + Contract.Assert(Below(Top, Top)); + Contract.Assert(Below(Bottom, Top)); + Contract.Assert(Below(Bottom, Bottom)); + + Contract.Assert(IsTop(Join(Top, Top))); + Contract.Assert(IsBottom(Join(Bottom, Bottom))); + } + } + + public class NativeAbstractInterpretation + { + public static void RunAbstractInterpretation(Program program) { + Contract.Requires(program != null); + + if (!CommandLineOptions.Clo.UseAbstractInterpretation) { + return; + } + Helpers.ExtraTraceInformation("Starting abstract interpretation"); + + DateTime start = new DateTime(); // to please compiler's definite assignment rules + if (CommandLineOptions.Clo.Trace) { + Console.WriteLine(); + Console.WriteLine("Running abstract interpretation..."); + start = DateTime.UtcNow; + } + + WidenPoints.Compute(program); + + NativeLattice lattice = null; + if (CommandLineOptions.Clo.Ai.J_Trivial) { + lattice = new TrivialDomain(); + } else if (CommandLineOptions.Clo.Ai.J_Intervals) { + lattice = new NativeIntervallDomain(); + } + + if (lattice != null) { + Dictionary procedureImplementations = ComputeProcImplMap(program); + ComputeProgramInvariants(program, procedureImplementations, lattice); + if (CommandLineOptions.Clo.Ai.DebugStatistics) { + Console.Error.WriteLine(lattice); + } + } + + if (CommandLineOptions.Clo.Trace) { + DateTime end = DateTime.UtcNow; + TimeSpan elapsed = end - start; + Console.WriteLine(" [{0} s]", elapsed.TotalSeconds); + Console.Out.Flush(); + } + } + + private static Dictionary ComputeProcImplMap(Program program) { + Contract.Requires(program != null); + // Since implementations call procedures (impl. signatures) + // rather than directly calling other implementations, we first + // need to compute which implementations implement which + // procedures and remember which implementations call which + // procedures. + + return program + .Implementations + .GroupBy(i => i.Proc).Select(g => g.ToArray()).ToDictionary(a => a[0].Proc); + } + + /// + /// Compute and apply the invariants for the program using the underlying abstract domain. + /// + public static void ComputeProgramInvariants(Program program, Dictionary procedureImplementations, NativeLattice lattice) { + Contract.Requires(program != null); + Contract.Requires(procedureImplementations != null); + Contract.Requires(lattice != null); + + // Gather all the axioms to create the initial lattice element + // Differently stated, it is the \alpha from axioms (i.e. first order formulae) to the underlyng abstract domain + var initialElement = lattice.Top; + Contract.Assert(initialElement != null); + foreach (var ax in program.Axioms) { + initialElement = lattice.Constrain(initialElement, ax.Expr); + } + + // analyze each procedure + foreach (var proc in program.Procedures) { + if (procedureImplementations.ContainsKey(proc)) { + // analyze each implementation of the procedure + foreach (var impl in procedureImplementations[proc]) { + // add the precondition to the axioms + Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap()); + var start = initialElement; + foreach (Requires pre in proc.Requires) { + Expr e = Substituter.Apply(formalProcImplSubst, pre.Condition); + start = lattice.Constrain(start, e); + } + + lattice.Specialize(impl); + Analyze(impl, lattice, start); + lattice.Specialize(null); + } + } + } + } + + public static void Analyze(Implementation impl, NativeLattice lattice, NativeLattice.Element start) { + // We need to keep track of some information for each(some) block(s). To do that efficiently, + // we number the implementation's blocks sequentially, and then we can use arrays to store + // the additional information. + var pre = new NativeLattice.Element[impl.Blocks.Count]; // set to null if we never compute a join/widen at this block + var post = CommandLineOptions.Clo.InstrumentInfer == CommandLineOptions.InstrumentationPlaces.Everywhere ? new NativeLattice.Element[impl.Blocks.Count] : null; + var iterations = new int[impl.Blocks.Count]; + var bottom = lattice.Bottom; + int n = 0; + foreach (var block in impl.Blocks) { + block.aiId = n; + // Note: The forward analysis below will store lattice elements in pre[n] if pre[n] is non-null. + // Thus, the assignment "pre[n] = bottom;" below must be done under the following condition: + // n == 0 || block.widenBlock + // One possible strategy would be to do it only under that condition. Alternatively, + // one could do the assignment under the following condition: + // n == 0 || block.widenBlock || block.Predecessors.Length != 1 + // (which would require first setting the Predecessors field). In any case, if + // CommandLineOptions.Clo.InstrumentInfer == CommandLineOptions.InstrumentationPlaces.Everywhere + // then all pre[n] should be set. + pre[n] = bottom; + n++; + } + Contract.Assert(n == impl.Blocks.Count); + + var workItems = new Queue>(); + workItems.Enqueue(new Tuple(impl.Blocks[0], start)); + //ComputeBlockInvariantsNative(impl, ); + // compute a fixpoint here + while (workItems.Count > 0) { + var workItem = workItems.Dequeue(); + var b = workItem.Item1; + var id = b.aiId; + var e = workItem.Item2; + if (pre[id] == null) { + // no pre information stored here, so just go ahead through the block + } else if (lattice.Below(e, pre[id])) { + // no change + continue; + } else if (b.widenBlock && CommandLineOptions.Clo.StepsBeforeWidening <= iterations[id]) { + e = lattice.Widen(pre[id], e); + pre[id] = e; + iterations[id]++; + } else { + e = lattice.Join(pre[id], e); + pre[id] = e; + iterations[id]++; + } + + // propagate'e' through b.Cmds + foreach (Cmd cmd in b.Cmds) { + e = Step(lattice, cmd, e); + } + + if (post != null && pre[id] != null) { + post[id] = e; + } + + var g = b.TransferCmd as GotoCmd; + if (g != null) { // if g==null, it's a pity we didn't pay attention to that earlier, because then we could have skipped analyzing the code in this block + foreach (Block succ in g.labelTargets) { + workItems.Enqueue(new Tuple(succ, e)); + } + } + } + + Instrument(impl, pre, post); + } + + static void Instrument(Implementation impl, NativeLattice.Element[] pre, NativeLattice.Element[] post) { + Contract.Requires(impl != null); + Contract.Requires(pre != null); + + foreach (var b in impl.Blocks) { + var element = pre[b.aiId]; + if (element != null && (b.widenBlock || CommandLineOptions.Clo.InstrumentInfer == CommandLineOptions.InstrumentationPlaces.Everywhere)) { + List newCommands = new List(); + Expr inv = element.ToExpr(); + PredicateCmd cmd; + var kv = new QKeyValue(Token.NoToken, "inferred", new List(), null); + if (CommandLineOptions.Clo.InstrumentWithAsserts) { + cmd = new AssertCmd(Token.NoToken, inv, kv); + } else { + cmd = new AssumeCmd(Token.NoToken, inv, kv); + } + newCommands.Add(cmd); + newCommands.AddRange(b.Cmds); + if (post != null && post[b.aiId] != null) { + inv = post[b.aiId].ToExpr(); + kv = new QKeyValue(Token.NoToken, "inferred", new List(), null); + if (CommandLineOptions.Clo.InstrumentWithAsserts) { + cmd = new AssertCmd(Token.NoToken, inv, kv); + } else { + cmd = new AssumeCmd(Token.NoToken, inv, kv); + } + newCommands.Add(cmd); + } + b.Cmds = newCommands; // destructively replace the commands of the block + } + } + } + + /// + /// The abstract transition relation. + /// 'cmd' is allowed to be a StateCmd. + /// + static NativeLattice.Element Step(NativeLattice lattice, Cmd cmd, NativeLattice.Element elmt) { + Contract.Requires(lattice != null); + Contract.Requires(cmd != null); + Contract.Requires(elmt != null); + Contract.Ensures(Contract.Result() != null); + + if (cmd is AssignCmd) { // parallel assignment + var c = (AssignCmd)cmd; + elmt = lattice.Update(elmt, c.AsSimpleAssignCmd); + } else if (cmd is HavocCmd) { + var c = (HavocCmd)cmd; + foreach (IdentifierExpr id in c.Vars) { + Contract.Assert(id != null); + elmt = lattice.Eliminate(elmt, id.Decl); + } + } else if (cmd is PredicateCmd) { + var c = (PredicateCmd)cmd; + var conjuncts = new List(); + foreach (var ee in Conjuncts(c.Expr)) { + Contract.Assert(ee != null); + elmt = lattice.Constrain(elmt, ee); + } + } else if (cmd is StateCmd) { + var c = (StateCmd)cmd; + // Iterate the abstract transition on all the commands in the desugaring of the call + foreach (Cmd callDesug in c.Cmds) { + Contract.Assert(callDesug != null); + elmt = Step(lattice, callDesug, elmt); + } + // Project out the local variables of the StateCmd + foreach (Variable local in c.Locals) { + Contract.Assert(local != null); + elmt = lattice.Eliminate(elmt, local); + } + } else if (cmd is SugaredCmd) { + var c = (SugaredCmd)cmd; + elmt = Step(lattice, c.Desugaring, elmt); + } else if (cmd is CommentCmd) { + // skip + } else { + Contract.Assert(false); // unknown command + } + return elmt; + } + + /// + /// Yields the conjuncts of 'expr'. + /// + public static IEnumerable Conjuncts(Expr expr) { + Contract.Requires(expr != null); + + var e = expr as NAryExpr; + if (e != null && e.Fun.FunctionName == "&&") { // if it is a conjunction + foreach (Expr ee in e.Args) { + Contract.Assert(ee != null); + foreach (var c in Conjuncts(ee)) { + yield return c; + } + } + } else { + yield return expr; + } + } + + } +} diff --git a/Source/AbsInt/Traverse.cs b/Source/AbsInt/Traverse.cs index 184a4071..92377e56 100644 --- a/Source/AbsInt/Traverse.cs +++ b/Source/AbsInt/Traverse.cs @@ -1,169 +1,169 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.Boogie { - using System; - using System.Collections.Generic; - using System.Diagnostics.Contracts; - - - /// - /// This class provides the functionality of traversing a program to determine which - /// blocks are blocks where the widening operator may need to be applied. Assumes - /// all 'currentlyTraversed' bits to be initially false, and leaves them that way in - /// the end. Assumes the 'widenBlock' bits are initially false, and sets them - /// appropriately. - /// - public class WidenPoints { - /// - /// Compute the widen points of a program - /// - public static void Compute(Program program) { - Contract.Requires(program != null); - cce.BeginExpose(program); - - foreach (var impl in program.Implementations) { - if (impl.Blocks != null && impl.Blocks.Count > 0) { - Contract.Assume(cce.IsConsistent(impl)); - cce.BeginExpose(impl); - Block start = impl.Blocks[0]; - Contract.Assume(start != null); - Contract.Assume(cce.IsConsistent(start)); - Visit(start); - - // We reset the state... - foreach (Block b in impl.Blocks) { - cce.BeginExpose(b); - b.TraversingStatus = Block.VisitState.ToVisit; - cce.EndExpose(); - } - cce.EndExpose(); - } - } - cce.EndExpose(); - } - - static void Visit(Block b) { - Contract.Requires(b != null); - Contract.Assume(cce.IsExposable(b)); - if (b.TraversingStatus == Block.VisitState.BeingVisited) { - cce.BeginExpose(b); - // we got here through a back-edge - b.widenBlock = true; - cce.EndExpose(); - } else if (b.TraversingStatus == Block.VisitState.AlreadyVisited) { - // do nothing... we already saw this node - } else if (b.TransferCmd is GotoCmd) { - Contract.Assert(b.TraversingStatus == Block.VisitState.ToVisit); - - GotoCmd g = (GotoCmd)b.TransferCmd; - cce.BeginExpose(b); - - cce.BeginExpose(g); //PM: required for the subsequent expose (g.labelTargets) - b.TraversingStatus = Block.VisitState.BeingVisited; - - // labelTargets is made non-null by Resolve, which we assume - // has already called in a prior pass. - Contract.Assume(g.labelTargets != null); - cce.BeginExpose(g.labelTargets); - foreach (Block succ in g.labelTargets) - // invariant b.currentlyTraversed; - //PM: The following loop invariant will work once properties are axiomatized - //&& (g.labelNames != null && g.labelTargets != null ==> g.labelNames.Length == g.labelTargets.Length); - { - Contract.Assert(succ != null); - Visit(succ); - } - cce.EndExpose(); - - Contract.Assert(b.TraversingStatus == Block.VisitState.BeingVisited); - // System.Diagnostics.Debug.Assert(b.currentlyTraversed); - - b.TraversingStatus = Block.VisitState.AlreadyVisited; - - //PM: The folowing assumption is needed because we cannot prove that a simple field update - //PM: leaves the value of a property unchanged. - Contract.Assume(g.labelNames == null || g.labelNames.Count == g.labelTargets.Count); - cce.EndExpose(); - } else { - Contract.Assert(b.TransferCmd == null || b.TransferCmd is ReturnCmd); // It must be a returnCmd; - } - } - - static private Block rootBlock = null; // The root point we have to consider - - /// - /// Compute the blocks in the body loop. - /// Tt is the head of the loop. It must be a widen block - /// The blocks that are in the loop from block - /// - public static List ComputeLoopBodyFrom(Block block) { - Contract.Requires(block.widenBlock); - Contract.Requires(block != null); - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - - Contract.Assert(rootBlock == null); - rootBlock = block; - - List blocksInLoop = new List(); // We use a list just because .net does not define a set - List visitingPath = new List(); // The order is important, as we want paths - - blocksInLoop.Add(block); - - DoDFSVisit(block, visitingPath, blocksInLoop); - - visitingPath.Add(block); - - - rootBlock = null; // We reset the invariant - - return blocksInLoop; - } - - /// - /// Perform the Depth-first search of the so to find the loop - /// The block to visit - /// The path we are visiting so far - /// - private static void DoDFSVisit(Block block, List path, List blocksInPath) { - Contract.Requires(block != null); - Contract.Requires(cce.NonNullElements(path)); - Contract.Requires(cce.NonNullElements(path)); - #region case 1. We visit the root => We are done, "path" is a path inside the loop - if (block == rootBlock && path.Count > 1) { - blocksInPath.AddRange(path); // Add all the blocks in this path - } - - #endregion - #region case 2. We visit a node that ends with a return => "path" is not inside the loop - if (block.TransferCmd is ReturnCmd) { - return; - } - #endregion - #region case 3. We visit a node with successors => continue the exploration of its successors - { - Contract.Assert(block.TransferCmd is GotoCmd); - GotoCmd successors = (GotoCmd)block.TransferCmd; - Contract.Assert(successors != null); - - if (successors.labelTargets != null) - foreach (Block nextBlock in successors.labelTargets) { - Contract.Assert(nextBlock != null); - if (path.Contains(nextBlock)) // If the current path has already seen the block, just skip it - continue; - // Otherwise we perform the DFS visit - path.Add(nextBlock); - DoDFSVisit(nextBlock, path, blocksInPath); - - Contract.Assert(nextBlock == path[path.Count - 1]); - path.RemoveAt(path.Count - 1); - } - - } - - #endregion - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.Boogie { + using System; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + + + /// + /// This class provides the functionality of traversing a program to determine which + /// blocks are blocks where the widening operator may need to be applied. Assumes + /// all 'currentlyTraversed' bits to be initially false, and leaves them that way in + /// the end. Assumes the 'widenBlock' bits are initially false, and sets them + /// appropriately. + /// + public class WidenPoints { + /// + /// Compute the widen points of a program + /// + public static void Compute(Program program) { + Contract.Requires(program != null); + cce.BeginExpose(program); + + foreach (var impl in program.Implementations) { + if (impl.Blocks != null && impl.Blocks.Count > 0) { + Contract.Assume(cce.IsConsistent(impl)); + cce.BeginExpose(impl); + Block start = impl.Blocks[0]; + Contract.Assume(start != null); + Contract.Assume(cce.IsConsistent(start)); + Visit(start); + + // We reset the state... + foreach (Block b in impl.Blocks) { + cce.BeginExpose(b); + b.TraversingStatus = Block.VisitState.ToVisit; + cce.EndExpose(); + } + cce.EndExpose(); + } + } + cce.EndExpose(); + } + + static void Visit(Block b) { + Contract.Requires(b != null); + Contract.Assume(cce.IsExposable(b)); + if (b.TraversingStatus == Block.VisitState.BeingVisited) { + cce.BeginExpose(b); + // we got here through a back-edge + b.widenBlock = true; + cce.EndExpose(); + } else if (b.TraversingStatus == Block.VisitState.AlreadyVisited) { + // do nothing... we already saw this node + } else if (b.TransferCmd is GotoCmd) { + Contract.Assert(b.TraversingStatus == Block.VisitState.ToVisit); + + GotoCmd g = (GotoCmd)b.TransferCmd; + cce.BeginExpose(b); + + cce.BeginExpose(g); //PM: required for the subsequent expose (g.labelTargets) + b.TraversingStatus = Block.VisitState.BeingVisited; + + // labelTargets is made non-null by Resolve, which we assume + // has already called in a prior pass. + Contract.Assume(g.labelTargets != null); + cce.BeginExpose(g.labelTargets); + foreach (Block succ in g.labelTargets) + // invariant b.currentlyTraversed; + //PM: The following loop invariant will work once properties are axiomatized + //&& (g.labelNames != null && g.labelTargets != null ==> g.labelNames.Length == g.labelTargets.Length); + { + Contract.Assert(succ != null); + Visit(succ); + } + cce.EndExpose(); + + Contract.Assert(b.TraversingStatus == Block.VisitState.BeingVisited); + // System.Diagnostics.Debug.Assert(b.currentlyTraversed); + + b.TraversingStatus = Block.VisitState.AlreadyVisited; + + //PM: The folowing assumption is needed because we cannot prove that a simple field update + //PM: leaves the value of a property unchanged. + Contract.Assume(g.labelNames == null || g.labelNames.Count == g.labelTargets.Count); + cce.EndExpose(); + } else { + Contract.Assert(b.TransferCmd == null || b.TransferCmd is ReturnCmd); // It must be a returnCmd; + } + } + + static private Block rootBlock = null; // The root point we have to consider + + /// + /// Compute the blocks in the body loop. + /// Tt is the head of the loop. It must be a widen block + /// The blocks that are in the loop from block + /// + public static List ComputeLoopBodyFrom(Block block) { + Contract.Requires(block.widenBlock); + Contract.Requires(block != null); + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + + Contract.Assert(rootBlock == null); + rootBlock = block; + + List blocksInLoop = new List(); // We use a list just because .net does not define a set + List visitingPath = new List(); // The order is important, as we want paths + + blocksInLoop.Add(block); + + DoDFSVisit(block, visitingPath, blocksInLoop); + + visitingPath.Add(block); + + + rootBlock = null; // We reset the invariant + + return blocksInLoop; + } + + /// + /// Perform the Depth-first search of the so to find the loop + /// The block to visit + /// The path we are visiting so far + /// + private static void DoDFSVisit(Block block, List path, List blocksInPath) { + Contract.Requires(block != null); + Contract.Requires(cce.NonNullElements(path)); + Contract.Requires(cce.NonNullElements(path)); + #region case 1. We visit the root => We are done, "path" is a path inside the loop + if (block == rootBlock && path.Count > 1) { + blocksInPath.AddRange(path); // Add all the blocks in this path + } + + #endregion + #region case 2. We visit a node that ends with a return => "path" is not inside the loop + if (block.TransferCmd is ReturnCmd) { + return; + } + #endregion + #region case 3. We visit a node with successors => continue the exploration of its successors + { + Contract.Assert(block.TransferCmd is GotoCmd); + GotoCmd successors = (GotoCmd)block.TransferCmd; + Contract.Assert(successors != null); + + if (successors.labelTargets != null) + foreach (Block nextBlock in successors.labelTargets) { + Contract.Assert(nextBlock != null); + if (path.Contains(nextBlock)) // If the current path has already seen the block, just skip it + continue; + // Otherwise we perform the DFS visit + path.Add(nextBlock); + DoDFSVisit(nextBlock, path, blocksInPath); + + Contract.Assert(nextBlock == path[path.Count - 1]); + path.RemoveAt(path.Count - 1); + } + + } + + #endregion + } + } +} diff --git a/Source/AbsInt/TrivialDomain.cs b/Source/AbsInt/TrivialDomain.cs index f9298e11..123bcefe 100644 --- a/Source/AbsInt/TrivialDomain.cs +++ b/Source/AbsInt/TrivialDomain.cs @@ -1,79 +1,79 @@ -using System; -using System.Numerics; -using System.Collections.Generic; -using System.Diagnostics.Contracts; - -namespace Microsoft.Boogie.AbstractInterpretation -{ - class TrivialDomain : NativeLattice - { - class E : NativeLattice.Element - { - public readonly bool IsTop; - public E(bool isTop) { - IsTop = isTop; - } - - public override Expr ToExpr() { - return Expr.Literal(IsTop); - } - } - - private E top = new E(true); - private E bottom = new E(false); - - public override Element Top { get { return top; } } - public override Element Bottom { get { return bottom; } } - - public override bool IsTop(Element element) { - var e = (E)element; - return e.IsTop; - } - public override bool IsBottom(Element element) { - var e = (E)element; - return !e.IsTop; - } - - public override bool Below(Element a, Element b) { - return IsBottom(a) || IsTop(b); - } - - public override Element Meet(Element a, Element b) { - if (IsBottom(b)) { - return b; - } else { - return a; - } - } - - public override Element Join(Element a, Element b) { - if (IsTop(b)) { - return b; - } else { - return a; - } - } - - public override Element Widen(Element a, Element b) { - return Join(a, b); // it's a finite domain, after all - } - - public override Element Constrain(Element element, Expr expr) { - var e = (E)element; - var lit = expr as LiteralExpr; - if (lit != null && lit.isBool && !(bool)lit.Val) { - return bottom; - } else { - return e; - } - } - - public override Element Update(Element element, AssignCmd cmd) { - return element; - } - - public override Element Eliminate(Element element, Variable v) { - return element; - } - } -} +using System; +using System.Numerics; +using System.Collections.Generic; +using System.Diagnostics.Contracts; + +namespace Microsoft.Boogie.AbstractInterpretation +{ + class TrivialDomain : NativeLattice + { + class E : NativeLattice.Element + { + public readonly bool IsTop; + public E(bool isTop) { + IsTop = isTop; + } + + public override Expr ToExpr() { + return Expr.Literal(IsTop); + } + } + + private E top = new E(true); + private E bottom = new E(false); + + public override Element Top { get { return top; } } + public override Element Bottom { get { return bottom; } } + + public override bool IsTop(Element element) { + var e = (E)element; + return e.IsTop; + } + public override bool IsBottom(Element element) { + var e = (E)element; + return !e.IsTop; + } + + public override bool Below(Element a, Element b) { + return IsBottom(a) || IsTop(b); + } + + public override Element Meet(Element a, Element b) { + if (IsBottom(b)) { + return b; + } else { + return a; + } + } + + public override Element Join(Element a, Element b) { + if (IsTop(b)) { + return b; + } else { + return a; + } + } + + public override Element Widen(Element a, Element b) { + return Join(a, b); // it's a finite domain, after all + } + + public override Element Constrain(Element element, Expr expr) { + var e = (E)element; + var lit = expr as LiteralExpr; + if (lit != null && lit.isBool && !(bool)lit.Val) { + return bottom; + } else { + return e; + } + } + + public override Element Update(Element element, AssignCmd cmd) { + return element; + } + + public override Element Eliminate(Element element, Variable v) { + return element; + } + } +} diff --git a/Source/AbsInt/cce.cs b/Source/AbsInt/cce.cs index 693d608c..627add75 100644 --- a/Source/AbsInt/cce.cs +++ b/Source/AbsInt/cce.cs @@ -1,62 +1,62 @@ - -using System; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Text; -using Microsoft.Boogie; - - /// - /// A class containing static methods to extend the functionality of Code Contracts - /// - -public static class cce { - [Pure] - public static T NonNull(T t) { - Contract.Assert(t != null); - return t; - } - [Pure] - public static bool NonNullElements(IEnumerable collection) { - return collection != null && Contract.ForAll(collection, c => c != null); - } - [Pure] - public static bool NonNullElements(VariableSeq collection) { - return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); - } - - public class UnreachableException : Exception { - public UnreachableException() { - } - } - - [Pure] - public static void BeginExpose(object o) { - } - [Pure] - public static void EndExpose() { - } - - public static bool IsPeerConsistent(this object o) { - return true; - } - - public static bool IsConsistent(this object o) { - return true; - } - - public static bool IsExposable(this object o) { - return true; - } - public static class Owner { - [Pure] - public static bool Same(object o, object p) { - return true; - } - } -} -public class PeerAttribute : System.Attribute { -} -public class RepAttribute : System.Attribute { -} -public class CapturedAttribute : System.Attribute { -} + +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Text; +using Microsoft.Boogie; + + /// + /// A class containing static methods to extend the functionality of Code Contracts + /// + +public static class cce { + [Pure] + public static T NonNull(T t) { + Contract.Assert(t != null); + return t; + } + [Pure] + public static bool NonNullElements(IEnumerable collection) { + return collection != null && Contract.ForAll(collection, c => c != null); + } + [Pure] + public static bool NonNullElements(VariableSeq collection) { + return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); + } + + public class UnreachableException : Exception { + public UnreachableException() { + } + } + + [Pure] + public static void BeginExpose(object o) { + } + [Pure] + public static void EndExpose() { + } + + public static bool IsPeerConsistent(this object o) { + return true; + } + + public static bool IsConsistent(this object o) { + return true; + } + + public static bool IsExposable(this object o) { + return true; + } + public static class Owner { + [Pure] + public static bool Same(object o, object p) { + return true; + } + } +} +public class PeerAttribute : System.Attribute { +} +public class RepAttribute : System.Attribute { +} +public class CapturedAttribute : System.Attribute { +} diff --git a/Source/BVD/App.config b/Source/BVD/App.config index fad249e4..8e156463 100644 --- a/Source/BVD/App.config +++ b/Source/BVD/App.config @@ -1,6 +1,6 @@ - - - - - + + + + + \ No newline at end of file diff --git a/Source/BVD/BVD.csproj b/Source/BVD/BVD.csproj index ccf52191..e83cfdd7 100644 --- a/Source/BVD/BVD.csproj +++ b/Source/BVD/BVD.csproj @@ -1,106 +1,106 @@ - - - - - Debug - AnyCPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797} - WinExe - Properties - Microsoft.Boogie.ModelViewer - BVD - 512 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - 12.0.0 - 2.0 - - - AnyCPU - true - full - false - ..\..\Binaries\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - ..\..\Binaries\ - TRACE - prompt - 4 - - - true - bin\QED\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - - - - - - - - - - - - - - - - - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C} - ModelViewer - - - - - False - Microsoft .NET Framework 4.5 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - - - + + + + + Debug + AnyCPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797} + WinExe + Properties + Microsoft.Boogie.ModelViewer + BVD + 512 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + 12.0.0 + 2.0 + + + AnyCPU + true + full + false + ..\..\Binaries\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + ..\..\Binaries\ + TRACE + prompt + 4 + + + true + bin\QED\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + + + + + + + + + + + + + + + + + + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C} + ModelViewer + + + + + False + Microsoft .NET Framework 4.5 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + + + + diff --git a/Source/BVD/Program.cs b/Source/BVD/Program.cs index 669ea995..a606c863 100644 --- a/Source/BVD/Program.cs +++ b/Source/BVD/Program.cs @@ -1,28 +1,28 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Windows.Forms; - -namespace Microsoft.Boogie.ModelViewer -{ - static class Program - { - /// - /// The main entry point for the application. - /// - [STAThread] - static void Main() - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - try - { - Application.Run(new Main(System.Environment.GetCommandLineArgs())); - } - catch (Exception exc) - { - MessageBox.Show(exc.Message, "Model Viewer Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; + +namespace Microsoft.Boogie.ModelViewer +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + try + { + Application.Run(new Main(System.Environment.GetCommandLineArgs())); + } + catch (Exception exc) + { + MessageBox.Show(exc.Message, "Model Viewer Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); + } + } + } +} diff --git a/Source/BVD/Properties/AssemblyInfo.cs b/Source/BVD/Properties/AssemblyInfo.cs index 3512374e..0e9c953a 100644 --- a/Source/BVD/Properties/AssemblyInfo.cs +++ b/Source/BVD/Properties/AssemblyInfo.cs @@ -1,36 +1,36 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("BVD")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("BVD")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("00610a12-cf4c-4c29-af30-31a99d22b9d8")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("BVD")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("BVD")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("00610a12-cf4c-4c29-af30-31a99d22b9d8")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Source/Basetypes/Basetypes.csproj b/Source/Basetypes/Basetypes.csproj index 4ecdee8d..5b425bc5 100644 --- a/Source/Basetypes/Basetypes.csproj +++ b/Source/Basetypes/Basetypes.csproj @@ -1,204 +1,204 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} - Library - Properties - Basetypes - Basetypes - v4.0 - 512 - 1 - true - ..\InterimKey.snk - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - Client - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - False - False - True - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - - - - - - - Full - %28none%29 - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - true - bin\z3apidebug\ - DEBUG;TRACE - full - AnyCPU - - - true - GlobalSuppressions.cs - prompt - Migrated rules for Basetypes.ruleset - true - 4 - false - - - true - bin\Checked\ - DEBUG;TRACE - full - AnyCPU - bin\Debug\Basetypes.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - True - False - True - False - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - False - Full - Build - 0 - 4 - false - - - true - bin\QED\ - DEBUG;TRACE - full - AnyCPU - prompt - AllRules.ruleset - - - - - - - - - - version.cs - - - - - - - - - - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} - CodeContractsExtender - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - + + + + Debug + AnyCPU + 9.0.21022 + 2.0 + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} + Library + Properties + Basetypes + BoogieBasetypes + v4.0 + 512 + 1 + true + ..\InterimKey.snk + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + False + False + True + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + + + + + + + Full + %28none%29 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + true + bin\z3apidebug\ + DEBUG;TRACE + full + AnyCPU + + + true + GlobalSuppressions.cs + prompt + Migrated rules for Basetypes.ruleset + true + 4 + false + + + true + bin\Checked\ + DEBUG;TRACE + full + AnyCPU + bin\Debug\Basetypes.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + True + False + True + False + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + False + Full + Build + 0 + 4 + false + + + true + bin\QED\ + DEBUG;TRACE + full + AnyCPU + prompt + AllRules.ruleset + + + + + + + + + + version.cs + + + + + + + + + + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} + CodeContractsExtender + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + \ No newline at end of file diff --git a/Source/Basetypes/BigDec.cs b/Source/Basetypes/BigDec.cs index 0aeea8b1..e4666793 100644 --- a/Source/Basetypes/BigDec.cs +++ b/Source/Basetypes/BigDec.cs @@ -1,380 +1,380 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Text; -using System.Diagnostics.Contracts; -using System.Diagnostics; - - -namespace Microsoft.Basetypes { - using BIM = System.Numerics.BigInteger; - - - /// - /// A representation of decimal values. - /// - public struct BigDec { - - // the internal representation - [Rep] - internal readonly BIM mantissa; - [Rep] - internal readonly int exponent; - - public BIM Mantissa { - get { - return mantissa; - } - } - - public int Exponent { - get { - return exponent; - } - } - - public static readonly BigDec ZERO = FromInt(0); - private static readonly BIM ten = new BIM(10); - - - //////////////////////////////////////////////////////////////////////////// - // Constructors - - [Pure] - public static BigDec FromInt(int v) { - return new BigDec(v, 0); - } - - [Pure] - public static BigDec FromBigInt(BIM v) { - return new BigDec(v, 0); - } - - [Pure] - public static BigDec FromString(string v) { - if (v == null) throw new FormatException(); - - BIM integral = BIM.Zero; - BIM fraction = BIM.Zero; - int exponent = 0; - - int len = v.Length; - - int i = v.IndexOf('e'); - if (i >= 0) { - if (i + 1 == v.Length) throw new FormatException(); - exponent = Int32.Parse(v.Substring(i + 1, len - i - 1)); - len = i; - } - - int fractionLen = 0; - i = v.IndexOf('.'); - if (i >= 0) { - if (i + 1 == v.Length) throw new FormatException(); - fractionLen = len - i - 1; - fraction = BIM.Parse(v.Substring(i + 1, fractionLen)); - len = i; - } - - integral = BIM.Parse(v.Substring(0, len)); - - if (!fraction.IsZero) { - while (fractionLen > 0) { - integral = integral * ten; - exponent = exponent - 1; - fractionLen = fractionLen - 1; - } - } - - if (integral.Sign == -1) { - return new BigDec(integral - fraction, exponent); - } - else { - return new BigDec(integral + fraction, exponent); - } - } - - internal BigDec(BIM mantissa, int exponent) { - if (mantissa.IsZero) { - this.mantissa = mantissa; - this.exponent = 0; - } - else { - while (mantissa % ten == BIM.Zero) { - mantissa = mantissa / ten; - exponent = exponent + 1; - } - this.mantissa = mantissa; - this.exponent = exponent; - } - } - - - //////////////////////////////////////////////////////////////////////////// - // Basic object operations - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is BigDec)) - return false; - - return (this == (BigDec)obj); - } - - [Pure] - public override int GetHashCode() { - return this.mantissa.GetHashCode() * 13 + this.exponent.GetHashCode(); - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return String.Format("{0}e{1}", this.mantissa.ToString(), this.exponent.ToString()); - } - - - //////////////////////////////////////////////////////////////////////////// - // Conversion operations - - // ``floor`` rounds towards negative infinity (like SMT-LIBv2's to_int). - /// - /// Computes the floor and ceiling of this BigDec. Note the choice of rounding towards negative - /// infinity rather than zero for floor is because SMT-LIBv2's to_int function floors this way. - /// - /// The Floor (rounded towards negative infinity) - /// Ceiling (rounded towards positive infinity) - public void FloorCeiling(out BIM floor, out BIM ceiling) { - BIM n = this.mantissa; - int e = this.exponent; - if (n.IsZero) { - floor = ceiling = n; - } else if (0 <= e) { - // it's an integer - for (; 0 < e; e--) { - n = n * ten; - } - floor = ceiling = n; - } else { - // it's a non-zero integer, so the ceiling is one more than the floor - for (; e < 0 && !n.IsZero; e++) { - n = n / ten; // Division rounds towards negative infinity - } - - if (this.mantissa >= 0) { - floor = n; - ceiling = n + 1; - } else { - ceiling = n; - floor = n - 1; - } - } - Debug.Assert(floor <= ceiling, "Invariant was not maintained"); - } - - [Pure] - public String ToDecimalString(int maxDigits) { - string s = this.mantissa.ToString(); - int digits = (this.mantissa >= 0) ? s.Length : s.Length - 1; - BIM max = BIM.Pow(10, maxDigits); - BIM min = -max; - - if (this.exponent >= 0) { - if (maxDigits < digits || maxDigits - digits < this.exponent) { - return String.Format("{0}.0", (this.mantissa >= 0) ? max.ToString() : min.ToString()); - } - else { - return String.Format("{0}{1}.0", s, new string('0', this.exponent)); - } - } - else { - int exp = -this.exponent; - - if (exp < digits) { - int intDigits = digits - exp; - if (maxDigits < intDigits) { - return String.Format("{0}.0", (this.mantissa >= 0) ? max.ToString() : min.ToString()); - } - else { - int fracDigits = Math.Min(maxDigits, digits - intDigits); - return String.Format("{0}.{1}", s.Substring(0, intDigits), s.Substring(intDigits, fracDigits)); - } - } - else { - int fracDigits = Math.Min(maxDigits, digits); - return String.Format("0.{0}{1}", new string('0', exp - fracDigits), s.Substring(0, fracDigits)); - } - } - } - - [Pure] - public string ToDecimalString() { - string m = this.mantissa.ToString(); - var e = this.exponent; - if (0 <= this.exponent) { - return m + Zeros(e) + ".0"; - } else { - e = -e; - // compute k to be the longest suffix of m consisting of all zeros (but no longer than e, and not the entire string) - var maxK = e < m.Length ? e : m.Length - 1; - var last = m.Length - 1; - var k = 0; - while (k < maxK && m[last - k] == '0') { - k++; - } - if (0 < k) { - // chop off the suffix of k zeros from m and adjust e accordingly - m = m.Substring(0, m.Length - k); - e -= k; - } - if (e == 0) { - return m; - } else if (e < m.Length) { - var n = m.Length - e; - return m.Substring(0, n) + "." + m.Substring(n); - } else { - return "0." + Zeros(e - m.Length) + m; - } - } - } - - [Pure] - public static string Zeros(int n) { - Contract.Requires(0 <= n); - if (n <= 10) { - var tenZeros = "0000000000"; - return tenZeros.Substring(0, n); - } else { - var d = n / 2; - var s = Zeros(d); - if (n % 2 == 0) { - return s + s; - } else { - return s + s + "0"; - } - } - } - - - //////////////////////////////////////////////////////////////////////////// - // Basic arithmetic operations - - [Pure] - public BigDec Abs { - get { - return new BigDec(BIM.Abs(this.mantissa), this.exponent); - } - } - - [Pure] - public BigDec Negate { - get { - return new BigDec(BIM.Negate(this.mantissa), this.exponent); - } - } - - [Pure] - public static BigDec operator -(BigDec x) { - return x.Negate; - } - - [Pure] - public static BigDec operator +(BigDec x, BigDec y) { - BIM m1 = x.mantissa; - int e1 = x.exponent; - BIM m2 = y.mantissa; - int e2 = y.exponent; - if (e2 < e1) { - m1 = y.mantissa; - e1 = y.exponent; - m2 = x.mantissa; - e2 = x.exponent; - } - - while (e2 > e1) { - m2 = m2 * ten; - e2 = e2 - 1; - } - - return new BigDec(m1 + m2, e1); - } - - [Pure] - public static BigDec operator -(BigDec x, BigDec y) { - return x + y.Negate; - } - - [Pure] - public static BigDec operator *(BigDec x, BigDec y) { - return new BigDec(x.mantissa * y.mantissa, x.exponent + y.exponent); - } - - - //////////////////////////////////////////////////////////////////////////// - // Some basic comparison operations - - public bool IsPositive { - get { - return (this.mantissa > BIM.Zero); - } - } - - public bool IsNegative { - get { - return (this.mantissa < BIM.Zero); - } - } - - public bool IsZero { - get { - return this.mantissa.IsZero; - } - } - - [Pure] - public int CompareTo(BigDec that) { - if (this.mantissa == that.mantissa && this.exponent == that.exponent) { - return 0; - } - else { - BigDec d = this - that; - return d.IsNegative ? -1 : 1; - } - } - - [Pure] - public static bool operator ==(BigDec x, BigDec y) { - return x.CompareTo(y) == 0; - } - - [Pure] - public static bool operator !=(BigDec x, BigDec y) { - return x.CompareTo(y) != 0; - } - - [Pure] - public static bool operator <(BigDec x, BigDec y) { - return x.CompareTo(y) < 0; - } - - [Pure] - public static bool operator >(BigDec x, BigDec y) { - return x.CompareTo(y) > 0; - } - - [Pure] - public static bool operator <=(BigDec x, BigDec y) { - return x.CompareTo(y) <= 0; - } - - [Pure] - public static bool operator >=(BigDec x, BigDec y) { - return x.CompareTo(y) >= 0; - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Text; +using System.Diagnostics.Contracts; +using System.Diagnostics; + + +namespace Microsoft.Basetypes { + using BIM = System.Numerics.BigInteger; + + + /// + /// A representation of decimal values. + /// + public struct BigDec { + + // the internal representation + [Rep] + internal readonly BIM mantissa; + [Rep] + internal readonly int exponent; + + public BIM Mantissa { + get { + return mantissa; + } + } + + public int Exponent { + get { + return exponent; + } + } + + public static readonly BigDec ZERO = FromInt(0); + private static readonly BIM ten = new BIM(10); + + + //////////////////////////////////////////////////////////////////////////// + // Constructors + + [Pure] + public static BigDec FromInt(int v) { + return new BigDec(v, 0); + } + + [Pure] + public static BigDec FromBigInt(BIM v) { + return new BigDec(v, 0); + } + + [Pure] + public static BigDec FromString(string v) { + if (v == null) throw new FormatException(); + + BIM integral = BIM.Zero; + BIM fraction = BIM.Zero; + int exponent = 0; + + int len = v.Length; + + int i = v.IndexOf('e'); + if (i >= 0) { + if (i + 1 == v.Length) throw new FormatException(); + exponent = Int32.Parse(v.Substring(i + 1, len - i - 1)); + len = i; + } + + int fractionLen = 0; + i = v.IndexOf('.'); + if (i >= 0) { + if (i + 1 == v.Length) throw new FormatException(); + fractionLen = len - i - 1; + fraction = BIM.Parse(v.Substring(i + 1, fractionLen)); + len = i; + } + + integral = BIM.Parse(v.Substring(0, len)); + + if (!fraction.IsZero) { + while (fractionLen > 0) { + integral = integral * ten; + exponent = exponent - 1; + fractionLen = fractionLen - 1; + } + } + + if (integral.Sign == -1) { + return new BigDec(integral - fraction, exponent); + } + else { + return new BigDec(integral + fraction, exponent); + } + } + + internal BigDec(BIM mantissa, int exponent) { + if (mantissa.IsZero) { + this.mantissa = mantissa; + this.exponent = 0; + } + else { + while (mantissa % ten == BIM.Zero) { + mantissa = mantissa / ten; + exponent = exponent + 1; + } + this.mantissa = mantissa; + this.exponent = exponent; + } + } + + + //////////////////////////////////////////////////////////////////////////// + // Basic object operations + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is BigDec)) + return false; + + return (this == (BigDec)obj); + } + + [Pure] + public override int GetHashCode() { + return this.mantissa.GetHashCode() * 13 + this.exponent.GetHashCode(); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return String.Format("{0}e{1}", this.mantissa.ToString(), this.exponent.ToString()); + } + + + //////////////////////////////////////////////////////////////////////////// + // Conversion operations + + // ``floor`` rounds towards negative infinity (like SMT-LIBv2's to_int). + /// + /// Computes the floor and ceiling of this BigDec. Note the choice of rounding towards negative + /// infinity rather than zero for floor is because SMT-LIBv2's to_int function floors this way. + /// + /// The Floor (rounded towards negative infinity) + /// Ceiling (rounded towards positive infinity) + public void FloorCeiling(out BIM floor, out BIM ceiling) { + BIM n = this.mantissa; + int e = this.exponent; + if (n.IsZero) { + floor = ceiling = n; + } else if (0 <= e) { + // it's an integer + for (; 0 < e; e--) { + n = n * ten; + } + floor = ceiling = n; + } else { + // it's a non-zero integer, so the ceiling is one more than the floor + for (; e < 0 && !n.IsZero; e++) { + n = n / ten; // Division rounds towards negative infinity + } + + if (this.mantissa >= 0) { + floor = n; + ceiling = n + 1; + } else { + ceiling = n; + floor = n - 1; + } + } + Debug.Assert(floor <= ceiling, "Invariant was not maintained"); + } + + [Pure] + public String ToDecimalString(int maxDigits) { + string s = this.mantissa.ToString(); + int digits = (this.mantissa >= 0) ? s.Length : s.Length - 1; + BIM max = BIM.Pow(10, maxDigits); + BIM min = -max; + + if (this.exponent >= 0) { + if (maxDigits < digits || maxDigits - digits < this.exponent) { + return String.Format("{0}.0", (this.mantissa >= 0) ? max.ToString() : min.ToString()); + } + else { + return String.Format("{0}{1}.0", s, new string('0', this.exponent)); + } + } + else { + int exp = -this.exponent; + + if (exp < digits) { + int intDigits = digits - exp; + if (maxDigits < intDigits) { + return String.Format("{0}.0", (this.mantissa >= 0) ? max.ToString() : min.ToString()); + } + else { + int fracDigits = Math.Min(maxDigits, digits - intDigits); + return String.Format("{0}.{1}", s.Substring(0, intDigits), s.Substring(intDigits, fracDigits)); + } + } + else { + int fracDigits = Math.Min(maxDigits, digits); + return String.Format("0.{0}{1}", new string('0', exp - fracDigits), s.Substring(0, fracDigits)); + } + } + } + + [Pure] + public string ToDecimalString() { + string m = this.mantissa.ToString(); + var e = this.exponent; + if (0 <= this.exponent) { + return m + Zeros(e) + ".0"; + } else { + e = -e; + // compute k to be the longest suffix of m consisting of all zeros (but no longer than e, and not the entire string) + var maxK = e < m.Length ? e : m.Length - 1; + var last = m.Length - 1; + var k = 0; + while (k < maxK && m[last - k] == '0') { + k++; + } + if (0 < k) { + // chop off the suffix of k zeros from m and adjust e accordingly + m = m.Substring(0, m.Length - k); + e -= k; + } + if (e == 0) { + return m; + } else if (e < m.Length) { + var n = m.Length - e; + return m.Substring(0, n) + "." + m.Substring(n); + } else { + return "0." + Zeros(e - m.Length) + m; + } + } + } + + [Pure] + public static string Zeros(int n) { + Contract.Requires(0 <= n); + if (n <= 10) { + var tenZeros = "0000000000"; + return tenZeros.Substring(0, n); + } else { + var d = n / 2; + var s = Zeros(d); + if (n % 2 == 0) { + return s + s; + } else { + return s + s + "0"; + } + } + } + + + //////////////////////////////////////////////////////////////////////////// + // Basic arithmetic operations + + [Pure] + public BigDec Abs { + get { + return new BigDec(BIM.Abs(this.mantissa), this.exponent); + } + } + + [Pure] + public BigDec Negate { + get { + return new BigDec(BIM.Negate(this.mantissa), this.exponent); + } + } + + [Pure] + public static BigDec operator -(BigDec x) { + return x.Negate; + } + + [Pure] + public static BigDec operator +(BigDec x, BigDec y) { + BIM m1 = x.mantissa; + int e1 = x.exponent; + BIM m2 = y.mantissa; + int e2 = y.exponent; + if (e2 < e1) { + m1 = y.mantissa; + e1 = y.exponent; + m2 = x.mantissa; + e2 = x.exponent; + } + + while (e2 > e1) { + m2 = m2 * ten; + e2 = e2 - 1; + } + + return new BigDec(m1 + m2, e1); + } + + [Pure] + public static BigDec operator -(BigDec x, BigDec y) { + return x + y.Negate; + } + + [Pure] + public static BigDec operator *(BigDec x, BigDec y) { + return new BigDec(x.mantissa * y.mantissa, x.exponent + y.exponent); + } + + + //////////////////////////////////////////////////////////////////////////// + // Some basic comparison operations + + public bool IsPositive { + get { + return (this.mantissa > BIM.Zero); + } + } + + public bool IsNegative { + get { + return (this.mantissa < BIM.Zero); + } + } + + public bool IsZero { + get { + return this.mantissa.IsZero; + } + } + + [Pure] + public int CompareTo(BigDec that) { + if (this.mantissa == that.mantissa && this.exponent == that.exponent) { + return 0; + } + else { + BigDec d = this - that; + return d.IsNegative ? -1 : 1; + } + } + + [Pure] + public static bool operator ==(BigDec x, BigDec y) { + return x.CompareTo(y) == 0; + } + + [Pure] + public static bool operator !=(BigDec x, BigDec y) { + return x.CompareTo(y) != 0; + } + + [Pure] + public static bool operator <(BigDec x, BigDec y) { + return x.CompareTo(y) < 0; + } + + [Pure] + public static bool operator >(BigDec x, BigDec y) { + return x.CompareTo(y) > 0; + } + + [Pure] + public static bool operator <=(BigDec x, BigDec y) { + return x.CompareTo(y) <= 0; + } + + [Pure] + public static bool operator >=(BigDec x, BigDec y) { + return x.CompareTo(y) >= 0; + } + } +} diff --git a/Source/Basetypes/BigNum.cs b/Source/Basetypes/BigNum.cs index ff676bc6..4469f149 100644 --- a/Source/Basetypes/BigNum.cs +++ b/Source/Basetypes/BigNum.cs @@ -1,361 +1,361 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Text; -using System.Diagnostics.Contracts; - - -namespace Microsoft.Basetypes { - using BIM = System.Numerics.BigInteger; - - /// - /// A thin wrapper around System.Numerics.BigInteger - /// (to be able to define equality, etc. properly) - /// - public struct BigNum { - - // the internal representation - [Rep] - internal readonly System.Numerics.BigInteger val; - public static readonly BigNum ZERO = new BigNum(BIM.Zero); - public static readonly BigNum ONE = new BigNum(BIM.One); - public static readonly BigNum MINUS_ONE = new BigNum(-BIM.One); - - [Pure] - public static BigNum FromInt(int v) { - return new BigNum(new BIM(v)); - } - - [Pure] - public static BigNum FromUInt(uint v) { - return new BigNum(new BIM((long)v)); - } - - [Pure] - public static BigNum FromLong(long v) { - return new BigNum(new BIM(v)); - } - - [Pure] - public static BigNum FromBigInt(System.Numerics.BigInteger v) { - return new BigNum(v); - } - - [Pure] - public static BigNum FromULong(ulong v) { - return FromString("" + v); - } - - [Pure] - public static BigNum FromString(string v) { - try { - return new BigNum(BIM.Parse(v)); - } catch (System.ArgumentException) { - throw new FormatException(); - } - } - - public static bool TryParse(string v, out BigNum res) { - try { - res = BigNum.FromString(v); - return true; - } catch (FormatException) { - res = ZERO; - return false; - } - } - - // Convert to int, without checking whether overflows occur - public int ToInt { - get { - return (int)val; - } - } - - public BIM ToBigInteger { - get { - return val; - } - } - - // Convert to int; assert that no overflows occur - public int ToIntSafe { - get { - Contract.Assert(this.InInt32); - return this.ToInt; - } - } - - public Rational ToRational { - get { - return Rational.FromBignum(this); - } - } - - public byte[] ToByteArray() - { - return this.val.ToByteArray(); - } - - internal BigNum(System.Numerics.BigInteger val) { - this.val = val; - } - - public static bool operator ==(BigNum x, BigNum y) { - return (x.val == y.val); - } - - public static bool operator !=(BigNum x, BigNum y) { - return !(x.val == y.val); - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is BigNum)) - return false; - - BigNum other = (BigNum)obj; - return (this.val == other.val); - } - - [Pure] - public override int GetHashCode() { - return this.val.GetHashCode(); - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return cce.NonNull(val.ToString()); - } - - ////////////////////////////////////////////////////////////////////////////// - // Very limited support for format strings - // Note: Negative integers are linearised with a minus "-" in hexadecimal, - // not in 2-complement notation (in contrast to what the method - // int32.ToString(format) does) - - [Pure] - public string/*!*/ ToString(string/*!*/ format) { - Contract.Requires(format != null); - Contract.Ensures(Contract.Result() != null); - if (format.StartsWith("d") || format.StartsWith("D")) { - string res = this.Abs.ToString(); - Contract.Assert(res != null); - return addMinus(this.Signum, - prefixWithZeros(extractPrecision(format), res)); - } else if (format.StartsWith("x") || format.StartsWith("X")) { - string res = this.toHex(format.Substring(0, 1)); - Contract.Assert(res != null); - return addMinus(this.Signum, - prefixWithZeros(extractPrecision(format), res)); - } else { - throw new FormatException("Format " + format + " is not supported"); - } - } - - private static readonly System.Numerics.BigInteger BI_2_TO_24 = new BIM(0x1000000); - - [Pure] - private string/*!*/ toHex(string/*!*/ format) { - Contract.Requires(format != null); - Contract.Ensures(Contract.Result() != null); - string res = ""; - System.Numerics.BigInteger rem = this.Abs.val; - - while (rem > BIM.Zero) { - res = ((int)(rem % BI_2_TO_24)).ToString(format) + res; - rem = rem / BI_2_TO_24; - } - - return res; - } - - [Pure] - private int extractPrecision(string/*!*/ format) { - Contract.Requires(format != null); - if (format.Length > 1) - // will throw a FormatException if the precision is invalid; - // that is ok - return Int32.Parse(format.Substring(1)); - // always output at least one digit - return 1; - } - - [Pure] - private string/*!*/ addMinus(int signum, string/*!*/ suffix) { - Contract.Requires(suffix != null); - Contract.Ensures(Contract.Result() != null); - if (signum < 0) - return "-" + suffix; - return suffix; - } - - [Pure] - private string/*!*/ prefixWithZeros(int minLength, string/*!*/ suffix) { - Contract.Requires(suffix != null); - Contract.Ensures(Contract.Result() != null); - StringBuilder res = new StringBuilder(); - while (res.Length + suffix.Length < minLength) - res.Append("0"); - res.Append(suffix); - return res.ToString(); - } - - //////////////////////////////////////////////////////////////////////////// - // Basic arithmetic operations - - public BigNum Abs { - get { - return new BigNum(BIM.Abs(this.val)); - } - } - - public BigNum Neg { - get { - return new BigNum(-this.val); - } - } - - [Pure] - public static BigNum operator -(BigNum x) { - return x.Neg; - } - - [Pure] - public static BigNum operator +(BigNum x, BigNum y) { - return new BigNum(x.val + y.val); - } - - [Pure] - public static BigNum operator -(BigNum x, BigNum y) { - return new BigNum(x.val - y.val); - } - - [Pure] - public static BigNum operator *(BigNum x, BigNum y) { - return new BigNum(x.val * y.val); - } - - // TODO: check that this has a proper semantics (which? :-)) - [Pure] - public static BigNum operator /(BigNum x, BigNum y) { - return new BigNum(x.val / y.val); - } - - // TODO: check that this has a proper semantics (which? :-)) - [Pure] - public static BigNum operator %(BigNum x, BigNum y) { - return new BigNum(x.val - ((x.val / y.val) * y.val)); - } - - [Pure] - public BigNum Min(BigNum that) { - return new BigNum(this.val <= that.val ? this.val : that.val); - } - - [Pure] - public BigNum Max(BigNum that) { - return new BigNum(this.val >= that.val ? this.val : that.val); - } - - /// - /// Returns the greatest common divisor of this and _y. - /// - /// - /// - public BigNum Gcd(BigNum _y) { - Contract.Ensures(!Contract.Result().IsNegative); - BigNum x = this.Abs; - BigNum y = _y.Abs; - - while (true) { - if (x < y) { - y = y % x; - if (y.IsZero) { - return x; - } - } else { - x = x % y; - if (x.IsZero) { - return y; - } - } - } - } - - //////////////////////////////////////////////////////////////////////////// - // Some basic comparison operations - - public int Signum { - get { - return this.val.Sign; - } - } - - public bool IsPositive { - get { - return (this.val > BIM.Zero); - } - } - - public bool IsNegative { - get { - return (this.val < BIM.Zero); - } - } - - public bool IsZero { - get { - return this.val.IsZero; - } - } - - [Pure] - public int CompareTo(BigNum that) { - if (this.val == that.val) - return 0; - if (this.val < that.val) - return -1; - return 1; - } - - [Pure] - public static bool operator <(BigNum x, BigNum y) { - return (x.val < y.val); - } - - [Pure] - public static bool operator >(BigNum x, BigNum y) { - return (x.val > y.val); - } - - [Pure] - public static bool operator <=(BigNum x, BigNum y) { - return (x.val <= y.val); - } - - [Pure] - public static bool operator >=(BigNum x, BigNum y) { - return (x.val >= y.val); - } - - - private static readonly System.Numerics.BigInteger MaxInt32 = - new BIM(Int32.MaxValue); - private static readonly System.Numerics.BigInteger MinInt32 = - new BIM(Int32.MinValue); - - public bool InInt32 { - get { - return (val >= MinInt32) && (val <= MaxInt32); - } - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Text; +using System.Diagnostics.Contracts; + + +namespace Microsoft.Basetypes { + using BIM = System.Numerics.BigInteger; + + /// + /// A thin wrapper around System.Numerics.BigInteger + /// (to be able to define equality, etc. properly) + /// + public struct BigNum { + + // the internal representation + [Rep] + internal readonly System.Numerics.BigInteger val; + public static readonly BigNum ZERO = new BigNum(BIM.Zero); + public static readonly BigNum ONE = new BigNum(BIM.One); + public static readonly BigNum MINUS_ONE = new BigNum(-BIM.One); + + [Pure] + public static BigNum FromInt(int v) { + return new BigNum(new BIM(v)); + } + + [Pure] + public static BigNum FromUInt(uint v) { + return new BigNum(new BIM((long)v)); + } + + [Pure] + public static BigNum FromLong(long v) { + return new BigNum(new BIM(v)); + } + + [Pure] + public static BigNum FromBigInt(System.Numerics.BigInteger v) { + return new BigNum(v); + } + + [Pure] + public static BigNum FromULong(ulong v) { + return FromString("" + v); + } + + [Pure] + public static BigNum FromString(string v) { + try { + return new BigNum(BIM.Parse(v)); + } catch (System.ArgumentException) { + throw new FormatException(); + } + } + + public static bool TryParse(string v, out BigNum res) { + try { + res = BigNum.FromString(v); + return true; + } catch (FormatException) { + res = ZERO; + return false; + } + } + + // Convert to int, without checking whether overflows occur + public int ToInt { + get { + return (int)val; + } + } + + public BIM ToBigInteger { + get { + return val; + } + } + + // Convert to int; assert that no overflows occur + public int ToIntSafe { + get { + Contract.Assert(this.InInt32); + return this.ToInt; + } + } + + public Rational ToRational { + get { + return Rational.FromBignum(this); + } + } + + public byte[] ToByteArray() + { + return this.val.ToByteArray(); + } + + internal BigNum(System.Numerics.BigInteger val) { + this.val = val; + } + + public static bool operator ==(BigNum x, BigNum y) { + return (x.val == y.val); + } + + public static bool operator !=(BigNum x, BigNum y) { + return !(x.val == y.val); + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is BigNum)) + return false; + + BigNum other = (BigNum)obj; + return (this.val == other.val); + } + + [Pure] + public override int GetHashCode() { + return this.val.GetHashCode(); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return cce.NonNull(val.ToString()); + } + + ////////////////////////////////////////////////////////////////////////////// + // Very limited support for format strings + // Note: Negative integers are linearised with a minus "-" in hexadecimal, + // not in 2-complement notation (in contrast to what the method + // int32.ToString(format) does) + + [Pure] + public string/*!*/ ToString(string/*!*/ format) { + Contract.Requires(format != null); + Contract.Ensures(Contract.Result() != null); + if (format.StartsWith("d") || format.StartsWith("D")) { + string res = this.Abs.ToString(); + Contract.Assert(res != null); + return addMinus(this.Signum, + prefixWithZeros(extractPrecision(format), res)); + } else if (format.StartsWith("x") || format.StartsWith("X")) { + string res = this.toHex(format.Substring(0, 1)); + Contract.Assert(res != null); + return addMinus(this.Signum, + prefixWithZeros(extractPrecision(format), res)); + } else { + throw new FormatException("Format " + format + " is not supported"); + } + } + + private static readonly System.Numerics.BigInteger BI_2_TO_24 = new BIM(0x1000000); + + [Pure] + private string/*!*/ toHex(string/*!*/ format) { + Contract.Requires(format != null); + Contract.Ensures(Contract.Result() != null); + string res = ""; + System.Numerics.BigInteger rem = this.Abs.val; + + while (rem > BIM.Zero) { + res = ((int)(rem % BI_2_TO_24)).ToString(format) + res; + rem = rem / BI_2_TO_24; + } + + return res; + } + + [Pure] + private int extractPrecision(string/*!*/ format) { + Contract.Requires(format != null); + if (format.Length > 1) + // will throw a FormatException if the precision is invalid; + // that is ok + return Int32.Parse(format.Substring(1)); + // always output at least one digit + return 1; + } + + [Pure] + private string/*!*/ addMinus(int signum, string/*!*/ suffix) { + Contract.Requires(suffix != null); + Contract.Ensures(Contract.Result() != null); + if (signum < 0) + return "-" + suffix; + return suffix; + } + + [Pure] + private string/*!*/ prefixWithZeros(int minLength, string/*!*/ suffix) { + Contract.Requires(suffix != null); + Contract.Ensures(Contract.Result() != null); + StringBuilder res = new StringBuilder(); + while (res.Length + suffix.Length < minLength) + res.Append("0"); + res.Append(suffix); + return res.ToString(); + } + + //////////////////////////////////////////////////////////////////////////// + // Basic arithmetic operations + + public BigNum Abs { + get { + return new BigNum(BIM.Abs(this.val)); + } + } + + public BigNum Neg { + get { + return new BigNum(-this.val); + } + } + + [Pure] + public static BigNum operator -(BigNum x) { + return x.Neg; + } + + [Pure] + public static BigNum operator +(BigNum x, BigNum y) { + return new BigNum(x.val + y.val); + } + + [Pure] + public static BigNum operator -(BigNum x, BigNum y) { + return new BigNum(x.val - y.val); + } + + [Pure] + public static BigNum operator *(BigNum x, BigNum y) { + return new BigNum(x.val * y.val); + } + + // TODO: check that this has a proper semantics (which? :-)) + [Pure] + public static BigNum operator /(BigNum x, BigNum y) { + return new BigNum(x.val / y.val); + } + + // TODO: check that this has a proper semantics (which? :-)) + [Pure] + public static BigNum operator %(BigNum x, BigNum y) { + return new BigNum(x.val - ((x.val / y.val) * y.val)); + } + + [Pure] + public BigNum Min(BigNum that) { + return new BigNum(this.val <= that.val ? this.val : that.val); + } + + [Pure] + public BigNum Max(BigNum that) { + return new BigNum(this.val >= that.val ? this.val : that.val); + } + + /// + /// Returns the greatest common divisor of this and _y. + /// + /// + /// + public BigNum Gcd(BigNum _y) { + Contract.Ensures(!Contract.Result().IsNegative); + BigNum x = this.Abs; + BigNum y = _y.Abs; + + while (true) { + if (x < y) { + y = y % x; + if (y.IsZero) { + return x; + } + } else { + x = x % y; + if (x.IsZero) { + return y; + } + } + } + } + + //////////////////////////////////////////////////////////////////////////// + // Some basic comparison operations + + public int Signum { + get { + return this.val.Sign; + } + } + + public bool IsPositive { + get { + return (this.val > BIM.Zero); + } + } + + public bool IsNegative { + get { + return (this.val < BIM.Zero); + } + } + + public bool IsZero { + get { + return this.val.IsZero; + } + } + + [Pure] + public int CompareTo(BigNum that) { + if (this.val == that.val) + return 0; + if (this.val < that.val) + return -1; + return 1; + } + + [Pure] + public static bool operator <(BigNum x, BigNum y) { + return (x.val < y.val); + } + + [Pure] + public static bool operator >(BigNum x, BigNum y) { + return (x.val > y.val); + } + + [Pure] + public static bool operator <=(BigNum x, BigNum y) { + return (x.val <= y.val); + } + + [Pure] + public static bool operator >=(BigNum x, BigNum y) { + return (x.val >= y.val); + } + + + private static readonly System.Numerics.BigInteger MaxInt32 = + new BIM(Int32.MaxValue); + private static readonly System.Numerics.BigInteger MinInt32 = + new BIM(Int32.MinValue); + + public bool InInt32 { + get { + return (val >= MinInt32) && (val <= MaxInt32); + } + } + } +} diff --git a/Source/Basetypes/Rational.cs b/Source/Basetypes/Rational.cs index cd0eddce..ef59cf4f 100644 --- a/Source/Basetypes/Rational.cs +++ b/Source/Basetypes/Rational.cs @@ -1,248 +1,248 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Diagnostics.Contracts; - -namespace Microsoft.Basetypes { - /// - /// The representation of a rational number. - /// - public struct Rational { - public static readonly Rational ZERO = Rational.FromInts(0, 1); - public static readonly Rational ONE = Rational.FromInts(1, 1); - public static readonly Rational MINUS_ONE = Rational.FromInts(-1, 1); - - private BigNum numerator, denominator; - - // int numerator; - // int denominator; - - - // invariant: 0 < denominator || (numerator == 0 && denominator == 0); - // invariant: numerator != 0 ==> gcd(abs(numerator),denominator) == 1; - // invariant: numerator == 0 ==> denominator == 1 || denominator == 0; - - public static Rational FromInt(int x) { - return FromBignum(BigNum.FromInt(x)); - } - - public static Rational FromBignum(BigNum n) - { - return new Rational(n, BigNum.ONE); - } - - private Rational(BigNum num, BigNum den) - { - Contract.Assert(den.Signum > 0); - Contract.Assert(num == BigNum.ZERO || num.Gcd(den) == BigNum.ONE); - numerator = num; - denominator = den; - } - - public static Rational FromBignums(BigNum num, BigNum den) { - Contract.Assert(!den.IsZero); - if (num == BigNum.ZERO) - return ZERO; - if (den.Signum < 0) { - den = -den; - num = -num; - } - if (den == BigNum.ONE) - return new Rational(num, den); - var gcd = num.Gcd(den); - if (gcd == BigNum.ONE) - return new Rational(num, den); - return new Rational(num / gcd, den / gcd); - } - - public static Rational FromInts(int num, int den) { - return FromBignums(BigNum.FromInt(num), BigNum.FromInt(den)); - } - - /// - /// Returns the absolute value of the rational. - /// - public Rational Abs() { - Contract.Ensures(Contract.Result().IsNonNegative); - if (IsNonNegative) { - return this; - } else { - return -this; - } - } - - /// - /// Returns a rational whose numerator and denominator, resepctively, are the Gcd - /// of the numerators and denominators of r and s. If one of r and s is 0, the absolute - /// value of the other is returned. If both are 0, 1 is returned. - /// - public static Rational Gcd(Rational r, Rational s) { - Contract.Ensures(Contract.Result().IsPositive); - if (r.IsZero) { - if (s.IsZero) { - return ONE; - } else { - return s.Abs(); - } - } else if (s.IsZero) { - return r.Abs(); - } else { - return new Rational(r.Numerator.Gcd(s.Numerator), - r.Denominator.Gcd(s.Denominator)); - } - } - - public BigNum Numerator { get { return numerator; } } - public BigNum Denominator { get { return denominator == BigNum.ZERO ? BigNum.ONE : denominator; } } - - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return String.Format("{0}/{1}", Numerator, Denominator); - } - - - public static bool operator ==(Rational r, Rational s) { - return r.Numerator == s.Numerator && r.Denominator == s.Denominator; - } - - public static bool operator !=(Rational r, Rational s) { - return !(r == s); - } - - public override bool Equals(object obj) { - if (obj == null) - return false; - return obj is Rational && (Rational)obj == this; - } - - public override int GetHashCode() { - return this.Numerator.GetHashCode() * 13 + this.Denominator.GetHashCode(); - } - - public int Signum { - get { - return this.Numerator.Signum; - } - } - - public bool IsZero { - get { - return Signum == 0; - } - } - - public bool IsNonZero { - get { - return Signum != 0; - } - } - - public bool IsIntegral { - get { - return Denominator == BigNum.ONE; - } - } - - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public bool HasValue(int n) { - return this == FromInt(n); - } - - /// - /// Returns the rational as an integer. Requires the rational to be integral. - /// - public int AsInteger { - get { - Contract.Assert(this.IsIntegral); - return Numerator.ToIntSafe; - } - } - - public BigNum AsBigNum { - get { - Contract.Assert(this.IsIntegral); - return Numerator; - } - } - - public double AsDouble { - [Pure] - get { - if (this.IsZero) { - return 0.0; - } else { - return (double)Numerator.ToIntSafe / (double)Denominator.ToIntSafe; - } - } - } - - public bool IsNegative { - [Pure] - get { - return Signum < 0; - } - } - - public bool IsPositive { - [Pure] - get { - return 0 < Signum; - } - } - - public bool IsNonNegative { - [Pure] - get { - return 0 <= Signum; - } - } - - public static Rational operator -(Rational r) - { - return new Rational(-r.Numerator, r.Denominator); - } - - public static Rational operator /(Rational r, Rational s) - { - return FromBignums(r.Numerator * s.Denominator, r.Denominator * s.Numerator); - } - - public static Rational operator -(Rational r, Rational s) - { - return r + (-s); - } - - public static Rational operator +(Rational r, Rational s) - { - return FromBignums(r.Numerator * s.Denominator + s.Numerator * r.Denominator, r.Denominator * s.Denominator); - } - - public static Rational operator *(Rational r, Rational s) - { - return FromBignums(r.Numerator * s.Numerator, r.Denominator * s.Denominator); - } - - public static bool operator <(Rational r, Rational s) - { - return (r - s).Signum < 0; - } - - public static bool operator <=(Rational r, Rational s) - { - return !(r > s); - } - - public static bool operator >=(Rational r, Rational s) { - return !(r < s); - } - - public static bool operator >(Rational r, Rational s) { - return s < r; - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Diagnostics.Contracts; + +namespace Microsoft.Basetypes { + /// + /// The representation of a rational number. + /// + public struct Rational { + public static readonly Rational ZERO = Rational.FromInts(0, 1); + public static readonly Rational ONE = Rational.FromInts(1, 1); + public static readonly Rational MINUS_ONE = Rational.FromInts(-1, 1); + + private BigNum numerator, denominator; + + // int numerator; + // int denominator; + + + // invariant: 0 < denominator || (numerator == 0 && denominator == 0); + // invariant: numerator != 0 ==> gcd(abs(numerator),denominator) == 1; + // invariant: numerator == 0 ==> denominator == 1 || denominator == 0; + + public static Rational FromInt(int x) { + return FromBignum(BigNum.FromInt(x)); + } + + public static Rational FromBignum(BigNum n) + { + return new Rational(n, BigNum.ONE); + } + + private Rational(BigNum num, BigNum den) + { + Contract.Assert(den.Signum > 0); + Contract.Assert(num == BigNum.ZERO || num.Gcd(den) == BigNum.ONE); + numerator = num; + denominator = den; + } + + public static Rational FromBignums(BigNum num, BigNum den) { + Contract.Assert(!den.IsZero); + if (num == BigNum.ZERO) + return ZERO; + if (den.Signum < 0) { + den = -den; + num = -num; + } + if (den == BigNum.ONE) + return new Rational(num, den); + var gcd = num.Gcd(den); + if (gcd == BigNum.ONE) + return new Rational(num, den); + return new Rational(num / gcd, den / gcd); + } + + public static Rational FromInts(int num, int den) { + return FromBignums(BigNum.FromInt(num), BigNum.FromInt(den)); + } + + /// + /// Returns the absolute value of the rational. + /// + public Rational Abs() { + Contract.Ensures(Contract.Result().IsNonNegative); + if (IsNonNegative) { + return this; + } else { + return -this; + } + } + + /// + /// Returns a rational whose numerator and denominator, resepctively, are the Gcd + /// of the numerators and denominators of r and s. If one of r and s is 0, the absolute + /// value of the other is returned. If both are 0, 1 is returned. + /// + public static Rational Gcd(Rational r, Rational s) { + Contract.Ensures(Contract.Result().IsPositive); + if (r.IsZero) { + if (s.IsZero) { + return ONE; + } else { + return s.Abs(); + } + } else if (s.IsZero) { + return r.Abs(); + } else { + return new Rational(r.Numerator.Gcd(s.Numerator), + r.Denominator.Gcd(s.Denominator)); + } + } + + public BigNum Numerator { get { return numerator; } } + public BigNum Denominator { get { return denominator == BigNum.ZERO ? BigNum.ONE : denominator; } } + + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return String.Format("{0}/{1}", Numerator, Denominator); + } + + + public static bool operator ==(Rational r, Rational s) { + return r.Numerator == s.Numerator && r.Denominator == s.Denominator; + } + + public static bool operator !=(Rational r, Rational s) { + return !(r == s); + } + + public override bool Equals(object obj) { + if (obj == null) + return false; + return obj is Rational && (Rational)obj == this; + } + + public override int GetHashCode() { + return this.Numerator.GetHashCode() * 13 + this.Denominator.GetHashCode(); + } + + public int Signum { + get { + return this.Numerator.Signum; + } + } + + public bool IsZero { + get { + return Signum == 0; + } + } + + public bool IsNonZero { + get { + return Signum != 0; + } + } + + public bool IsIntegral { + get { + return Denominator == BigNum.ONE; + } + } + + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public bool HasValue(int n) { + return this == FromInt(n); + } + + /// + /// Returns the rational as an integer. Requires the rational to be integral. + /// + public int AsInteger { + get { + Contract.Assert(this.IsIntegral); + return Numerator.ToIntSafe; + } + } + + public BigNum AsBigNum { + get { + Contract.Assert(this.IsIntegral); + return Numerator; + } + } + + public double AsDouble { + [Pure] + get { + if (this.IsZero) { + return 0.0; + } else { + return (double)Numerator.ToIntSafe / (double)Denominator.ToIntSafe; + } + } + } + + public bool IsNegative { + [Pure] + get { + return Signum < 0; + } + } + + public bool IsPositive { + [Pure] + get { + return 0 < Signum; + } + } + + public bool IsNonNegative { + [Pure] + get { + return 0 <= Signum; + } + } + + public static Rational operator -(Rational r) + { + return new Rational(-r.Numerator, r.Denominator); + } + + public static Rational operator /(Rational r, Rational s) + { + return FromBignums(r.Numerator * s.Denominator, r.Denominator * s.Numerator); + } + + public static Rational operator -(Rational r, Rational s) + { + return r + (-s); + } + + public static Rational operator +(Rational r, Rational s) + { + return FromBignums(r.Numerator * s.Denominator + s.Numerator * r.Denominator, r.Denominator * s.Denominator); + } + + public static Rational operator *(Rational r, Rational s) + { + return FromBignums(r.Numerator * s.Numerator, r.Denominator * s.Denominator); + } + + public static bool operator <(Rational r, Rational s) + { + return (r - s).Signum < 0; + } + + public static bool operator <=(Rational r, Rational s) + { + return !(r > s); + } + + public static bool operator >=(Rational r, Rational s) { + return !(r < s); + } + + public static bool operator >(Rational r, Rational s) { + return s < r; + } + } +} diff --git a/Source/Basetypes/Set.cs b/Source/Basetypes/Set.cs index dfd65b4b..0cc1d103 100644 --- a/Source/Basetypes/Set.cs +++ b/Source/Basetypes/Set.cs @@ -1,286 +1,286 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.Boogie { - using System; - using System.IO; - using System.Collections; - using System.Collections.Generic; - using System.Diagnostics.Contracts; - - /// - /// A class representing a mathematical set. - /// - public class GSet : ICloneable, IEnumerable, IEnumerable { - /*[Own]*/ - Dictionary ht; - List arr; // keep elements in a well-defined order; otherwise iteration is non-deterministic - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(ht != null); - Contract.Invariant(arr != null); - Contract.Invariant(ht.Count == arr.Count); - } - - - public GSet() { - ht = new Dictionary(); - arr = new List(); - //:base(); - } - - private GSet(Dictionary/*!*/ ht, List arr) { - Contract.Requires(ht != null); - Contract.Requires(arr != null); - this.ht = ht; - this.arr = arr; - //:base(); - } - - public GSet(int capacity) { - ht = new Dictionary(capacity); - arr = new List(capacity); - //:base(); - } - - - public readonly static GSet/*!*/ Empty = new GSet(); - - public void Clear() { - ht.Clear(); - arr.Clear(); - } - - /// - /// This method idempotently adds "o" to the set. - /// In notation: - /// this.SetElements = this.SetElements_old \union {o}; - /// - public void Add(T o) { - if (!ht.ContainsKey(o)) { - ht[o] = arr.Count; - arr.Add(o); - } - } - - /// - /// this.SetElements = this.SetElements_old \union s.GSetElements; - /// - public void AddRange(IEnumerable s) { - foreach (T o in s) { - Add(o); - } - } - - /// - /// this.SetElements = this.SetElements_old \setminus {o}; - /// - public void Remove(T o) { - int idx; - if (ht.TryGetValue(o, out idx)) { - var last = arr[arr.Count - 1]; - arr.RemoveAt(arr.Count - 1); - if (idx != arr.Count) { - arr[idx] = last; - ht[last] = idx; - } - ht.Remove(o); - } - } - - /// - /// this.SetElements = this.SetElements_old \setminus s.SetElements; - /// - public void RemoveRange(IEnumerable s) { - Contract.Requires(s != null); - if (s == this) { - ht.Clear(); - arr.Clear(); - } else { - foreach (T o in s) { - Remove(o); - } - } - } - - /// - /// Returns an arbitrary element from the set. - /// - public T Choose() { - Contract.Requires((Count > 0)); - foreach(var e in this) - return e; - return default(T); - } - - /// - /// Picks an arbitrary element from the set, removes it, and returns it. - /// - public T Take() { - Contract.Requires((Count > 0)); - Contract.Ensures(Count == Contract.OldValue(Count) - 1); - T r = Choose(); - Remove(r); - return r; - } - - public void Intersect(GSet/*!*/ s) { - Contract.Requires(s != null); - if (s == this) return; - ht.Clear(); - var newArr = new List(); - foreach (T key in arr) { - if (s.ht.ContainsKey(key)) { - ht[key] = newArr.Count; - newArr.Add(key); - } - } - arr = newArr; - } - - /// - /// The getter returns true iff "o" is in the set. - /// The setter adds the value "o" (for "true") or removes "o" (for "false") - /// - public bool this[T o] { - get { - return ht.ContainsKey(o); - } - set { - if (value) { - Add(o); - } else { - Remove(o); - } - } - } - - /// - /// Returns true iff "o" is an element of "this". - /// - /// - /// - [Pure] - public bool Contains(T o) { - return this.ht.ContainsKey(o); - } - - /// - /// Returns true iff every element of "s" is an element of "this", that is, if - /// "s" is a subset of "this". - /// - /// - /// - public bool ContainsRange(IEnumerable s) { - Contract.Requires(s != null); - if (s != this) { - foreach (T key in s) { - if (!this.ht.ContainsKey(key)) { - return false; - } - } - } - return true; - } - - public object/*!*/ Clone() { - Contract.Ensures(Contract.Result() != null); - return new GSet(new Dictionary(ht), new List(arr)); - } - - public virtual int Count { - get { - return ht.Count; - } - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - string s = null; - foreach (object/*!*/ key in ht.Keys) { - Contract.Assert(key != null); - if (s == null) { - s = "{"; - } else { - s += ", "; - } - s += key.ToString(); - } - if (s == null) { - return "{}"; - } else { - return s + "}"; - } - } - - //----------------------------- Static Methods --------------------------------- - - // Functional Intersect - public static GSet/*!*/ Intersect(GSet/*!*/ a, GSet/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result>() != null); - //Contract.Ensures(Contract.ForAll(result, x => a[x] && b[x] )); - GSet/*!*/ res = (GSet/*!*/)cce.NonNull(a.Clone()); - res.Intersect(b); - return res; - } - // Functional Union - public static GSet/*!*/ Union(GSet/*!*/ a, GSet/*!*/ b) { - Contract.Requires(a != null); - Contract.Requires(b != null); - Contract.Ensures(Contract.Result>() != null); - // Contract.Ensures(Contract.ForAll(result, x => a[x] || b[x] )); - GSet/*!*/ res = (GSet/*!*/)cce.NonNull(a.Clone()); - res.AddRange(b); - return res; - } - - public delegate bool SetFilter(object/*!*/ obj); - - public static GSet/*!*/ Filter(GSet/*!*/ a, Func filter) { - Contract.Requires(filter != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result>() != null); - GSet inter = new GSet(); - - foreach (T elem in a) { - Contract.Assert(elem != null); - if (filter(elem)) { - inter.Add(elem); - } - } - return inter; - } - - public IEnumerator GetEnumerator() - { - return arr.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IEnumerable)arr).GetEnumerator(); - } - - public bool AddAll(IEnumerable s) - { - foreach (T e in s) Add(e); - return true; - } - } - - - public interface IWorkList : ICollection { - bool Add(object o); - bool AddAll(IEnumerable objs); - bool IsEmpty(); - object Pull(); - } - - +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.Boogie { + using System; + using System.IO; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + + /// + /// A class representing a mathematical set. + /// + public class GSet : ICloneable, IEnumerable, IEnumerable { + /*[Own]*/ + Dictionary ht; + List arr; // keep elements in a well-defined order; otherwise iteration is non-deterministic + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(ht != null); + Contract.Invariant(arr != null); + Contract.Invariant(ht.Count == arr.Count); + } + + + public GSet() { + ht = new Dictionary(); + arr = new List(); + //:base(); + } + + private GSet(Dictionary/*!*/ ht, List arr) { + Contract.Requires(ht != null); + Contract.Requires(arr != null); + this.ht = ht; + this.arr = arr; + //:base(); + } + + public GSet(int capacity) { + ht = new Dictionary(capacity); + arr = new List(capacity); + //:base(); + } + + + public readonly static GSet/*!*/ Empty = new GSet(); + + public void Clear() { + ht.Clear(); + arr.Clear(); + } + + /// + /// This method idempotently adds "o" to the set. + /// In notation: + /// this.SetElements = this.SetElements_old \union {o}; + /// + public void Add(T o) { + if (!ht.ContainsKey(o)) { + ht[o] = arr.Count; + arr.Add(o); + } + } + + /// + /// this.SetElements = this.SetElements_old \union s.GSetElements; + /// + public void AddRange(IEnumerable s) { + foreach (T o in s) { + Add(o); + } + } + + /// + /// this.SetElements = this.SetElements_old \setminus {o}; + /// + public void Remove(T o) { + int idx; + if (ht.TryGetValue(o, out idx)) { + var last = arr[arr.Count - 1]; + arr.RemoveAt(arr.Count - 1); + if (idx != arr.Count) { + arr[idx] = last; + ht[last] = idx; + } + ht.Remove(o); + } + } + + /// + /// this.SetElements = this.SetElements_old \setminus s.SetElements; + /// + public void RemoveRange(IEnumerable s) { + Contract.Requires(s != null); + if (s == this) { + ht.Clear(); + arr.Clear(); + } else { + foreach (T o in s) { + Remove(o); + } + } + } + + /// + /// Returns an arbitrary element from the set. + /// + public T Choose() { + Contract.Requires((Count > 0)); + foreach(var e in this) + return e; + return default(T); + } + + /// + /// Picks an arbitrary element from the set, removes it, and returns it. + /// + public T Take() { + Contract.Requires((Count > 0)); + Contract.Ensures(Count == Contract.OldValue(Count) - 1); + T r = Choose(); + Remove(r); + return r; + } + + public void Intersect(GSet/*!*/ s) { + Contract.Requires(s != null); + if (s == this) return; + ht.Clear(); + var newArr = new List(); + foreach (T key in arr) { + if (s.ht.ContainsKey(key)) { + ht[key] = newArr.Count; + newArr.Add(key); + } + } + arr = newArr; + } + + /// + /// The getter returns true iff "o" is in the set. + /// The setter adds the value "o" (for "true") or removes "o" (for "false") + /// + public bool this[T o] { + get { + return ht.ContainsKey(o); + } + set { + if (value) { + Add(o); + } else { + Remove(o); + } + } + } + + /// + /// Returns true iff "o" is an element of "this". + /// + /// + /// + [Pure] + public bool Contains(T o) { + return this.ht.ContainsKey(o); + } + + /// + /// Returns true iff every element of "s" is an element of "this", that is, if + /// "s" is a subset of "this". + /// + /// + /// + public bool ContainsRange(IEnumerable s) { + Contract.Requires(s != null); + if (s != this) { + foreach (T key in s) { + if (!this.ht.ContainsKey(key)) { + return false; + } + } + } + return true; + } + + public object/*!*/ Clone() { + Contract.Ensures(Contract.Result() != null); + return new GSet(new Dictionary(ht), new List(arr)); + } + + public virtual int Count { + get { + return ht.Count; + } + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + string s = null; + foreach (object/*!*/ key in ht.Keys) { + Contract.Assert(key != null); + if (s == null) { + s = "{"; + } else { + s += ", "; + } + s += key.ToString(); + } + if (s == null) { + return "{}"; + } else { + return s + "}"; + } + } + + //----------------------------- Static Methods --------------------------------- + + // Functional Intersect + public static GSet/*!*/ Intersect(GSet/*!*/ a, GSet/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result>() != null); + //Contract.Ensures(Contract.ForAll(result, x => a[x] && b[x] )); + GSet/*!*/ res = (GSet/*!*/)cce.NonNull(a.Clone()); + res.Intersect(b); + return res; + } + // Functional Union + public static GSet/*!*/ Union(GSet/*!*/ a, GSet/*!*/ b) { + Contract.Requires(a != null); + Contract.Requires(b != null); + Contract.Ensures(Contract.Result>() != null); + // Contract.Ensures(Contract.ForAll(result, x => a[x] || b[x] )); + GSet/*!*/ res = (GSet/*!*/)cce.NonNull(a.Clone()); + res.AddRange(b); + return res; + } + + public delegate bool SetFilter(object/*!*/ obj); + + public static GSet/*!*/ Filter(GSet/*!*/ a, Func filter) { + Contract.Requires(filter != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result>() != null); + GSet inter = new GSet(); + + foreach (T elem in a) { + Contract.Assert(elem != null); + if (filter(elem)) { + inter.Add(elem); + } + } + return inter; + } + + public IEnumerator GetEnumerator() + { + return arr.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)arr).GetEnumerator(); + } + + public bool AddAll(IEnumerable s) + { + foreach (T e in s) Add(e); + return true; + } + } + + + public interface IWorkList : ICollection { + bool Add(object o); + bool AddAll(IEnumerable objs); + bool IsEmpty(); + object Pull(); + } + + } \ No newline at end of file diff --git a/Source/Basetypes/cce.cs b/Source/Basetypes/cce.cs index ef594484..1e0b12a5 100644 --- a/Source/Basetypes/cce.cs +++ b/Source/Basetypes/cce.cs @@ -1,193 +1,193 @@ -using System; -using SA=System.Attribute; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Text; -//using Microsoft.Boogie; - -/// -/// A class containing static methods to extend the functionality of Code Contracts -/// - -public static class cce { - //[Pure] - //public static bool NonNullElements(Microsoft.Dafny.Graph collection) { - // return collection != null && cce.NonNullElements(collection.TopologicallySortedComponents()); - //} - [Pure] - public static T NonNull(T t) { - Contract.Assert(t != null); - return t; - } - [Pure] - public static bool NonNullElements(IEnumerable collection) { - return collection != null && Contract.ForAll(collection, c => c != null); - } - [Pure] - public static bool NonNullElements(IDictionary collection) { - return collection != null && Contract.ForAll(collection, pair => NonNullElements(pair)); - } - //[Pure] - //public static bool NonNullElements(VariableSeq collection) { - // return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); - //} - /// - /// For possibly-null lists of non-null elements - /// - /// - /// - /// If true, the collection is treated as an IEnumerable<T!>?, rather than an IEnumerable<T!>! - /// - [Pure] - public static bool NonNullElements(IEnumerable collection, bool nullability) { - return (nullability && collection == null) || cce.NonNullElements(collection); - //Should be the same as: - /*if(nullability&&collection==null) - * return true; - * return cce.NonNullElements(collection) - */ - - } - [Pure] - public static bool NonNullElements(KeyValuePair kvp) { - return kvp.Key != null && kvp.Value != null; - } - [Pure] - public static bool NonNullElements(IEnumerator iEnumerator) { - return iEnumerator != null; - } - //[Pure] - //public static bool NonNullElements(Graphing.Graph graph) { - // return cce.NonNullElements(graph.TopologicalSort()); - //} - [Pure] - public static void BeginExpose(object o) { - } - [Pure] - public static void EndExpose() { - } - [Pure] - public static bool IsPeerConsistent(object o) { - return true; - } - [Pure] - public static bool IsConsistent(object o) { - return true; - } - [Pure] - public static bool IsExposable(object o) { - return true; - } - [Pure] - public static bool IsExposed(object o) { - return true; - } - [Pure] - public static bool IsNew(object o) { - return true; - } - public static class Owner { - [Pure] - public static bool Same(object o, object p) { - return true; - } - [Pure] - public static void AssignSame(object o, object p) { - } - [Pure] - public static object ElementProxy(object o) { - return o; - } - [Pure] - public static bool None(object o) { - return true; - } - [Pure] - public static bool Different(object o, object p) { - return true; - } - [Pure] - public static bool New(object o) { - return true; - } - } - [Pure] - public static void LoopInvariant(bool p) { - Contract.Assert(p); - } - public class UnreachableException : Exception { - public UnreachableException() { - } - } - //[Pure] - //public static bool IsValid(Microsoft.Dafny.Expression expression) { - // return true; - //} - //public static List toList(PureCollections.Sequence s) { - // List toRet = new List(); - // foreach (T t in s.elems) - // if(t!=null) - // toRet.Add(t); - // return toRet; - //} - - //internal static bool NonNullElements(Set set) { - // return set != null && Contract.ForAll(0,set.Count, i => set[i] != null); - //} -} - -public class PeerAttribute : SA { -} -public class RepAttribute : SA { -} -public class CapturedAttribute : SA { -} -public class NotDelayedAttribute : SA { -} -public class NoDefaultContractAttribute : SA { -} -public class VerifyAttribute : SA { - public VerifyAttribute(bool b) { - - } -} -public class StrictReadonlyAttribute : SA { -} -public class AdditiveAttribute : SA { -} -public class ReadsAttribute : SA { - public enum Reads { - Nothing, - Everything, - }; - public ReadsAttribute(object o) { - } -} -public class GlobalAccessAttribute : SA { - public GlobalAccessAttribute(bool b) { - } -} -public class EscapesAttribute : SA { - public EscapesAttribute(bool b, bool b_2) { - } -} -public class NeedsContractsAttribute : SA { - public NeedsContractsAttribute() { - } - public NeedsContractsAttribute(bool ret, bool parameters) { - } - public NeedsContractsAttribute(bool ret, int[] parameters) { - } -} -public class ImmutableAttribute : SA { -} -public class InsideAttribute : SA { -} -public class SpecPublicAttribute : SA { -} -public class ElementsPeerAttribute : SA { -} -public class ResultNotNewlyAllocatedAttribute : SA { -} -public class OnceAttribute : SA { +using System; +using SA=System.Attribute; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Text; +//using Microsoft.Boogie; + +/// +/// A class containing static methods to extend the functionality of Code Contracts +/// + +public static class cce { + //[Pure] + //public static bool NonNullElements(Microsoft.Dafny.Graph collection) { + // return collection != null && cce.NonNullElements(collection.TopologicallySortedComponents()); + //} + [Pure] + public static T NonNull(T t) { + Contract.Assert(t != null); + return t; + } + [Pure] + public static bool NonNullElements(IEnumerable collection) { + return collection != null && Contract.ForAll(collection, c => c != null); + } + [Pure] + public static bool NonNullElements(IDictionary collection) { + return collection != null && Contract.ForAll(collection, pair => NonNullElements(pair)); + } + //[Pure] + //public static bool NonNullElements(VariableSeq collection) { + // return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); + //} + /// + /// For possibly-null lists of non-null elements + /// + /// + /// + /// If true, the collection is treated as an IEnumerable<T!>?, rather than an IEnumerable<T!>! + /// + [Pure] + public static bool NonNullElements(IEnumerable collection, bool nullability) { + return (nullability && collection == null) || cce.NonNullElements(collection); + //Should be the same as: + /*if(nullability&&collection==null) + * return true; + * return cce.NonNullElements(collection) + */ + + } + [Pure] + public static bool NonNullElements(KeyValuePair kvp) { + return kvp.Key != null && kvp.Value != null; + } + [Pure] + public static bool NonNullElements(IEnumerator iEnumerator) { + return iEnumerator != null; + } + //[Pure] + //public static bool NonNullElements(Graphing.Graph graph) { + // return cce.NonNullElements(graph.TopologicalSort()); + //} + [Pure] + public static void BeginExpose(object o) { + } + [Pure] + public static void EndExpose() { + } + [Pure] + public static bool IsPeerConsistent(object o) { + return true; + } + [Pure] + public static bool IsConsistent(object o) { + return true; + } + [Pure] + public static bool IsExposable(object o) { + return true; + } + [Pure] + public static bool IsExposed(object o) { + return true; + } + [Pure] + public static bool IsNew(object o) { + return true; + } + public static class Owner { + [Pure] + public static bool Same(object o, object p) { + return true; + } + [Pure] + public static void AssignSame(object o, object p) { + } + [Pure] + public static object ElementProxy(object o) { + return o; + } + [Pure] + public static bool None(object o) { + return true; + } + [Pure] + public static bool Different(object o, object p) { + return true; + } + [Pure] + public static bool New(object o) { + return true; + } + } + [Pure] + public static void LoopInvariant(bool p) { + Contract.Assert(p); + } + public class UnreachableException : Exception { + public UnreachableException() { + } + } + //[Pure] + //public static bool IsValid(Microsoft.Dafny.Expression expression) { + // return true; + //} + //public static List toList(PureCollections.Sequence s) { + // List toRet = new List(); + // foreach (T t in s.elems) + // if(t!=null) + // toRet.Add(t); + // return toRet; + //} + + //internal static bool NonNullElements(Set set) { + // return set != null && Contract.ForAll(0,set.Count, i => set[i] != null); + //} +} + +public class PeerAttribute : SA { +} +public class RepAttribute : SA { +} +public class CapturedAttribute : SA { +} +public class NotDelayedAttribute : SA { +} +public class NoDefaultContractAttribute : SA { +} +public class VerifyAttribute : SA { + public VerifyAttribute(bool b) { + + } +} +public class StrictReadonlyAttribute : SA { +} +public class AdditiveAttribute : SA { +} +public class ReadsAttribute : SA { + public enum Reads { + Nothing, + Everything, + }; + public ReadsAttribute(object o) { + } +} +public class GlobalAccessAttribute : SA { + public GlobalAccessAttribute(bool b) { + } +} +public class EscapesAttribute : SA { + public EscapesAttribute(bool b, bool b_2) { + } +} +public class NeedsContractsAttribute : SA { + public NeedsContractsAttribute() { + } + public NeedsContractsAttribute(bool ret, bool parameters) { + } + public NeedsContractsAttribute(bool ret, int[] parameters) { + } +} +public class ImmutableAttribute : SA { +} +public class InsideAttribute : SA { +} +public class SpecPublicAttribute : SA { +} +public class ElementsPeerAttribute : SA { +} +public class ResultNotNewlyAllocatedAttribute : SA { +} +public class OnceAttribute : SA { } \ No newline at end of file diff --git a/Source/Boogie.sln b/Source/Boogie.sln index f16c1032..0823775c 100644 --- a/Source/Boogie.sln +++ b/Source/Boogie.sln @@ -1,643 +1,643 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Provers", "Provers", "{B758C1E3-824A-439F-AA2F-0BA1143E8C8D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BoogieDriver", "BoogieDriver\BoogieDriver.csproj", "{DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}" - ProjectSection(ProjectDependencies) = postProject - {D07B8E38-E172-47F4-AD02-0373014A46D3} = {D07B8E38-E172-47F4-AD02-0373014A46D3} - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AbsInt", "AbsInt\AbsInt.csproj", "{0EFA3E43-690B-48DC-A72C-384A3EA7F31F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SMTLib", "Provers\SMTLib\SMTLib.csproj", "{9B163AA3-36BC-4AFB-88AB-79BC9E97E401}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VCGeneration", "VCGeneration\VCGeneration.csproj", "{E1F10180-C7B9-4147-B51F-FA1B701966DC}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VCExpr", "VCExpr\VCExpr.csproj", "{56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", "{B230A69C-C466-4065-B9C1-84D80E76D802}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Graph", "Graph\Graph.csproj", "{69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Basetypes", "Basetypes\Basetypes.csproj", "{43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeContractsExtender", "CodeContractsExtender\CodeContractsExtender.csproj", "{ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModelViewer", "ModelViewer\ModelViewer.csproj", "{A678C6EB-B329-46A9-BBFC-7585F01ACD7C}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "Model\Model.csproj", "{ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParserHelper", "ParserHelper\ParserHelper.csproj", "{FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Houdini", "Houdini\Houdini.csproj", "{CF41E903-78EB-43BA-A355-E5FEB5ECECD4}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Predication", "Predication\Predication.csproj", "{AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Doomed", "Doomed\Doomed.csproj", "{884386A3-58E9-40BB-A273-B24976775553}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExecutionEngine", "ExecutionEngine\ExecutionEngine.csproj", "{EAA5EB79-D475-4601-A59B-825C191CD25F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BVD", "BVD\BVD.csproj", "{8A05D14E-F2BF-4890-BBE0-D76B18A50797}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Concurrency", "Concurrency\Concurrency.csproj", "{D07B8E38-E172-47F4-AD02-0373014A46D3}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{0C77D814-EC94-45D7-9F9B-213C425D0F15}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoreTests", "UnitTests\CoreTests\CoreTests.csproj", "{961B3BCA-2067-43B2-8E43-23C4293F21B9}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtil", "UnitTests\TestUtil\TestUtil.csproj", "{59118E35-4236-495E-AF6E-0D641302ED2C}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasetypesTests", "UnitTests\BasetypesTests\BasetypesTests.csproj", "{D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Checked|.NET = Checked|.NET - Checked|Any CPU = Checked|Any CPU - Checked|Mixed Platforms = Checked|Mixed Platforms - Checked|x86 = Checked|x86 - Debug|.NET = Debug|.NET - Debug|Any CPU = Debug|Any CPU - Debug|Mixed Platforms = Debug|Mixed Platforms - Debug|x86 = Debug|x86 - Release|.NET = Release|.NET - Release|Any CPU = Release|Any CPU - Release|Mixed Platforms = Release|Mixed Platforms - Release|x86 = Release|x86 - z3apidebug|.NET = z3apidebug|.NET - z3apidebug|Any CPU = z3apidebug|Any CPU - z3apidebug|Mixed Platforms = z3apidebug|Mixed Platforms - z3apidebug|x86 = z3apidebug|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|.NET.ActiveCfg = Checked|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|.NET.Build.0 = Checked|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|Any CPU.Build.0 = Checked|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|x86.ActiveCfg = Checked|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|.NET.ActiveCfg = Debug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|.NET.Build.0 = Debug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|x86.ActiveCfg = Debug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|.NET.ActiveCfg = Release|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|.NET.Build.0 = Release|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|Any CPU.Build.0 = Release|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|x86.ActiveCfg = Release|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|x86.ActiveCfg = z3apidebug|x86 - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|x86.Build.0 = z3apidebug|x86 - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|.NET.ActiveCfg = Checked|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|.NET.Build.0 = Checked|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|Any CPU.Build.0 = Checked|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|x86.ActiveCfg = Checked|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|.NET.ActiveCfg = Debug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|.NET.Build.0 = Debug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|x86.ActiveCfg = Debug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|.NET.ActiveCfg = Release|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|.NET.Build.0 = Release|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|Any CPU.Build.0 = Release|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|x86.ActiveCfg = Release|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|x86.ActiveCfg = z3apidebug|x86 - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|x86.Build.0 = z3apidebug|x86 - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|.NET.ActiveCfg = Checked|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|.NET.Build.0 = Checked|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|Any CPU.Build.0 = Checked|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|x86.ActiveCfg = Checked|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|.NET.ActiveCfg = Debug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|.NET.Build.0 = Debug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|x86.ActiveCfg = Debug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|.NET.ActiveCfg = Release|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|Any CPU.Build.0 = Release|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|x86.ActiveCfg = Release|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|.NET.ActiveCfg = Checked|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|.NET.Build.0 = Checked|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|Any CPU.Build.0 = Checked|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|x86.ActiveCfg = Checked|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|.NET.ActiveCfg = Debug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|.NET.Build.0 = Debug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|x86.ActiveCfg = Debug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|.NET.ActiveCfg = Release|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|Any CPU.Build.0 = Release|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|x86.ActiveCfg = Release|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|.NET.ActiveCfg = Checked|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|.NET.Build.0 = Checked|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|Any CPU.Build.0 = Checked|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|x86.ActiveCfg = Checked|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|.NET.ActiveCfg = Debug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|.NET.Build.0 = Debug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|x86.ActiveCfg = Debug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|.NET.ActiveCfg = Release|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|Any CPU.Build.0 = Release|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|x86.ActiveCfg = Release|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|.NET.ActiveCfg = Checked|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|.NET.Build.0 = Checked|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|Any CPU.Build.0 = Checked|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|x86.ActiveCfg = Checked|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|.NET.ActiveCfg = Debug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|.NET.Build.0 = Debug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|x86.ActiveCfg = Debug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|.NET.ActiveCfg = Release|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|.NET.Build.0 = Release|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|Any CPU.Build.0 = Release|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|x86.ActiveCfg = Release|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|.NET.ActiveCfg = Checked|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|.NET.Build.0 = Checked|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|Any CPU.Build.0 = Checked|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|x86.ActiveCfg = Checked|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|.NET.ActiveCfg = Debug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|.NET.Build.0 = Debug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|x86.ActiveCfg = Debug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|.NET.ActiveCfg = Release|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|Any CPU.Build.0 = Release|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|x86.ActiveCfg = Release|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|.NET.ActiveCfg = Checked|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|.NET.Build.0 = Checked|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|Any CPU.Build.0 = Checked|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|x86.ActiveCfg = Checked|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|.NET.ActiveCfg = Debug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|.NET.Build.0 = Debug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|x86.ActiveCfg = Debug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|.NET.ActiveCfg = Release|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|.NET.Build.0 = Release|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|Any CPU.Build.0 = Release|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|x86.ActiveCfg = Release|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|.NET.ActiveCfg = Checked|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|.NET.Build.0 = Checked|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|Any CPU.Build.0 = Checked|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|x86.ActiveCfg = Checked|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|.NET.ActiveCfg = Debug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|.NET.Build.0 = Debug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|x86.ActiveCfg = Debug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|.NET.ActiveCfg = Release|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|.NET.Build.0 = Release|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|Any CPU.Build.0 = Release|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|x86.ActiveCfg = Release|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|.NET.ActiveCfg = Checked|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|.NET.Build.0 = Checked|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|Any CPU.ActiveCfg = Checked|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|Mixed Platforms.ActiveCfg = Checked|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|Mixed Platforms.Build.0 = Checked|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|x86.ActiveCfg = Checked|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|x86.Build.0 = Checked|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|.NET.ActiveCfg = Debug|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|.NET.Build.0 = Debug|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|Any CPU.ActiveCfg = Debug|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|x86.ActiveCfg = Debug|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|x86.Build.0 = Debug|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|.NET.ActiveCfg = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|Any CPU.ActiveCfg = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|Mixed Platforms.Build.0 = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|x86.ActiveCfg = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|x86.Build.0 = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|.NET.ActiveCfg = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|Any CPU.ActiveCfg = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|Mixed Platforms.ActiveCfg = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|Mixed Platforms.Build.0 = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|x86.ActiveCfg = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|x86.Build.0 = Release|x86 - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|.NET.ActiveCfg = Checked|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|.NET.Build.0 = Checked|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Any CPU.Build.0 = Checked|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|x86.ActiveCfg = Checked|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|.NET.ActiveCfg = Debug|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|.NET.Build.0 = Debug|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|x86.ActiveCfg = Debug|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|.NET.ActiveCfg = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Any CPU.Build.0 = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|x86.ActiveCfg = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|x86.Build.0 = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|.NET.ActiveCfg = Checked|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|.NET.Build.0 = Checked|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|Any CPU.Build.0 = Checked|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|x86.ActiveCfg = Checked|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|.NET.ActiveCfg = Debug|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|.NET.Build.0 = Debug|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|x86.ActiveCfg = Debug|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|.NET.ActiveCfg = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|Any CPU.Build.0 = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|x86.ActiveCfg = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|x86.Build.0 = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|.NET.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|.NET.Build.0 = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|Any CPU.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|Any CPU.Build.0 = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|x86.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|.NET.ActiveCfg = Debug|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|.NET.Build.0 = Debug|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|x86.ActiveCfg = Debug|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|.NET.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|Any CPU.Build.0 = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|x86.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|x86.Build.0 = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|.NET.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|.NET.Build.0 = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Any CPU.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Any CPU.Build.0 = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|x86.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|.NET.ActiveCfg = Debug|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|.NET.Build.0 = Debug|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|x86.ActiveCfg = Debug|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|.NET.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Any CPU.Build.0 = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|x86.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Checked|.NET.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Checked|.NET.Build.0 = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Checked|Any CPU.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Checked|Any CPU.Build.0 = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Checked|x86.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Debug|.NET.ActiveCfg = Debug|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Debug|.NET.Build.0 = Debug|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Debug|Any CPU.Build.0 = Debug|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Debug|x86.ActiveCfg = Debug|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Release|.NET.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Release|.NET.Build.0 = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Release|Any CPU.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Release|Any CPU.Build.0 = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Release|x86.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|.NET.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|.NET.Build.0 = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|Any CPU.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|Any CPU.Build.0 = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|x86.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|.NET.ActiveCfg = Debug|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|.NET.Build.0 = Debug|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|x86.ActiveCfg = Debug|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|.NET.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|Any CPU.Build.0 = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|x86.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|.NET.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|.NET.Build.0 = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|Any CPU.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|Any CPU.Build.0 = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|x86.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|.NET.ActiveCfg = Debug|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|.NET.Build.0 = Debug|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|x86.ActiveCfg = Debug|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|.NET.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|.NET.Build.0 = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|Any CPU.Build.0 = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|x86.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|.NET.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|.NET.Build.0 = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|Any CPU.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|Any CPU.Build.0 = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|x86.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|.NET.ActiveCfg = Debug|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|.NET.Build.0 = Debug|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|x86.ActiveCfg = Debug|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|.NET.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|.NET.Build.0 = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|Any CPU.Build.0 = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|x86.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|.NET.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|Any CPU.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|Any CPU.Build.0 = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|x86.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|.NET.ActiveCfg = Debug|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|x86.ActiveCfg = Debug|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|.NET.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|Any CPU.Build.0 = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|x86.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|.NET.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|Any CPU.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|Any CPU.Build.0 = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|x86.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|.NET.ActiveCfg = Debug|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|x86.ActiveCfg = Debug|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|.NET.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|Any CPU.Build.0 = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|x86.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|.NET.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|Any CPU.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|Any CPU.Build.0 = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|x86.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|.NET.ActiveCfg = Debug|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|x86.ActiveCfg = Debug|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|.NET.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|Any CPU.Build.0 = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|x86.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|x86.ActiveCfg = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401} = {B758C1E3-824A-439F-AA2F-0BA1143E8C8D} - {961B3BCA-2067-43B2-8E43-23C4293F21B9} = {0C77D814-EC94-45D7-9F9B-213C425D0F15} - {59118E35-4236-495E-AF6E-0D641302ED2C} = {0C77D814-EC94-45D7-9F9B-213C425D0F15} - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9} = {0C77D814-EC94-45D7-9F9B-213C425D0F15} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Provers", "Provers", "{B758C1E3-824A-439F-AA2F-0BA1143E8C8D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BoogieDriver", "BoogieDriver\BoogieDriver.csproj", "{DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}" + ProjectSection(ProjectDependencies) = postProject + {D07B8E38-E172-47F4-AD02-0373014A46D3} = {D07B8E38-E172-47F4-AD02-0373014A46D3} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AbsInt", "AbsInt\AbsInt.csproj", "{0EFA3E43-690B-48DC-A72C-384A3EA7F31F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SMTLib", "Provers\SMTLib\SMTLib.csproj", "{9B163AA3-36BC-4AFB-88AB-79BC9E97E401}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VCGeneration", "VCGeneration\VCGeneration.csproj", "{E1F10180-C7B9-4147-B51F-FA1B701966DC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VCExpr", "VCExpr\VCExpr.csproj", "{56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", "{B230A69C-C466-4065-B9C1-84D80E76D802}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Graph", "Graph\Graph.csproj", "{69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Basetypes", "Basetypes\Basetypes.csproj", "{43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeContractsExtender", "CodeContractsExtender\CodeContractsExtender.csproj", "{ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModelViewer", "ModelViewer\ModelViewer.csproj", "{A678C6EB-B329-46A9-BBFC-7585F01ACD7C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "Model\Model.csproj", "{ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParserHelper", "ParserHelper\ParserHelper.csproj", "{FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Houdini", "Houdini\Houdini.csproj", "{CF41E903-78EB-43BA-A355-E5FEB5ECECD4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Predication", "Predication\Predication.csproj", "{AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Doomed", "Doomed\Doomed.csproj", "{884386A3-58E9-40BB-A273-B24976775553}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExecutionEngine", "ExecutionEngine\ExecutionEngine.csproj", "{EAA5EB79-D475-4601-A59B-825C191CD25F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BVD", "BVD\BVD.csproj", "{8A05D14E-F2BF-4890-BBE0-D76B18A50797}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Concurrency", "Concurrency\Concurrency.csproj", "{D07B8E38-E172-47F4-AD02-0373014A46D3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{0C77D814-EC94-45D7-9F9B-213C425D0F15}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoreTests", "UnitTests\CoreTests\CoreTests.csproj", "{961B3BCA-2067-43B2-8E43-23C4293F21B9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtil", "UnitTests\TestUtil\TestUtil.csproj", "{59118E35-4236-495E-AF6E-0D641302ED2C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasetypesTests", "UnitTests\BasetypesTests\BasetypesTests.csproj", "{D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Checked|.NET = Checked|.NET + Checked|Any CPU = Checked|Any CPU + Checked|Mixed Platforms = Checked|Mixed Platforms + Checked|x86 = Checked|x86 + Debug|.NET = Debug|.NET + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|.NET = Release|.NET + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + z3apidebug|.NET = z3apidebug|.NET + z3apidebug|Any CPU = z3apidebug|Any CPU + z3apidebug|Mixed Platforms = z3apidebug|Mixed Platforms + z3apidebug|x86 = z3apidebug|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|.NET.ActiveCfg = Checked|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|.NET.Build.0 = Checked|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|Any CPU.Build.0 = Checked|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|x86.ActiveCfg = Checked|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|.NET.ActiveCfg = Debug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|.NET.Build.0 = Debug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|x86.ActiveCfg = Debug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|.NET.ActiveCfg = Release|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|.NET.Build.0 = Release|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|Any CPU.Build.0 = Release|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|x86.ActiveCfg = Release|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|x86.ActiveCfg = z3apidebug|x86 + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|x86.Build.0 = z3apidebug|x86 + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|.NET.ActiveCfg = Checked|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|.NET.Build.0 = Checked|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|Any CPU.Build.0 = Checked|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|x86.ActiveCfg = Checked|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|.NET.ActiveCfg = Debug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|.NET.Build.0 = Debug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|x86.ActiveCfg = Debug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|.NET.ActiveCfg = Release|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|.NET.Build.0 = Release|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|Any CPU.Build.0 = Release|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|x86.ActiveCfg = Release|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|x86.ActiveCfg = z3apidebug|x86 + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|x86.Build.0 = z3apidebug|x86 + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|.NET.ActiveCfg = Checked|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|.NET.Build.0 = Checked|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|Any CPU.Build.0 = Checked|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|x86.ActiveCfg = Checked|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|.NET.ActiveCfg = Debug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|.NET.Build.0 = Debug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|x86.ActiveCfg = Debug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|.NET.ActiveCfg = Release|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|Any CPU.Build.0 = Release|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|x86.ActiveCfg = Release|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|.NET.ActiveCfg = Checked|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|.NET.Build.0 = Checked|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|Any CPU.Build.0 = Checked|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|x86.ActiveCfg = Checked|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|.NET.ActiveCfg = Debug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|.NET.Build.0 = Debug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|x86.ActiveCfg = Debug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|.NET.ActiveCfg = Release|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|Any CPU.Build.0 = Release|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|x86.ActiveCfg = Release|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|.NET.ActiveCfg = Checked|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|.NET.Build.0 = Checked|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|Any CPU.Build.0 = Checked|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|x86.ActiveCfg = Checked|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|.NET.ActiveCfg = Debug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|.NET.Build.0 = Debug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|x86.ActiveCfg = Debug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|.NET.ActiveCfg = Release|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|Any CPU.Build.0 = Release|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|x86.ActiveCfg = Release|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|.NET.ActiveCfg = Checked|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|.NET.Build.0 = Checked|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|Any CPU.Build.0 = Checked|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|x86.ActiveCfg = Checked|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|.NET.ActiveCfg = Debug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|.NET.Build.0 = Debug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|x86.ActiveCfg = Debug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|.NET.ActiveCfg = Release|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|.NET.Build.0 = Release|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|Any CPU.Build.0 = Release|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|x86.ActiveCfg = Release|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|.NET.ActiveCfg = Checked|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|.NET.Build.0 = Checked|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|Any CPU.Build.0 = Checked|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|x86.ActiveCfg = Checked|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|.NET.ActiveCfg = Debug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|.NET.Build.0 = Debug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|x86.ActiveCfg = Debug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|.NET.ActiveCfg = Release|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|Any CPU.Build.0 = Release|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|x86.ActiveCfg = Release|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|.NET.ActiveCfg = Checked|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|.NET.Build.0 = Checked|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|Any CPU.Build.0 = Checked|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|x86.ActiveCfg = Checked|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|.NET.ActiveCfg = Debug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|.NET.Build.0 = Debug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|x86.ActiveCfg = Debug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|.NET.ActiveCfg = Release|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|.NET.Build.0 = Release|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|Any CPU.Build.0 = Release|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|x86.ActiveCfg = Release|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|.NET.ActiveCfg = Checked|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|.NET.Build.0 = Checked|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|Any CPU.Build.0 = Checked|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|x86.ActiveCfg = Checked|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|.NET.ActiveCfg = Debug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|.NET.Build.0 = Debug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|x86.ActiveCfg = Debug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|.NET.ActiveCfg = Release|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|.NET.Build.0 = Release|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|Any CPU.Build.0 = Release|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|x86.ActiveCfg = Release|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|.NET.ActiveCfg = Checked|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|.NET.Build.0 = Checked|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|Any CPU.ActiveCfg = Checked|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|Mixed Platforms.ActiveCfg = Checked|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|Mixed Platforms.Build.0 = Checked|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|x86.ActiveCfg = Checked|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|x86.Build.0 = Checked|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|.NET.ActiveCfg = Debug|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|.NET.Build.0 = Debug|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|Any CPU.ActiveCfg = Debug|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|x86.ActiveCfg = Debug|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|x86.Build.0 = Debug|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|.NET.ActiveCfg = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|Any CPU.ActiveCfg = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|Mixed Platforms.Build.0 = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|x86.ActiveCfg = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|x86.Build.0 = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|.NET.ActiveCfg = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|Any CPU.ActiveCfg = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|Mixed Platforms.ActiveCfg = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|Mixed Platforms.Build.0 = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|x86.ActiveCfg = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|x86.Build.0 = Release|x86 + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|.NET.ActiveCfg = Checked|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|.NET.Build.0 = Checked|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Any CPU.Build.0 = Checked|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|x86.ActiveCfg = Checked|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|.NET.ActiveCfg = Debug|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|.NET.Build.0 = Debug|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|x86.ActiveCfg = Debug|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|.NET.ActiveCfg = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Any CPU.Build.0 = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|x86.ActiveCfg = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|x86.Build.0 = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|.NET.ActiveCfg = Checked|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|.NET.Build.0 = Checked|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|Any CPU.Build.0 = Checked|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|x86.ActiveCfg = Checked|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|.NET.ActiveCfg = Debug|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|.NET.Build.0 = Debug|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|x86.ActiveCfg = Debug|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|.NET.ActiveCfg = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|Any CPU.Build.0 = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|x86.ActiveCfg = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|x86.Build.0 = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|.NET.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|.NET.Build.0 = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|Any CPU.Build.0 = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|x86.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|.NET.ActiveCfg = Debug|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|.NET.Build.0 = Debug|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|x86.ActiveCfg = Debug|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|.NET.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|Any CPU.Build.0 = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|x86.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|x86.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|.NET.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|.NET.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Any CPU.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|x86.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|.NET.ActiveCfg = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|.NET.Build.0 = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|x86.ActiveCfg = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|.NET.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Any CPU.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|x86.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|.NET.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|.NET.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|Any CPU.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|x86.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|.NET.ActiveCfg = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|.NET.Build.0 = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|Any CPU.Build.0 = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|x86.ActiveCfg = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|.NET.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|.NET.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|Any CPU.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|Any CPU.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|x86.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|.NET.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|.NET.Build.0 = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|Any CPU.Build.0 = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|x86.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|.NET.ActiveCfg = Debug|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|.NET.Build.0 = Debug|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|x86.ActiveCfg = Debug|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|.NET.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|Any CPU.Build.0 = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|x86.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|.NET.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|.NET.Build.0 = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|Any CPU.Build.0 = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|x86.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|.NET.ActiveCfg = Debug|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|.NET.Build.0 = Debug|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|x86.ActiveCfg = Debug|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|.NET.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|.NET.Build.0 = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|Any CPU.Build.0 = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|x86.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|.NET.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|.NET.Build.0 = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|Any CPU.Build.0 = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|x86.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|.NET.ActiveCfg = Debug|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|.NET.Build.0 = Debug|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|x86.ActiveCfg = Debug|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|.NET.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|.NET.Build.0 = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|Any CPU.Build.0 = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|x86.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|.NET.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|Any CPU.Build.0 = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|x86.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|.NET.ActiveCfg = Debug|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|x86.ActiveCfg = Debug|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|.NET.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|Any CPU.Build.0 = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|x86.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|.NET.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|Any CPU.Build.0 = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|x86.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|.NET.ActiveCfg = Debug|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|x86.ActiveCfg = Debug|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|.NET.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|Any CPU.Build.0 = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|x86.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|.NET.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|Any CPU.Build.0 = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|x86.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|.NET.ActiveCfg = Debug|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|x86.ActiveCfg = Debug|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|.NET.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|Any CPU.Build.0 = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|x86.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|x86.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401} = {B758C1E3-824A-439F-AA2F-0BA1143E8C8D} + {961B3BCA-2067-43B2-8E43-23C4293F21B9} = {0C77D814-EC94-45D7-9F9B-213C425D0F15} + {59118E35-4236-495E-AF6E-0D641302ED2C} = {0C77D814-EC94-45D7-9F9B-213C425D0F15} + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9} = {0C77D814-EC94-45D7-9F9B-213C425D0F15} + EndGlobalSection +EndGlobal diff --git a/Source/BoogieDriver/BoogieDriver.cs b/Source/BoogieDriver/BoogieDriver.cs index fa038803..be88a745 100644 --- a/Source/BoogieDriver/BoogieDriver.cs +++ b/Source/BoogieDriver/BoogieDriver.cs @@ -1,106 +1,106 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -//--------------------------------------------------------------------------------------------- -// OnlyBoogie OnlyBoogie.ssc -// - main program for taking a BPL program and verifying it -//--------------------------------------------------------------------------------------------- - -namespace Microsoft.Boogie { - using System; - using System.IO; - using System.Collections.Generic; - using System.Diagnostics.Contracts; - - /* - The following assemblies are referenced because they are needed at runtime, not at compile time: - BaseTypes - Provers.Z3 - System.Compiler.Framework - */ - - public class OnlyBoogie - { - - public static int Main(string[] args) - { - Contract.Requires(cce.NonNullElements(args)); - - ExecutionEngine.printer = new ConsolePrinter(); - - CommandLineOptions.Install(new CommandLineOptions()); - - CommandLineOptions.Clo.RunningBoogieFromCommandLine = true; - if (!CommandLineOptions.Clo.Parse(args)) { - goto END; - } - if (CommandLineOptions.Clo.Files.Count == 0) { - ExecutionEngine.printer.ErrorWriteLine(Console.Out, "*** Error: No input files were specified."); - goto END; - } - if (CommandLineOptions.Clo.XmlSink != null) { - string errMsg = CommandLineOptions.Clo.XmlSink.Open(); - if (errMsg != null) { - ExecutionEngine.printer.ErrorWriteLine(Console.Out, "*** Error: " + errMsg); - goto END; - } - } - if (!CommandLineOptions.Clo.DontShowLogo) { - Console.WriteLine(CommandLineOptions.Clo.Version); - } - if (CommandLineOptions.Clo.ShowEnv == CommandLineOptions.ShowEnvironment.Always) { - Console.WriteLine("---Command arguments"); - foreach (string arg in args) { - Contract.Assert(arg != null); - Console.WriteLine(arg); - } - - Console.WriteLine("--------------------"); - } - - Helpers.ExtraTraceInformation("Becoming sentient"); - - List fileList = new List(); - foreach (string file in CommandLineOptions.Clo.Files) { - string extension = Path.GetExtension(file); - if (extension != null) { - extension = extension.ToLower(); - } - if (extension == ".txt") { - StreamReader stream = new StreamReader(file); - string s = stream.ReadToEnd(); - fileList.AddRange(s.Split(new char[3] {' ', '\n', '\r'}, StringSplitOptions.RemoveEmptyEntries)); - } - else { - fileList.Add(file); - } - } - foreach (string file in fileList) { - Contract.Assert(file != null); - string extension = Path.GetExtension(file); - if (extension != null) { - extension = extension.ToLower(); - } - if (extension != ".bpl") { - ExecutionEngine.printer.ErrorWriteLine(Console.Out, "*** Error: '{0}': Filename extension '{1}' is not supported. Input files must be BoogiePL programs (.bpl).", file, - extension == null ? "" : extension); - goto END; - } - } - ExecutionEngine.ProcessFiles(fileList); - return 0; - - END: - if (CommandLineOptions.Clo.XmlSink != null) { - CommandLineOptions.Clo.XmlSink.Close(); - } - if (CommandLineOptions.Clo.Wait) { - Console.WriteLine("Press Enter to exit."); - Console.ReadLine(); - } - return 1; - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- +// OnlyBoogie OnlyBoogie.ssc +// - main program for taking a BPL program and verifying it +//--------------------------------------------------------------------------------------------- + +namespace Microsoft.Boogie { + using System; + using System.IO; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + + /* + The following assemblies are referenced because they are needed at runtime, not at compile time: + BaseTypes + Provers.Z3 + System.Compiler.Framework + */ + + public class OnlyBoogie + { + + public static int Main(string[] args) + { + Contract.Requires(cce.NonNullElements(args)); + + ExecutionEngine.printer = new ConsolePrinter(); + + CommandLineOptions.Install(new CommandLineOptions()); + + CommandLineOptions.Clo.RunningBoogieFromCommandLine = true; + if (!CommandLineOptions.Clo.Parse(args)) { + goto END; + } + if (CommandLineOptions.Clo.Files.Count == 0) { + ExecutionEngine.printer.ErrorWriteLine(Console.Out, "*** Error: No input files were specified."); + goto END; + } + if (CommandLineOptions.Clo.XmlSink != null) { + string errMsg = CommandLineOptions.Clo.XmlSink.Open(); + if (errMsg != null) { + ExecutionEngine.printer.ErrorWriteLine(Console.Out, "*** Error: " + errMsg); + goto END; + } + } + if (!CommandLineOptions.Clo.DontShowLogo) { + Console.WriteLine(CommandLineOptions.Clo.Version); + } + if (CommandLineOptions.Clo.ShowEnv == CommandLineOptions.ShowEnvironment.Always) { + Console.WriteLine("---Command arguments"); + foreach (string arg in args) { + Contract.Assert(arg != null); + Console.WriteLine(arg); + } + + Console.WriteLine("--------------------"); + } + + Helpers.ExtraTraceInformation("Becoming sentient"); + + List fileList = new List(); + foreach (string file in CommandLineOptions.Clo.Files) { + string extension = Path.GetExtension(file); + if (extension != null) { + extension = extension.ToLower(); + } + if (extension == ".txt") { + StreamReader stream = new StreamReader(file); + string s = stream.ReadToEnd(); + fileList.AddRange(s.Split(new char[3] {' ', '\n', '\r'}, StringSplitOptions.RemoveEmptyEntries)); + } + else { + fileList.Add(file); + } + } + foreach (string file in fileList) { + Contract.Assert(file != null); + string extension = Path.GetExtension(file); + if (extension != null) { + extension = extension.ToLower(); + } + if (extension != ".bpl") { + ExecutionEngine.printer.ErrorWriteLine(Console.Out, "*** Error: '{0}': Filename extension '{1}' is not supported. Input files must be BoogiePL programs (.bpl).", file, + extension == null ? "" : extension); + goto END; + } + } + ExecutionEngine.ProcessFiles(fileList); + return 0; + + END: + if (CommandLineOptions.Clo.XmlSink != null) { + CommandLineOptions.Clo.XmlSink.Close(); + } + if (CommandLineOptions.Clo.Wait) { + Console.WriteLine("Press Enter to exit."); + Console.ReadLine(); + } + return 1; + } + } +} diff --git a/Source/BoogieDriver/BoogieDriver.csproj b/Source/BoogieDriver/BoogieDriver.csproj index 14d607f9..90e0be41 100644 --- a/Source/BoogieDriver/BoogieDriver.csproj +++ b/Source/BoogieDriver/BoogieDriver.csproj @@ -1,324 +1,324 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A} - Exe - Properties - BoogieDriver - Boogie - v4.0 - 512 - 1 - true - ..\InterimKey.snk - - - 3.5 - - false - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - true - - - true - full - false - ..\..\Binaries\ - TRACE;DEBUG - prompt - 4 - False - False - True - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - - - - - - - Full - %28none%29 - AllRules.ruleset - - - pdbonly - true - ..\..\Binaries\ - TRACE - prompt - 4 - AllRules.ruleset - - - true - ..\Provers\Z3api\bin\z3apidebug\ - DEBUG;TRACE - full - x86 - - - true - GlobalSuppressions.cs - prompt - Migrated rules for BoogieDriver.ruleset - true - 4 - false - - - true - ..\..\Binaries\ - DEBUG;TRACE - full - AnyCPU - ..\..\Binaries\Boogie.exe.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - True - False - True - False - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - False - Full - Build - 0 - 4 - false - - - true - bin\x86\Debug\ - TRACE;DEBUG - full - x86 - ..\..\Binaries\Boogie.exe.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - false - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - 4 - false - - - bin\x86\Release\ - TRACE - true - pdbonly - x86 - bin\Release\Boogie.exe.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - false - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - false - 4 - - - true - bin\x86\z3apidebug\ - DEBUG;TRACE - full - x86 - bin\z3apidebug\Boogie.exe.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - Migrated rules for BoogieDriver.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - false - true - 4 - false - - - true - bin\x86\Checked\ - DEBUG;TRACE - full - x86 - ..\..\Binaries\Boogie.exe.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - false - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - false - 4 - false - - - true - bin\QED\ - TRACE;DEBUG - full - AnyCPU - prompt - AllRules.ruleset - - - true - ..\..\Binaries\ - TRACE;DEBUG - full - AnyCPU - prompt - AllRules.ruleset - false - - - - - - - - - - - - - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F} - AbsInt - - - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} - Basetypes - - - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} - CodeContractsExtender - - - {B230A69C-C466-4065-B9C1-84D80E76D802} - Core - - - {884386A3-58E9-40BB-A273-B24976775553} - Doomed - - - {EAA5EB79-D475-4601-A59B-825C191CD25F} - ExecutionEngine - - - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E} - Graph - - - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4} - Houdini - - - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5} - ParserHelper - - - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44} - Predication - - - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401} - SMTLib - - - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1} - VCExpr - - - {E1F10180-C7B9-4147-B51F-FA1B701966DC} - VCGeneration - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - + + + + Debug + AnyCPU + 9.0.21022 + 2.0 + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A} + Exe + Properties + BoogieDriver + Boogie + v4.0 + 512 + 1 + true + ..\InterimKey.snk + + + 3.5 + + false + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + true + + + true + full + false + ..\..\Binaries\ + TRACE;DEBUG + prompt + 4 + False + False + True + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + + + + + + + Full + %28none%29 + AllRules.ruleset + + + pdbonly + true + ..\..\Binaries\ + TRACE + prompt + 4 + AllRules.ruleset + + + true + ..\Provers\Z3api\bin\z3apidebug\ + DEBUG;TRACE + full + x86 + + + true + GlobalSuppressions.cs + prompt + Migrated rules for BoogieDriver.ruleset + true + 4 + false + + + true + ..\..\Binaries\ + DEBUG;TRACE + full + AnyCPU + ..\..\Binaries\Boogie.exe.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + True + False + True + False + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + False + Full + Build + 0 + 4 + false + + + true + bin\x86\Debug\ + TRACE;DEBUG + full + x86 + ..\..\Binaries\Boogie.exe.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + false + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + 4 + false + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + bin\Release\Boogie.exe.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + false + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + false + 4 + + + true + bin\x86\z3apidebug\ + DEBUG;TRACE + full + x86 + bin\z3apidebug\Boogie.exe.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + Migrated rules for BoogieDriver.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + false + true + 4 + false + + + true + bin\x86\Checked\ + DEBUG;TRACE + full + x86 + ..\..\Binaries\Boogie.exe.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + false + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + false + 4 + false + + + true + bin\QED\ + TRACE;DEBUG + full + AnyCPU + prompt + AllRules.ruleset + + + true + ..\..\Binaries\ + TRACE;DEBUG + full + AnyCPU + prompt + AllRules.ruleset + false + + + + + + + + + + + + + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F} + AbsInt + + + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} + Basetypes + + + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} + CodeContractsExtender + + + {B230A69C-C466-4065-B9C1-84D80E76D802} + Core + + + {884386A3-58E9-40BB-A273-B24976775553} + Doomed + + + {EAA5EB79-D475-4601-A59B-825C191CD25F} + ExecutionEngine + + + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E} + Graph + + + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4} + Houdini + + + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5} + ParserHelper + + + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44} + Predication + + + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401} + SMTLib + + + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1} + VCExpr + + + {E1F10180-C7B9-4147-B51F-FA1B701966DC} + VCGeneration + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + \ No newline at end of file diff --git a/Source/BoogieDriver/cce.cs b/Source/BoogieDriver/cce.cs index 23d79815..42cabfcb 100644 --- a/Source/BoogieDriver/cce.cs +++ b/Source/BoogieDriver/cce.cs @@ -1,105 +1,105 @@ - -using System; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Text; -using Microsoft.Boogie; - - /// - /// A class containing static methods to extend the functionality of Code Contracts - /// - -public static class cce { - [Pure] - public static T NonNull(T t) { - Contract.Assert(t != null); - return t; - } - [Pure] - public static bool NonNullElements(IEnumerable collection) { - return collection != null && Contract.ForAll(collection, c => c != null); - } - [Pure] - public static bool NonNullElements(IDictionary collection) { - return collection != null && NonNullElements(collection.Keys) && NonNullElements(collection.Values); - } - [Pure] - public static bool NonNullElements(VariableSeq collection) { - return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); - } - [Pure] - public static void BeginExpose(object o) { - } - [Pure] - public static void EndExpose() { - } - [Pure] - public static bool IsPeerConsistent(object o) { - return true; - } - [Pure] - public static bool IsConsistent(object o) { - return true; - } - [Pure] - public static bool IsExposable(object o) { - return true; - } - [Pure] - public static bool IsExposed(object o) { - return true; - } - public static class Owner { - [Pure] - public static bool Same(object o, object p) { - return true; - } - [Pure] - public static void AssignSame(object o, object p) { - } - [Pure] - public static object ElementProxy(object o) { - return o; - } - [Pure] - public static bool None(object o) { - return true; - } - } - [Pure] - public static void LoopInvariant(bool p) { - Contract.Assert(p); - } - - public class UnreachableException : Exception { - public UnreachableException() { - } - } -} - -public class PeerAttribute : System.Attribute { -} -public class RepAttribute : System.Attribute { -} -public class CapturedAttribute : System.Attribute { -} -public class NotDelayedAttribute : System.Attribute { -} -public class NoDefaultContractAttribute : System.Attribute { -} -public class VerifyAttribute : System.Attribute { - public VerifyAttribute(bool b) { - - } -} -public class StrictReadonlyAttribute : System.Attribute { - } -public class AdditiveAttribute : System.Attribute { -} -public class ReadsAttribute : System.Attribute { - public enum Reads { - Nothing, - }; - public ReadsAttribute(object o) { - } -} + +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Text; +using Microsoft.Boogie; + + /// + /// A class containing static methods to extend the functionality of Code Contracts + /// + +public static class cce { + [Pure] + public static T NonNull(T t) { + Contract.Assert(t != null); + return t; + } + [Pure] + public static bool NonNullElements(IEnumerable collection) { + return collection != null && Contract.ForAll(collection, c => c != null); + } + [Pure] + public static bool NonNullElements(IDictionary collection) { + return collection != null && NonNullElements(collection.Keys) && NonNullElements(collection.Values); + } + [Pure] + public static bool NonNullElements(VariableSeq collection) { + return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); + } + [Pure] + public static void BeginExpose(object o) { + } + [Pure] + public static void EndExpose() { + } + [Pure] + public static bool IsPeerConsistent(object o) { + return true; + } + [Pure] + public static bool IsConsistent(object o) { + return true; + } + [Pure] + public static bool IsExposable(object o) { + return true; + } + [Pure] + public static bool IsExposed(object o) { + return true; + } + public static class Owner { + [Pure] + public static bool Same(object o, object p) { + return true; + } + [Pure] + public static void AssignSame(object o, object p) { + } + [Pure] + public static object ElementProxy(object o) { + return o; + } + [Pure] + public static bool None(object o) { + return true; + } + } + [Pure] + public static void LoopInvariant(bool p) { + Contract.Assert(p); + } + + public class UnreachableException : Exception { + public UnreachableException() { + } + } +} + +public class PeerAttribute : System.Attribute { +} +public class RepAttribute : System.Attribute { +} +public class CapturedAttribute : System.Attribute { +} +public class NotDelayedAttribute : System.Attribute { +} +public class NoDefaultContractAttribute : System.Attribute { +} +public class VerifyAttribute : System.Attribute { + public VerifyAttribute(bool b) { + + } +} +public class StrictReadonlyAttribute : System.Attribute { + } +public class AdditiveAttribute : System.Attribute { +} +public class ReadsAttribute : System.Attribute { + public enum Reads { + Nothing, + }; + public ReadsAttribute(object o) { + } +} diff --git a/Source/CodeContractsExtender/CodeContractsExtender.csproj b/Source/CodeContractsExtender/CodeContractsExtender.csproj index c87ed8ab..38535dc4 100644 --- a/Source/CodeContractsExtender/CodeContractsExtender.csproj +++ b/Source/CodeContractsExtender/CodeContractsExtender.csproj @@ -1,202 +1,202 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} - Library - Properties - CodeContractsExtender - CodeContractsExtender - v4.0 - 512 - true - ..\InterimKey.snk - 1 - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - Client - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - False - False - True - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - - - - - - - Full - %28none%29 - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - true - bin\z3apidebug\ - DEBUG;TRACE - full - AnyCPU - - - true - GlobalSuppressions.cs - prompt - Migrated rules for CodeContractsExtender.ruleset - true - 4 - false - - - true - bin\Checked\ - DEBUG;TRACE - full - AnyCPU - bin\Debug\CodeContractsExtender.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - True - False - True - False - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - False - Full - Build - 0 - 4 - false - - - true - bin\QED\ - DEBUG;TRACE - full - AnyCPU - prompt - AllRules.ruleset - - - - - 3.5 - - - 3.5 - - - 3.5 - - - - - - - version.cs - - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - - + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} + Library + Properties + CodeContractsExtender + BoogieCodeContractsExtender + v4.0 + 512 + true + ..\InterimKey.snk + 1 + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + False + False + True + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + + + + + + + Full + %28none%29 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + true + bin\z3apidebug\ + DEBUG;TRACE + full + AnyCPU + + + true + GlobalSuppressions.cs + prompt + Migrated rules for CodeContractsExtender.ruleset + true + 4 + false + + + true + bin\Checked\ + DEBUG;TRACE + full + AnyCPU + bin\Debug\CodeContractsExtender.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + True + False + True + False + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + False + Full + Build + 0 + 4 + false + + + true + bin\QED\ + DEBUG;TRACE + full + AnyCPU + prompt + AllRules.ruleset + + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + version.cs + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + \ No newline at end of file diff --git a/Source/CodeContractsExtender/cce.cs b/Source/CodeContractsExtender/cce.cs index 02b80458..0e6a0607 100644 --- a/Source/CodeContractsExtender/cce.cs +++ b/Source/CodeContractsExtender/cce.cs @@ -1,184 +1,184 @@ -using System; -using SA=System.Attribute; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Text; -//using Microsoft.Boogie; - -/// -/// A class containing static methods to extend the functionality of Code Contracts -/// - -public static class cce { - //[Pure] - //public static bool NonNullElements(Microsoft.Dafny.Graph collection) { - // return collection != null && cce.NonNullElements(collection.TopologicallySortedComponents()); - //} - [Pure] - public static T NonNull(T t) where T : class { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); - return t; - } - [Pure] - public static bool NonNullElements(IEnumerable collection) where T : class { - return collection != null && Contract.ForAll(collection, c => c != null); - } - [Pure] - public static bool NonNullDictionaryAndValues(IDictionary collection) where TValue : class { - return collection != null && cce.NonNullElements(collection.Values); - } - //[Pure] - //public static bool NonNullElements(List collection) { - // return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); - //} - /// - /// For possibly-null lists of non-null elements - /// - /// - /// - /// If true, the collection is treated as an IEnumerable<T!>?, rather than an IEnumerable<T!>! - /// - [Pure] - public static bool NonNullElements(IEnumerable collection, bool nullability) where T : class { - return (nullability && collection == null) || cce.NonNullElements(collection); - //Should be the same as: - /*if(nullability&&collection==null) - * return true; - * return cce.NonNullElements(collection) - */ - - } - [Pure] - public static bool NonNullElements(KeyValuePair kvp) where TKey : class where TValue : class { - return kvp.Key != null && kvp.Value != null; - } - [Pure] - public static bool NonNullElements(IEnumerator iEnumerator) where T : class { - return iEnumerator != null; - } - [Pure] - public static bool NonNull(HashSet set) where T : class { - return set != null && !set.Contains(null); - } - //[Pure] - //public static bool NonNullElements(Graphing.Graph graph) { - // return cce.NonNullElements(graph.TopologicalSort()); - //} - [Pure] - public static void BeginExpose(object o) { - } - [Pure] - public static void EndExpose() { - } - [Pure] - public static bool IsPeerConsistent(object o) { - return true; - } - [Pure] - public static bool IsConsistent(object o) { - return true; - } - [Pure] - public static bool IsExposable(object o) { - return true; - } - [Pure] - public static bool IsExposed(object o) { - return true; - } - [Pure] - public static bool IsNew(object o) { - return true; - } - public static class Owner { - [Pure] - public static bool Same(object o, object p) { - return true; - } - [Pure] - public static void AssignSame(object o, object p) { - } - [Pure] - public static object ElementProxy(object o) { - return o; - } - [Pure] - public static bool None(object o) { - return true; - } - [Pure] - public static bool Different(object o, object p) { - return true; - } - [Pure] - public static bool New(object o) { - return true; - } - } - [Pure] - public static void LoopInvariant(bool p) { - Contract.Assert(p); - } - public class UnreachableException : Exception { - public UnreachableException() { - } - } - -} - -public class PeerAttribute : SA { -} -public class RepAttribute : SA { -} -public class CapturedAttribute : SA { -} -public class NotDelayedAttribute : SA { -} -public class NoDefaultContractAttribute : SA { -} -public class VerifyAttribute : SA { - public VerifyAttribute(bool b) { - - } -} -public class StrictReadonlyAttribute : SA { -} -public class AdditiveAttribute : SA { -} -public class ReadsAttribute : SA { - public enum Reads { - Nothing, - Everything, - }; - public ReadsAttribute(object o) { - } -} -public class GlobalAccessAttribute : SA { - public GlobalAccessAttribute(bool b) { - } -} -public class EscapesAttribute : SA { - public EscapesAttribute(bool b, bool b_2) { - } -} -public class NeedsContractsAttribute : SA { - public NeedsContractsAttribute() { - } - public NeedsContractsAttribute(bool ret, bool parameters) { - } - public NeedsContractsAttribute(bool ret, int[] parameters) { - } -} -public class ImmutableAttribute : SA { -} -public class InsideAttribute : SA { -} -public class SpecPublicAttribute : SA { -} -public class ElementsPeerAttribute : SA { -} -public class ResultNotNewlyAllocatedAttribute : SA { -} -public class OnceAttribute : SA { +using System; +using SA=System.Attribute; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Text; +//using Microsoft.Boogie; + +/// +/// A class containing static methods to extend the functionality of Code Contracts +/// + +public static class cce { + //[Pure] + //public static bool NonNullElements(Microsoft.Dafny.Graph collection) { + // return collection != null && cce.NonNullElements(collection.TopologicallySortedComponents()); + //} + [Pure] + public static T NonNull(T t) where T : class { + Contract.Requires(t != null); + Contract.Ensures(Contract.Result() != null); + return t; + } + [Pure] + public static bool NonNullElements(IEnumerable collection) where T : class { + return collection != null && Contract.ForAll(collection, c => c != null); + } + [Pure] + public static bool NonNullDictionaryAndValues(IDictionary collection) where TValue : class { + return collection != null && cce.NonNullElements(collection.Values); + } + //[Pure] + //public static bool NonNullElements(List collection) { + // return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); + //} + /// + /// For possibly-null lists of non-null elements + /// + /// + /// + /// If true, the collection is treated as an IEnumerable<T!>?, rather than an IEnumerable<T!>! + /// + [Pure] + public static bool NonNullElements(IEnumerable collection, bool nullability) where T : class { + return (nullability && collection == null) || cce.NonNullElements(collection); + //Should be the same as: + /*if(nullability&&collection==null) + * return true; + * return cce.NonNullElements(collection) + */ + + } + [Pure] + public static bool NonNullElements(KeyValuePair kvp) where TKey : class where TValue : class { + return kvp.Key != null && kvp.Value != null; + } + [Pure] + public static bool NonNullElements(IEnumerator iEnumerator) where T : class { + return iEnumerator != null; + } + [Pure] + public static bool NonNull(HashSet set) where T : class { + return set != null && !set.Contains(null); + } + //[Pure] + //public static bool NonNullElements(Graphing.Graph graph) { + // return cce.NonNullElements(graph.TopologicalSort()); + //} + [Pure] + public static void BeginExpose(object o) { + } + [Pure] + public static void EndExpose() { + } + [Pure] + public static bool IsPeerConsistent(object o) { + return true; + } + [Pure] + public static bool IsConsistent(object o) { + return true; + } + [Pure] + public static bool IsExposable(object o) { + return true; + } + [Pure] + public static bool IsExposed(object o) { + return true; + } + [Pure] + public static bool IsNew(object o) { + return true; + } + public static class Owner { + [Pure] + public static bool Same(object o, object p) { + return true; + } + [Pure] + public static void AssignSame(object o, object p) { + } + [Pure] + public static object ElementProxy(object o) { + return o; + } + [Pure] + public static bool None(object o) { + return true; + } + [Pure] + public static bool Different(object o, object p) { + return true; + } + [Pure] + public static bool New(object o) { + return true; + } + } + [Pure] + public static void LoopInvariant(bool p) { + Contract.Assert(p); + } + public class UnreachableException : Exception { + public UnreachableException() { + } + } + +} + +public class PeerAttribute : SA { +} +public class RepAttribute : SA { +} +public class CapturedAttribute : SA { +} +public class NotDelayedAttribute : SA { +} +public class NoDefaultContractAttribute : SA { +} +public class VerifyAttribute : SA { + public VerifyAttribute(bool b) { + + } +} +public class StrictReadonlyAttribute : SA { +} +public class AdditiveAttribute : SA { +} +public class ReadsAttribute : SA { + public enum Reads { + Nothing, + Everything, + }; + public ReadsAttribute(object o) { + } +} +public class GlobalAccessAttribute : SA { + public GlobalAccessAttribute(bool b) { + } +} +public class EscapesAttribute : SA { + public EscapesAttribute(bool b, bool b_2) { + } +} +public class NeedsContractsAttribute : SA { + public NeedsContractsAttribute() { + } + public NeedsContractsAttribute(bool ret, bool parameters) { + } + public NeedsContractsAttribute(bool ret, int[] parameters) { + } +} +public class ImmutableAttribute : SA { +} +public class InsideAttribute : SA { +} +public class SpecPublicAttribute : SA { +} +public class ElementsPeerAttribute : SA { +} +public class ResultNotNewlyAllocatedAttribute : SA { +} +public class OnceAttribute : SA { } \ No newline at end of file diff --git a/Source/Concurrency/App.config b/Source/Concurrency/App.config index 84bc4207..e95ce985 100644 --- a/Source/Concurrency/App.config +++ b/Source/Concurrency/App.config @@ -1,6 +1,6 @@ - - - - - - + + + + + + diff --git a/Source/Concurrency/CivlRefinement.cs b/Source/Concurrency/CivlRefinement.cs new file mode 100644 index 00000000..75ff2358 --- /dev/null +++ b/Source/Concurrency/CivlRefinement.cs @@ -0,0 +1,1230 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Boogie; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using Microsoft.Boogie.GraphUtil; + +namespace Microsoft.Boogie +{ + public class MyDuplicator : Duplicator + { + CivlTypeChecker civlTypeChecker; + public int layerNum; + Procedure enclosingProc; + Implementation enclosingImpl; + public Dictionary procMap; /* Original -> Duplicate */ + public Dictionary absyMap; /* Duplicate -> Original */ + public Dictionary implMap; /* Duplicate -> Original */ + public HashSet yieldingProcs; + public List impls; + + public MyDuplicator(CivlTypeChecker civlTypeChecker, int layerNum) + { + this.civlTypeChecker = civlTypeChecker; + this.layerNum = layerNum; + this.enclosingProc = null; + this.enclosingImpl = null; + this.procMap = new Dictionary(); + this.absyMap = new Dictionary(); + this.implMap = new Dictionary(); + this.yieldingProcs = new HashSet(); + this.impls = new List(); + } + + private void ProcessCallCmd(CallCmd originalCallCmd, CallCmd callCmd, List newCmds) + { + int enclosingProcLayerNum = civlTypeChecker.procToActionInfo[enclosingImpl.Proc].createdAtLayerNum; + Procedure originalProc = originalCallCmd.Proc; + + if (civlTypeChecker.procToAtomicProcedureInfo.ContainsKey(originalProc)) + { + if (civlTypeChecker.CallExists(originalCallCmd, enclosingProcLayerNum, layerNum)) + { + newCmds.Add(callCmd); + } + } + else if (civlTypeChecker.procToActionInfo.ContainsKey(originalProc)) + { + AtomicActionInfo atomicActionInfo = civlTypeChecker.procToActionInfo[originalProc] as AtomicActionInfo; + if (atomicActionInfo != null && atomicActionInfo.gate.Count > 0 && layerNum == enclosingProcLayerNum) + { + newCmds.Add(new HavocCmd(Token.NoToken, new List(new IdentifierExpr[] { Expr.Ident(dummyLocalVar) }))); + Dictionary map = new Dictionary(); + for (int i = 0; i < originalProc.InParams.Count; i++) + { + map[originalProc.InParams[i]] = callCmd.Ins[i]; + } + Substitution subst = Substituter.SubstitutionFromHashtable(map); + foreach (AssertCmd assertCmd in atomicActionInfo.gate) + { + newCmds.Add(Substituter.Apply(subst, assertCmd)); + } + } + newCmds.Add(callCmd); + } + else + { + Debug.Assert(false); + } + } + + private void ProcessParCallCmd(ParCallCmd originalParCallCmd, ParCallCmd parCallCmd, List newCmds) + { + int maxCalleeLayerNum = 0; + foreach (CallCmd iter in originalParCallCmd.CallCmds) + { + int calleeLayerNum = civlTypeChecker.procToActionInfo[iter.Proc].createdAtLayerNum; + if (calleeLayerNum > maxCalleeLayerNum) + maxCalleeLayerNum = calleeLayerNum; + } + if (layerNum > maxCalleeLayerNum) + { + for (int i = 0; i < parCallCmd.CallCmds.Count; i++) + { + ProcessCallCmd(originalParCallCmd.CallCmds[i], parCallCmd.CallCmds[i], newCmds); + absyMap[parCallCmd.CallCmds[i]] = originalParCallCmd; + } + } + else + { + newCmds.Add(parCallCmd); + } + } + + public override List VisitCmdSeq(List cmdSeq) + { + List cmds = base.VisitCmdSeq(cmdSeq); + List newCmds = new List(); + for (int i = 0; i < cmds.Count; i++) + { + Cmd originalCmd = cmdSeq[i]; + Cmd cmd = cmds[i]; + + CallCmd originalCallCmd = originalCmd as CallCmd; + if (originalCallCmd != null) + { + ProcessCallCmd(originalCallCmd, cmd as CallCmd, newCmds); + continue; + } + + ParCallCmd originalParCallCmd = originalCmd as ParCallCmd; + if (originalParCallCmd != null) + { + ProcessParCallCmd(originalParCallCmd, cmd as ParCallCmd, newCmds); + continue; + } + + newCmds.Add(cmd); + } + return newCmds; + } + + public override YieldCmd VisitYieldCmd(YieldCmd node) + { + YieldCmd yieldCmd = base.VisitYieldCmd(node); + absyMap[yieldCmd] = node; + return yieldCmd; + } + + public override Block VisitBlock(Block node) + { + Block block = base.VisitBlock(node); + absyMap[block] = node; + return block; + } + + public override Cmd VisitCallCmd(CallCmd node) + { + CallCmd callCmd = (CallCmd) base.VisitCallCmd(node); + callCmd.Proc = VisitProcedure(callCmd.Proc); + callCmd.callee = callCmd.Proc.Name; + absyMap[callCmd] = node; + return callCmd; + } + + public override Cmd VisitParCallCmd(ParCallCmd node) + { + ParCallCmd parCallCmd = (ParCallCmd) base.VisitParCallCmd(node); + absyMap[parCallCmd] = node; + return parCallCmd; + } + + public override Procedure VisitProcedure(Procedure node) + { + if (!civlTypeChecker.procToActionInfo.ContainsKey(node)) + return node; + if (!procMap.ContainsKey(node)) + { + enclosingProc = node; + Procedure proc = (Procedure)node.Clone(); + proc.Name = string.Format("{0}_{1}", node.Name, layerNum); + proc.InParams = this.VisitVariableSeq(node.InParams); + proc.Modifies = this.VisitIdentifierExprSeq(node.Modifies); + proc.OutParams = this.VisitVariableSeq(node.OutParams); + + ActionInfo actionInfo = civlTypeChecker.procToActionInfo[node]; + if (actionInfo.createdAtLayerNum < layerNum) + { + proc.Requires = new List(); + proc.Ensures = new List(); + Implementation impl; + AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; + if (atomicActionInfo != null) + { + CodeExpr action = (CodeExpr)VisitCodeExpr(atomicActionInfo.action); + List cmds = new List(); + foreach (AssertCmd assertCmd in atomicActionInfo.gate) + { + cmds.Add(new AssumeCmd(Token.NoToken, (Expr)Visit(assertCmd.Expr))); + } + Block newInitBlock = new Block(Token.NoToken, "_init", cmds, + new GotoCmd(Token.NoToken, new List(new string[] { action.Blocks[0].Label }), + new List(new Block[] { action.Blocks[0] }))); + List newBlocks = new List(); + newBlocks.Add(newInitBlock); + newBlocks.AddRange(action.Blocks); + impl = new Implementation(Token.NoToken, proc.Name, node.TypeParameters, node.InParams, node.OutParams, action.LocVars, newBlocks); + } + else + { + Block newInitBlock = new Block(Token.NoToken, "_init", new List(), new ReturnCmd(Token.NoToken)); + List newBlocks = new List(); + newBlocks.Add(newInitBlock); + impl = new Implementation(Token.NoToken, proc.Name, node.TypeParameters, node.InParams, node.OutParams, new List(), newBlocks); + } + impl.Proc = proc; + impl.Proc.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); + impl.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); + impls.Add(impl); + } + else + { + yieldingProcs.Add(proc); + proc.Requires = this.VisitRequiresSeq(node.Requires); + proc.Ensures = this.VisitEnsuresSeq(node.Ensures); + } + procMap[node] = proc; + proc.Modifies = new List(); + civlTypeChecker.SharedVariables.Iter(x => proc.Modifies.Add(Expr.Ident(x))); + } + return procMap[node]; + } + + private Variable dummyLocalVar; + public override Implementation VisitImplementation(Implementation node) + { + enclosingImpl = node; + dummyLocalVar = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "og_dummy", Type.Bool)); + Implementation impl = base.VisitImplementation(node); + implMap[impl] = node; + impl.LocVars.Add(dummyLocalVar); + impl.Name = impl.Proc.Name; + return impl; + } + + public override Requires VisitRequires(Requires node) + { + Requires requires = base.VisitRequires(node); + if (node.Free) + return requires; + if (!civlTypeChecker.absyToLayerNums[node].Contains(layerNum)) + requires.Condition = Expr.True; + return requires; + } + + public override Ensures VisitEnsures(Ensures node) + { + Ensures ensures = base.VisitEnsures(node); + if (node.Free) + return ensures; + AtomicActionInfo atomicActionInfo = civlTypeChecker.procToActionInfo[enclosingProc] as AtomicActionInfo; + bool isAtomicSpecification = atomicActionInfo != null && atomicActionInfo.ensures == node; + if (isAtomicSpecification || !civlTypeChecker.absyToLayerNums[node].Contains(layerNum)) + { + ensures.Condition = Expr.True; + ensures.Attributes = CivlRefinement.RemoveMoverAttribute(ensures.Attributes); + } + return ensures; + } + + public override Cmd VisitAssertCmd(AssertCmd node) + { + AssertCmd assertCmd = (AssertCmd) base.VisitAssertCmd(node); + if (!civlTypeChecker.absyToLayerNums[node].Contains(layerNum)) + assertCmd.Expr = Expr.True; + return assertCmd; + } + } + + public class CivlRefinement + { + LinearTypeChecker linearTypeChecker; + CivlTypeChecker civlTypeChecker; + Dictionary absyMap; + Dictionary implMap; + HashSet yieldingProcs; + int layerNum; + List globalMods; + Dictionary asyncAndParallelCallDesugarings; + List yieldCheckerProcs; + List yieldCheckerImpls; + Procedure yieldProc; + + Variable pc; + Variable ok; + Expr alpha; + Expr beta; + HashSet frame; + + public CivlRefinement(LinearTypeChecker linearTypeChecker, CivlTypeChecker civlTypeChecker, MyDuplicator duplicator) + { + this.linearTypeChecker = linearTypeChecker; + this.civlTypeChecker = civlTypeChecker; + this.absyMap = duplicator.absyMap; + this.layerNum = duplicator.layerNum; + this.implMap = duplicator.implMap; + this.yieldingProcs = duplicator.yieldingProcs; + Program program = linearTypeChecker.program; + globalMods = new List(); + foreach (Variable g in civlTypeChecker.SharedVariables) + { + globalMods.Add(Expr.Ident(g)); + } + asyncAndParallelCallDesugarings = new Dictionary(); + yieldCheckerProcs = new List(); + yieldCheckerImpls = new List(); + yieldProc = null; + } + + private IEnumerable AvailableLinearVars(Absy absy) + { + HashSet availableVars = new HashSet(linearTypeChecker.AvailableLinearVars(absyMap[absy])); + foreach (var g in civlTypeChecker.globalVarToSharedVarInfo.Keys) + { + SharedVariableInfo info = civlTypeChecker.globalVarToSharedVarInfo[g]; + if (!(info.introLayerNum <= layerNum && layerNum <= info.hideLayerNum)) + { + availableVars.Remove(g); + } + } + foreach (var v in civlTypeChecker.localVarToLocalVariableInfo.Keys) + { + LocalVariableInfo info = civlTypeChecker.localVarToLocalVariableInfo[v]; + if (layerNum < info.layer) + { + availableVars.Remove(v); + } + } + return availableVars; + } + + private CallCmd CallToYieldProc(IToken tok, Dictionary ogOldGlobalMap, Dictionary domainNameToLocalVar) + { + List exprSeq = new List(); + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + exprSeq.Add(Expr.Ident(domainNameToLocalVar[domainName])); + } + foreach (IdentifierExpr ie in globalMods) + { + exprSeq.Add(Expr.Ident(ogOldGlobalMap[ie.Decl])); + } + if (yieldProc == null) + { + List inputs = new List(); + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + var domain = linearTypeChecker.linearDomains[domainName]; + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List(), new List { domain.elementType }, Type.Bool)), true); + inputs.Add(f); + } + foreach (IdentifierExpr ie in globalMods) + { + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", ie.Decl.Name), ie.Decl.TypedIdent.Type), true); + inputs.Add(f); + } + yieldProc = new Procedure(Token.NoToken, string.Format("og_yield_{0}", layerNum), new List(), inputs, new List(), new List(), new List(), new List()); + yieldProc.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); + } + CallCmd yieldCallCmd = new CallCmd(Token.NoToken, yieldProc.Name, exprSeq, new List()); + yieldCallCmd.Proc = yieldProc; + return yieldCallCmd; + } + + private void AddCallToYieldProc(IToken tok, List newCmds, Dictionary ogOldGlobalMap, Dictionary domainNameToLocalVar) + { + if (!CommandLineOptions.Clo.TrustNonInterference) + { + CallCmd yieldCallCmd = CallToYieldProc(tok, ogOldGlobalMap, domainNameToLocalVar); + newCmds.Add(yieldCallCmd); + } + + if (pc != null) + { + Expr aa = OldEqualityExprForGlobals(ogOldGlobalMap); + Expr bb = OldEqualityExpr(ogOldGlobalMap); + + // assert pc || g_old == g || beta(i, g_old, o, g); + Expr assertExpr = Expr.Or(Expr.Ident(pc), Expr.Or(aa, beta)); + assertExpr.Typecheck(new TypecheckingContext(null)); + AssertCmd skipOrBetaAssertCmd = new AssertCmd(tok, assertExpr); + skipOrBetaAssertCmd.ErrorData = "Transition invariant in initial state violated"; + newCmds.Add(skipOrBetaAssertCmd); + + // assert pc ==> o_old == o && g_old == g; + assertExpr = Expr.Imp(Expr.Ident(pc), bb); + assertExpr.Typecheck(new TypecheckingContext(null)); + AssertCmd skipAssertCmd = new AssertCmd(tok, assertExpr); + skipAssertCmd.ErrorData = "Transition invariant in final state violated"; ; + newCmds.Add(skipAssertCmd); + + // pc, ok := g_old == g ==> pc, ok || beta(i, g_old, o, g); + List pcUpdateLHS = new List( + new AssignLhs[] { + new SimpleAssignLhs(Token.NoToken, Expr.Ident(pc)), + new SimpleAssignLhs(Token.NoToken, Expr.Ident(ok)) + }); + List pcUpdateRHS = new List( + new Expr[] { + Expr.Imp(aa, Expr.Ident(pc)), + Expr.Or(Expr.Ident(ok), beta) + }); + foreach (Expr e in pcUpdateRHS) + { + e.Typecheck(new TypecheckingContext(null)); + } + newCmds.Add(new AssignCmd(Token.NoToken, pcUpdateLHS, pcUpdateRHS)); + } + } + + private Dictionary ComputeAvailableExprs(IEnumerable availableLinearVars, Dictionary domainNameToInputVar) + { + Dictionary domainNameToExpr = new Dictionary(); + foreach (var domainName in linearTypeChecker.linearDomains.Keys) + { + var expr = Expr.Ident(domainNameToInputVar[domainName]); + expr.Resolve(new ResolutionContext(null)); + expr.Typecheck(new TypecheckingContext(null)); + domainNameToExpr[domainName] = expr; + } + foreach (Variable v in availableLinearVars) + { + var domainName = linearTypeChecker.FindDomainName(v); + if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; + var domain = linearTypeChecker.linearDomains[domainName]; + if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; + Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List { Expr.Ident(v) }); + var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapOrBool), new List { ie, domainNameToExpr[domainName] }); + expr.Resolve(new ResolutionContext(null)); + expr.Typecheck(new TypecheckingContext(null)); + domainNameToExpr[domainName] = expr; + } + return domainNameToExpr; + } + + private void AddUpdatesToOldGlobalVars(List newCmds, Dictionary ogOldGlobalMap, Dictionary domainNameToLocalVar, Dictionary domainNameToExpr) + { + List lhss = new List(); + List rhss = new List(); + foreach (var domainName in linearTypeChecker.linearDomains.Keys) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(domainNameToLocalVar[domainName]))); + rhss.Add(domainNameToExpr[domainName]); + } + foreach (Variable g in ogOldGlobalMap.Keys) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(ogOldGlobalMap[g]))); + rhss.Add(Expr.Ident(g)); + } + if (lhss.Count > 0) + { + newCmds.Add(new AssignCmd(Token.NoToken, lhss, rhss)); + } + } + + private Expr OldEqualityExpr(Dictionary ogOldGlobalMap) + { + Expr bb = Expr.True; + foreach (Variable o in ogOldGlobalMap.Keys) + { + if (o is GlobalVariable && !frame.Contains(o)) continue; + bb = Expr.And(bb, Expr.Eq(Expr.Ident(o), Expr.Ident(ogOldGlobalMap[o]))); + bb.Type = Type.Bool; + } + return bb; + } + + private Expr OldEqualityExprForGlobals(Dictionary ogOldGlobalMap) + { + Expr bb = Expr.True; + foreach (Variable o in ogOldGlobalMap.Keys) + { + if (o is GlobalVariable && frame.Contains(o)) + { + bb = Expr.And(bb, Expr.Eq(Expr.Ident(o), Expr.Ident(ogOldGlobalMap[o]))); + bb.Type = Type.Bool; + } + } + return bb; + } + + private void DesugarYield(YieldCmd yieldCmd, List cmds, List newCmds, Dictionary ogOldGlobalMap, Dictionary domainNameToInputVar, Dictionary domainNameToLocalVar) + { + AddCallToYieldProc(yieldCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); + + if (globalMods.Count > 0) + { + newCmds.Add(new HavocCmd(Token.NoToken, globalMods)); + if (pc != null) + { + // assume pc || alpha(i, g); + Expr assumeExpr = Expr.Or(Expr.Ident(pc), alpha); + assumeExpr.Type = Type.Bool; + newCmds.Add(new AssumeCmd(Token.NoToken, assumeExpr)); + } + } + + Dictionary domainNameToExpr = ComputeAvailableExprs(AvailableLinearVars(yieldCmd), domainNameToInputVar); + AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); + + for (int j = 0; j < cmds.Count; j++) + { + PredicateCmd predCmd = (PredicateCmd)cmds[j]; + newCmds.Add(new AssumeCmd(Token.NoToken, predCmd.Expr)); + } + } + + public void DesugarParallelCallCmd(List newCmds, ParCallCmd parCallCmd) + { + List parallelCalleeNames = new List(); + List ins = new List(); + List outs = new List(); + string procName = "og"; + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + procName = procName + "_" + callCmd.Proc.Name; + ins.AddRange(callCmd.Ins); + outs.AddRange(callCmd.Outs); + } + Procedure proc; + if (asyncAndParallelCallDesugarings.ContainsKey(procName)) + { + proc = asyncAndParallelCallDesugarings[procName]; + } + else + { + List inParams = new List(); + List outParams = new List(); + List requiresSeq = new List(); + List ensuresSeq = new List(); + int count = 0; + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + Dictionary map = new Dictionary(); + foreach (Variable x in callCmd.Proc.InParams) + { + Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_{0}_{1}", count, x.Name), x.TypedIdent.Type), true); + inParams.Add(y); + map[x] = Expr.Ident(y); + } + foreach (Variable x in callCmd.Proc.OutParams) + { + Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_{0}_{1}", count, x.Name), x.TypedIdent.Type), false); + outParams.Add(y); + map[x] = Expr.Ident(y); + } + Contract.Assume(callCmd.Proc.TypeParameters.Count == 0); + Substitution subst = Substituter.SubstitutionFromHashtable(map); + foreach (Requires req in callCmd.Proc.Requires) + { + requiresSeq.Add(new Requires(req.tok, req.Free, Substituter.Apply(subst, req.Condition), null, req.Attributes)); + } + foreach (Ensures ens in callCmd.Proc.Ensures) + { + ensuresSeq.Add(new Ensures(ens.tok, ens.Free, Substituter.Apply(subst, ens.Condition), null, ens.Attributes)); + } + count++; + } + proc = new Procedure(Token.NoToken, procName, new List(), inParams, outParams, requiresSeq, globalMods, ensuresSeq); + asyncAndParallelCallDesugarings[procName] = proc; + } + CallCmd dummyCallCmd = new CallCmd(parCallCmd.tok, proc.Name, ins, outs, parCallCmd.Attributes); + dummyCallCmd.Proc = proc; + newCmds.Add(dummyCallCmd); + } + + private void CreateYieldCheckerImpl(Implementation impl, List> yields) + { + if (yields.Count == 0) return; + + Dictionary map = new Dictionary(); + foreach (Variable local in impl.LocVars) + { + var copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, local.Name, local.TypedIdent.Type)); + map[local] = Expr.Ident(copy); + } + + Program program = linearTypeChecker.program; + List locals = new List(); + List inputs = new List(); + foreach (IdentifierExpr ie in map.Values) + { + locals.Add(ie.Decl); + } + for (int i = 0; i < impl.InParams.Count - linearTypeChecker.linearDomains.Count; i++) + { + Variable inParam = impl.InParams[i]; + Variable copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, inParam.Name, inParam.TypedIdent.Type)); + locals.Add(copy); + map[impl.InParams[i]] = Expr.Ident(copy); + } + { + int i = impl.InParams.Count - linearTypeChecker.linearDomains.Count; + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + Variable inParam = impl.InParams[i]; + Variable copy = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, inParam.Name, inParam.TypedIdent.Type), true); + inputs.Add(copy); + map[impl.InParams[i]] = Expr.Ident(copy); + i++; + } + } + for (int i = 0; i < impl.OutParams.Count; i++) + { + Variable outParam = impl.OutParams[i]; + var copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, outParam.Name, outParam.TypedIdent.Type)); + locals.Add(copy); + map[impl.OutParams[i]] = Expr.Ident(copy); + } + Dictionary ogOldLocalMap = new Dictionary(); + Dictionary assumeMap = new Dictionary(map); + foreach (IdentifierExpr ie in globalMods) + { + Variable g = ie.Decl; + var copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_local_old_{0}", g.Name), g.TypedIdent.Type)); + locals.Add(copy); + ogOldLocalMap[g] = Expr.Ident(copy); + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", g.Name), g.TypedIdent.Type), true); + inputs.Add(f); + assumeMap[g] = Expr.Ident(f); + } + + Substitution assumeSubst = Substituter.SubstitutionFromHashtable(assumeMap); + Substitution oldSubst = Substituter.SubstitutionFromHashtable(ogOldLocalMap); + Substitution subst = Substituter.SubstitutionFromHashtable(map); + List yieldCheckerBlocks = new List(); + List labels = new List(); + List labelTargets = new List(); + Block yieldCheckerBlock = new Block(Token.NoToken, "exit", new List(), new ReturnCmd(Token.NoToken)); + labels.Add(yieldCheckerBlock.Label); + labelTargets.Add(yieldCheckerBlock); + yieldCheckerBlocks.Add(yieldCheckerBlock); + int yieldCount = 0; + foreach (List cs in yields) + { + List newCmds = new List(); + foreach (Cmd cmd in cs) + { + PredicateCmd predCmd = (PredicateCmd)cmd; + newCmds.Add(new AssumeCmd(Token.NoToken, Substituter.ApplyReplacingOldExprs(assumeSubst, oldSubst, predCmd.Expr))); + } + foreach (Cmd cmd in cs) + { + PredicateCmd predCmd = (PredicateCmd)cmd; + var newExpr = Substituter.ApplyReplacingOldExprs(subst, oldSubst, predCmd.Expr); + if (predCmd is AssertCmd) + { + AssertCmd assertCmd = new AssertCmd(predCmd.tok, newExpr, predCmd.Attributes); + assertCmd.ErrorData = "Non-interference check failed"; + newCmds.Add(assertCmd); + } + else + { + newCmds.Add(new AssumeCmd(Token.NoToken, newExpr)); + } + } + newCmds.Add(new AssumeCmd(Token.NoToken, Expr.False)); + yieldCheckerBlock = new Block(Token.NoToken, "L" + yieldCount++, newCmds, new ReturnCmd(Token.NoToken)); + labels.Add(yieldCheckerBlock.Label); + labelTargets.Add(yieldCheckerBlock); + yieldCheckerBlocks.Add(yieldCheckerBlock); + } + yieldCheckerBlocks.Insert(0, new Block(Token.NoToken, "enter", new List(), new GotoCmd(Token.NoToken, labels, labelTargets))); + + // Create the yield checker procedure + var yieldCheckerName = string.Format("{0}_YieldChecker_{1}", "Impl", impl.Name); + var yieldCheckerProc = new Procedure(Token.NoToken, yieldCheckerName, impl.TypeParameters, inputs, new List(), new List(), new List(), new List()); + yieldCheckerProc.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); + yieldCheckerProcs.Add(yieldCheckerProc); + + // Create the yield checker implementation + var yieldCheckerImpl = new Implementation(Token.NoToken, yieldCheckerName, impl.TypeParameters, inputs, new List(), locals, yieldCheckerBlocks); + yieldCheckerImpl.Proc = yieldCheckerProc; + yieldCheckerImpl.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); + yieldCheckerImpls.Add(yieldCheckerImpl); + } + + private bool IsYieldingHeader(Graph graph, Block header) + { + foreach (Block backEdgeNode in graph.BackEdgeNodes(header)) + { + foreach (Block x in graph.NaturalLoops(header, backEdgeNode)) + { + foreach (Cmd cmd in x.Cmds) + { + if (cmd is YieldCmd) + return true; + if (cmd is ParCallCmd) + return true; + CallCmd callCmd = cmd as CallCmd; + if (callCmd == null) continue; + if (yieldingProcs.Contains(callCmd.Proc)) + return true; + } + } + } + return false; + } + + private Graph ComputeYieldingLoopHeaders(Implementation impl, out HashSet yieldingHeaders) + { + Graph graph; + impl.PruneUnreachableBlocks(); + impl.ComputePredecessorsForBlocks(); + graph = Program.GraphFromImpl(impl); + graph.ComputeLoops(); + if (!graph.Reducible) + { + throw new Exception("Irreducible flow graphs are unsupported."); + } + yieldingHeaders = new HashSet(); + IEnumerable sortedHeaders = graph.SortHeadersByDominance(); + foreach (Block header in sortedHeaders) + { + if (yieldingHeaders.Any(x => graph.DominatorMap.DominatedBy(x, header))) + { + yieldingHeaders.Add(header); + } + else if (IsYieldingHeader(graph, header)) + { + yieldingHeaders.Add(header); + } + else + { + continue; + } + } + return graph; + } + + private void SetupRefinementCheck(Implementation impl, + out List newLocalVars, + out Dictionary domainNameToInputVar, out Dictionary domainNameToLocalVar, out Dictionary ogOldGlobalMap) + { + pc = null; + ok = null; + alpha = null; + beta = null; + frame = null; + + newLocalVars = new List(); + Program program = linearTypeChecker.program; + ogOldGlobalMap = new Dictionary(); + foreach (IdentifierExpr ie in globalMods) + { + Variable g = ie.Decl; + LocalVariable l = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", g.Name), g.TypedIdent.Type)); + ogOldGlobalMap[g] = l; + newLocalVars.Add(l); + } + + Procedure originalProc = implMap[impl].Proc; + ActionInfo actionInfo = civlTypeChecker.procToActionInfo[originalProc]; + if (actionInfo.createdAtLayerNum == this.layerNum) + { + pc = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "og_pc", Type.Bool)); + newLocalVars.Add(pc); + ok = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "og_ok", Type.Bool)); + newLocalVars.Add(ok); + Dictionary alwaysMap = new Dictionary(); + for (int i = 0; i < originalProc.InParams.Count; i++) + { + alwaysMap[originalProc.InParams[i]] = Expr.Ident(impl.InParams[i]); + } + for (int i = 0; i < originalProc.OutParams.Count; i++) + { + alwaysMap[originalProc.OutParams[i]] = Expr.Ident(impl.OutParams[i]); + } + Substitution always = Substituter.SubstitutionFromHashtable(alwaysMap); + Dictionary foroldMap = new Dictionary(); + foreach (IdentifierExpr ie in globalMods) + { + foroldMap[ie.Decl] = Expr.Ident(ogOldGlobalMap[ie.Decl]); + } + Substitution forold = Substituter.SubstitutionFromHashtable(foroldMap); + frame = new HashSet(civlTypeChecker.SharedVariables); + foreach (Variable v in civlTypeChecker.SharedVariables) + { + if (civlTypeChecker.globalVarToSharedVarInfo[v].hideLayerNum <= actionInfo.createdAtLayerNum || + civlTypeChecker.globalVarToSharedVarInfo[v].introLayerNum > actionInfo.createdAtLayerNum) + { + frame.Remove(v); + } + } + AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; + if (atomicActionInfo == null) + { + beta = Expr.True; + foreach (var v in frame) + { + beta = Expr.And(beta, Expr.Eq(Expr.Ident(v), foroldMap[v])); + } + alpha = Expr.True; + } + else + { + Expr betaExpr = (new MoverCheck.TransitionRelationComputation(civlTypeChecker.program, atomicActionInfo, frame, new HashSet())).TransitionRelationCompute(true); + beta = Substituter.ApplyReplacingOldExprs(always, forold, betaExpr); + Expr alphaExpr = Expr.True; + foreach (AssertCmd assertCmd in atomicActionInfo.gate) + { + alphaExpr = Expr.And(alphaExpr, assertCmd.Expr); + alphaExpr.Type = Type.Bool; + } + alpha = Substituter.Apply(always, alphaExpr); + } + foreach (Variable f in impl.OutParams) + { + LocalVariable copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_old_{0}", f.Name), f.TypedIdent.Type)); + newLocalVars.Add(copy); + ogOldGlobalMap[f] = copy; + } + } + + domainNameToInputVar = new Dictionary(); + domainNameToLocalVar = new Dictionary(); + { + int i = impl.InParams.Count - linearTypeChecker.linearDomains.Count; + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + Variable inParam = impl.InParams[i]; + domainNameToInputVar[domainName] = inParam; + Variable l = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, inParam.Name + "_local", inParam.TypedIdent.Type)); + domainNameToLocalVar[domainName] = l; + newLocalVars.Add(l); + i++; + } + } + } + + private void TransformImpl(Implementation impl) + { + HashSet yieldingHeaders; + Graph graph = ComputeYieldingLoopHeaders(impl, out yieldingHeaders); + + List newLocalVars; + Dictionary domainNameToInputVar, domainNameToLocalVar; + Dictionary ogOldGlobalMap; + SetupRefinementCheck(impl, out newLocalVars, out domainNameToInputVar, out domainNameToLocalVar, out ogOldGlobalMap); + + List> yields = CollectAndDesugarYields(impl, domainNameToInputVar, domainNameToLocalVar, ogOldGlobalMap); + + List oldPcs, oldOks; + ProcessLoopHeaders(impl, graph, yieldingHeaders, domainNameToInputVar, domainNameToLocalVar, ogOldGlobalMap, out oldPcs, out oldOks); + + AddInitialBlock(impl, oldPcs, oldOks, domainNameToInputVar, domainNameToLocalVar, ogOldGlobalMap); + + CreateYieldCheckerImpl(impl, yields); + + impl.LocVars.AddRange(newLocalVars); + impl.LocVars.AddRange(oldPcs); + impl.LocVars.AddRange(oldOks); + + UnifyCallsToYieldProc(impl, ogOldGlobalMap, domainNameToLocalVar); + } + + private void UnifyCallsToYieldProc(Implementation impl, Dictionary ogOldGlobalMap, Dictionary domainNameToLocalVar) + { + CallCmd yieldCallCmd = CallToYieldProc(Token.NoToken, ogOldGlobalMap, domainNameToLocalVar); + Block yieldCheckBlock = new Block(Token.NoToken, "CallToYieldProc", new List(new Cmd[] { yieldCallCmd, new AssumeCmd(Token.NoToken, Expr.False) }), new ReturnCmd(Token.NoToken)); + List newBlocks = new List(); + foreach (Block b in impl.Blocks) + { + TransferCmd transferCmd = b.TransferCmd; + List newCmds = new List(); + for (int i = b.Cmds.Count-1; i >= 0; i--) + { + CallCmd callCmd = b.Cmds[i] as CallCmd; + if (callCmd == null || callCmd.Proc != yieldProc) + { + newCmds.Insert(0, b.Cmds[i]); + } + else + { + Block newBlock = new Block(Token.NoToken, b.Label + i, newCmds, transferCmd); + newCmds = new List(); + transferCmd = new GotoCmd(Token.NoToken, new List(new string[] { newBlock.Label, yieldCheckBlock.Label }), + new List(new Block[] { newBlock, yieldCheckBlock })); + newBlocks.Add(newBlock); + } + } + b.Cmds = newCmds; + b.TransferCmd = transferCmd; + } + impl.Blocks.AddRange(newBlocks); + impl.Blocks.Add(yieldCheckBlock); + } + + private List> CollectAndDesugarYields(Implementation impl, + Dictionary domainNameToInputVar, Dictionary domainNameToLocalVar, Dictionary ogOldGlobalMap) + { + // Collect the yield predicates and desugar yields + List> yields = new List>(); + List cmds = new List(); + foreach (Block b in impl.Blocks) + { + YieldCmd yieldCmd = null; + List newCmds = new List(); + for (int i = 0; i < b.Cmds.Count; i++) + { + Cmd cmd = b.Cmds[i]; + if (cmd is YieldCmd) + { + yieldCmd = (YieldCmd)cmd; + continue; + } + if (yieldCmd != null) + { + PredicateCmd pcmd = cmd as PredicateCmd; + if (pcmd == null) + { + DesugarYield(yieldCmd, cmds, newCmds, ogOldGlobalMap, domainNameToInputVar, domainNameToLocalVar); + if (cmds.Count > 0) + { + yields.Add(cmds); + cmds = new List(); + } + yieldCmd = null; + } + else + { + cmds.Add(pcmd); + } + } + + if (cmd is CallCmd) + { + CallCmd callCmd = cmd as CallCmd; + if (yieldingProcs.Contains(callCmd.Proc)) + { + AddCallToYieldProc(callCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); + } + if (callCmd.IsAsync) + { + if (!asyncAndParallelCallDesugarings.ContainsKey(callCmd.Proc.Name)) + { + asyncAndParallelCallDesugarings[callCmd.Proc.Name] = new Procedure(Token.NoToken, string.Format("DummyAsyncTarget_{0}", callCmd.Proc.Name), callCmd.Proc.TypeParameters, callCmd.Proc.InParams, callCmd.Proc.OutParams, callCmd.Proc.Requires, new List(), new List()); + } + var dummyAsyncTargetProc = asyncAndParallelCallDesugarings[callCmd.Proc.Name]; + CallCmd dummyCallCmd = new CallCmd(callCmd.tok, dummyAsyncTargetProc.Name, callCmd.Ins, callCmd.Outs, callCmd.Attributes); + dummyCallCmd.Proc = dummyAsyncTargetProc; + newCmds.Add(dummyCallCmd); + } + else + { + newCmds.Add(callCmd); + } + if (yieldingProcs.Contains(callCmd.Proc)) + { + HashSet availableLinearVars = new HashSet(AvailableLinearVars(callCmd)); + linearTypeChecker.AddAvailableVars(callCmd, availableLinearVars); + + if (!callCmd.IsAsync && globalMods.Count > 0 && pc != null) + { + // assume pc || alpha(i, g); + Expr assumeExpr = Expr.Or(Expr.Ident(pc), alpha); + assumeExpr.Type = Type.Bool; + newCmds.Add(new AssumeCmd(Token.NoToken, assumeExpr)); + } + + Dictionary domainNameToExpr = ComputeAvailableExprs(availableLinearVars, domainNameToInputVar); + AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); + } + } + else if (cmd is ParCallCmd) + { + ParCallCmd parCallCmd = cmd as ParCallCmd; + AddCallToYieldProc(parCallCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); + DesugarParallelCallCmd(newCmds, parCallCmd); + HashSet availableLinearVars = new HashSet(AvailableLinearVars(parCallCmd)); + linearTypeChecker.AddAvailableVars(parCallCmd, availableLinearVars); + + if (globalMods.Count > 0 && pc != null) + { + // assume pc || alpha(i, g); + Expr assumeExpr = Expr.Or(Expr.Ident(pc), alpha); + assumeExpr.Type = Type.Bool; + newCmds.Add(new AssumeCmd(Token.NoToken, assumeExpr)); + } + + Dictionary domainNameToExpr = ComputeAvailableExprs(availableLinearVars, domainNameToInputVar); + AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); + } + else + { + newCmds.Add(cmd); + } + } + if (yieldCmd != null) + { + DesugarYield(yieldCmd, cmds, newCmds, ogOldGlobalMap, domainNameToInputVar, domainNameToLocalVar); + if (cmds.Count > 0) + { + yields.Add(cmds); + cmds = new List(); + } + } + if (b.TransferCmd is ReturnCmd) + { + AddCallToYieldProc(b.TransferCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); + if (pc != null) + { + AssertCmd assertCmd = new AssertCmd(b.TransferCmd.tok, Expr.Ident(ok)); + assertCmd.ErrorData = "Failed to execute atomic action before procedure return"; + newCmds.Add(assertCmd); + } + } + b.Cmds = newCmds; + } + return yields; + } + + private void ProcessLoopHeaders(Implementation impl, Graph graph, HashSet yieldingHeaders, + Dictionary domainNameToInputVar, Dictionary domainNameToLocalVar, Dictionary ogOldGlobalMap, + out List oldPcs, out List oldOks) + { + oldPcs = new List(); + oldOks = new List(); + foreach (Block header in yieldingHeaders) + { + LocalVariable oldPc = null; + LocalVariable oldOk = null; + if (pc != null) + { + oldPc = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("{0}_{1}", pc.Name, header.Label), Type.Bool)); + oldPcs.Add(oldPc); + oldOk = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("{0}_{1}", ok.Name, header.Label), Type.Bool)); + oldOks.Add(oldOk); + } + Dictionary domainNameToExpr = ComputeAvailableExprs(AvailableLinearVars(header), domainNameToInputVar); + foreach (Block pred in header.Predecessors) + { + AddCallToYieldProc(header.tok, pred.Cmds, ogOldGlobalMap, domainNameToLocalVar); + if (pc != null && !graph.BackEdgeNodes(header).Contains(pred)) + { + pred.Cmds.Add(new AssignCmd(Token.NoToken, new List( + new AssignLhs[] { new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldPc)), new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldOk)) }), + new List(new Expr[] { Expr.Ident(pc), Expr.Ident(ok) }))); + } + AddUpdatesToOldGlobalVars(pred.Cmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); + } + List newCmds = new List(); + if (pc != null) + { + AssertCmd assertCmd; + assertCmd = new AssertCmd(header.tok, Expr.Eq(Expr.Ident(oldPc), Expr.Ident(pc))); + assertCmd.ErrorData = "Specification state must not change for transitions ending in loop headers"; + newCmds.Add(assertCmd); + assertCmd = new AssertCmd(header.tok, Expr.Imp(Expr.Ident(oldOk), Expr.Ident(ok))); + assertCmd.ErrorData = "Specification state must not change for transitions ending in loop headers"; + newCmds.Add(assertCmd); + } + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + newCmds.Add(new AssumeCmd(Token.NoToken, Expr.Eq(Expr.Ident(domainNameToLocalVar[domainName]), domainNameToExpr[domainName]))); + } + foreach (Variable v in ogOldGlobalMap.Keys) + { + newCmds.Add(new AssumeCmd(Token.NoToken, Expr.Eq(Expr.Ident(v), Expr.Ident(ogOldGlobalMap[v])))); + } + newCmds.AddRange(header.Cmds); + header.Cmds = newCmds; + } + } + + private void AddInitialBlock(Implementation impl, List oldPcs, List oldOks, + Dictionary domainNameToInputVar, Dictionary domainNameToLocalVar, Dictionary ogOldGlobalMap) + { + // Add initial block + List lhss = new List(); + List rhss = new List(); + if (pc != null) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(pc))); + rhss.Add(Expr.False); + foreach (Variable oldPc in oldPcs) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldPc))); + rhss.Add(Expr.False); + } + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(ok))); + rhss.Add(Expr.False); + foreach (Variable oldOk in oldOks) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldOk))); + rhss.Add(Expr.False); + } + } + Dictionary domainNameToExpr = new Dictionary(); + foreach (var domainName in linearTypeChecker.linearDomains.Keys) + { + domainNameToExpr[domainName] = Expr.Ident(domainNameToInputVar[domainName]); + } + for (int i = 0; i < impl.InParams.Count - linearTypeChecker.linearDomains.Count; i++) + { + Variable v = impl.InParams[i]; + var domainName = linearTypeChecker.FindDomainName(v); + if (domainName == null) continue; + if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; + var domain = linearTypeChecker.linearDomains[domainName]; + if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; + Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List { Expr.Ident(v) }); + domainNameToExpr[domainName] = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapOrBool), new List { ie, domainNameToExpr[domainName] }); + } + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(domainNameToLocalVar[domainName]))); + rhss.Add(domainNameToExpr[domainName]); + } + foreach (Variable g in ogOldGlobalMap.Keys) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(ogOldGlobalMap[g]))); + rhss.Add(Expr.Ident(g)); + } + if (lhss.Count > 0) + { + Block initBlock = new Block(Token.NoToken, "og_init", new List { new AssignCmd(Token.NoToken, lhss, rhss) }, new GotoCmd(Token.NoToken, new List { impl.Blocks[0].Label }, new List { impl.Blocks[0] })); + impl.Blocks.Insert(0, initBlock); + } + } + + private void AddYieldProcAndImpl(List decls) + { + if (yieldProc == null) return; + + Program program = linearTypeChecker.program; + List inputs = new List(); + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + var domain = linearTypeChecker.linearDomains[domainName]; + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List(), new List { domain.elementType }, Type.Bool)), true); + inputs.Add(f); + } + foreach (IdentifierExpr ie in globalMods) + { + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", ie.Decl.Name), ie.Decl.TypedIdent.Type), true); + inputs.Add(f); + } + List blocks = new List(); + TransferCmd transferCmd = new ReturnCmd(Token.NoToken); + if (yieldCheckerProcs.Count > 0) + { + List blockTargets = new List(); + List labelTargets = new List(); + int labelCount = 0; + foreach (Procedure proc in yieldCheckerProcs) + { + List exprSeq = new List(); + foreach (Variable v in inputs) + { + exprSeq.Add(Expr.Ident(v)); + } + CallCmd callCmd = new CallCmd(Token.NoToken, proc.Name, exprSeq, new List()); + callCmd.Proc = proc; + string label = string.Format("L_{0}", labelCount++); + Block block = new Block(Token.NoToken, label, new List { callCmd }, new ReturnCmd(Token.NoToken)); + labelTargets.Add(label); + blockTargets.Add(block); + blocks.Add(block); + } + transferCmd = new GotoCmd(Token.NoToken, labelTargets, blockTargets); + } + blocks.Insert(0, new Block(Token.NoToken, "enter", new List(), transferCmd)); + + var yieldImpl = new Implementation(Token.NoToken, yieldProc.Name, new List(), inputs, new List(), new List(), blocks); + yieldImpl.Proc = yieldProc; + yieldImpl.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); + decls.Add(yieldProc); + decls.Add(yieldImpl); + } + + public static QKeyValue RemoveYieldsAttribute(QKeyValue iter) + { + if (iter == null) return null; + iter.Next = RemoveYieldsAttribute(iter.Next); + return (iter.Key == "yields") ? iter.Next : iter; + } + + public static QKeyValue RemoveMoverAttribute(QKeyValue iter) + { + if (iter == null) return null; + iter.Next = RemoveMoverAttribute(iter.Next); + if (iter.Key == "atomic" || iter.Key == "right" || iter.Key == "left" || iter.Key == "both") + return iter.Next; + else + return iter; + } + + private List Collect() + { + List decls = new List(); + foreach (Procedure proc in yieldCheckerProcs) + { + decls.Add(proc); + } + foreach (Implementation impl in yieldCheckerImpls) + { + decls.Add(impl); + } + foreach (Procedure proc in asyncAndParallelCallDesugarings.Values) + { + decls.Add(proc); + } + AddYieldProcAndImpl(decls); + return decls; + } + + public static void AddCheckers(LinearTypeChecker linearTypeChecker, CivlTypeChecker civlTypeChecker, List decls) + { + Program program = linearTypeChecker.program; + foreach (int layerNum in civlTypeChecker.AllLayerNums) + { + if (CommandLineOptions.Clo.TrustLayersDownto <= layerNum || layerNum <= CommandLineOptions.Clo.TrustLayersUpto) continue; + + MyDuplicator duplicator = new MyDuplicator(civlTypeChecker, layerNum); + foreach (var proc in program.Procedures) + { + if (!civlTypeChecker.procToActionInfo.ContainsKey(proc)) continue; + Procedure duplicateProc = duplicator.VisitProcedure(proc); + decls.Add(duplicateProc); + } + decls.AddRange(duplicator.impls); + CivlRefinement civlTransform = new CivlRefinement(linearTypeChecker, civlTypeChecker, duplicator); + foreach (var impl in program.Implementations) + { + if (!civlTypeChecker.procToActionInfo.ContainsKey(impl.Proc) || civlTypeChecker.procToActionInfo[impl.Proc].createdAtLayerNum < layerNum) + continue; + Implementation duplicateImpl = duplicator.VisitImplementation(impl); + civlTransform.TransformImpl(duplicateImpl); + decls.Add(duplicateImpl); + } + decls.AddRange(civlTransform.Collect()); + } + } + } +} diff --git a/Source/Concurrency/CivlTypeChecker.cs b/Source/Concurrency/CivlTypeChecker.cs new file mode 100644 index 00000000..b426d9ed --- /dev/null +++ b/Source/Concurrency/CivlTypeChecker.cs @@ -0,0 +1,1160 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Boogie; +using System.Diagnostics.Contracts; +using System.Diagnostics; + +namespace Microsoft.Boogie +{ + public enum MoverType + { + Top, + Atomic, + Right, + Left, + Both + } + + public class ActionInfo + { + public Procedure proc; + public int createdAtLayerNum; + public int availableUptoLayerNum; + public bool hasImplementation; + public bool isExtern; + + public ActionInfo(Procedure proc, int createdAtLayerNum, int availableUptoLayerNum) + { + this.proc = proc; + this.createdAtLayerNum = createdAtLayerNum; + this.availableUptoLayerNum = availableUptoLayerNum; + this.hasImplementation = false; + this.isExtern = QKeyValue.FindBoolAttribute(proc.Attributes, "extern"); + } + + public virtual bool IsRightMover + { + get { return true; } + } + + public virtual bool IsLeftMover + { + get { return true; } + } + } + + public class AtomicActionInfo : ActionInfo + { + public Ensures ensures; + public MoverType moverType; + public List gate; + public CodeExpr action; + public List thisGate; + public CodeExpr thisAction; + public List thisInParams; + public List thisOutParams; + public List thatGate; + public CodeExpr thatAction; + public List thatInParams; + public List thatOutParams; + public HashSet actionUsedGlobalVars; + public HashSet modifiedGlobalVars; + public HashSet gateUsedGlobalVars; + public bool hasAssumeCmd; + public Dictionary thisMap; + public Dictionary thatMap; + + public bool CommutesWith(AtomicActionInfo actionInfo) + { + if (this.modifiedGlobalVars.Intersect(actionInfo.actionUsedGlobalVars).Count() > 0) + return false; + if (this.actionUsedGlobalVars.Intersect(actionInfo.modifiedGlobalVars).Count() > 0) + return false; + return true; + } + + public override bool IsRightMover + { + get { return moverType == MoverType.Right || moverType == MoverType.Both; } + } + + public override bool IsLeftMover + { + get { return moverType == MoverType.Left || moverType == MoverType.Both; } + } + + public AtomicActionInfo(Procedure proc, Ensures ensures, MoverType moverType, int layerNum, int availableUptoLayerNum) + : base(proc, layerNum, availableUptoLayerNum) + { + this.ensures = ensures; + this.moverType = moverType; + this.gate = new List(); + this.action = ensures.Condition as CodeExpr; + this.thisGate = new List(); + this.thisInParams = new List(); + this.thisOutParams = new List(); + this.thatGate = new List(); + this.thatInParams = new List(); + this.thatOutParams = new List(); + this.hasAssumeCmd = false; + this.thisMap = new Dictionary(); + this.thatMap = new Dictionary(); + + foreach (Block block in this.action.Blocks) + { + block.Cmds.ForEach(x => this.hasAssumeCmd = this.hasAssumeCmd || x is AssumeCmd); + } + + foreach (Block block in this.action.Blocks) + { + if (block.TransferCmd is ReturnExprCmd) + { + block.TransferCmd = new ReturnCmd(block.TransferCmd.tok); + } + } + + var cmds = this.action.Blocks[0].Cmds; + for (int i = 0; i < cmds.Count; i++) + { + AssertCmd assertCmd = cmds[i] as AssertCmd; + if (assertCmd == null) break; + this.gate.Add(assertCmd); + cmds[i] = new AssumeCmd(assertCmd.tok, Expr.True); + } + + foreach (Variable x in proc.InParams) + { + Variable thisx = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "this_" + x.Name, x.TypedIdent.Type), true, x.Attributes); + this.thisInParams.Add(thisx); + this.thisMap[x] = Expr.Ident(thisx); + Variable thatx = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), true, x.Attributes); + this.thatInParams.Add(thatx); + this.thatMap[x] = Expr.Ident(thatx); + } + foreach (Variable x in proc.OutParams) + { + Variable thisx = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "this_" + x.Name, x.TypedIdent.Type), false, x.Attributes); + this.thisOutParams.Add(thisx); + this.thisMap[x] = Expr.Ident(thisx); + Variable thatx = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), false, x.Attributes); + this.thatOutParams.Add(thatx); + this.thatMap[x] = Expr.Ident(thatx); + } + List thisLocVars = new List(); + List thatLocVars = new List(); + foreach (Variable x in this.action.LocVars) + { + Variable thisx = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "this_" + x.Name, x.TypedIdent.Type), false); + thisMap[x] = Expr.Ident(thisx); + thisLocVars.Add(thisx); + Variable thatx = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), false); + thatMap[x] = Expr.Ident(thatx); + thatLocVars.Add(thatx); + } + Contract.Assume(proc.TypeParameters.Count == 0); + Substitution thisSubst = Substituter.SubstitutionFromHashtable(this.thisMap); + Substitution thatSubst = Substituter.SubstitutionFromHashtable(this.thatMap); + foreach (AssertCmd assertCmd in this.gate) + { + this.thisGate.Add((AssertCmd)Substituter.Apply(thisSubst, assertCmd)); + this.thatGate.Add((AssertCmd)Substituter.Apply(thatSubst, assertCmd)); + } + this.thisAction = new CodeExpr(thisLocVars, SubstituteBlocks(this.action.Blocks, thisSubst, "this_")); + this.thatAction = new CodeExpr(thatLocVars, SubstituteBlocks(this.action.Blocks, thatSubst, "that_")); + + { + VariableCollector collector = new VariableCollector(); + collector.Visit(this.action); + this.actionUsedGlobalVars = new HashSet(collector.usedVars.Where(x => x is GlobalVariable)); + } + + List modifiedVars = new List(); + foreach (Block block in this.action.Blocks) + { + block.Cmds.ForEach(cmd => cmd.AddAssignedVariables(modifiedVars)); + } + this.modifiedGlobalVars = new HashSet(modifiedVars.Where(x => x is GlobalVariable)); + + { + VariableCollector collector = new VariableCollector(); + this.gate.ForEach(assertCmd => collector.Visit(assertCmd)); + this.gateUsedGlobalVars = new HashSet(collector.usedVars.Where(x => x is GlobalVariable)); + } + } + + private List SubstituteBlocks(List blocks, Substitution subst, string blockLabelPrefix) + { + Dictionary blockMap = new Dictionary(); + List otherBlocks = new List(); + foreach (Block block in blocks) + { + List otherCmds = new List(); + foreach (Cmd cmd in block.Cmds) + { + otherCmds.Add(Substituter.Apply(subst, cmd)); + } + Block otherBlock = new Block(); + otherBlock.Cmds = otherCmds; + otherBlock.Label = blockLabelPrefix + block.Label; + otherBlocks.Add(otherBlock); + blockMap[block] = otherBlock; + } + foreach (Block block in blocks) + { + if (block.TransferCmd is ReturnCmd) + { + blockMap[block].TransferCmd = new ReturnCmd(block.TransferCmd.tok); + continue; + } + List otherGotoCmdLabelTargets = new List(); + List otherGotoCmdLabelNames = new List(); + GotoCmd gotoCmd = block.TransferCmd as GotoCmd; + foreach (Block target in gotoCmd.labelTargets) + { + otherGotoCmdLabelTargets.Add(blockMap[target]); + otherGotoCmdLabelNames.Add(blockMap[target].Label); + } + blockMap[block].TransferCmd = new GotoCmd(block.TransferCmd.tok, otherGotoCmdLabelNames, otherGotoCmdLabelTargets); + } + return otherBlocks; + } + } + + public class SharedVariableInfo + { + public int introLayerNum; + public int hideLayerNum; + + public SharedVariableInfo(int introLayerNum, int hideLayerNum) + { + this.introLayerNum = introLayerNum; + this.hideLayerNum = hideLayerNum; + } + } + + public class LayerEraser : ReadOnlyVisitor + { + private QKeyValue RemoveLayerAttribute(QKeyValue iter) + { + if (iter == null) return null; + iter.Next = RemoveLayerAttribute(iter.Next); + return (iter.Key == "layer") ? iter.Next : iter; + } + + public override Variable VisitVariable(Variable node) + { + node.Attributes = RemoveLayerAttribute(node.Attributes); + return base.VisitVariable(node); + } + + public override Procedure VisitProcedure(Procedure node) + { + node.Attributes = RemoveLayerAttribute(node.Attributes); + return base.VisitProcedure(node); + } + + public override Implementation VisitImplementation(Implementation node) + { + node.Attributes = RemoveLayerAttribute(node.Attributes); + return base.VisitImplementation(node); + } + + public override Requires VisitRequires(Requires node) + { + node.Attributes = RemoveLayerAttribute(node.Attributes); + return base.VisitRequires(node); + } + + public override Ensures VisitEnsures(Ensures node) + { + node.Attributes = RemoveLayerAttribute(node.Attributes); + return base.VisitEnsures(node); + } + + public override Cmd VisitAssertCmd(AssertCmd node) + { + node.Attributes = RemoveLayerAttribute(node.Attributes); + return base.VisitAssertCmd(node); + } + } + + public class LayerRange + { + public int lowerLayerNum; + public int upperLayerNum; + public LayerRange(int layer) + { + this.lowerLayerNum = layer; + this.upperLayerNum = layer; + } + public LayerRange(int lower, int upper) + { + this.lowerLayerNum = lower; + this.upperLayerNum = upper; + } + public LayerRange(IEnumerable layerNums) + { + int min = int.MaxValue; + int max = int.MinValue; + foreach (var layerNum in layerNums) + { + if (layerNum < min) + { + min = layerNum; + } + if (max < layerNum) + { + max = layerNum; + } + } + this.lowerLayerNum = min; + this.upperLayerNum = max; + } + public bool Contains(int layerNum) + { + return lowerLayerNum <= layerNum && layerNum <= upperLayerNum; + } + public bool Subset(int lower, int upper) + { + return lower <= lowerLayerNum && upperLayerNum <= upper; + } + public bool Equal(int lower, int upper) + { + return lower == lowerLayerNum && upperLayerNum == upper; + } + public bool Subset(LayerRange info) + { + return info.lowerLayerNum <= lowerLayerNum && upperLayerNum <= info.upperLayerNum; + } + } + + public class AtomicProcedureInfo + { + public bool isPure; + public LayerRange layerRange; + public AtomicProcedureInfo() + { + this.isPure = true; + this.layerRange = null; + } + public AtomicProcedureInfo(LayerRange layerRange) + { + this.isPure = false; + this.layerRange = layerRange; + } + } + + public class LocalVariableInfo + { + public int layer; + public LocalVariableInfo(int layer) + { + this.layer = layer; + } + } + + public class CivlTypeChecker : ReadOnlyVisitor + { + CheckingContext checkingContext; + Procedure enclosingProc; + Implementation enclosingImpl; + HashSet sharedVarsAccessed; + int introducedLocalVarsUpperBound; + + public Program program; + public int errorCount; + public Dictionary globalVarToSharedVarInfo; + public Dictionary procToActionInfo; + public Dictionary procToAtomicProcedureInfo; + public Dictionary> absyToLayerNums; + public Dictionary localVarToLocalVariableInfo; + Dictionary pureCallLayer; + + public bool CallExists(CallCmd callCmd, int enclosingProcLayerNum, int layerNum) + { + Debug.Assert(procToAtomicProcedureInfo.ContainsKey(callCmd.Proc)); + var atomicProcedureInfo = procToAtomicProcedureInfo[callCmd.Proc]; + if (atomicProcedureInfo.isPure) + { + return pureCallLayer[callCmd] <= layerNum; + } + else + { + return enclosingProcLayerNum == layerNum; + } + } + + private static List FindLayers(QKeyValue kv) + { + List layers = new List(); + for (; kv != null; kv = kv.Next) + { + if (kv.Key != "layer") continue; + foreach (var o in kv.Params) + { + Expr e = o as Expr; + if (e == null) return null; + LiteralExpr l = e as LiteralExpr; + if (l == null) return null; + if (!l.isBigNum) return null; + layers.Add(l.asBigNum.ToIntSafe); + } + } + return layers; + } + + private static int Least(IEnumerable layerNums) + { + int least = int.MaxValue; + foreach (var layer in layerNums) + { + if (layer < least) + { + least = layer; + } + } + return least; + } + + private static MoverType GetMoverType(Ensures e) + { + if (QKeyValue.FindBoolAttribute(e.Attributes, "atomic")) + return MoverType.Atomic; + if (QKeyValue.FindBoolAttribute(e.Attributes, "right")) + return MoverType.Right; + if (QKeyValue.FindBoolAttribute(e.Attributes, "left")) + return MoverType.Left; + if (QKeyValue.FindBoolAttribute(e.Attributes, "both")) + return MoverType.Both; + return MoverType.Top; + } + + public CivlTypeChecker(Program program) + { + this.errorCount = 0; + this.checkingContext = new CheckingContext(null); + this.program = program; + this.enclosingProc = null; + this.enclosingImpl = null; + this.sharedVarsAccessed = null; + this.introducedLocalVarsUpperBound = int.MinValue; + + this.localVarToLocalVariableInfo = new Dictionary(); + this.absyToLayerNums = new Dictionary>(); + this.globalVarToSharedVarInfo = new Dictionary(); + this.procToActionInfo = new Dictionary(); + this.procToAtomicProcedureInfo = new Dictionary(); + this.pureCallLayer = new Dictionary(); + + foreach (var g in program.GlobalVariables) + { + List layerNums = FindLayers(g.Attributes); + if (layerNums.Count == 0) + { + // Inaccessible from yielding and atomic procedures + } + else if (layerNums.Count == 1) + { + this.globalVarToSharedVarInfo[g] = new SharedVariableInfo(layerNums[0], int.MaxValue); + } + else if (layerNums.Count == 2) + { + this.globalVarToSharedVarInfo[g] = new SharedVariableInfo(layerNums[0], layerNums[1]); + } + else + { + Error(g, "Too many layer numbers"); + } + } + } + + private HashSet allLayerNums; + public IEnumerable AllLayerNums + { + get + { + if (allLayerNums == null) + { + allLayerNums = new HashSet(); + foreach (ActionInfo actionInfo in procToActionInfo.Values) + { + allLayerNums.Add(actionInfo.createdAtLayerNum); + } + foreach (var layerNums in absyToLayerNums.Values) + { + foreach (var layer in layerNums) + { + allLayerNums.Add(layer); + } + } + } + return allLayerNums; + } + } + + private LayerRange FindLayerRange() + { + int maxIntroLayerNum = int.MinValue; + int minHideLayerNum = int.MaxValue; + foreach (var g in sharedVarsAccessed) + { + if (globalVarToSharedVarInfo[g].introLayerNum > maxIntroLayerNum) + { + maxIntroLayerNum = globalVarToSharedVarInfo[g].introLayerNum; + } + if (globalVarToSharedVarInfo[g].hideLayerNum < minHideLayerNum) + { + minHideLayerNum = globalVarToSharedVarInfo[g].hideLayerNum; + } + } + return new LayerRange(maxIntroLayerNum, minHideLayerNum); + } + + public void TypeCheck() + { + foreach (var proc in program.Procedures) + { + if (!QKeyValue.FindBoolAttribute(proc.Attributes, "pure")) continue; + if (QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) + { + Error(proc, "Pure procedure must not yield"); + continue; + } + if (QKeyValue.FindBoolAttribute(proc.Attributes, "layer")) + { + Error(proc, "Pure procedure must not have layers"); + continue; + } + if (proc.Modifies.Count > 0) + { + Error(proc, "Pure procedure must not modify a global variable"); + continue; + } + procToAtomicProcedureInfo[proc] = new AtomicProcedureInfo(); + } + foreach (var proc in program.Procedures) + { + if (QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) continue; + var procLayerNums = FindLayers(proc.Attributes); + if (procLayerNums.Count == 0) continue; + foreach (IdentifierExpr ie in proc.Modifies) + { + if (!globalVarToSharedVarInfo.ContainsKey(ie.Decl)) + { + Error(proc, "Atomic procedure cannot modify a global variable without layer numbers"); + continue; + } + } + int lower, upper; + if (procLayerNums.Count == 1) + { + lower = procLayerNums[0]; + upper = procLayerNums[0]; + } + else if (procLayerNums.Count == 2) + { + lower = procLayerNums[0]; + upper = procLayerNums[1]; + if (lower >= upper) + { + Error(proc, "Lower layer must be less than upper layer"); + continue; + } + } + else + { + Error(proc, "Atomic procedure must specify a layer range"); + continue; + } + LayerRange layerRange = new LayerRange(lower, upper); + procToAtomicProcedureInfo[proc] = new AtomicProcedureInfo(layerRange); + } + if (errorCount > 0) return; + + foreach (Implementation impl in program.Implementations) + { + if (!procToAtomicProcedureInfo.ContainsKey(impl.Proc)) continue; + var atomicProcedureInfo = procToAtomicProcedureInfo[impl.Proc]; + if (atomicProcedureInfo.isPure) + { + this.enclosingImpl = impl; + (new PurityChecker(this)).VisitImplementation(impl); + } + else + { + this.enclosingImpl = impl; + this.sharedVarsAccessed = new HashSet(); + (new PurityChecker(this)).VisitImplementation(impl); + LayerRange upperBound = FindLayerRange(); + LayerRange lowerBound = atomicProcedureInfo.layerRange; + if (!lowerBound.Subset(upperBound)) + { + Error(impl, "Atomic procedure cannot access global variable"); + } + this.sharedVarsAccessed = null; + } + } + if (errorCount > 0) return; + + foreach (var proc in program.Procedures) + { + if (!QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) continue; + + int createdAtLayerNum; // must be initialized by the following code, otherwise it is an error + int availableUptoLayerNum = int.MaxValue; + List attrs = FindLayers(proc.Attributes); + if (attrs.Count == 1) + { + createdAtLayerNum = attrs[0]; + } + else if (attrs.Count == 2) + { + createdAtLayerNum = attrs[0]; + availableUptoLayerNum = attrs[1]; + } + else + { + Error(proc, "Incorrect number of layers"); + continue; + } + foreach (Ensures e in proc.Ensures) + { + MoverType moverType = GetMoverType(e); + if (moverType == MoverType.Top) continue; + CodeExpr codeExpr = e.Condition as CodeExpr; + if (codeExpr == null) + { + Error(e, "An atomic action must be a CodeExpr"); + continue; + } + if (procToActionInfo.ContainsKey(proc)) + { + Error(proc, "A procedure can have at most one atomic action"); + continue; + } + if (availableUptoLayerNum <= createdAtLayerNum) + { + Error(proc, "Creation layer number must be less than the available upto layer number"); + continue; + } + + sharedVarsAccessed = new HashSet(); + enclosingProc = proc; + enclosingImpl = null; + base.VisitEnsures(e); + LayerRange upperBound = FindLayerRange(); + LayerRange lowerBound = new LayerRange(createdAtLayerNum, availableUptoLayerNum); + if (lowerBound.Subset(upperBound)) + { + procToActionInfo[proc] = new AtomicActionInfo(proc, e, moverType, createdAtLayerNum, availableUptoLayerNum); + } + else + { + Error(e, "A variable being accessed in this action is unavailable"); + } + sharedVarsAccessed = null; + } + if (errorCount > 0) continue; + if (!procToActionInfo.ContainsKey(proc)) + { + if (availableUptoLayerNum < createdAtLayerNum) + { + Error(proc, "Creation layer number must be no more than the available upto layer number"); + continue; + } + else + { + procToActionInfo[proc] = new ActionInfo(proc, createdAtLayerNum, availableUptoLayerNum); + } + } + } + if (errorCount > 0) return; + + foreach (var impl in program.Implementations) + { + if (!procToActionInfo.ContainsKey(impl.Proc)) continue; + ActionInfo actionInfo = procToActionInfo[impl.Proc]; + procToActionInfo[impl.Proc].hasImplementation = true; + if (actionInfo.isExtern) + { + Error(impl.Proc, "Extern procedure cannot have an implementation"); + } + } + if (errorCount > 0) return; + + foreach (Procedure proc in procToActionInfo.Keys) + { + for (int i = 0; i < proc.InParams.Count; i++) + { + Variable v = proc.InParams[i]; + var layer = FindLocalVariableLayer(proc, v, procToActionInfo[proc].createdAtLayerNum); + if (layer == int.MinValue) continue; + localVarToLocalVariableInfo[v] = new LocalVariableInfo(layer); + } + for (int i = 0; i < proc.OutParams.Count; i++) + { + Variable v = proc.OutParams[i]; + var layer = FindLocalVariableLayer(proc, v, procToActionInfo[proc].createdAtLayerNum); + if (layer == int.MinValue) continue; + localVarToLocalVariableInfo[v] = new LocalVariableInfo(layer); + } + } + foreach (Implementation node in program.Implementations) + { + if (!procToActionInfo.ContainsKey(node.Proc)) continue; + foreach (Variable v in node.LocVars) + { + var layer = FindLocalVariableLayer(node, v, procToActionInfo[node.Proc].createdAtLayerNum); + if (layer == int.MinValue) continue; + localVarToLocalVariableInfo[v] = new LocalVariableInfo(layer); + } + for (int i = 0; i < node.Proc.InParams.Count; i++) + { + Variable v = node.Proc.InParams[i]; + if (!localVarToLocalVariableInfo.ContainsKey(v)) continue; + var layer = localVarToLocalVariableInfo[v].layer; + localVarToLocalVariableInfo[node.InParams[i]] = new LocalVariableInfo(layer); + } + for (int i = 0; i < node.Proc.OutParams.Count; i++) + { + Variable v = node.Proc.OutParams[i]; + if (!localVarToLocalVariableInfo.ContainsKey(v)) continue; + var layer = localVarToLocalVariableInfo[v].layer; + localVarToLocalVariableInfo[node.OutParams[i]] = new LocalVariableInfo(layer); + } + } + if (errorCount > 0) return; + + this.VisitProgram(program); + if (errorCount > 0) return; + YieldTypeChecker.PerformYieldSafeCheck(this); + new LayerEraser().VisitProgram(program); + } + + public IEnumerable SharedVariables + { + get { return this.globalVarToSharedVarInfo.Keys; } + } + + private int FindLocalVariableLayer(Declaration decl, Variable v, int enclosingProcLayerNum) + { + var layers = FindLayers(v.Attributes); + if (layers.Count == 0) return int.MinValue; + if (layers.Count > 1) + { + Error(decl, "Incorrect number of layers"); + return int.MinValue; + } + if (layers[0] > enclosingProcLayerNum) + { + Error(decl, "Layer of local variable cannot be greater than the creation layer of enclosing procedure"); + return int.MinValue; + } + return layers[0]; + } + + public override Implementation VisitImplementation(Implementation node) + { + if (!procToActionInfo.ContainsKey(node.Proc)) + { + return node; + } + this.enclosingImpl = node; + this.enclosingProc = null; + return base.VisitImplementation(node); + } + + public override Procedure VisitProcedure(Procedure node) + { + if (!procToActionInfo.ContainsKey(node)) + { + return node; + } + this.enclosingProc = node; + this.enclosingImpl = null; + return base.VisitProcedure(node); + } + + public override Cmd VisitCallCmd(CallCmd node) + { + int enclosingProcLayerNum = procToActionInfo[enclosingImpl.Proc].createdAtLayerNum; + if (procToActionInfo.ContainsKey(node.Proc)) + { + ActionInfo actionInfo = procToActionInfo[node.Proc]; + if (node.IsAsync && actionInfo is AtomicActionInfo) + { + Error(node, "Target of async call cannot be an atomic action"); + } + int calleeLayerNum = procToActionInfo[node.Proc].createdAtLayerNum; + if (enclosingProcLayerNum < calleeLayerNum || + (enclosingProcLayerNum == calleeLayerNum && actionInfo is AtomicActionInfo)) + { + Error(node, "The layer of the caller must be greater than the layer of the callee"); + } + else if (enclosingProcLayerNum == calleeLayerNum && enclosingImpl.OutParams.Count > 0) + { + HashSet outParams = new HashSet(enclosingImpl.OutParams); + foreach (var x in node.Outs) + { + if (x.Decl is GlobalVariable) + { + Error(node, "A global variable cannot be used as output argument for this call"); + } + else if (outParams.Contains(x.Decl)) + { + Error(node, "An output variable of the enclosing implementation cannot be used as output argument for this call"); + } + } + } + if (actionInfo.availableUptoLayerNum < enclosingProcLayerNum) + { + Error(node, "The callee is not available in the caller procedure"); + } + for (int i = 0; i < node.Ins.Count; i++) + { + Visit(node.Ins[i]); + if (introducedLocalVarsUpperBound != int.MinValue) + { + var formal = node.Proc.InParams[i]; + if (!localVarToLocalVariableInfo.ContainsKey(formal) || + introducedLocalVarsUpperBound > localVarToLocalVariableInfo[formal].layer) + { + Error(node, "An introduced local variable is accessed but not available"); + } + introducedLocalVarsUpperBound = int.MinValue; + } + } + for (int i = 0; i < node.Outs.Count; i++) + { + var formal = node.Proc.OutParams[i]; + if (!localVarToLocalVariableInfo.ContainsKey(formal)) continue; + var actual = node.Outs[i].Decl; + if (localVarToLocalVariableInfo.ContainsKey(actual) && + localVarToLocalVariableInfo[formal].layer <= localVarToLocalVariableInfo[actual].layer) + continue; + Error(node, "Formal parameter of call must be introduced no later than the actual parameter"); + } + return node; + } + else if (procToAtomicProcedureInfo.ContainsKey(node.Proc)) + { + var atomicProcedureInfo = procToAtomicProcedureInfo[node.Proc]; + if (atomicProcedureInfo.isPure) + { + if (node.Outs.Count > 0) + { + int inferredLayer = int.MinValue; + foreach (var ie in node.Outs) + { + if (!localVarToLocalVariableInfo.ContainsKey(ie.Decl)) continue; + if (inferredLayer < localVarToLocalVariableInfo[ie.Decl].layer) + { + inferredLayer = localVarToLocalVariableInfo[ie.Decl].layer; + } + } + pureCallLayer[node] = inferredLayer; + if (inferredLayer != int.MinValue) + { + foreach (var ie in node.Outs) + { + if (!localVarToLocalVariableInfo.ContainsKey(ie.Decl)) + { + Error(node, "Output variable must be introduced"); + } + else if (inferredLayer != localVarToLocalVariableInfo[ie.Decl].layer) + { + Error(node, "All output variables must be introduced at the same layer"); + } + } + } + Debug.Assert(introducedLocalVarsUpperBound == int.MinValue); + foreach (var e in node.Ins) + { + Visit(e); + if (inferredLayer < introducedLocalVarsUpperBound) + { + Error(node, "An introduced local variable is not accessible"); + } + introducedLocalVarsUpperBound = int.MinValue; + } + } + else + { + Debug.Assert(introducedLocalVarsUpperBound == int.MinValue); + int inferredLayer = int.MinValue; + foreach (var e in node.Ins) + { + Visit(e); + if (inferredLayer < introducedLocalVarsUpperBound) + { + inferredLayer = introducedLocalVarsUpperBound; + } + introducedLocalVarsUpperBound = int.MinValue; + } + pureCallLayer[node] = inferredLayer; + } + } + else + { + if (enclosingProcLayerNum != atomicProcedureInfo.layerRange.upperLayerNum) + { + Error(node, "Creation layer of caller must be the upper bound of the layer range of callee"); + } + foreach (var ie in node.Proc.Modifies) + { + if (enclosingProcLayerNum != globalVarToSharedVarInfo[ie.Decl].introLayerNum) + { + Error(node, "Creation layer of caller must be identical to the introduction layer of modified variable"); + } + } + foreach (var ie in node.Outs) + { + if (localVarToLocalVariableInfo.ContainsKey(ie.Decl) && + enclosingProcLayerNum == localVarToLocalVariableInfo[ie.Decl].layer) + continue; + Error(node, "Output variable must be introduced at the creation layer of caller"); + } + } + return node; + } + else + { + Error(node, "A yielding procedure can call only atomic or yielding procedures"); + return node; + } + } + + public override Cmd VisitParCallCmd(ParCallCmd node) + { + int enclosingProcLayerNum = procToActionInfo[enclosingImpl.Proc].createdAtLayerNum; + bool isLeftMover = true; + bool isRightMover = true; + int maxCalleeLayerNum = 0; + int atomicActionCalleeLayerNum = 0; + int numAtomicActions = 0; + foreach (CallCmd iter in node.CallCmds) + { + ActionInfo actionInfo = procToActionInfo[iter.Proc]; + isLeftMover = isLeftMover && actionInfo.IsLeftMover; + isRightMover = isRightMover && actionInfo.IsRightMover; + if (actionInfo.createdAtLayerNum > maxCalleeLayerNum) + { + maxCalleeLayerNum = actionInfo.createdAtLayerNum; + } + if (actionInfo is AtomicActionInfo) + { + numAtomicActions++; + if (atomicActionCalleeLayerNum == 0) + { + atomicActionCalleeLayerNum = actionInfo.createdAtLayerNum; + } + else if (atomicActionCalleeLayerNum != actionInfo.createdAtLayerNum) + { + Error(node, "All atomic actions must be introduced at the same layer"); + } + } + } + if (numAtomicActions > 1 && !isLeftMover && !isRightMover) + { + Error(node, "The atomic actions in the parallel call must be all right movers or all left movers"); + } + if (0 < atomicActionCalleeLayerNum && atomicActionCalleeLayerNum < maxCalleeLayerNum) + { + Error(node, "Atomic actions must be introduced at the highest layer"); + } + return base.VisitParCallCmd(node); + } + + public override Expr VisitIdentifierExpr(IdentifierExpr node) + { + if (node.Decl is GlobalVariable) + { + if (sharedVarsAccessed == null) + { + Error(node, "Shared variable can be accessed only in atomic actions or specifications"); + } + else if (this.globalVarToSharedVarInfo.ContainsKey(node.Decl)) + { + sharedVarsAccessed.Add(node.Decl); + } + else + { + Error(node, "Accessed shared variable must have layer annotation"); + } + } + else if ((node.Decl is Formal || node.Decl is Variable) && localVarToLocalVariableInfo.ContainsKey(node.Decl)) + { + var localVariableInfo = localVarToLocalVariableInfo[node.Decl]; + if (introducedLocalVarsUpperBound < localVariableInfo.layer) + { + introducedLocalVarsUpperBound = localVariableInfo.layer; + } + } + return base.VisitIdentifierExpr(node); + } + + public override Ensures VisitEnsures(Ensures ensures) + { + ActionInfo actionInfo = procToActionInfo[enclosingProc]; + AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; + if (atomicActionInfo != null && atomicActionInfo.ensures == ensures) + { + // This case has already been checked + } + else + { + sharedVarsAccessed = new HashSet(); + Debug.Assert(introducedLocalVarsUpperBound == int.MinValue); + base.VisitEnsures(ensures); + CheckAndAddLayers(ensures, ensures.Attributes, actionInfo.createdAtLayerNum); + if (introducedLocalVarsUpperBound > Least(FindLayers(ensures.Attributes))) + { + Error(ensures, "An introduced local variable is accessed but not available"); + } + introducedLocalVarsUpperBound = int.MinValue; + sharedVarsAccessed = null; + } + return ensures; + } + + public override Requires VisitRequires(Requires requires) + { + sharedVarsAccessed = new HashSet(); + Debug.Assert(introducedLocalVarsUpperBound == int.MinValue); + base.VisitRequires(requires); + CheckAndAddLayers(requires, requires.Attributes, procToActionInfo[enclosingProc].createdAtLayerNum); + if (introducedLocalVarsUpperBound > Least(FindLayers(requires.Attributes))) + { + Error(requires, "An introduced local variable is accessed but not available"); + } + introducedLocalVarsUpperBound = int.MinValue; + sharedVarsAccessed = null; + return requires; + } + + public override Cmd VisitAssertCmd(AssertCmd node) + { + if (enclosingImpl == null) + { + // in this case, we are visiting an assert inside a CodeExpr + return base.VisitAssertCmd(node); + } + sharedVarsAccessed = new HashSet(); + Debug.Assert(introducedLocalVarsUpperBound == int.MinValue); + base.VisitAssertCmd(node); + CheckAndAddLayers(node, node.Attributes, procToActionInfo[enclosingImpl.Proc].createdAtLayerNum); + if (introducedLocalVarsUpperBound > Least(FindLayers(node.Attributes))) + { + Error(node, "An introduced local variable is accessed but not available"); + } + introducedLocalVarsUpperBound = int.MinValue; + sharedVarsAccessed = null; + return node; + } + + private List RemoveDuplicatesAndSort(List attrs) + { + HashSet layerSet = new HashSet(attrs); + List layers = new List(layerSet); + layers.Sort(); + return layers; + } + + private void CheckAndAddLayers(Absy node, QKeyValue attributes, int enclosingProcLayerNum) + { + List attrs = RemoveDuplicatesAndSort(FindLayers(attributes)); + if (attrs.Count == 0) + { + Error(node, "layer not present"); + return; + } + LayerRange upperBound = FindLayerRange(); + absyToLayerNums[node] = new HashSet(); + foreach (int layerNum in attrs) + { + if (layerNum > enclosingProcLayerNum) + { + Error(node, "The layer cannot be greater than the layer of enclosing procedure"); + } + else if (upperBound.Contains(layerNum)) + { + absyToLayerNums[node].Add(layerNum); + } + else + { + Error(node, string.Format("A variable being accessed in this specification is unavailable at layer {0}", layerNum)); + } + } + } + + public void Error(Absy node, string message) + { + checkingContext.Error(node, message); + errorCount++; + } + + private class PurityChecker : StandardVisitor + { + private CivlTypeChecker civlTypeChecker; + + public PurityChecker(CivlTypeChecker civlTypeChecker) + { + this.civlTypeChecker = civlTypeChecker; + } + + public override Cmd VisitCallCmd(CallCmd node) + { + Procedure enclosingProc = civlTypeChecker.enclosingImpl.Proc; + if (!civlTypeChecker.procToAtomicProcedureInfo.ContainsKey(node.Proc)) + { + civlTypeChecker.Error(node, "Atomic procedure can only call an atomic procedure"); + return base.VisitCallCmd(node); + } + var callerInfo = civlTypeChecker.procToAtomicProcedureInfo[enclosingProc]; + var calleeInfo = civlTypeChecker.procToAtomicProcedureInfo[node.Proc]; + if (calleeInfo.isPure) + { + // do nothing + } + else if (callerInfo.isPure) + { + civlTypeChecker.Error(node, "Pure procedure can only call pure procedures"); + } + else if (!callerInfo.layerRange.Subset(calleeInfo.layerRange)) + { + civlTypeChecker.Error(node, "Caller layers must be subset of callee layers"); + } + return base.VisitCallCmd(node); + } + + public override Cmd VisitParCallCmd(ParCallCmd node) + { + civlTypeChecker.Error(node, "Atomic procedures cannot make parallel calls"); + return node; + } + + public override Expr VisitIdentifierExpr(IdentifierExpr node) + { + Procedure enclosingProc = civlTypeChecker.enclosingImpl.Proc; + if (node.Decl is GlobalVariable) + { + if (civlTypeChecker.procToAtomicProcedureInfo[enclosingProc].isPure) + { + civlTypeChecker.Error(node, "Pure procedure cannot access global variables"); + } + else if (!civlTypeChecker.globalVarToSharedVarInfo.ContainsKey(node.Decl)) + { + civlTypeChecker.Error(node, "Atomic procedure cannot access a global variable without layer numbers"); + } + else + { + civlTypeChecker.sharedVarsAccessed.Add(node.Decl); + } + } + return node; + } + } + } +} diff --git a/Source/Concurrency/Concurrency.csproj b/Source/Concurrency/Concurrency.csproj index c245d05a..ac90077c 100644 --- a/Source/Concurrency/Concurrency.csproj +++ b/Source/Concurrency/Concurrency.csproj @@ -1,115 +1,115 @@ - - - - - Debug - AnyCPU - {D07B8E38-E172-47F4-AD02-0373014A46D3} - Library - Properties - Concurrency - Concurrency - v4.0 - 512 - Client - - - AnyCPU - true - full - false - bin\Debug\ - TRACE;DEBUG - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - true - - - ..\InterimKey.snk - - - true - bin\QED\ - TRACE;DEBUG;QED - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - - - ..\..\Binaries\Microsoft.Automata.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {43dfad18-3e35-4558-9be2-caff6b5ba8a0} - Basetypes - - - {b230a69c-c466-4065-b9c1-84d80e76d802} - Core - - - {69a2b0b8-bcac-4101-ae7a-556fcc58c06e} - Graph - - - {fcd3ac7f-9dfd-46c8-ab1e-09f0b0f16dc5} - ParserHelper - - - - - - - + + + + + Debug + AnyCPU + {D07B8E38-E172-47F4-AD02-0373014A46D3} + Library + Properties + Concurrency + BoogieConcurrency + v4.0 + 512 + Client + + + AnyCPU + true + full + false + bin\Debug\ + TRACE;DEBUG + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + true + + + ..\InterimKey.snk + + + true + bin\QED\ + TRACE;DEBUG;QED + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + + + + ..\..\Binaries\Microsoft.Automata.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {43dfad18-3e35-4558-9be2-caff6b5ba8a0} + Basetypes + + + {b230a69c-c466-4065-b9c1-84d80e76d802} + Core + + + {69a2b0b8-bcac-4101-ae7a-556fcc58c06e} + Graph + + + {fcd3ac7f-9dfd-46c8-ab1e-09f0b0f16dc5} + ParserHelper + + + + + + + \ No newline at end of file diff --git a/Source/Concurrency/LinearSets.cs b/Source/Concurrency/LinearSets.cs index e3891c18..f654b688 100644 --- a/Source/Concurrency/LinearSets.cs +++ b/Source/Concurrency/LinearSets.cs @@ -1,1004 +1,1003 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Boogie; -using System.Diagnostics; - -namespace Microsoft.Boogie -{ - public class LinearEraser : ReadOnlyVisitor - { - private QKeyValue RemoveLinearAttribute(QKeyValue iter) - { - if (iter == null) return null; - iter.Next = RemoveLinearAttribute(iter.Next); - return (iter.Key == "linear" || iter.Key == "linear_in" || iter.Key == "linear_out") ? iter.Next : iter; - } - - public override Variable VisitVariable(Variable node) - { - node.Attributes = RemoveLinearAttribute(node.Attributes); - return base.VisitVariable(node); - } - - public override Function VisitFunction(Function node) - { - node.Attributes = RemoveLinearAttribute(node.Attributes); - return base.VisitFunction(node); - } - } - - public enum LinearKind { - LINEAR, - LINEAR_IN, - LINEAR_OUT - } - - public class LinearTypeChecker : ReadOnlyVisitor - { - public Program program; - public int errorCount; - public CheckingContext checkingContext; - public Dictionary> domainNameToCollectors; - private Dictionary> availableLinearVars; - public Dictionary inParamToLinearQualifier; - public Dictionary outParamToDomainName; - public Dictionary varToDomainName; - public Dictionary globalVarToDomainName; - public Dictionary linearDomains; - - public LinearTypeChecker(Program program) - { - this.program = program; - this.errorCount = 0; - this.checkingContext = new CheckingContext(null); - this.domainNameToCollectors = new Dictionary>(); - this.availableLinearVars = new Dictionary>(); - this.inParamToLinearQualifier = new Dictionary(); - this.outParamToDomainName = new Dictionary(); - this.varToDomainName = new Dictionary(); - this.globalVarToDomainName = new Dictionary(); - this.linearDomains = new Dictionary(); - } - public void TypeCheck() - { - this.VisitProgram(program); - foreach (string domainName in domainNameToCollectors.Keys) - { - var collectors = domainNameToCollectors[domainName]; - if (collectors.Count == 0) continue; - this.linearDomains[domainName] = new LinearDomain(program, domainName, collectors); - } - Dictionary> newAvailableLinearVars = new Dictionary>(); - foreach (Absy absy in this.availableLinearVars.Keys) - { - HashSet vars = new HashSet(); - foreach (Variable var in this.availableLinearVars[absy]) - { - if (var is GlobalVariable) continue; - string domainName = FindDomainName(var); - if (this.linearDomains.ContainsKey(domainName)) - { - vars.Add(var); - } - } - newAvailableLinearVars[absy] = vars; - } - this.availableLinearVars = newAvailableLinearVars; - var temp = new Dictionary(); - foreach (Variable v in outParamToDomainName.Keys) - { - if (linearDomains.ContainsKey(outParamToDomainName[v])) - temp[v] = outParamToDomainName[v]; - } - this.outParamToDomainName = temp; - temp = new Dictionary(); - foreach (Variable v in varToDomainName.Keys) - { - if (linearDomains.ContainsKey(varToDomainName[v])) - temp[v] = varToDomainName[v]; - } - this.varToDomainName = temp; - temp = new Dictionary(); - foreach (Variable v in globalVarToDomainName.Keys) - { - if (linearDomains.ContainsKey(globalVarToDomainName[v])) - temp[v] = globalVarToDomainName[v]; - } - this.globalVarToDomainName = temp; - } - private void Error(Absy node, string message) - { - checkingContext.Error(node, message); - errorCount++; - } - public override Program VisitProgram(Program node) - { - foreach (GlobalVariable g in program.GlobalVariables) - { - string domainName = FindDomainName(g); - if (domainName != null) - { - globalVarToDomainName[g] = domainName; - } - } - return base.VisitProgram(node); - } - public override Function VisitFunction(Function node) - { - string domainName = QKeyValue.FindStringAttribute(node.Attributes, "linear"); - if (domainName != null) - { - if (!domainNameToCollectors.ContainsKey(domainName)) - { - domainNameToCollectors[domainName] = new Dictionary(); - } - if (node.InParams.Count == 1 && node.OutParams.Count == 1) - { - Type inType = node.InParams[0].TypedIdent.Type; - MapType outType = node.OutParams[0].TypedIdent.Type as MapType; - if (domainNameToCollectors[domainName].ContainsKey(inType)) - { - Error(node, string.Format("A collector for domain for input type has already been defined")); - } - else if (outType == null || outType.Arguments.Count != 1 || !outType.Result.Equals(Type.Bool)) - { - Error(node, "Output of a linear domain collector should be of set type"); - } - else - { - domainNameToCollectors[domainName][inType] = node; - } - } - else - { - Error(node, "Linear domain collector should have one input and one output parameter"); - } - } - return base.VisitFunction(node); - } - public override Implementation VisitImplementation(Implementation node) - { - node.PruneUnreachableBlocks(); - node.ComputePredecessorsForBlocks(); - GraphUtil.Graph graph = Program.GraphFromImpl(node); - graph.ComputeLoops(); - - HashSet start = new HashSet(globalVarToDomainName.Keys); - for (int i = 0; i < node.InParams.Count; i++) - { - Variable v = node.Proc.InParams[i]; - string domainName = FindDomainName(v); - if (domainName != null) - { - var kind = FindLinearKind(v); - inParamToLinearQualifier[node.InParams[i]] = new LinearQualifier(domainName, kind); - if (kind == LinearKind.LINEAR || kind == LinearKind.LINEAR_IN) - { - start.Add(node.InParams[i]); - } - } - } - for (int i = 0; i < node.OutParams.Count; i++) - { - string domainName = FindDomainName(node.Proc.OutParams[i]); - if (domainName != null) - { - outParamToDomainName[node.OutParams[i]] = domainName; - } - } - - var oldErrorCount = this.errorCount; - var impl = base.VisitImplementation(node); - if (oldErrorCount < this.errorCount) - return impl; - - Stack dfsStack = new Stack(); - HashSet dfsStackAsSet = new HashSet(); - availableLinearVars[node.Blocks[0]] = start; - dfsStack.Push(node.Blocks[0]); - dfsStackAsSet.Add(node.Blocks[0]); - while (dfsStack.Count > 0) - { - Block b = dfsStack.Pop(); - dfsStackAsSet.Remove(b); - HashSet end = PropagateAvailableLinearVarsAcrossBlock(b); - if (b.TransferCmd is ReturnCmd) - { - foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(end)) - { - Error(b.TransferCmd, string.Format("Global variable {0} must be available at a return", g.Name)); - } - foreach (Variable v in node.InParams) - { - if (FindDomainName(v) == null || FindLinearKind(v) == LinearKind.LINEAR_IN || end.Contains(v)) continue; - Error(b.TransferCmd, string.Format("Input variable {0} must be available at a return", v.Name)); - } - foreach (Variable v in node.OutParams) - { - if (FindDomainName(v) == null || end.Contains(v)) continue; - Error(b.TransferCmd, string.Format("Output variable {0} must be available at a return", v.Name)); - } - continue; - } - GotoCmd gotoCmd = b.TransferCmd as GotoCmd; - foreach (Block target in gotoCmd.labelTargets) - { - if (!availableLinearVars.ContainsKey(target)) - { - availableLinearVars[target] = new HashSet(end); - dfsStack.Push(target); - dfsStackAsSet.Add(target); - } - else - { - var savedAvailableVars = new HashSet(availableLinearVars[target]); - availableLinearVars[target].IntersectWith(end); - if (savedAvailableVars.IsProperSupersetOf(availableLinearVars[target]) && !dfsStackAsSet.Contains(target)) - { - dfsStack.Push(target); - dfsStackAsSet.Add(target); - } - } - } - } - - if (graph.Reducible) - { - foreach (Block header in graph.Headers) - { - foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(availableLinearVars[header])) - { - Error(header, string.Format("Global variable {0} must be available at a loop head", g.Name)); - } - } - } - return impl; - } - public void AddAvailableVars(CallCmd callCmd, HashSet start) - { - foreach (IdentifierExpr ie in callCmd.Outs) - { - if (FindDomainName(ie.Decl) == null) continue; - start.Add(ie.Decl); - } - for (int i = 0; i < callCmd.Proc.InParams.Count; i++) - { - IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr; - if (ie == null) continue; - Variable v = callCmd.Proc.InParams[i]; - if (FindDomainName(v) == null) continue; - if (FindLinearKind(v) == LinearKind.LINEAR_OUT) - { - start.Add(ie.Decl); - } - } - } - public void AddAvailableVars(ParCallCmd parCallCmd, HashSet start) - { - foreach (CallCmd callCmd in parCallCmd.CallCmds) - { - AddAvailableVars(callCmd, start); - } - } - private HashSet PropagateAvailableLinearVarsAcrossBlock(Block b) { - HashSet start = new HashSet(availableLinearVars[b]); - foreach (Cmd cmd in b.Cmds) - { - if (cmd is AssignCmd) - { - AssignCmd assignCmd = (AssignCmd)cmd; - for (int i = 0; i < assignCmd.Lhss.Count; i++) - { - if (FindDomainName(assignCmd.Lhss[i].DeepAssignedVariable) == null) continue; - IdentifierExpr ie = assignCmd.Rhss[i] as IdentifierExpr; - if (!start.Contains(ie.Decl)) - { - Error(ie, "unavailable source for a linear read"); - } - else - { - start.Remove(ie.Decl); - } - } - foreach (AssignLhs assignLhs in assignCmd.Lhss) - { - if (FindDomainName(assignLhs.DeepAssignedVariable) == null) continue; - start.Add(assignLhs.DeepAssignedVariable); - } - } - else if (cmd is CallCmd) - { - foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start)) - { - Error(cmd, string.Format("Global variable {0} must be available at a call", g.Name)); - } - CallCmd callCmd = (CallCmd)cmd; - for (int i = 0; i < callCmd.Proc.InParams.Count; i++) - { - Variable param = callCmd.Proc.InParams[i]; - if (FindDomainName(param) == null) continue; - IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr; - LinearKind paramKind = FindLinearKind(param); - if (start.Contains(ie.Decl)) - { - if (callCmd.IsAsync || paramKind == LinearKind.LINEAR_IN) - { - start.Remove(ie.Decl); - } - } - else - { - if (paramKind == LinearKind.LINEAR_OUT) - { - start.Add(ie.Decl); - } - else - { - Error(ie, "unavailable source for a linear read"); - } - } - } - availableLinearVars[callCmd] = new HashSet(start); - AddAvailableVars(callCmd, start); - } - else if (cmd is ParCallCmd) - { - foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start)) - { - Error(cmd, string.Format("Global variable {0} must be available at a call", g.Name)); - } - ParCallCmd parCallCmd = (ParCallCmd)cmd; - foreach (CallCmd callCmd in parCallCmd.CallCmds) - { - for (int i = 0; i < callCmd.Proc.InParams.Count; i++) - { - Variable param = callCmd.Proc.InParams[i]; - if (FindDomainName(param) == null) continue; - IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr; - LinearKind paramKind = FindLinearKind(param); - if (start.Contains(ie.Decl)) - { - if (paramKind == LinearKind.LINEAR_IN) - { - start.Remove(ie.Decl); - } - } - else - { - if (paramKind == LinearKind.LINEAR_OUT) - { - start.Add(ie.Decl); - } - else - { - Error(ie, "unavailable source for a linear read"); - } - } - } - } - availableLinearVars[parCallCmd] = new HashSet(start); - AddAvailableVars(parCallCmd, start); - } - else if (cmd is HavocCmd) - { - HavocCmd havocCmd = (HavocCmd)cmd; - foreach (IdentifierExpr ie in havocCmd.Vars) - { - if (FindDomainName(ie.Decl) == null) continue; - start.Remove(ie.Decl); - } - } - else if (cmd is YieldCmd) - { - foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start)) - { - Error(cmd, string.Format("Global variable {0} must be available at a yield", g.Name)); - } - availableLinearVars[cmd] = new HashSet(start); - } - } - return start; - } - public string FindDomainName(Variable v) - { - if (globalVarToDomainName.ContainsKey(v)) - return globalVarToDomainName[v]; - if (inParamToLinearQualifier.ContainsKey(v)) - return inParamToLinearQualifier[v].domainName; - if (outParamToDomainName.ContainsKey(v)) - return outParamToDomainName[v]; - string domainName = QKeyValue.FindStringAttribute(v.Attributes, "linear"); - if (domainName != null) - return domainName; - domainName = QKeyValue.FindStringAttribute(v.Attributes, "linear_in"); - if (domainName != null) - return domainName; - return QKeyValue.FindStringAttribute(v.Attributes, "linear_out"); - } - public LinearKind FindLinearKind(Variable v) - { - if (globalVarToDomainName.ContainsKey(v)) - return LinearKind.LINEAR; - if (inParamToLinearQualifier.ContainsKey(v)) - return inParamToLinearQualifier[v].kind; - if (outParamToDomainName.ContainsKey(v)) - return LinearKind.LINEAR; - - if (QKeyValue.FindStringAttribute(v.Attributes, "linear") != null) - { - return LinearKind.LINEAR; - } - else if (QKeyValue.FindStringAttribute(v.Attributes, "linear_in") != null) - { - return LinearKind.LINEAR_IN; - } - else if (QKeyValue.FindStringAttribute(v.Attributes, "linear_out") != null) - { - return LinearKind.LINEAR_OUT; - } - else - { - Debug.Assert(false); - return LinearKind.LINEAR; - } - } - public override Variable VisitVariable(Variable node) - { - string domainName = FindDomainName(node); - if (domainName != null) - { - if (!domainNameToCollectors.ContainsKey(domainName)) - { - domainNameToCollectors[domainName] = new Dictionary(); - } - LinearKind kind = FindLinearKind(node); - if (kind != LinearKind.LINEAR) - { - if (node is GlobalVariable || node is LocalVariable || (node is Formal && !(node as Formal).InComing)) - { - Error(node, "Variable must be declared linear (as opposed to linear_in or linear_out)"); - } - } - } - return base.VisitVariable(node); - } - public override Cmd VisitAssignCmd(AssignCmd node) - { - HashSet rhsVars = new HashSet(); - for (int i = 0; i < node.Lhss.Count; i++) - { - AssignLhs lhs = node.Lhss[i]; - Variable lhsVar = lhs.DeepAssignedVariable; - string domainName = FindDomainName(lhsVar); - if (domainName == null) continue; - SimpleAssignLhs salhs = lhs as SimpleAssignLhs; - if (salhs == null) - { - Error(node, string.Format("Only simple assignment allowed on linear variable {0}", lhsVar.Name)); - continue; - } - IdentifierExpr rhs = node.Rhss[i] as IdentifierExpr; - if (rhs == null) - { - Error(node, string.Format("Only variable can be assigned to linear variable {0}", lhsVar.Name)); - continue; - } - string rhsDomainName = FindDomainName(rhs.Decl); - if (rhsDomainName == null) - { - Error(node, string.Format("Only linear variable can be assigned to linear variable {0}", lhsVar.Name)); - continue; - } - if (domainName != rhsDomainName) - { - Error(node, string.Format("Linear variable of domain {0} cannot be assigned to linear variable of domain {1}", rhsDomainName, domainName)); - continue; - } - if (rhsVars.Contains(rhs.Decl)) - { - Error(node, string.Format("Linear variable {0} can occur only once in the right-hand-side of an assignment", rhs.Decl.Name)); - continue; - } - rhsVars.Add(rhs.Decl); - } - return base.VisitAssignCmd(node); - } - public override Cmd VisitCallCmd(CallCmd node) - { - HashSet inVars = new HashSet(); - for (int i = 0; i < node.Proc.InParams.Count; i++) - { - Variable formal = node.Proc.InParams[i]; - string domainName = FindDomainName(formal); - if (domainName == null) continue; - IdentifierExpr actual = node.Ins[i] as IdentifierExpr; - if (actual == null) - { - Error(node, string.Format("Only variable can be passed to linear parameter {0}", formal.Name)); - continue; - } - string actualDomainName = FindDomainName(actual.Decl); - if (actualDomainName == null) - { - Error(node, string.Format("Only a linear argument can be passed to linear parameter {0}", formal.Name)); - continue; - } - if (domainName != actualDomainName) - { - Error(node, "The domains of formal and actual parameters must be the same"); - continue; - } - if (actual.Decl is GlobalVariable) - { - Error(node, "Only local linear variable can be an actual input parameter of a procedure call"); - continue; - } - if (inVars.Contains(actual.Decl)) - { - Error(node, string.Format("Linear variable {0} can occur only once as an input parameter", actual.Decl.Name)); - continue; - } - inVars.Add(actual.Decl); - } - for (int i = 0; i < node.Proc.OutParams.Count; i++) - { - IdentifierExpr actual = node.Outs[i]; - string actualDomainName = FindDomainName(actual.Decl); - if (actualDomainName == null) continue; - Variable formal = node.Proc.OutParams[i]; - string domainName = FindDomainName(formal); - if (domainName == null) - { - Error(node, "Only a linear variable can be passed to a linear parameter"); - continue; - } - if (domainName != actualDomainName) - { - Error(node, "The domains of formal and actual parameters must be the same"); - continue; - } - if (actual.Decl is GlobalVariable) - { - Error(node, "Only local linear variable can be actual output parameter of a procedure call"); - continue; - } - } - return base.VisitCallCmd(node); - } - public override Cmd VisitParCallCmd(ParCallCmd node) - { - HashSet parallelCallInvars = new HashSet(); - foreach (CallCmd callCmd in node.CallCmds) - { - for (int i = 0; i < callCmd.Proc.InParams.Count; i++) - { - Variable formal = callCmd.Proc.InParams[i]; - string domainName = FindDomainName(formal); - if (domainName == null) continue; - IdentifierExpr actual = callCmd.Ins[i] as IdentifierExpr; - if (parallelCallInvars.Contains(actual.Decl)) - { - Error(node, string.Format("Linear variable {0} can occur only once as an input parameter of a parallel call", actual.Decl.Name)); - } - else - { - parallelCallInvars.Add(actual.Decl); - } - } - } - return base.VisitParCallCmd(node); - } - - public override Requires VisitRequires(Requires requires) - { - return requires; - } - - public override Ensures VisitEnsures(Ensures ensures) - { - return ensures; - } - - public IEnumerable AvailableLinearVars(Absy absy) - { - if (availableLinearVars.ContainsKey(absy)) - { - return availableLinearVars[absy]; - } - else - { - return new HashSet(); - } - } - - private void AddDisjointnessExpr(List newCmds, Absy absy, Dictionary domainNameToInputVar) - { - Dictionary> domainNameToScope = new Dictionary>(); - foreach (var domainName in linearDomains.Keys) - { - domainNameToScope[domainName] = new HashSet(); - } - foreach (Variable v in AvailableLinearVars(absy)) - { - var domainName = FindDomainName(v); - domainNameToScope[domainName].Add(v); - } - foreach (Variable v in program.GlobalVariables) - { - var domainName = FindDomainName(v); - if (domainName == null) continue; - domainNameToScope[domainName].Add(v); - } - foreach (string domainName in linearDomains.Keys) - { - newCmds.Add(new AssumeCmd(Token.NoToken, DisjointnessExpr(domainName, domainNameToInputVar[domainName], domainNameToScope[domainName]))); - } - } - - public void Transform() - { - foreach (var impl in program.Implementations) - { - Dictionary domainNameToInputVar = new Dictionary(); - foreach (string domainName in linearDomains.Keys) - { - var domain = linearDomains[domainName]; - Formal f = new Formal( - Token.NoToken, - new TypedIdent(Token.NoToken, - "linear_" + domainName + "_in", - new MapType(Token.NoToken, new List(), - new List { domain.elementType }, Type.Bool)), true); - impl.InParams.Add(f); - domainNameToInputVar[domainName] = f; - } - - foreach (Block b in impl.Blocks) - { - List newCmds = new List(); - for (int i = 0; i < b.Cmds.Count; i++) - { - Cmd cmd = b.Cmds[i]; - newCmds.Add(cmd); - if (cmd is CallCmd) - { - CallCmd callCmd = cmd as CallCmd; - if (callCmd.IsAsync) - { - foreach (var domainName in linearDomains.Keys) - { - var domain = linearDomains[domainName]; - var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstBool), new List { Expr.False }); - expr.Resolve(new ResolutionContext(null)); - expr.Typecheck(new TypecheckingContext(null)); - callCmd.Ins.Add(expr); - } - } - else - { - Dictionary domainNameToExpr = new Dictionary(); - foreach (var domainName in linearDomains.Keys) - { - domainNameToExpr[domainName] = Expr.Ident(domainNameToInputVar[domainName]); - } - foreach (Variable v in AvailableLinearVars(callCmd)) - { - var domainName = FindDomainName(v); - var domain = linearDomains[domainName]; - if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; - Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List { Expr.Ident(v) }); - var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapOrBool), new List { ie, domainNameToExpr[domainName] }); - expr.Resolve(new ResolutionContext(null)); - expr.Typecheck(new TypecheckingContext(null)); - domainNameToExpr[domainName] = expr; - } - foreach (var domainName in linearDomains.Keys) - { - callCmd.Ins.Add(domainNameToExpr[domainName]); - } - } - } - else if (cmd is ParCallCmd) - { - ParCallCmd parCallCmd = (ParCallCmd)cmd; - foreach (CallCmd callCmd in parCallCmd.CallCmds) - { - foreach (var domainName in linearDomains.Keys) - { - var domain = linearDomains[domainName]; - var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstBool), new List { Expr.False }); - expr.Resolve(new ResolutionContext(null)); - expr.Typecheck(new TypecheckingContext(null)); - callCmd.Ins.Add(expr); - } - } - } - else if (cmd is YieldCmd) - { - AddDisjointnessExpr(newCmds, cmd, domainNameToInputVar); - } - } - b.Cmds = newCmds; - } - - { - // Loops - impl.PruneUnreachableBlocks(); - impl.ComputePredecessorsForBlocks(); - GraphUtil.Graph g = Program.GraphFromImpl(impl); - g.ComputeLoops(); - if (g.Reducible) - { - foreach (Block header in g.Headers) - { - List newCmds = new List(); - AddDisjointnessExpr(newCmds, header, domainNameToInputVar); - newCmds.AddRange(header.Cmds); - header.Cmds = newCmds; - } - } - } - } - - foreach (var proc in program.Procedures) - { - Dictionary> domainNameToInputScope = new Dictionary>(); - Dictionary> domainNameToOutputScope = new Dictionary>(); - foreach (var domainName in linearDomains.Keys) - { - domainNameToInputScope[domainName] = new HashSet(); - domainNameToOutputScope[domainName] = new HashSet(); - - } - foreach (Variable v in globalVarToDomainName.Keys) - { - var domainName = globalVarToDomainName[v]; - domainNameToInputScope[domainName].Add(v); - domainNameToOutputScope[domainName].Add(v); - } - foreach (Variable v in proc.InParams) - { - var domainName = FindDomainName(v); - if (domainName == null) continue; - if (!this.linearDomains.ContainsKey(domainName)) continue; - domainNameToInputScope[domainName].Add(v); - } - foreach (Variable v in proc.OutParams) - { - var domainName = FindDomainName(v); - if (domainName == null) continue; - if (!this.linearDomains.ContainsKey(domainName)) continue; - domainNameToOutputScope[domainName].Add(v); - } - foreach (var domainName in linearDomains.Keys) - { - proc.Requires.Add(new Requires(true, DisjointnessExpr(domainName, domainNameToInputScope[domainName]))); - var domain = linearDomains[domainName]; - Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List(), new List { domain.elementType }, Type.Bool)), true); - proc.InParams.Add(f); - proc.Ensures.Add(new Ensures(true, DisjointnessExpr(domainName, f, domainNameToOutputScope[domainName]))); - } - } - - foreach (LinearDomain domain in linearDomains.Values) - { - program.AddTopLevelDeclaration(domain.mapConstBool); - program.AddTopLevelDeclaration(domain.mapConstInt); - program.AddTopLevelDeclaration(domain.mapEqInt); - program.AddTopLevelDeclaration(domain.mapImpBool); - program.AddTopLevelDeclaration(domain.mapOrBool); - foreach (Axiom axiom in domain.axioms) - { - program.AddTopLevelDeclaration(axiom); - } - } - - //int oldPrintUnstructured = CommandLineOptions.Clo.PrintUnstructured; - //CommandLineOptions.Clo.PrintUnstructured = 1; - //PrintBplFile("lsd.bpl", program, false, false); - //CommandLineOptions.Clo.PrintUnstructured = oldPrintUnstructured; - } - - private Expr SubsetExpr(LinearDomain domain, Expr ie, Variable partition, int partitionCount) - { - Expr e = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstInt), new List { new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(partitionCount)) }); - e = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapEqInt), new List { Expr.Ident(partition), e }); - e = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapImpBool), new List { ie, e }); - e = Expr.Eq(e, new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstBool), new List { Expr.True })); - return e; - } - - private Expr SubsetExprs(LinearDomain domain, HashSet scope, Variable partition, int count, Expr expr) - { - foreach (Variable v in scope) - { - if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; - Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List { Expr.Ident(v) }); - expr = Expr.And(SubsetExpr(domain, ie, partition, count), expr); - count++; - } - expr = new ExistsExpr(Token.NoToken, new List { partition }, expr); - expr.Resolve(new ResolutionContext(null)); - expr.Typecheck(new TypecheckingContext(null)); - return expr; - } - - public Expr DisjointnessExpr(string domainName, Variable inputVar, HashSet scope) - { - LinearDomain domain = linearDomains[domainName]; - BoundVariable partition = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("partition_{0}", domainName), new MapType(Token.NoToken, new List(), new List { domain.elementType }, Microsoft.Boogie.Type.Int))); - return SubsetExprs(domain, scope, partition, 1, SubsetExpr(domain, Expr.Ident(inputVar), partition, 0)); - } - - public Expr DisjointnessExpr(string domainName, HashSet scope) - { - LinearDomain domain = linearDomains[domainName]; - BoundVariable partition = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("partition_{0}", domainName), new MapType(Token.NoToken, new List(), new List { domain.elementType }, Microsoft.Boogie.Type.Int))); - return SubsetExprs(domain, scope, partition, 0, Expr.True); - } - } - - public class LinearQualifier - { - public string domainName; - public LinearKind kind; - public LinearQualifier(string domainName, LinearKind kind) - { - this.domainName = domainName; - this.kind = kind; - } - } - - public class LinearDomain - { - public Function mapEqInt; - public Function mapConstInt; - public Function mapOrBool; - public Function mapImpBool; - public Function mapConstBool; - public List axioms; - public Type elementType; - public Dictionary collectors; - - public LinearDomain(Program program, string domainName, Dictionary collectors) - { - this.axioms = new List(); - this.collectors = collectors; - MapType setType = (MapType)collectors.First().Value.OutParams[0].TypedIdent.Type; - this.elementType = setType.Arguments[0]; - MapType mapTypeBool = new MapType(Token.NoToken, new List(), new List { this.elementType }, Type.Bool); - MapType mapTypeInt = new MapType(Token.NoToken, new List(), new List { this.elementType }, Type.Int); - this.mapOrBool = new Function(Token.NoToken, "linear_" + domainName + "_MapOr", - new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool), true), - new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool), true) }, - new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); - if (CommandLineOptions.Clo.UseArrayTheory) - { - this.mapOrBool.AddAttribute("builtin", "MapOr"); - } - else - { - BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool)); - IdentifierExpr aie = Expr.Ident(a); - BoundVariable b = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool)); - IdentifierExpr bie = Expr.Ident(b); - BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); - IdentifierExpr xie = Expr.Ident(x); - var mapApplTerm = new NAryExpr(Token.NoToken, new FunctionCall(mapOrBool), new List { aie, bie } ); - var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { mapApplTerm, xie } ); - var rhsTerm = Expr.Or(new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { aie, xie } ), - new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { bie, xie} )); - var axiomExpr = new ForallExpr(Token.NoToken, new List(), new List { a, b }, null, - new Trigger(Token.NoToken, true, new List { mapApplTerm }), - new ForallExpr(Token.NoToken, new List { x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, rhsTerm))); - axiomExpr.Typecheck(new TypecheckingContext(null)); - axioms.Add(new Axiom(Token.NoToken, axiomExpr)); - } - - this.mapImpBool = new Function(Token.NoToken, "linear_" + domainName + "_MapImp", - new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool), true), - new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool), true) }, - new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); - if (CommandLineOptions.Clo.UseArrayTheory) - { - this.mapImpBool.AddAttribute("builtin", "MapImp"); - } - else - { - BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool)); - IdentifierExpr aie = Expr.Ident(a); - BoundVariable b = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool)); - IdentifierExpr bie = Expr.Ident(b); - BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); - IdentifierExpr xie = Expr.Ident(x); - var mapApplTerm = new NAryExpr(Token.NoToken, new FunctionCall(mapImpBool), new List { aie, bie }); - var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { mapApplTerm, xie }); - var rhsTerm = Expr.Imp(new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { aie, xie }), - new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { bie, xie })); - var axiomExpr = new ForallExpr(Token.NoToken, new List(), new List { a, b }, null, - new Trigger(Token.NoToken, true, new List { mapApplTerm }), - new ForallExpr(Token.NoToken, new List { x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, rhsTerm))); - axiomExpr.Typecheck(new TypecheckingContext(null)); - axioms.Add(new Axiom(Token.NoToken, axiomExpr)); - } - - this.mapConstBool = new Function(Token.NoToken, "linear_" + domainName + "_MapConstBool", - new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", Type.Bool), true) }, - new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); - if (CommandLineOptions.Clo.UseArrayTheory) - { - this.mapConstBool.AddAttribute("builtin", "MapConst"); - } - else - { - BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); - IdentifierExpr xie = Expr.Ident(x); - var trueTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), - new List { new NAryExpr(Token.NoToken, new FunctionCall(mapConstBool), new List { Expr.True }), xie }); - var trueAxiomExpr = new ForallExpr(Token.NoToken, new List { x }, trueTerm); - trueAxiomExpr.Typecheck(new TypecheckingContext(null)); - axioms.Add(new Axiom(Token.NoToken, trueAxiomExpr)); - var falseTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), - new List { new NAryExpr(Token.NoToken, new FunctionCall(mapConstBool), new List { Expr.False }), xie }); - var falseAxiomExpr = new ForallExpr(Token.NoToken, new List { x }, Expr.Unary(Token.NoToken, UnaryOperator.Opcode.Not, falseTerm)); - falseAxiomExpr.Typecheck(new TypecheckingContext(null)); - axioms.Add(new Axiom(Token.NoToken, falseAxiomExpr)); - } - - this.mapEqInt = new Function(Token.NoToken, "linear_" + domainName + "_MapEq", - new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeInt), true), - new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeInt), true) }, - new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); - if (CommandLineOptions.Clo.UseArrayTheory) - { - this.mapEqInt.AddAttribute("builtin", "MapEq"); - } - else - { - BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeInt)); - IdentifierExpr aie = Expr.Ident(a); - BoundVariable b = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeInt)); - IdentifierExpr bie = Expr.Ident(b); - BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); - IdentifierExpr xie = Expr.Ident(x); - var mapApplTerm = new NAryExpr(Token.NoToken, new FunctionCall(mapEqInt), new List { aie, bie }); - var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { mapApplTerm, xie }); - var rhsTerm = Expr.Eq(new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { aie, xie }), - new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { bie, xie })); - var axiomExpr = new ForallExpr(Token.NoToken, new List(), new List { a, b }, null, - new Trigger(Token.NoToken, true, new List { mapApplTerm }), - new ForallExpr(Token.NoToken, new List { x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, rhsTerm))); - axiomExpr.Typecheck(new TypecheckingContext(null)); - axioms.Add(new Axiom(Token.NoToken, axiomExpr)); - } - - this.mapConstInt = new Function(Token.NoToken, "linear_" + domainName + "_MapConstInt", - new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", Type.Int), true) }, - new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeInt), false)); - if (CommandLineOptions.Clo.UseArrayTheory) - { - this.mapConstInt.AddAttribute("builtin", "MapConst"); - } - else - { - BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", Type.Int)); - IdentifierExpr aie = Expr.Ident(a); - BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); - IdentifierExpr xie = Expr.Ident(x); - var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { new NAryExpr(Token.NoToken, new FunctionCall(mapConstInt), new List { aie }), xie }); - var axiomExpr = new ForallExpr(Token.NoToken, new List { a, x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, aie)); - axiomExpr.Typecheck(new TypecheckingContext(null)); - axioms.Add(new Axiom(Token.NoToken, axiomExpr)); - } - - foreach (var axiom in axioms) - { - axiom.Expr.Resolve(new ResolutionContext(null)); - axiom.Expr.Typecheck(new TypecheckingContext(null)); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Boogie; +using System.Diagnostics; + +namespace Microsoft.Boogie +{ + public class LinearEraser : ReadOnlyVisitor + { + private QKeyValue RemoveLinearAttribute(QKeyValue iter) + { + if (iter == null) return null; + iter.Next = RemoveLinearAttribute(iter.Next); + return (iter.Key == "linear" || iter.Key == "linear_in" || iter.Key == "linear_out") ? iter.Next : iter; + } + + public override Variable VisitVariable(Variable node) + { + node.Attributes = RemoveLinearAttribute(node.Attributes); + return base.VisitVariable(node); + } + + public override Function VisitFunction(Function node) + { + node.Attributes = RemoveLinearAttribute(node.Attributes); + return base.VisitFunction(node); + } + } + + public enum LinearKind { + LINEAR, + LINEAR_IN, + LINEAR_OUT + } + + public class LinearTypeChecker : ReadOnlyVisitor + { + public Program program; + public int errorCount; + public CheckingContext checkingContext; + public Dictionary> domainNameToCollectors; + private Dictionary> availableLinearVars; + public Dictionary inParamToLinearQualifier; + public Dictionary outParamToDomainName; + public Dictionary varToDomainName; + public Dictionary globalVarToDomainName; + public Dictionary linearDomains; + + public LinearTypeChecker(Program program) + { + this.program = program; + this.errorCount = 0; + this.checkingContext = new CheckingContext(null); + this.domainNameToCollectors = new Dictionary>(); + this.availableLinearVars = new Dictionary>(); + this.inParamToLinearQualifier = new Dictionary(); + this.outParamToDomainName = new Dictionary(); + this.varToDomainName = new Dictionary(); + this.globalVarToDomainName = new Dictionary(); + this.linearDomains = new Dictionary(); + } + public void TypeCheck() + { + this.VisitProgram(program); + foreach (string domainName in domainNameToCollectors.Keys) + { + var collectors = domainNameToCollectors[domainName]; + if (collectors.Count == 0) continue; + this.linearDomains[domainName] = new LinearDomain(program, domainName, collectors); + } + Dictionary> newAvailableLinearVars = new Dictionary>(); + foreach (Absy absy in this.availableLinearVars.Keys) + { + HashSet vars = new HashSet(); + foreach (Variable var in this.availableLinearVars[absy]) + { + if (var is GlobalVariable) continue; + string domainName = FindDomainName(var); + if (this.linearDomains.ContainsKey(domainName)) + { + vars.Add(var); + } + } + newAvailableLinearVars[absy] = vars; + } + this.availableLinearVars = newAvailableLinearVars; + var temp = new Dictionary(); + foreach (Variable v in outParamToDomainName.Keys) + { + if (linearDomains.ContainsKey(outParamToDomainName[v])) + temp[v] = outParamToDomainName[v]; + } + this.outParamToDomainName = temp; + temp = new Dictionary(); + foreach (Variable v in varToDomainName.Keys) + { + if (linearDomains.ContainsKey(varToDomainName[v])) + temp[v] = varToDomainName[v]; + } + this.varToDomainName = temp; + temp = new Dictionary(); + foreach (Variable v in globalVarToDomainName.Keys) + { + if (linearDomains.ContainsKey(globalVarToDomainName[v])) + temp[v] = globalVarToDomainName[v]; + } + this.globalVarToDomainName = temp; + } + private void Error(Absy node, string message) + { + checkingContext.Error(node, message); + errorCount++; + } + public override Program VisitProgram(Program node) + { + foreach (GlobalVariable g in program.GlobalVariables) + { + string domainName = FindDomainName(g); + if (domainName != null) + { + globalVarToDomainName[g] = domainName; + } + } + return base.VisitProgram(node); + } + public override Function VisitFunction(Function node) + { + string domainName = QKeyValue.FindStringAttribute(node.Attributes, "linear"); + if (domainName != null) + { + if (!domainNameToCollectors.ContainsKey(domainName)) + { + domainNameToCollectors[domainName] = new Dictionary(); + } + if (node.InParams.Count == 1 && node.OutParams.Count == 1) + { + Type inType = node.InParams[0].TypedIdent.Type; + MapType outType = node.OutParams[0].TypedIdent.Type as MapType; + if (domainNameToCollectors[domainName].ContainsKey(inType)) + { + Error(node, string.Format("A collector for domain for input type has already been defined")); + } + else if (outType == null || outType.Arguments.Count != 1 || !outType.Result.Equals(Type.Bool)) + { + Error(node, "Output of a linear domain collector should be of set type"); + } + else + { + domainNameToCollectors[domainName][inType] = node; + } + } + else + { + Error(node, "Linear domain collector should have one input and one output parameter"); + } + } + return base.VisitFunction(node); + } + public override Implementation VisitImplementation(Implementation node) + { + node.PruneUnreachableBlocks(); + node.ComputePredecessorsForBlocks(); + GraphUtil.Graph graph = Program.GraphFromImpl(node); + graph.ComputeLoops(); + + HashSet start = new HashSet(globalVarToDomainName.Keys); + for (int i = 0; i < node.InParams.Count; i++) + { + Variable v = node.Proc.InParams[i]; + string domainName = FindDomainName(v); + if (domainName != null) + { + var kind = FindLinearKind(v); + inParamToLinearQualifier[node.InParams[i]] = new LinearQualifier(domainName, kind); + if (kind == LinearKind.LINEAR || kind == LinearKind.LINEAR_IN) + { + start.Add(node.InParams[i]); + } + } + } + for (int i = 0; i < node.OutParams.Count; i++) + { + string domainName = FindDomainName(node.Proc.OutParams[i]); + if (domainName != null) + { + outParamToDomainName[node.OutParams[i]] = domainName; + } + } + + var oldErrorCount = this.errorCount; + var impl = base.VisitImplementation(node); + if (oldErrorCount < this.errorCount) + return impl; + + Stack dfsStack = new Stack(); + HashSet dfsStackAsSet = new HashSet(); + availableLinearVars[node.Blocks[0]] = start; + dfsStack.Push(node.Blocks[0]); + dfsStackAsSet.Add(node.Blocks[0]); + while (dfsStack.Count > 0) + { + Block b = dfsStack.Pop(); + dfsStackAsSet.Remove(b); + HashSet end = PropagateAvailableLinearVarsAcrossBlock(b); + if (b.TransferCmd is ReturnCmd) + { + foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(end)) + { + Error(b.TransferCmd, string.Format("Global variable {0} must be available at a return", g.Name)); + } + foreach (Variable v in node.InParams) + { + if (FindDomainName(v) == null || FindLinearKind(v) == LinearKind.LINEAR_IN || end.Contains(v)) continue; + Error(b.TransferCmd, string.Format("Input variable {0} must be available at a return", v.Name)); + } + foreach (Variable v in node.OutParams) + { + if (FindDomainName(v) == null || end.Contains(v)) continue; + Error(b.TransferCmd, string.Format("Output variable {0} must be available at a return", v.Name)); + } + continue; + } + GotoCmd gotoCmd = b.TransferCmd as GotoCmd; + foreach (Block target in gotoCmd.labelTargets) + { + if (!availableLinearVars.ContainsKey(target)) + { + availableLinearVars[target] = new HashSet(end); + dfsStack.Push(target); + dfsStackAsSet.Add(target); + } + else + { + var savedAvailableVars = new HashSet(availableLinearVars[target]); + availableLinearVars[target].IntersectWith(end); + if (savedAvailableVars.IsProperSupersetOf(availableLinearVars[target]) && !dfsStackAsSet.Contains(target)) + { + dfsStack.Push(target); + dfsStackAsSet.Add(target); + } + } + } + } + + if (graph.Reducible) + { + foreach (Block header in graph.Headers) + { + foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(availableLinearVars[header])) + { + Error(header, string.Format("Global variable {0} must be available at a loop head", g.Name)); + } + } + } + return impl; + } + public void AddAvailableVars(CallCmd callCmd, HashSet start) + { + foreach (IdentifierExpr ie in callCmd.Outs) + { + if (FindDomainName(ie.Decl) == null) continue; + start.Add(ie.Decl); + } + for (int i = 0; i < callCmd.Proc.InParams.Count; i++) + { + IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr; + if (ie == null) continue; + Variable v = callCmd.Proc.InParams[i]; + if (FindDomainName(v) == null) continue; + if (FindLinearKind(v) == LinearKind.LINEAR_OUT) + { + start.Add(ie.Decl); + } + } + } + public void AddAvailableVars(ParCallCmd parCallCmd, HashSet start) + { + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + AddAvailableVars(callCmd, start); + } + } + private HashSet PropagateAvailableLinearVarsAcrossBlock(Block b) { + HashSet start = new HashSet(availableLinearVars[b]); + foreach (Cmd cmd in b.Cmds) + { + if (cmd is AssignCmd) + { + AssignCmd assignCmd = (AssignCmd)cmd; + for (int i = 0; i < assignCmd.Lhss.Count; i++) + { + if (FindDomainName(assignCmd.Lhss[i].DeepAssignedVariable) == null) continue; + IdentifierExpr ie = assignCmd.Rhss[i] as IdentifierExpr; + if (!start.Contains(ie.Decl)) + { + Error(ie, "unavailable source for a linear read"); + } + else + { + start.Remove(ie.Decl); + } + } + foreach (AssignLhs assignLhs in assignCmd.Lhss) + { + if (FindDomainName(assignLhs.DeepAssignedVariable) == null) continue; + start.Add(assignLhs.DeepAssignedVariable); + } + } + else if (cmd is CallCmd) + { + foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start)) + { + Error(cmd, string.Format("Global variable {0} must be available at a call", g.Name)); + } + CallCmd callCmd = (CallCmd)cmd; + for (int i = 0; i < callCmd.Proc.InParams.Count; i++) + { + Variable param = callCmd.Proc.InParams[i]; + if (FindDomainName(param) == null) continue; + IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr; + LinearKind paramKind = FindLinearKind(param); + if (start.Contains(ie.Decl)) + { + if (callCmd.IsAsync || paramKind == LinearKind.LINEAR_IN) + { + start.Remove(ie.Decl); + } + } + else + { + if (paramKind == LinearKind.LINEAR_OUT) + { + start.Add(ie.Decl); + } + else + { + Error(ie, "unavailable source for a linear read"); + } + } + } + availableLinearVars[callCmd] = new HashSet(start); + AddAvailableVars(callCmd, start); + } + else if (cmd is ParCallCmd) + { + foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start)) + { + Error(cmd, string.Format("Global variable {0} must be available at a call", g.Name)); + } + ParCallCmd parCallCmd = (ParCallCmd)cmd; + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + for (int i = 0; i < callCmd.Proc.InParams.Count; i++) + { + Variable param = callCmd.Proc.InParams[i]; + if (FindDomainName(param) == null) continue; + IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr; + LinearKind paramKind = FindLinearKind(param); + if (start.Contains(ie.Decl)) + { + if (paramKind == LinearKind.LINEAR_IN) + { + start.Remove(ie.Decl); + } + } + else + { + if (paramKind == LinearKind.LINEAR_OUT) + { + start.Add(ie.Decl); + } + else + { + Error(ie, "unavailable source for a linear read"); + } + } + } + } + availableLinearVars[parCallCmd] = new HashSet(start); + AddAvailableVars(parCallCmd, start); + } + else if (cmd is HavocCmd) + { + HavocCmd havocCmd = (HavocCmd)cmd; + foreach (IdentifierExpr ie in havocCmd.Vars) + { + if (FindDomainName(ie.Decl) == null) continue; + start.Remove(ie.Decl); + } + } + else if (cmd is YieldCmd) + { + foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start)) + { + Error(cmd, string.Format("Global variable {0} must be available at a yield", g.Name)); + } + availableLinearVars[cmd] = new HashSet(start); + } + } + return start; + } + public string FindDomainName(Variable v) + { + if (globalVarToDomainName.ContainsKey(v)) + return globalVarToDomainName[v]; + if (inParamToLinearQualifier.ContainsKey(v)) + return inParamToLinearQualifier[v].domainName; + if (outParamToDomainName.ContainsKey(v)) + return outParamToDomainName[v]; + string domainName = QKeyValue.FindStringAttribute(v.Attributes, "linear"); + if (domainName != null) + return domainName; + domainName = QKeyValue.FindStringAttribute(v.Attributes, "linear_in"); + if (domainName != null) + return domainName; + return QKeyValue.FindStringAttribute(v.Attributes, "linear_out"); + } + public LinearKind FindLinearKind(Variable v) + { + if (globalVarToDomainName.ContainsKey(v)) + return LinearKind.LINEAR; + if (inParamToLinearQualifier.ContainsKey(v)) + return inParamToLinearQualifier[v].kind; + if (outParamToDomainName.ContainsKey(v)) + return LinearKind.LINEAR; + + if (QKeyValue.FindStringAttribute(v.Attributes, "linear") != null) + { + return LinearKind.LINEAR; + } + else if (QKeyValue.FindStringAttribute(v.Attributes, "linear_in") != null) + { + return LinearKind.LINEAR_IN; + } + else if (QKeyValue.FindStringAttribute(v.Attributes, "linear_out") != null) + { + return LinearKind.LINEAR_OUT; + } + else + { + Debug.Assert(false); + return LinearKind.LINEAR; + } + } + public override Variable VisitVariable(Variable node) + { + string domainName = FindDomainName(node); + if (domainName != null) + { + if (!domainNameToCollectors.ContainsKey(domainName)) + { + domainNameToCollectors[domainName] = new Dictionary(); + } + LinearKind kind = FindLinearKind(node); + if (kind != LinearKind.LINEAR) + { + if (node is GlobalVariable || node is LocalVariable || (node is Formal && !(node as Formal).InComing)) + { + Error(node, "Variable must be declared linear (as opposed to linear_in or linear_out)"); + } + } + } + return base.VisitVariable(node); + } + public override Cmd VisitAssignCmd(AssignCmd node) + { + HashSet rhsVars = new HashSet(); + for (int i = 0; i < node.Lhss.Count; i++) + { + AssignLhs lhs = node.Lhss[i]; + Variable lhsVar = lhs.DeepAssignedVariable; + string domainName = FindDomainName(lhsVar); + if (domainName == null) continue; + SimpleAssignLhs salhs = lhs as SimpleAssignLhs; + if (salhs == null) + { + Error(node, string.Format("Only simple assignment allowed on linear variable {0}", lhsVar.Name)); + continue; + } + IdentifierExpr rhs = node.Rhss[i] as IdentifierExpr; + if (rhs == null) + { + Error(node, string.Format("Only variable can be assigned to linear variable {0}", lhsVar.Name)); + continue; + } + string rhsDomainName = FindDomainName(rhs.Decl); + if (rhsDomainName == null) + { + Error(node, string.Format("Only linear variable can be assigned to linear variable {0}", lhsVar.Name)); + continue; + } + if (domainName != rhsDomainName) + { + Error(node, string.Format("Linear variable of domain {0} cannot be assigned to linear variable of domain {1}", rhsDomainName, domainName)); + continue; + } + if (rhsVars.Contains(rhs.Decl)) + { + Error(node, string.Format("Linear variable {0} can occur only once in the right-hand-side of an assignment", rhs.Decl.Name)); + continue; + } + rhsVars.Add(rhs.Decl); + } + return base.VisitAssignCmd(node); + } + public override Cmd VisitCallCmd(CallCmd node) + { + HashSet inVars = new HashSet(); + for (int i = 0; i < node.Proc.InParams.Count; i++) + { + Variable formal = node.Proc.InParams[i]; + string domainName = FindDomainName(formal); + if (domainName == null) continue; + IdentifierExpr actual = node.Ins[i] as IdentifierExpr; + if (actual == null) + { + Error(node, string.Format("Only variable can be passed to linear parameter {0}", formal.Name)); + continue; + } + string actualDomainName = FindDomainName(actual.Decl); + if (actualDomainName == null) + { + Error(node, string.Format("Only a linear argument can be passed to linear parameter {0}", formal.Name)); + continue; + } + if (domainName != actualDomainName) + { + Error(node, "The domains of formal and actual parameters must be the same"); + continue; + } + if (actual.Decl is GlobalVariable) + { + Error(node, "Only local linear variable can be an actual input parameter of a procedure call"); + continue; + } + if (inVars.Contains(actual.Decl)) + { + Error(node, string.Format("Linear variable {0} can occur only once as an input parameter", actual.Decl.Name)); + continue; + } + inVars.Add(actual.Decl); + } + for (int i = 0; i < node.Proc.OutParams.Count; i++) + { + IdentifierExpr actual = node.Outs[i]; + string actualDomainName = FindDomainName(actual.Decl); + if (actualDomainName == null) continue; + Variable formal = node.Proc.OutParams[i]; + string domainName = FindDomainName(formal); + if (domainName == null) + { + Error(node, "Only a linear variable can be passed to a linear parameter"); + continue; + } + if (domainName != actualDomainName) + { + Error(node, "The domains of formal and actual parameters must be the same"); + continue; + } + if (actual.Decl is GlobalVariable) + { + Error(node, "Only local linear variable can be actual output parameter of a procedure call"); + continue; + } + } + return base.VisitCallCmd(node); + } + public override Cmd VisitParCallCmd(ParCallCmd node) + { + HashSet parallelCallInvars = new HashSet(); + foreach (CallCmd callCmd in node.CallCmds) + { + for (int i = 0; i < callCmd.Proc.InParams.Count; i++) + { + Variable formal = callCmd.Proc.InParams[i]; + string domainName = FindDomainName(formal); + if (domainName == null) continue; + IdentifierExpr actual = callCmd.Ins[i] as IdentifierExpr; + if (parallelCallInvars.Contains(actual.Decl)) + { + Error(node, string.Format("Linear variable {0} can occur only once as an input parameter of a parallel call", actual.Decl.Name)); + } + else + { + parallelCallInvars.Add(actual.Decl); + } + } + } + return base.VisitParCallCmd(node); + } + + public override Requires VisitRequires(Requires requires) + { + return requires; + } + + public override Ensures VisitEnsures(Ensures ensures) + { + return ensures; + } + + public IEnumerable AvailableLinearVars(Absy absy) + { + if (availableLinearVars.ContainsKey(absy)) + { + return availableLinearVars[absy]; + } + else + { + return new HashSet(); + } + } + + private void AddDisjointnessExpr(List newCmds, Absy absy, Dictionary domainNameToInputVar) + { + Dictionary> domainNameToScope = new Dictionary>(); + foreach (var domainName in linearDomains.Keys) + { + domainNameToScope[domainName] = new HashSet(); + } + foreach (Variable v in AvailableLinearVars(absy)) + { + var domainName = FindDomainName(v); + domainNameToScope[domainName].Add(v); + } + foreach (Variable v in globalVarToDomainName.Keys) + { + var domainName = FindDomainName(v); + domainNameToScope[domainName].Add(v); + } + foreach (string domainName in linearDomains.Keys) + { + newCmds.Add(new AssumeCmd(Token.NoToken, DisjointnessExpr(domainName, domainNameToInputVar[domainName], domainNameToScope[domainName]))); + } + } + + public void Transform() + { + foreach (var impl in program.Implementations) + { + Dictionary domainNameToInputVar = new Dictionary(); + foreach (string domainName in linearDomains.Keys) + { + var domain = linearDomains[domainName]; + Formal f = new Formal( + Token.NoToken, + new TypedIdent(Token.NoToken, + "linear_" + domainName + "_in", + new MapType(Token.NoToken, new List(), + new List { domain.elementType }, Type.Bool)), true); + impl.InParams.Add(f); + domainNameToInputVar[domainName] = f; + } + + foreach (Block b in impl.Blocks) + { + List newCmds = new List(); + for (int i = 0; i < b.Cmds.Count; i++) + { + Cmd cmd = b.Cmds[i]; + newCmds.Add(cmd); + if (cmd is CallCmd) + { + CallCmd callCmd = cmd as CallCmd; + if (callCmd.IsAsync) + { + foreach (var domainName in linearDomains.Keys) + { + var domain = linearDomains[domainName]; + var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstBool), new List { Expr.False }); + expr.Resolve(new ResolutionContext(null)); + expr.Typecheck(new TypecheckingContext(null)); + callCmd.Ins.Add(expr); + } + } + else + { + Dictionary domainNameToExpr = new Dictionary(); + foreach (var domainName in linearDomains.Keys) + { + domainNameToExpr[domainName] = Expr.Ident(domainNameToInputVar[domainName]); + } + foreach (Variable v in AvailableLinearVars(callCmd)) + { + var domainName = FindDomainName(v); + var domain = linearDomains[domainName]; + if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; + Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List { Expr.Ident(v) }); + var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapOrBool), new List { ie, domainNameToExpr[domainName] }); + expr.Resolve(new ResolutionContext(null)); + expr.Typecheck(new TypecheckingContext(null)); + domainNameToExpr[domainName] = expr; + } + foreach (var domainName in linearDomains.Keys) + { + callCmd.Ins.Add(domainNameToExpr[domainName]); + } + } + } + else if (cmd is ParCallCmd) + { + ParCallCmd parCallCmd = (ParCallCmd)cmd; + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + foreach (var domainName in linearDomains.Keys) + { + var domain = linearDomains[domainName]; + var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstBool), new List { Expr.False }); + expr.Resolve(new ResolutionContext(null)); + expr.Typecheck(new TypecheckingContext(null)); + callCmd.Ins.Add(expr); + } + } + } + else if (cmd is YieldCmd) + { + AddDisjointnessExpr(newCmds, cmd, domainNameToInputVar); + } + } + b.Cmds = newCmds; + } + + { + // Loops + impl.PruneUnreachableBlocks(); + impl.ComputePredecessorsForBlocks(); + GraphUtil.Graph g = Program.GraphFromImpl(impl); + g.ComputeLoops(); + if (g.Reducible) + { + foreach (Block header in g.Headers) + { + List newCmds = new List(); + AddDisjointnessExpr(newCmds, header, domainNameToInputVar); + newCmds.AddRange(header.Cmds); + header.Cmds = newCmds; + } + } + } + } + + foreach (var proc in program.Procedures) + { + Dictionary> domainNameToInputScope = new Dictionary>(); + Dictionary> domainNameToOutputScope = new Dictionary>(); + foreach (var domainName in linearDomains.Keys) + { + domainNameToInputScope[domainName] = new HashSet(); + domainNameToOutputScope[domainName] = new HashSet(); + + } + foreach (Variable v in globalVarToDomainName.Keys) + { + var domainName = globalVarToDomainName[v]; + domainNameToInputScope[domainName].Add(v); + domainNameToOutputScope[domainName].Add(v); + } + foreach (Variable v in proc.InParams) + { + var domainName = FindDomainName(v); + if (domainName == null) continue; + if (!this.linearDomains.ContainsKey(domainName)) continue; + domainNameToInputScope[domainName].Add(v); + } + foreach (Variable v in proc.OutParams) + { + var domainName = FindDomainName(v); + if (domainName == null) continue; + if (!this.linearDomains.ContainsKey(domainName)) continue; + domainNameToOutputScope[domainName].Add(v); + } + foreach (var domainName in linearDomains.Keys) + { + proc.Requires.Add(new Requires(true, DisjointnessExpr(domainName, domainNameToInputScope[domainName]))); + var domain = linearDomains[domainName]; + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List(), new List { domain.elementType }, Type.Bool)), true); + proc.InParams.Add(f); + proc.Ensures.Add(new Ensures(true, DisjointnessExpr(domainName, f, domainNameToOutputScope[domainName]))); + } + } + + foreach (LinearDomain domain in linearDomains.Values) + { + program.AddTopLevelDeclaration(domain.mapConstBool); + program.AddTopLevelDeclaration(domain.mapConstInt); + program.AddTopLevelDeclaration(domain.mapEqInt); + program.AddTopLevelDeclaration(domain.mapImpBool); + program.AddTopLevelDeclaration(domain.mapOrBool); + foreach (Axiom axiom in domain.axioms) + { + program.AddTopLevelDeclaration(axiom); + } + } + + //int oldPrintUnstructured = CommandLineOptions.Clo.PrintUnstructured; + //CommandLineOptions.Clo.PrintUnstructured = 1; + //PrintBplFile("lsd.bpl", program, false, false); + //CommandLineOptions.Clo.PrintUnstructured = oldPrintUnstructured; + } + + private Expr SubsetExpr(LinearDomain domain, Expr ie, Variable partition, int partitionCount) + { + Expr e = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstInt), new List { new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(partitionCount)) }); + e = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapEqInt), new List { Expr.Ident(partition), e }); + e = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapImpBool), new List { ie, e }); + e = Expr.Eq(e, new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstBool), new List { Expr.True })); + return e; + } + + private Expr SubsetExprs(LinearDomain domain, HashSet scope, Variable partition, int count, Expr expr) + { + foreach (Variable v in scope) + { + if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; + Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List { Expr.Ident(v) }); + expr = Expr.And(SubsetExpr(domain, ie, partition, count), expr); + count++; + } + expr = new ExistsExpr(Token.NoToken, new List { partition }, expr); + expr.Resolve(new ResolutionContext(null)); + expr.Typecheck(new TypecheckingContext(null)); + return expr; + } + + public Expr DisjointnessExpr(string domainName, Variable inputVar, HashSet scope) + { + LinearDomain domain = linearDomains[domainName]; + BoundVariable partition = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("partition_{0}", domainName), new MapType(Token.NoToken, new List(), new List { domain.elementType }, Microsoft.Boogie.Type.Int))); + return SubsetExprs(domain, scope, partition, 1, SubsetExpr(domain, Expr.Ident(inputVar), partition, 0)); + } + + public Expr DisjointnessExpr(string domainName, HashSet scope) + { + LinearDomain domain = linearDomains[domainName]; + BoundVariable partition = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("partition_{0}", domainName), new MapType(Token.NoToken, new List(), new List { domain.elementType }, Microsoft.Boogie.Type.Int))); + return SubsetExprs(domain, scope, partition, 0, Expr.True); + } + } + + public class LinearQualifier + { + public string domainName; + public LinearKind kind; + public LinearQualifier(string domainName, LinearKind kind) + { + this.domainName = domainName; + this.kind = kind; + } + } + + public class LinearDomain + { + public Function mapEqInt; + public Function mapConstInt; + public Function mapOrBool; + public Function mapImpBool; + public Function mapConstBool; + public List axioms; + public Type elementType; + public Dictionary collectors; + + public LinearDomain(Program program, string domainName, Dictionary collectors) + { + this.axioms = new List(); + this.collectors = collectors; + MapType setType = (MapType)collectors.First().Value.OutParams[0].TypedIdent.Type; + this.elementType = setType.Arguments[0]; + MapType mapTypeBool = new MapType(Token.NoToken, new List(), new List { this.elementType }, Type.Bool); + MapType mapTypeInt = new MapType(Token.NoToken, new List(), new List { this.elementType }, Type.Int); + this.mapOrBool = new Function(Token.NoToken, "linear_" + domainName + "_MapOr", + new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool), true), + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool), true) }, + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); + if (CommandLineOptions.Clo.UseArrayTheory) + { + this.mapOrBool.AddAttribute("builtin", "MapOr"); + } + else + { + BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool)); + IdentifierExpr aie = Expr.Ident(a); + BoundVariable b = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool)); + IdentifierExpr bie = Expr.Ident(b); + BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); + IdentifierExpr xie = Expr.Ident(x); + var mapApplTerm = new NAryExpr(Token.NoToken, new FunctionCall(mapOrBool), new List { aie, bie } ); + var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { mapApplTerm, xie } ); + var rhsTerm = Expr.Or(new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { aie, xie } ), + new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { bie, xie} )); + var axiomExpr = new ForallExpr(Token.NoToken, new List(), new List { a, b }, null, + new Trigger(Token.NoToken, true, new List { mapApplTerm }), + new ForallExpr(Token.NoToken, new List { x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, rhsTerm))); + axiomExpr.Typecheck(new TypecheckingContext(null)); + axioms.Add(new Axiom(Token.NoToken, axiomExpr)); + } + + this.mapImpBool = new Function(Token.NoToken, "linear_" + domainName + "_MapImp", + new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool), true), + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool), true) }, + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); + if (CommandLineOptions.Clo.UseArrayTheory) + { + this.mapImpBool.AddAttribute("builtin", "MapImp"); + } + else + { + BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool)); + IdentifierExpr aie = Expr.Ident(a); + BoundVariable b = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool)); + IdentifierExpr bie = Expr.Ident(b); + BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); + IdentifierExpr xie = Expr.Ident(x); + var mapApplTerm = new NAryExpr(Token.NoToken, new FunctionCall(mapImpBool), new List { aie, bie }); + var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { mapApplTerm, xie }); + var rhsTerm = Expr.Imp(new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { aie, xie }), + new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { bie, xie })); + var axiomExpr = new ForallExpr(Token.NoToken, new List(), new List { a, b }, null, + new Trigger(Token.NoToken, true, new List { mapApplTerm }), + new ForallExpr(Token.NoToken, new List { x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, rhsTerm))); + axiomExpr.Typecheck(new TypecheckingContext(null)); + axioms.Add(new Axiom(Token.NoToken, axiomExpr)); + } + + this.mapConstBool = new Function(Token.NoToken, "linear_" + domainName + "_MapConstBool", + new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", Type.Bool), true) }, + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); + if (CommandLineOptions.Clo.UseArrayTheory) + { + this.mapConstBool.AddAttribute("builtin", "MapConst"); + } + else + { + BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); + IdentifierExpr xie = Expr.Ident(x); + var trueTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), + new List { new NAryExpr(Token.NoToken, new FunctionCall(mapConstBool), new List { Expr.True }), xie }); + var trueAxiomExpr = new ForallExpr(Token.NoToken, new List { x }, trueTerm); + trueAxiomExpr.Typecheck(new TypecheckingContext(null)); + axioms.Add(new Axiom(Token.NoToken, trueAxiomExpr)); + var falseTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), + new List { new NAryExpr(Token.NoToken, new FunctionCall(mapConstBool), new List { Expr.False }), xie }); + var falseAxiomExpr = new ForallExpr(Token.NoToken, new List { x }, Expr.Unary(Token.NoToken, UnaryOperator.Opcode.Not, falseTerm)); + falseAxiomExpr.Typecheck(new TypecheckingContext(null)); + axioms.Add(new Axiom(Token.NoToken, falseAxiomExpr)); + } + + this.mapEqInt = new Function(Token.NoToken, "linear_" + domainName + "_MapEq", + new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeInt), true), + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeInt), true) }, + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); + if (CommandLineOptions.Clo.UseArrayTheory) + { + this.mapEqInt.AddAttribute("builtin", "MapEq"); + } + else + { + BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeInt)); + IdentifierExpr aie = Expr.Ident(a); + BoundVariable b = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeInt)); + IdentifierExpr bie = Expr.Ident(b); + BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); + IdentifierExpr xie = Expr.Ident(x); + var mapApplTerm = new NAryExpr(Token.NoToken, new FunctionCall(mapEqInt), new List { aie, bie }); + var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { mapApplTerm, xie }); + var rhsTerm = Expr.Eq(new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { aie, xie }), + new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { bie, xie })); + var axiomExpr = new ForallExpr(Token.NoToken, new List(), new List { a, b }, null, + new Trigger(Token.NoToken, true, new List { mapApplTerm }), + new ForallExpr(Token.NoToken, new List { x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, rhsTerm))); + axiomExpr.Typecheck(new TypecheckingContext(null)); + axioms.Add(new Axiom(Token.NoToken, axiomExpr)); + } + + this.mapConstInt = new Function(Token.NoToken, "linear_" + domainName + "_MapConstInt", + new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", Type.Int), true) }, + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeInt), false)); + if (CommandLineOptions.Clo.UseArrayTheory) + { + this.mapConstInt.AddAttribute("builtin", "MapConst"); + } + else + { + BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", Type.Int)); + IdentifierExpr aie = Expr.Ident(a); + BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); + IdentifierExpr xie = Expr.Ident(x); + var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { new NAryExpr(Token.NoToken, new FunctionCall(mapConstInt), new List { aie }), xie }); + var axiomExpr = new ForallExpr(Token.NoToken, new List { a, x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, aie)); + axiomExpr.Typecheck(new TypecheckingContext(null)); + axioms.Add(new Axiom(Token.NoToken, axiomExpr)); + } + + foreach (var axiom in axioms) + { + axiom.Expr.Resolve(new ResolutionContext(null)); + axiom.Expr.Typecheck(new TypecheckingContext(null)); + } + } + } +} diff --git a/Source/Concurrency/MoverCheck.cs b/Source/Concurrency/MoverCheck.cs index 971e7271..732bcaa4 100644 --- a/Source/Concurrency/MoverCheck.cs +++ b/Source/Concurrency/MoverCheck.cs @@ -1,649 +1,673 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Diagnostics.Contracts; -using System.Diagnostics; - -namespace Microsoft.Boogie -{ - public class MoverCheck - { - LinearTypeChecker linearTypeChecker; - MoverTypeChecker moverTypeChecker; - List decls; - HashSet> commutativityCheckerCache; - HashSet> gatePreservationCheckerCache; - HashSet> failurePreservationCheckerCache; - private MoverCheck(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker, List decls) - { - this.linearTypeChecker = linearTypeChecker; - this.moverTypeChecker = moverTypeChecker; - this.decls = decls; - this.commutativityCheckerCache = new HashSet>(); - this.gatePreservationCheckerCache = new HashSet>(); - this.failurePreservationCheckerCache = new HashSet>(); - } - - public static void AddCheckers(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker, List decls) - { - if (moverTypeChecker.procToActionInfo.Count == 0) - return; - - List sortedByCreatedLayerNum = new List(moverTypeChecker.procToActionInfo.Values.Where(x => x is AtomicActionInfo)); - sortedByCreatedLayerNum.Sort((x, y) => { return (x.createdAtLayerNum == y.createdAtLayerNum) ? 0 : (x.createdAtLayerNum < y.createdAtLayerNum) ? -1 : 1; }); - List sortedByAvailableUptoLayerNum = new List(moverTypeChecker.procToActionInfo.Values.Where(x => x is AtomicActionInfo)); - sortedByAvailableUptoLayerNum.Sort((x, y) => { return (x.availableUptoLayerNum == y.availableUptoLayerNum) ? 0 : (x.availableUptoLayerNum < y.availableUptoLayerNum) ? -1 : 1; }); - - Dictionary> pools = new Dictionary>(); - int indexIntoSortedByCreatedLayerNum = 0; - int indexIntoSortedByAvailableUptoLayerNum = 0; - HashSet currPool = new HashSet(); - while (indexIntoSortedByCreatedLayerNum < sortedByCreatedLayerNum.Count) - { - var currLayerNum = sortedByCreatedLayerNum[indexIntoSortedByCreatedLayerNum].createdAtLayerNum; - pools[currLayerNum] = new HashSet(currPool); - while (indexIntoSortedByCreatedLayerNum < sortedByCreatedLayerNum.Count) - { - var actionInfo = sortedByCreatedLayerNum[indexIntoSortedByCreatedLayerNum] as AtomicActionInfo; - if (actionInfo.createdAtLayerNum > currLayerNum) break; - pools[currLayerNum].Add(actionInfo); - indexIntoSortedByCreatedLayerNum++; - } - while (indexIntoSortedByAvailableUptoLayerNum < sortedByAvailableUptoLayerNum.Count) - { - var actionInfo = sortedByAvailableUptoLayerNum[indexIntoSortedByAvailableUptoLayerNum] as AtomicActionInfo; - if (actionInfo.availableUptoLayerNum > currLayerNum) break; - pools[currLayerNum].Remove(actionInfo); - indexIntoSortedByAvailableUptoLayerNum++; - } - currPool = pools[currLayerNum]; - } - - Program program = moverTypeChecker.program; - MoverCheck moverChecking = new MoverCheck(linearTypeChecker, moverTypeChecker, decls); - foreach (int layerNum in pools.Keys) - { - foreach (AtomicActionInfo first in pools[layerNum]) - { - Debug.Assert(first.moverType != MoverType.Top); - if (first.moverType == MoverType.Atomic) - continue; - foreach (AtomicActionInfo second in pools[layerNum]) - { - if (first.IsRightMover) - { - moverChecking.CreateCommutativityChecker(program, first, second); - moverChecking.CreateGatePreservationChecker(program, second, first); - } - if (first.IsLeftMover) - { - moverChecking.CreateCommutativityChecker(program, second, first); - moverChecking.CreateGatePreservationChecker(program, first, second); - moverChecking.CreateFailurePreservationChecker(program, second, first); - } - } - } - } - foreach (ActionInfo actionInfo in moverTypeChecker.procToActionInfo.Values) - { - AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; - if (atomicActionInfo != null && atomicActionInfo.IsLeftMover && atomicActionInfo.hasAssumeCmd) - { - moverChecking.CreateNonBlockingChecker(program, atomicActionInfo); - } - } - } - - public sealed class MyDuplicator : Duplicator - { - public override Expr VisitIdentifierExpr(IdentifierExpr node) - { - IdentifierExpr ret = (IdentifierExpr) base.VisitIdentifierExpr(node); - if (ret.Decl is GlobalVariable) - { - return new OldExpr(Token.NoToken, ret); - } - else - { - return ret; - } - } - } - - public class TransitionRelationComputation - { - private Program program; - private AtomicActionInfo first; // corresponds to that* - private AtomicActionInfo second; // corresponds to this* - private Stack cmdStack; - private List paths; - private HashSet frame; - private HashSet postExistVars; - - public TransitionRelationComputation(Program program, AtomicActionInfo second, HashSet frame, HashSet postExistVars) - { - this.postExistVars = postExistVars; - this.frame = frame; - TransitionRelationComputationHelper(program, null, second); - } - - public TransitionRelationComputation(Program program, AtomicActionInfo first, AtomicActionInfo second, HashSet frame, HashSet postExistVars) - { - this.postExistVars = postExistVars; - this.frame = frame; - TransitionRelationComputationHelper(program, first, second); - } - - private void TransitionRelationComputationHelper(Program program, AtomicActionInfo first, AtomicActionInfo second) - { - this.program = program; - this.first = first; - this.second = second; - this.cmdStack = new Stack(); - this.paths = new List(); - List havocVars = new List(); - this.second.thisOutParams.ForEach(v => havocVars.Add(Expr.Ident(v))); - this.second.thisAction.LocVars.ForEach(v => havocVars.Add(Expr.Ident(v))); - if (havocVars.Count > 0) - { - HavocCmd havocCmd = new HavocCmd(Token.NoToken, havocVars); - cmdStack.Push(havocCmd); - } - Search(this.second.thisAction.Blocks[0], false); - } - - private void Substitute(Dictionary map, ref List pathExprs, ref Dictionary varToExpr) - { - Substitution subst = Substituter.SubstitutionFromHashtable(map); - List oldPathExprs = pathExprs; - pathExprs = new List(); - foreach (Expr pathExpr in oldPathExprs) - { - pathExprs.Add(Substituter.Apply(subst, pathExpr)); - } - Dictionary oldVarToExpr = varToExpr; - varToExpr = new Dictionary(); - foreach (Variable v in oldVarToExpr.Keys) - { - varToExpr[v] = Substituter.Apply(subst, oldVarToExpr[v]); - } - } - - struct PathInfo - { - public HashSet existsVars; - public Dictionary varToExpr; - public List pathExprs; - - public PathInfo(HashSet existsVars, Dictionary varToExpr, List pathExprs) - { - this.existsVars = existsVars; - this.varToExpr = varToExpr; - this.pathExprs = pathExprs; - } - } - - private void FlattenAnd(Expr x, List xs) - { - NAryExpr naryExpr = x as NAryExpr; - if (naryExpr != null && naryExpr.Fun.FunctionName == "&&") - { - FlattenAnd(naryExpr.Args[0], xs); - FlattenAnd(naryExpr.Args[1], xs); - } - else - { - xs.Add(x); - } - } - - private void AddPath() - { - HashSet existsVars = new HashSet(); - Dictionary varToExpr = new Dictionary(); - foreach (Variable v in frame) - { - varToExpr[v] = Expr.Ident(v); - } - if (first != null) - { - foreach (Variable v in first.thatOutParams) - { - varToExpr[v] = Expr.Ident(v); - } - } - foreach (Variable v in second.thisOutParams) - { - varToExpr[v] = Expr.Ident(v); - } - List pathExprs = new List(); - int boundVariableCount = 0; - foreach (Cmd cmd in cmdStack) - { - if (cmd is AssumeCmd) - { - AssumeCmd assumeCmd = cmd as AssumeCmd; - FlattenAnd(assumeCmd.Expr, pathExprs); - } - else if (cmd is AssignCmd) - { - AssignCmd assignCmd = (cmd as AssignCmd).AsSimpleAssignCmd; - Dictionary map = new Dictionary(); - for (int k = 0; k < assignCmd.Lhss.Count; k++) - { - map[assignCmd.Lhss[k].DeepAssignedVariable] = assignCmd.Rhss[k]; - } - Substitute(map, ref pathExprs, ref varToExpr); - } - else if (cmd is HavocCmd) - { - HavocCmd havocCmd = cmd as HavocCmd; - Dictionary map = new Dictionary(); - foreach (IdentifierExpr ie in havocCmd.Vars) - { - BoundVariable bv = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "#tmp_" + boundVariableCount++, ie.Decl.TypedIdent.Type)); - map[ie.Decl] = Expr.Ident(bv); - existsVars.Add(bv); - } - Substitute(map, ref pathExprs, ref varToExpr); - } - else - { - Debug.Assert(false); - } - } - paths.Add(new PathInfo(existsVars, varToExpr, pathExprs)); - } - - private Expr CalculatePathCondition(PathInfo path) - { - Expr returnExpr = Expr.True; - - HashSet existsVars = path.existsVars; - Dictionary existsMap = new Dictionary(); - - Dictionary varToExpr = path.varToExpr; - foreach (Variable v in varToExpr.Keys) - { - if (postExistVars.Contains(v)) continue; - IdentifierExpr ie = varToExpr[v] as IdentifierExpr; - if (ie != null && !existsMap.ContainsKey(ie.Decl) && existsVars.Contains(ie.Decl)) - { - existsMap[ie.Decl] = Expr.Ident(v); - existsVars.Remove(ie.Decl); - } - else - { - returnExpr = Expr.And(returnExpr, Expr.Eq(Expr.Ident(v), (new MyDuplicator()).VisitExpr(varToExpr[v]))); - returnExpr.Type = Type.Bool; - } - } - - List pathExprs = new List(); - path.pathExprs.ForEach(x => pathExprs.Add((new MyDuplicator()).VisitExpr(x))); - foreach (Expr x in pathExprs) - { - Variable boundVar; - Expr boundVarExpr; - if (InferSubstitution(x, out boundVar, out boundVarExpr) && existsVars.Contains(boundVar)) - { - existsMap[boundVar] = boundVarExpr; - existsVars.Remove(boundVar); - } - else - { - returnExpr = Expr.And(returnExpr, x); - returnExpr.Type = Type.Bool; - } - } - - returnExpr = Substituter.Apply(Substituter.SubstitutionFromHashtable(existsMap), returnExpr); - if (existsVars.Count > 0) - { - returnExpr = new ExistsExpr(Token.NoToken, new List(existsVars), returnExpr); - } - return returnExpr; - } - - bool InferSubstitution(Expr x, out Variable var, out Expr expr) - { - var = null; - expr = null; - NAryExpr naryExpr = x as NAryExpr; - if (naryExpr == null || naryExpr.Fun.FunctionName != "==") - { - return false; - } - IdentifierExpr arg0 = naryExpr.Args[0] as IdentifierExpr; - if (arg0 != null && arg0.Decl is BoundVariable) - { - var = arg0.Decl; - expr = naryExpr.Args[1]; - return true; - } - IdentifierExpr arg1 = naryExpr.Args[1] as IdentifierExpr; - if (arg1 != null && arg1.Decl is BoundVariable) - { - var = arg1.Decl; - expr = naryExpr.Args[0]; - return true; - } - return false; - } - - public Expr TransitionRelationCompute() - { - Expr transitionRelation = Expr.False; - foreach (PathInfo path in paths) - { - transitionRelation = Expr.Or(transitionRelation, CalculatePathCondition(path)); - } - ResolutionContext rc = new ResolutionContext(null); - rc.StateMode = ResolutionContext.State.Two; - transitionRelation.Resolve(rc); - transitionRelation.Typecheck(new TypecheckingContext(null)); - return transitionRelation; - } - - private void Search(Block b, bool inFirst) - { - int pathSizeAtEntry = cmdStack.Count; - foreach (Cmd cmd in b.Cmds) - { - cmdStack.Push(cmd); - } - if (b.TransferCmd is ReturnCmd) - { - if (first == null || inFirst) - { - AddPath(); - } - else - { - List havocVars = new List(); - first.thatOutParams.ForEach(v => havocVars.Add(Expr.Ident(v))); - first.thatAction.LocVars.ForEach(v => havocVars.Add(Expr.Ident(v))); - if (havocVars.Count > 0) - { - HavocCmd havocCmd = new HavocCmd(Token.NoToken, havocVars); - cmdStack.Push(havocCmd); - } - Search(first.thatAction.Blocks[0], true); - } - } - else - { - GotoCmd gotoCmd = b.TransferCmd as GotoCmd; - foreach (Block target in gotoCmd.labelTargets) - { - Search(target, inFirst); - } - } - Debug.Assert(cmdStack.Count >= pathSizeAtEntry); - while (cmdStack.Count > pathSizeAtEntry) - { - cmdStack.Pop(); - } - } - } - - private static List CloneBlocks(List blocks) - { - Dictionary blockMap = new Dictionary(); - List otherBlocks = new List(); - foreach (Block block in blocks) - { - List otherCmds = new List(); - foreach (Cmd cmd in block.Cmds) - { - otherCmds.Add(cmd); - } - Block otherBlock = new Block(); - otherBlock.Cmds = otherCmds; - otherBlock.Label = block.Label; - otherBlocks.Add(otherBlock); - blockMap[block] = otherBlock; - } - foreach (Block block in blocks) - { - if (block.TransferCmd is ReturnCmd) continue; - List otherGotoCmdLabelTargets = new List(); - List otherGotoCmdLabelNames = new List(); - GotoCmd gotoCmd = block.TransferCmd as GotoCmd; - foreach (Block target in gotoCmd.labelTargets) - { - otherGotoCmdLabelTargets.Add(blockMap[target]); - otherGotoCmdLabelNames.Add(blockMap[target].Label); - } - blockMap[block].TransferCmd = new GotoCmd(block.TransferCmd.tok, otherGotoCmdLabelNames, otherGotoCmdLabelTargets); - } - return otherBlocks; - } - - private List DisjointnessRequires(Program program, AtomicActionInfo first, AtomicActionInfo second, HashSet frame) - { - List requires = new List(); - Dictionary> domainNameToScope = new Dictionary>(); - foreach (var domainName in linearTypeChecker.linearDomains.Keys) - { - domainNameToScope[domainName] = new HashSet(); - } - foreach (Variable v in frame) - { - var domainName = linearTypeChecker.FindDomainName(v); - if (domainName == null) continue; - if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; - domainNameToScope[domainName].Add(v); - } - if (first != null) - { - foreach (Variable v in first.thatInParams) - { - var domainName = linearTypeChecker.FindDomainName(v); - if (domainName == null) continue; - if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; - domainNameToScope[domainName].Add(v); - } - } - foreach (Variable v in second.thisInParams) - { - var domainName = linearTypeChecker.FindDomainName(v); - if (domainName == null) continue; - if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; - domainNameToScope[domainName].Add(v); - } - foreach (string domainName in domainNameToScope.Keys) - { - requires.Add(new Requires(false, linearTypeChecker.DisjointnessExpr(domainName, domainNameToScope[domainName]))); - } - return requires; - } - - private void CreateCommutativityChecker(Program program, AtomicActionInfo first, AtomicActionInfo second) - { - if (first == second && first.thatInParams.Count == 0 && first.thatOutParams.Count == 0) - return; - if (first.CommutesWith(second)) - return; - Tuple actionPair = new Tuple(first, second); - if (commutativityCheckerCache.Contains(actionPair)) - return; - commutativityCheckerCache.Add(actionPair); - - List inputs = new List(); - inputs.AddRange(first.thatInParams); - inputs.AddRange(second.thisInParams); - List outputs = new List(); - outputs.AddRange(first.thatOutParams); - outputs.AddRange(second.thisOutParams); - List locals = new List(); - locals.AddRange(first.thatAction.LocVars); - locals.AddRange(second.thisAction.LocVars); - List firstBlocks = CloneBlocks(first.thatAction.Blocks); - List secondBlocks = CloneBlocks(second.thisAction.Blocks); - foreach (Block b in firstBlocks) - { - if (b.TransferCmd is ReturnCmd) - { - List bs = new List(); - bs.Add(secondBlocks[0]); - List ls = new List(); - ls.Add(secondBlocks[0].Label); - b.TransferCmd = new GotoCmd(Token.NoToken, ls, bs); - } - } - List blocks = new List(); - blocks.AddRange(firstBlocks); - blocks.AddRange(secondBlocks); - HashSet frame = new HashSet(); - frame.UnionWith(first.gateUsedGlobalVars); - frame.UnionWith(first.actionUsedGlobalVars); - frame.UnionWith(second.gateUsedGlobalVars); - frame.UnionWith(second.actionUsedGlobalVars); - List requires = DisjointnessRequires(program, first, second, frame); - foreach (AssertCmd assertCmd in first.thatGate) - requires.Add(new Requires(false, assertCmd.Expr)); - foreach (AssertCmd assertCmd in second.thisGate) - requires.Add(new Requires(false, assertCmd.Expr)); - List ensures = new List(); - Expr transitionRelation = (new TransitionRelationComputation(program, first, second, frame, new HashSet())).TransitionRelationCompute(); - Ensures ensureCheck = new Ensures(false, transitionRelation); - ensureCheck.ErrorData = string.Format("Commutativity check between {0} and {1} failed", first.proc.Name, second.proc.Name); - ensures.Add(ensureCheck); - string checkerName = string.Format("CommutativityChecker_{0}_{1}", first.proc.Name, second.proc.Name); - List globalVars = new List(); - moverTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); - Procedure proc = new Procedure(Token.NoToken, checkerName, new List(), inputs, outputs, requires, globalVars, ensures); - Implementation impl = new Implementation(Token.NoToken, checkerName, new List(), inputs, outputs, locals, blocks); - impl.Proc = proc; - this.decls.Add(impl); - this.decls.Add(proc); - } - - private void CreateGatePreservationChecker(Program program, AtomicActionInfo first, AtomicActionInfo second) - { - if (first.gateUsedGlobalVars.Intersect(second.modifiedGlobalVars).Count() == 0) - return; - Tuple actionPair = new Tuple(first, second); - if (gatePreservationCheckerCache.Contains(actionPair)) - return; - gatePreservationCheckerCache.Add(actionPair); - - List inputs = new List(); - inputs.AddRange(first.thatInParams); - inputs.AddRange(second.thisInParams); - List outputs = new List(); - outputs.AddRange(first.thatOutParams); - outputs.AddRange(second.thisOutParams); - List locals = new List(); - locals.AddRange(second.thisAction.LocVars); - List secondBlocks = CloneBlocks(second.thisAction.Blocks); - HashSet frame = new HashSet(); - frame.UnionWith(first.gateUsedGlobalVars); - frame.UnionWith(second.gateUsedGlobalVars); - frame.UnionWith(second.actionUsedGlobalVars); - List requires = DisjointnessRequires(program, first, second, frame); - List ensures = new List(); - foreach (AssertCmd assertCmd in first.thatGate) - { - requires.Add(new Requires(false, assertCmd.Expr)); - Ensures ensureCheck = new Ensures(assertCmd.tok, false, assertCmd.Expr, null); - ensureCheck.ErrorData = string.Format("Gate not preserved by {0}", second.proc.Name); - ensures.Add(ensureCheck); - } - foreach (AssertCmd assertCmd in second.thisGate) - requires.Add(new Requires(false, assertCmd.Expr)); - string checkerName = string.Format("GatePreservationChecker_{0}_{1}", first.proc.Name, second.proc.Name); - List globalVars = new List(); - moverTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); - Procedure proc = new Procedure(Token.NoToken, checkerName, new List(), inputs, outputs, requires, globalVars, ensures); - Implementation impl = new Implementation(Token.NoToken, checkerName, new List(), inputs, outputs, locals, secondBlocks); - impl.Proc = proc; - this.decls.Add(impl); - this.decls.Add(proc); - } - - private void CreateFailurePreservationChecker(Program program, AtomicActionInfo first, AtomicActionInfo second) - { - if (first.gateUsedGlobalVars.Intersect(second.modifiedGlobalVars).Count() == 0) - return; - Tuple actionPair = new Tuple(first, second); - if (failurePreservationCheckerCache.Contains(actionPair)) - return; - failurePreservationCheckerCache.Add(actionPair); - - List inputs = new List(); - inputs.AddRange(first.thatInParams); - inputs.AddRange(second.thisInParams); - List outputs = new List(); - outputs.AddRange(first.thatOutParams); - outputs.AddRange(second.thisOutParams); - List locals = new List(); - locals.AddRange(second.thisAction.LocVars); - List secondBlocks = CloneBlocks(second.thisAction.Blocks); - HashSet frame = new HashSet(); - frame.UnionWith(first.gateUsedGlobalVars); - frame.UnionWith(second.gateUsedGlobalVars); - frame.UnionWith(second.actionUsedGlobalVars); - List requires = DisjointnessRequires(program, first, second, frame); - Expr gateExpr = Expr.True; - foreach (AssertCmd assertCmd in first.thatGate) - { - gateExpr = Expr.And(gateExpr, assertCmd.Expr); - gateExpr.Type = Type.Bool; - } - gateExpr = Expr.Not(gateExpr); - gateExpr.Type = Type.Bool; - requires.Add(new Requires(false, gateExpr)); - List ensures = new List(); - Ensures ensureCheck = new Ensures(false, gateExpr); - ensureCheck.ErrorData = string.Format("Gate failure of {0} not preserved by {1}", first.proc.Name, second.proc.Name); - ensures.Add(ensureCheck); - foreach (AssertCmd assertCmd in second.thisGate) - requires.Add(new Requires(false, assertCmd.Expr)); - string checkerName = string.Format("FailurePreservationChecker_{0}_{1}", first.proc.Name, second.proc.Name); - List globalVars = new List(); - moverTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); - Procedure proc = new Procedure(Token.NoToken, checkerName, new List(), inputs, outputs, requires, globalVars, ensures); - Implementation impl = new Implementation(Token.NoToken, checkerName, new List(), inputs, outputs, locals, secondBlocks); - impl.Proc = proc; - this.decls.Add(impl); - this.decls.Add(proc); - } - - private void CreateNonBlockingChecker(Program program, AtomicActionInfo second) - { - List inputs = new List(); - inputs.AddRange(second.thisInParams); - - HashSet frame = new HashSet(); - frame.UnionWith(second.gateUsedGlobalVars); - frame.UnionWith(second.actionUsedGlobalVars); - List requires = DisjointnessRequires(program, null, second, frame); - foreach (AssertCmd assertCmd in second.thisGate) - { - requires.Add(new Requires(false, assertCmd.Expr)); - } - HashSet postExistVars = new HashSet(); - postExistVars.UnionWith(frame); - postExistVars.UnionWith(second.thisOutParams); - Expr ensuresExpr = (new TransitionRelationComputation(program, second, frame, postExistVars)).TransitionRelationCompute(); - List ensures = new List(); - Ensures ensureCheck = new Ensures(false, ensuresExpr); - ensureCheck.ErrorData = string.Format("{0} is blocking", second.proc.Name); - ensures.Add(ensureCheck); - - List blocks = new List(); - blocks.Add(new Block(Token.NoToken, "L", new List(), new ReturnCmd(Token.NoToken))); - string checkerName = string.Format("NonBlockingChecker_{0}", second.proc.Name); - List globalVars = new List(); - moverTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); - Procedure proc = new Procedure(Token.NoToken, checkerName, new List(), inputs, new List(), requires, globalVars, ensures); - Implementation impl = new Implementation(Token.NoToken, checkerName, new List(), inputs, new List(), new List(), blocks); - impl.Proc = proc; - this.decls.Add(impl); - this.decls.Add(proc); - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Diagnostics.Contracts; +using System.Diagnostics; + +namespace Microsoft.Boogie +{ + public class MoverCheck + { + LinearTypeChecker linearTypeChecker; + CivlTypeChecker civlTypeChecker; + List decls; + HashSet> commutativityCheckerCache; + HashSet> gatePreservationCheckerCache; + HashSet> failurePreservationCheckerCache; + private MoverCheck(LinearTypeChecker linearTypeChecker, CivlTypeChecker civlTypeChecker, List decls) + { + this.linearTypeChecker = linearTypeChecker; + this.civlTypeChecker = civlTypeChecker; + this.decls = decls; + this.commutativityCheckerCache = new HashSet>(); + this.gatePreservationCheckerCache = new HashSet>(); + this.failurePreservationCheckerCache = new HashSet>(); + } + + public static void AddCheckers(LinearTypeChecker linearTypeChecker, CivlTypeChecker civlTypeChecker, List decls) + { + if (civlTypeChecker.procToActionInfo.Count == 0) + return; + + List sortedByCreatedLayerNum = new List(civlTypeChecker.procToActionInfo.Values.Where(x => x is AtomicActionInfo && !x.isExtern)); + sortedByCreatedLayerNum.Sort((x, y) => { return (x.createdAtLayerNum == y.createdAtLayerNum) ? 0 : (x.createdAtLayerNum < y.createdAtLayerNum) ? -1 : 1; }); + List sortedByAvailableUptoLayerNum = new List(civlTypeChecker.procToActionInfo.Values.Where(x => x is AtomicActionInfo && !x.isExtern)); + sortedByAvailableUptoLayerNum.Sort((x, y) => { return (x.availableUptoLayerNum == y.availableUptoLayerNum) ? 0 : (x.availableUptoLayerNum < y.availableUptoLayerNum) ? -1 : 1; }); + + Dictionary> pools = new Dictionary>(); + int indexIntoSortedByCreatedLayerNum = 0; + int indexIntoSortedByAvailableUptoLayerNum = 0; + HashSet currPool = new HashSet(); + while (indexIntoSortedByCreatedLayerNum < sortedByCreatedLayerNum.Count) + { + var currLayerNum = sortedByCreatedLayerNum[indexIntoSortedByCreatedLayerNum].createdAtLayerNum; + pools[currLayerNum] = new HashSet(currPool); + while (indexIntoSortedByCreatedLayerNum < sortedByCreatedLayerNum.Count) + { + var actionInfo = sortedByCreatedLayerNum[indexIntoSortedByCreatedLayerNum] as AtomicActionInfo; + if (actionInfo.createdAtLayerNum > currLayerNum) break; + pools[currLayerNum].Add(actionInfo); + indexIntoSortedByCreatedLayerNum++; + } + while (indexIntoSortedByAvailableUptoLayerNum < sortedByAvailableUptoLayerNum.Count) + { + var actionInfo = sortedByAvailableUptoLayerNum[indexIntoSortedByAvailableUptoLayerNum] as AtomicActionInfo; + if (actionInfo.availableUptoLayerNum > currLayerNum) break; + pools[currLayerNum].Remove(actionInfo); + indexIntoSortedByAvailableUptoLayerNum++; + } + currPool = pools[currLayerNum]; + } + + Program program = civlTypeChecker.program; + MoverCheck moverChecking = new MoverCheck(linearTypeChecker, civlTypeChecker, decls); + foreach (int layerNum in pools.Keys) + { + foreach (AtomicActionInfo first in pools[layerNum]) + { + Debug.Assert(first.moverType != MoverType.Top); + if (first.moverType == MoverType.Atomic) + continue; + foreach (AtomicActionInfo second in pools[layerNum]) + { + if (first.IsRightMover) + { + moverChecking.CreateCommutativityChecker(program, first, second); + moverChecking.CreateGatePreservationChecker(program, second, first); + } + if (first.IsLeftMover) + { + moverChecking.CreateCommutativityChecker(program, second, first); + moverChecking.CreateGatePreservationChecker(program, first, second); + moverChecking.CreateFailurePreservationChecker(program, second, first); + } + } + } + } + foreach (AtomicActionInfo atomicActionInfo in sortedByCreatedLayerNum) + { + if (atomicActionInfo.IsLeftMover && atomicActionInfo.hasAssumeCmd) + { + moverChecking.CreateNonBlockingChecker(program, atomicActionInfo); + } + } + } + + public sealed class MyDuplicator : Duplicator + { + public override Expr VisitIdentifierExpr(IdentifierExpr node) + { + IdentifierExpr ret = (IdentifierExpr) base.VisitIdentifierExpr(node); + if (ret.Decl is GlobalVariable) + { + return new OldExpr(Token.NoToken, ret); + } + else + { + return ret; + } + } + } + + public class TransitionRelationComputation + { + private Program program; + private AtomicActionInfo first; // corresponds to that* + private AtomicActionInfo second; // corresponds to this* + private Stack cmdStack; + private List paths; + private HashSet frame; + private HashSet postExistVars; + + public TransitionRelationComputation(Program program, AtomicActionInfo second, HashSet frame, HashSet postExistVars) + { + this.postExistVars = postExistVars; + this.frame = frame; + TransitionRelationComputationHelper(program, null, second); + } + + public TransitionRelationComputation(Program program, AtomicActionInfo first, AtomicActionInfo second, HashSet frame, HashSet postExistVars) + { + this.postExistVars = postExistVars; + this.frame = frame; + TransitionRelationComputationHelper(program, first, second); + } + + private void TransitionRelationComputationHelper(Program program, AtomicActionInfo first, AtomicActionInfo second) + { + this.program = program; + this.first = first; + this.second = second; + this.cmdStack = new Stack(); + this.paths = new List(); + List havocVars = new List(); + this.second.thisOutParams.ForEach(v => havocVars.Add(Expr.Ident(v))); + this.second.thisAction.LocVars.ForEach(v => havocVars.Add(Expr.Ident(v))); + if (havocVars.Count > 0) + { + HavocCmd havocCmd = new HavocCmd(Token.NoToken, havocVars); + cmdStack.Push(havocCmd); + } + Search(this.second.thisAction.Blocks[0], false); + } + + private void Substitute(Dictionary map, ref List pathExprs, ref Dictionary varToExpr) + { + Substitution subst = Substituter.SubstitutionFromHashtable(map); + List oldPathExprs = pathExprs; + pathExprs = new List(); + foreach (Expr pathExpr in oldPathExprs) + { + pathExprs.Add(Substituter.Apply(subst, pathExpr)); + } + Dictionary oldVarToExpr = varToExpr; + varToExpr = new Dictionary(); + foreach (Variable v in oldVarToExpr.Keys) + { + varToExpr[v] = Substituter.Apply(subst, oldVarToExpr[v]); + } + } + + struct PathInfo + { + public HashSet existsVars; + public Dictionary varToExpr; + public List pathExprs; + + public PathInfo(HashSet existsVars, Dictionary varToExpr, List pathExprs) + { + this.existsVars = existsVars; + this.varToExpr = varToExpr; + this.pathExprs = pathExprs; + } + } + + private void FlattenAnd(Expr x, List xs) + { + NAryExpr naryExpr = x as NAryExpr; + if (naryExpr != null && naryExpr.Fun.FunctionName == "&&") + { + FlattenAnd(naryExpr.Args[0], xs); + FlattenAnd(naryExpr.Args[1], xs); + } + else + { + xs.Add(x); + } + } + + private void AddPath() + { + HashSet existsVars = new HashSet(); + Dictionary varToExpr = new Dictionary(); + foreach (Variable v in frame) + { + varToExpr[v] = Expr.Ident(v); + } + if (first != null) + { + foreach (Variable v in first.thatOutParams) + { + varToExpr[v] = Expr.Ident(v); + } + } + foreach (Variable v in second.thisOutParams) + { + varToExpr[v] = Expr.Ident(v); + } + List pathExprs = new List(); + int boundVariableCount = 0; + foreach (Cmd cmd in cmdStack) + { + if (cmd is AssumeCmd) + { + AssumeCmd assumeCmd = cmd as AssumeCmd; + FlattenAnd(assumeCmd.Expr, pathExprs); + } + else if (cmd is AssignCmd) + { + AssignCmd assignCmd = (cmd as AssignCmd).AsSimpleAssignCmd; + Dictionary map = new Dictionary(); + for (int k = 0; k < assignCmd.Lhss.Count; k++) + { + map[assignCmd.Lhss[k].DeepAssignedVariable] = assignCmd.Rhss[k]; + } + Substitute(map, ref pathExprs, ref varToExpr); + } + else if (cmd is HavocCmd) + { + HavocCmd havocCmd = cmd as HavocCmd; + Dictionary map = new Dictionary(); + foreach (IdentifierExpr ie in havocCmd.Vars) + { + BoundVariable bv = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "#tmp_" + boundVariableCount++, ie.Decl.TypedIdent.Type)); + map[ie.Decl] = Expr.Ident(bv); + existsVars.Add(bv); + } + Substitute(map, ref pathExprs, ref varToExpr); + } + else + { + Debug.Assert(false); + } + } + paths.Add(new PathInfo(existsVars, varToExpr, pathExprs)); + } + + private Expr CalculatePathCondition(PathInfo path) + { + Expr returnExpr = Expr.True; + + HashSet existsVars = path.existsVars; + Dictionary existsMap = new Dictionary(); + + Dictionary varToExpr = path.varToExpr; + foreach (Variable v in varToExpr.Keys) + { + if (postExistVars.Contains(v)) continue; + IdentifierExpr ie = varToExpr[v] as IdentifierExpr; + if (ie != null && !existsMap.ContainsKey(ie.Decl) && existsVars.Contains(ie.Decl)) + { + existsMap[ie.Decl] = Expr.Ident(v); + existsVars.Remove(ie.Decl); + } + else + { + returnExpr = Expr.And(returnExpr, Expr.Eq(Expr.Ident(v), (new MyDuplicator()).VisitExpr(varToExpr[v]))); + returnExpr.Type = Type.Bool; + } + } + + List pathExprs = new List(); + path.pathExprs.ForEach(x => pathExprs.Add((new MyDuplicator()).VisitExpr(x))); + foreach (Expr x in pathExprs) + { + Variable boundVar; + Expr boundVarExpr; + if (InferSubstitution(x, out boundVar, out boundVarExpr) && existsVars.Contains(boundVar)) + { + existsMap[boundVar] = boundVarExpr; + existsVars.Remove(boundVar); + } + else + { + returnExpr = Expr.And(returnExpr, x); + returnExpr.Type = Type.Bool; + } + } + + returnExpr = Substituter.Apply(Substituter.SubstitutionFromHashtable(existsMap), returnExpr); + if (existsVars.Count > 0) + { + returnExpr = new ExistsExpr(Token.NoToken, new List(existsVars), returnExpr); + } + return returnExpr; + } + + bool InferSubstitution(Expr x, out Variable var, out Expr expr) + { + var = null; + expr = null; + NAryExpr naryExpr = x as NAryExpr; + if (naryExpr == null || naryExpr.Fun.FunctionName != "==") + { + return false; + } + IdentifierExpr arg0 = naryExpr.Args[0] as IdentifierExpr; + if (arg0 != null && arg0.Decl is BoundVariable) + { + var = arg0.Decl; + expr = naryExpr.Args[1]; + return true; + } + IdentifierExpr arg1 = naryExpr.Args[1] as IdentifierExpr; + if (arg1 != null && arg1.Decl is BoundVariable) + { + var = arg1.Decl; + expr = naryExpr.Args[0]; + return true; + } + return false; + } + + public Expr TransitionRelationCompute(bool withOriginalInOutVariables = false) + { + Expr transitionRelation = Expr.False; + foreach (PathInfo path in paths) + { + transitionRelation = Expr.Or(transitionRelation, CalculatePathCondition(path)); + } + ResolutionContext rc = new ResolutionContext(null); + rc.StateMode = ResolutionContext.State.Two; + transitionRelation.Resolve(rc); + transitionRelation.Typecheck(new TypecheckingContext(null)); + + if (withOriginalInOutVariables) + { + Dictionary invertedMap = new Dictionary(); + if (first != null) + { + foreach (var x in first.thatMap) + { + invertedMap[((IdentifierExpr)x.Value).Decl] = Expr.Ident(x.Key); + } + } + if (second != null) + { + foreach (var x in second.thisMap) + { + invertedMap[((IdentifierExpr)x.Value).Decl] = Expr.Ident(x.Key); + } + } + Substitution subst = Substituter.SubstitutionFromHashtable(invertedMap); + return Substituter.Apply(subst, transitionRelation); + } + else + { + return transitionRelation; + } + + } + + private void Search(Block b, bool inFirst) + { + int pathSizeAtEntry = cmdStack.Count; + foreach (Cmd cmd in b.Cmds) + { + cmdStack.Push(cmd); + } + if (b.TransferCmd is ReturnCmd) + { + if (first == null || inFirst) + { + AddPath(); + } + else + { + List havocVars = new List(); + first.thatOutParams.ForEach(v => havocVars.Add(Expr.Ident(v))); + first.thatAction.LocVars.ForEach(v => havocVars.Add(Expr.Ident(v))); + if (havocVars.Count > 0) + { + HavocCmd havocCmd = new HavocCmd(Token.NoToken, havocVars); + cmdStack.Push(havocCmd); + } + Search(first.thatAction.Blocks[0], true); + } + } + else + { + GotoCmd gotoCmd = b.TransferCmd as GotoCmd; + foreach (Block target in gotoCmd.labelTargets) + { + Search(target, inFirst); + } + } + Debug.Assert(cmdStack.Count >= pathSizeAtEntry); + while (cmdStack.Count > pathSizeAtEntry) + { + cmdStack.Pop(); + } + } + } + + private static List CloneBlocks(List blocks) + { + Dictionary blockMap = new Dictionary(); + List otherBlocks = new List(); + foreach (Block block in blocks) + { + List otherCmds = new List(); + foreach (Cmd cmd in block.Cmds) + { + otherCmds.Add(cmd); + } + Block otherBlock = new Block(); + otherBlock.Cmds = otherCmds; + otherBlock.Label = block.Label; + otherBlocks.Add(otherBlock); + blockMap[block] = otherBlock; + } + foreach (Block block in blocks) + { + if (block.TransferCmd is ReturnCmd) continue; + List otherGotoCmdLabelTargets = new List(); + List otherGotoCmdLabelNames = new List(); + GotoCmd gotoCmd = block.TransferCmd as GotoCmd; + foreach (Block target in gotoCmd.labelTargets) + { + otherGotoCmdLabelTargets.Add(blockMap[target]); + otherGotoCmdLabelNames.Add(blockMap[target].Label); + } + blockMap[block].TransferCmd = new GotoCmd(block.TransferCmd.tok, otherGotoCmdLabelNames, otherGotoCmdLabelTargets); + } + return otherBlocks; + } + + private List DisjointnessRequires(Program program, AtomicActionInfo first, AtomicActionInfo second, HashSet frame) + { + List requires = new List(); + Dictionary> domainNameToScope = new Dictionary>(); + foreach (var domainName in linearTypeChecker.linearDomains.Keys) + { + domainNameToScope[domainName] = new HashSet(); + } + foreach (Variable v in frame) + { + var domainName = linearTypeChecker.FindDomainName(v); + if (domainName == null) continue; + if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; + domainNameToScope[domainName].Add(v); + } + if (first != null) + { + foreach (Variable v in first.thatInParams) + { + var domainName = linearTypeChecker.FindDomainName(v); + if (domainName == null) continue; + if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; + domainNameToScope[domainName].Add(v); + } + } + foreach (Variable v in second.thisInParams) + { + var domainName = linearTypeChecker.FindDomainName(v); + if (domainName == null) continue; + if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; + domainNameToScope[domainName].Add(v); + } + foreach (string domainName in domainNameToScope.Keys) + { + requires.Add(new Requires(false, linearTypeChecker.DisjointnessExpr(domainName, domainNameToScope[domainName]))); + } + return requires; + } + + private void CreateCommutativityChecker(Program program, AtomicActionInfo first, AtomicActionInfo second) + { + if (first == second && first.thatInParams.Count == 0 && first.thatOutParams.Count == 0) + return; + if (first.CommutesWith(second)) + return; + Tuple actionPair = new Tuple(first, second); + if (commutativityCheckerCache.Contains(actionPair)) + return; + commutativityCheckerCache.Add(actionPair); + + List inputs = new List(); + inputs.AddRange(first.thatInParams); + inputs.AddRange(second.thisInParams); + List outputs = new List(); + outputs.AddRange(first.thatOutParams); + outputs.AddRange(second.thisOutParams); + List locals = new List(); + locals.AddRange(first.thatAction.LocVars); + locals.AddRange(second.thisAction.LocVars); + List firstBlocks = CloneBlocks(first.thatAction.Blocks); + List secondBlocks = CloneBlocks(second.thisAction.Blocks); + foreach (Block b in firstBlocks) + { + if (b.TransferCmd is ReturnCmd) + { + List bs = new List(); + bs.Add(secondBlocks[0]); + List ls = new List(); + ls.Add(secondBlocks[0].Label); + b.TransferCmd = new GotoCmd(Token.NoToken, ls, bs); + } + } + List blocks = new List(); + blocks.AddRange(firstBlocks); + blocks.AddRange(secondBlocks); + HashSet frame = new HashSet(); + frame.UnionWith(first.gateUsedGlobalVars); + frame.UnionWith(first.actionUsedGlobalVars); + frame.UnionWith(second.gateUsedGlobalVars); + frame.UnionWith(second.actionUsedGlobalVars); + List requires = DisjointnessRequires(program, first, second, frame); + foreach (AssertCmd assertCmd in first.thatGate) + requires.Add(new Requires(false, assertCmd.Expr)); + foreach (AssertCmd assertCmd in second.thisGate) + requires.Add(new Requires(false, assertCmd.Expr)); + List ensures = new List(); + Expr transitionRelation = (new TransitionRelationComputation(program, first, second, frame, new HashSet())).TransitionRelationCompute(); + Ensures ensureCheck = new Ensures(false, transitionRelation); + ensureCheck.ErrorData = string.Format("Commutativity check between {0} and {1} failed", first.proc.Name, second.proc.Name); + ensures.Add(ensureCheck); + string checkerName = string.Format("CommutativityChecker_{0}_{1}", first.proc.Name, second.proc.Name); + List globalVars = new List(); + civlTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); + Procedure proc = new Procedure(Token.NoToken, checkerName, new List(), inputs, outputs, requires, globalVars, ensures); + Implementation impl = new Implementation(Token.NoToken, checkerName, new List(), inputs, outputs, locals, blocks); + impl.Proc = proc; + this.decls.Add(impl); + this.decls.Add(proc); + } + + private void CreateGatePreservationChecker(Program program, AtomicActionInfo first, AtomicActionInfo second) + { + if (first.gateUsedGlobalVars.Intersect(second.modifiedGlobalVars).Count() == 0) + return; + Tuple actionPair = new Tuple(first, second); + if (gatePreservationCheckerCache.Contains(actionPair)) + return; + gatePreservationCheckerCache.Add(actionPair); + + List inputs = new List(); + inputs.AddRange(first.thatInParams); + inputs.AddRange(second.thisInParams); + List outputs = new List(); + outputs.AddRange(first.thatOutParams); + outputs.AddRange(second.thisOutParams); + List locals = new List(); + locals.AddRange(second.thisAction.LocVars); + List secondBlocks = CloneBlocks(second.thisAction.Blocks); + HashSet frame = new HashSet(); + frame.UnionWith(first.gateUsedGlobalVars); + frame.UnionWith(second.gateUsedGlobalVars); + frame.UnionWith(second.actionUsedGlobalVars); + List requires = DisjointnessRequires(program, first, second, frame); + List ensures = new List(); + foreach (AssertCmd assertCmd in first.thatGate) + { + requires.Add(new Requires(false, assertCmd.Expr)); + Ensures ensureCheck = new Ensures(assertCmd.tok, false, assertCmd.Expr, null); + ensureCheck.ErrorData = string.Format("Gate not preserved by {0}", second.proc.Name); + ensures.Add(ensureCheck); + } + foreach (AssertCmd assertCmd in second.thisGate) + requires.Add(new Requires(false, assertCmd.Expr)); + string checkerName = string.Format("GatePreservationChecker_{0}_{1}", first.proc.Name, second.proc.Name); + List globalVars = new List(); + civlTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); + Procedure proc = new Procedure(Token.NoToken, checkerName, new List(), inputs, outputs, requires, globalVars, ensures); + Implementation impl = new Implementation(Token.NoToken, checkerName, new List(), inputs, outputs, locals, secondBlocks); + impl.Proc = proc; + this.decls.Add(impl); + this.decls.Add(proc); + } + + private void CreateFailurePreservationChecker(Program program, AtomicActionInfo first, AtomicActionInfo second) + { + if (first.gateUsedGlobalVars.Intersect(second.modifiedGlobalVars).Count() == 0) + return; + Tuple actionPair = new Tuple(first, second); + if (failurePreservationCheckerCache.Contains(actionPair)) + return; + failurePreservationCheckerCache.Add(actionPair); + + List inputs = new List(); + inputs.AddRange(first.thatInParams); + inputs.AddRange(second.thisInParams); + List outputs = new List(); + outputs.AddRange(first.thatOutParams); + outputs.AddRange(second.thisOutParams); + List locals = new List(); + locals.AddRange(second.thisAction.LocVars); + List secondBlocks = CloneBlocks(second.thisAction.Blocks); + HashSet frame = new HashSet(); + frame.UnionWith(first.gateUsedGlobalVars); + frame.UnionWith(second.gateUsedGlobalVars); + frame.UnionWith(second.actionUsedGlobalVars); + List requires = DisjointnessRequires(program, first, second, frame); + Expr gateExpr = Expr.True; + foreach (AssertCmd assertCmd in first.thatGate) + { + gateExpr = Expr.And(gateExpr, assertCmd.Expr); + gateExpr.Type = Type.Bool; + } + gateExpr = Expr.Not(gateExpr); + gateExpr.Type = Type.Bool; + requires.Add(new Requires(false, gateExpr)); + List ensures = new List(); + Ensures ensureCheck = new Ensures(false, gateExpr); + ensureCheck.ErrorData = string.Format("Gate failure of {0} not preserved by {1}", first.proc.Name, second.proc.Name); + ensures.Add(ensureCheck); + foreach (AssertCmd assertCmd in second.thisGate) + requires.Add(new Requires(false, assertCmd.Expr)); + string checkerName = string.Format("FailurePreservationChecker_{0}_{1}", first.proc.Name, second.proc.Name); + List globalVars = new List(); + civlTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); + Procedure proc = new Procedure(Token.NoToken, checkerName, new List(), inputs, outputs, requires, globalVars, ensures); + Implementation impl = new Implementation(Token.NoToken, checkerName, new List(), inputs, outputs, locals, secondBlocks); + impl.Proc = proc; + this.decls.Add(impl); + this.decls.Add(proc); + } + + private void CreateNonBlockingChecker(Program program, AtomicActionInfo second) + { + List inputs = new List(); + inputs.AddRange(second.thisInParams); + + HashSet frame = new HashSet(); + frame.UnionWith(second.gateUsedGlobalVars); + frame.UnionWith(second.actionUsedGlobalVars); + List requires = DisjointnessRequires(program, null, second, frame); + foreach (AssertCmd assertCmd in second.thisGate) + { + requires.Add(new Requires(false, assertCmd.Expr)); + } + HashSet postExistVars = new HashSet(); + postExistVars.UnionWith(frame); + postExistVars.UnionWith(second.thisOutParams); + Expr ensuresExpr = (new TransitionRelationComputation(program, second, frame, postExistVars)).TransitionRelationCompute(); + List ensures = new List(); + Ensures ensureCheck = new Ensures(false, ensuresExpr); + ensureCheck.ErrorData = string.Format("{0} is blocking", second.proc.Name); + ensures.Add(ensureCheck); + + List blocks = new List(); + blocks.Add(new Block(Token.NoToken, "L", new List(), new ReturnCmd(Token.NoToken))); + string checkerName = string.Format("NonBlockingChecker_{0}", second.proc.Name); + List globalVars = new List(); + civlTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); + Procedure proc = new Procedure(Token.NoToken, checkerName, new List(), inputs, new List(), requires, globalVars, ensures); + Implementation impl = new Implementation(Token.NoToken, checkerName, new List(), inputs, new List(), new List(), blocks); + impl.Proc = proc; + this.decls.Add(impl); + this.decls.Add(proc); + } + } } \ No newline at end of file diff --git a/Source/Concurrency/OwickiGries.cs b/Source/Concurrency/OwickiGries.cs deleted file mode 100644 index dbd1dcbd..00000000 --- a/Source/Concurrency/OwickiGries.cs +++ /dev/null @@ -1,1188 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Boogie; -using System.Diagnostics; -using System.Diagnostics.Contracts; -using Microsoft.Boogie.GraphUtil; - -namespace Microsoft.Boogie -{ - public class MyDuplicator : Duplicator - { - MoverTypeChecker moverTypeChecker; - public int layerNum; - Procedure enclosingProc; - Implementation enclosingImpl; - public Dictionary procMap; /* Original -> Duplicate */ - public Dictionary absyMap; /* Duplicate -> Original */ - public Dictionary implMap; /* Duplicate -> Original */ - public HashSet yieldingProcs; - public List impls; - - public MyDuplicator(MoverTypeChecker moverTypeChecker, int layerNum) - { - this.moverTypeChecker = moverTypeChecker; - this.layerNum = layerNum; - this.enclosingProc = null; - this.enclosingImpl = null; - this.procMap = new Dictionary(); - this.absyMap = new Dictionary(); - this.implMap = new Dictionary(); - this.yieldingProcs = new HashSet(); - this.impls = new List(); - } - - private void ProcessCallCmd(CallCmd originalCallCmd, CallCmd callCmd, List newCmds) - { - int enclosingProcLayerNum = moverTypeChecker.procToActionInfo[enclosingImpl.Proc].createdAtLayerNum; - Procedure originalProc = originalCallCmd.Proc; - if (moverTypeChecker.procToActionInfo.ContainsKey(originalProc)) - { - AtomicActionInfo atomicActionInfo = moverTypeChecker.procToActionInfo[originalProc] as AtomicActionInfo; - if (atomicActionInfo != null && atomicActionInfo.thisGate.Count > 0 && layerNum == enclosingProcLayerNum) - { - newCmds.Add(new HavocCmd(Token.NoToken, new List(new IdentifierExpr[] { Expr.Ident(dummyLocalVar) }))); - Dictionary map = new Dictionary(); - for (int i = 0; i < originalProc.InParams.Count; i++) - { - map[originalProc.InParams[i]] = callCmd.Ins[i]; - } - Substitution subst = Substituter.SubstitutionFromHashtable(map); - foreach (AssertCmd assertCmd in atomicActionInfo.thisGate) - { - newCmds.Add(Substituter.Apply(subst, assertCmd)); - } - } - } - newCmds.Add(callCmd); - } - - private void ProcessParCallCmd(ParCallCmd originalParCallCmd, ParCallCmd parCallCmd, List newCmds) - { - int maxCalleeLayerNum = 0; - foreach (CallCmd iter in originalParCallCmd.CallCmds) - { - int calleeLayerNum = moverTypeChecker.procToActionInfo[iter.Proc].createdAtLayerNum; - if (calleeLayerNum > maxCalleeLayerNum) - maxCalleeLayerNum = calleeLayerNum; - } - if (layerNum > maxCalleeLayerNum) - { - for (int i = 0; i < parCallCmd.CallCmds.Count; i++) - { - ProcessCallCmd(originalParCallCmd.CallCmds[i], parCallCmd.CallCmds[i], newCmds); - absyMap[parCallCmd.CallCmds[i]] = originalParCallCmd; - } - } - else - { - newCmds.Add(parCallCmd); - } - } - - public override List VisitCmdSeq(List cmdSeq) - { - List cmds = base.VisitCmdSeq(cmdSeq); - List newCmds = new List(); - for (int i = 0; i < cmds.Count; i++) - { - Cmd originalCmd = cmdSeq[i]; - Cmd cmd = cmds[i]; - - CallCmd originalCallCmd = originalCmd as CallCmd; - if (originalCallCmd != null) - { - ProcessCallCmd(originalCallCmd, cmd as CallCmd, newCmds); - continue; - } - - ParCallCmd originalParCallCmd = originalCmd as ParCallCmd; - if (originalParCallCmd != null) - { - ProcessParCallCmd(originalParCallCmd, cmd as ParCallCmd, newCmds); - continue; - } - - newCmds.Add(cmd); - } - return newCmds; - } - - public override YieldCmd VisitYieldCmd(YieldCmd node) - { - YieldCmd yieldCmd = base.VisitYieldCmd(node); - absyMap[yieldCmd] = node; - return yieldCmd; - } - - public override Block VisitBlock(Block node) - { - Block block = base.VisitBlock(node); - absyMap[block] = node; - return block; - } - - public override Cmd VisitCallCmd(CallCmd node) - { - CallCmd callCmd = (CallCmd) base.VisitCallCmd(node); - callCmd.Proc = VisitProcedure(callCmd.Proc); - callCmd.callee = callCmd.Proc.Name; - absyMap[callCmd] = node; - return callCmd; - } - - public override Cmd VisitParCallCmd(ParCallCmd node) - { - ParCallCmd parCallCmd = (ParCallCmd) base.VisitParCallCmd(node); - absyMap[parCallCmd] = node; - return parCallCmd; - } - - public override Procedure VisitProcedure(Procedure node) - { - if (!moverTypeChecker.procToActionInfo.ContainsKey(node)) - return node; - if (!procMap.ContainsKey(node)) - { - enclosingProc = node; - Procedure proc = (Procedure)node.Clone(); - proc.Name = string.Format("{0}_{1}", node.Name, layerNum); - proc.InParams = this.VisitVariableSeq(node.InParams); - proc.Modifies = this.VisitIdentifierExprSeq(node.Modifies); - proc.OutParams = this.VisitVariableSeq(node.OutParams); - - ActionInfo actionInfo = moverTypeChecker.procToActionInfo[node]; - if (actionInfo.createdAtLayerNum < layerNum) - { - proc.Requires = new List(); - proc.Ensures = new List(); - Implementation impl; - AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; - if (atomicActionInfo != null) - { - CodeExpr action = (CodeExpr)VisitCodeExpr(atomicActionInfo.thisAction); - List cmds = new List(); - foreach (AssertCmd assertCmd in atomicActionInfo.thisGate) - { - cmds.Add(new AssumeCmd(Token.NoToken, (Expr)Visit(assertCmd.Expr))); - } - Block newInitBlock = new Block(Token.NoToken, "_init", cmds, - new GotoCmd(Token.NoToken, new List(new string[] { action.Blocks[0].Label }), - new List(new Block[] { action.Blocks[0] }))); - List newBlocks = new List(); - newBlocks.Add(newInitBlock); - newBlocks.AddRange(action.Blocks); - impl = new Implementation(Token.NoToken, proc.Name, node.TypeParameters, node.InParams, node.OutParams, action.LocVars, newBlocks); - } - else - { - Block newInitBlock = new Block(Token.NoToken, "_init", new List(), new ReturnCmd(Token.NoToken)); - List newBlocks = new List(); - newBlocks.Add(newInitBlock); - impl = new Implementation(Token.NoToken, proc.Name, node.TypeParameters, node.InParams, node.OutParams, new List(), newBlocks); - } - impl.Proc = proc; - impl.Proc.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); - impl.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); - impls.Add(impl); - } - else - { - yieldingProcs.Add(proc); - proc.Requires = this.VisitRequiresSeq(node.Requires); - proc.Ensures = this.VisitEnsuresSeq(node.Ensures); - } - procMap[node] = proc; - proc.Modifies = new List(); - moverTypeChecker.SharedVariables.Iter(x => proc.Modifies.Add(Expr.Ident(x))); - } - return procMap[node]; - } - - private Variable dummyLocalVar; - public override Implementation VisitImplementation(Implementation node) - { - enclosingImpl = node; - dummyLocalVar = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "og_dummy", Type.Bool)); - Implementation impl = base.VisitImplementation(node); - implMap[impl] = node; - impl.LocVars.Add(dummyLocalVar); - impl.Name = impl.Proc.Name; - return impl; - } - - public override Requires VisitRequires(Requires node) - { - Requires requires = base.VisitRequires(node); - if (node.Free) - return requires; - if (!moverTypeChecker.absyToLayerNums[node].Contains(layerNum)) - requires.Condition = Expr.True; - return requires; - } - - public override Ensures VisitEnsures(Ensures node) - { - Ensures ensures = base.VisitEnsures(node); - if (node.Free) - return ensures; - AtomicActionInfo atomicActionInfo = moverTypeChecker.procToActionInfo[enclosingProc] as AtomicActionInfo; - bool isAtomicSpecification = atomicActionInfo != null && atomicActionInfo.ensures == node; - if (isAtomicSpecification || !moverTypeChecker.absyToLayerNums[node].Contains(layerNum)) - { - ensures.Condition = Expr.True; - ensures.Attributes = OwickiGries.RemoveMoverAttribute(ensures.Attributes); - } - return ensures; - } - - public override Cmd VisitAssertCmd(AssertCmd node) - { - AssertCmd assertCmd = (AssertCmd) base.VisitAssertCmd(node); - if (!moverTypeChecker.absyToLayerNums[node].Contains(layerNum)) - assertCmd.Expr = Expr.True; - return assertCmd; - } - } - - public class OwickiGries - { - LinearTypeChecker linearTypeChecker; - MoverTypeChecker moverTypeChecker; - Dictionary absyMap; - Dictionary implMap; - HashSet yieldingProcs; - int layerNum; - List globalMods; - Dictionary asyncAndParallelCallDesugarings; - List yieldCheckerProcs; - List yieldCheckerImpls; - Procedure yieldProc; - - Variable pc; - Variable ok; - Expr alpha; - Expr beta; - HashSet frame; - - public OwickiGries(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker, MyDuplicator duplicator) - { - this.linearTypeChecker = linearTypeChecker; - this.moverTypeChecker = moverTypeChecker; - this.absyMap = duplicator.absyMap; - this.layerNum = duplicator.layerNum; - this.implMap = duplicator.implMap; - this.yieldingProcs = duplicator.yieldingProcs; - Program program = linearTypeChecker.program; - globalMods = new List(); - foreach (Variable g in moverTypeChecker.SharedVariables) - { - globalMods.Add(Expr.Ident(g)); - } - asyncAndParallelCallDesugarings = new Dictionary(); - yieldCheckerProcs = new List(); - yieldCheckerImpls = new List(); - yieldProc = null; - } - - private IEnumerable AvailableLinearVars(Absy absy) - { - return linearTypeChecker.AvailableLinearVars(absyMap[absy]); - } - - private CallCmd CallToYieldProc(IToken tok, Dictionary ogOldGlobalMap, Dictionary domainNameToLocalVar) - { - List exprSeq = new List(); - foreach (string domainName in linearTypeChecker.linearDomains.Keys) - { - exprSeq.Add(Expr.Ident(domainNameToLocalVar[domainName])); - } - foreach (IdentifierExpr ie in globalMods) - { - exprSeq.Add(Expr.Ident(ogOldGlobalMap[ie.Decl])); - } - if (yieldProc == null) - { - List inputs = new List(); - foreach (string domainName in linearTypeChecker.linearDomains.Keys) - { - var domain = linearTypeChecker.linearDomains[domainName]; - Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List(), new List { domain.elementType }, Type.Bool)), true); - inputs.Add(f); - } - foreach (IdentifierExpr ie in globalMods) - { - Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", ie.Decl.Name), ie.Decl.TypedIdent.Type), true); - inputs.Add(f); - } - yieldProc = new Procedure(Token.NoToken, string.Format("og_yield_{0}", layerNum), new List(), inputs, new List(), new List(), new List(), new List()); - yieldProc.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); - } - CallCmd yieldCallCmd = new CallCmd(Token.NoToken, yieldProc.Name, exprSeq, new List()); - yieldCallCmd.Proc = yieldProc; - return yieldCallCmd; - } - - private void AddCallToYieldProc(IToken tok, List newCmds, Dictionary ogOldGlobalMap, Dictionary domainNameToLocalVar) - { - if (!CommandLineOptions.Clo.TrustNonInterference) - { - CallCmd yieldCallCmd = CallToYieldProc(tok, ogOldGlobalMap, domainNameToLocalVar); - newCmds.Add(yieldCallCmd); - } - - if (pc != null) - { - Expr aa = OldEqualityExprForGlobals(ogOldGlobalMap); - Expr bb = OldEqualityExpr(ogOldGlobalMap); - - // assert pc || g_old == g || beta(i, g_old, o, g); - Expr assertExpr = Expr.Or(Expr.Ident(pc), Expr.Or(aa, beta)); - assertExpr.Typecheck(new TypecheckingContext(null)); - AssertCmd skipOrBetaAssertCmd = new AssertCmd(tok, assertExpr); - skipOrBetaAssertCmd.ErrorData = "Transition invariant in initial state violated"; - newCmds.Add(skipOrBetaAssertCmd); - - // assert pc ==> o_old == o && g_old == g; - assertExpr = Expr.Imp(Expr.Ident(pc), bb); - assertExpr.Typecheck(new TypecheckingContext(null)); - AssertCmd skipAssertCmd = new AssertCmd(tok, assertExpr); - skipAssertCmd.ErrorData = "Transition invariant in final state violated"; ; - newCmds.Add(skipAssertCmd); - - // pc, ok := g_old == g ==> pc, ok || beta(i, g_old, o, g); - List pcUpdateLHS = new List( - new AssignLhs[] { - new SimpleAssignLhs(Token.NoToken, Expr.Ident(pc)), - new SimpleAssignLhs(Token.NoToken, Expr.Ident(ok)) - }); - List pcUpdateRHS = new List( - new Expr[] { - Expr.Imp(aa, Expr.Ident(pc)), - Expr.Or(Expr.Ident(ok), beta) - }); - foreach (Expr e in pcUpdateRHS) - { - e.Typecheck(new TypecheckingContext(null)); - } - newCmds.Add(new AssignCmd(Token.NoToken, pcUpdateLHS, pcUpdateRHS)); - } - } - - private Dictionary ComputeAvailableExprs(IEnumerable availableLinearVars, Dictionary domainNameToInputVar) - { - Dictionary domainNameToExpr = new Dictionary(); - foreach (var domainName in linearTypeChecker.linearDomains.Keys) - { - var expr = Expr.Ident(domainNameToInputVar[domainName]); - expr.Resolve(new ResolutionContext(null)); - expr.Typecheck(new TypecheckingContext(null)); - domainNameToExpr[domainName] = expr; - } - foreach (Variable v in availableLinearVars) - { - var domainName = linearTypeChecker.FindDomainName(v); - if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; - var domain = linearTypeChecker.linearDomains[domainName]; - if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; - Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List { Expr.Ident(v) }); - var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapOrBool), new List { ie, domainNameToExpr[domainName] }); - expr.Resolve(new ResolutionContext(null)); - expr.Typecheck(new TypecheckingContext(null)); - domainNameToExpr[domainName] = expr; - } - return domainNameToExpr; - } - - private void AddUpdatesToOldGlobalVars(List newCmds, Dictionary ogOldGlobalMap, Dictionary domainNameToLocalVar, Dictionary domainNameToExpr) - { - List lhss = new List(); - List rhss = new List(); - foreach (var domainName in linearTypeChecker.linearDomains.Keys) - { - lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(domainNameToLocalVar[domainName]))); - rhss.Add(domainNameToExpr[domainName]); - } - foreach (Variable g in ogOldGlobalMap.Keys) - { - lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(ogOldGlobalMap[g]))); - rhss.Add(Expr.Ident(g)); - } - if (lhss.Count > 0) - { - newCmds.Add(new AssignCmd(Token.NoToken, lhss, rhss)); - } - } - - private Expr OldEqualityExpr(Dictionary ogOldGlobalMap) - { - Expr bb = Expr.True; - foreach (Variable o in ogOldGlobalMap.Keys) - { - if (o is GlobalVariable && !frame.Contains(o)) continue; - bb = Expr.And(bb, Expr.Eq(Expr.Ident(o), Expr.Ident(ogOldGlobalMap[o]))); - bb.Type = Type.Bool; - } - return bb; - } - - private Expr OldEqualityExprForGlobals(Dictionary ogOldGlobalMap) - { - Expr bb = Expr.True; - foreach (Variable o in ogOldGlobalMap.Keys) - { - if (o is GlobalVariable && frame.Contains(o)) - { - bb = Expr.And(bb, Expr.Eq(Expr.Ident(o), Expr.Ident(ogOldGlobalMap[o]))); - bb.Type = Type.Bool; - } - } - return bb; - } - - private void DesugarYield(YieldCmd yieldCmd, List cmds, List newCmds, Dictionary ogOldGlobalMap, Dictionary domainNameToInputVar, Dictionary domainNameToLocalVar) - { - AddCallToYieldProc(yieldCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); - - if (globalMods.Count > 0) - { - newCmds.Add(new HavocCmd(Token.NoToken, globalMods)); - if (pc != null) - { - // assume pc || alpha(i, g); - Expr assumeExpr = Expr.Or(Expr.Ident(pc), alpha); - assumeExpr.Type = Type.Bool; - newCmds.Add(new AssumeCmd(Token.NoToken, assumeExpr)); - } - } - - Dictionary domainNameToExpr = ComputeAvailableExprs(AvailableLinearVars(yieldCmd), domainNameToInputVar); - AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); - - for (int j = 0; j < cmds.Count; j++) - { - PredicateCmd predCmd = (PredicateCmd)cmds[j]; - newCmds.Add(new AssumeCmd(Token.NoToken, predCmd.Expr)); - } - } - - public void DesugarParallelCallCmd(List newCmds, ParCallCmd parCallCmd) - { - List parallelCalleeNames = new List(); - List ins = new List(); - List outs = new List(); - string procName = "og"; - foreach (CallCmd callCmd in parCallCmd.CallCmds) - { - procName = procName + "_" + callCmd.Proc.Name; - ins.AddRange(callCmd.Ins); - outs.AddRange(callCmd.Outs); - } - Procedure proc; - if (asyncAndParallelCallDesugarings.ContainsKey(procName)) - { - proc = asyncAndParallelCallDesugarings[procName]; - } - else - { - List inParams = new List(); - List outParams = new List(); - List requiresSeq = new List(); - List ensuresSeq = new List(); - int count = 0; - foreach (CallCmd callCmd in parCallCmd.CallCmds) - { - Dictionary map = new Dictionary(); - foreach (Variable x in callCmd.Proc.InParams) - { - Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_{0}_{1}", count, x.Name), x.TypedIdent.Type), true); - inParams.Add(y); - map[x] = Expr.Ident(y); - } - foreach (Variable x in callCmd.Proc.OutParams) - { - Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_{0}_{1}", count, x.Name), x.TypedIdent.Type), false); - outParams.Add(y); - map[x] = Expr.Ident(y); - } - Contract.Assume(callCmd.Proc.TypeParameters.Count == 0); - Substitution subst = Substituter.SubstitutionFromHashtable(map); - foreach (Requires req in callCmd.Proc.Requires) - { - requiresSeq.Add(new Requires(req.tok, req.Free, Substituter.Apply(subst, req.Condition), null, req.Attributes)); - } - foreach (Ensures ens in callCmd.Proc.Ensures) - { - ensuresSeq.Add(new Ensures(ens.tok, ens.Free, Substituter.Apply(subst, ens.Condition), null, ens.Attributes)); - } - count++; - } - proc = new Procedure(Token.NoToken, procName, new List(), inParams, outParams, requiresSeq, globalMods, ensuresSeq); - asyncAndParallelCallDesugarings[procName] = proc; - } - CallCmd dummyCallCmd = new CallCmd(parCallCmd.tok, proc.Name, ins, outs, parCallCmd.Attributes); - dummyCallCmd.Proc = proc; - newCmds.Add(dummyCallCmd); - } - - private void CreateYieldCheckerImpl(Implementation impl, List> yields) - { - if (yields.Count == 0) return; - - Dictionary map = new Dictionary(); - foreach (Variable local in impl.LocVars) - { - var copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, local.Name, local.TypedIdent.Type)); - map[local] = Expr.Ident(copy); - } - - Program program = linearTypeChecker.program; - List locals = new List(); - List inputs = new List(); - foreach (IdentifierExpr ie in map.Values) - { - locals.Add(ie.Decl); - } - for (int i = 0; i < impl.InParams.Count - linearTypeChecker.linearDomains.Count; i++) - { - Variable inParam = impl.InParams[i]; - Variable copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, inParam.Name, inParam.TypedIdent.Type)); - locals.Add(copy); - map[impl.InParams[i]] = Expr.Ident(copy); - } - { - int i = impl.InParams.Count - linearTypeChecker.linearDomains.Count; - foreach (string domainName in linearTypeChecker.linearDomains.Keys) - { - Variable inParam = impl.InParams[i]; - Variable copy = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, inParam.Name, inParam.TypedIdent.Type), true); - inputs.Add(copy); - map[impl.InParams[i]] = Expr.Ident(copy); - i++; - } - } - for (int i = 0; i < impl.OutParams.Count; i++) - { - Variable outParam = impl.OutParams[i]; - var copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, outParam.Name, outParam.TypedIdent.Type)); - locals.Add(copy); - map[impl.OutParams[i]] = Expr.Ident(copy); - } - Dictionary ogOldLocalMap = new Dictionary(); - Dictionary assumeMap = new Dictionary(map); - foreach (IdentifierExpr ie in globalMods) - { - Variable g = ie.Decl; - var copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_local_old_{0}", g.Name), g.TypedIdent.Type)); - locals.Add(copy); - ogOldLocalMap[g] = Expr.Ident(copy); - Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", g.Name), g.TypedIdent.Type), true); - inputs.Add(f); - assumeMap[g] = Expr.Ident(f); - } - - Substitution assumeSubst = Substituter.SubstitutionFromHashtable(assumeMap); - Substitution oldSubst = Substituter.SubstitutionFromHashtable(ogOldLocalMap); - Substitution subst = Substituter.SubstitutionFromHashtable(map); - List yieldCheckerBlocks = new List(); - List labels = new List(); - List labelTargets = new List(); - Block yieldCheckerBlock = new Block(Token.NoToken, "exit", new List(), new ReturnCmd(Token.NoToken)); - labels.Add(yieldCheckerBlock.Label); - labelTargets.Add(yieldCheckerBlock); - yieldCheckerBlocks.Add(yieldCheckerBlock); - int yieldCount = 0; - foreach (List cs in yields) - { - List newCmds = new List(); - foreach (Cmd cmd in cs) - { - PredicateCmd predCmd = (PredicateCmd)cmd; - newCmds.Add(new AssumeCmd(Token.NoToken, Substituter.ApplyReplacingOldExprs(assumeSubst, oldSubst, predCmd.Expr))); - } - foreach (Cmd cmd in cs) - { - PredicateCmd predCmd = (PredicateCmd)cmd; - var newExpr = Substituter.ApplyReplacingOldExprs(subst, oldSubst, predCmd.Expr); - if (predCmd is AssertCmd) - { - AssertCmd assertCmd = new AssertCmd(predCmd.tok, newExpr, predCmd.Attributes); - assertCmd.ErrorData = "Non-interference check failed"; - newCmds.Add(assertCmd); - } - else - { - newCmds.Add(new AssumeCmd(Token.NoToken, newExpr)); - } - } - newCmds.Add(new AssumeCmd(Token.NoToken, Expr.False)); - yieldCheckerBlock = new Block(Token.NoToken, "L" + yieldCount++, newCmds, new ReturnCmd(Token.NoToken)); - labels.Add(yieldCheckerBlock.Label); - labelTargets.Add(yieldCheckerBlock); - yieldCheckerBlocks.Add(yieldCheckerBlock); - } - yieldCheckerBlocks.Insert(0, new Block(Token.NoToken, "enter", new List(), new GotoCmd(Token.NoToken, labels, labelTargets))); - - // Create the yield checker procedure - var yieldCheckerName = string.Format("{0}_YieldChecker_{1}", "Impl", impl.Name); - var yieldCheckerProc = new Procedure(Token.NoToken, yieldCheckerName, impl.TypeParameters, inputs, new List(), new List(), new List(), new List()); - yieldCheckerProc.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); - yieldCheckerProcs.Add(yieldCheckerProc); - - // Create the yield checker implementation - var yieldCheckerImpl = new Implementation(Token.NoToken, yieldCheckerName, impl.TypeParameters, inputs, new List(), locals, yieldCheckerBlocks); - yieldCheckerImpl.Proc = yieldCheckerProc; - yieldCheckerImpl.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); - yieldCheckerImpls.Add(yieldCheckerImpl); - } - - private bool IsYieldingHeader(Graph graph, Block header) - { - foreach (Block backEdgeNode in graph.BackEdgeNodes(header)) - { - foreach (Block x in graph.NaturalLoops(header, backEdgeNode)) - { - foreach (Cmd cmd in x.Cmds) - { - if (cmd is YieldCmd) - return true; - if (cmd is ParCallCmd) - return true; - CallCmd callCmd = cmd as CallCmd; - if (callCmd == null) continue; - if (yieldingProcs.Contains(callCmd.Proc)) - return true; - } - } - } - return false; - } - - private Graph ComputeYieldingLoopHeaders(Implementation impl, out HashSet yieldingHeaders) - { - Graph graph; - impl.PruneUnreachableBlocks(); - impl.ComputePredecessorsForBlocks(); - graph = Program.GraphFromImpl(impl); - graph.ComputeLoops(); - if (!graph.Reducible) - { - throw new Exception("Irreducible flow graphs are unsupported."); - } - yieldingHeaders = new HashSet(); - IEnumerable sortedHeaders = graph.SortHeadersByDominance(); - foreach (Block header in sortedHeaders) - { - if (yieldingHeaders.Any(x => graph.DominatorMap.DominatedBy(x, header))) - { - yieldingHeaders.Add(header); - } - else if (IsYieldingHeader(graph, header)) - { - yieldingHeaders.Add(header); - } - else - { - continue; - } - } - return graph; - } - - private void SetupRefinementCheck(Implementation impl, - out List newLocalVars, - out Dictionary domainNameToInputVar, out Dictionary domainNameToLocalVar, out Dictionary ogOldGlobalMap) - { - pc = null; - ok = null; - alpha = null; - beta = null; - frame = null; - - newLocalVars = new List(); - Program program = linearTypeChecker.program; - ogOldGlobalMap = new Dictionary(); - foreach (IdentifierExpr ie in globalMods) - { - Variable g = ie.Decl; - LocalVariable l = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", g.Name), g.TypedIdent.Type)); - ogOldGlobalMap[g] = l; - newLocalVars.Add(l); - } - - Procedure originalProc = implMap[impl].Proc; - ActionInfo actionInfo = moverTypeChecker.procToActionInfo[originalProc]; - if (actionInfo.createdAtLayerNum == this.layerNum) - { - pc = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "og_pc", Type.Bool)); - newLocalVars.Add(pc); - ok = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "og_ok", Type.Bool)); - newLocalVars.Add(ok); - Dictionary alwaysMap = new Dictionary(); - for (int i = 0; i < originalProc.InParams.Count; i++) - { - alwaysMap[originalProc.InParams[i]] = Expr.Ident(impl.InParams[i]); - } - for (int i = 0; i < originalProc.OutParams.Count; i++) - { - alwaysMap[originalProc.OutParams[i]] = Expr.Ident(impl.OutParams[i]); - } - Substitution always = Substituter.SubstitutionFromHashtable(alwaysMap); - Dictionary foroldMap = new Dictionary(); - foreach (IdentifierExpr ie in globalMods) - { - foroldMap[ie.Decl] = Expr.Ident(ogOldGlobalMap[ie.Decl]); - } - Substitution forold = Substituter.SubstitutionFromHashtable(foroldMap); - frame = new HashSet(moverTypeChecker.SharedVariables); - HashSet introducedVars = new HashSet(); - foreach (Variable v in moverTypeChecker.SharedVariables) - { - if (moverTypeChecker.globalVarToSharedVarInfo[v].hideLayerNum <= actionInfo.createdAtLayerNum || - moverTypeChecker.globalVarToSharedVarInfo[v].introLayerNum > actionInfo.createdAtLayerNum) - { - frame.Remove(v); - } - if (moverTypeChecker.globalVarToSharedVarInfo[v].introLayerNum == actionInfo.createdAtLayerNum) - { - introducedVars.Add(v); - } - } - AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; - if (atomicActionInfo == null) - { - beta = Expr.True; - foreach (var v in frame) - { - beta = Expr.And(beta, Expr.Eq(Expr.Ident(v), foroldMap[v])); - } - alpha = Expr.True; - } - else - { - Expr betaExpr = (new MoverCheck.TransitionRelationComputation(moverTypeChecker.program, atomicActionInfo, frame, introducedVars)).TransitionRelationCompute(); - beta = Substituter.ApplyReplacingOldExprs(always, forold, betaExpr); - Expr alphaExpr = Expr.True; - foreach (AssertCmd assertCmd in atomicActionInfo.thisGate) - { - alphaExpr = Expr.And(alphaExpr, assertCmd.Expr); - alphaExpr.Type = Type.Bool; - } - alpha = Substituter.Apply(always, alphaExpr); - } - foreach (Variable f in impl.OutParams) - { - LocalVariable copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_old_{0}", f.Name), f.TypedIdent.Type)); - newLocalVars.Add(copy); - ogOldGlobalMap[f] = copy; - } - } - - domainNameToInputVar = new Dictionary(); - domainNameToLocalVar = new Dictionary(); - { - int i = impl.InParams.Count - linearTypeChecker.linearDomains.Count; - foreach (string domainName in linearTypeChecker.linearDomains.Keys) - { - Variable inParam = impl.InParams[i]; - domainNameToInputVar[domainName] = inParam; - Variable l = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, inParam.Name + "_local", inParam.TypedIdent.Type)); - domainNameToLocalVar[domainName] = l; - newLocalVars.Add(l); - i++; - } - } - } - - private void TransformImpl(Implementation impl) - { - HashSet yieldingHeaders; - Graph graph = ComputeYieldingLoopHeaders(impl, out yieldingHeaders); - - List newLocalVars; - Dictionary domainNameToInputVar, domainNameToLocalVar; - Dictionary ogOldGlobalMap; - SetupRefinementCheck(impl, out newLocalVars, out domainNameToInputVar, out domainNameToLocalVar, out ogOldGlobalMap); - - List> yields = CollectAndDesugarYields(impl, domainNameToInputVar, domainNameToLocalVar, ogOldGlobalMap); - - List oldPcs, oldOks; - ProcessLoopHeaders(impl, graph, yieldingHeaders, domainNameToInputVar, domainNameToLocalVar, ogOldGlobalMap, out oldPcs, out oldOks); - - AddInitialBlock(impl, oldPcs, oldOks, domainNameToInputVar, domainNameToLocalVar, ogOldGlobalMap); - - CreateYieldCheckerImpl(impl, yields); - - impl.LocVars.AddRange(newLocalVars); - impl.LocVars.AddRange(oldPcs); - impl.LocVars.AddRange(oldOks); - - UnifyCallsToYieldProc(impl, ogOldGlobalMap, domainNameToLocalVar); - } - - private void UnifyCallsToYieldProc(Implementation impl, Dictionary ogOldGlobalMap, Dictionary domainNameToLocalVar) - { - CallCmd yieldCallCmd = CallToYieldProc(Token.NoToken, ogOldGlobalMap, domainNameToLocalVar); - Block yieldCheckBlock = new Block(Token.NoToken, "CallToYieldProc", new List(new Cmd[] { yieldCallCmd, new AssumeCmd(Token.NoToken, Expr.False) }), new ReturnCmd(Token.NoToken)); - List newBlocks = new List(); - foreach (Block b in impl.Blocks) - { - TransferCmd transferCmd = b.TransferCmd; - List newCmds = new List(); - for (int i = b.Cmds.Count-1; i >= 0; i--) - { - CallCmd callCmd = b.Cmds[i] as CallCmd; - if (callCmd == null || callCmd.Proc != yieldProc) - { - newCmds.Insert(0, b.Cmds[i]); - } - else - { - Block newBlock = new Block(Token.NoToken, b.Label + i, newCmds, transferCmd); - newCmds = new List(); - transferCmd = new GotoCmd(Token.NoToken, new List(new string[] { newBlock.Label, yieldCheckBlock.Label }), - new List(new Block[] { newBlock, yieldCheckBlock })); - newBlocks.Add(newBlock); - } - } - b.Cmds = newCmds; - b.TransferCmd = transferCmd; - } - impl.Blocks.AddRange(newBlocks); - impl.Blocks.Add(yieldCheckBlock); - } - - private List> CollectAndDesugarYields(Implementation impl, - Dictionary domainNameToInputVar, Dictionary domainNameToLocalVar, Dictionary ogOldGlobalMap) - { - // Collect the yield predicates and desugar yields - List> yields = new List>(); - List cmds = new List(); - foreach (Block b in impl.Blocks) - { - YieldCmd yieldCmd = null; - List newCmds = new List(); - for (int i = 0; i < b.Cmds.Count; i++) - { - Cmd cmd = b.Cmds[i]; - if (cmd is YieldCmd) - { - yieldCmd = (YieldCmd)cmd; - continue; - } - if (yieldCmd != null) - { - PredicateCmd pcmd = cmd as PredicateCmd; - if (pcmd == null) - { - DesugarYield(yieldCmd, cmds, newCmds, ogOldGlobalMap, domainNameToInputVar, domainNameToLocalVar); - if (cmds.Count > 0) - { - yields.Add(cmds); - cmds = new List(); - } - yieldCmd = null; - } - else - { - cmds.Add(pcmd); - } - } - - if (cmd is CallCmd) - { - CallCmd callCmd = cmd as CallCmd; - if (yieldingProcs.Contains(callCmd.Proc)) - { - AddCallToYieldProc(callCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); - } - if (callCmd.IsAsync) - { - if (!asyncAndParallelCallDesugarings.ContainsKey(callCmd.Proc.Name)) - { - asyncAndParallelCallDesugarings[callCmd.Proc.Name] = new Procedure(Token.NoToken, string.Format("DummyAsyncTarget_{0}", callCmd.Proc.Name), callCmd.Proc.TypeParameters, callCmd.Proc.InParams, callCmd.Proc.OutParams, callCmd.Proc.Requires, new List(), new List()); - } - var dummyAsyncTargetProc = asyncAndParallelCallDesugarings[callCmd.Proc.Name]; - CallCmd dummyCallCmd = new CallCmd(callCmd.tok, dummyAsyncTargetProc.Name, callCmd.Ins, callCmd.Outs, callCmd.Attributes); - dummyCallCmd.Proc = dummyAsyncTargetProc; - newCmds.Add(dummyCallCmd); - } - else - { - newCmds.Add(callCmd); - } - if (yieldingProcs.Contains(callCmd.Proc)) - { - HashSet availableLinearVars = new HashSet(AvailableLinearVars(callCmd)); - linearTypeChecker.AddAvailableVars(callCmd, availableLinearVars); - Dictionary domainNameToExpr = ComputeAvailableExprs(availableLinearVars, domainNameToInputVar); - AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); - } - } - else if (cmd is ParCallCmd) - { - ParCallCmd parCallCmd = cmd as ParCallCmd; - AddCallToYieldProc(parCallCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); - DesugarParallelCallCmd(newCmds, parCallCmd); - HashSet availableLinearVars = new HashSet(AvailableLinearVars(parCallCmd)); - linearTypeChecker.AddAvailableVars(parCallCmd, availableLinearVars); - Dictionary domainNameToExpr = ComputeAvailableExprs(availableLinearVars, domainNameToInputVar); - AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); - } - else - { - newCmds.Add(cmd); - } - } - if (yieldCmd != null) - { - DesugarYield(yieldCmd, cmds, newCmds, ogOldGlobalMap, domainNameToInputVar, domainNameToLocalVar); - if (cmds.Count > 0) - { - yields.Add(cmds); - cmds = new List(); - } - } - if (b.TransferCmd is ReturnCmd) - { - AddCallToYieldProc(b.TransferCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); - if (pc != null) - { - AssertCmd assertCmd = new AssertCmd(b.TransferCmd.tok, Expr.Ident(ok)); - assertCmd.ErrorData = "Failed to execute atomic action before procedure return"; - newCmds.Add(assertCmd); - } - } - b.Cmds = newCmds; - } - return yields; - } - - private void ProcessLoopHeaders(Implementation impl, Graph graph, HashSet yieldingHeaders, - Dictionary domainNameToInputVar, Dictionary domainNameToLocalVar, Dictionary ogOldGlobalMap, - out List oldPcs, out List oldOks) - { - oldPcs = new List(); - oldOks = new List(); - foreach (Block header in yieldingHeaders) - { - LocalVariable oldPc = null; - LocalVariable oldOk = null; - if (pc != null) - { - oldPc = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("{0}_{1}", pc.Name, header.Label), Type.Bool)); - oldPcs.Add(oldPc); - oldOk = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("{0}_{1}", ok.Name, header.Label), Type.Bool)); - oldOks.Add(oldOk); - } - Dictionary domainNameToExpr = ComputeAvailableExprs(AvailableLinearVars(header), domainNameToInputVar); - foreach (Block pred in header.Predecessors) - { - AddCallToYieldProc(header.tok, pred.Cmds, ogOldGlobalMap, domainNameToLocalVar); - if (pc != null && !graph.BackEdgeNodes(header).Contains(pred)) - { - pred.Cmds.Add(new AssignCmd(Token.NoToken, new List( - new AssignLhs[] { new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldPc)), new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldOk)) }), - new List(new Expr[] { Expr.Ident(pc), Expr.Ident(ok) }))); - } - AddUpdatesToOldGlobalVars(pred.Cmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); - } - List newCmds = new List(); - if (pc != null) - { - AssertCmd assertCmd; - assertCmd = new AssertCmd(header.tok, Expr.Eq(Expr.Ident(oldPc), Expr.Ident(pc))); - assertCmd.ErrorData = "Specification state must not change for transitions ending in loop headers"; - newCmds.Add(assertCmd); - assertCmd = new AssertCmd(header.tok, Expr.Imp(Expr.Ident(oldOk), Expr.Ident(ok))); - assertCmd.ErrorData = "Specification state must not change for transitions ending in loop headers"; - newCmds.Add(assertCmd); - } - foreach (string domainName in linearTypeChecker.linearDomains.Keys) - { - newCmds.Add(new AssumeCmd(Token.NoToken, Expr.Eq(Expr.Ident(domainNameToLocalVar[domainName]), domainNameToExpr[domainName]))); - } - foreach (Variable v in ogOldGlobalMap.Keys) - { - newCmds.Add(new AssumeCmd(Token.NoToken, Expr.Eq(Expr.Ident(v), Expr.Ident(ogOldGlobalMap[v])))); - } - newCmds.AddRange(header.Cmds); - header.Cmds = newCmds; - } - } - - private void AddInitialBlock(Implementation impl, List oldPcs, List oldOks, - Dictionary domainNameToInputVar, Dictionary domainNameToLocalVar, Dictionary ogOldGlobalMap) - { - // Add initial block - List lhss = new List(); - List rhss = new List(); - if (pc != null) - { - lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(pc))); - rhss.Add(Expr.False); - foreach (Variable oldPc in oldPcs) - { - lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldPc))); - rhss.Add(Expr.False); - } - lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(ok))); - rhss.Add(Expr.False); - foreach (Variable oldOk in oldOks) - { - lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldOk))); - rhss.Add(Expr.False); - } - } - Dictionary domainNameToExpr = new Dictionary(); - foreach (var domainName in linearTypeChecker.linearDomains.Keys) - { - domainNameToExpr[domainName] = Expr.Ident(domainNameToInputVar[domainName]); - } - for (int i = 0; i < impl.InParams.Count - linearTypeChecker.linearDomains.Count; i++) - { - Variable v = impl.InParams[i]; - var domainName = linearTypeChecker.FindDomainName(v); - if (domainName == null) continue; - if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; - var domain = linearTypeChecker.linearDomains[domainName]; - if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; - Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List { Expr.Ident(v) }); - domainNameToExpr[domainName] = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapOrBool), new List { ie, domainNameToExpr[domainName] }); - } - foreach (string domainName in linearTypeChecker.linearDomains.Keys) - { - lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(domainNameToLocalVar[domainName]))); - rhss.Add(domainNameToExpr[domainName]); - } - foreach (Variable g in ogOldGlobalMap.Keys) - { - lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(ogOldGlobalMap[g]))); - rhss.Add(Expr.Ident(g)); - } - if (lhss.Count > 0) - { - Block initBlock = new Block(Token.NoToken, "og_init", new List { new AssignCmd(Token.NoToken, lhss, rhss) }, new GotoCmd(Token.NoToken, new List { impl.Blocks[0].Label }, new List { impl.Blocks[0] })); - impl.Blocks.Insert(0, initBlock); - } - } - - private void AddYieldProcAndImpl(List decls) - { - if (yieldProc == null) return; - - Program program = linearTypeChecker.program; - List inputs = new List(); - foreach (string domainName in linearTypeChecker.linearDomains.Keys) - { - var domain = linearTypeChecker.linearDomains[domainName]; - Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List(), new List { domain.elementType }, Type.Bool)), true); - inputs.Add(f); - } - foreach (IdentifierExpr ie in globalMods) - { - Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", ie.Decl.Name), ie.Decl.TypedIdent.Type), true); - inputs.Add(f); - } - List blocks = new List(); - TransferCmd transferCmd = new ReturnCmd(Token.NoToken); - if (yieldCheckerProcs.Count > 0) - { - List blockTargets = new List(); - List labelTargets = new List(); - int labelCount = 0; - foreach (Procedure proc in yieldCheckerProcs) - { - List exprSeq = new List(); - foreach (Variable v in inputs) - { - exprSeq.Add(Expr.Ident(v)); - } - CallCmd callCmd = new CallCmd(Token.NoToken, proc.Name, exprSeq, new List()); - callCmd.Proc = proc; - string label = string.Format("L_{0}", labelCount++); - Block block = new Block(Token.NoToken, label, new List { callCmd }, new ReturnCmd(Token.NoToken)); - labelTargets.Add(label); - blockTargets.Add(block); - blocks.Add(block); - } - transferCmd = new GotoCmd(Token.NoToken, labelTargets, blockTargets); - } - blocks.Insert(0, new Block(Token.NoToken, "enter", new List(), transferCmd)); - - var yieldImpl = new Implementation(Token.NoToken, yieldProc.Name, new List(), inputs, new List(), new List(), blocks); - yieldImpl.Proc = yieldProc; - yieldImpl.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); - decls.Add(yieldProc); - decls.Add(yieldImpl); - } - - public static QKeyValue RemoveYieldsAttribute(QKeyValue iter) - { - if (iter == null) return null; - iter.Next = RemoveYieldsAttribute(iter.Next); - return (iter.Key == "yields") ? iter.Next : iter; - } - - public static QKeyValue RemoveMoverAttribute(QKeyValue iter) - { - if (iter == null) return null; - iter.Next = RemoveMoverAttribute(iter.Next); - if (iter.Key == "atomic" || iter.Key == "right" || iter.Key == "left" || iter.Key == "both") - return iter.Next; - else - return iter; - } - - private List Collect() - { - List decls = new List(); - foreach (Procedure proc in yieldCheckerProcs) - { - decls.Add(proc); - } - foreach (Implementation impl in yieldCheckerImpls) - { - decls.Add(impl); - } - foreach (Procedure proc in asyncAndParallelCallDesugarings.Values) - { - decls.Add(proc); - } - AddYieldProcAndImpl(decls); - return decls; - } - - public static void AddCheckers(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker, List decls) - { - Program program = linearTypeChecker.program; - foreach (int layerNum in moverTypeChecker.AllCreatedLayerNums.Except(new int[] { moverTypeChecker.leastUnimplementedLayerNum })) - { - if (CommandLineOptions.Clo.TrustLayersDownto <= layerNum || layerNum <= CommandLineOptions.Clo.TrustLayersUpto) continue; - - MyDuplicator duplicator = new MyDuplicator(moverTypeChecker, layerNum); - foreach (var proc in program.Procedures) - { - if (!moverTypeChecker.procToActionInfo.ContainsKey(proc)) continue; - Procedure duplicateProc = duplicator.VisitProcedure(proc); - decls.Add(duplicateProc); - } - decls.AddRange(duplicator.impls); - OwickiGries ogTransform = new OwickiGries(linearTypeChecker, moverTypeChecker, duplicator); - foreach (var impl in program.Implementations) - { - if (!moverTypeChecker.procToActionInfo.ContainsKey(impl.Proc) || moverTypeChecker.procToActionInfo[impl.Proc].createdAtLayerNum < layerNum) - continue; - Implementation duplicateImpl = duplicator.VisitImplementation(impl); - ogTransform.TransformImpl(duplicateImpl); - decls.Add(duplicateImpl); - } - decls.AddRange(ogTransform.Collect()); - } - } - } -} diff --git a/Source/Concurrency/Program.cs b/Source/Concurrency/Program.cs index 8042476e..1be7cc07 100644 --- a/Source/Concurrency/Program.cs +++ b/Source/Concurrency/Program.cs @@ -1,44 +1,44 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Microsoft.Boogie -{ - public class Concurrency - { - public static void Transform(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker) - { - List originalDecls = new List(); - Program program = linearTypeChecker.program; - foreach (var decl in program.TopLevelDeclarations) - { - Procedure proc = decl as Procedure; - if (proc != null && moverTypeChecker.procToActionInfo.ContainsKey(proc)) - { - originalDecls.Add(proc); - continue; - } - Implementation impl = decl as Implementation; - if (impl != null && moverTypeChecker.procToActionInfo.ContainsKey(impl.Proc)) - { - originalDecls.Add(impl); - } - } - - List decls = new List(); - if (!CommandLineOptions.Clo.TrustAtomicityTypes) - { - MoverCheck.AddCheckers(linearTypeChecker, moverTypeChecker, decls); - } - OwickiGries.AddCheckers(linearTypeChecker, moverTypeChecker, decls); - foreach (Declaration decl in decls) - { - decl.Attributes = OwickiGries.RemoveYieldsAttribute(decl.Attributes); - } - program.RemoveTopLevelDeclarations(x => originalDecls.Contains(x)); - program.AddTopLevelDeclarations(decls); - } - - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Microsoft.Boogie +{ + public class Concurrency + { + public static void Transform(LinearTypeChecker linearTypeChecker, CivlTypeChecker civlTypeChecker) + { + List originalDecls = new List(); + Program program = linearTypeChecker.program; + foreach (var decl in program.TopLevelDeclarations) + { + Procedure proc = decl as Procedure; + if (proc != null && civlTypeChecker.procToActionInfo.ContainsKey(proc)) + { + originalDecls.Add(proc); + continue; + } + Implementation impl = decl as Implementation; + if (impl != null && civlTypeChecker.procToActionInfo.ContainsKey(impl.Proc)) + { + originalDecls.Add(impl); + } + } + + List decls = new List(); + if (!CommandLineOptions.Clo.TrustAtomicityTypes) + { + MoverCheck.AddCheckers(linearTypeChecker, civlTypeChecker, decls); + } + CivlRefinement.AddCheckers(linearTypeChecker, civlTypeChecker, decls); + foreach (Declaration decl in decls) + { + decl.Attributes = CivlRefinement.RemoveYieldsAttribute(decl.Attributes); + } + program.RemoveTopLevelDeclarations(x => originalDecls.Contains(x)); + program.AddTopLevelDeclarations(decls); + } + + } +} diff --git a/Source/Concurrency/Properties/AssemblyInfo.cs b/Source/Concurrency/Properties/AssemblyInfo.cs index 48430488..7e90c12f 100644 --- a/Source/Concurrency/Properties/AssemblyInfo.cs +++ b/Source/Concurrency/Properties/AssemblyInfo.cs @@ -1,36 +1,36 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Concurrency")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Concurrency")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("867039c5-87dc-4f76-9f90-4f52afc90116")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Concurrency")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Concurrency")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("867039c5-87dc-4f76-9f90-4f52afc90116")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Source/Concurrency/SimulationRelation.cs b/Source/Concurrency/SimulationRelation.cs index 7f130f76..c97ebfb7 100644 --- a/Source/Concurrency/SimulationRelation.cs +++ b/Source/Concurrency/SimulationRelation.cs @@ -1,197 +1,197 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Microsoft.Boogie.GraphUtil; - -namespace Microsoft.Boogie -{ - public class SimulationRelation - { - class Graph - { - HashSet nodes; - Dictionary>> successors; - Dictionary>> predecessors; - - public Graph(List> edges) - { - nodes = new HashSet(); - successors = new Dictionary>>(); - predecessors = new Dictionary>>(); - foreach (Tuple edge in edges) - { - T source = edge.Item1; - L label = edge.Item2; - T dest = edge.Item3; - nodes.Add(source); - nodes.Add(dest); - if (!successors.ContainsKey(source)) - { - successors[source] = new Dictionary>(); - } - if (!successors[source].ContainsKey(label)) - { - successors[source][label] = new List(); - } - if (!predecessors.ContainsKey(dest)) - { - predecessors[dest] = new Dictionary>(); - } - if (!predecessors[dest].ContainsKey(label)) - { - predecessors[dest][label] = new List(); - } - successors[source][label].Add(dest); - predecessors[dest][label].Add(source); - } - } - - public IEnumerable Nodes { get { return nodes; } } - - public IEnumerable Post(T t, L l) - { - if (successors.ContainsKey(t) && successors[t].ContainsKey(l)) - { - return successors[t][l]; - } - else - { - return Enumerable.Empty(); - } - } - - public IEnumerable Post(IEnumerable set, L l) - { - return set.Select(x => Post(x, l)).Aggregate(Enumerable.Empty(), (p, q) => p.Concat(q)); - } - - public IEnumerable Pre(T t, L l) - { - if (predecessors.ContainsKey(t) && predecessors[t].ContainsKey(l)) - { - return predecessors[t][l]; - } - else - { - return Enumerable.Empty(); - } - } - - public IEnumerable Pre(IEnumerable set, L l) - { - return set.Select(x => Pre(x, l)).Aggregate(Enumerable.Empty(), (p, q) => p.Concat(q)); - } - - public IEnumerable PostLabels(T t) - { - if (successors.ContainsKey(t)) - { - return successors[t].Keys; - } - else - { - return Enumerable.Empty(); - } - } - - public IEnumerable PreLabels(T t) - { - if (predecessors.ContainsKey(t)) - { - return predecessors[t].Keys; - } - else - { - return Enumerable.Empty(); - } - } - } - - Graph aGraph; - Graph bGraph; - Dictionary> initialConstraints; - - public SimulationRelation(List> aEdges, List> bEdges, Dictionary> initialConstraints) - { - this.aGraph = new Graph(aEdges); - this.bGraph = new Graph(bEdges); - this.initialConstraints = initialConstraints; - } - - public Dictionary> ComputeSimulationRelation() - { - Dictionary> prevsim; - Dictionary> sim; - Dictionary, HashSet> remove; - Queue> workQueue; - - prevsim = new Dictionary>(); - sim = new Dictionary>(); - remove = new Dictionary, HashSet>(); - workQueue = new Queue>(); - foreach (var a in aGraph.Nodes) - { - prevsim[a] = new HashSet(bGraph.Nodes); - sim[a] = new HashSet(); - HashSet aOutgoingLabels = new HashSet(aGraph.PostLabels(a)); - foreach (var b in bGraph.Nodes) - { - IEnumerable bOutgoingLabels = bGraph.PostLabels(b); - if (aOutgoingLabels.IsSubsetOf(bOutgoingLabels)) - { - sim[a].Add(b); - } - } - if (initialConstraints.ContainsKey(a)) - { - sim[a].IntersectWith(initialConstraints[a]); - } - - foreach (var l in aGraph.PreLabels(a)) - { - Tuple x = new Tuple(a, l); - remove[x] = new HashSet(bGraph.Pre(prevsim[a], l).Except(bGraph.Pre(sim[a], l))); - if (remove[x].Count > 0) - { - workQueue.Enqueue(x); - } - } - } - - while (workQueue.Count > 0) - { - Tuple x = workQueue.Dequeue(); - A v = x.Item1; - foreach (A u in aGraph.Pre(v, x.Item2)) - { - foreach (B w in remove[x]) - { - if (sim[u].Contains(w)) - { - sim[u].Remove(w); - foreach (L l in bGraph.PreLabels(w)) - { - foreach (B b in bGraph.Pre(w, l)) - { - if (bGraph.Post(b, l).Intersect(sim[u]).Count() == 0) - { - Tuple z = new Tuple(u, l); - if (!remove.ContainsKey(z)) - remove[z] = new HashSet(); - remove[z].Add(b); - workQueue.Enqueue(z); - } - } - } - } - } - } - prevsim[v] = new HashSet(sim[v]); - remove[x] = new HashSet(); - } - - return sim; - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Boogie.GraphUtil; + +namespace Microsoft.Boogie +{ + public class SimulationRelation + { + class Graph + { + HashSet nodes; + Dictionary>> successors; + Dictionary>> predecessors; + + public Graph(List> edges) + { + nodes = new HashSet(); + successors = new Dictionary>>(); + predecessors = new Dictionary>>(); + foreach (Tuple edge in edges) + { + T source = edge.Item1; + L label = edge.Item2; + T dest = edge.Item3; + nodes.Add(source); + nodes.Add(dest); + if (!successors.ContainsKey(source)) + { + successors[source] = new Dictionary>(); + } + if (!successors[source].ContainsKey(label)) + { + successors[source][label] = new List(); + } + if (!predecessors.ContainsKey(dest)) + { + predecessors[dest] = new Dictionary>(); + } + if (!predecessors[dest].ContainsKey(label)) + { + predecessors[dest][label] = new List(); + } + successors[source][label].Add(dest); + predecessors[dest][label].Add(source); + } + } + + public IEnumerable Nodes { get { return nodes; } } + + public IEnumerable Post(T t, L l) + { + if (successors.ContainsKey(t) && successors[t].ContainsKey(l)) + { + return successors[t][l]; + } + else + { + return Enumerable.Empty(); + } + } + + public IEnumerable Post(IEnumerable set, L l) + { + return set.Select(x => Post(x, l)).Aggregate(Enumerable.Empty(), (p, q) => p.Concat(q)); + } + + public IEnumerable Pre(T t, L l) + { + if (predecessors.ContainsKey(t) && predecessors[t].ContainsKey(l)) + { + return predecessors[t][l]; + } + else + { + return Enumerable.Empty(); + } + } + + public IEnumerable Pre(IEnumerable set, L l) + { + return set.Select(x => Pre(x, l)).Aggregate(Enumerable.Empty(), (p, q) => p.Concat(q)); + } + + public IEnumerable PostLabels(T t) + { + if (successors.ContainsKey(t)) + { + return successors[t].Keys; + } + else + { + return Enumerable.Empty(); + } + } + + public IEnumerable PreLabels(T t) + { + if (predecessors.ContainsKey(t)) + { + return predecessors[t].Keys; + } + else + { + return Enumerable.Empty(); + } + } + } + + Graph aGraph; + Graph bGraph; + Dictionary> initialConstraints; + + public SimulationRelation(List> aEdges, List> bEdges, Dictionary> initialConstraints) + { + this.aGraph = new Graph(aEdges); + this.bGraph = new Graph(bEdges); + this.initialConstraints = initialConstraints; + } + + public Dictionary> ComputeSimulationRelation() + { + Dictionary> prevsim; + Dictionary> sim; + Dictionary, HashSet> remove; + Queue> workQueue; + + prevsim = new Dictionary>(); + sim = new Dictionary>(); + remove = new Dictionary, HashSet>(); + workQueue = new Queue>(); + foreach (var a in aGraph.Nodes) + { + prevsim[a] = new HashSet(bGraph.Nodes); + sim[a] = new HashSet(); + HashSet aOutgoingLabels = new HashSet(aGraph.PostLabels(a)); + foreach (var b in bGraph.Nodes) + { + IEnumerable bOutgoingLabels = bGraph.PostLabels(b); + if (aOutgoingLabels.IsSubsetOf(bOutgoingLabels)) + { + sim[a].Add(b); + } + } + if (initialConstraints.ContainsKey(a)) + { + sim[a].IntersectWith(initialConstraints[a]); + } + + foreach (var l in aGraph.PreLabels(a)) + { + Tuple x = new Tuple(a, l); + remove[x] = new HashSet(bGraph.Pre(prevsim[a], l).Except(bGraph.Pre(sim[a], l))); + if (remove[x].Count > 0) + { + workQueue.Enqueue(x); + } + } + } + + while (workQueue.Count > 0) + { + Tuple x = workQueue.Dequeue(); + A v = x.Item1; + foreach (A u in aGraph.Pre(v, x.Item2)) + { + foreach (B w in remove[x]) + { + if (sim[u].Contains(w)) + { + sim[u].Remove(w); + foreach (L l in bGraph.PreLabels(w)) + { + foreach (B b in bGraph.Pre(w, l)) + { + if (bGraph.Post(b, l).Intersect(sim[u]).Count() == 0) + { + Tuple z = new Tuple(u, l); + if (!remove.ContainsKey(z)) + remove[z] = new HashSet(); + remove[z].Add(b); + workQueue.Enqueue(z); + } + } + } + } + } + } + prevsim[v] = new HashSet(sim[v]); + remove[x] = new HashSet(); + } + + return sim; + } + } +} diff --git a/Source/Concurrency/TypeCheck.cs b/Source/Concurrency/TypeCheck.cs deleted file mode 100644 index f2b2c0ca..00000000 --- a/Source/Concurrency/TypeCheck.cs +++ /dev/null @@ -1,724 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Microsoft.Boogie; -using System.Diagnostics.Contracts; -using System.Diagnostics; - -namespace Microsoft.Boogie -{ - public enum MoverType - { - Top, - Atomic, - Right, - Left, - Both - } - - public class ActionInfo - { - public Procedure proc; - public int createdAtLayerNum; - public int availableUptoLayerNum; - public bool hasImplementation; - - public ActionInfo(Procedure proc, int createdAtLayerNum, int availableUptoLayerNum) - { - this.proc = proc; - this.createdAtLayerNum = createdAtLayerNum; - this.availableUptoLayerNum = availableUptoLayerNum; - this.hasImplementation = false; - } - - public virtual bool IsRightMover - { - get { return true; } - } - - public virtual bool IsLeftMover - { - get { return true; } - } - } - - public class AtomicActionInfo : ActionInfo - { - public Ensures ensures; - public MoverType moverType; - public List thisGate; - public CodeExpr thisAction; - public List thisInParams; - public List thisOutParams; - public List thatGate; - public CodeExpr thatAction; - public List thatInParams; - public List thatOutParams; - public HashSet actionUsedGlobalVars; - public HashSet modifiedGlobalVars; - public HashSet gateUsedGlobalVars; - public bool hasAssumeCmd; - - public bool CommutesWith(AtomicActionInfo actionInfo) - { - if (this.modifiedGlobalVars.Intersect(actionInfo.actionUsedGlobalVars).Count() > 0) - return false; - if (this.actionUsedGlobalVars.Intersect(actionInfo.modifiedGlobalVars).Count() > 0) - return false; - return true; - } - - public override bool IsRightMover - { - get { return moverType == MoverType.Right || moverType == MoverType.Both; } - } - - public override bool IsLeftMover - { - get { return moverType == MoverType.Left || moverType == MoverType.Both; } - } - - public AtomicActionInfo(Procedure proc, Ensures ensures, MoverType moverType, int layerNum, int availableUptoLayerNum) - : base(proc, layerNum, availableUptoLayerNum) - { - CodeExpr codeExpr = ensures.Condition as CodeExpr; - this.ensures = ensures; - this.moverType = moverType; - this.thisGate = new List(); - this.thisAction = codeExpr; - this.thisInParams = new List(); - this.thisOutParams = new List(); - this.thatGate = new List(); - this.thatInParams = new List(); - this.thatOutParams = new List(); - this.hasAssumeCmd = false; - - foreach (Block block in codeExpr.Blocks) - { - block.Cmds.ForEach(x => this.hasAssumeCmd = this.hasAssumeCmd || x is AssumeCmd); - } - - var cmds = thisAction.Blocks[0].Cmds; - for (int i = 0; i < cmds.Count; i++) - { - AssertCmd assertCmd = cmds[i] as AssertCmd; - if (assertCmd == null) break; - thisGate.Add(assertCmd); - cmds[i] = new AssumeCmd(assertCmd.tok, Expr.True); - } - - Dictionary map = new Dictionary(); - foreach (Variable x in proc.InParams) - { - this.thisInParams.Add(x); - Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), true, x.Attributes); - this.thatInParams.Add(y); - map[x] = Expr.Ident(y); - } - foreach (Variable x in proc.OutParams) - { - this.thisOutParams.Add(x); - Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), false, x.Attributes); - this.thatOutParams.Add(y); - map[x] = Expr.Ident(y); - } - List thatLocVars = new List(); - foreach (Variable x in thisAction.LocVars) - { - Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), false); - map[x] = Expr.Ident(y); - thatLocVars.Add(y); - } - Contract.Assume(proc.TypeParameters.Count == 0); - Substitution subst = Substituter.SubstitutionFromHashtable(map); - foreach (AssertCmd assertCmd in thisGate) - { - thatGate.Add((AssertCmd)Substituter.Apply(subst, assertCmd)); - } - Dictionary blockMap = new Dictionary(); - List thatBlocks = new List(); - foreach (Block block in thisAction.Blocks) - { - List otherCmds = new List(); - foreach (Cmd cmd in block.Cmds) - { - otherCmds.Add(Substituter.Apply(subst, cmd)); - } - Block thatBlock = new Block(); - thatBlock.Cmds = otherCmds; - thatBlock.Label = "that_" + block.Label; - block.Label = "this_" + block.Label; - thatBlocks.Add(thatBlock); - blockMap[block] = thatBlock; - if (block.TransferCmd is GotoCmd) - { - GotoCmd gotoCmd = block.TransferCmd as GotoCmd; - for (int i = 0; i < gotoCmd.labelNames.Count; i++) - { - gotoCmd.labelNames[i] = "this_" + gotoCmd.labelNames[i]; - } - } - } - foreach (Block block in thisAction.Blocks) - { - if (block.TransferCmd is ReturnExprCmd) - { - block.TransferCmd = new ReturnCmd(block.TransferCmd.tok); - blockMap[block].TransferCmd = new ReturnCmd(block.TransferCmd.tok); - continue; - } - List thatGotoCmdLabelTargets = new List(); - List thatGotoCmdLabelNames = new List(); - GotoCmd gotoCmd = block.TransferCmd as GotoCmd; - foreach (Block target in gotoCmd.labelTargets) - { - thatGotoCmdLabelTargets.Add(blockMap[target]); - thatGotoCmdLabelNames.Add(blockMap[target].Label); - } - blockMap[block].TransferCmd = new GotoCmd(block.TransferCmd.tok, thatGotoCmdLabelNames, thatGotoCmdLabelTargets); - } - this.thatAction = new CodeExpr(thatLocVars, thatBlocks); - - { - VariableCollector collector = new VariableCollector(); - collector.Visit(codeExpr); - this.actionUsedGlobalVars = new HashSet(collector.usedVars.Where(x => x is GlobalVariable)); - } - - List modifiedVars = new List(); - foreach (Block block in codeExpr.Blocks) - { - block.Cmds.ForEach(cmd => cmd.AddAssignedVariables(modifiedVars)); - } - this.modifiedGlobalVars = new HashSet(modifiedVars.Where(x => x is GlobalVariable)); - - { - VariableCollector collector = new VariableCollector(); - this.thisGate.ForEach(assertCmd => collector.Visit(assertCmd)); - this.gateUsedGlobalVars = new HashSet(collector.usedVars.Where(x => x is GlobalVariable)); - } - } - } - - public class SharedVariableInfo - { - public int introLayerNum; - public int hideLayerNum; - - public SharedVariableInfo(int introLayerNum, int hideLayerNum) - { - this.introLayerNum = introLayerNum; - this.hideLayerNum = hideLayerNum; - } - } - - public class LayerEraser : ReadOnlyVisitor - { - private QKeyValue RemoveLayerAttribute(QKeyValue iter) - { - if (iter == null) return null; - iter.Next = RemoveLayerAttribute(iter.Next); - return (iter.Key == "layer") ? iter.Next : iter; - } - - public override Variable VisitVariable(Variable node) - { - node.Attributes = RemoveLayerAttribute(node.Attributes); - return base.VisitVariable(node); - } - - public override Procedure VisitProcedure(Procedure node) - { - node.Attributes = RemoveLayerAttribute(node.Attributes); - return base.VisitProcedure(node); - } - - public override Implementation VisitImplementation(Implementation node) - { - node.Attributes = RemoveLayerAttribute(node.Attributes); - return base.VisitImplementation(node); - } - - public override Requires VisitRequires(Requires node) - { - node.Attributes = RemoveLayerAttribute(node.Attributes); - return base.VisitRequires(node); - } - - public override Ensures VisitEnsures(Ensures node) - { - node.Attributes = RemoveLayerAttribute(node.Attributes); - return base.VisitEnsures(node); - } - - public override Cmd VisitAssertCmd(AssertCmd node) - { - node.Attributes = RemoveLayerAttribute(node.Attributes); - return base.VisitAssertCmd(node); - } - } - - public class MoverTypeChecker : ReadOnlyVisitor - { - CheckingContext checkingContext; - public int errorCount; - public Dictionary globalVarToSharedVarInfo; - Procedure enclosingProc; - Implementation enclosingImpl; - public Dictionary procToActionInfo; - public Program program; - bool canAccessSharedVars; - bool canAccessAuxVars; - int minLayerNum; - int maxLayerNum; - public Dictionary> absyToLayerNums; - HashSet auxVars; - public int leastUnimplementedLayerNum; - - private static List FindLayers(QKeyValue kv) - { - HashSet attrs = new HashSet(); - for (; kv != null; kv = kv.Next) - { - if (kv.Key != "layer") continue; - foreach (var o in kv.Params) - { - Expr e = o as Expr; - if (e == null) continue; - LiteralExpr l = e as LiteralExpr; - if (l != null && l.isBigNum) - attrs.Add(l.asBigNum.ToIntSafe); - } - } - List layers = attrs.ToList(); - layers.Sort(); - return layers; - } - - private static MoverType GetMoverType(Ensures e) - { - if (QKeyValue.FindBoolAttribute(e.Attributes, "atomic")) - return MoverType.Atomic; - if (QKeyValue.FindBoolAttribute(e.Attributes, "right")) - return MoverType.Right; - if (QKeyValue.FindBoolAttribute(e.Attributes, "left")) - return MoverType.Left; - if (QKeyValue.FindBoolAttribute(e.Attributes, "both")) - return MoverType.Both; - return MoverType.Top; - } - - public MoverTypeChecker(Program program) - { - this.auxVars = new HashSet(); - this.absyToLayerNums = new Dictionary>(); - this.globalVarToSharedVarInfo = new Dictionary(); - this.procToActionInfo = new Dictionary(); - this.errorCount = 0; - this.checkingContext = new CheckingContext(null); - this.program = program; - this.enclosingProc = null; - this.enclosingImpl = null; - this.canAccessSharedVars = false; - this.canAccessAuxVars = false; - this.minLayerNum = int.MaxValue; - this.maxLayerNum = -1; - this.leastUnimplementedLayerNum = int.MaxValue; - foreach (var g in program.GlobalVariables) - { - List layerNums = FindLayers(g.Attributes); - if (layerNums.Count == 0) - { - // Cannot access atomic actions - } - else if (layerNums.Count == 1) - { - this.globalVarToSharedVarInfo[g] = new SharedVariableInfo(layerNums[0], int.MaxValue); - } - else if (layerNums.Count == 2) - { - this.globalVarToSharedVarInfo[g] = new SharedVariableInfo(layerNums[0], layerNums[1]); - } - else - { - Error(g, "Too many layer numbers"); - } - } - } - - private HashSet allCreatedLayerNums; - public IEnumerable AllCreatedLayerNums - { - get - { - if (allCreatedLayerNums == null) - { - allCreatedLayerNums = new HashSet(); - foreach (ActionInfo actionInfo in procToActionInfo.Values) - { - allCreatedLayerNums.Add(actionInfo.createdAtLayerNum); - } - } - return allCreatedLayerNums; - } - } - - public void TypeCheck() - { - foreach (var proc in program.Procedures) - { - if (!QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) continue; - - int createdAtLayerNum; // must be initialized by the following code, otherwise it is an error - int availableUptoLayerNum = int.MaxValue; - List attrs = FindLayers(proc.Attributes); - if (attrs.Count == 1) - { - createdAtLayerNum = attrs[0]; - } - else if (attrs.Count == 2) - { - createdAtLayerNum = attrs[0]; - availableUptoLayerNum = attrs[1]; - } - else - { - Error(proc, "Incorrect number of layers"); - continue; - } - if (availableUptoLayerNum <= createdAtLayerNum) - { - Error(proc, "Creation layer number must be less than the available upto layer number"); - continue; - } - foreach (Ensures e in proc.Ensures) - { - MoverType moverType = GetMoverType(e); - if (moverType == MoverType.Top) continue; - CodeExpr codeExpr = e.Condition as CodeExpr; - if (codeExpr == null) - { - Error(e, "An atomic action must be a CodeExpr"); - continue; - } - if (procToActionInfo.ContainsKey(proc)) - { - Error(proc, "A procedure can have at most one atomic action"); - continue; - } - - minLayerNum = int.MaxValue; - maxLayerNum = -1; - canAccessSharedVars = true; - enclosingProc = proc; - enclosingImpl = null; - base.VisitEnsures(e); - canAccessSharedVars = false; - if (maxLayerNum > createdAtLayerNum) - { - Error(e, "A variable being accessed is introduced after this action is created"); - } - else if (availableUptoLayerNum > minLayerNum) - { - Error(e, "A variable being accessed is hidden before this action becomes unavailable"); - } - else - { - procToActionInfo[proc] = new AtomicActionInfo(proc, e, moverType, createdAtLayerNum, availableUptoLayerNum); - } - } - if (errorCount > 0) continue; - if (!procToActionInfo.ContainsKey(proc)) - { - procToActionInfo[proc] = new ActionInfo(proc, createdAtLayerNum, availableUptoLayerNum); - } - } - if (errorCount > 0) return; - foreach (var impl in program.Implementations) - { - if (!procToActionInfo.ContainsKey(impl.Proc)) continue; - procToActionInfo[impl.Proc].hasImplementation = true; - } - foreach (var proc in procToActionInfo.Keys) - { - ActionInfo actionInfo = procToActionInfo[proc]; - if (actionInfo.hasImplementation) continue; - if (leastUnimplementedLayerNum == int.MaxValue) - { - leastUnimplementedLayerNum = actionInfo.createdAtLayerNum; - } - else if (leastUnimplementedLayerNum == actionInfo.createdAtLayerNum) - { - // do nothing - } - else - { - Error(proc, "All unimplemented atomic actions must be created at the same layer"); - } - } - foreach (var g in this.globalVarToSharedVarInfo.Keys) - { - var info = globalVarToSharedVarInfo[g]; - if (!this.AllCreatedLayerNums.Contains(info.introLayerNum)) - { - Error(g, "Variable must be introduced with creation of some atomic action"); - } - if (info.hideLayerNum != int.MaxValue && !this.AllCreatedLayerNums.Contains(info.hideLayerNum)) - { - Error(g, "Variable must be hidden with creation of some atomic action"); - } - } - if (errorCount > 0) return; - this.VisitProgram(program); - if (errorCount > 0) return; - YieldTypeChecker.PerformYieldSafeCheck(this); - new LayerEraser().VisitProgram(program); - } - - public IEnumerable SharedVariables - { - get { return this.globalVarToSharedVarInfo.Keys; } - } - - public override Implementation VisitImplementation(Implementation node) - { - if (!procToActionInfo.ContainsKey(node.Proc)) - { - return node; - } - this.enclosingImpl = node; - this.enclosingProc = null; - auxVars = new HashSet(); - foreach (Variable v in node.LocVars) - { - if (QKeyValue.FindBoolAttribute(v.Attributes, "aux")) - { - auxVars.Add(v); - } - } - return base.VisitImplementation(node); - } - - public override Procedure VisitProcedure(Procedure node) - { - if (!procToActionInfo.ContainsKey(node)) - { - return node; - } - this.enclosingProc = node; - this.enclosingImpl = null; - return base.VisitProcedure(node); - } - - public override Cmd VisitCallCmd(CallCmd node) - { - int enclosingProcLayerNum = procToActionInfo[enclosingImpl.Proc].createdAtLayerNum; - if (procToActionInfo.ContainsKey(node.Proc)) - { - ActionInfo actionInfo = procToActionInfo[node.Proc]; - if (node.IsAsync && actionInfo is AtomicActionInfo) - { - Error(node, "Target of async call cannot be an atomic action"); - } - int calleeLayerNum = procToActionInfo[node.Proc].createdAtLayerNum; - if (enclosingProcLayerNum < calleeLayerNum || - (enclosingProcLayerNum == calleeLayerNum && actionInfo is AtomicActionInfo)) - { - Error(node, "The layer of the caller must be greater than the layer of the callee"); - } - else if (enclosingProcLayerNum == calleeLayerNum && enclosingImpl.OutParams.Count > 0) - { - HashSet outParams = new HashSet(enclosingImpl.OutParams); - foreach (var x in node.Outs) - { - if (x.Decl is GlobalVariable) - { - Error(node, "A global variable cannot be used as output argument for this call"); - } - else if (outParams.Contains(x.Decl)) - { - Error(node, "An output variable of the enclosing implementation cannot be used as output argument for this call"); - } - } - } - if (actionInfo.availableUptoLayerNum < enclosingProcLayerNum) - { - Error(node, "The callee is not available in the caller procedure"); - } - } - else - { - Error(node, "Yielding procedure can call only a yielding procedure"); - } - return base.VisitCallCmd(node); - } - - public override Cmd VisitParCallCmd(ParCallCmd node) - { - int enclosingProcLayerNum = procToActionInfo[enclosingImpl.Proc].createdAtLayerNum; - bool isLeftMover = true; - bool isRightMover = true; - int maxCalleeLayerNum = 0; - int numAtomicActions = 0; - foreach (CallCmd iter in node.CallCmds) - { - ActionInfo actionInfo = procToActionInfo[iter.Proc]; - isLeftMover = isLeftMover && actionInfo.IsLeftMover; - isRightMover = isRightMover && actionInfo.IsRightMover; - if (actionInfo.createdAtLayerNum > maxCalleeLayerNum) - { - maxCalleeLayerNum = actionInfo.createdAtLayerNum; - } - if (actionInfo is AtomicActionInfo) - { - numAtomicActions++; - } - } - if (maxCalleeLayerNum < enclosingProcLayerNum && !isLeftMover && !isRightMover && node.CallCmds.Count > 1) - { - Error(node, "The callees in the parallel call must be all right movers or all left movers"); - } - if (maxCalleeLayerNum == enclosingProcLayerNum && numAtomicActions > 0) - { - Error(node, "If some callee in the parallel call has the same layer as the enclosing procedure, then no callee can be an atomic action"); - } - return base.VisitParCallCmd(node); - } - - public override Cmd VisitAssignCmd(AssignCmd node) - { - Contract.Ensures(Contract.Result() == node); - for (int i = 0; i < node.Lhss.Count; ++i) - { - bool savedCanAccessSharedVars = canAccessSharedVars; - bool savedCanAccessAuxVars = canAccessAuxVars; - Variable v = node.Lhss[i].DeepAssignedVariable; - if (v is LocalVariable && auxVars.Contains(v)) - { - canAccessSharedVars = true; - canAccessAuxVars = true; - } - this.Visit(node.Lhss[i]); - this.Visit(node.Rhss[i]); - canAccessSharedVars = savedCanAccessSharedVars; - canAccessAuxVars = savedCanAccessAuxVars; - } - return node; - } - - public override Expr VisitIdentifierExpr(IdentifierExpr node) - { - if (node.Decl is GlobalVariable) - { - if (!canAccessSharedVars) - { - Error(node, "Shared variable can be accessed only in atomic actions or specifications"); - } - else if (this.globalVarToSharedVarInfo.ContainsKey(node.Decl)) - { - if (this.globalVarToSharedVarInfo[node.Decl].hideLayerNum < minLayerNum) - { - minLayerNum = this.globalVarToSharedVarInfo[node.Decl].hideLayerNum; - } - if (this.globalVarToSharedVarInfo[node.Decl].introLayerNum > maxLayerNum) - { - maxLayerNum = this.globalVarToSharedVarInfo[node.Decl].introLayerNum; - } - } - else - { - Error(node, "Accessed shared variable must have layer annotation"); - } - } - else if (node.Decl is LocalVariable && auxVars.Contains(node.Decl) && !canAccessAuxVars) - { - Error(node, "Auxiliary variable can be accessed only in assertions"); - } - - return base.VisitIdentifierExpr(node); - } - - public override Ensures VisitEnsures(Ensures ensures) - { - minLayerNum = int.MaxValue; - maxLayerNum = -1; - canAccessSharedVars = true; - Ensures ret = base.VisitEnsures(ensures); - canAccessSharedVars = false; - ActionInfo actionInfo = procToActionInfo[enclosingProc]; - AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; - if (atomicActionInfo != null && atomicActionInfo.ensures == ensures) - { - // This case has already been checked - } - else - { - CheckAndAddLayers(ensures, ensures.Attributes, actionInfo.createdAtLayerNum); - } - return ret; - } - - public override Requires VisitRequires(Requires requires) - { - minLayerNum = int.MaxValue; - maxLayerNum = -1; - canAccessSharedVars = true; - Requires ret = base.VisitRequires(requires); - canAccessSharedVars = false; - CheckAndAddLayers(requires, requires.Attributes, procToActionInfo[enclosingProc].createdAtLayerNum); - return ret; - } - - public override Cmd VisitAssertCmd(AssertCmd node) - { - if (enclosingImpl == null) - return base.VisitAssertCmd(node); - minLayerNum = int.MaxValue; - maxLayerNum = -1; - canAccessSharedVars = true; - canAccessAuxVars = true; - Cmd ret = base.VisitAssertCmd(node); - canAccessAuxVars = false; - canAccessSharedVars = false; - CheckAndAddLayers(node, node.Attributes, procToActionInfo[enclosingImpl.Proc].createdAtLayerNum); - return ret; - } - - private void CheckAndAddLayers(Absy node, QKeyValue attributes, int enclosingProcLayerNum) - { - List attrs = FindLayers(attributes); - if (attrs.Count == 0) - { - Error(node, "layer not present"); - return; - } - absyToLayerNums[node] = new HashSet(); - foreach (int layerNum in attrs) - { - if (layerNum == leastUnimplementedLayerNum || !AllCreatedLayerNums.Contains(layerNum)) - { - Error(node, "Illegal layer number"); - } - else if (layerNum > enclosingProcLayerNum) - { - Error(node, "The layer cannot be greater than the layer of enclosing procedure"); - } - else if (maxLayerNum < layerNum && layerNum <= minLayerNum) - { - absyToLayerNums[node].Add(layerNum); - } - else - { - Error(node, string.Format("A variable being accessed in this specification is unavailable at layer {0}", layerNum)); - } - } - } - - public void Error(Absy node, string message) - { - checkingContext.Error(node, message); - errorCount++; - } - } -} \ No newline at end of file diff --git a/Source/Concurrency/YieldTypeChecker.cs b/Source/Concurrency/YieldTypeChecker.cs index 95884626..ed59d3ad 100644 --- a/Source/Concurrency/YieldTypeChecker.cs +++ b/Source/Concurrency/YieldTypeChecker.cs @@ -1,363 +1,368 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Microsoft.Boogie; -using System.Diagnostics.Contracts; -using Microsoft.Boogie.AbstractInterpretation; -using Microsoft.Boogie.GraphUtil; -using System.Diagnostics; - -namespace Microsoft.Boogie -{ - class YieldTypeChecker - { - static List> ASpec; - static List> BSpec; - static List> CSpec; - static YieldTypeChecker() - { - // initial: 0, final: 1 - ASpec = new List>(); - ASpec.Add(new Tuple(0, 'Y', 1)); - ASpec.Add(new Tuple(1, 'Y', 1)); - ASpec.Add(new Tuple(1, 'B', 1)); - ASpec.Add(new Tuple(1, 'R', 1)); - ASpec.Add(new Tuple(1, 'L', 1)); - ASpec.Add(new Tuple(1, 'A', 1)); - ASpec.Add(new Tuple(0, 'P', 0)); - ASpec.Add(new Tuple(1, 'P', 1)); - - // initial: 1, final: 0 - BSpec = new List>(); - BSpec.Add(new Tuple(1, 'Y', 0)); - BSpec.Add(new Tuple(1, 'Y', 1)); - BSpec.Add(new Tuple(1, 'B', 1)); - BSpec.Add(new Tuple(1, 'R', 1)); - BSpec.Add(new Tuple(1, 'L', 1)); - BSpec.Add(new Tuple(1, 'A', 1)); - BSpec.Add(new Tuple(0, 'P', 0)); - BSpec.Add(new Tuple(1, 'P', 1)); - - // initial: {0, 1}, final: {0, 1} - CSpec = new List>(); - CSpec.Add(new Tuple(0, 'B', 0)); - CSpec.Add(new Tuple(0, 'R', 0)); - CSpec.Add(new Tuple(0, 'Y', 0)); - CSpec.Add(new Tuple(0, 'B', 1)); - CSpec.Add(new Tuple(0, 'R', 1)); - CSpec.Add(new Tuple(0, 'L', 1)); - CSpec.Add(new Tuple(0, 'A', 1)); - CSpec.Add(new Tuple(1, 'B', 1)); - CSpec.Add(new Tuple(1, 'L', 1)); - CSpec.Add(new Tuple(1, 'Y', 0)); - CSpec.Add(new Tuple(0, 'P', 0)); - CSpec.Add(new Tuple(1, 'P', 1)); - } - - private void IsYieldTypeSafe() - { - List> implEdges = new List>(); - foreach (Tuple e in edgeLabels.Keys) - { - implEdges.Add(new Tuple(e.Item1, edgeLabels[e], e.Item2)); - } - //Console.WriteLine(PrintGraph(impl, implEdges, initialState, finalStates)); - ASpecCheck(implEdges); - BSpecCheck(implEdges); - CSpecCheck(implEdges); - } - - private void ASpecCheck(List> implEdges) - { - Dictionary> initialConstraints = new Dictionary>(); - initialConstraints[initialState] = new HashSet(new int[] { 0 }); - foreach (var finalState in finalStates) - { - initialConstraints[finalState] = new HashSet(new int[] { 1 }); - } - SimulationRelation x = new SimulationRelation(implEdges, ASpec, initialConstraints); - Dictionary> simulationRelation = x.ComputeSimulationRelation(); - if (simulationRelation[initialState].Count == 0) - { - moverTypeChecker.Error(impl, string.Format("Implementation {0} fails simulation check A at layer {1}. An action must be preceded by a yield.\n", impl.Name, currLayerNum)); - } - } - - private void BSpecCheck(List> implEdges) - { - Dictionary> initialConstraints = new Dictionary>(); - initialConstraints[initialState] = new HashSet(new int[] { 1 }); - foreach (var finalState in finalStates) - { - initialConstraints[finalState] = new HashSet(new int[] { 0 }); - } - SimulationRelation x = new SimulationRelation(implEdges, BSpec, initialConstraints); - Dictionary> simulationRelation = x.ComputeSimulationRelation(); - if (simulationRelation[initialState].Count == 0) - { - moverTypeChecker.Error(impl, string.Format("Implementation {0} fails simulation check B at layer {1}. An action must be succeeded by a yield.\n", impl.Name, currLayerNum)); - } - } - - private void CSpecCheck(List> implEdges) - { - Dictionary> initialConstraints = new Dictionary>(); - foreach (Block block in loopHeaders) - { - if (!IsTerminatingLoopHeader(block)) - { - initialConstraints[absyToNode[block]] = new HashSet(new int[] { 0 }); - } - } - SimulationRelation x = new SimulationRelation(implEdges, CSpec, initialConstraints); - Dictionary> simulationRelation = x.ComputeSimulationRelation(); - if (simulationRelation[initialState].Count == 0) - { - moverTypeChecker.Error(impl, string.Format("Implementation {0} fails simulation check C at layer {1}. Transactions must be separated by a yield.\n", impl.Name, currLayerNum)); - } - } - - private bool IsTerminatingLoopHeader(Block block) - { - foreach (Cmd cmd in block.Cmds) - { - AssertCmd assertCmd = cmd as AssertCmd; - if (assertCmd != null && QKeyValue.FindBoolAttribute(assertCmd.Attributes, "terminates") && moverTypeChecker.absyToLayerNums[assertCmd].Contains(currLayerNum)) - { - return true; - } - } - return false; - } - - public static void PerformYieldSafeCheck(MoverTypeChecker moverTypeChecker) - { - foreach (var impl in moverTypeChecker.program.Implementations) - { - if (!moverTypeChecker.procToActionInfo.ContainsKey(impl.Proc)) continue; - impl.PruneUnreachableBlocks(); - Graph implGraph = Program.GraphFromImpl(impl); - implGraph.ComputeLoops(); - int specLayerNum = moverTypeChecker.procToActionInfo[impl.Proc].createdAtLayerNum; - foreach (int layerNum in moverTypeChecker.AllCreatedLayerNums.Except(new int[] { moverTypeChecker.leastUnimplementedLayerNum })) - { - if (layerNum > specLayerNum) continue; - YieldTypeChecker executor = new YieldTypeChecker(moverTypeChecker, impl, layerNum, implGraph.Headers); - } - } - } - - int stateCounter; - MoverTypeChecker moverTypeChecker; - Implementation impl; - int currLayerNum; - Dictionary absyToNode; - Dictionary nodeToAbsy; - int initialState; - HashSet finalStates; - Dictionary, int> edgeLabels; - IEnumerable loopHeaders; - - private YieldTypeChecker(MoverTypeChecker moverTypeChecker, Implementation impl, int currLayerNum, IEnumerable loopHeaders) - { - this.moverTypeChecker = moverTypeChecker; - this.impl = impl; - this.currLayerNum = currLayerNum; - this.loopHeaders = loopHeaders; - this.stateCounter = 0; - this.absyToNode = new Dictionary(); - this.initialState = 0; - this.finalStates = new HashSet(); - this.edgeLabels = new Dictionary, int>(); - - foreach (Block block in impl.Blocks) - { - absyToNode[block] = stateCounter; - stateCounter++; - foreach (Cmd cmd in block.Cmds) - { - absyToNode[cmd] = stateCounter; - stateCounter++; - } - absyToNode[block.TransferCmd] = stateCounter; - stateCounter++; - if (block.TransferCmd is ReturnCmd) - { - finalStates.Add(absyToNode[block.TransferCmd]); - } - } - foreach (Block block in impl.Blocks) - { - Absy blockEntry = block.Cmds.Count == 0 ? (Absy)block.TransferCmd : (Absy)block.Cmds[0]; - edgeLabels[new Tuple(absyToNode[block], absyToNode[blockEntry])] = 'P'; - - GotoCmd gotoCmd = block.TransferCmd as GotoCmd; - if (gotoCmd == null) continue; - foreach (Block successor in gotoCmd.labelTargets) - { - edgeLabels[new Tuple(absyToNode[gotoCmd], absyToNode[successor])] = 'P'; - } - } - - this.nodeToAbsy = new Dictionary(); - foreach (KeyValuePair state in absyToNode) - { - this.nodeToAbsy[state.Value] = state.Key; - } - - ComputeGraph(); - IsYieldTypeSafe(); - } - - private void ComputeGraph() - { - foreach (Block block in impl.Blocks) - { - for (int i = 0; i < block.Cmds.Count; i++) - { - Cmd cmd = block.Cmds[i]; - int curr = absyToNode[cmd]; - int next = (i + 1 == block.Cmds.Count) ? absyToNode[block.TransferCmd] : absyToNode[block.Cmds[i + 1]]; - Tuple edge = new Tuple(curr, next); - if (cmd is CallCmd) - { - CallCmd callCmd = cmd as CallCmd; - if (callCmd.IsAsync) - { - ActionInfo actionInfo = moverTypeChecker.procToActionInfo[callCmd.Proc]; - if (currLayerNum <= actionInfo.createdAtLayerNum) - edgeLabels[edge] = 'L'; - else - edgeLabels[edge] = 'B'; - } - else if (!moverTypeChecker.procToActionInfo.ContainsKey(callCmd.Proc)) - { - edgeLabels[edge] = 'P'; - } - else - { - MoverType moverType; - ActionInfo actionInfo = moverTypeChecker.procToActionInfo[callCmd.Proc]; - if (actionInfo.createdAtLayerNum >= currLayerNum) - { - moverType = MoverType.Top; - } - else - { - AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; - if (atomicActionInfo == null) - moverType = MoverType.Both; - else - moverType = atomicActionInfo.moverType; - } - switch (moverType) - { - case MoverType.Atomic: - edgeLabels[edge] = 'A'; - break; - case MoverType.Both: - edgeLabels[edge] = 'B'; - break; - case MoverType.Left: - edgeLabels[edge] = 'L'; - break; - case MoverType.Right: - edgeLabels[edge] = 'R'; - break; - case MoverType.Top: - edgeLabels[edge] = 'Y'; - break; - } - } - } - else if (cmd is ParCallCmd) - { - ParCallCmd parCallCmd = cmd as ParCallCmd; - bool isYield = false; - bool isRightMover = true; - bool isLeftMover = true; - foreach (CallCmd callCmd in parCallCmd.CallCmds) - { - if (moverTypeChecker.procToActionInfo[callCmd.Proc].createdAtLayerNum >= currLayerNum) - { - isYield = true; - } - } - if (isYield) - { - edgeLabels[edge] = 'Y'; - } - else - { - foreach (CallCmd callCmd in parCallCmd.CallCmds) - { - ActionInfo actionInfo = moverTypeChecker.procToActionInfo[callCmd.Proc]; - isRightMover = isRightMover && actionInfo.IsRightMover; - isLeftMover = isLeftMover && actionInfo.IsLeftMover; - } - if (isLeftMover && isRightMover) - { - edgeLabels[edge] = 'B'; - } - else if (isLeftMover) - { - edgeLabels[edge] = 'L'; - } - else if (isRightMover) - { - edgeLabels[edge] = 'R'; - } - else - { - Debug.Assert(parCallCmd.CallCmds.Count == 1); - edgeLabels[edge] = 'A'; - } - } - } - else if (cmd is YieldCmd) - { - edgeLabels[edge] = 'Y'; - } - else - { - edgeLabels[edge] = 'P'; - } - } - } - } - - private static string PrintGraph(Implementation impl, List> edges, int initialState, HashSet finalStates) - { - var s = new StringBuilder(); - s.AppendLine("\nImplementation " + impl.Proc.Name + " digraph G {"); - foreach (var e in edges) - { - string label = "P"; - switch (e.Item2) - { - case 'P': label = "P"; break; - case 'Y': label = "Y"; break; - case 'B': label = "B"; break; - case 'R': label = "R"; break; - case 'L': label = "L"; break; - case 'A': label = "A"; break; - default: Debug.Assert(false); break; - } - s.AppendLine(" \"" + e.Item1.ToString() + "\" -- " + label + " --> " + " \"" + e.Item3.ToString() + "\";"); - } - s.AppendLine("}"); - s.AppendLine("Initial state: " + initialState); - s.Append("Final states: "); - bool first = true; - foreach (int finalState in finalStates) - { - s.Append((first ? "" : ", ") + finalState); - first = false; - } - s.AppendLine(); - return s.ToString(); - } - } -} +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Boogie; +using System.Diagnostics.Contracts; +using Microsoft.Boogie.AbstractInterpretation; +using Microsoft.Boogie.GraphUtil; +using System.Diagnostics; + +namespace Microsoft.Boogie +{ + class YieldTypeChecker + { + static List> ASpec; + static List> BSpec; + static List> CSpec; + static YieldTypeChecker() + { + // initial: 0, final: 1 + ASpec = new List>(); + ASpec.Add(new Tuple(0, 'Y', 1)); + ASpec.Add(new Tuple(1, 'Y', 1)); + ASpec.Add(new Tuple(1, 'B', 1)); + ASpec.Add(new Tuple(1, 'R', 1)); + ASpec.Add(new Tuple(1, 'L', 1)); + ASpec.Add(new Tuple(1, 'A', 1)); + ASpec.Add(new Tuple(0, 'P', 0)); + ASpec.Add(new Tuple(1, 'P', 1)); + + // initial: 1, final: 0 + BSpec = new List>(); + BSpec.Add(new Tuple(1, 'Y', 0)); + BSpec.Add(new Tuple(1, 'Y', 1)); + BSpec.Add(new Tuple(1, 'B', 1)); + BSpec.Add(new Tuple(1, 'R', 1)); + BSpec.Add(new Tuple(1, 'L', 1)); + BSpec.Add(new Tuple(1, 'A', 1)); + BSpec.Add(new Tuple(0, 'P', 0)); + BSpec.Add(new Tuple(1, 'P', 1)); + + // initial: {0, 1}, final: {0, 1} + CSpec = new List>(); + CSpec.Add(new Tuple(0, 'B', 0)); + CSpec.Add(new Tuple(0, 'R', 0)); + CSpec.Add(new Tuple(0, 'Y', 0)); + CSpec.Add(new Tuple(0, 'B', 1)); + CSpec.Add(new Tuple(0, 'R', 1)); + CSpec.Add(new Tuple(0, 'L', 1)); + CSpec.Add(new Tuple(0, 'A', 1)); + CSpec.Add(new Tuple(1, 'B', 1)); + CSpec.Add(new Tuple(1, 'L', 1)); + CSpec.Add(new Tuple(1, 'Y', 0)); + CSpec.Add(new Tuple(0, 'P', 0)); + CSpec.Add(new Tuple(1, 'P', 1)); + } + + private void IsYieldTypeSafe() + { + List> implEdges = new List>(); + foreach (Tuple e in edgeLabels.Keys) + { + implEdges.Add(new Tuple(e.Item1, edgeLabels[e], e.Item2)); + } + //Console.WriteLine(PrintGraph(impl, implEdges, initialState, finalStates)); + ASpecCheck(implEdges); + BSpecCheck(implEdges); + CSpecCheck(implEdges); + } + + private void ASpecCheck(List> implEdges) + { + Dictionary> initialConstraints = new Dictionary>(); + initialConstraints[initialState] = new HashSet(new int[] { 0 }); + foreach (var finalState in finalStates) + { + initialConstraints[finalState] = new HashSet(new int[] { 1 }); + } + SimulationRelation x = new SimulationRelation(implEdges, ASpec, initialConstraints); + Dictionary> simulationRelation = x.ComputeSimulationRelation(); + if (simulationRelation[initialState].Count == 0) + { + civlTypeChecker.Error(impl, string.Format("Implementation {0} fails simulation check A at layer {1}. An action must be preceded by a yield.\n", impl.Name, currLayerNum)); + } + } + + private void BSpecCheck(List> implEdges) + { + Dictionary> initialConstraints = new Dictionary>(); + initialConstraints[initialState] = new HashSet(new int[] { 1 }); + foreach (var finalState in finalStates) + { + initialConstraints[finalState] = new HashSet(new int[] { 0 }); + } + SimulationRelation x = new SimulationRelation(implEdges, BSpec, initialConstraints); + Dictionary> simulationRelation = x.ComputeSimulationRelation(); + if (simulationRelation[initialState].Count == 0) + { + civlTypeChecker.Error(impl, string.Format("Implementation {0} fails simulation check B at layer {1}. An action must be succeeded by a yield.\n", impl.Name, currLayerNum)); + } + } + + private void CSpecCheck(List> implEdges) + { + Dictionary> initialConstraints = new Dictionary>(); + foreach (Block block in loopHeaders) + { + if (!IsTerminatingLoopHeader(block)) + { + initialConstraints[absyToNode[block]] = new HashSet(new int[] { 0 }); + } + } + SimulationRelation x = new SimulationRelation(implEdges, CSpec, initialConstraints); + Dictionary> simulationRelation = x.ComputeSimulationRelation(); + if (simulationRelation[initialState].Count == 0) + { + civlTypeChecker.Error(impl, string.Format("Implementation {0} fails simulation check C at layer {1}. Transactions must be separated by a yield.\n", impl.Name, currLayerNum)); + } + } + + private bool IsTerminatingLoopHeader(Block block) + { + foreach (Cmd cmd in block.Cmds) + { + AssertCmd assertCmd = cmd as AssertCmd; + if (assertCmd != null && QKeyValue.FindBoolAttribute(assertCmd.Attributes, "terminates") && civlTypeChecker.absyToLayerNums[assertCmd].Contains(currLayerNum)) + { + return true; + } + } + return false; + } + + public static void PerformYieldSafeCheck(CivlTypeChecker civlTypeChecker) + { + foreach (var impl in civlTypeChecker.program.Implementations) + { + if (!civlTypeChecker.procToActionInfo.ContainsKey(impl.Proc)) continue; + impl.PruneUnreachableBlocks(); + Graph implGraph = Program.GraphFromImpl(impl); + implGraph.ComputeLoops(); + int specLayerNum = civlTypeChecker.procToActionInfo[impl.Proc].createdAtLayerNum; + foreach (int layerNum in civlTypeChecker.AllLayerNums) + { + if (layerNum > specLayerNum) continue; + YieldTypeChecker executor = new YieldTypeChecker(civlTypeChecker, impl, layerNum, implGraph.Headers); + } + } + } + + int stateCounter; + CivlTypeChecker civlTypeChecker; + Implementation impl; + int currLayerNum; + Dictionary absyToNode; + Dictionary nodeToAbsy; + int initialState; + HashSet finalStates; + Dictionary, int> edgeLabels; + IEnumerable loopHeaders; + + private YieldTypeChecker(CivlTypeChecker civlTypeChecker, Implementation impl, int currLayerNum, IEnumerable loopHeaders) + { + this.civlTypeChecker = civlTypeChecker; + this.impl = impl; + this.currLayerNum = currLayerNum; + this.loopHeaders = loopHeaders; + this.stateCounter = 0; + this.absyToNode = new Dictionary(); + this.initialState = 0; + this.finalStates = new HashSet(); + this.edgeLabels = new Dictionary, int>(); + + foreach (Block block in impl.Blocks) + { + absyToNode[block] = stateCounter; + stateCounter++; + foreach (Cmd cmd in block.Cmds) + { + absyToNode[cmd] = stateCounter; + stateCounter++; + } + absyToNode[block.TransferCmd] = stateCounter; + stateCounter++; + if (block.TransferCmd is ReturnCmd) + { + finalStates.Add(absyToNode[block.TransferCmd]); + } + } + foreach (Block block in impl.Blocks) + { + Absy blockEntry = block.Cmds.Count == 0 ? (Absy)block.TransferCmd : (Absy)block.Cmds[0]; + edgeLabels[new Tuple(absyToNode[block], absyToNode[blockEntry])] = 'P'; + + GotoCmd gotoCmd = block.TransferCmd as GotoCmd; + if (gotoCmd == null) continue; + foreach (Block successor in gotoCmd.labelTargets) + { + edgeLabels[new Tuple(absyToNode[gotoCmd], absyToNode[successor])] = 'P'; + } + } + + this.nodeToAbsy = new Dictionary(); + foreach (KeyValuePair state in absyToNode) + { + this.nodeToAbsy[state.Value] = state.Key; + } + + ComputeGraph(); + IsYieldTypeSafe(); + } + + private void ComputeGraph() + { + foreach (Block block in impl.Blocks) + { + for (int i = 0; i < block.Cmds.Count; i++) + { + Cmd cmd = block.Cmds[i]; + int curr = absyToNode[cmd]; + int next = (i + 1 == block.Cmds.Count) ? absyToNode[block.TransferCmd] : absyToNode[block.Cmds[i + 1]]; + Tuple edge = new Tuple(curr, next); + if (cmd is CallCmd) + { + CallCmd callCmd = cmd as CallCmd; + if (callCmd.IsAsync) + { + ActionInfo actionInfo = civlTypeChecker.procToActionInfo[callCmd.Proc]; + if (currLayerNum <= actionInfo.createdAtLayerNum) + edgeLabels[edge] = 'L'; + else + edgeLabels[edge] = 'B'; + } + else if (!civlTypeChecker.procToActionInfo.ContainsKey(callCmd.Proc)) + { + edgeLabels[edge] = 'P'; + } + else + { + MoverType moverType; + ActionInfo actionInfo = civlTypeChecker.procToActionInfo[callCmd.Proc]; + if (actionInfo.createdAtLayerNum >= currLayerNum) + { + moverType = MoverType.Top; + } + else + { + AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; + if (atomicActionInfo == null) + moverType = MoverType.Both; + else + moverType = atomicActionInfo.moverType; + } + switch (moverType) + { + case MoverType.Atomic: + edgeLabels[edge] = 'A'; + break; + case MoverType.Both: + edgeLabels[edge] = 'B'; + break; + case MoverType.Left: + edgeLabels[edge] = 'L'; + break; + case MoverType.Right: + edgeLabels[edge] = 'R'; + break; + case MoverType.Top: + edgeLabels[edge] = 'Y'; + break; + } + } + } + else if (cmd is ParCallCmd) + { + ParCallCmd parCallCmd = cmd as ParCallCmd; + bool isYield = false; + bool isRightMover = true; + bool isLeftMover = true; + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + if (civlTypeChecker.procToActionInfo[callCmd.Proc].createdAtLayerNum >= currLayerNum) + { + isYield = true; + } + } + if (isYield) + { + edgeLabels[edge] = 'Y'; + } + else + { + int numAtomicActions = 0; + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + ActionInfo actionInfo = civlTypeChecker.procToActionInfo[callCmd.Proc]; + isRightMover = isRightMover && actionInfo.IsRightMover; + isLeftMover = isLeftMover && actionInfo.IsLeftMover; + if (actionInfo is AtomicActionInfo) + { + numAtomicActions++; + } + } + if (isLeftMover && isRightMover) + { + edgeLabels[edge] = 'B'; + } + else if (isLeftMover) + { + edgeLabels[edge] = 'L'; + } + else if (isRightMover) + { + edgeLabels[edge] = 'R'; + } + else + { + Debug.Assert(numAtomicActions == 1); + edgeLabels[edge] = 'A'; + } + } + } + else if (cmd is YieldCmd) + { + edgeLabels[edge] = 'Y'; + } + else + { + edgeLabels[edge] = 'P'; + } + } + } + } + + private static string PrintGraph(Implementation impl, List> edges, int initialState, HashSet finalStates) + { + var s = new StringBuilder(); + s.AppendLine("\nImplementation " + impl.Proc.Name + " digraph G {"); + foreach (var e in edges) + { + string label = "P"; + switch (e.Item2) + { + case 'P': label = "P"; break; + case 'Y': label = "Y"; break; + case 'B': label = "B"; break; + case 'R': label = "R"; break; + case 'L': label = "L"; break; + case 'A': label = "A"; break; + default: Debug.Assert(false); break; + } + s.AppendLine(" \"" + e.Item1.ToString() + "\" -- " + label + " --> " + " \"" + e.Item3.ToString() + "\";"); + } + s.AppendLine("}"); + s.AppendLine("Initial state: " + initialState); + s.Append("Final states: "); + bool first = true; + foreach (int finalState in finalStates) + { + s.Append((first ? "" : ", ") + finalState); + first = false; + } + s.AppendLine(); + return s.ToString(); + } + } +} diff --git a/Source/Core/Absy.cs b/Source/Core/Absy.cs index a1a54024..8a8558bf 100644 --- a/Source/Core/Absy.cs +++ b/Source/Core/Absy.cs @@ -1,4456 +1,4529 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -//--------------------------------------------------------------------------------------------- -// BoogiePL - Absy.cs -//--------------------------------------------------------------------------------------------- -namespace Microsoft.Boogie.AbstractInterpretation { - using System.Diagnostics; - using System.Diagnostics.Contracts; - using System.Collections; - using System.Collections.Generic; - using System.Linq; - - public class CallSite { - public readonly Implementation/*!*/ Impl; - public readonly Block/*!*/ Block; - public readonly int Statement; // invariant: Block[Statement] is CallCmd - public readonly ProcedureSummaryEntry/*!*/ SummaryEntry; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Impl != null); - Contract.Invariant(Block != null); - Contract.Invariant(SummaryEntry != null); - } - - - public CallSite(Implementation impl, Block b, int stmt, ProcedureSummaryEntry summaryEntry) { - Contract.Requires(summaryEntry != null); - Contract.Requires(b != null); - Contract.Requires(impl != null); - this.Impl = impl; - this.Block = b; - this.Statement = stmt; - this.SummaryEntry = summaryEntry; - } - } - - public class ProcedureSummaryEntry { - - private HashSet/*!*/ _returnPoints; // whenever OnExit changes, we start analysis again at all the ReturnPoints - - public HashSet/*!*/ ReturnPoints { - get { - Contract.Ensures(Contract.Result>() != null); - return this._returnPoints; - } - set { - Contract.Requires(value != null); - this._returnPoints = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._returnPoints != null); - } - - public ProcedureSummaryEntry() { - this._returnPoints = new HashSet(); - } - - } // class - - public class ProcedureSummary : ArrayList/**/ - { - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant( - !IsReadOnly && !IsFixedSize); - } - - public new ProcedureSummaryEntry/*!*/ this[int i] { - get { - Contract.Requires(0 <= i && i < Count); - Contract.Ensures(Contract.Result() != null); - return cce.NonNull((ProcedureSummaryEntry/*!*/)base[i]); - } - } - - } // class -} // namespace - -namespace Microsoft.Boogie { - using System; - using System.Linq; - using System.Collections; - using System.Diagnostics; - using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Diagnostics.Contracts; - using Microsoft.Boogie.AbstractInterpretation; - using Microsoft.Boogie.GraphUtil; - using Set = GSet; - - [ContractClass(typeof(AbsyContracts))] - public abstract class Absy { - private IToken/*!*/ _tok; - private int uniqueId; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._tok != null); - } - - public IToken tok { //Rename this property and "_tok" if possible - get { - Contract.Ensures(Contract.Result() != null); - return this._tok; - } - set { - Contract.Requires(value != null); - this._tok = value; - } - } - - public int Line { - get { - return tok != null ? tok.line : -1; - } - } - public int Col { - get { - return tok != null ? tok.col : -1; - } - } - - public Absy(IToken tok) { - Contract.Requires(tok != null); - this._tok = tok; - this.uniqueId = System.Threading.Interlocked.Increment(ref CurrentAbsyNodeId); - } - - private static int CurrentAbsyNodeId = -1; - - // We uniquely number every AST node to make them - // suitable for our implementation of functional maps. - // - public int UniqueId { - get { - return this.uniqueId; - } - } - - private const int indent_size = 2; - protected static string Indent(int level) { - return new string(' ', (indent_size * level)); - } - [NeedsContracts] - public abstract void Resolve(ResolutionContext/*!*/ rc); - - /// - /// Requires the object to have been successfully resolved. - /// - /// - [NeedsContracts] - public abstract void Typecheck(TypecheckingContext/*!*/ tc); - /// - /// Intorduced this so the uniqueId is not the same on a cloned object. - /// - /// - public virtual Absy Clone() { - Contract.Ensures(Contract.Result() != null); - Absy/*!*/ result = cce.NonNull((Absy/*!*/)this.MemberwiseClone()); - result.uniqueId = System.Threading.Interlocked.Increment(ref CurrentAbsyNodeId); // BUGBUG?? - - if (InternalNumberedMetadata != null) { - // This should probably use the lock - result.InternalNumberedMetadata = new List(this.InternalNumberedMetadata); - } - - return result; - } - - public virtual Absy StdDispatch(StandardVisitor visitor) { - Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - System.Diagnostics.Debug.Fail("Unknown Absy node type: " + this.GetType()); - throw new System.NotImplementedException(); - } - - #region numberedmetadata - // Implementation of Numbered Metadata - // This allows any number of arbitrary objects to be - // associated with an instance of an Absy at run time - // in a type safe manner using an integer as a key. - - // We could use a dictionary but we use a List for look up speed - // For this to work well the user needs to use small integers as - // keys. The list is created lazily to minimise memory overhead. - private volatile List InternalNumberedMetadata = null; - - // The lock exists to ensure that InternalNumberedMetadata is a singleton - // for every instance of this class. - // It is static to minimise the memory overhead (we don't want a lock per instance). - private static readonly Object NumberedMetadataLock = new object(); - - /// - /// Gets the number of meta data objects associated with this instance - /// - /// The numbered meta data count. - public int NumberedMetaDataCount - { - get { return InternalNumberedMetadata == null? 0: InternalNumberedMetadata.Count; } - } - - /// - /// Gets an IEnumerable over the numbered metadata associated - /// with this instance. - /// - /// - /// The numbered meta data enumerable that looks like the Enumerable - /// of a dictionary. - /// - public IEnumerable> NumberedMetadata - { - get { - if (InternalNumberedMetadata == null) - return Enumerable.Empty>(); - else - return InternalNumberedMetadata.Select((v, index) => new KeyValuePair(index, v)); - } - } - - /// - /// Gets the metatdata at specified index. - /// ArgumentOutOfRange exception is raised if it is not available. - /// InvalidCastExcpetion is raised if the metadata is available but the wrong type was requested. - /// - /// The stored metadata of type T - /// The index of the metadata - /// The type of the metadata object required - public T GetMetadata(int index) { - // We aren't using NumberedMetadataLock for speed. Perhaps we should be using it? - if (InternalNumberedMetadata == null) - throw new ArgumentOutOfRangeException(); - - if (InternalNumberedMetadata[index] is T) - return (T) InternalNumberedMetadata[index]; - else if (InternalNumberedMetadata[index] == null) { - throw new InvalidCastException("Numbered metadata " + index + - " is null which cannot be casted to " + typeof(T)); - } - else { - throw new InvalidCastException("Numbered metadata " + index + - " is of type " + InternalNumberedMetadata[index].GetType() + - " rather than requested type " + typeof(T)); - } - } - - private void InitialiseNumberedMetadata() { - // Ensure InternalNumberedMetadata is a singleton - if (InternalNumberedMetadata == null) { - lock (NumberedMetadataLock) { - if (InternalNumberedMetadata == null) - InternalNumberedMetadata = new List(); - } - } - } - - /// - /// Sets the metadata for this instace at a specified index. - /// - /// The index of the metadata - /// The value to set - /// The type of value - public void SetMetadata(int index, T value) { - InitialiseNumberedMetadata(); - - if (index < 0) - throw new IndexOutOfRangeException(); - - lock (NumberedMetadataLock) { - if (index < InternalNumberedMetadata.Count) - InternalNumberedMetadata[index] = value; - else { - // Make sure expansion only happens once whilst we pad - if (InternalNumberedMetadata.Capacity <= index) { - // Use the next available power of 2 - InternalNumberedMetadata.Capacity = (int) Math.Pow(2, Math.Ceiling(Math.Log(index+1,2))); - } - - // Pad with nulls - while (InternalNumberedMetadata.Count < index) - InternalNumberedMetadata.Add (null); - - InternalNumberedMetadata.Add(value); - Debug.Assert(InternalNumberedMetadata.Count == (index + 1)); - } - } - } - - #endregion - - } - - [ContractClassFor(typeof(Absy))] - public abstract class AbsyContracts : Absy { - public override void Resolve(ResolutionContext rc) { - Contract.Requires(rc != null); - throw new NotImplementedException(); - } - public AbsyContracts() :base(null){ - - } - public override void Typecheck(TypecheckingContext tc) { - Contract.Requires(tc != null); - throw new NotImplementedException(); - } - } - - public interface IPotentialErrorNode - { - TGet ErrorData - { - get; - } - } - - public interface IPotentialErrorNode : IPotentialErrorNode - { - new TSet ErrorData - { - set; - } - } - - public class Program : Absy { - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(cce.NonNullElements(this.topLevelDeclarations)); - Contract.Invariant(cce.NonNullElements(this.globalVariablesCache, true)); - } - - public Program() - : base(Token.NoToken) { - this.topLevelDeclarations = new List(); - } - - public void Emit(TokenTextWriter stream) { - Contract.Requires(stream != null); - stream.SetToken(this); - this.topLevelDeclarations.Emit(stream); - } - - public void ProcessDatatypeConstructors() { - Dictionary constructors = new Dictionary(); - List prunedTopLevelDeclarations = new List(); - foreach (Declaration decl in TopLevelDeclarations) { - Function func = decl as Function; - if (func == null || !QKeyValue.FindBoolAttribute(decl.Attributes, "constructor")) { - prunedTopLevelDeclarations.Add(decl); - continue; - } - if (constructors.ContainsKey(func.Name)) continue; - DatatypeConstructor constructor = new DatatypeConstructor(func); - constructors.Add(func.Name, constructor); - prunedTopLevelDeclarations.Add(constructor); - } - ClearTopLevelDeclarations(); - AddTopLevelDeclarations(prunedTopLevelDeclarations); - - foreach (DatatypeConstructor f in constructors.Values) { - for (int i = 0; i < f.InParams.Count; i++) { - DatatypeSelector selector = new DatatypeSelector(f, i); - f.selectors.Add(selector); - AddTopLevelDeclaration(selector); - } - DatatypeMembership membership = new DatatypeMembership(f); - f.membership = membership; - AddTopLevelDeclaration(membership); - } - } - - /// - /// Returns the number of name resolution errors. - /// - /// - public int Resolve() { - return Resolve((IErrorSink)null); - } - - public int Resolve(IErrorSink errorSink) { - ResolutionContext rc = new ResolutionContext(errorSink); - Resolve(rc); - return rc.ErrorCount; - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - Helpers.ExtraTraceInformation("Starting resolution"); - - foreach (var d in TopLevelDeclarations) { - d.Register(rc); - } - - ResolveTypes(rc); - - var prunedTopLevelDecls = new List(); - foreach (var d in TopLevelDeclarations) { - if (QKeyValue.FindBoolAttribute(d.Attributes, "ignore")) { - continue; - } - // resolve all the non-type-declarations - if (!(d is TypeCtorDecl || d is TypeSynonymDecl)) { - int e = rc.ErrorCount; - d.Resolve(rc); - if (CommandLineOptions.Clo.OverlookBoogieTypeErrors && rc.ErrorCount != e && d is Implementation) { - // ignore this implementation - System.Console.WriteLine("Warning: Ignoring implementation {0} because of translation resolution errors", ((Implementation)d).Name); - rc.ErrorCount = e; - continue; - } - } - prunedTopLevelDecls.Add(d); - } - ClearTopLevelDeclarations(); - AddTopLevelDeclarations(prunedTopLevelDecls); - - foreach (var v in Variables) { - v.ResolveWhere(rc); - } - } - - private void ResolveTypes(ResolutionContext rc) { - Contract.Requires(rc != null); - // first resolve type constructors - foreach (var d in TopLevelDeclarations.OfType()) { - if (!QKeyValue.FindBoolAttribute(d.Attributes, "ignore")) - d.Resolve(rc); - } - - // collect type synonym declarations - List/*!*/ synonymDecls = new List(); - foreach (var d in TopLevelDeclarations.OfType()) { - Contract.Assert(d != null); - if (!QKeyValue.FindBoolAttribute(d.Attributes, "ignore")) - synonymDecls.Add((TypeSynonymDecl)d); - } - - // then resolve the type synonyms by a simple - // fixed-point iteration - TypeSynonymDecl.ResolveTypeSynonyms(synonymDecls, rc); - } - - public int Typecheck() { - return this.Typecheck((IErrorSink)null); - } - - public int Typecheck(IErrorSink errorSink) { - TypecheckingContext tc = new TypecheckingContext(errorSink); - Typecheck(tc); - return tc.ErrorCount; - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - Helpers.ExtraTraceInformation("Starting typechecking"); - - int oldErrorCount = tc.ErrorCount; - foreach (var d in TopLevelDeclarations) { - d.Typecheck(tc); - } - - if (oldErrorCount == tc.ErrorCount) { - // check whether any type proxies have remained uninstantiated - TypeAmbiguitySeeker/*!*/ seeker = new TypeAmbiguitySeeker(tc); - foreach (var d in TopLevelDeclarations) { - seeker.Visit(d); - } - } - } - - public override Absy Clone() - { - var cloned = (Program)base.Clone(); - cloned.topLevelDeclarations = new List(); - cloned.AddTopLevelDeclarations(topLevelDeclarations); - return cloned; - } - - [Rep] - private List/*!*/ topLevelDeclarations; - - public IEnumerable TopLevelDeclarations - { - get - { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return topLevelDeclarations.AsReadOnly(); - } - - set - { - Contract.Requires(value != null); - // materialize the decls, in case there is any dependency - // back on topLevelDeclarations - var v = value.ToList(); - // remove null elements - v.RemoveAll(d => (d == null)); - // now clear the decls - ClearTopLevelDeclarations(); - // and add the values - AddTopLevelDeclarations(v); - } - } - - public void AddTopLevelDeclaration(Declaration decl) - { - Contract.Requires(!TopLevelDeclarationsAreFrozen); - Contract.Requires(decl != null); - - topLevelDeclarations.Add(decl); - this.globalVariablesCache = null; - } - - public void AddTopLevelDeclarations(IEnumerable decls) - { - Contract.Requires(!TopLevelDeclarationsAreFrozen); - Contract.Requires(cce.NonNullElements(decls)); - - topLevelDeclarations.AddRange(decls); - this.globalVariablesCache = null; - } - - public void RemoveTopLevelDeclaration(Declaration decl) - { - Contract.Requires(!TopLevelDeclarationsAreFrozen); - - topLevelDeclarations.Remove(decl); - this.globalVariablesCache = null; - } - - public void RemoveTopLevelDeclarations(Predicate match) - { - Contract.Requires(!TopLevelDeclarationsAreFrozen); - - topLevelDeclarations.RemoveAll(match); - this.globalVariablesCache = null; - } - - public void ClearTopLevelDeclarations() - { - Contract.Requires(!TopLevelDeclarationsAreFrozen); - - topLevelDeclarations.Clear(); - this.globalVariablesCache = null; - } - - bool topLevelDeclarationsAreFrozen; - public bool TopLevelDeclarationsAreFrozen { get { return topLevelDeclarationsAreFrozen; } } - public void FreezeTopLevelDeclarations() - { - topLevelDeclarationsAreFrozen = true; - } - - Dictionary implementationsCache; - public IEnumerable Implementations - { - get - { - if (implementationsCache != null) - { - return implementationsCache.Values; - } - var result = TopLevelDeclarations.OfType(); - if (topLevelDeclarationsAreFrozen) - { - implementationsCache = result.ToDictionary(p => p.Id); - } - return result; - } - } - - public Implementation FindImplementation(string id) - { - Implementation result = null; - if (implementationsCache != null && implementationsCache.TryGetValue(id, out result)) - { - return result; - } - else - { - return Implementations.FirstOrDefault(i => i.Id == id); - } - } - - List axiomsCache; - public IEnumerable Axioms - { - get - { - if (axiomsCache != null) - { - return axiomsCache; - } - var result = TopLevelDeclarations.OfType(); - if (topLevelDeclarationsAreFrozen) - { - axiomsCache = result.ToList(); - } - return result; - } - } - - Dictionary proceduresCache; - public IEnumerable Procedures - { - get - { - if (proceduresCache != null) - { - return proceduresCache.Values; - } - var result = TopLevelDeclarations.OfType(); - if (topLevelDeclarationsAreFrozen) - { - proceduresCache = result.ToDictionary(p => p.Name); - } - return result; - } - } - - public Procedure FindProcedure(string name) - { - Procedure result = null; - if (proceduresCache != null && proceduresCache.TryGetValue(name, out result)) - { - return result; - } - else - { - return Procedures.FirstOrDefault(p => p.Name == name); - } - } - - Dictionary functionsCache; - public IEnumerable Functions - { - get - { - if (functionsCache != null) - { - return functionsCache.Values; - } - var result = TopLevelDeclarations.OfType(); - if (topLevelDeclarationsAreFrozen) - { - functionsCache = result.ToDictionary(f => f.Name); - } - return result; - } - } - - public Function FindFunction(string name) - { - Function result = null; - if (functionsCache != null && functionsCache.TryGetValue(name, out result)) - { - return result; - } - else - { - return Functions.FirstOrDefault(f => f.Name == name); - } - } - - public IEnumerable Variables - { - get - { - return TopLevelDeclarations.OfType(); - } - } - - public IEnumerable Constants - { - get - { - return TopLevelDeclarations.OfType(); - } - } - - private IEnumerable globalVariablesCache = null; - public List/*!*/ GlobalVariables - { - get - { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - - if (globalVariablesCache == null) - globalVariablesCache = TopLevelDeclarations.OfType(); - - return new List(globalVariablesCache); - } - } - - public IEnumerable Blocks() - { - return Implementations.Select(Item => Item.Blocks).SelectMany(Item => Item); - } - - public void ComputeStronglyConnectedComponents() { - foreach (var d in this.TopLevelDeclarations) { - d.ComputeStronglyConnectedComponents(); - } - } - - /// - /// Reset the abstract stated computed before - /// - public void ResetAbstractInterpretationState() { - foreach (var d in this.TopLevelDeclarations) { - d.ResetAbstractInterpretationState(); - } - } - - public void UnrollLoops(int n, bool uc) { - Contract.Requires(0 <= n); - foreach (var impl in Implementations) { - if (impl.Blocks != null && impl.Blocks.Count > 0) { - cce.BeginExpose(impl); - { - Block start = impl.Blocks[0]; - Contract.Assume(start != null); - Contract.Assume(cce.IsConsistent(start)); - impl.Blocks = LoopUnroll.UnrollLoops(start, n, uc); - impl.FreshenCaptureStates(); - } - cce.EndExpose(); - } - } - } - - void CreateProceduresForLoops(Implementation impl, Graph/*!*/ g, - List/*!*/ loopImpls, - Dictionary> fullMap) { - Contract.Requires(impl != null); - Contract.Requires(cce.NonNullElements(loopImpls)); - // Enumerate the headers - // for each header h: - // create implementation p_h with - // inputs = inputs, outputs, and locals of impl - // outputs = outputs and locals of impl - // locals = empty set - // add call o := p_h(i) at the beginning of the header block - // break the back edges whose target is h - // Enumerate the headers again to create the bodies of p_h - // for each header h: - // compute the loop corresponding to h - // make copies of all blocks in the loop for h - // delete all target edges that do not go to a block in the loop - // create a new entry block and a new return block - // add edges from entry block to the loop header and the return block - // add calls o := p_h(i) at the end of the blocks that are sources of back edges - foreach (Block block in impl.Blocks) - { - AddToFullMap(fullMap, impl.Name, block.Label, block); - } - - bool detLoopExtract = CommandLineOptions.Clo.DeterministicExtractLoops; - - Dictionary/*!*/>/*!*/ loopHeaderToInputs = new Dictionary/*!*/>(); - Dictionary/*!*/>/*!*/ loopHeaderToOutputs = new Dictionary/*!*/>(); - Dictionary/*!*/>/*!*/ loopHeaderToSubstMap = new Dictionary/*!*/>(); - Dictionary/*!*/ loopHeaderToLoopProc = new Dictionary(); - Dictionary/*!*/ loopHeaderToCallCmd1 = new Dictionary(); - Dictionary loopHeaderToCallCmd2 = new Dictionary(); - Dictionary loopHeaderToAssignCmd = new Dictionary(); - - foreach (Block/*!*/ header in g.Headers) { - Contract.Assert(header != null); - Contract.Assert(header != null); - List inputs = new List(); - List outputs = new List(); - List callInputs1 = new List(); - List callOutputs1 = new List(); - List callInputs2 = new List(); - List callOutputs2 = new List(); - List lhss = new List(); - List rhss = new List(); - Dictionary substMap = new Dictionary(); // Variable -> IdentifierExpr - - List/*!*/ targets = new List(); - HashSet footprint = new HashSet(); - - foreach (Block/*!*/ b in g.BackEdgeNodes(header)) - { - Contract.Assert(b != null); - foreach (Block/*!*/ block in g.NaturalLoops(header, b)) - { - Contract.Assert(block != null); - foreach (Cmd/*!*/ cmd in block.Cmds) - { - Contract.Assert(cmd != null); - cmd.AddAssignedVariables(targets); - - VariableCollector c = new VariableCollector(); - c.Visit(cmd); - footprint.UnionWith(c.usedVars); - } - } - } - - List/*!*/ globalMods = new List(); - Set targetSet = new Set(); - foreach (Variable/*!*/ v in targets) - { - Contract.Assert(v != null); - if (targetSet.Contains(v)) - continue; - targetSet.Add(v); - if (v is GlobalVariable) - globalMods.Add(new IdentifierExpr(Token.NoToken, v)); - } - - foreach (Variable v in impl.InParams) { - Contract.Assert(v != null); - if (!footprint.Contains(v)) continue; - callInputs1.Add(new IdentifierExpr(Token.NoToken, v)); - Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "in_" + v.Name, v.TypedIdent.Type), true); - inputs.Add(f); - callInputs2.Add(new IdentifierExpr(Token.NoToken, f)); - substMap[v] = new IdentifierExpr(Token.NoToken, f); - } - foreach (Variable v in impl.OutParams) { - Contract.Assert(v != null); - if (!footprint.Contains(v)) continue; - callInputs1.Add(new IdentifierExpr(Token.NoToken, v)); - Formal f1 = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "in_" + v.Name, v.TypedIdent.Type), true); - inputs.Add(f1); - if (targetSet.Contains(v)) - { - callOutputs1.Add(new IdentifierExpr(Token.NoToken, v)); - Formal f2 = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "out_" + v.Name, v.TypedIdent.Type), false); - outputs.Add(f2); - callInputs2.Add(new IdentifierExpr(Token.NoToken, f2)); - callOutputs2.Add(new IdentifierExpr(Token.NoToken, f2)); - lhss.Add(new SimpleAssignLhs(Token.NoToken, new IdentifierExpr(Token.NoToken, f2))); - rhss.Add(new IdentifierExpr(Token.NoToken, f1)); - substMap[v] = new IdentifierExpr(Token.NoToken, f2); - } - else - { - callInputs2.Add(new IdentifierExpr(Token.NoToken, f1)); - substMap[v] = new IdentifierExpr(Token.NoToken, f1); - } - } - foreach (Variable v in impl.LocVars) { - Contract.Assert(v != null); - if (!footprint.Contains(v)) continue; - callInputs1.Add(new IdentifierExpr(Token.NoToken, v)); - Formal f1 = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "in_" + v.Name, v.TypedIdent.Type), true); - inputs.Add(f1); - if (targetSet.Contains(v)) - { - callOutputs1.Add(new IdentifierExpr(Token.NoToken, v)); - Formal f2 = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "out_" + v.Name, v.TypedIdent.Type), false); - outputs.Add(f2); - callInputs2.Add(new IdentifierExpr(Token.NoToken, f2)); - callOutputs2.Add(new IdentifierExpr(Token.NoToken, f2)); - lhss.Add(new SimpleAssignLhs(Token.NoToken, new IdentifierExpr(Token.NoToken, f2))); - rhss.Add(new IdentifierExpr(Token.NoToken, f1)); - substMap[v] = new IdentifierExpr(Token.NoToken, f2); - } - else - { - callInputs2.Add(new IdentifierExpr(Token.NoToken, f1)); - substMap[v] = new IdentifierExpr(Token.NoToken, f1); - } - } - - loopHeaderToInputs[header] = inputs; - loopHeaderToOutputs[header] = outputs; - loopHeaderToSubstMap[header] = substMap; - LoopProcedure loopProc = new LoopProcedure(impl, header, inputs, outputs, globalMods); - loopHeaderToLoopProc[header] = loopProc; - - CallCmd callCmd1 = new CallCmd(Token.NoToken, loopProc.Name, callInputs1, callOutputs1); - callCmd1.Proc = loopProc; - loopHeaderToCallCmd1[header] = callCmd1; - - CallCmd callCmd2 = new CallCmd(Token.NoToken, loopProc.Name, callInputs2, callOutputs2); - callCmd2.Proc = loopProc; - loopHeaderToCallCmd2[header] = callCmd2; - - Debug.Assert(lhss.Count == rhss.Count); - if (lhss.Count > 0) - { - AssignCmd assignCmd = new AssignCmd(Token.NoToken, lhss, rhss); - loopHeaderToAssignCmd[header] = assignCmd; - } - } - - // Keep track of the new blocks created: maps a header node to the - // header_last block that was created because of splitting header. - Dictionary newBlocksCreated = new Dictionary(); - - bool headRecursion = false; // testing an option to put recursive call before loop body - - IEnumerable sortedHeaders = g.SortHeadersByDominance(); - foreach (Block/*!*/ header in sortedHeaders) - { - Contract.Assert(header != null); - LoopProcedure loopProc = loopHeaderToLoopProc[header]; - Dictionary blockMap = new Dictionary(); - HashSet dummyBlocks = new HashSet(); - - CodeCopier codeCopier = new CodeCopier(loopHeaderToSubstMap[header]); // fix me - List inputs = loopHeaderToInputs[header]; - List outputs = loopHeaderToOutputs[header]; - int si_unique_loc = 1; // Added by AL: to distinguish the back edges - foreach (Block/*!*/ source in g.BackEdgeNodes(header)) { - Contract.Assert(source != null); - foreach (Block/*!*/ block in g.NaturalLoops(header, source)) { - Contract.Assert(block != null); - if (blockMap.ContainsKey(block)) - continue; - Block newBlock = new Block(); - newBlock.Label = block.Label; - if (headRecursion && block == header) - { - CallCmd callCmd = (CallCmd)(loopHeaderToCallCmd2[header]).Clone(); - addUniqueCallAttr(si_unique_loc, callCmd); - si_unique_loc++; - newBlock.Cmds.Add(callCmd); // add the recursive call at head of loop - var rest = codeCopier.CopyCmdSeq(block.Cmds); - newBlock.Cmds.AddRange(rest); - } - else - newBlock.Cmds = codeCopier.CopyCmdSeq(block.Cmds); - blockMap[block] = newBlock; - if (newBlocksCreated.ContainsKey(block)) - { - Block newBlock2 = new Block(); - newBlock2.Label = newBlocksCreated[block].Label; - newBlock2.Cmds = codeCopier.CopyCmdSeq(newBlocksCreated[block].Cmds); - blockMap[newBlocksCreated[block]] = newBlock2; - } - //for detLoopExtract, need the immediate successors even outside the loop - if (detLoopExtract) { - GotoCmd auxGotoCmd = block.TransferCmd as GotoCmd; - Contract.Assert(auxGotoCmd != null && auxGotoCmd.labelNames != null && - auxGotoCmd.labelTargets != null && auxGotoCmd.labelTargets.Count >= 1); - foreach(var bl in auxGotoCmd.labelTargets) { - bool found = false; - foreach(var n in g.NaturalLoops(header, source)) { //very expensive, can we do a contains? - if (bl == n) { //clarify: is this the right comparison? - found = true; - break; - } - } - if (!found) { - Block auxNewBlock = new Block(); - auxNewBlock.Label = ((Block)bl).Label; - auxNewBlock.Cmds = codeCopier.CopyCmdSeq(((Block)bl).Cmds); - //add restoration code for such blocks - if (loopHeaderToAssignCmd.ContainsKey(header)) - { - AssignCmd assignCmd = loopHeaderToAssignCmd[header]; - auxNewBlock.Cmds.Add(assignCmd); - } - List lhsg = new List(); - List/*!*/ globalsMods = loopHeaderToLoopProc[header].Modifies; - foreach (IdentifierExpr gl in globalsMods) - lhsg.Add(new SimpleAssignLhs(Token.NoToken, gl)); - List rhsg = new List(); - foreach (IdentifierExpr gl in globalsMods) - rhsg.Add(new OldExpr(Token.NoToken, gl)); - if (lhsg.Count != 0) - { - AssignCmd globalAssignCmd = new AssignCmd(Token.NoToken, lhsg, rhsg); - auxNewBlock.Cmds.Add(globalAssignCmd); - } - blockMap[(Block)bl] = auxNewBlock; - } - } - - } - } - - List cmdSeq; - if (headRecursion) - cmdSeq = new List(); - else - { - CallCmd callCmd = (CallCmd)(loopHeaderToCallCmd2[header]).Clone(); - addUniqueCallAttr(si_unique_loc, callCmd); - si_unique_loc++; - cmdSeq = new List { callCmd }; - } - - Block/*!*/ block1 = new Block(Token.NoToken, source.Label + "_dummy", - new List{ new AssumeCmd(Token.NoToken, Expr.False) }, new ReturnCmd(Token.NoToken)); - Block/*!*/ block2 = new Block(Token.NoToken, block1.Label, - cmdSeq, new ReturnCmd(Token.NoToken)); - impl.Blocks.Add(block1); - dummyBlocks.Add(block1.Label); - - GotoCmd gotoCmd = source.TransferCmd as GotoCmd; - Contract.Assert(gotoCmd != null && gotoCmd.labelNames != null && gotoCmd.labelTargets != null && gotoCmd.labelTargets.Count >= 1); - List/*!*/ newLabels = new List(); - List/*!*/ newTargets = new List(); - for (int i = 0; i < gotoCmd.labelTargets.Count; i++) { - if (gotoCmd.labelTargets[i] == header) - continue; - newTargets.Add(gotoCmd.labelTargets[i]); - newLabels.Add(gotoCmd.labelNames[i]); - } - newTargets.Add(block1); - newLabels.Add(block1.Label); - gotoCmd.labelNames = newLabels; - gotoCmd.labelTargets = newTargets; - blockMap[block1] = block2; - } - List/*!*/ blocks = new List(); - Block exit = new Block(Token.NoToken, "exit", new List(), new ReturnCmd(Token.NoToken)); - GotoCmd cmd = new GotoCmd(Token.NoToken, - new List { cce.NonNull(blockMap[header]).Label, exit.Label }, - new List { blockMap[header], exit }); - - if (detLoopExtract) //cutting the non-determinism - cmd = new GotoCmd(Token.NoToken, - new List { cce.NonNull(blockMap[header]).Label }, - new List { blockMap[header] }); - - Block entry; - List initCmds = new List(); - if (loopHeaderToAssignCmd.ContainsKey(header)) { - AssignCmd assignCmd = loopHeaderToAssignCmd[header]; - initCmds.Add(assignCmd); - } - - entry = new Block(Token.NoToken, "entry", initCmds, cmd); - blocks.Add(entry); - - foreach (Block/*!*/ block in blockMap.Keys) { - Contract.Assert(block != null); - Block/*!*/ newBlock = cce.NonNull(blockMap[block]); - GotoCmd gotoCmd = block.TransferCmd as GotoCmd; - if (gotoCmd == null) { - newBlock.TransferCmd = new ReturnCmd(Token.NoToken); - } else { - Contract.Assume(gotoCmd.labelNames != null && gotoCmd.labelTargets != null); - List newLabels = new List(); - List newTargets = new List(); - for (int i = 0; i < gotoCmd.labelTargets.Count; i++) { - Block target = gotoCmd.labelTargets[i]; - if (blockMap.ContainsKey(target)) { - newLabels.Add(gotoCmd.labelNames[i]); - newTargets.Add(blockMap[target]); - } - } - if (newTargets.Count == 0) { - if (!detLoopExtract) - newBlock.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.False)); - newBlock.TransferCmd = new ReturnCmd(Token.NoToken); - } else { - newBlock.TransferCmd = new GotoCmd(Token.NoToken, newLabels, newTargets); - } - } - blocks.Add(newBlock); - } - blocks.Add(exit); - Implementation loopImpl = - new Implementation(Token.NoToken, loopProc.Name, - new List(), inputs, outputs, new List(), blocks); - loopImpl.Proc = loopProc; - loopImpls.Add(loopImpl); - - // Make a (shallow) copy of the header before splitting it - Block origHeader = new Block(header.tok, header.Label, header.Cmds, header.TransferCmd); - - // Finally, add call to the loop in the containing procedure - string lastIterBlockName = header.Label + "_last"; - Block lastIterBlock = new Block(Token.NoToken, lastIterBlockName, header.Cmds, header.TransferCmd); - newBlocksCreated[header] = lastIterBlock; - header.Cmds = new List { loopHeaderToCallCmd1[header] }; - header.TransferCmd = new GotoCmd(Token.NoToken, new List { lastIterBlockName }, new List { lastIterBlock }); - impl.Blocks.Add(lastIterBlock); - blockMap[origHeader] = blockMap[header]; - blockMap.Remove(header); - - Contract.Assert(fullMap[impl.Name][header.Label] == header); - fullMap[impl.Name][header.Label] = origHeader; - - foreach (Block block in blockMap.Keys) - { - // Don't add dummy blocks to the map - if (dummyBlocks.Contains(blockMap[block].Label)) continue; - - // Following two statements are for nested loops: compose map - if (!fullMap[impl.Name].ContainsKey(block.Label)) continue; - var target = fullMap[impl.Name][block.Label]; - - AddToFullMap(fullMap, loopProc.Name, blockMap[block].Label, target); - } - - fullMap[impl.Name].Remove(header.Label); - fullMap[impl.Name][lastIterBlockName] = origHeader; - } - } - - private void addUniqueCallAttr(int val, CallCmd cmd) - { - var a = new List(); - a.Add(new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(val))); - - cmd.Attributes = new QKeyValue(Token.NoToken, "si_unique_call", a, cmd.Attributes); - } - - private void AddToFullMap(Dictionary> fullMap, string procName, string blockName, Block block) - { - if (!fullMap.ContainsKey(procName)) - fullMap[procName] = new Dictionary(); - fullMap[procName][blockName] = block; - } - - public static Graph BuildCallGraph(Program program) { - Graph callGraph = new Graph(); - Dictionary> procToImpls = new Dictionary>(); - foreach (var proc in program.Procedures) { - procToImpls[proc] = new HashSet(); - } - foreach (var impl in program.Implementations) { - if (impl.SkipVerification) continue; - callGraph.AddSource(impl); - procToImpls[impl.Proc].Add(impl); - } - foreach (var impl in program.Implementations) { - if (impl.SkipVerification) continue; - foreach (Block b in impl.Blocks) { - foreach (Cmd c in b.Cmds) { - CallCmd cc = c as CallCmd; - if (cc == null) continue; - foreach (Implementation callee in procToImpls[cc.Proc]) { - callGraph.AddEdge(impl, callee); - } - } - } - } - return callGraph; - } - - public static Graph/*!*/ GraphFromImpl(Implementation impl) { - Contract.Requires(impl != null); - Contract.Ensures(cce.NonNullElements(Contract.Result>().Nodes)); - Contract.Ensures(Contract.Result>() != null); - - Graph g = new Graph(); - g.AddSource(impl.Blocks[0]); // there is always at least one node in the graph - - foreach (Block b in impl.Blocks) { - Contract.Assert(b != null); - GotoCmd gtc = b.TransferCmd as GotoCmd; - if (gtc != null) { - foreach (Block/*!*/ dest in cce.NonNull(gtc.labelTargets)) { - Contract.Assert(dest != null); - g.AddEdge(b, dest); - } - } - } - return g; - } - - public class IrreducibleLoopException : Exception {} - - public Graph ProcessLoops(Implementation impl) { - while (true) { - impl.PruneUnreachableBlocks(); - impl.ComputePredecessorsForBlocks(); - Graph/*!*/ g = GraphFromImpl(impl); - g.ComputeLoops(); - if (g.Reducible) { - return g; - } - throw new IrreducibleLoopException(); -#if USED_CODE - System.Diagnostics.Debug.Assert(g.SplitCandidates.Count > 0); - Block splitCandidate = null; - foreach (Block b in g.SplitCandidates) { - if (b.Predecessors.Length > 1) { - splitCandidate = b; - break; - } - } - System.Diagnostics.Debug.Assert(splitCandidate != null); - int count = 0; - foreach (Block b in splitCandidate.Predecessors) { - GotoCmd gotoCmd = (GotoCmd)b.TransferCmd; - gotoCmd.labelNames.Remove(splitCandidate.Label); - gotoCmd.labelTargets.Remove(splitCandidate); - - CodeCopier codeCopier = new CodeCopier(new Hashtable(), new Hashtable()); - List newCmdSeq = codeCopier.CopyCmdSeq(splitCandidate.Cmds); - TransferCmd newTransferCmd; - GotoCmd splitGotoCmd = splitCandidate.TransferCmd as GotoCmd; - if (splitGotoCmd == null) { - newTransferCmd = new ReturnCmd(splitCandidate.tok); - } - else { - List newLabelNames = new List(); - newLabelNames.AddRange(splitGotoCmd.labelNames); - List newLabelTargets = new List(); - newLabelTargets.AddRange(splitGotoCmd.labelTargets); - newTransferCmd = new GotoCmd(splitCandidate.tok, newLabelNames, newLabelTargets); - } - Block copy = new Block(splitCandidate.tok, splitCandidate.Label + count++, newCmdSeq, newTransferCmd); - - impl.Blocks.Add(copy); - gotoCmd.AddTarget(copy); - } -#endif - } - } - - public Dictionary> ExtractLoops() - { - HashSet procsWithIrreducibleLoops = null; - return ExtractLoops(out procsWithIrreducibleLoops); - } - - public Dictionary> ExtractLoops(out HashSet procsWithIrreducibleLoops) - { - procsWithIrreducibleLoops = new HashSet(); - List/*!*/ loopImpls = new List(); - Dictionary> fullMap = new Dictionary>(); - foreach (var impl in this.Implementations) - { - if (impl.Blocks != null && impl.Blocks.Count > 0) - { - try - { - Graph g = ProcessLoops(impl); - CreateProceduresForLoops(impl, g, loopImpls, fullMap); - } - catch (IrreducibleLoopException) - { - System.Diagnostics.Debug.Assert(!fullMap.ContainsKey(impl.Name)); - fullMap[impl.Name] = null; - procsWithIrreducibleLoops.Add(impl.Name); - - if (CommandLineOptions.Clo.ExtractLoopsUnrollIrreducible) - { - // statically unroll loops in this procedure - - // First, build a map of the current blocks - var origBlocks = new Dictionary(); - foreach (var blk in impl.Blocks) origBlocks.Add(blk.Label, blk); - - // unroll - Block start = impl.Blocks[0]; - impl.Blocks = LoopUnroll.UnrollLoops(start, CommandLineOptions.Clo.RecursionBound, false); - - // Now construct the "map back" information - // Resulting block label -> original block - var blockMap = new Dictionary(); - foreach (var blk in impl.Blocks) - { - var sl = LoopUnroll.sanitizeLabel(blk.Label); - if (sl == blk.Label) blockMap.Add(blk.Label, blk); - else - { - Contract.Assert(origBlocks.ContainsKey(sl)); - blockMap.Add(blk.Label, origBlocks[sl]); - } - } - fullMap[impl.Name] = blockMap; - } - } - } - } - foreach (Implementation/*!*/ loopImpl in loopImpls) - { - Contract.Assert(loopImpl != null); - AddTopLevelDeclaration(loopImpl); - AddTopLevelDeclaration(loopImpl.Proc); - } - return fullMap; - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitProgram(this); - } - - int extractedFunctionCount; - public string FreshExtractedFunctionName() - { - var c = System.Threading.Interlocked.Increment(ref extractedFunctionCount); - return string.Format("##extracted_function##{0}", c); - } - - private int invariantGenerationCounter = 0; - - public Constant MakeExistentialBoolean() { - Constant ExistentialBooleanConstant = new Constant(Token.NoToken, new TypedIdent(tok, "_b" + invariantGenerationCounter, Microsoft.Boogie.Type.Bool), false); - invariantGenerationCounter++; - ExistentialBooleanConstant.AddAttribute("existential", new object[] { Expr.True }); - AddTopLevelDeclaration(ExistentialBooleanConstant); - return ExistentialBooleanConstant; - } - - public PredicateCmd CreateCandidateInvariant(Expr e, string tag = null) { - Constant ExistentialBooleanConstant = MakeExistentialBoolean(); - IdentifierExpr ExistentialBoolean = new IdentifierExpr(Token.NoToken, ExistentialBooleanConstant); - PredicateCmd invariant = new AssertCmd(Token.NoToken, Expr.Imp(ExistentialBoolean, e)); - if (tag != null) - invariant.Attributes = new QKeyValue(Token.NoToken, "tag", new List(new object[] { tag }), null); - return invariant; - } - } - - //--------------------------------------------------------------------- - // Declarations - - [ContractClass(typeof(DeclarationContracts))] - public abstract class Declaration : Absy { - public QKeyValue Attributes; - - public Declaration(IToken tok) - : base(tok) { - Contract.Requires(tok != null); - } - - protected void EmitAttributes(TokenTextWriter stream) { - Contract.Requires(stream != null); - for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { - kv.Emit(stream); - stream.Write(" "); - } - } - - protected void ResolveAttributes(ResolutionContext rc) { - Contract.Requires(rc != null); - for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { - kv.Resolve(rc); - } - } - - protected void TypecheckAttributes(TypecheckingContext rc) { - Contract.Requires(rc != null); - for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { - kv.Typecheck(rc); - } - } - - /// - /// If the declaration has an attribute {:name} or {:name true}, then set "result" to "true" and return "true". - /// If the declaration has an attribute {:name false}, then set "result" to "false" and return "true". - /// Otherwise, return "false" and leave "result" unchanged (which gives the caller an easy way to indicate - /// a default value if the attribute is not mentioned). - /// If there is more than one attribute called :name, then the last attribute rules. - /// - public bool CheckBooleanAttribute(string name, ref bool result) { - Contract.Requires(name != null); - var kv = FindAttribute(name); - if (kv != null) { - if (kv.Params.Count == 0) { - result = true; - return true; - } else if (kv.Params.Count == 1) { - var lit = kv.Params[0] as LiteralExpr; - if (lit != null && lit.isBool) { - result = lit.asBool; - return true; - } - } - } - return false; - } - - /// - /// Find and return the last occurrence of an attribute with the name "name", if any. If none, return null. - /// - public QKeyValue FindAttribute(string name) { - Contract.Requires(name != null); - QKeyValue res = null; - for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { - if (kv.Key == name) { - res = kv; - } - } - return res; - } - - // Look for {:name expr} in list of attributes. - public Expr FindExprAttribute(string name) { - Contract.Requires(name != null); - Expr res = null; - for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { - if (kv.Key == name) { - if (kv.Params.Count == 1 && kv.Params[0] is Expr) { - res = (Expr)kv.Params[0]; - } - } - } - return res; - } - - // Look for {:name string} in list of attributes. - public string FindStringAttribute(string name) { - Contract.Requires(name != null); - return QKeyValue.FindStringAttribute(this.Attributes, name); - } - - // Look for {:name N} or {:name N} in list of attributes. Return result in 'result' - // (which is not touched if there is no attribute specified). - // - // Returns false is there was an error processing the flag, true otherwise. - public bool CheckIntAttribute(string name, ref int result) { - Contract.Requires(name != null); - Expr expr = FindExprAttribute(name); - if (expr != null) { - if (expr is LiteralExpr && ((LiteralExpr)expr).isBigNum) { - result = ((LiteralExpr)expr).asBigNum.ToInt; - } else { - return false; - } - } - return true; - } - - public void AddAttribute(string name, params object[] vals) { - Contract.Requires(name != null); - QKeyValue kv; - for (kv = this.Attributes; kv != null; kv = kv.Next) { - if (kv.Key == name) { - kv.AddParams(vals); - break; - } - } - if (kv == null) { - Attributes = new QKeyValue(tok, name, new List(vals), Attributes); - } - } - - public abstract void Emit(TokenTextWriter/*!*/ stream, int level); - public abstract void Register(ResolutionContext/*!*/ rc); - - /// - /// Compute the strongly connected components of the declaration. - /// By default, it does nothing - /// - public virtual void ComputeStronglyConnectedComponents() { /* Does nothing */ - } - - /// - /// Reset the abstract stated computed before - /// - public virtual void ResetAbstractInterpretationState() { /* does nothing */ - } - } - [ContractClassFor(typeof(Declaration))] - public abstract class DeclarationContracts : Declaration { - public DeclarationContracts() :base(null){ - } - public override void Register(ResolutionContext rc) { - Contract.Requires(rc != null); - throw new NotImplementedException(); - } - public override void Emit(TokenTextWriter stream, int level) { - Contract.Requires(stream != null); - throw new NotImplementedException(); - } - } - - public class Axiom : Declaration { - private Expr/*!*/ expression; - - public Expr Expr { - get { - Contract.Ensures(Contract.Result() != null); - return this.expression; - } - set { - Contract.Requires(value != null); - this.expression = value; - } - } - - [ContractInvariantMethod] - void ExprInvariant() { - Contract.Invariant(this.expression != null); - } - - public string Comment; - - public Axiom(IToken tok, Expr expr) - : this(tok, expr, null) { - Contract.Requires(expr != null); - Contract.Requires(tok != null); - } - - public Axiom(IToken/*!*/ tok, Expr/*!*/ expr, string comment) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - this.expression = expr; - Comment = comment; - } - - public Axiom(IToken tok, Expr expr, string comment, QKeyValue kv) - : this(tok, expr, comment) { - Contract.Requires(expr != null); - Contract.Requires(tok != null); - this.Attributes = kv; - } - - public bool DependenciesCollected { get; set; } - - ISet functionDependencies; - - public ISet FunctionDependencies - { - get { return functionDependencies; } - } - - public void AddFunctionDependency(Function function) - { - Contract.Requires(function != null); - - if (functionDependencies == null) - { - functionDependencies = new HashSet(); - } - functionDependencies.Add(function); - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - if (Comment != null) { - stream.WriteLine(this, level, "// " + Comment); - } - stream.Write(this, level, "axiom "); - EmitAttributes(stream); - this.Expr.Emit(stream); - stream.WriteLine(";"); - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddAxiom(this); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - ResolveAttributes(rc); - rc.StateMode = ResolutionContext.State.StateLess; - Expr.Resolve(rc); - rc.StateMode = ResolutionContext.State.Single; - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - TypecheckAttributes(tc); - Expr.Typecheck(tc); - Contract.Assert(Expr.Type != null); // follows from postcondition of Expr.Typecheck - if (!Expr.Type.Unify(Type.Bool)) { - tc.Error(this, "axioms must be of type bool"); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitAxiom(this); - } - } - - public abstract class NamedDeclaration : Declaration { - private string/*!*/ name; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(name != null); - } - - public string/*!*/ Name { - get { - Contract.Ensures(Contract.Result() != null); - - return this.name; - } - set { - Contract.Requires(value != null); - this.name = value; - } - } - - public int TimeLimit - { - get - { - int tl = CommandLineOptions.Clo.ProverKillTime; - CheckIntAttribute("timeLimit", ref tl); - return tl; - } - } - - public NamedDeclaration(IToken/*!*/ tok, string/*!*/ name) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - this.name = name; - } - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - return cce.NonNull(Name); - } - } - - public class TypeCtorDecl : NamedDeclaration { - public readonly int Arity; - - public TypeCtorDecl(IToken/*!*/ tok, string/*!*/ name, int Arity) - : base(tok, name) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - this.Arity = Arity; - } - public TypeCtorDecl(IToken/*!*/ tok, string/*!*/ name, int Arity, QKeyValue kv) - : base(tok, name) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - this.Arity = Arity; - this.Attributes = kv; - } - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, "type "); - EmitAttributes(stream); - stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(Name)); - for (int i = 0; i < Arity; ++i) - stream.Write(" _"); - stream.WriteLine(";"); - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddType(this); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - ResolveAttributes(rc); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - TypecheckAttributes(tc); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitTypeCtorDecl(this); - } - } - - public class TypeSynonymDecl : NamedDeclaration { - private List/*!*/ typeParameters; - - public List TypeParameters { - get { - Contract.Ensures(Contract.Result>() != null); - return this.typeParameters; - } - set { - Contract.Requires(value != null); - this.typeParameters = value; - } - } - - private Type/*!*/ body; - - public Type Body { - get { - Contract.Ensures(Contract.Result() != null); - return this.body; - } - set { - Contract.Requires(value != null); - this.body = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this.body != null); - Contract.Invariant(this.typeParameters != null); - } - - public TypeSynonymDecl(IToken/*!*/ tok, string/*!*/ name, - List/*!*/ typeParams, Type/*!*/ body) - : base(tok, name) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - Contract.Requires(typeParams != null); - Contract.Requires(body != null); - this.typeParameters = typeParams; - this.body = body; - } - public TypeSynonymDecl(IToken/*!*/ tok, string/*!*/ name, - List/*!*/ typeParams, Type/*!*/ body, QKeyValue kv) - : base(tok, name) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - Contract.Requires(typeParams != null); - Contract.Requires(body != null); - this.typeParameters = typeParams; - this.body = body; - this.Attributes = kv; - } - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, "type "); - EmitAttributes(stream); - stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(Name)); - if (TypeParameters.Count > 0) - stream.Write(" "); - TypeParameters.Emit(stream, " "); - stream.Write(" = "); - Body.Emit(stream); - stream.WriteLine(";"); - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddType(this); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - ResolveAttributes(rc); - - int previousState = rc.TypeBinderState; - try { - foreach (TypeVariable/*!*/ v in TypeParameters) { - Contract.Assert(v != null); - rc.AddTypeBinder(v); - } - Body = Body.ResolveType(rc); - } finally { - rc.TypeBinderState = previousState; - } - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - TypecheckAttributes(tc); - } - - public static void ResolveTypeSynonyms(List/*!*/ synonymDecls, ResolutionContext/*!*/ rc) { - Contract.Requires(cce.NonNullElements(synonymDecls)); - Contract.Requires(rc != null); - // then discover all dependencies between type synonyms - IDictionary/*!*/>/*!*/ deps = - new Dictionary/*!*/>(); - foreach (TypeSynonymDecl/*!*/ decl in synonymDecls) { - Contract.Assert(decl != null); - List/*!*/ declDeps = new List(); - FindDependencies(decl.Body, declDeps, rc); - deps.Add(decl, declDeps); - } - - List/*!*/ resolved = new List(); - - int unresolved = synonymDecls.Count - resolved.Count; - while (unresolved > 0) { - foreach (TypeSynonymDecl/*!*/ decl in synonymDecls) { - Contract.Assert(decl != null); - if (!resolved.Contains(decl) && - deps[decl].All(d => resolved.Contains(d))) { - decl.Resolve(rc); - resolved.Add(decl); - } - } - - int newUnresolved = synonymDecls.Count - resolved.Count; - if (newUnresolved < unresolved) { - // we are making progress - unresolved = newUnresolved; - } else { - // there have to be cycles in the definitions - foreach (TypeSynonymDecl/*!*/ decl in synonymDecls) { - Contract.Assert(decl != null); - if (!resolved.Contains(decl)) { - rc.Error(decl, - "type synonym could not be resolved because of cycles: {0}" + - " (replacing body with \"bool\" to continue resolving)", - decl.Name); - - // we simply replace the bodies of all remaining type - // synonyms with "bool" so that resolution can continue - decl.Body = Type.Bool; - decl.Resolve(rc); - } - } - - unresolved = 0; - } - } - } - - // determine a list of all type synonyms that occur in "type" - private static void FindDependencies(Type/*!*/ type, List/*!*/ deps, ResolutionContext/*!*/ rc) { - Contract.Requires(type != null); - Contract.Requires(cce.NonNullElements(deps)); - Contract.Requires(rc != null); - if (type.IsVariable || type.IsBasic) { - // nothing - } else if (type.IsUnresolved) { - UnresolvedTypeIdentifier/*!*/ unresType = type.AsUnresolved; - Contract.Assert(unresType != null); - TypeSynonymDecl dep = rc.LookUpTypeSynonym(unresType.Name); - if (dep != null) - deps.Add(dep); - foreach (Type/*!*/ subtype in unresType.Arguments) { - Contract.Assert(subtype != null); - FindDependencies(subtype, deps, rc); - } - } else if (type.IsMap) { - MapType/*!*/ mapType = type.AsMap; - Contract.Assert(mapType != null); - foreach (Type/*!*/ subtype in mapType.Arguments) { - Contract.Assert(subtype != null); - FindDependencies(subtype, deps, rc); - } - FindDependencies(mapType.Result, deps, rc); - } else if (type.IsCtor) { - // this can happen because we allow types to be resolved multiple times - CtorType/*!*/ ctorType = type.AsCtor; - Contract.Assert(ctorType != null); - foreach (Type/*!*/ subtype in ctorType.Arguments) { - Contract.Assert(subtype != null); - FindDependencies(subtype, deps, rc); - } - } else { - System.Diagnostics.Debug.Fail("Did not expect this type during resolution: " - + type); - } - } - - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitTypeSynonymDecl(this); - } - } - - public abstract class Variable : NamedDeclaration { - private TypedIdent/*!*/ typedIdent; - - public TypedIdent TypedIdent { - get { - Contract.Ensures(Contract.Result() != null); - return this.typedIdent; - } - set { - Contract.Requires(value != null); - this.typedIdent = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this.typedIdent != null); - } - - public Variable(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent) - : base(tok, typedIdent.Name) { - Contract.Requires(tok != null); - Contract.Requires(typedIdent != null); - this.typedIdent = typedIdent; - } - - public Variable(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent, QKeyValue kv) - : base(tok, typedIdent.Name) { - Contract.Requires(tok != null); - Contract.Requires(typedIdent != null); - this.typedIdent = typedIdent; - this.Attributes = kv; - } - - public abstract bool IsMutable { - get; - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, "var "); - EmitVitals(stream, level, true); - stream.WriteLine(";"); - } - public void EmitVitals(TokenTextWriter stream, int level, bool emitAttributes) { - Contract.Requires(stream != null); - if (emitAttributes) { - EmitAttributes(stream); - } - if (CommandLineOptions.Clo.PrintWithUniqueASTIds && this.TypedIdent.HasName) { - stream.Write("h{0}^^", this.GetHashCode()); // the idea is that this will prepend the name printed by TypedIdent.Emit - } - this.TypedIdent.Emit(stream); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - this.TypedIdent.Resolve(rc); - } - public void ResolveWhere(ResolutionContext rc) { - Contract.Requires(rc != null); - if (QKeyValue.FindBoolAttribute(Attributes, "assumption") && this.TypedIdent.WhereExpr != null) - { - rc.Error(tok, "assumption variable may not be declared with a where clause"); - } - if (this.TypedIdent.WhereExpr != null) { - this.TypedIdent.WhereExpr.Resolve(rc); - } - ResolveAttributes(rc); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - TypecheckAttributes(tc); - this.TypedIdent.Typecheck(tc); - if (QKeyValue.FindBoolAttribute(Attributes, "assumption") && !this.TypedIdent.Type.IsBool) - { - tc.Error(tok, "assumption variable must be of type 'bool'"); - } - } - } - - public class VariableComparer : IComparer { - public int Compare(object a, object b) { - Variable A = a as Variable; - Variable B = b as Variable; - if (A == null || B == null) { - throw new ArgumentException("VariableComparer works only on objects of type Variable"); - } - return cce.NonNull(A.Name).CompareTo(B.Name); - } - } - - // class to specify the <:-parents of the values of constants - public class ConstantParent { - public readonly IdentifierExpr/*!*/ Parent; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Parent != null); - } - - // if true, the sub-dag underneath this constant-parent edge is - // disjoint from all other unique sub-dags - public readonly bool Unique; - - public ConstantParent(IdentifierExpr parent, bool unique) { - Contract.Requires(parent != null); - Parent = parent; - Unique = unique; - } - } - - public class Constant : Variable { - // when true, the value of this constant is meant to be distinct - // from all other constants. - public readonly bool Unique; - - // the <:-parents of the value of this constant. If the field is - // null, no information about the parents is provided, which means - // that the parental situation is unconstrained. - public readonly ReadOnlyCollection Parents; - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(cce.NonNullElements(Parents, true)); - } - - // if true, it is assumed that the immediate <:-children of the - // value of this constant are completely specified - public readonly bool ChildrenComplete; - - public Constant(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent) - : base(tok, typedIdent) { - Contract.Requires(tok != null); - Contract.Requires(typedIdent != null); - Contract.Requires(typedIdent.Name != null && (!typedIdent.HasName || typedIdent.Name.Length > 0)); - Contract.Requires(typedIdent.WhereExpr == null); - this.Unique = true; - this.Parents = null; - this.ChildrenComplete = false; - } - public Constant(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent, bool unique) - : base(tok, typedIdent) { - Contract.Requires(tok != null); - Contract.Requires(typedIdent != null); - Contract.Requires(typedIdent.Name != null && typedIdent.Name.Length > 0); - Contract.Requires(typedIdent.WhereExpr == null); - this.Unique = unique; - this.Parents = null; - this.ChildrenComplete = false; - } - public Constant(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent, - bool unique, - IEnumerable parents, bool childrenComplete, - QKeyValue kv) - : base(tok, typedIdent, kv) { - Contract.Requires(tok != null); - Contract.Requires(typedIdent != null); - Contract.Requires(cce.NonNullElements(parents, true)); - Contract.Requires(typedIdent.Name != null && typedIdent.Name.Length > 0); - Contract.Requires(typedIdent.WhereExpr == null); - this.Unique = unique; - this.Parents = parents == null ? null : new ReadOnlyCollection(parents.ToList()); - this.ChildrenComplete = childrenComplete; - } - public override bool IsMutable { - get { - return false; - } - } - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, "const "); - EmitAttributes(stream); - if (this.Unique) { - stream.Write(this, level, "unique "); - } - EmitVitals(stream, level, false); - - if (Parents != null || ChildrenComplete) { - stream.Write(this, level, " extends"); - string/*!*/ sep = " "; - foreach (ConstantParent/*!*/ p in cce.NonNull(Parents)) { - Contract.Assert(p != null); - stream.Write(this, level, sep); - sep = ", "; - if (p.Unique) - stream.Write(this, level, "unique "); - p.Parent.Emit(stream); - } - if (ChildrenComplete) - stream.Write(this, level, " complete"); - } - - stream.WriteLine(";"); - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddVariable(this, true); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - base.Resolve(rc); - if (Parents != null) { - foreach (ConstantParent/*!*/ p in Parents) { - Contract.Assert(p != null); - p.Parent.Resolve(rc); - if (p.Parent.Decl != null && !(p.Parent.Decl is Constant)) - rc.Error(p.Parent, "the parent of a constant has to be a constant"); - if (this.Equals(p.Parent.Decl)) - rc.Error(p.Parent, "constant cannot be its own parent"); - } - } - - // check that no parent occurs twice - // (could be optimised) - if (Parents != null) { - for (int i = 0; i < Parents.Count; ++i) { - if (Parents[i].Parent.Decl != null) { - for (int j = i + 1; j < Parents.Count; ++j) { - if (Parents[j].Parent.Decl != null && - cce.NonNull(Parents[i].Parent.Decl).Equals(Parents[j].Parent.Decl)) - rc.Error(Parents[j].Parent, - "{0} occurs more than once as parent", - Parents[j].Parent.Decl); - } - } - } - } - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - base.Typecheck(tc); - - if (Parents != null) { - foreach (ConstantParent/*!*/ p in Parents) { - Contract.Assert(p != null); - p.Parent.Typecheck(tc); - if (!cce.NonNull(p.Parent.Decl).TypedIdent.Type.Unify(this.TypedIdent.Type)) - tc.Error(p.Parent, - "parent of constant has incompatible type ({0} instead of {1})", - p.Parent.Decl.TypedIdent.Type, this.TypedIdent.Type); - } - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitConstant(this); - } - } - public class GlobalVariable : Variable { - public GlobalVariable(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent) - : base(tok, typedIdent) { - Contract.Requires(tok != null); - Contract.Requires(typedIdent != null); - } - public GlobalVariable(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent, QKeyValue kv) - : base(tok, typedIdent, kv) { - Contract.Requires(tok != null); - Contract.Requires(typedIdent != null); - } - public override bool IsMutable { - get { - return true; - } - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddVariable(this, true); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitGlobalVariable(this); - } - } - public class Formal : Variable { - public bool InComing; - public Formal(IToken tok, TypedIdent typedIdent, bool incoming, QKeyValue kv) - : base(tok, typedIdent, kv) { - Contract.Requires(typedIdent != null); - Contract.Requires(tok != null); - InComing = incoming; - } - public Formal(IToken tok, TypedIdent typedIdent, bool incoming) - : this(tok, typedIdent, incoming, null) { - Contract.Requires(typedIdent != null); - Contract.Requires(tok != null); - } - public override bool IsMutable { - get { - return !InComing; - } - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddVariable(this, false); - } - - /// - /// Given a sequence of Formal declarations, returns sequence of Formals like the given one but without where clauses - /// and without any attributes. - /// The Type of each Formal is cloned. - /// - public static List StripWhereClauses(List w) { - Contract.Requires(w != null); - Contract.Ensures(Contract.Result>() != null); - List s = new List(); - foreach (Variable/*!*/ v in w) { - Contract.Assert(v != null); - Formal f = (Formal)v; - TypedIdent ti = f.TypedIdent; - s.Add(new Formal(f.tok, new TypedIdent(ti.tok, ti.Name, ti.Type.CloneUnresolved()), f.InComing, null)); - } - return s; - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitFormal(this); - } - } - public class LocalVariable : Variable { - public LocalVariable(IToken tok, TypedIdent typedIdent, QKeyValue kv) - : base(tok, typedIdent, kv) { - Contract.Requires(typedIdent != null); - Contract.Requires(tok != null); - } - public LocalVariable(IToken tok, TypedIdent typedIdent) - : base(tok, typedIdent, null) { - Contract.Requires(typedIdent != null); - Contract.Requires(tok != null); - } - public override bool IsMutable { - get { - return true; - } - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddVariable(this, false); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitLocalVariable(this); - } - } - public class Incarnation : LocalVariable { - public int incarnationNumber; - public Incarnation(Variable/*!*/ var, int i) : - base( - var.tok, - new TypedIdent(var.TypedIdent.tok, var.TypedIdent.Name + "@" + i, var.TypedIdent.Type) - ) { - Contract.Requires(var != null); - incarnationNumber = i; - } - - } - public class BoundVariable : Variable { - public BoundVariable(IToken tok, TypedIdent typedIdent) - : base(tok, typedIdent) { - Contract.Requires(typedIdent != null); - Contract.Requires(tok != null); - Contract.Requires(typedIdent.WhereExpr == null); - } - public BoundVariable(IToken tok, TypedIdent typedIdent, QKeyValue kv) - : base(tok, typedIdent, kv) { - Contract.Requires(typedIdent != null); - Contract.Requires(tok != null); - Contract.Requires(typedIdent.WhereExpr == null); - } - public override bool IsMutable { - get { - return false; - } - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddVariable(this, false); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitBoundVariable(this); - } - } - - public abstract class DeclWithFormals : NamedDeclaration { - public List/*!*/ TypeParameters; - - private /*readonly--except in StandardVisitor*/ List/*!*/ inParams, outParams; - - public List/*!*/ InParams { - get { - Contract.Ensures(Contract.Result>() != null); - return this.inParams; - } - set { - Contract.Requires(value != null); - this.inParams = value; - } - } - - public List/*!*/ OutParams - { - get { - Contract.Ensures(Contract.Result>() != null); - return this.outParams; - } - set { - Contract.Requires(value != null); - this.outParams = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(TypeParameters != null); - Contract.Invariant(this.inParams != null); - Contract.Invariant(this.outParams != null); - } - - public DeclWithFormals(IToken tok, string name, List typeParams, - List inParams, List outParams) - : base(tok, name) { - Contract.Requires(inParams != null); - Contract.Requires(outParams != null); - Contract.Requires(typeParams != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - this.TypeParameters = typeParams; - this.inParams = inParams; - this.outParams = outParams; - } - - protected DeclWithFormals(DeclWithFormals that) - : base(that.tok, cce.NonNull(that.Name)) { - Contract.Requires(that != null); - this.TypeParameters = that.TypeParameters; - this.inParams = cce.NonNull(that.InParams); - this.outParams = cce.NonNull(that.OutParams); - } - - public byte[] MD5Checksum_; - public byte[] MD5Checksum - { - get - { - if (MD5Checksum_ == null) - { - var c = Checksum; - if (c != null) - { - MD5Checksum_ = System.Security.Cryptography.MD5.Create().ComputeHash(System.Text.Encoding.UTF8.GetBytes(c)); - } - } - return MD5Checksum_; - } - } - - public byte[] MD5DependencyChecksum_; - public byte[] MD5DependencyChecksum - { - get - { - Contract.Requires(DependenciesCollected); - - if (MD5DependencyChecksum_ == null && MD5Checksum != null) - { - var c = MD5Checksum; - var transFuncDeps = new HashSet(); - if (procedureDependencies != null) - { - foreach (var p in procedureDependencies) - { - if (p.FunctionDependencies != null) - { - foreach (var f in p.FunctionDependencies) - { - transFuncDeps.Add(f); - } - } - var pc = p.MD5Checksum; - if (pc == null) { return null; } - c = ChecksumHelper.CombineChecksums(c, pc, true); - } - } - if (FunctionDependencies != null) - { - foreach (var f in FunctionDependencies) - { - transFuncDeps.Add(f); - } - } - var q = new Queue(transFuncDeps); - while (q.Any()) - { - var f = q.Dequeue(); - var fc = f.MD5Checksum; - if (fc == null) { return null; } - c = ChecksumHelper.CombineChecksums(c, fc, true); - if (f.FunctionDependencies != null) - { - foreach (var d in f.FunctionDependencies) - { - if (!transFuncDeps.Contains(d)) - { - transFuncDeps.Add(d); - q.Enqueue(d); - } - } - } - } - MD5DependencyChecksum_ = c; - } - return MD5DependencyChecksum_; - } - } - - public string Checksum - { - get - { - return FindStringAttribute("checksum"); - } - } - - string dependencyChecksum; - public string DependencyChecksum - { - get - { - if (dependencyChecksum == null && DependenciesCollected && MD5DependencyChecksum != null) - { - dependencyChecksum = BitConverter.ToString(MD5DependencyChecksum); - } - return dependencyChecksum; - } - } - - public bool DependenciesCollected { get; set; } - - ISet procedureDependencies; - - public ISet ProcedureDependencies - { - get { return procedureDependencies; } - } - - public void AddProcedureDependency(Procedure procedure) - { - Contract.Requires(procedure != null); - - if (procedureDependencies == null) - { - procedureDependencies = new HashSet(); - } - procedureDependencies.Add(procedure); - } - - ISet functionDependencies; - - public ISet FunctionDependencies - { - get { return functionDependencies; } - } - - public void AddFunctionDependency(Function function) - { - Contract.Requires(function != null); - - if (functionDependencies == null) - { - functionDependencies = new HashSet(); - } - functionDependencies.Add(function); - } - - protected void EmitSignature(TokenTextWriter stream, bool shortRet) { - Contract.Requires(stream != null); - Type.EmitOptionalTypeParams(stream, TypeParameters); - stream.Write("("); - stream.push(); - InParams.Emit(stream, true); - stream.Write(")"); - stream.sep(); - - if (shortRet) { - Contract.Assert(OutParams.Count == 1); - stream.Write(" : "); - cce.NonNull(OutParams[0]).TypedIdent.Type.Emit(stream); - } else if (OutParams.Count > 0) { - stream.Write(" returns ("); - OutParams.Emit(stream, true); - stream.Write(")"); - } - stream.pop(); - } - - // Register all type parameters at the resolution context - protected void RegisterTypeParameters(ResolutionContext rc) { - Contract.Requires(rc != null); - foreach (TypeVariable/*!*/ v in TypeParameters) { - Contract.Assert(v != null); - rc.AddTypeBinder(v); - } - } - - protected void SortTypeParams() { - List/*!*/ allTypes = new List(InParams.Select(Item => Item.TypedIdent.Type).ToArray()); - Contract.Assert(allTypes != null); - allTypes.AddRange(new List(OutParams.Select(Item => Item.TypedIdent.Type).ToArray())); - TypeParameters = Type.SortTypeParams(TypeParameters, allTypes, null); - } - - /// - /// Adds the given formals to the current variable context, and then resolves - /// the types of those formals. Does NOT resolve the where clauses of the - /// formals. - /// Relies on the caller to first create, and later tear down, that variable - /// context. - /// - /// - protected void RegisterFormals(List formals, ResolutionContext rc) { - Contract.Requires(rc != null); - Contract.Requires(formals != null); - foreach (Formal/*!*/ f in formals) { - Contract.Assert(f != null); - if (f.Name != TypedIdent.NoName) { - rc.AddVariable(f, false); - } - f.Resolve(rc); - } - } - - /// - /// Resolves the where clauses (and attributes) of the formals. - /// - /// - protected void ResolveFormals(List formals, ResolutionContext rc) { - Contract.Requires(rc != null); - Contract.Requires(formals != null); - foreach (Formal/*!*/ f in formals) { - Contract.Assert(f != null); - f.ResolveWhere(rc); - } - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - TypecheckAttributes(tc); - foreach (Formal/*!*/ p in InParams) { - Contract.Assert(p != null); - p.Typecheck(tc); - } - foreach (Formal/*!*/ p in OutParams) { - Contract.Assert(p != null); - p.Typecheck(tc); - } - } - } - - public class DatatypeConstructor : Function { - public List selectors; - public DatatypeMembership membership; - - public DatatypeConstructor(Function func) - : base(func.tok, func.Name, func.TypeParameters, func.InParams, func.OutParams[0], func.Comment, func.Attributes) - { - selectors = new List(); - } - - public override void Resolve(ResolutionContext rc) { - HashSet selectorNames = new HashSet(); - foreach (DatatypeSelector selector in selectors) { - if (selector.Name.StartsWith("#")) { - rc.Error(selector.tok, "The selector must be a non-empty string"); - } - else { - if (selectorNames.Contains(selector.Name)) - rc.Error(this.tok, "The selectors for a constructor must be distinct strings"); - else - selectorNames.Add(selector.Name); - } - } - base.Resolve(rc); - } - - public override void Typecheck(TypecheckingContext tc) { - CtorType outputType = this.OutParams[0].TypedIdent.Type as CtorType; - if (outputType == null || !outputType.IsDatatype()) { - tc.Error(tok, "The output type of a constructor must be a datatype"); - } - base.Typecheck(tc); - } - } - - public class DatatypeSelector : Function { - public Function constructor; - public int index; - public DatatypeSelector(Function constructor, int index) - : base(constructor.InParams[index].tok, - constructor.InParams[index].Name + "#" + constructor.Name, - new List { new Formal(constructor.tok, new TypedIdent(constructor.tok, "", constructor.OutParams[0].TypedIdent.Type), true) }, - new Formal(constructor.tok, new TypedIdent(constructor.tok, "", constructor.InParams[index].TypedIdent.Type), false)) - { - this.constructor = constructor; - this.index = index; - } - - public override void Emit(TokenTextWriter stream, int level) { } - } - - public class DatatypeMembership : Function { - public Function constructor; - public DatatypeMembership(Function constructor) - : base(constructor.tok, - "is#" + constructor.Name, - new List { new Formal(constructor.tok, new TypedIdent(constructor.tok, "", constructor.OutParams[0].TypedIdent.Type), true) }, - new Formal(constructor.tok, new TypedIdent(constructor.tok, "", Type.Bool), false)) - { - this.constructor = constructor; - } - - public override void Emit(TokenTextWriter stream, int level) { } - } - - public class Function : DeclWithFormals { - public string Comment; - - // the body is only set if the function is declared with {:inline} - public Expr Body; - public Axiom DefinitionAxiom; - - public IList otherDefinitionAxioms; - public IEnumerable OtherDefinitionAxioms - { - get - { - return otherDefinitionAxioms; - } - } - - public void AddOtherDefinitionAxiom(Axiom axiom) - { - Contract.Requires(axiom != null); - - if (otherDefinitionAxioms == null) - { - otherDefinitionAxioms = new List(); - } - otherDefinitionAxioms.Add(axiom); - } - - public bool doingExpansion; - - private bool neverTrigger; - private bool neverTriggerComputed; - - public Function(IToken tok, string name, List args, Variable result) - : this(tok, name, new List(), args, result, null) { - Contract.Requires(result != null); - Contract.Requires(args != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - //:this(tok, name, new List(), args, result, null); - } - public Function(IToken tok, string name, List typeParams, List args, Variable result) - : this(tok, name, typeParams, args, result, null) { - Contract.Requires(result != null); - Contract.Requires(args != null); - Contract.Requires(typeParams != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - //:this(tok, name, typeParams, args, result, null); - } - public Function(IToken tok, string name, List args, Variable result, string comment) - : this(tok, name, new List(), args, result, comment) { - Contract.Requires(result != null); - Contract.Requires(args != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - //:this(tok, name, new List(), args, result, comment); - } - public Function(IToken tok, string name, List typeParams, List args, Variable/*!*/ result, string comment) - : base(tok, name, typeParams, args, new List { result }) { - Contract.Requires(result != null); - Contract.Requires(args != null); - Contract.Requires(typeParams != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - Comment = comment; - } - public Function(IToken tok, string name, List typeParams, List args, Variable result, - string comment, QKeyValue kv) - : this(tok, name, typeParams, args, result, comment) { - Contract.Requires(args != null); - Contract.Requires(result != null); - Contract.Requires(typeParams != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - //:this(tok, name, typeParams, args, result, comment); - this.Attributes = kv; - } - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - if (Comment != null) { - stream.WriteLine(this, level, "// " + Comment); - } - stream.Write(this, level, "function "); - EmitAttributes(stream); - if (Body != null && !QKeyValue.FindBoolAttribute(Attributes, "inline")) { - // Boogie inlines any function whose .Body field is non-null. The parser populates the .Body field - // is the :inline attribute is present, but if someone creates the Boogie file directly as an AST, then - // the :inline attribute may not be there. We'll make sure it's printed, so one can see that this means - // that the body will be inlined. - stream.Write("{:inline} "); - } - if (CommandLineOptions.Clo.PrintWithUniqueASTIds) { - stream.Write("h{0}^^{1}", this.GetHashCode(), TokenTextWriter.SanitizeIdentifier(this.Name)); - } else { - stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); - } - EmitSignature(stream, true); - if (Body != null) { - stream.WriteLine(); - stream.WriteLine("{"); - stream.Write(level + 1, ""); - Body.Emit(stream); - stream.WriteLine(); - stream.WriteLine("}"); - } else { - stream.WriteLine(";"); - } - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddProcedure(this); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - int previousTypeBinderState = rc.TypeBinderState; - try { - RegisterTypeParameters(rc); - rc.PushVarContext(); - RegisterFormals(InParams, rc); - RegisterFormals(OutParams, rc); - ResolveAttributes(rc); - if (Body != null) - { - rc.StateMode = ResolutionContext.State.StateLess; - Body.Resolve(rc); - rc.StateMode = ResolutionContext.State.Single; - } - rc.PopVarContext(); - Type.CheckBoundVariableOccurrences(TypeParameters, - new List(InParams.Select(Item => Item.TypedIdent.Type).ToArray()), - new List(OutParams.Select(Item => Item.TypedIdent.Type).ToArray()), - this.tok, "function arguments", - rc); - } finally { - rc.TypeBinderState = previousTypeBinderState; - } - SortTypeParams(); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - // PR: why was the base call left out previously? - base.Typecheck(tc); - // TypecheckAttributes(tc); - if (Body != null) { - Body.Typecheck(tc); - if (!cce.NonNull(Body.Type).Unify(cce.NonNull(OutParams[0]).TypedIdent.Type)) - tc.Error(Body, - "function body with invalid type: {0} (expected: {1})", - Body.Type, cce.NonNull(OutParams[0]).TypedIdent.Type); - } - } - - public bool NeverTrigger { - get { - if (!neverTriggerComputed) { - this.CheckBooleanAttribute("never_pattern", ref neverTrigger); - neverTriggerComputed = true; - } - return neverTrigger; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitFunction(this); - } - - public Axiom CreateDefinitionAxiom(Expr definition, QKeyValue kv = null) { - Contract.Requires(definition != null); - - List dummies = new List(); - List callArgs = new List(); - int i = 0; - foreach (Formal/*!*/ f in InParams) { - Contract.Assert(f != null); - string nm = f.TypedIdent.HasName ? f.TypedIdent.Name : "_" + i; - dummies.Add(new BoundVariable(f.tok, new TypedIdent(f.tok, nm, f.TypedIdent.Type))); - callArgs.Add(new IdentifierExpr(f.tok, nm)); - i++; - } - List/*!*/ quantifiedTypeVars = new List(); - foreach (TypeVariable/*!*/ t in TypeParameters) { - Contract.Assert(t != null); - quantifiedTypeVars.Add(new TypeVariable(tok, t.Name)); - } - - Expr call = new NAryExpr(tok, new FunctionCall(new IdentifierExpr(tok, Name)), callArgs); - // specify the type of the function, because it might be that - // type parameters only occur in the output type - call = Expr.CoerceType(tok, call, (Type)OutParams[0].TypedIdent.Type.Clone()); - Expr def = Expr.Binary(tok, BinaryOperator.Opcode.Eq, call, definition); - if (quantifiedTypeVars.Count != 0 || dummies.Count != 0) { - def = new ForallExpr(tok, quantifiedTypeVars, dummies, - kv, - new Trigger(tok, true, new List { call }, null), - def); - } - DefinitionAxiom = new Axiom(tok, def); - return DefinitionAxiom; - } - } - - public class Macro : Function { - public Macro(IToken tok, string name, List args, Variable result) - : base(tok, name, args, result) { } - } - - public class Requires : Absy, IPotentialErrorNode { - public readonly bool Free; - - private Expr/*!*/ _condition; - - public Expr/*!*/ Condition { - get { - Contract.Ensures(Contract.Result() != null); - return this._condition; - } - set { - Contract.Requires(value != null); - this._condition = value; - } - } - - public string Comment; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._condition != null); - } - - - // TODO: convert to use generics - private string errorData; - public string ErrorData { - get { - return errorData; - } - set { - errorData = value; - } - } - - - private MiningStrategy errorDataEnhanced; - public MiningStrategy ErrorDataEnhanced { - get { - return errorDataEnhanced; - } - set { - errorDataEnhanced = value; - } - } - - public QKeyValue Attributes; - - public String ErrorMessage { - get { - return QKeyValue.FindStringAttribute(Attributes, "msg"); - } - } - - public Requires(IToken token, bool free, Expr condition, string comment, QKeyValue kv) - : base(token) { - Contract.Requires(condition != null); - Contract.Requires(token != null); - this.Free = free; - this._condition = condition; - this.Comment = comment; - this.Attributes = kv; - } - - public Requires(IToken token, bool free, Expr condition, string comment) - : this(token, free, condition, comment, null) { - Contract.Requires(condition != null); - Contract.Requires(token != null); - //:this(token, free, condition, comment, null); - } - - public Requires(bool free, Expr condition) - : this(Token.NoToken, free, condition, null) { - Contract.Requires(condition != null); - //:this(Token.NoToken, free, condition, null); - } - - public Requires(bool free, Expr condition, string comment) - : this(Token.NoToken, free, condition, comment) { - Contract.Requires(condition != null); - //:this(Token.NoToken, free, condition, comment); - } - - public void Emit(TokenTextWriter stream, int level) { - Contract.Requires(stream != null); - if (Comment != null) { - stream.WriteLine(this, level, "// " + Comment); - } - stream.Write(this, level, "{0}requires ", Free ? "free " : ""); - Cmd.EmitAttributes(stream, Attributes); - this.Condition.Emit(stream); - stream.WriteLine(";"); - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - this.Condition.Resolve(rc); - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - this.Condition.Typecheck(tc); - Contract.Assert(this.Condition.Type != null); // follows from postcondition of Expr.Typecheck - if (!this.Condition.Type.Unify(Type.Bool)) { - tc.Error(this, "preconditions must be of type bool"); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - return visitor.VisitRequires(this); - } - } - - public class Ensures : Absy, IPotentialErrorNode { - public readonly bool Free; - - private Expr/*!*/ _condition; - - public Expr/*!*/ Condition { - get { - Contract.Ensures(Contract.Result() != null); - return this._condition; - } - set { - Contract.Requires(value != null); - this._condition = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._condition != null); - } - - public string Comment; - - // TODO: convert to use generics - private string errorData; - public string ErrorData { - get { - return errorData; - } - set { - errorData = value; - } - } - - private MiningStrategy errorDataEnhanced; - public MiningStrategy ErrorDataEnhanced { - get { - return errorDataEnhanced; - } - set { - errorDataEnhanced = value; - } - } - - public String ErrorMessage { - get { - return QKeyValue.FindStringAttribute(Attributes, "msg"); - } - } - - public QKeyValue Attributes; - - public Ensures(IToken token, bool free, Expr/*!*/ condition, string comment, QKeyValue kv) - : base(token) { - Contract.Requires(condition != null); - Contract.Requires(token != null); - this.Free = free; - this._condition = condition; - this.Comment = comment; - this.Attributes = kv; - } - - public Ensures(IToken token, bool free, Expr condition, string comment) - : this(token, free, condition, comment, null) { - Contract.Requires(condition != null); - Contract.Requires(token != null); - //:this(token, free, condition, comment, null); - } - - public Ensures(bool free, Expr condition) - : this(Token.NoToken, free, condition, null) { - Contract.Requires(condition != null); - //:this(Token.NoToken, free, condition, null); - } - - public Ensures(bool free, Expr condition, string comment) - : this(Token.NoToken, free, condition, comment) { - Contract.Requires(condition != null); - //:this(Token.NoToken, free, condition, comment); - } - - public void Emit(TokenTextWriter stream, int level) { - Contract.Requires(stream != null); - if (Comment != null) { - stream.WriteLine(this, level, "// " + Comment); - } - stream.Write(this, level, "{0}ensures ", Free ? "free " : ""); - Cmd.EmitAttributes(stream, Attributes); - this.Condition.Emit(stream); - stream.WriteLine(";"); - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - this.Condition.Resolve(rc); - } - - public override void Typecheck(TypecheckingContext tc) { - this.Condition.Typecheck(tc); - Contract.Assert(this.Condition.Type != null); // follows from postcondition of Expr.Typecheck - if (!this.Condition.Type.Unify(Type.Bool)) { - tc.Error(this, "postconditions must be of type bool"); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - return visitor.VisitEnsures(this); - } - } - - public class Procedure : DeclWithFormals { - public List/*!*/ Requires; - public List/*!*/ Modifies; - public List/*!*/ Ensures; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Requires != null); - Contract.Invariant(Modifies != null); - Contract.Invariant(Ensures != null); - Contract.Invariant(Summary != null); - } - - - // Abstract interpretation: Procedure-specific invariants... - [Rep] - public readonly ProcedureSummary/*!*/ Summary; - - public Procedure(IToken/*!*/ tok, string/*!*/ name, List/*!*/ typeParams, List/*!*/ inParams, List/*!*/ outParams, - List/*!*/ requires, List/*!*/ modifies, List/*!*/ ensures) - : this(tok, name, typeParams, inParams, outParams, requires, modifies, ensures, null) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - Contract.Requires(typeParams != null); - Contract.Requires(inParams != null); - Contract.Requires(outParams != null); - Contract.Requires(requires != null); - Contract.Requires(modifies != null); - Contract.Requires(ensures != null); - //:this(tok, name, typeParams, inParams, outParams, requires, modifies, ensures, null); - } - - public Procedure(IToken/*!*/ tok, string/*!*/ name, List/*!*/ typeParams, List/*!*/ inParams, List/*!*/ outParams, - List/*!*/ @requires, List/*!*/ @modifies, List/*!*/ @ensures, QKeyValue kv - ) - : base(tok, name, typeParams, inParams, outParams) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - Contract.Requires(typeParams != null); - Contract.Requires(inParams != null); - Contract.Requires(outParams != null); - Contract.Requires(@requires != null); - Contract.Requires(@modifies != null); - Contract.Requires(@ensures != null); - this.Requires = @requires; - this.Modifies = @modifies; - this.Ensures = @ensures; - this.Summary = new ProcedureSummary(); - this.Attributes = kv; - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, "procedure "); - EmitAttributes(stream); - stream.Write(this, level, "{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); - EmitSignature(stream, false); - stream.WriteLine(";"); - - level++; - - foreach (Requires/*!*/ e in this.Requires) { - Contract.Assert(e != null); - e.Emit(stream, level); - } - - if (this.Modifies.Count > 0) { - stream.Write(level, "modifies "); - this.Modifies.Emit(stream, false); - stream.WriteLine(";"); - } - - foreach (Ensures/*!*/ e in this.Ensures) { - Contract.Assert(e != null); - e.Emit(stream, level); - } - - if (!CommandLineOptions.Clo.IntraproceduralInfer) { - for (int s = 0; s < this.Summary.Count; s++) { - ProcedureSummaryEntry/*!*/ entry = cce.NonNull(this.Summary[s]); - stream.Write(level + 1, "// "); - stream.WriteLine(); - } - } - - stream.WriteLine(); - stream.WriteLine(); - } - - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddProcedure(this); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.PushVarContext(); - - foreach (IdentifierExpr/*!*/ ide in Modifies) { - Contract.Assert(ide != null); - ide.Resolve(rc); - } - - int previousTypeBinderState = rc.TypeBinderState; - try { - RegisterTypeParameters(rc); - - RegisterFormals(InParams, rc); - ResolveFormals(InParams, rc); // "where" clauses of in-parameters are resolved without the out-parameters in scope - foreach (Requires/*!*/ e in Requires) { - Contract.Assert(e != null); - e.Resolve(rc); - } - RegisterFormals(OutParams, rc); - ResolveFormals(OutParams, rc); // "where" clauses of out-parameters are resolved with both in- and out-parametes in scope - - rc.StateMode = ResolutionContext.State.Two; - foreach (Ensures/*!*/ e in Ensures) { - Contract.Assert(e != null); - e.Resolve(rc); - } - rc.StateMode = ResolutionContext.State.Single; - ResolveAttributes(rc); - - Type.CheckBoundVariableOccurrences(TypeParameters, - new List(InParams.Select(Item => Item.TypedIdent.Type).ToArray()), - new List(OutParams.Select(Item => Item.TypedIdent.Type).ToArray()), - this.tok, "procedure arguments", - rc); - - } finally { - rc.TypeBinderState = previousTypeBinderState; - } - - rc.PopVarContext(); - - SortTypeParams(); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - base.Typecheck(tc); - foreach (IdentifierExpr/*!*/ ide in Modifies) { - Contract.Assert(ide != null); - Contract.Assume(ide.Decl != null); - if (!ide.Decl.IsMutable) { - tc.Error(this, "modifies list contains constant: {0}", ide.Name); - } - ide.Typecheck(tc); - } - foreach (Requires/*!*/ e in Requires) { - Contract.Assert(e != null); - e.Typecheck(tc); - } - bool oldYields = tc.Yields; - tc.Yields = QKeyValue.FindBoolAttribute(Attributes, "yields"); - foreach (Ensures/*!*/ e in Ensures) { - Contract.Assert(e != null); - e.Typecheck(tc); - } - tc.Yields = oldYields; - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitProcedure(this); - } - } - - public class LoopProcedure : Procedure - { - public Implementation enclosingImpl; - private Dictionary blockMap; - private Dictionary blockLabelMap; - - public LoopProcedure(Implementation impl, Block header, - List inputs, List outputs, List globalMods) - : base(Token.NoToken, impl.Name + "_loop_" + header.ToString(), - new List(), inputs, outputs, - new List(), globalMods, new List()) - { - enclosingImpl = impl; - } - - public void setBlockMap(Dictionary bm) - { - blockMap = bm; - blockLabelMap = new Dictionary(); - foreach (var kvp in bm) - { - blockLabelMap.Add(kvp.Key.Label, kvp.Value); - } - } - - public Block getBlock(string label) - { - if (blockLabelMap.ContainsKey(label)) return blockLabelMap[label]; - return null; - } - } - - public class Implementation : DeclWithFormals { - public List/*!*/ LocVars; - [Rep] - public StmtList StructuredStmts; - [Rep] - public List/*!*/ Blocks; - public Procedure Proc; - - // Blocks before applying passification etc. - // Both are used only when /inline is set. - public List OriginalBlocks; - public List OriginalLocVars; - - public readonly ISet AssertionChecksums = new HashSet(ChecksumComparer.Default); - - public sealed class ChecksumComparer : IEqualityComparer - { - static IEqualityComparer defaultComparer; - public static IEqualityComparer Default - { - get - { - if (defaultComparer == null) - { - defaultComparer = new ChecksumComparer(); - } - return defaultComparer; - } - } - - public bool Equals(byte[] x, byte[] y) - { - if (x == null || y == null) - { - return x == y; - } - else - { - return x.SequenceEqual(y); - } - } - - public int GetHashCode(byte[] checksum) - { - if (checksum == null) - { - throw new ArgumentNullException("checksum"); - } - else - { - var result = 17; - for (int i = 0; i < checksum.Length; i++) - { - result = result * 23 + checksum[i]; - } - return result; - } - } - } - - public void AddAssertionChecksum(byte[] checksum) - { - Contract.Requires(checksum != null); - - if (AssertionChecksums != null) - { - AssertionChecksums.Add(checksum); - } - } - - public ISet AssertionChecksumsInCachedSnapshot { get; set; } - - public bool IsAssertionChecksumInCachedSnapshot(byte[] checksum) - { - Contract.Requires(AssertionChecksumsInCachedSnapshot != null); - - return AssertionChecksumsInCachedSnapshot.Contains(checksum); - } - - public IList RecycledFailingAssertions { get; protected set; } - - public void AddRecycledFailingAssertion(AssertCmd assertion) - { - if (RecycledFailingAssertions == null) - { - RecycledFailingAssertions = new List(); - } - RecycledFailingAssertions.Add(assertion); - } - - // Strongly connected components - private StronglyConnectedComponents scc; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(LocVars != null); - Contract.Invariant(cce.NonNullElements(Blocks)); - Contract.Invariant(cce.NonNullElements(OriginalBlocks, true)); - Contract.Invariant(cce.NonNullElements(scc, true)); - - } - private bool BlockPredecessorsComputed; - public bool StronglyConnectedComponentsComputed { - get { - return this.scc != null; - } - } - - public bool SkipVerification { - get { - bool verify = true; - cce.NonNull(this.Proc).CheckBooleanAttribute("verify", ref verify); - this.CheckBooleanAttribute("verify", ref verify); - if (!verify) { - return true; - } - - if (CommandLineOptions.Clo.ProcedureInlining == CommandLineOptions.Inlining.Assert || - CommandLineOptions.Clo.ProcedureInlining == CommandLineOptions.Inlining.Assume) { - Expr inl = this.FindExprAttribute("inline"); - if (inl == null) - inl = this.Proc.FindExprAttribute("inline"); - if (inl != null && inl is LiteralExpr && ((LiteralExpr)inl).isBigNum && ((LiteralExpr)inl).asBigNum.Signum > 0) { - return true; - } - } - - if (CommandLineOptions.Clo.StratifiedInlining > 0) { - return !QKeyValue.FindBoolAttribute(Attributes, "entrypoint"); - } - - return false; - } - } - - public string Id - { - get - { - var id = FindStringAttribute("id"); - if (id == null) - { - id = Name + GetHashCode().ToString() + ":0"; - } - return id; - } - } - - public int Priority - { - get - { - int priority = 0; - CheckIntAttribute("priority", ref priority); - if (priority <= 0) - { - priority = 1; - } - return priority; - } - } - - public IDictionary ErrorChecksumToCachedError { get; private set; } - - public bool IsErrorChecksumInCachedSnapshot(byte[] checksum) - { - Contract.Requires(ErrorChecksumToCachedError != null); - - return ErrorChecksumToCachedError.ContainsKey(checksum); - } - - public void SetErrorChecksumToCachedError(IEnumerable> errors) - { - Contract.Requires(errors != null); - - ErrorChecksumToCachedError = new Dictionary(ChecksumComparer.Default); - foreach (var kv in errors) - { - ErrorChecksumToCachedError[kv.Item1] = kv.Item3; - if (kv.Item2 != null) - { - ErrorChecksumToCachedError[kv.Item2] = null; - } - } - } - - public bool HasCachedSnapshot - { - get - { - return ErrorChecksumToCachedError != null && AssertionChecksumsInCachedSnapshot != null; - } - } - - public bool AnyErrorsInCachedSnapshot - { - get - { - Contract.Requires(ErrorChecksumToCachedError != null); - - return ErrorChecksumToCachedError.Any(); - } - } - - IList injectedAssumptionVariables; - public IList InjectedAssumptionVariables - { - get - { - return injectedAssumptionVariables != null ? injectedAssumptionVariables : new List(); - } - } - - IList doomedInjectedAssumptionVariables; - public IList DoomedInjectedAssumptionVariables - { - get - { - return doomedInjectedAssumptionVariables != null ? doomedInjectedAssumptionVariables : new List(); - } - } - - public List RelevantInjectedAssumptionVariables(Dictionary incarnationMap) - { - return InjectedAssumptionVariables.Where(v => { Expr e; if (incarnationMap.TryGetValue(v, out e)) { var le = e as LiteralExpr; return le == null || !le.IsTrue; } else { return false; } }).ToList(); - } - - public List RelevantDoomedInjectedAssumptionVariables(Dictionary incarnationMap) - { - return DoomedInjectedAssumptionVariables.Where(v => { Expr e; if (incarnationMap.TryGetValue(v, out e)) { var le = e as LiteralExpr; return le == null || !le.IsTrue; } else { return false; } }).ToList(); - } - - public Expr ConjunctionOfInjectedAssumptionVariables(Dictionary incarnationMap, out bool isTrue) - { - Contract.Requires(incarnationMap != null); - - var vars = RelevantInjectedAssumptionVariables(incarnationMap).Select(v => incarnationMap[v]).ToList(); - isTrue = vars.Count == 0; - return LiteralExpr.BinaryTreeAnd(vars); - } - - public void InjectAssumptionVariable(LocalVariable variable, bool isDoomed = false) - { - LocVars.Add(variable); - if (isDoomed) - { - if (doomedInjectedAssumptionVariables == null) - { - doomedInjectedAssumptionVariables = new List(); - } - doomedInjectedAssumptionVariables.Add(variable); - } - else - { - if (injectedAssumptionVariables == null) - { - injectedAssumptionVariables = new List(); - } - injectedAssumptionVariables.Add(variable); - } - } - - public Implementation(IToken tok, string name, List typeParams, List inParams, List outParams, List localVariables, [Captured] StmtList structuredStmts, QKeyValue kv) - : this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, kv, new Errors()) { - Contract.Requires(structuredStmts != null); - Contract.Requires(localVariables != null); - Contract.Requires(outParams != null); - Contract.Requires(inParams != null); - Contract.Requires(typeParams != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - //:this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, new Errors()); - } - - public Implementation(IToken tok, string name, List typeParams, List inParams, List outParams, List localVariables, [Captured] StmtList structuredStmts) - : this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, new Errors()) { - Contract.Requires(structuredStmts != null); - Contract.Requires(localVariables != null); - Contract.Requires(outParams != null); - Contract.Requires(inParams != null); - Contract.Requires(typeParams != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - //:this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, new Errors()); - } - - public Implementation(IToken tok, string name, List typeParams, List inParams, List outParams, List localVariables, [Captured] StmtList structuredStmts, Errors errorHandler) - : this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, errorHandler) { - Contract.Requires(errorHandler != null); - Contract.Requires(structuredStmts != null); - Contract.Requires(localVariables != null); - Contract.Requires(outParams != null); - Contract.Requires(inParams != null); - Contract.Requires(typeParams != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - //:this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, errorHandler); - } - - public Implementation(IToken/*!*/ tok, - string/*!*/ name, - List/*!*/ typeParams, - List/*!*/ inParams, - List/*!*/ outParams, - List/*!*/ localVariables, - [Captured] StmtList/*!*/ structuredStmts, - QKeyValue kv, - Errors/*!*/ errorHandler) - : base(tok, name, typeParams, inParams, outParams) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - Contract.Requires(typeParams != null); - Contract.Requires(inParams != null); - Contract.Requires(outParams != null); - Contract.Requires(localVariables != null); - Contract.Requires(structuredStmts != null); - Contract.Requires(errorHandler != null); - LocVars = localVariables; - StructuredStmts = structuredStmts; - BigBlocksResolutionContext ctx = new BigBlocksResolutionContext(structuredStmts, errorHandler); - Blocks = ctx.Blocks; - BlockPredecessorsComputed = false; - scc = null; - Attributes = kv; - } - - public Implementation(IToken tok, string name, List typeParams, List inParams, List outParams, List localVariables, [Captured] List block) - : this(tok, name, typeParams, inParams, outParams, localVariables, block, null) { - Contract.Requires(cce.NonNullElements(block)); - Contract.Requires(localVariables != null); - Contract.Requires(outParams != null); - Contract.Requires(inParams != null); - Contract.Requires(typeParams != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - //:this(tok, name, typeParams, inParams, outParams, localVariables, block, null); - } - - public Implementation(IToken/*!*/ tok, - string/*!*/ name, - List/*!*/ typeParams, - List/*!*/ inParams, - List/*!*/ outParams, - List/*!*/ localVariables, - [Captured] List/*!*/ blocks, - QKeyValue kv) - : base(tok, name, typeParams, inParams, outParams) { - Contract.Requires(name != null); - Contract.Requires(inParams != null); - Contract.Requires(outParams != null); - Contract.Requires(localVariables != null); - Contract.Requires(cce.NonNullElements(blocks)); - LocVars = localVariables; - Blocks = blocks; - BlockPredecessorsComputed = false; - scc = null; - Attributes = kv; - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, "implementation "); - EmitAttributes(stream); - stream.Write(this, level, "{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); - EmitSignature(stream, false); - stream.WriteLine(); - - stream.WriteLine(level, "{0}", '{'); - - foreach (Variable/*!*/ v in this.LocVars) { - Contract.Assert(v != null); - v.Emit(stream, level + 1); - } - - if (this.StructuredStmts != null && !CommandLineOptions.Clo.PrintInstrumented && !CommandLineOptions.Clo.PrintInlined) { - if (this.LocVars.Count > 0) { - stream.WriteLine(); - } - if (CommandLineOptions.Clo.PrintUnstructured < 2) { - if (CommandLineOptions.Clo.PrintUnstructured == 1) { - stream.WriteLine(this, level + 1, "/*** structured program:"); - } - this.StructuredStmts.Emit(stream, level + 1); - if (CommandLineOptions.Clo.PrintUnstructured == 1) { - stream.WriteLine(level + 1, "**** end structured program */"); - } - } - } - - if (this.StructuredStmts == null || 1 <= CommandLineOptions.Clo.PrintUnstructured || - CommandLineOptions.Clo.PrintInstrumented || CommandLineOptions.Clo.PrintInlined) { - foreach (Block b in this.Blocks) { - b.Emit(stream, level + 1); - } - } - - stream.WriteLine(level, "{0}", '}'); - - stream.WriteLine(); - stream.WriteLine(); - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - // nothing to register - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - if (Proc != null) { - // already resolved - return; - } - - DeclWithFormals dwf = rc.LookUpProcedure(cce.NonNull(this.Name)); - Proc = dwf as Procedure; - if (dwf == null) { - rc.Error(this, "implementation given for undeclared procedure: {0}", this.Name); - } else if (Proc == null) { - rc.Error(this, "implementations given for function, not procedure: {0}", this.Name); - } - - int previousTypeBinderState = rc.TypeBinderState; - try { - RegisterTypeParameters(rc); - - rc.PushVarContext(); - RegisterFormals(InParams, rc); - RegisterFormals(OutParams, rc); - - foreach (Variable/*!*/ v in LocVars) { - Contract.Assert(v != null); - v.Register(rc); - v.Resolve(rc); - } - foreach (Variable/*!*/ v in LocVars) { - Contract.Assert(v != null); - v.ResolveWhere(rc); - } - - rc.PushProcedureContext(); - foreach (Block b in Blocks) { - b.Register(rc); - } - - ResolveAttributes(rc); - - rc.StateMode = ResolutionContext.State.Two; - foreach (Block b in Blocks) { - b.Resolve(rc); - } - rc.StateMode = ResolutionContext.State.Single; - - rc.PopProcedureContext(); - rc.PopVarContext(); - - Type.CheckBoundVariableOccurrences(TypeParameters, - new List(InParams.Select(Item => Item.TypedIdent.Type).ToArray()), - new List(OutParams.Select(Item => Item.TypedIdent.Type).ToArray()), - this.tok, "implementation arguments", - rc); - } finally { - rc.TypeBinderState = previousTypeBinderState; - } - SortTypeParams(); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - base.Typecheck(tc); - - Contract.Assume(this.Proc != null); - - if (this.TypeParameters.Count != Proc.TypeParameters.Count) { - tc.Error(this, "mismatched number of type parameters in procedure implementation: {0}", - this.Name); - } else { - // if the numbers of type parameters are different, it is - // difficult to compare the argument types - MatchFormals(this.InParams, Proc.InParams, "in", tc); - MatchFormals(this.OutParams, Proc.OutParams, "out", tc); - } - - foreach (Variable/*!*/ v in LocVars) { - Contract.Assert(v != null); - v.Typecheck(tc); - } - List oldFrame = tc.Frame; - bool oldYields = tc.Yields; - tc.Frame = Proc.Modifies; - tc.Yields = QKeyValue.FindBoolAttribute(Proc.Attributes, "yields"); - foreach (Block b in Blocks) { - b.Typecheck(tc); - } - Contract.Assert(tc.Frame == Proc.Modifies); - tc.Frame = oldFrame; - tc.Yields = oldYields; - } - void MatchFormals(List/*!*/ implFormals, List/*!*/ procFormals, string/*!*/ inout, TypecheckingContext/*!*/ tc) { - Contract.Requires(implFormals != null); - Contract.Requires(procFormals != null); - Contract.Requires(inout != null); - Contract.Requires(tc != null); - if (implFormals.Count != procFormals.Count) { - tc.Error(this, "mismatched number of {0}-parameters in procedure implementation: {1}", - inout, this.Name); - } else { - // unify the type parameters so that types can be compared - Contract.Assert(Proc != null); - Contract.Assert(this.TypeParameters.Count == Proc.TypeParameters.Count); - - IDictionary/*!*/ subst1 = - new Dictionary(); - IDictionary/*!*/ subst2 = - new Dictionary(); - - for (int i = 0; i < this.TypeParameters.Count; ++i) { - TypeVariable/*!*/ newVar = - new TypeVariable(Token.NoToken, Proc.TypeParameters[i].Name); - Contract.Assert(newVar != null); - subst1.Add(Proc.TypeParameters[i], newVar); - subst2.Add(this.TypeParameters[i], newVar); - } - - for (int i = 0; i < implFormals.Count; i++) { - // the names of the formals are allowed to change from the proc to the impl - - // but types must be identical - Type t = cce.NonNull((Variable)implFormals[i]).TypedIdent.Type.Substitute(subst2); - Type u = cce.NonNull((Variable)procFormals[i]).TypedIdent.Type.Substitute(subst1); - if (!t.Equals(u)) { - string/*!*/ a = cce.NonNull((Variable)implFormals[i]).Name; - Contract.Assert(a != null); - string/*!*/ b = cce.NonNull((Variable)procFormals[i]).Name; - Contract.Assert(b != null); - string/*!*/ c; - if (a == b) { - c = a; - } else { - c = String.Format("{0} (named {1} in implementation)", b, a); - } - tc.Error(this, "mismatched type of {0}-parameter in implementation {1}: {2}", inout, this.Name, c); - } - } - } - } - - private Dictionary/*?*/ formalMap = null; - public void ResetImplFormalMap() { - this.formalMap = null; - } - public Dictionary/*!*/ GetImplFormalMap() { - Contract.Ensures(Contract.Result>() != null); - - if (this.formalMap != null) - return this.formalMap; - else { - Dictionary/*!*/ map = new Dictionary (InParams.Count + OutParams.Count); - - Contract.Assume(this.Proc != null); - Contract.Assume(InParams.Count == Proc.InParams.Count); - for (int i = 0; i < InParams.Count; i++) { - Variable/*!*/ v = InParams[i]; - Contract.Assert(v != null); - IdentifierExpr ie = new IdentifierExpr(v.tok, v); - Variable/*!*/ pv = Proc.InParams[i]; - Contract.Assert(pv != null); - map.Add(pv, ie); - } - System.Diagnostics.Debug.Assert(OutParams.Count == Proc.OutParams.Count); - for (int i = 0; i < OutParams.Count; i++) { - Variable/*!*/ v = cce.NonNull(OutParams[i]); - IdentifierExpr ie = new IdentifierExpr(v.tok, v); - Variable pv = cce.NonNull(Proc.OutParams[i]); - map.Add(pv, ie); - } - this.formalMap = map; - - if (CommandLineOptions.Clo.PrintWithUniqueASTIds) { - Console.WriteLine("Implementation.GetImplFormalMap on {0}:", this.Name); - using (TokenTextWriter stream = new TokenTextWriter("", Console.Out, /*setTokens=*/false, /*pretty=*/ false)) { - foreach (var e in map) { - Console.Write(" "); - cce.NonNull((Variable/*!*/)e.Key).Emit(stream, 0); - Console.Write(" --> "); - cce.NonNull((Expr)e.Value).Emit(stream); - Console.WriteLine(); - } - } - } - - return map; - } - } - - /// - /// Return a collection of blocks that are reachable from the block passed as a parameter. - /// The block must be defined in the current implementation - /// - public ICollection GetConnectedComponents(Block startingBlock) { - Contract.Requires(startingBlock != null); - Contract.Ensures(cce.NonNullElements(Contract.Result>(), true)); - Contract.Assert(this.Blocks.Contains(startingBlock)); - - if (!this.BlockPredecessorsComputed) - ComputeStronglyConnectedComponents(); - -#if DEBUG_PRINT - System.Console.WriteLine("* Strongly connected components * \n{0} \n ** ", scc); -#endif - - foreach (ICollection component in cce.NonNull(this.scc)) { - foreach (Block/*!*/ b in component) { - Contract.Assert(b != null); - if (b == startingBlock) // We found the compontent that owns the startingblock - { - return component; - } - } - } - - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // if we are here, it means that the block is not in one of the components. This is an error. - } - - /// - /// Compute the strongly connected compontents of the blocks in the implementation. - /// As a side effect, it also computes the "predecessor" relation for the block in the implementation - /// - override public void ComputeStronglyConnectedComponents() { - if (!this.BlockPredecessorsComputed) - ComputePredecessorsForBlocks(); - - Adjacency next = new Adjacency(Successors); - Adjacency prev = new Adjacency(Predecessors); - - this.scc = new StronglyConnectedComponents(this.Blocks, next, prev); - scc.Compute(); - - - foreach (Block/*!*/ block in this.Blocks) { - Contract.Assert(block != null); - block.Predecessors = new List(); - } - - } - - /// - /// Reset the abstract stated computed before - /// - override public void ResetAbstractInterpretationState() { - foreach (Block/*!*/ b in this.Blocks) { - Contract.Assert(b != null); - b.ResetAbstractInterpretationState(); - } - } - - /// - /// A private method used as delegate for the strongly connected components. - /// It return, given a node, the set of its successors - /// - private IEnumerable/**//*!*/ Successors(Block node) { - Contract.Requires(node != null); - Contract.Ensures(Contract.Result() != null); - - GotoCmd gotoCmd = node.TransferCmd as GotoCmd; - - if (gotoCmd != null) { // If it is a gotoCmd - Contract.Assert(gotoCmd.labelTargets != null); - - return gotoCmd.labelTargets; - } else { // otherwise must be a ReturnCmd - Contract.Assert(node.TransferCmd is ReturnCmd); - - return new List(); - } - } - - /// - /// A private method used as delegate for the strongly connected components. - /// It return, given a node, the set of its predecessors - /// - private IEnumerable/**//*!*/ Predecessors(Block node) { - Contract.Requires(node != null); - Contract.Ensures(Contract.Result() != null); - - Contract.Assert(this.BlockPredecessorsComputed); - - return node.Predecessors; - } - - /// - /// Compute the predecessor informations for the blocks - /// - public void ComputePredecessorsForBlocks() { - foreach (Block b in this.Blocks) { - b.Predecessors = new List(); - } - foreach (Block b in this.Blocks) { - GotoCmd gtc = b.TransferCmd as GotoCmd; - if (gtc != null) { - Contract.Assert(gtc.labelTargets != null); - foreach (Block/*!*/ dest in gtc.labelTargets) { - Contract.Assert(dest != null); - dest.Predecessors.Add(b); - } - } - } - this.BlockPredecessorsComputed = true; - } - - public void PruneUnreachableBlocks() { - ArrayList /*Block!*/ visitNext = new ArrayList /*Block!*/ (); - List reachableBlocks = new List(); - HashSet reachable = new HashSet(); // the set of elements in "reachableBlocks" - - visitNext.Add(this.Blocks[0]); - while (visitNext.Count != 0) { - Block b = cce.NonNull((Block)visitNext[visitNext.Count - 1]); - visitNext.RemoveAt(visitNext.Count - 1); - if (!reachable.Contains(b)) { - reachableBlocks.Add(b); - reachable.Add(b); - if (b.TransferCmd is GotoCmd) { - if (CommandLineOptions.Clo.PruneInfeasibleEdges) { - foreach (Cmd/*!*/ s in b.Cmds) { - Contract.Assert(s != null); - if (s is PredicateCmd) { - LiteralExpr e = ((PredicateCmd)s).Expr as LiteralExpr; - if (e != null && e.IsFalse) { - // This statement sequence will never reach the end, because of this "assume false" or "assert false". - // Hence, it does not reach its successors. - b.TransferCmd = new ReturnCmd(b.TransferCmd.tok); - goto NEXT_BLOCK; - } - } - } - } - // it seems that the goto statement at the end may be reached - foreach (Block succ in cce.NonNull((GotoCmd)b.TransferCmd).labelTargets) { - Contract.Assume(succ != null); - visitNext.Add(succ); - } - } - } - NEXT_BLOCK: { - } - } - - this.Blocks = reachableBlocks; - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitImplementation(this); - } - - public void FreshenCaptureStates() { - - // Assume commands with the "captureState" attribute allow model states to be - // captured for error reporting. - // Some program transformations, such as loop unrolling, duplicate parts of the - // program, leading to "capture-state-assumes" being duplicated. This leads - // to ambiguity when getting a state from the model. - // This method replaces the key of every "captureState" attribute with something - // unique - - int FreshCounter = 0; - foreach(var b in Blocks) { - List newCmds = new List(); - for (int i = 0; i < b.Cmds.Count(); i++) { - var a = b.Cmds[i] as AssumeCmd; - if (a != null && (QKeyValue.FindStringAttribute(a.Attributes, "captureState") != null)) { - string StateName = QKeyValue.FindStringAttribute(a.Attributes, "captureState"); - newCmds.Add(new AssumeCmd(Token.NoToken, a.Expr, FreshenCaptureState(a.Attributes, FreshCounter))); - FreshCounter++; - } - else { - newCmds.Add(b.Cmds[i]); - } - } - b.Cmds = newCmds; - } - } - - private QKeyValue FreshenCaptureState(QKeyValue Attributes, int FreshCounter) { - // Returns attributes identical to Attributes, but: - // - reversed (for ease of implementation; should not matter) - // - with the value for "captureState" replaced by a fresh value - Contract.Requires(QKeyValue.FindStringAttribute(Attributes, "captureState") != null); - string FreshValue = QKeyValue.FindStringAttribute(Attributes, "captureState") + "$renamed$" + Name + "$" + FreshCounter; - - QKeyValue result = null; - while (Attributes != null) { - if (Attributes.Key.Equals("captureState")) { - result = new QKeyValue(Token.NoToken, Attributes.Key, new List() { FreshValue }, result); - } else { - result = new QKeyValue(Token.NoToken, Attributes.Key, Attributes.Params, result); - } - Attributes = Attributes.Next; - } - return result; - } - - } - - - public class TypedIdent : Absy { - public const string NoName = ""; - - private string/*!*/ _name; - - public string/*!*/ Name { - get { - Contract.Ensures(Contract.Result() != null); - return this._name; - } - set { - Contract.Requires(value != null); - this._name = value; - } - } - - private Type/*!*/ _type; - - public Type/*!*/ Type { - get { - Contract.Ensures(Contract.Result() != null); - return this._type; - } - set { - Contract.Requires(value != null); - this._type = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._name != null); - Contract.Invariant(this._type != null); - } - - public Expr WhereExpr; - // [NotDelayed] - public TypedIdent(IToken/*!*/ tok, string/*!*/ name, Type/*!*/ type) - : this(tok, name, type, null) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - Contract.Requires(type != null); - Contract.Ensures(this.WhereExpr == null); //PM: needed to verify BoogiePropFactory.FreshBoundVariable - //:this(tok, name, type, null); // here for aesthetic reasons - } - // [NotDelayed] - public TypedIdent(IToken/*!*/ tok, string/*!*/ name, Type/*!*/ type, Expr whereExpr) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - Contract.Requires(type != null); - Contract.Ensures(this.WhereExpr == whereExpr); - this._name = name; - this._type = type; - this.WhereExpr = whereExpr; - } - public bool HasName { - get { - return this.Name != NoName; - } - } - public void Emit(TokenTextWriter stream) { - Contract.Requires(stream != null); - stream.SetToken(this); - stream.push(); - if (this.Name != NoName) { - stream.Write("{0}: ", TokenTextWriter.SanitizeIdentifier(this.Name)); - } - this.Type.Emit(stream); - if (this.WhereExpr != null) { - stream.sep(); - stream.Write(" where "); - this.WhereExpr.Emit(stream); - } - stream.pop(); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - // NOTE: WhereExpr needs to be resolved by the caller, because the caller must provide a modified ResolutionContext - this.Type = this.Type.ResolveType(rc); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - // type variables can occur when working with polymorphic functions/procedures - // if (!this.Type.IsClosed) - // tc.Error(this, "free variables in type of an identifier: {0}", - // this.Type.FreeVariables); - if (this.WhereExpr != null) { - this.WhereExpr.Typecheck(tc); - Contract.Assert(this.WhereExpr.Type != null); // follows from postcondition of Expr.Typecheck - if (!this.WhereExpr.Type.Unify(Type.Bool)) { - tc.Error(this, "where clauses must be of type bool"); - } - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitTypedIdent(this); - } - } - - #region Helper methods for generic Sequences - - public static class TypeVariableSeqAlgorithms { - public static void AppendWithoutDups(this List tvs, List s1) { - Contract.Requires(s1 != null); - for (int i = 0; i < s1.Count; i++) { - TypeVariable/*!*/ next = s1[i]; - Contract.Assert(next != null); - if (!tvs.Contains(next)) - tvs.Add(next); - } - } - } - - public static class Emitter { - - public static void Emit(this List/*!*/ decls, TokenTextWriter stream) { - Contract.Requires(stream != null); - Contract.Requires(cce.NonNullElements(decls)); - bool first = true; - foreach (Declaration d in decls) { - if (d == null) - continue; - if (first) { - first = false; - } else { - stream.WriteLine(); - } - d.Emit(stream, 0); - } - } - - public static void Emit(this List ss, TokenTextWriter stream) { - Contract.Requires(stream != null); - string sep = ""; - foreach (string/*!*/ s in ss) { - Contract.Assert(s != null); - stream.Write(sep); - sep = ", "; - stream.Write(s); - } - } - - public static void Emit(this IList ts, TokenTextWriter stream) { - Contract.Requires(stream != null); - string sep = ""; - stream.push(); - foreach (Expr/*!*/ e in ts) { - Contract.Assert(e != null); - stream.Write(sep); - sep = ", "; - stream.sep(); - e.Emit(stream); - } - stream.pop(); - } - - public static void Emit(this List ids, TokenTextWriter stream, bool printWhereComments) { - Contract.Requires(stream != null); - string sep = ""; - foreach (IdentifierExpr/*!*/ e in ids) { - Contract.Assert(e != null); - stream.Write(sep); - sep = ", "; - e.Emit(stream); - - if (printWhereComments && e.Decl != null && e.Decl.TypedIdent.WhereExpr != null) { - stream.Write(" /* where "); - e.Decl.TypedIdent.WhereExpr.Emit(stream); - stream.Write(" */"); - } - } - } - - public static void Emit(this List vs, TokenTextWriter stream, bool emitAttributes) { - Contract.Requires(stream != null); - string sep = ""; - stream.push(); - foreach (Variable/*!*/ v in vs) { - Contract.Assert(v != null); - stream.Write(sep); - sep = ", "; - stream.sep(); - v.EmitVitals(stream, 0, emitAttributes); - } - stream.pop(); - } - - public static void Emit(this List tys, TokenTextWriter stream, string separator) { - Contract.Requires(separator != null); - Contract.Requires(stream != null); - string sep = ""; - foreach (Type/*!*/ v in tys) { - Contract.Assert(v != null); - stream.Write(sep); - sep = separator; - v.Emit(stream); - } - } - - public static void Emit(this List tvs, TokenTextWriter stream, string separator) { - Contract.Requires(separator != null); - Contract.Requires(stream != null); - string sep = ""; - foreach (TypeVariable/*!*/ v in tvs) { - Contract.Assert(v != null); - stream.Write(sep); - sep = separator; - v.Emit(stream); - } - } - - } - #endregion - - - #region Regular Expressions - // a data structure to recover the "program structure" from the flow graph - public abstract class RE : Cmd { - public RE() - : base(Token.NoToken) { - } - public override void AddAssignedVariables(List vars) { - //Contract.Requires(vars != null); - throw new NotImplementedException(); - } - } - public class AtomicRE : RE { - private Block/*!*/ _b; - - public Block b - { - get - { - Contract.Ensures(Contract.Result() != null); - return this._b; - } - set - { - Contract.Requires(value != null); - this._b = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._b != null); - } - - public AtomicRE(Block block) { - Contract.Requires(block != null); - this._b = block; - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - b.Resolve(rc); - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - b.Typecheck(tc); - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - b.Emit(stream, level); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitAtomicRE(this); - } - } - public abstract class CompoundRE : RE { - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - return; - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - return; - } - } - public class Sequential : CompoundRE { - private RE/*!*/ _first; - - public RE/*!*/ first { - get { - Contract.Ensures(Contract.Result() != null); - return this._first; - } - set { - Contract.Requires(value != null); - this._first = value; - } - } - - private RE/*!*/ _second; - - public RE/*!*/ second { - get { - Contract.Ensures(Contract.Result() != null); - return this._second; - } - set { - Contract.Requires(value != null); - this._second = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._first != null); - Contract.Invariant(this._second != null); - } - - public Sequential(RE first, RE second) { - Contract.Requires(first != null); - Contract.Requires(second != null); - this._first = first; - this._second = second; - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.WriteLine(); - stream.WriteLine("{0};", Indent(stream.UseForComputingChecksums ? 0 : level)); - first.Emit(stream, level + 1); - second.Emit(stream, level + 1); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitSequential(this); - } - } - public class Choice : CompoundRE { - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._rs != null); - } - - private List/*!*/ _rs; - - public List/*!*/ rs { //Rename this (and _rs) if possible - get { - Contract.Ensures(Contract.Result>() != null); - return this._rs; - } - set { - Contract.Requires(value != null); - this._rs = value; - } - } - - public Choice(List operands) { - Contract.Requires(operands != null); - this._rs = operands; - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.WriteLine(); - stream.WriteLine("{0}[]", Indent(stream.UseForComputingChecksums ? 0 : level)); - foreach (RE/*!*/ r in rs) { - Contract.Assert(r != null); - r.Emit(stream, level + 1); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitChoice(this); - } - } - public class DAG2RE { - public static RE Transform(Block b) { - Contract.Requires(b != null); - Contract.Ensures(Contract.Result() != null); - TransferCmd tc = b.TransferCmd; - if (tc is ReturnCmd) { - return new AtomicRE(b); - } else if (tc is GotoCmd) { - GotoCmd/*!*/ g = (GotoCmd)tc; - Contract.Assert(g != null); - Contract.Assume(g.labelTargets != null); - if (g.labelTargets.Count == 1) { - return new Sequential(new AtomicRE(b), Transform(cce.NonNull(g.labelTargets[0]))); - } else { - List rs = new List(); - foreach (Block/*!*/ target in g.labelTargets) { - Contract.Assert(target != null); - RE r = Transform(target); - rs.Add(r); - } - RE second = new Choice(rs); - return new Sequential(new AtomicRE(b), second); - } - } else { - Contract.Assume(false); - throw new cce.UnreachableException(); - } - } - } - - #endregion - - // NOTE: This class is here for convenience, since this file's - // classes are used pretty much everywhere. - - public class BoogieDebug { - public static bool DoPrinting = false; - - public static void Write(string format, params object[] args) { - Contract.Requires(args != null); - Contract.Requires(format != null); - if (DoPrinting) { - Console.Error.Write(format, args); - } - } - - public static void WriteLine(string format, params object[] args) { - Contract.Requires(args != null); - Contract.Requires(format != null); - if (DoPrinting) { - Console.Error.WriteLine(format, args); - } - } - - public static void WriteLine() { - if (DoPrinting) { - Console.Error.WriteLine(); - } - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- +// BoogiePL - Absy.cs +//--------------------------------------------------------------------------------------------- +namespace Microsoft.Boogie.AbstractInterpretation { + using System.Diagnostics; + using System.Diagnostics.Contracts; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + public class CallSite { + public readonly Implementation/*!*/ Impl; + public readonly Block/*!*/ Block; + public readonly int Statement; // invariant: Block[Statement] is CallCmd + public readonly ProcedureSummaryEntry/*!*/ SummaryEntry; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Impl != null); + Contract.Invariant(Block != null); + Contract.Invariant(SummaryEntry != null); + } + + + public CallSite(Implementation impl, Block b, int stmt, ProcedureSummaryEntry summaryEntry) { + Contract.Requires(summaryEntry != null); + Contract.Requires(b != null); + Contract.Requires(impl != null); + this.Impl = impl; + this.Block = b; + this.Statement = stmt; + this.SummaryEntry = summaryEntry; + } + } + + public class ProcedureSummaryEntry { + + private HashSet/*!*/ _returnPoints; // whenever OnExit changes, we start analysis again at all the ReturnPoints + + public HashSet/*!*/ ReturnPoints { + get { + Contract.Ensures(Contract.Result>() != null); + return this._returnPoints; + } + set { + Contract.Requires(value != null); + this._returnPoints = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._returnPoints != null); + } + + public ProcedureSummaryEntry() { + this._returnPoints = new HashSet(); + } + + } // class + + public class ProcedureSummary : ArrayList/**/ + { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant( + !IsReadOnly && !IsFixedSize); + } + + public new ProcedureSummaryEntry/*!*/ this[int i] { + get { + Contract.Requires(0 <= i && i < Count); + Contract.Ensures(Contract.Result() != null); + return cce.NonNull((ProcedureSummaryEntry/*!*/)base[i]); + } + } + + } // class +} // namespace + +namespace Microsoft.Boogie { + using System; + using System.Linq; + using System.Collections; + using System.Diagnostics; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Diagnostics.Contracts; + using Microsoft.Boogie.AbstractInterpretation; + using Microsoft.Boogie.GraphUtil; + using Set = GSet; + + [ContractClass(typeof(AbsyContracts))] + public abstract class Absy { + private IToken/*!*/ _tok; + private int uniqueId; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._tok != null); + } + + public IToken tok { //Rename this property and "_tok" if possible + get { + Contract.Ensures(Contract.Result() != null); + return this._tok; + } + set { + Contract.Requires(value != null); + this._tok = value; + } + } + + public int Line { + get { + return tok != null ? tok.line : -1; + } + } + public int Col { + get { + return tok != null ? tok.col : -1; + } + } + + public Absy(IToken tok) { + Contract.Requires(tok != null); + this._tok = tok; + this.uniqueId = System.Threading.Interlocked.Increment(ref CurrentAbsyNodeId); + } + + private static int CurrentAbsyNodeId = -1; + + // We uniquely number every AST node to make them + // suitable for our implementation of functional maps. + // + public int UniqueId { + get { + return this.uniqueId; + } + } + + private const int indent_size = 2; + protected static string Indent(int level) { + return new string(' ', (indent_size * level)); + } + [NeedsContracts] + public abstract void Resolve(ResolutionContext/*!*/ rc); + + /// + /// Requires the object to have been successfully resolved. + /// + /// + [NeedsContracts] + public abstract void Typecheck(TypecheckingContext/*!*/ tc); + /// + /// Intorduced this so the uniqueId is not the same on a cloned object. + /// + /// + public virtual Absy Clone() { + Contract.Ensures(Contract.Result() != null); + Absy/*!*/ result = cce.NonNull((Absy/*!*/)this.MemberwiseClone()); + result.uniqueId = System.Threading.Interlocked.Increment(ref CurrentAbsyNodeId); // BUGBUG?? + + if (InternalNumberedMetadata != null) { + // This should probably use the lock + result.InternalNumberedMetadata = new List(this.InternalNumberedMetadata); + } + + return result; + } + + public virtual Absy StdDispatch(StandardVisitor visitor) { + Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + System.Diagnostics.Debug.Fail("Unknown Absy node type: " + this.GetType()); + throw new System.NotImplementedException(); + } + + #region numberedmetadata + // Implementation of Numbered Metadata + // This allows any number of arbitrary objects to be + // associated with an instance of an Absy at run time + // in a type safe manner using an integer as a key. + + // We could use a dictionary but we use a List for look up speed + // For this to work well the user needs to use small integers as + // keys. The list is created lazily to minimise memory overhead. + private volatile List InternalNumberedMetadata = null; + + // The lock exists to ensure that InternalNumberedMetadata is a singleton + // for every instance of this class. + // It is static to minimise the memory overhead (we don't want a lock per instance). + private static readonly Object NumberedMetadataLock = new object(); + + /// + /// Gets the number of meta data objects associated with this instance + /// + /// The numbered meta data count. + public int NumberedMetaDataCount + { + get { return InternalNumberedMetadata == null? 0: InternalNumberedMetadata.Count; } + } + + /// + /// Gets an IEnumerable over the numbered metadata associated + /// with this instance. + /// + /// + /// The numbered meta data enumerable that looks like the Enumerable + /// of a dictionary. + /// + public IEnumerable> NumberedMetadata + { + get { + if (InternalNumberedMetadata == null) + return Enumerable.Empty>(); + else + return InternalNumberedMetadata.Select((v, index) => new KeyValuePair(index, v)); + } + } + + /// + /// Gets the metatdata at specified index. + /// ArgumentOutOfRange exception is raised if it is not available. + /// InvalidCastExcpetion is raised if the metadata is available but the wrong type was requested. + /// + /// The stored metadata of type T + /// The index of the metadata + /// The type of the metadata object required + public T GetMetadata(int index) { + // We aren't using NumberedMetadataLock for speed. Perhaps we should be using it? + if (InternalNumberedMetadata == null) + throw new ArgumentOutOfRangeException(); + + if (InternalNumberedMetadata[index] is T) + return (T) InternalNumberedMetadata[index]; + else if (InternalNumberedMetadata[index] == null) { + throw new InvalidCastException("Numbered metadata " + index + + " is null which cannot be casted to " + typeof(T)); + } + else { + throw new InvalidCastException("Numbered metadata " + index + + " is of type " + InternalNumberedMetadata[index].GetType() + + " rather than requested type " + typeof(T)); + } + } + + private void InitialiseNumberedMetadata() { + // Ensure InternalNumberedMetadata is a singleton + if (InternalNumberedMetadata == null) { + lock (NumberedMetadataLock) { + if (InternalNumberedMetadata == null) + InternalNumberedMetadata = new List(); + } + } + } + + /// + /// Sets the metadata for this instace at a specified index. + /// + /// The index of the metadata + /// The value to set + /// The type of value + public void SetMetadata(int index, T value) { + InitialiseNumberedMetadata(); + + if (index < 0) + throw new IndexOutOfRangeException(); + + lock (NumberedMetadataLock) { + if (index < InternalNumberedMetadata.Count) + InternalNumberedMetadata[index] = value; + else { + // Make sure expansion only happens once whilst we pad + if (InternalNumberedMetadata.Capacity <= index) { + // Use the next available power of 2 + InternalNumberedMetadata.Capacity = (int) Math.Pow(2, Math.Ceiling(Math.Log(index+1,2))); + } + + // Pad with nulls + while (InternalNumberedMetadata.Count < index) + InternalNumberedMetadata.Add (null); + + InternalNumberedMetadata.Add(value); + Debug.Assert(InternalNumberedMetadata.Count == (index + 1)); + } + } + } + + #endregion + + } + + [ContractClassFor(typeof(Absy))] + public abstract class AbsyContracts : Absy { + public override void Resolve(ResolutionContext rc) { + Contract.Requires(rc != null); + throw new NotImplementedException(); + } + public AbsyContracts() :base(null){ + + } + public override void Typecheck(TypecheckingContext tc) { + Contract.Requires(tc != null); + throw new NotImplementedException(); + } + } + + public interface IPotentialErrorNode + { + TGet ErrorData + { + get; + } + } + + public interface IPotentialErrorNode : IPotentialErrorNode + { + new TSet ErrorData + { + set; + } + } + + public class Program : Absy { + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cce.NonNullElements(this.topLevelDeclarations)); + Contract.Invariant(cce.NonNullElements(this.globalVariablesCache, true)); + } + + public Program() + : base(Token.NoToken) { + this.topLevelDeclarations = new List(); + } + + public void Emit(TokenTextWriter stream) { + Contract.Requires(stream != null); + stream.SetToken(this); + this.topLevelDeclarations.Emit(stream); + } + + public void ProcessDatatypeConstructors() { + Dictionary constructors = new Dictionary(); + List prunedTopLevelDeclarations = new List(); + foreach (Declaration decl in TopLevelDeclarations) { + Function func = decl as Function; + if (func == null || !QKeyValue.FindBoolAttribute(decl.Attributes, "constructor")) { + prunedTopLevelDeclarations.Add(decl); + continue; + } + if (constructors.ContainsKey(func.Name)) continue; + DatatypeConstructor constructor = new DatatypeConstructor(func); + constructors.Add(func.Name, constructor); + prunedTopLevelDeclarations.Add(constructor); + } + ClearTopLevelDeclarations(); + AddTopLevelDeclarations(prunedTopLevelDeclarations); + + foreach (DatatypeConstructor f in constructors.Values) { + for (int i = 0; i < f.InParams.Count; i++) { + DatatypeSelector selector = new DatatypeSelector(f, i); + f.selectors.Add(selector); + AddTopLevelDeclaration(selector); + } + DatatypeMembership membership = new DatatypeMembership(f); + f.membership = membership; + AddTopLevelDeclaration(membership); + } + } + + /// + /// Returns the number of name resolution errors. + /// + /// + public int Resolve() { + return Resolve((IErrorSink)null); + } + + public int Resolve(IErrorSink errorSink) { + ResolutionContext rc = new ResolutionContext(errorSink); + Resolve(rc); + return rc.ErrorCount; + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + Helpers.ExtraTraceInformation("Starting resolution"); + + foreach (var d in TopLevelDeclarations) { + d.Register(rc); + } + + ResolveTypes(rc); + + var prunedTopLevelDecls = new List(); + foreach (var d in TopLevelDeclarations) { + if (QKeyValue.FindBoolAttribute(d.Attributes, "ignore")) { + continue; + } + // resolve all the non-type-declarations + if (!(d is TypeCtorDecl || d is TypeSynonymDecl)) { + int e = rc.ErrorCount; + d.Resolve(rc); + if (CommandLineOptions.Clo.OverlookBoogieTypeErrors && rc.ErrorCount != e && d is Implementation) { + // ignore this implementation + System.Console.WriteLine("Warning: Ignoring implementation {0} because of translation resolution errors", ((Implementation)d).Name); + rc.ErrorCount = e; + continue; + } + } + prunedTopLevelDecls.Add(d); + } + ClearTopLevelDeclarations(); + AddTopLevelDeclarations(prunedTopLevelDecls); + + foreach (var v in Variables) { + v.ResolveWhere(rc); + } + } + + private void ResolveTypes(ResolutionContext rc) { + Contract.Requires(rc != null); + // first resolve type constructors + foreach (var d in TopLevelDeclarations.OfType()) { + if (!QKeyValue.FindBoolAttribute(d.Attributes, "ignore")) + d.Resolve(rc); + } + + // collect type synonym declarations + List/*!*/ synonymDecls = new List(); + foreach (var d in TopLevelDeclarations.OfType()) { + Contract.Assert(d != null); + if (!QKeyValue.FindBoolAttribute(d.Attributes, "ignore")) + synonymDecls.Add((TypeSynonymDecl)d); + } + + // then resolve the type synonyms by a simple + // fixed-point iteration + TypeSynonymDecl.ResolveTypeSynonyms(synonymDecls, rc); + } + + public int Typecheck() { + return this.Typecheck((IErrorSink)null); + } + + public int Typecheck(IErrorSink errorSink) { + TypecheckingContext tc = new TypecheckingContext(errorSink); + Typecheck(tc); + return tc.ErrorCount; + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + Helpers.ExtraTraceInformation("Starting typechecking"); + + int oldErrorCount = tc.ErrorCount; + foreach (var d in TopLevelDeclarations) { + d.Typecheck(tc); + } + + if (oldErrorCount == tc.ErrorCount) { + // check whether any type proxies have remained uninstantiated + TypeAmbiguitySeeker/*!*/ seeker = new TypeAmbiguitySeeker(tc); + foreach (var d in TopLevelDeclarations) { + seeker.Visit(d); + } + } + } + + public override Absy Clone() + { + var cloned = (Program)base.Clone(); + cloned.topLevelDeclarations = new List(); + cloned.AddTopLevelDeclarations(topLevelDeclarations); + return cloned; + } + + [Rep] + private List/*!*/ topLevelDeclarations; + + public IEnumerable TopLevelDeclarations + { + get + { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return topLevelDeclarations.AsReadOnly(); + } + + set + { + Contract.Requires(value != null); + // materialize the decls, in case there is any dependency + // back on topLevelDeclarations + var v = value.ToList(); + // remove null elements + v.RemoveAll(d => (d == null)); + // now clear the decls + ClearTopLevelDeclarations(); + // and add the values + AddTopLevelDeclarations(v); + } + } + + public void AddTopLevelDeclaration(Declaration decl) + { + Contract.Requires(!TopLevelDeclarationsAreFrozen); + Contract.Requires(decl != null); + + topLevelDeclarations.Add(decl); + this.globalVariablesCache = null; + } + + public void AddTopLevelDeclarations(IEnumerable decls) + { + Contract.Requires(!TopLevelDeclarationsAreFrozen); + Contract.Requires(cce.NonNullElements(decls)); + + topLevelDeclarations.AddRange(decls); + this.globalVariablesCache = null; + } + + public void RemoveTopLevelDeclaration(Declaration decl) + { + Contract.Requires(!TopLevelDeclarationsAreFrozen); + + topLevelDeclarations.Remove(decl); + this.globalVariablesCache = null; + } + + public void RemoveTopLevelDeclarations(Predicate match) + { + Contract.Requires(!TopLevelDeclarationsAreFrozen); + + topLevelDeclarations.RemoveAll(match); + this.globalVariablesCache = null; + } + + public void ClearTopLevelDeclarations() + { + Contract.Requires(!TopLevelDeclarationsAreFrozen); + + topLevelDeclarations.Clear(); + this.globalVariablesCache = null; + } + + bool topLevelDeclarationsAreFrozen; + public bool TopLevelDeclarationsAreFrozen { get { return topLevelDeclarationsAreFrozen; } } + public void FreezeTopLevelDeclarations() + { + topLevelDeclarationsAreFrozen = true; + } + + Dictionary implementationsCache; + public IEnumerable Implementations + { + get + { + if (implementationsCache != null) + { + return implementationsCache.Values; + } + var result = TopLevelDeclarations.OfType(); + if (topLevelDeclarationsAreFrozen) + { + implementationsCache = result.ToDictionary(p => p.Id); + } + return result; + } + } + + public Implementation FindImplementation(string id) + { + Implementation result = null; + if (implementationsCache != null && implementationsCache.TryGetValue(id, out result)) + { + return result; + } + else + { + return Implementations.FirstOrDefault(i => i.Id == id); + } + } + + List axiomsCache; + public IEnumerable Axioms + { + get + { + if (axiomsCache != null) + { + return axiomsCache; + } + var result = TopLevelDeclarations.OfType(); + if (topLevelDeclarationsAreFrozen) + { + axiomsCache = result.ToList(); + } + return result; + } + } + + Dictionary proceduresCache; + public IEnumerable Procedures + { + get + { + if (proceduresCache != null) + { + return proceduresCache.Values; + } + var result = TopLevelDeclarations.OfType(); + if (topLevelDeclarationsAreFrozen) + { + proceduresCache = result.ToDictionary(p => p.Name); + } + return result; + } + } + + public Procedure FindProcedure(string name) + { + Procedure result = null; + if (proceduresCache != null && proceduresCache.TryGetValue(name, out result)) + { + return result; + } + else + { + return Procedures.FirstOrDefault(p => p.Name == name); + } + } + + Dictionary functionsCache; + public IEnumerable Functions + { + get + { + if (functionsCache != null) + { + return functionsCache.Values; + } + var result = TopLevelDeclarations.OfType(); + if (topLevelDeclarationsAreFrozen) + { + functionsCache = result.ToDictionary(f => f.Name); + } + return result; + } + } + + public Function FindFunction(string name) + { + Function result = null; + if (functionsCache != null && functionsCache.TryGetValue(name, out result)) + { + return result; + } + else + { + return Functions.FirstOrDefault(f => f.Name == name); + } + } + + public IEnumerable Variables + { + get + { + return TopLevelDeclarations.OfType(); + } + } + + public IEnumerable Constants + { + get + { + return TopLevelDeclarations.OfType(); + } + } + + private IEnumerable globalVariablesCache = null; + public List/*!*/ GlobalVariables + { + get + { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + + if (globalVariablesCache == null) + globalVariablesCache = TopLevelDeclarations.OfType(); + + return new List(globalVariablesCache); + } + } + + public readonly ISet NecessaryAssumes = new HashSet(); + + public IEnumerable Blocks() + { + return Implementations.Select(Item => Item.Blocks).SelectMany(Item => Item); + } + + public void ComputeStronglyConnectedComponents() { + foreach (var d in this.TopLevelDeclarations) { + d.ComputeStronglyConnectedComponents(); + } + } + + /// + /// Reset the abstract stated computed before + /// + public void ResetAbstractInterpretationState() { + foreach (var d in this.TopLevelDeclarations) { + d.ResetAbstractInterpretationState(); + } + } + + public void UnrollLoops(int n, bool uc) { + Contract.Requires(0 <= n); + foreach (var impl in Implementations) { + if (impl.Blocks != null && impl.Blocks.Count > 0) { + cce.BeginExpose(impl); + { + Block start = impl.Blocks[0]; + Contract.Assume(start != null); + Contract.Assume(cce.IsConsistent(start)); + impl.Blocks = LoopUnroll.UnrollLoops(start, n, uc); + impl.FreshenCaptureStates(); + } + cce.EndExpose(); + } + } + } + + + /// + /// Finds blocks that break out of a loop in NaturalLoops(header, backEdgeNode) + /// + /// + /// + /// + private HashSet GetBreakBlocksOfLoop(Block header, Block backEdgeNode, Graph/*!*/ g) + { + Contract.Assert(CommandLineOptions.Clo.DeterministicExtractLoops, "Can only be called with /deterministicExtractLoops option"); + var immSuccBlks = new HashSet(); + var loopBlocks = g.NaturalLoops(header, backEdgeNode); + foreach (Block/*!*/ block in loopBlocks) + { + Contract.Assert(block != null); + var auxCmd = block.TransferCmd as GotoCmd; + if (auxCmd == null) continue; + foreach (var bl in auxCmd.labelTargets) + { + if (loopBlocks.Contains(bl)) continue; + immSuccBlks.Add(bl); + } + } + return immSuccBlks; + } + + private HashSet GetBlocksInAllNaturalLoops(Block header, Graph/*!*/ g) + { + Contract.Assert(CommandLineOptions.Clo.DeterministicExtractLoops, "Can only be called with /deterministicExtractLoops option"); + var allBlocksInNaturalLoops = new HashSet(); + foreach (Block/*!*/ source in g.BackEdgeNodes(header)) + { + Contract.Assert(source != null); + g.NaturalLoops(header, source).Iter(b => allBlocksInNaturalLoops.Add(b)); + } + return allBlocksInNaturalLoops; + } + + + void CreateProceduresForLoops(Implementation impl, Graph/*!*/ g, + List/*!*/ loopImpls, + Dictionary> fullMap) { + Contract.Requires(impl != null); + Contract.Requires(cce.NonNullElements(loopImpls)); + // Enumerate the headers + // for each header h: + // create implementation p_h with + // inputs = inputs, outputs, and locals of impl + // outputs = outputs and locals of impl + // locals = empty set + // add call o := p_h(i) at the beginning of the header block + // break the back edges whose target is h + // Enumerate the headers again to create the bodies of p_h + // for each header h: + // compute the loop corresponding to h + // make copies of all blocks in the loop for h + // delete all target edges that do not go to a block in the loop + // create a new entry block and a new return block + // add edges from entry block to the loop header and the return block + // add calls o := p_h(i) at the end of the blocks that are sources of back edges + foreach (Block block in impl.Blocks) + { + AddToFullMap(fullMap, impl.Name, block.Label, block); + } + + bool detLoopExtract = CommandLineOptions.Clo.DeterministicExtractLoops; + + Dictionary/*!*/>/*!*/ loopHeaderToInputs = new Dictionary/*!*/>(); + Dictionary/*!*/>/*!*/ loopHeaderToOutputs = new Dictionary/*!*/>(); + Dictionary/*!*/>/*!*/ loopHeaderToSubstMap = new Dictionary/*!*/>(); + Dictionary/*!*/ loopHeaderToLoopProc = new Dictionary(); + Dictionary/*!*/ loopHeaderToCallCmd1 = new Dictionary(); + Dictionary loopHeaderToCallCmd2 = new Dictionary(); + Dictionary loopHeaderToAssignCmd = new Dictionary(); + + foreach (Block/*!*/ header in g.Headers) { + Contract.Assert(header != null); + Contract.Assert(header != null); + List inputs = new List(); + List outputs = new List(); + List callInputs1 = new List(); + List callOutputs1 = new List(); + List callInputs2 = new List(); + List callOutputs2 = new List(); + List lhss = new List(); + List rhss = new List(); + Dictionary substMap = new Dictionary(); // Variable -> IdentifierExpr + + List/*!*/ targets = new List(); + HashSet footprint = new HashSet(); + + foreach (Block/*!*/ b in g.BackEdgeNodes(header)) + { + Contract.Assert(b != null); + HashSet immSuccBlks = new HashSet(); + if (detLoopExtract) + { + //Need to get the blocks that exit the loop, as we need to add them to targets and footprint + immSuccBlks = GetBreakBlocksOfLoop(header, b, g); + } + foreach (Block/*!*/ block in g.NaturalLoops(header, b).Union(immSuccBlks)) + { + Contract.Assert(block != null); + foreach (Cmd/*!*/ cmd in block.Cmds) + { + Contract.Assert(cmd != null); + cmd.AddAssignedVariables(targets); + + VariableCollector c = new VariableCollector(); + c.Visit(cmd); + footprint.UnionWith(c.usedVars); + } + } + } + + List/*!*/ globalMods = new List(); + Set targetSet = new Set(); + foreach (Variable/*!*/ v in targets) + { + Contract.Assert(v != null); + if (targetSet.Contains(v)) + continue; + targetSet.Add(v); + if (v is GlobalVariable) + globalMods.Add(new IdentifierExpr(Token.NoToken, v)); + } + + foreach (Variable v in impl.InParams) { + Contract.Assert(v != null); + if (!footprint.Contains(v)) continue; + callInputs1.Add(new IdentifierExpr(Token.NoToken, v)); + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "in_" + v.Name, v.TypedIdent.Type), true); + inputs.Add(f); + callInputs2.Add(new IdentifierExpr(Token.NoToken, f)); + substMap[v] = new IdentifierExpr(Token.NoToken, f); + } + foreach (Variable v in impl.OutParams) { + Contract.Assert(v != null); + if (!footprint.Contains(v)) continue; + callInputs1.Add(new IdentifierExpr(Token.NoToken, v)); + Formal f1 = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "in_" + v.Name, v.TypedIdent.Type), true); + inputs.Add(f1); + if (targetSet.Contains(v)) + { + callOutputs1.Add(new IdentifierExpr(Token.NoToken, v)); + Formal f2 = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "out_" + v.Name, v.TypedIdent.Type), false); + outputs.Add(f2); + callInputs2.Add(new IdentifierExpr(Token.NoToken, f2)); + callOutputs2.Add(new IdentifierExpr(Token.NoToken, f2)); + lhss.Add(new SimpleAssignLhs(Token.NoToken, new IdentifierExpr(Token.NoToken, f2))); + rhss.Add(new IdentifierExpr(Token.NoToken, f1)); + substMap[v] = new IdentifierExpr(Token.NoToken, f2); + } + else + { + callInputs2.Add(new IdentifierExpr(Token.NoToken, f1)); + substMap[v] = new IdentifierExpr(Token.NoToken, f1); + } + } + foreach (Variable v in impl.LocVars) { + Contract.Assert(v != null); + if (!footprint.Contains(v)) continue; + callInputs1.Add(new IdentifierExpr(Token.NoToken, v)); + Formal f1 = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "in_" + v.Name, v.TypedIdent.Type), true); + inputs.Add(f1); + if (targetSet.Contains(v)) + { + callOutputs1.Add(new IdentifierExpr(Token.NoToken, v)); + Formal f2 = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "out_" + v.Name, v.TypedIdent.Type), false); + outputs.Add(f2); + callInputs2.Add(new IdentifierExpr(Token.NoToken, f2)); + callOutputs2.Add(new IdentifierExpr(Token.NoToken, f2)); + lhss.Add(new SimpleAssignLhs(Token.NoToken, new IdentifierExpr(Token.NoToken, f2))); + rhss.Add(new IdentifierExpr(Token.NoToken, f1)); + substMap[v] = new IdentifierExpr(Token.NoToken, f2); + } + else + { + callInputs2.Add(new IdentifierExpr(Token.NoToken, f1)); + substMap[v] = new IdentifierExpr(Token.NoToken, f1); + } + } + + loopHeaderToInputs[header] = inputs; + loopHeaderToOutputs[header] = outputs; + loopHeaderToSubstMap[header] = substMap; + LoopProcedure loopProc = new LoopProcedure(impl, header, inputs, outputs, globalMods); + loopHeaderToLoopProc[header] = loopProc; + + CallCmd callCmd1 = new CallCmd(Token.NoToken, loopProc.Name, callInputs1, callOutputs1); + callCmd1.Proc = loopProc; + loopHeaderToCallCmd1[header] = callCmd1; + + CallCmd callCmd2 = new CallCmd(Token.NoToken, loopProc.Name, callInputs2, callOutputs2); + callCmd2.Proc = loopProc; + loopHeaderToCallCmd2[header] = callCmd2; + + Debug.Assert(lhss.Count == rhss.Count); + if (lhss.Count > 0) + { + AssignCmd assignCmd = new AssignCmd(Token.NoToken, lhss, rhss); + loopHeaderToAssignCmd[header] = assignCmd; + } + } + + // Keep track of the new blocks created: maps a header node to the + // header_last block that was created because of splitting header. + Dictionary newBlocksCreated = new Dictionary(); + + bool headRecursion = false; // testing an option to put recursive call before loop body + + IEnumerable sortedHeaders = g.SortHeadersByDominance(); + foreach (Block/*!*/ header in sortedHeaders) + { + Contract.Assert(header != null); + LoopProcedure loopProc = loopHeaderToLoopProc[header]; + Dictionary blockMap = new Dictionary(); + HashSet dummyBlocks = new HashSet(); + + CodeCopier codeCopier = new CodeCopier(loopHeaderToSubstMap[header]); // fix me + List inputs = loopHeaderToInputs[header]; + List outputs = loopHeaderToOutputs[header]; + int si_unique_loc = 1; // Added by AL: to distinguish the back edges + foreach (Block/*!*/ source in g.BackEdgeNodes(header)) { + Contract.Assert(source != null); + foreach (Block/*!*/ block in g.NaturalLoops(header, source)) { + Contract.Assert(block != null); + if (blockMap.ContainsKey(block)) + continue; + Block newBlock = new Block(); + newBlock.Label = block.Label; + if (headRecursion && block == header) + { + CallCmd callCmd = (CallCmd)(loopHeaderToCallCmd2[header]).Clone(); + addUniqueCallAttr(si_unique_loc, callCmd); + si_unique_loc++; + newBlock.Cmds.Add(callCmd); // add the recursive call at head of loop + var rest = codeCopier.CopyCmdSeq(block.Cmds); + newBlock.Cmds.AddRange(rest); + } + else + newBlock.Cmds = codeCopier.CopyCmdSeq(block.Cmds); + blockMap[block] = newBlock; + if (newBlocksCreated.ContainsKey(block)) + { + Block newBlock2 = new Block(); + newBlock2.Label = newBlocksCreated[block].Label; + newBlock2.Cmds = codeCopier.CopyCmdSeq(newBlocksCreated[block].Cmds); + blockMap[newBlocksCreated[block]] = newBlock2; + } + //for detLoopExtract, need the immediate successors even outside the loop + if (detLoopExtract) { + GotoCmd auxGotoCmd = block.TransferCmd as GotoCmd; + Contract.Assert(auxGotoCmd != null && auxGotoCmd.labelNames != null && + auxGotoCmd.labelTargets != null && auxGotoCmd.labelTargets.Count >= 1); + //BUGFIX on 10/26/15: this contains nodes present in NaturalLoops for a different backedgenode + var loopNodes = GetBlocksInAllNaturalLoops(header, g); //var loopNodes = g.NaturalLoops(header, source); + foreach(var bl in auxGotoCmd.labelTargets) { + if (g.Nodes.Contains(bl) && //newly created blocks are not present in NaturalLoop(header, xx, g) + !loopNodes.Contains(bl)) { + Block auxNewBlock = new Block(); + auxNewBlock.Label = ((Block)bl).Label; + //these blocks may have read/write locals that are not present in naturalLoops + //we need to capture these variables + auxNewBlock.Cmds = codeCopier.CopyCmdSeq(((Block)bl).Cmds); + //add restoration code for such blocks + if (loopHeaderToAssignCmd.ContainsKey(header)) + { + AssignCmd assignCmd = loopHeaderToAssignCmd[header]; + auxNewBlock.Cmds.Add(assignCmd); + } + List lhsg = new List(); + List/*!*/ globalsMods = loopHeaderToLoopProc[header].Modifies; + foreach (IdentifierExpr gl in globalsMods) + lhsg.Add(new SimpleAssignLhs(Token.NoToken, gl)); + List rhsg = new List(); + foreach (IdentifierExpr gl in globalsMods) + rhsg.Add(new OldExpr(Token.NoToken, gl)); + if (lhsg.Count != 0) + { + AssignCmd globalAssignCmd = new AssignCmd(Token.NoToken, lhsg, rhsg); + auxNewBlock.Cmds.Add(globalAssignCmd); + } + blockMap[(Block)bl] = auxNewBlock; + } + } + + } + } + + List cmdSeq; + if (headRecursion) + cmdSeq = new List(); + else + { + CallCmd callCmd = (CallCmd)(loopHeaderToCallCmd2[header]).Clone(); + addUniqueCallAttr(si_unique_loc, callCmd); + si_unique_loc++; + cmdSeq = new List { callCmd }; + } + + Block/*!*/ block1 = new Block(Token.NoToken, source.Label + "_dummy", + new List{ new AssumeCmd(Token.NoToken, Expr.False) }, new ReturnCmd(Token.NoToken)); + Block/*!*/ block2 = new Block(Token.NoToken, block1.Label, + cmdSeq, new ReturnCmd(Token.NoToken)); + impl.Blocks.Add(block1); + dummyBlocks.Add(block1.Label); + + GotoCmd gotoCmd = source.TransferCmd as GotoCmd; + Contract.Assert(gotoCmd != null && gotoCmd.labelNames != null && gotoCmd.labelTargets != null && gotoCmd.labelTargets.Count >= 1); + List/*!*/ newLabels = new List(); + List/*!*/ newTargets = new List(); + for (int i = 0; i < gotoCmd.labelTargets.Count; i++) { + if (gotoCmd.labelTargets[i] == header) + continue; + newTargets.Add(gotoCmd.labelTargets[i]); + newLabels.Add(gotoCmd.labelNames[i]); + } + newTargets.Add(block1); + newLabels.Add(block1.Label); + gotoCmd.labelNames = newLabels; + gotoCmd.labelTargets = newTargets; + blockMap[block1] = block2; + } + List/*!*/ blocks = new List(); + Block exit = new Block(Token.NoToken, "exit", new List(), new ReturnCmd(Token.NoToken)); + GotoCmd cmd = new GotoCmd(Token.NoToken, + new List { cce.NonNull(blockMap[header]).Label, exit.Label }, + new List { blockMap[header], exit }); + + if (detLoopExtract) //cutting the non-determinism + cmd = new GotoCmd(Token.NoToken, + new List { cce.NonNull(blockMap[header]).Label }, + new List { blockMap[header] }); + + Block entry; + List initCmds = new List(); + if (loopHeaderToAssignCmd.ContainsKey(header)) { + AssignCmd assignCmd = loopHeaderToAssignCmd[header]; + initCmds.Add(assignCmd); + } + + entry = new Block(Token.NoToken, "entry", initCmds, cmd); + blocks.Add(entry); + + foreach (Block/*!*/ block in blockMap.Keys) { + Contract.Assert(block != null); + Block/*!*/ newBlock = cce.NonNull(blockMap[block]); + GotoCmd gotoCmd = block.TransferCmd as GotoCmd; + if (gotoCmd == null) { + newBlock.TransferCmd = new ReturnCmd(Token.NoToken); + } else { + Contract.Assume(gotoCmd.labelNames != null && gotoCmd.labelTargets != null); + List newLabels = new List(); + List newTargets = new List(); + for (int i = 0; i < gotoCmd.labelTargets.Count; i++) { + Block target = gotoCmd.labelTargets[i]; + if (blockMap.ContainsKey(target)) { + newLabels.Add(gotoCmd.labelNames[i]); + newTargets.Add(blockMap[target]); + } + } + if (newTargets.Count == 0) { + if (!detLoopExtract) + newBlock.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.False)); + newBlock.TransferCmd = new ReturnCmd(Token.NoToken); + } else { + newBlock.TransferCmd = new GotoCmd(Token.NoToken, newLabels, newTargets); + } + } + blocks.Add(newBlock); + } + blocks.Add(exit); + Implementation loopImpl = + new Implementation(Token.NoToken, loopProc.Name, + new List(), inputs, outputs, new List(), blocks); + loopImpl.Proc = loopProc; + loopImpls.Add(loopImpl); + + // Make a (shallow) copy of the header before splitting it + Block origHeader = new Block(header.tok, header.Label, header.Cmds, header.TransferCmd); + + // Finally, add call to the loop in the containing procedure + string lastIterBlockName = header.Label + "_last"; + Block lastIterBlock = new Block(Token.NoToken, lastIterBlockName, header.Cmds, header.TransferCmd); + newBlocksCreated[header] = lastIterBlock; + header.Cmds = new List { loopHeaderToCallCmd1[header] }; + header.TransferCmd = new GotoCmd(Token.NoToken, new List { lastIterBlockName }, new List { lastIterBlock }); + impl.Blocks.Add(lastIterBlock); + blockMap[origHeader] = blockMap[header]; + blockMap.Remove(header); + + Contract.Assert(fullMap[impl.Name][header.Label] == header); + fullMap[impl.Name][header.Label] = origHeader; + + foreach (Block block in blockMap.Keys) + { + // Don't add dummy blocks to the map + if (dummyBlocks.Contains(blockMap[block].Label)) continue; + + // Following two statements are for nested loops: compose map + if (!fullMap[impl.Name].ContainsKey(block.Label)) continue; + var target = fullMap[impl.Name][block.Label]; + + AddToFullMap(fullMap, loopProc.Name, blockMap[block].Label, target); + } + + fullMap[impl.Name].Remove(header.Label); + fullMap[impl.Name][lastIterBlockName] = origHeader; + } + } + + private void addUniqueCallAttr(int val, CallCmd cmd) + { + var a = new List(); + a.Add(new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(val))); + + cmd.Attributes = new QKeyValue(Token.NoToken, "si_unique_call", a, cmd.Attributes); + } + + private void AddToFullMap(Dictionary> fullMap, string procName, string blockName, Block block) + { + if (!fullMap.ContainsKey(procName)) + fullMap[procName] = new Dictionary(); + fullMap[procName][blockName] = block; + } + + public static Graph BuildCallGraph(Program program) { + Graph callGraph = new Graph(); + Dictionary> procToImpls = new Dictionary>(); + foreach (var proc in program.Procedures) { + procToImpls[proc] = new HashSet(); + } + foreach (var impl in program.Implementations) { + if (impl.SkipVerification) continue; + callGraph.AddSource(impl); + procToImpls[impl.Proc].Add(impl); + } + foreach (var impl in program.Implementations) { + if (impl.SkipVerification) continue; + foreach (Block b in impl.Blocks) { + foreach (Cmd c in b.Cmds) { + CallCmd cc = c as CallCmd; + if (cc == null) continue; + foreach (Implementation callee in procToImpls[cc.Proc]) { + callGraph.AddEdge(impl, callee); + } + } + } + } + return callGraph; + } + + public static Graph/*!*/ GraphFromImpl(Implementation impl) { + Contract.Requires(impl != null); + Contract.Ensures(cce.NonNullElements(Contract.Result>().Nodes)); + Contract.Ensures(Contract.Result>() != null); + + Graph g = new Graph(); + g.AddSource(impl.Blocks[0]); // there is always at least one node in the graph + + foreach (Block b in impl.Blocks) { + Contract.Assert(b != null); + GotoCmd gtc = b.TransferCmd as GotoCmd; + if (gtc != null) { + foreach (Block/*!*/ dest in cce.NonNull(gtc.labelTargets)) { + Contract.Assert(dest != null); + g.AddEdge(b, dest); + } + } + } + return g; + } + + public class IrreducibleLoopException : Exception {} + + public Graph ProcessLoops(Implementation impl) { + while (true) { + impl.PruneUnreachableBlocks(); + impl.ComputePredecessorsForBlocks(); + Graph/*!*/ g = GraphFromImpl(impl); + g.ComputeLoops(); + if (g.Reducible) { + return g; + } + throw new IrreducibleLoopException(); +#if USED_CODE + System.Diagnostics.Debug.Assert(g.SplitCandidates.Count > 0); + Block splitCandidate = null; + foreach (Block b in g.SplitCandidates) { + if (b.Predecessors.Length > 1) { + splitCandidate = b; + break; + } + } + System.Diagnostics.Debug.Assert(splitCandidate != null); + int count = 0; + foreach (Block b in splitCandidate.Predecessors) { + GotoCmd gotoCmd = (GotoCmd)b.TransferCmd; + gotoCmd.labelNames.Remove(splitCandidate.Label); + gotoCmd.labelTargets.Remove(splitCandidate); + + CodeCopier codeCopier = new CodeCopier(new Hashtable(), new Hashtable()); + List newCmdSeq = codeCopier.CopyCmdSeq(splitCandidate.Cmds); + TransferCmd newTransferCmd; + GotoCmd splitGotoCmd = splitCandidate.TransferCmd as GotoCmd; + if (splitGotoCmd == null) { + newTransferCmd = new ReturnCmd(splitCandidate.tok); + } + else { + List newLabelNames = new List(); + newLabelNames.AddRange(splitGotoCmd.labelNames); + List newLabelTargets = new List(); + newLabelTargets.AddRange(splitGotoCmd.labelTargets); + newTransferCmd = new GotoCmd(splitCandidate.tok, newLabelNames, newLabelTargets); + } + Block copy = new Block(splitCandidate.tok, splitCandidate.Label + count++, newCmdSeq, newTransferCmd); + + impl.Blocks.Add(copy); + gotoCmd.AddTarget(copy); + } +#endif + } + } + + public Dictionary> ExtractLoops() + { + HashSet procsWithIrreducibleLoops = null; + return ExtractLoops(out procsWithIrreducibleLoops); + } + + public Dictionary> ExtractLoops(out HashSet procsWithIrreducibleLoops) + { + procsWithIrreducibleLoops = new HashSet(); + List/*!*/ loopImpls = new List(); + Dictionary> fullMap = new Dictionary>(); + foreach (var impl in this.Implementations) + { + if (impl.Blocks != null && impl.Blocks.Count > 0) + { + try + { + Graph g = ProcessLoops(impl); + CreateProceduresForLoops(impl, g, loopImpls, fullMap); + } + catch (IrreducibleLoopException) + { + System.Diagnostics.Debug.Assert(!fullMap.ContainsKey(impl.Name)); + fullMap[impl.Name] = null; + procsWithIrreducibleLoops.Add(impl.Name); + + if (CommandLineOptions.Clo.ExtractLoopsUnrollIrreducible) + { + // statically unroll loops in this procedure + + // First, build a map of the current blocks + var origBlocks = new Dictionary(); + foreach (var blk in impl.Blocks) origBlocks.Add(blk.Label, blk); + + // unroll + Block start = impl.Blocks[0]; + impl.Blocks = LoopUnroll.UnrollLoops(start, CommandLineOptions.Clo.RecursionBound, false); + + // Now construct the "map back" information + // Resulting block label -> original block + var blockMap = new Dictionary(); + foreach (var blk in impl.Blocks) + { + var sl = LoopUnroll.sanitizeLabel(blk.Label); + if (sl == blk.Label) blockMap.Add(blk.Label, blk); + else + { + Contract.Assert(origBlocks.ContainsKey(sl)); + blockMap.Add(blk.Label, origBlocks[sl]); + } + } + fullMap[impl.Name] = blockMap; + } + } + } + } + foreach (Implementation/*!*/ loopImpl in loopImpls) + { + Contract.Assert(loopImpl != null); + AddTopLevelDeclaration(loopImpl); + AddTopLevelDeclaration(loopImpl.Proc); + } + return fullMap; + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitProgram(this); + } + + int extractedFunctionCount; + public string FreshExtractedFunctionName() + { + var c = System.Threading.Interlocked.Increment(ref extractedFunctionCount); + return string.Format("##extracted_function##{0}", c); + } + + private int invariantGenerationCounter = 0; + + public Constant MakeExistentialBoolean() { + Constant ExistentialBooleanConstant = new Constant(Token.NoToken, new TypedIdent(tok, "_b" + invariantGenerationCounter, Microsoft.Boogie.Type.Bool), false); + invariantGenerationCounter++; + ExistentialBooleanConstant.AddAttribute("existential", new object[] { Expr.True }); + AddTopLevelDeclaration(ExistentialBooleanConstant); + return ExistentialBooleanConstant; + } + + public PredicateCmd CreateCandidateInvariant(Expr e, string tag = null) { + Constant ExistentialBooleanConstant = MakeExistentialBoolean(); + IdentifierExpr ExistentialBoolean = new IdentifierExpr(Token.NoToken, ExistentialBooleanConstant); + PredicateCmd invariant = new AssertCmd(Token.NoToken, Expr.Imp(ExistentialBoolean, e)); + if (tag != null) + invariant.Attributes = new QKeyValue(Token.NoToken, "tag", new List(new object[] { tag }), null); + return invariant; + } + } + + //--------------------------------------------------------------------- + // Declarations + + [ContractClass(typeof(DeclarationContracts))] + public abstract class Declaration : Absy { + public QKeyValue Attributes; + + public Declaration(IToken tok) + : base(tok) { + Contract.Requires(tok != null); + } + + protected void EmitAttributes(TokenTextWriter stream) { + Contract.Requires(stream != null); + for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { + kv.Emit(stream); + stream.Write(" "); + } + } + + protected void ResolveAttributes(ResolutionContext rc) { + Contract.Requires(rc != null); + for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { + kv.Resolve(rc); + } + } + + protected void TypecheckAttributes(TypecheckingContext rc) { + Contract.Requires(rc != null); + for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { + kv.Typecheck(rc); + } + } + + /// + /// If the declaration has an attribute {:name} or {:name true}, then set "result" to "true" and return "true". + /// If the declaration has an attribute {:name false}, then set "result" to "false" and return "true". + /// Otherwise, return "false" and leave "result" unchanged (which gives the caller an easy way to indicate + /// a default value if the attribute is not mentioned). + /// If there is more than one attribute called :name, then the last attribute rules. + /// + public bool CheckBooleanAttribute(string name, ref bool result) { + Contract.Requires(name != null); + var kv = FindAttribute(name); + if (kv != null) { + if (kv.Params.Count == 0) { + result = true; + return true; + } else if (kv.Params.Count == 1) { + var lit = kv.Params[0] as LiteralExpr; + if (lit != null && lit.isBool) { + result = lit.asBool; + return true; + } + } + } + return false; + } + + /// + /// Find and return the last occurrence of an attribute with the name "name", if any. If none, return null. + /// + public QKeyValue FindAttribute(string name) { + Contract.Requires(name != null); + QKeyValue res = null; + for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { + if (kv.Key == name) { + res = kv; + } + } + return res; + } + + // Look for {:name expr} in list of attributes. + public Expr FindExprAttribute(string name) { + Contract.Requires(name != null); + Expr res = null; + for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { + if (kv.Key == name) { + if (kv.Params.Count == 1 && kv.Params[0] is Expr) { + res = (Expr)kv.Params[0]; + } + } + } + return res; + } + + // Look for {:name string} in list of attributes. + public string FindStringAttribute(string name) { + Contract.Requires(name != null); + return QKeyValue.FindStringAttribute(this.Attributes, name); + } + + // Look for {:name N} or {:name N} in list of attributes. Return result in 'result' + // (which is not touched if there is no attribute specified). + // + // Returns false is there was an error processing the flag, true otherwise. + public bool CheckIntAttribute(string name, ref int result) { + Contract.Requires(name != null); + Expr expr = FindExprAttribute(name); + if (expr != null) { + if (expr is LiteralExpr && ((LiteralExpr)expr).isBigNum) { + result = ((LiteralExpr)expr).asBigNum.ToInt; + } else { + return false; + } + } + return true; + } + + public void AddAttribute(string name, params object[] vals) { + Contract.Requires(name != null); + QKeyValue kv; + for (kv = this.Attributes; kv != null; kv = kv.Next) { + if (kv.Key == name) { + kv.AddParams(vals); + break; + } + } + if (kv == null) { + Attributes = new QKeyValue(tok, name, new List(vals), Attributes); + } + } + + public abstract void Emit(TokenTextWriter/*!*/ stream, int level); + public abstract void Register(ResolutionContext/*!*/ rc); + + /// + /// Compute the strongly connected components of the declaration. + /// By default, it does nothing + /// + public virtual void ComputeStronglyConnectedComponents() { /* Does nothing */ + } + + /// + /// Reset the abstract stated computed before + /// + public virtual void ResetAbstractInterpretationState() { /* does nothing */ + } + } + [ContractClassFor(typeof(Declaration))] + public abstract class DeclarationContracts : Declaration { + public DeclarationContracts() :base(null){ + } + public override void Register(ResolutionContext rc) { + Contract.Requires(rc != null); + throw new NotImplementedException(); + } + public override void Emit(TokenTextWriter stream, int level) { + Contract.Requires(stream != null); + throw new NotImplementedException(); + } + } + + public class Axiom : Declaration { + private Expr/*!*/ expression; + + public Expr Expr { + get { + Contract.Ensures(Contract.Result() != null); + return this.expression; + } + set { + Contract.Requires(value != null); + this.expression = value; + } + } + + [ContractInvariantMethod] + void ExprInvariant() { + Contract.Invariant(this.expression != null); + } + + public string Comment; + + public Axiom(IToken tok, Expr expr) + : this(tok, expr, null) { + Contract.Requires(expr != null); + Contract.Requires(tok != null); + } + + public Axiom(IToken/*!*/ tok, Expr/*!*/ expr, string comment) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + this.expression = expr; + Comment = comment; + } + + public Axiom(IToken tok, Expr expr, string comment, QKeyValue kv) + : this(tok, expr, comment) { + Contract.Requires(expr != null); + Contract.Requires(tok != null); + this.Attributes = kv; + } + + public bool DependenciesCollected { get; set; } + + ISet functionDependencies; + + public ISet FunctionDependencies + { + get { return functionDependencies; } + } + + public void AddFunctionDependency(Function function) + { + Contract.Requires(function != null); + + if (functionDependencies == null) + { + functionDependencies = new HashSet(); + } + functionDependencies.Add(function); + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + if (Comment != null) { + stream.WriteLine(this, level, "// " + Comment); + } + stream.Write(this, level, "axiom "); + EmitAttributes(stream); + this.Expr.Emit(stream); + stream.WriteLine(";"); + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddAxiom(this); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + ResolveAttributes(rc); + rc.StateMode = ResolutionContext.State.StateLess; + Expr.Resolve(rc); + rc.StateMode = ResolutionContext.State.Single; + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + TypecheckAttributes(tc); + Expr.Typecheck(tc); + Contract.Assert(Expr.Type != null); // follows from postcondition of Expr.Typecheck + if (!Expr.Type.Unify(Type.Bool)) { + tc.Error(this, "axioms must be of type bool"); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitAxiom(this); + } + } + + public abstract class NamedDeclaration : Declaration { + private string/*!*/ name; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(name != null); + } + + public string/*!*/ Name { + get { + Contract.Ensures(Contract.Result() != null); + + return this.name; + } + set { + Contract.Requires(value != null); + this.name = value; + } + } + + public int TimeLimit + { + get + { + int tl = CommandLineOptions.Clo.ProverKillTime; + CheckIntAttribute("timeLimit", ref tl); + return tl; + } + } + + public NamedDeclaration(IToken/*!*/ tok, string/*!*/ name) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + this.name = name; + } + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result() != null); + return cce.NonNull(Name); + } + } + + public class TypeCtorDecl : NamedDeclaration { + public readonly int Arity; + + public TypeCtorDecl(IToken/*!*/ tok, string/*!*/ name, int Arity) + : base(tok, name) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + this.Arity = Arity; + } + public TypeCtorDecl(IToken/*!*/ tok, string/*!*/ name, int Arity, QKeyValue kv) + : base(tok, name) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + this.Arity = Arity; + this.Attributes = kv; + } + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "type "); + EmitAttributes(stream); + stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(Name)); + for (int i = 0; i < Arity; ++i) + stream.Write(" _"); + stream.WriteLine(";"); + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddType(this); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + ResolveAttributes(rc); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + TypecheckAttributes(tc); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitTypeCtorDecl(this); + } + } + + public class TypeSynonymDecl : NamedDeclaration { + private List/*!*/ typeParameters; + + public List TypeParameters { + get { + Contract.Ensures(Contract.Result>() != null); + return this.typeParameters; + } + set { + Contract.Requires(value != null); + this.typeParameters = value; + } + } + + private Type/*!*/ body; + + public Type Body { + get { + Contract.Ensures(Contract.Result() != null); + return this.body; + } + set { + Contract.Requires(value != null); + this.body = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this.body != null); + Contract.Invariant(this.typeParameters != null); + } + + public TypeSynonymDecl(IToken/*!*/ tok, string/*!*/ name, + List/*!*/ typeParams, Type/*!*/ body) + : base(tok, name) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + Contract.Requires(typeParams != null); + Contract.Requires(body != null); + this.typeParameters = typeParams; + this.body = body; + } + public TypeSynonymDecl(IToken/*!*/ tok, string/*!*/ name, + List/*!*/ typeParams, Type/*!*/ body, QKeyValue kv) + : base(tok, name) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + Contract.Requires(typeParams != null); + Contract.Requires(body != null); + this.typeParameters = typeParams; + this.body = body; + this.Attributes = kv; + } + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "type "); + EmitAttributes(stream); + stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(Name)); + if (TypeParameters.Count > 0) + stream.Write(" "); + TypeParameters.Emit(stream, " "); + stream.Write(" = "); + Body.Emit(stream); + stream.WriteLine(";"); + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddType(this); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + ResolveAttributes(rc); + + int previousState = rc.TypeBinderState; + try { + foreach (TypeVariable/*!*/ v in TypeParameters) { + Contract.Assert(v != null); + rc.AddTypeBinder(v); + } + Body = Body.ResolveType(rc); + } finally { + rc.TypeBinderState = previousState; + } + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + TypecheckAttributes(tc); + } + + public static void ResolveTypeSynonyms(List/*!*/ synonymDecls, ResolutionContext/*!*/ rc) { + Contract.Requires(cce.NonNullElements(synonymDecls)); + Contract.Requires(rc != null); + // then discover all dependencies between type synonyms + IDictionary/*!*/>/*!*/ deps = + new Dictionary/*!*/>(); + foreach (TypeSynonymDecl/*!*/ decl in synonymDecls) { + Contract.Assert(decl != null); + List/*!*/ declDeps = new List(); + FindDependencies(decl.Body, declDeps, rc); + deps.Add(decl, declDeps); + } + + List/*!*/ resolved = new List(); + + int unresolved = synonymDecls.Count - resolved.Count; + while (unresolved > 0) { + foreach (TypeSynonymDecl/*!*/ decl in synonymDecls) { + Contract.Assert(decl != null); + if (!resolved.Contains(decl) && + deps[decl].All(d => resolved.Contains(d))) { + decl.Resolve(rc); + resolved.Add(decl); + } + } + + int newUnresolved = synonymDecls.Count - resolved.Count; + if (newUnresolved < unresolved) { + // we are making progress + unresolved = newUnresolved; + } else { + // there have to be cycles in the definitions + foreach (TypeSynonymDecl/*!*/ decl in synonymDecls) { + Contract.Assert(decl != null); + if (!resolved.Contains(decl)) { + rc.Error(decl, + "type synonym could not be resolved because of cycles: {0}" + + " (replacing body with \"bool\" to continue resolving)", + decl.Name); + + // we simply replace the bodies of all remaining type + // synonyms with "bool" so that resolution can continue + decl.Body = Type.Bool; + decl.Resolve(rc); + } + } + + unresolved = 0; + } + } + } + + // determine a list of all type synonyms that occur in "type" + private static void FindDependencies(Type/*!*/ type, List/*!*/ deps, ResolutionContext/*!*/ rc) { + Contract.Requires(type != null); + Contract.Requires(cce.NonNullElements(deps)); + Contract.Requires(rc != null); + if (type.IsVariable || type.IsBasic) { + // nothing + } else if (type.IsUnresolved) { + UnresolvedTypeIdentifier/*!*/ unresType = type.AsUnresolved; + Contract.Assert(unresType != null); + TypeSynonymDecl dep = rc.LookUpTypeSynonym(unresType.Name); + if (dep != null) + deps.Add(dep); + foreach (Type/*!*/ subtype in unresType.Arguments) { + Contract.Assert(subtype != null); + FindDependencies(subtype, deps, rc); + } + } else if (type.IsMap) { + MapType/*!*/ mapType = type.AsMap; + Contract.Assert(mapType != null); + foreach (Type/*!*/ subtype in mapType.Arguments) { + Contract.Assert(subtype != null); + FindDependencies(subtype, deps, rc); + } + FindDependencies(mapType.Result, deps, rc); + } else if (type.IsCtor) { + // this can happen because we allow types to be resolved multiple times + CtorType/*!*/ ctorType = type.AsCtor; + Contract.Assert(ctorType != null); + foreach (Type/*!*/ subtype in ctorType.Arguments) { + Contract.Assert(subtype != null); + FindDependencies(subtype, deps, rc); + } + } else { + System.Diagnostics.Debug.Fail("Did not expect this type during resolution: " + + type); + } + } + + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitTypeSynonymDecl(this); + } + } + + public abstract class Variable : NamedDeclaration { + private TypedIdent/*!*/ typedIdent; + + public TypedIdent TypedIdent { + get { + Contract.Ensures(Contract.Result() != null); + return this.typedIdent; + } + set { + Contract.Requires(value != null); + this.typedIdent = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this.typedIdent != null); + } + + public Variable(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent) + : base(tok, typedIdent.Name) { + Contract.Requires(tok != null); + Contract.Requires(typedIdent != null); + this.typedIdent = typedIdent; + } + + public Variable(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent, QKeyValue kv) + : base(tok, typedIdent.Name) { + Contract.Requires(tok != null); + Contract.Requires(typedIdent != null); + this.typedIdent = typedIdent; + this.Attributes = kv; + } + + public abstract bool IsMutable { + get; + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "var "); + EmitVitals(stream, level, true); + stream.WriteLine(";"); + } + public void EmitVitals(TokenTextWriter stream, int level, bool emitAttributes) { + Contract.Requires(stream != null); + if (emitAttributes) { + EmitAttributes(stream); + } + if (CommandLineOptions.Clo.PrintWithUniqueASTIds && this.TypedIdent.HasName) { + stream.Write("h{0}^^", this.GetHashCode()); // the idea is that this will prepend the name printed by TypedIdent.Emit + } + this.TypedIdent.Emit(stream); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + this.TypedIdent.Resolve(rc); + } + public void ResolveWhere(ResolutionContext rc) { + Contract.Requires(rc != null); + if (QKeyValue.FindBoolAttribute(Attributes, "assumption") && this.TypedIdent.WhereExpr != null) + { + rc.Error(tok, "assumption variable may not be declared with a where clause"); + } + if (this.TypedIdent.WhereExpr != null) { + this.TypedIdent.WhereExpr.Resolve(rc); + } + ResolveAttributes(rc); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + TypecheckAttributes(tc); + this.TypedIdent.Typecheck(tc); + if (QKeyValue.FindBoolAttribute(Attributes, "assumption") && !this.TypedIdent.Type.IsBool) + { + tc.Error(tok, "assumption variable must be of type 'bool'"); + } + } + } + + public class VariableComparer : IComparer { + public int Compare(object a, object b) { + Variable A = a as Variable; + Variable B = b as Variable; + if (A == null || B == null) { + throw new ArgumentException("VariableComparer works only on objects of type Variable"); + } + return cce.NonNull(A.Name).CompareTo(B.Name); + } + } + + // class to specify the <:-parents of the values of constants + public class ConstantParent { + public readonly IdentifierExpr/*!*/ Parent; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Parent != null); + } + + // if true, the sub-dag underneath this constant-parent edge is + // disjoint from all other unique sub-dags + public readonly bool Unique; + + public ConstantParent(IdentifierExpr parent, bool unique) { + Contract.Requires(parent != null); + Parent = parent; + Unique = unique; + } + } + + public class Constant : Variable { + // when true, the value of this constant is meant to be distinct + // from all other constants. + public readonly bool Unique; + + // the <:-parents of the value of this constant. If the field is + // null, no information about the parents is provided, which means + // that the parental situation is unconstrained. + public readonly ReadOnlyCollection Parents; + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cce.NonNullElements(Parents, true)); + } + + // if true, it is assumed that the immediate <:-children of the + // value of this constant are completely specified + public readonly bool ChildrenComplete; + + public Constant(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent) + : base(tok, typedIdent) { + Contract.Requires(tok != null); + Contract.Requires(typedIdent != null); + Contract.Requires(typedIdent.Name != null && (!typedIdent.HasName || typedIdent.Name.Length > 0)); + Contract.Requires(typedIdent.WhereExpr == null); + this.Unique = true; + this.Parents = null; + this.ChildrenComplete = false; + } + public Constant(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent, bool unique) + : base(tok, typedIdent) { + Contract.Requires(tok != null); + Contract.Requires(typedIdent != null); + Contract.Requires(typedIdent.Name != null && typedIdent.Name.Length > 0); + Contract.Requires(typedIdent.WhereExpr == null); + this.Unique = unique; + this.Parents = null; + this.ChildrenComplete = false; + } + public Constant(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent, + bool unique, + IEnumerable parents, bool childrenComplete, + QKeyValue kv) + : base(tok, typedIdent, kv) { + Contract.Requires(tok != null); + Contract.Requires(typedIdent != null); + Contract.Requires(cce.NonNullElements(parents, true)); + Contract.Requires(typedIdent.Name != null && typedIdent.Name.Length > 0); + Contract.Requires(typedIdent.WhereExpr == null); + this.Unique = unique; + this.Parents = parents == null ? null : new ReadOnlyCollection(parents.ToList()); + this.ChildrenComplete = childrenComplete; + } + public override bool IsMutable { + get { + return false; + } + } + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "const "); + EmitAttributes(stream); + if (this.Unique) { + stream.Write(this, level, "unique "); + } + EmitVitals(stream, level, false); + + if (Parents != null || ChildrenComplete) { + stream.Write(this, level, " extends"); + string/*!*/ sep = " "; + foreach (ConstantParent/*!*/ p in cce.NonNull(Parents)) { + Contract.Assert(p != null); + stream.Write(this, level, sep); + sep = ", "; + if (p.Unique) + stream.Write(this, level, "unique "); + p.Parent.Emit(stream); + } + if (ChildrenComplete) + stream.Write(this, level, " complete"); + } + + stream.WriteLine(";"); + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddVariable(this, true); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + base.Resolve(rc); + if (Parents != null) { + foreach (ConstantParent/*!*/ p in Parents) { + Contract.Assert(p != null); + p.Parent.Resolve(rc); + if (p.Parent.Decl != null && !(p.Parent.Decl is Constant)) + rc.Error(p.Parent, "the parent of a constant has to be a constant"); + if (this.Equals(p.Parent.Decl)) + rc.Error(p.Parent, "constant cannot be its own parent"); + } + } + + // check that no parent occurs twice + // (could be optimised) + if (Parents != null) { + for (int i = 0; i < Parents.Count; ++i) { + if (Parents[i].Parent.Decl != null) { + for (int j = i + 1; j < Parents.Count; ++j) { + if (Parents[j].Parent.Decl != null && + cce.NonNull(Parents[i].Parent.Decl).Equals(Parents[j].Parent.Decl)) + rc.Error(Parents[j].Parent, + "{0} occurs more than once as parent", + Parents[j].Parent.Decl); + } + } + } + } + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + base.Typecheck(tc); + + if (Parents != null) { + foreach (ConstantParent/*!*/ p in Parents) { + Contract.Assert(p != null); + p.Parent.Typecheck(tc); + if (!cce.NonNull(p.Parent.Decl).TypedIdent.Type.Unify(this.TypedIdent.Type)) + tc.Error(p.Parent, + "parent of constant has incompatible type ({0} instead of {1})", + p.Parent.Decl.TypedIdent.Type, this.TypedIdent.Type); + } + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitConstant(this); + } + } + public class GlobalVariable : Variable { + public GlobalVariable(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent) + : base(tok, typedIdent) { + Contract.Requires(tok != null); + Contract.Requires(typedIdent != null); + } + public GlobalVariable(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent, QKeyValue kv) + : base(tok, typedIdent, kv) { + Contract.Requires(tok != null); + Contract.Requires(typedIdent != null); + } + public override bool IsMutable { + get { + return true; + } + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddVariable(this, true); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitGlobalVariable(this); + } + } + public class Formal : Variable { + public bool InComing; + public Formal(IToken tok, TypedIdent typedIdent, bool incoming, QKeyValue kv) + : base(tok, typedIdent, kv) { + Contract.Requires(typedIdent != null); + Contract.Requires(tok != null); + InComing = incoming; + } + public Formal(IToken tok, TypedIdent typedIdent, bool incoming) + : this(tok, typedIdent, incoming, null) { + Contract.Requires(typedIdent != null); + Contract.Requires(tok != null); + } + public override bool IsMutable { + get { + return !InComing; + } + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddVariable(this, false); + } + + /// + /// Given a sequence of Formal declarations, returns sequence of Formals like the given one but without where clauses + /// and without any attributes. + /// The Type of each Formal is cloned. + /// + public static List StripWhereClauses(List w) { + Contract.Requires(w != null); + Contract.Ensures(Contract.Result>() != null); + List s = new List(); + foreach (Variable/*!*/ v in w) { + Contract.Assert(v != null); + Formal f = (Formal)v; + TypedIdent ti = f.TypedIdent; + s.Add(new Formal(f.tok, new TypedIdent(ti.tok, ti.Name, ti.Type.CloneUnresolved()), f.InComing, null)); + } + return s; + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitFormal(this); + } + } + public class LocalVariable : Variable { + public LocalVariable(IToken tok, TypedIdent typedIdent, QKeyValue kv) + : base(tok, typedIdent, kv) { + Contract.Requires(typedIdent != null); + Contract.Requires(tok != null); + } + public LocalVariable(IToken tok, TypedIdent typedIdent) + : base(tok, typedIdent, null) { + Contract.Requires(typedIdent != null); + Contract.Requires(tok != null); + } + public override bool IsMutable { + get { + return true; + } + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddVariable(this, false); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitLocalVariable(this); + } + } + public class Incarnation : LocalVariable { + public int incarnationNumber; + public readonly Variable OriginalVariable; + public Incarnation(Variable/*!*/ var, int i) : + base( + var.tok, + new TypedIdent(var.TypedIdent.tok, var.TypedIdent.Name + "@" + i, var.TypedIdent.Type) + ) { + Contract.Requires(var != null); + incarnationNumber = i; + OriginalVariable = var; + } + + } + public class BoundVariable : Variable { + public BoundVariable(IToken tok, TypedIdent typedIdent) + : base(tok, typedIdent) { + Contract.Requires(typedIdent != null); + Contract.Requires(tok != null); + Contract.Requires(typedIdent.WhereExpr == null); + } + public BoundVariable(IToken tok, TypedIdent typedIdent, QKeyValue kv) + : base(tok, typedIdent, kv) { + Contract.Requires(typedIdent != null); + Contract.Requires(tok != null); + Contract.Requires(typedIdent.WhereExpr == null); + } + public override bool IsMutable { + get { + return false; + } + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddVariable(this, false); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitBoundVariable(this); + } + } + + public abstract class DeclWithFormals : NamedDeclaration { + public List/*!*/ TypeParameters; + + private /*readonly--except in StandardVisitor*/ List/*!*/ inParams, outParams; + + public List/*!*/ InParams { + get { + Contract.Ensures(Contract.Result>() != null); + return this.inParams; + } + set { + Contract.Requires(value != null); + this.inParams = value; + } + } + + public List/*!*/ OutParams + { + get { + Contract.Ensures(Contract.Result>() != null); + return this.outParams; + } + set { + Contract.Requires(value != null); + this.outParams = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(TypeParameters != null); + Contract.Invariant(this.inParams != null); + Contract.Invariant(this.outParams != null); + } + + public DeclWithFormals(IToken tok, string name, List typeParams, + List inParams, List outParams) + : base(tok, name) { + Contract.Requires(inParams != null); + Contract.Requires(outParams != null); + Contract.Requires(typeParams != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + this.TypeParameters = typeParams; + this.inParams = inParams; + this.outParams = outParams; + } + + protected DeclWithFormals(DeclWithFormals that) + : base(that.tok, cce.NonNull(that.Name)) { + Contract.Requires(that != null); + this.TypeParameters = that.TypeParameters; + this.inParams = cce.NonNull(that.InParams); + this.outParams = cce.NonNull(that.OutParams); + } + + public byte[] MD5Checksum_; + public byte[] MD5Checksum + { + get + { + if (MD5Checksum_ == null) + { + var c = Checksum; + if (c != null) + { + MD5Checksum_ = System.Security.Cryptography.MD5.Create().ComputeHash(System.Text.Encoding.UTF8.GetBytes(c)); + } + } + return MD5Checksum_; + } + } + + public byte[] MD5DependencyChecksum_; + public byte[] MD5DependencyChecksum + { + get + { + Contract.Requires(DependenciesCollected); + + if (MD5DependencyChecksum_ == null && MD5Checksum != null) + { + var c = MD5Checksum; + var transFuncDeps = new HashSet(); + if (procedureDependencies != null) + { + foreach (var p in procedureDependencies) + { + if (p.FunctionDependencies != null) + { + foreach (var f in p.FunctionDependencies) + { + transFuncDeps.Add(f); + } + } + var pc = p.MD5Checksum; + if (pc == null) { return null; } + c = ChecksumHelper.CombineChecksums(c, pc, true); + } + } + if (FunctionDependencies != null) + { + foreach (var f in FunctionDependencies) + { + transFuncDeps.Add(f); + } + } + var q = new Queue(transFuncDeps); + while (q.Any()) + { + var f = q.Dequeue(); + var fc = f.MD5Checksum; + if (fc == null) { return null; } + c = ChecksumHelper.CombineChecksums(c, fc, true); + if (f.FunctionDependencies != null) + { + foreach (var d in f.FunctionDependencies) + { + if (!transFuncDeps.Contains(d)) + { + transFuncDeps.Add(d); + q.Enqueue(d); + } + } + } + } + MD5DependencyChecksum_ = c; + } + return MD5DependencyChecksum_; + } + } + + public string Checksum + { + get + { + return FindStringAttribute("checksum"); + } + } + + string dependencyChecksum; + public string DependencyChecksum + { + get + { + if (dependencyChecksum == null && DependenciesCollected && MD5DependencyChecksum != null) + { + dependencyChecksum = BitConverter.ToString(MD5DependencyChecksum); + } + return dependencyChecksum; + } + } + + public bool DependenciesCollected { get; set; } + + ISet procedureDependencies; + + public ISet ProcedureDependencies + { + get { return procedureDependencies; } + } + + public void AddProcedureDependency(Procedure procedure) + { + Contract.Requires(procedure != null); + + if (procedureDependencies == null) + { + procedureDependencies = new HashSet(); + } + procedureDependencies.Add(procedure); + } + + ISet functionDependencies; + + public ISet FunctionDependencies + { + get { return functionDependencies; } + } + + public void AddFunctionDependency(Function function) + { + Contract.Requires(function != null); + + if (functionDependencies == null) + { + functionDependencies = new HashSet(); + } + functionDependencies.Add(function); + } + + public bool SignatureEquals(DeclWithFormals other) + { + Contract.Requires(other != null); + + string sig = null; + string otherSig = null; + using (var strWr = new System.IO.StringWriter()) + using (var tokTxtWr = new TokenTextWriter("", strWr, false, false)) + { + EmitSignature(tokTxtWr, this is Function); + sig = strWr.ToString(); + } + + using (var otherStrWr = new System.IO.StringWriter()) + using (var otherTokTxtWr = new TokenTextWriter("", otherStrWr, false, false)) + { + EmitSignature(otherTokTxtWr, other is Function); + otherSig = otherStrWr.ToString(); + } + return sig == otherSig; + } + + protected void EmitSignature(TokenTextWriter stream, bool shortRet) { + Contract.Requires(stream != null); + Type.EmitOptionalTypeParams(stream, TypeParameters); + stream.Write("("); + stream.push(); + InParams.Emit(stream, true); + stream.Write(")"); + stream.sep(); + + if (shortRet) { + Contract.Assert(OutParams.Count == 1); + stream.Write(" : "); + cce.NonNull(OutParams[0]).TypedIdent.Type.Emit(stream); + } else if (OutParams.Count > 0) { + stream.Write(" returns ("); + OutParams.Emit(stream, true); + stream.Write(")"); + } + stream.pop(); + } + + // Register all type parameters at the resolution context + protected void RegisterTypeParameters(ResolutionContext rc) { + Contract.Requires(rc != null); + foreach (TypeVariable/*!*/ v in TypeParameters) { + Contract.Assert(v != null); + rc.AddTypeBinder(v); + } + } + + protected void SortTypeParams() { + List/*!*/ allTypes = new List(InParams.Select(Item => Item.TypedIdent.Type).ToArray()); + Contract.Assert(allTypes != null); + allTypes.AddRange(new List(OutParams.Select(Item => Item.TypedIdent.Type).ToArray())); + TypeParameters = Type.SortTypeParams(TypeParameters, allTypes, null); + } + + /// + /// Adds the given formals to the current variable context, and then resolves + /// the types of those formals. Does NOT resolve the where clauses of the + /// formals. + /// Relies on the caller to first create, and later tear down, that variable + /// context. + /// + /// + protected void RegisterFormals(List formals, ResolutionContext rc) { + Contract.Requires(rc != null); + Contract.Requires(formals != null); + foreach (Formal/*!*/ f in formals) { + Contract.Assert(f != null); + if (f.Name != TypedIdent.NoName) { + rc.AddVariable(f, false); + } + f.Resolve(rc); + } + } + + /// + /// Resolves the where clauses (and attributes) of the formals. + /// + /// + protected void ResolveFormals(List formals, ResolutionContext rc) { + Contract.Requires(rc != null); + Contract.Requires(formals != null); + foreach (Formal/*!*/ f in formals) { + Contract.Assert(f != null); + f.ResolveWhere(rc); + } + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + TypecheckAttributes(tc); + foreach (Formal/*!*/ p in InParams) { + Contract.Assert(p != null); + p.Typecheck(tc); + } + foreach (Formal/*!*/ p in OutParams) { + Contract.Assert(p != null); + p.Typecheck(tc); + } + } + } + + public class DatatypeConstructor : Function { + public List selectors; + public DatatypeMembership membership; + + public DatatypeConstructor(Function func) + : base(func.tok, func.Name, func.TypeParameters, func.InParams, func.OutParams[0], func.Comment, func.Attributes) + { + selectors = new List(); + } + + public override void Resolve(ResolutionContext rc) { + HashSet selectorNames = new HashSet(); + foreach (DatatypeSelector selector in selectors) { + if (selector.Name.StartsWith("#")) { + rc.Error(selector.tok, "The selector must be a non-empty string"); + } + else { + if (selectorNames.Contains(selector.Name)) + rc.Error(this.tok, "The selectors for a constructor must be distinct strings"); + else + selectorNames.Add(selector.Name); + } + } + base.Resolve(rc); + } + + public override void Typecheck(TypecheckingContext tc) { + CtorType outputType = this.OutParams[0].TypedIdent.Type as CtorType; + if (outputType == null || !outputType.IsDatatype()) { + tc.Error(tok, "The output type of a constructor must be a datatype"); + } + base.Typecheck(tc); + } + } + + public class DatatypeSelector : Function { + public Function constructor; + public int index; + public DatatypeSelector(Function constructor, int index) + : base(constructor.InParams[index].tok, + constructor.InParams[index].Name + "#" + constructor.Name, + new List { new Formal(constructor.tok, new TypedIdent(constructor.tok, "", constructor.OutParams[0].TypedIdent.Type), true) }, + new Formal(constructor.tok, new TypedIdent(constructor.tok, "", constructor.InParams[index].TypedIdent.Type), false)) + { + this.constructor = constructor; + this.index = index; + } + + public override void Emit(TokenTextWriter stream, int level) { } + } + + public class DatatypeMembership : Function { + public Function constructor; + public DatatypeMembership(Function constructor) + : base(constructor.tok, + "is#" + constructor.Name, + new List { new Formal(constructor.tok, new TypedIdent(constructor.tok, "", constructor.OutParams[0].TypedIdent.Type), true) }, + new Formal(constructor.tok, new TypedIdent(constructor.tok, "", Type.Bool), false)) + { + this.constructor = constructor; + } + + public override void Emit(TokenTextWriter stream, int level) { } + } + + public class Function : DeclWithFormals { + public string Comment; + + // the body is only set if the function is declared with {:inline} + public Expr Body; + public Axiom DefinitionAxiom; + + public IList otherDefinitionAxioms; + public IEnumerable OtherDefinitionAxioms + { + get + { + return otherDefinitionAxioms; + } + } + + public void AddOtherDefinitionAxiom(Axiom axiom) + { + Contract.Requires(axiom != null); + + if (otherDefinitionAxioms == null) + { + otherDefinitionAxioms = new List(); + } + otherDefinitionAxioms.Add(axiom); + } + + public bool doingExpansion; + + private bool neverTrigger; + private bool neverTriggerComputed; + + public string OriginalLambdaExprAsString; + + public Function(IToken tok, string name, List args, Variable result) + : this(tok, name, new List(), args, result, null) { + Contract.Requires(result != null); + Contract.Requires(args != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + //:this(tok, name, new List(), args, result, null); + } + public Function(IToken tok, string name, List typeParams, List args, Variable result) + : this(tok, name, typeParams, args, result, null) { + Contract.Requires(result != null); + Contract.Requires(args != null); + Contract.Requires(typeParams != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + //:this(tok, name, typeParams, args, result, null); + } + public Function(IToken tok, string name, List args, Variable result, string comment) + : this(tok, name, new List(), args, result, comment) { + Contract.Requires(result != null); + Contract.Requires(args != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + //:this(tok, name, new List(), args, result, comment); + } + public Function(IToken tok, string name, List typeParams, List args, Variable/*!*/ result, string comment) + : base(tok, name, typeParams, args, new List { result }) { + Contract.Requires(result != null); + Contract.Requires(args != null); + Contract.Requires(typeParams != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + Comment = comment; + } + public Function(IToken tok, string name, List typeParams, List args, Variable result, + string comment, QKeyValue kv) + : this(tok, name, typeParams, args, result, comment) { + Contract.Requires(args != null); + Contract.Requires(result != null); + Contract.Requires(typeParams != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + //:this(tok, name, typeParams, args, result, comment); + this.Attributes = kv; + } + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + if (Comment != null) { + stream.WriteLine(this, level, "// " + Comment); + } + stream.Write(this, level, "function "); + EmitAttributes(stream); + if (Body != null && !QKeyValue.FindBoolAttribute(Attributes, "inline")) { + // Boogie inlines any function whose .Body field is non-null. The parser populates the .Body field + // is the :inline attribute is present, but if someone creates the Boogie file directly as an AST, then + // the :inline attribute may not be there. We'll make sure it's printed, so one can see that this means + // that the body will be inlined. + stream.Write("{:inline} "); + } + if (CommandLineOptions.Clo.PrintWithUniqueASTIds) { + stream.Write("h{0}^^{1}", this.GetHashCode(), TokenTextWriter.SanitizeIdentifier(this.Name)); + } else { + stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); + } + EmitSignature(stream, true); + if (Body != null) { + stream.WriteLine(); + stream.WriteLine("{"); + stream.Write(level + 1, ""); + Body.Emit(stream); + stream.WriteLine(); + stream.WriteLine("}"); + } else { + stream.WriteLine(";"); + } + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddProcedure(this); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + int previousTypeBinderState = rc.TypeBinderState; + try { + RegisterTypeParameters(rc); + rc.PushVarContext(); + RegisterFormals(InParams, rc); + RegisterFormals(OutParams, rc); + ResolveAttributes(rc); + if (Body != null) + { + rc.StateMode = ResolutionContext.State.StateLess; + Body.Resolve(rc); + rc.StateMode = ResolutionContext.State.Single; + } + rc.PopVarContext(); + Type.CheckBoundVariableOccurrences(TypeParameters, + new List(InParams.Select(Item => Item.TypedIdent.Type).ToArray()), + new List(OutParams.Select(Item => Item.TypedIdent.Type).ToArray()), + this.tok, "function arguments", + rc); + } finally { + rc.TypeBinderState = previousTypeBinderState; + } + SortTypeParams(); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + // PR: why was the base call left out previously? + base.Typecheck(tc); + // TypecheckAttributes(tc); + if (Body != null) { + Body.Typecheck(tc); + if (!cce.NonNull(Body.Type).Unify(cce.NonNull(OutParams[0]).TypedIdent.Type)) + tc.Error(Body, + "function body with invalid type: {0} (expected: {1})", + Body.Type, cce.NonNull(OutParams[0]).TypedIdent.Type); + } + } + + public bool NeverTrigger { + get { + if (!neverTriggerComputed) { + this.CheckBooleanAttribute("never_pattern", ref neverTrigger); + neverTriggerComputed = true; + } + return neverTrigger; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitFunction(this); + } + + public Axiom CreateDefinitionAxiom(Expr definition, QKeyValue kv = null) { + Contract.Requires(definition != null); + + List dummies = new List(); + List callArgs = new List(); + int i = 0; + foreach (Formal/*!*/ f in InParams) { + Contract.Assert(f != null); + string nm = f.TypedIdent.HasName ? f.TypedIdent.Name : "_" + i; + dummies.Add(new BoundVariable(f.tok, new TypedIdent(f.tok, nm, f.TypedIdent.Type))); + callArgs.Add(new IdentifierExpr(f.tok, nm)); + i++; + } + List/*!*/ quantifiedTypeVars = new List(); + foreach (TypeVariable/*!*/ t in TypeParameters) { + Contract.Assert(t != null); + quantifiedTypeVars.Add(new TypeVariable(tok, t.Name)); + } + + Expr call = new NAryExpr(tok, new FunctionCall(new IdentifierExpr(tok, Name)), callArgs); + // specify the type of the function, because it might be that + // type parameters only occur in the output type + call = Expr.CoerceType(tok, call, (Type)OutParams[0].TypedIdent.Type.Clone()); + Expr def = Expr.Binary(tok, BinaryOperator.Opcode.Eq, call, definition); + if (quantifiedTypeVars.Count != 0 || dummies.Count != 0) { + def = new ForallExpr(tok, quantifiedTypeVars, dummies, + kv, + new Trigger(tok, true, new List { call }, null), + def); + } + DefinitionAxiom = new Axiom(tok, def); + return DefinitionAxiom; + } + } + + public class Macro : Function { + public Macro(IToken tok, string name, List args, Variable result) + : base(tok, name, args, result) { } + } + + public class Requires : Absy, IPotentialErrorNode { + public readonly bool Free; + + private Expr/*!*/ _condition; + + public Expr/*!*/ Condition { + get { + Contract.Ensures(Contract.Result() != null); + return this._condition; + } + set { + Contract.Requires(value != null); + this._condition = value; + } + } + + public string Comment; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._condition != null); + } + + + // TODO: convert to use generics + private string errorData; + public string ErrorData { + get { + return errorData; + } + set { + errorData = value; + } + } + + + private MiningStrategy errorDataEnhanced; + public MiningStrategy ErrorDataEnhanced { + get { + return errorDataEnhanced; + } + set { + errorDataEnhanced = value; + } + } + + public QKeyValue Attributes; + + public String ErrorMessage { + get { + return QKeyValue.FindStringAttribute(Attributes, "msg"); + } + } + + public Requires(IToken token, bool free, Expr condition, string comment, QKeyValue kv) + : base(token) { + Contract.Requires(condition != null); + Contract.Requires(token != null); + this.Free = free; + this._condition = condition; + this.Comment = comment; + this.Attributes = kv; + } + + public Requires(IToken token, bool free, Expr condition, string comment) + : this(token, free, condition, comment, null) { + Contract.Requires(condition != null); + Contract.Requires(token != null); + //:this(token, free, condition, comment, null); + } + + public Requires(bool free, Expr condition) + : this(Token.NoToken, free, condition, null) { + Contract.Requires(condition != null); + //:this(Token.NoToken, free, condition, null); + } + + public Requires(bool free, Expr condition, string comment) + : this(Token.NoToken, free, condition, comment) { + Contract.Requires(condition != null); + //:this(Token.NoToken, free, condition, comment); + } + + public void Emit(TokenTextWriter stream, int level) { + Contract.Requires(stream != null); + if (Comment != null) { + stream.WriteLine(this, level, "// " + Comment); + } + stream.Write(this, level, "{0}requires ", Free ? "free " : ""); + Cmd.EmitAttributes(stream, Attributes); + this.Condition.Emit(stream); + stream.WriteLine(";"); + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + this.Condition.Resolve(rc); + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + this.Condition.Typecheck(tc); + Contract.Assert(this.Condition.Type != null); // follows from postcondition of Expr.Typecheck + if (!this.Condition.Type.Unify(Type.Bool)) { + tc.Error(this, "preconditions must be of type bool"); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + return visitor.VisitRequires(this); + } + } + + public class Ensures : Absy, IPotentialErrorNode { + public readonly bool Free; + + private Expr/*!*/ _condition; + + public Expr/*!*/ Condition { + get { + Contract.Ensures(Contract.Result() != null); + return this._condition; + } + set { + Contract.Requires(value != null); + this._condition = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._condition != null); + } + + public string Comment; + + // TODO: convert to use generics + private string errorData; + public string ErrorData { + get { + return errorData; + } + set { + errorData = value; + } + } + + private MiningStrategy errorDataEnhanced; + public MiningStrategy ErrorDataEnhanced { + get { + return errorDataEnhanced; + } + set { + errorDataEnhanced = value; + } + } + + public String ErrorMessage { + get { + return QKeyValue.FindStringAttribute(Attributes, "msg"); + } + } + + public QKeyValue Attributes; + + public Ensures(IToken token, bool free, Expr/*!*/ condition, string comment, QKeyValue kv) + : base(token) { + Contract.Requires(condition != null); + Contract.Requires(token != null); + this.Free = free; + this._condition = condition; + this.Comment = comment; + this.Attributes = kv; + } + + public Ensures(IToken token, bool free, Expr condition, string comment) + : this(token, free, condition, comment, null) { + Contract.Requires(condition != null); + Contract.Requires(token != null); + //:this(token, free, condition, comment, null); + } + + public Ensures(bool free, Expr condition) + : this(Token.NoToken, free, condition, null) { + Contract.Requires(condition != null); + //:this(Token.NoToken, free, condition, null); + } + + public Ensures(bool free, Expr condition, string comment) + : this(Token.NoToken, free, condition, comment) { + Contract.Requires(condition != null); + //:this(Token.NoToken, free, condition, comment); + } + + public void Emit(TokenTextWriter stream, int level) { + Contract.Requires(stream != null); + if (Comment != null) { + stream.WriteLine(this, level, "// " + Comment); + } + stream.Write(this, level, "{0}ensures ", Free ? "free " : ""); + Cmd.EmitAttributes(stream, Attributes); + this.Condition.Emit(stream); + stream.WriteLine(";"); + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + this.Condition.Resolve(rc); + } + + public override void Typecheck(TypecheckingContext tc) { + this.Condition.Typecheck(tc); + Contract.Assert(this.Condition.Type != null); // follows from postcondition of Expr.Typecheck + if (!this.Condition.Type.Unify(Type.Bool)) { + tc.Error(this, "postconditions must be of type bool"); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + return visitor.VisitEnsures(this); + } + } + + public class Procedure : DeclWithFormals { + public List/*!*/ Requires; + public List/*!*/ Modifies; + public List/*!*/ Ensures; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Requires != null); + Contract.Invariant(Modifies != null); + Contract.Invariant(Ensures != null); + Contract.Invariant(Summary != null); + } + + + // Abstract interpretation: Procedure-specific invariants... + [Rep] + public readonly ProcedureSummary/*!*/ Summary; + + public Procedure(IToken/*!*/ tok, string/*!*/ name, List/*!*/ typeParams, List/*!*/ inParams, List/*!*/ outParams, + List/*!*/ requires, List/*!*/ modifies, List/*!*/ ensures) + : this(tok, name, typeParams, inParams, outParams, requires, modifies, ensures, null) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + Contract.Requires(typeParams != null); + Contract.Requires(inParams != null); + Contract.Requires(outParams != null); + Contract.Requires(requires != null); + Contract.Requires(modifies != null); + Contract.Requires(ensures != null); + //:this(tok, name, typeParams, inParams, outParams, requires, modifies, ensures, null); + } + + public Procedure(IToken/*!*/ tok, string/*!*/ name, List/*!*/ typeParams, List/*!*/ inParams, List/*!*/ outParams, + List/*!*/ @requires, List/*!*/ @modifies, List/*!*/ @ensures, QKeyValue kv + ) + : base(tok, name, typeParams, inParams, outParams) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + Contract.Requires(typeParams != null); + Contract.Requires(inParams != null); + Contract.Requires(outParams != null); + Contract.Requires(@requires != null); + Contract.Requires(@modifies != null); + Contract.Requires(@ensures != null); + this.Requires = @requires; + this.Modifies = @modifies; + this.Ensures = @ensures; + this.Summary = new ProcedureSummary(); + this.Attributes = kv; + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "procedure "); + EmitAttributes(stream); + stream.Write(this, level, "{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); + EmitSignature(stream, false); + stream.WriteLine(";"); + + level++; + + foreach (Requires/*!*/ e in this.Requires) { + Contract.Assert(e != null); + e.Emit(stream, level); + } + + if (this.Modifies.Count > 0) { + stream.Write(level, "modifies "); + this.Modifies.Emit(stream, false); + stream.WriteLine(";"); + } + + foreach (Ensures/*!*/ e in this.Ensures) { + Contract.Assert(e != null); + e.Emit(stream, level); + } + + if (!CommandLineOptions.Clo.IntraproceduralInfer) { + for (int s = 0; s < this.Summary.Count; s++) { + ProcedureSummaryEntry/*!*/ entry = cce.NonNull(this.Summary[s]); + stream.Write(level + 1, "// "); + stream.WriteLine(); + } + } + + stream.WriteLine(); + stream.WriteLine(); + } + + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddProcedure(this); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.PushVarContext(); + + foreach (IdentifierExpr/*!*/ ide in Modifies) { + Contract.Assert(ide != null); + ide.Resolve(rc); + } + + int previousTypeBinderState = rc.TypeBinderState; + try { + RegisterTypeParameters(rc); + + RegisterFormals(InParams, rc); + ResolveFormals(InParams, rc); // "where" clauses of in-parameters are resolved without the out-parameters in scope + foreach (Requires/*!*/ e in Requires) { + Contract.Assert(e != null); + e.Resolve(rc); + } + RegisterFormals(OutParams, rc); + ResolveFormals(OutParams, rc); // "where" clauses of out-parameters are resolved with both in- and out-parametes in scope + + rc.StateMode = ResolutionContext.State.Two; + foreach (Ensures/*!*/ e in Ensures) { + Contract.Assert(e != null); + e.Resolve(rc); + } + rc.StateMode = ResolutionContext.State.Single; + ResolveAttributes(rc); + + Type.CheckBoundVariableOccurrences(TypeParameters, + new List(InParams.Select(Item => Item.TypedIdent.Type).ToArray()), + new List(OutParams.Select(Item => Item.TypedIdent.Type).ToArray()), + this.tok, "procedure arguments", + rc); + + } finally { + rc.TypeBinderState = previousTypeBinderState; + } + + rc.PopVarContext(); + + SortTypeParams(); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + base.Typecheck(tc); + foreach (IdentifierExpr/*!*/ ide in Modifies) { + Contract.Assert(ide != null); + Contract.Assume(ide.Decl != null); + if (!ide.Decl.IsMutable) { + tc.Error(this, "modifies list contains constant: {0}", ide.Name); + } + ide.Typecheck(tc); + } + foreach (Requires/*!*/ e in Requires) { + Contract.Assert(e != null); + e.Typecheck(tc); + } + bool oldYields = tc.Yields; + tc.Yields = QKeyValue.FindBoolAttribute(Attributes, "yields"); + foreach (Ensures/*!*/ e in Ensures) { + Contract.Assert(e != null); + e.Typecheck(tc); + } + tc.Yields = oldYields; + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitProcedure(this); + } + } + + public class LoopProcedure : Procedure + { + public Implementation enclosingImpl; + private Dictionary blockMap; + private Dictionary blockLabelMap; + + public LoopProcedure(Implementation impl, Block header, + List inputs, List outputs, List globalMods) + : base(Token.NoToken, impl.Name + "_loop_" + header.ToString(), + new List(), inputs, outputs, + new List(), globalMods, new List()) + { + enclosingImpl = impl; + } + + public void setBlockMap(Dictionary bm) + { + blockMap = bm; + blockLabelMap = new Dictionary(); + foreach (var kvp in bm) + { + blockLabelMap.Add(kvp.Key.Label, kvp.Value); + } + } + + public Block getBlock(string label) + { + if (blockLabelMap.ContainsKey(label)) return blockLabelMap[label]; + return null; + } + } + + public class Implementation : DeclWithFormals { + public List/*!*/ LocVars; + [Rep] + public StmtList StructuredStmts; + [Rep] + public List/*!*/ Blocks; + public Procedure Proc; + + // Blocks before applying passification etc. + // Both are used only when /inline is set. + public List OriginalBlocks; + public List OriginalLocVars; + + public readonly ISet AssertionChecksums = new HashSet(ChecksumComparer.Default); + + public sealed class ChecksumComparer : IEqualityComparer + { + static IEqualityComparer defaultComparer; + public static IEqualityComparer Default + { + get + { + if (defaultComparer == null) + { + defaultComparer = new ChecksumComparer(); + } + return defaultComparer; + } + } + + public bool Equals(byte[] x, byte[] y) + { + if (x == null || y == null) + { + return x == y; + } + else + { + return x.SequenceEqual(y); + } + } + + public int GetHashCode(byte[] checksum) + { + if (checksum == null) + { + throw new ArgumentNullException("checksum"); + } + else + { + var result = 17; + for (int i = 0; i < checksum.Length; i++) + { + result = result * 23 + checksum[i]; + } + return result; + } + } + } + + public void AddAssertionChecksum(byte[] checksum) + { + Contract.Requires(checksum != null); + + if (AssertionChecksums != null) + { + AssertionChecksums.Add(checksum); + } + } + + public ISet AssertionChecksumsInCachedSnapshot { get; set; } + + public bool IsAssertionChecksumInCachedSnapshot(byte[] checksum) + { + Contract.Requires(AssertionChecksumsInCachedSnapshot != null); + + return AssertionChecksumsInCachedSnapshot.Contains(checksum); + } + + public IList RecycledFailingAssertions { get; protected set; } + + public void AddRecycledFailingAssertion(AssertCmd assertion) + { + if (RecycledFailingAssertions == null) + { + RecycledFailingAssertions = new List(); + } + RecycledFailingAssertions.Add(assertion); + } + + public Cmd ExplicitAssumptionAboutCachedPrecondition { get; set; } + + // Strongly connected components + private StronglyConnectedComponents scc; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(LocVars != null); + Contract.Invariant(cce.NonNullElements(Blocks)); + Contract.Invariant(cce.NonNullElements(OriginalBlocks, true)); + Contract.Invariant(cce.NonNullElements(scc, true)); + + } + private bool BlockPredecessorsComputed; + public bool StronglyConnectedComponentsComputed { + get { + return this.scc != null; + } + } + + public bool SkipVerification { + get { + bool verify = true; + cce.NonNull(this.Proc).CheckBooleanAttribute("verify", ref verify); + this.CheckBooleanAttribute("verify", ref verify); + if (!verify) { + return true; + } + + if (CommandLineOptions.Clo.ProcedureInlining == CommandLineOptions.Inlining.Assert || + CommandLineOptions.Clo.ProcedureInlining == CommandLineOptions.Inlining.Assume) { + Expr inl = this.FindExprAttribute("inline"); + if (inl == null) + inl = this.Proc.FindExprAttribute("inline"); + if (inl != null && inl is LiteralExpr && ((LiteralExpr)inl).isBigNum && ((LiteralExpr)inl).asBigNum.Signum > 0) { + return true; + } + } + + if (CommandLineOptions.Clo.StratifiedInlining > 0) { + return !QKeyValue.FindBoolAttribute(Attributes, "entrypoint"); + } + + return false; + } + } + + public string Id + { + get + { + var id = FindStringAttribute("id"); + if (id == null) + { + id = Name + GetHashCode().ToString() + ":0"; + } + return id; + } + } + + public int Priority + { + get + { + int priority = 0; + CheckIntAttribute("priority", ref priority); + if (priority <= 0) + { + priority = 1; + } + return priority; + } + } + + public IDictionary ErrorChecksumToCachedError { get; private set; } + + public bool IsErrorChecksumInCachedSnapshot(byte[] checksum) + { + Contract.Requires(ErrorChecksumToCachedError != null); + + return ErrorChecksumToCachedError.ContainsKey(checksum); + } + + public void SetErrorChecksumToCachedError(IEnumerable> errors) + { + Contract.Requires(errors != null); + + ErrorChecksumToCachedError = new Dictionary(ChecksumComparer.Default); + foreach (var kv in errors) + { + ErrorChecksumToCachedError[kv.Item1] = kv.Item3; + if (kv.Item2 != null) + { + ErrorChecksumToCachedError[kv.Item2] = null; + } + } + } + + public bool HasCachedSnapshot + { + get + { + return ErrorChecksumToCachedError != null && AssertionChecksumsInCachedSnapshot != null; + } + } + + public bool AnyErrorsInCachedSnapshot + { + get + { + Contract.Requires(ErrorChecksumToCachedError != null); + + return ErrorChecksumToCachedError.Any(); + } + } + + IList injectedAssumptionVariables; + public IList InjectedAssumptionVariables + { + get + { + return injectedAssumptionVariables != null ? injectedAssumptionVariables : new List(); + } + } + + IList doomedInjectedAssumptionVariables; + public IList DoomedInjectedAssumptionVariables + { + get + { + return doomedInjectedAssumptionVariables != null ? doomedInjectedAssumptionVariables : new List(); + } + } + + public List RelevantInjectedAssumptionVariables(Dictionary incarnationMap) + { + return InjectedAssumptionVariables.Where(v => { Expr e; if (incarnationMap.TryGetValue(v, out e)) { var le = e as LiteralExpr; return le == null || !le.IsTrue; } else { return false; } }).ToList(); + } + + public List RelevantDoomedInjectedAssumptionVariables(Dictionary incarnationMap) + { + return DoomedInjectedAssumptionVariables.Where(v => { Expr e; if (incarnationMap.TryGetValue(v, out e)) { var le = e as LiteralExpr; return le == null || !le.IsTrue; } else { return false; } }).ToList(); + } + + public Expr ConjunctionOfInjectedAssumptionVariables(Dictionary incarnationMap, out bool isTrue) + { + Contract.Requires(incarnationMap != null); + + var vars = RelevantInjectedAssumptionVariables(incarnationMap).Select(v => incarnationMap[v]).ToList(); + isTrue = vars.Count == 0; + return LiteralExpr.BinaryTreeAnd(vars); + } + + public void InjectAssumptionVariable(LocalVariable variable, bool isDoomed = false) + { + LocVars.Add(variable); + if (isDoomed) + { + if (doomedInjectedAssumptionVariables == null) + { + doomedInjectedAssumptionVariables = new List(); + } + doomedInjectedAssumptionVariables.Add(variable); + } + else + { + if (injectedAssumptionVariables == null) + { + injectedAssumptionVariables = new List(); + } + injectedAssumptionVariables.Add(variable); + } + } + + public Implementation(IToken tok, string name, List typeParams, List inParams, List outParams, List localVariables, [Captured] StmtList structuredStmts, QKeyValue kv) + : this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, kv, new Errors()) { + Contract.Requires(structuredStmts != null); + Contract.Requires(localVariables != null); + Contract.Requires(outParams != null); + Contract.Requires(inParams != null); + Contract.Requires(typeParams != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + //:this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, new Errors()); + } + + public Implementation(IToken tok, string name, List typeParams, List inParams, List outParams, List localVariables, [Captured] StmtList structuredStmts) + : this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, new Errors()) { + Contract.Requires(structuredStmts != null); + Contract.Requires(localVariables != null); + Contract.Requires(outParams != null); + Contract.Requires(inParams != null); + Contract.Requires(typeParams != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + //:this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, new Errors()); + } + + public Implementation(IToken tok, string name, List typeParams, List inParams, List outParams, List localVariables, [Captured] StmtList structuredStmts, Errors errorHandler) + : this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, errorHandler) { + Contract.Requires(errorHandler != null); + Contract.Requires(structuredStmts != null); + Contract.Requires(localVariables != null); + Contract.Requires(outParams != null); + Contract.Requires(inParams != null); + Contract.Requires(typeParams != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + //:this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, errorHandler); + } + + public Implementation(IToken/*!*/ tok, + string/*!*/ name, + List/*!*/ typeParams, + List/*!*/ inParams, + List/*!*/ outParams, + List/*!*/ localVariables, + [Captured] StmtList/*!*/ structuredStmts, + QKeyValue kv, + Errors/*!*/ errorHandler) + : base(tok, name, typeParams, inParams, outParams) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + Contract.Requires(typeParams != null); + Contract.Requires(inParams != null); + Contract.Requires(outParams != null); + Contract.Requires(localVariables != null); + Contract.Requires(structuredStmts != null); + Contract.Requires(errorHandler != null); + LocVars = localVariables; + StructuredStmts = structuredStmts; + BigBlocksResolutionContext ctx = new BigBlocksResolutionContext(structuredStmts, errorHandler); + Blocks = ctx.Blocks; + BlockPredecessorsComputed = false; + scc = null; + Attributes = kv; + } + + public Implementation(IToken tok, string name, List typeParams, List inParams, List outParams, List localVariables, [Captured] List block) + : this(tok, name, typeParams, inParams, outParams, localVariables, block, null) { + Contract.Requires(cce.NonNullElements(block)); + Contract.Requires(localVariables != null); + Contract.Requires(outParams != null); + Contract.Requires(inParams != null); + Contract.Requires(typeParams != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + //:this(tok, name, typeParams, inParams, outParams, localVariables, block, null); + } + + public Implementation(IToken/*!*/ tok, + string/*!*/ name, + List/*!*/ typeParams, + List/*!*/ inParams, + List/*!*/ outParams, + List/*!*/ localVariables, + [Captured] List/*!*/ blocks, + QKeyValue kv) + : base(tok, name, typeParams, inParams, outParams) { + Contract.Requires(name != null); + Contract.Requires(inParams != null); + Contract.Requires(outParams != null); + Contract.Requires(localVariables != null); + Contract.Requires(cce.NonNullElements(blocks)); + LocVars = localVariables; + Blocks = blocks; + BlockPredecessorsComputed = false; + scc = null; + Attributes = kv; + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "implementation "); + EmitAttributes(stream); + stream.Write(this, level, "{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); + EmitSignature(stream, false); + stream.WriteLine(); + + stream.WriteLine(level, "{0}", '{'); + + foreach (Variable/*!*/ v in this.LocVars) { + Contract.Assert(v != null); + v.Emit(stream, level + 1); + } + + if (this.StructuredStmts != null && !CommandLineOptions.Clo.PrintInstrumented && !CommandLineOptions.Clo.PrintInlined) { + if (this.LocVars.Count > 0) { + stream.WriteLine(); + } + if (CommandLineOptions.Clo.PrintUnstructured < 2) { + if (CommandLineOptions.Clo.PrintUnstructured == 1) { + stream.WriteLine(this, level + 1, "/*** structured program:"); + } + this.StructuredStmts.Emit(stream, level + 1); + if (CommandLineOptions.Clo.PrintUnstructured == 1) { + stream.WriteLine(level + 1, "**** end structured program */"); + } + } + } + + if (this.StructuredStmts == null || 1 <= CommandLineOptions.Clo.PrintUnstructured || + CommandLineOptions.Clo.PrintInstrumented || CommandLineOptions.Clo.PrintInlined) { + foreach (Block b in this.Blocks) { + b.Emit(stream, level + 1); + } + } + + stream.WriteLine(level, "{0}", '}'); + + stream.WriteLine(); + stream.WriteLine(); + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + // nothing to register + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + if (Proc != null) { + // already resolved + return; + } + + DeclWithFormals dwf = rc.LookUpProcedure(cce.NonNull(this.Name)); + Proc = dwf as Procedure; + if (dwf == null) { + rc.Error(this, "implementation given for undeclared procedure: {0}", this.Name); + } else if (Proc == null) { + rc.Error(this, "implementations given for function, not procedure: {0}", this.Name); + } + + int previousTypeBinderState = rc.TypeBinderState; + try { + RegisterTypeParameters(rc); + + rc.PushVarContext(); + RegisterFormals(InParams, rc); + RegisterFormals(OutParams, rc); + + foreach (Variable/*!*/ v in LocVars) { + Contract.Assert(v != null); + v.Register(rc); + v.Resolve(rc); + } + foreach (Variable/*!*/ v in LocVars) { + Contract.Assert(v != null); + v.ResolveWhere(rc); + } + + rc.PushProcedureContext(); + foreach (Block b in Blocks) { + b.Register(rc); + } + + ResolveAttributes(rc); + + rc.StateMode = ResolutionContext.State.Two; + foreach (Block b in Blocks) { + b.Resolve(rc); + } + rc.StateMode = ResolutionContext.State.Single; + + rc.PopProcedureContext(); + rc.PopVarContext(); + + Type.CheckBoundVariableOccurrences(TypeParameters, + new List(InParams.Select(Item => Item.TypedIdent.Type).ToArray()), + new List(OutParams.Select(Item => Item.TypedIdent.Type).ToArray()), + this.tok, "implementation arguments", + rc); + } finally { + rc.TypeBinderState = previousTypeBinderState; + } + SortTypeParams(); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + base.Typecheck(tc); + + Contract.Assume(this.Proc != null); + + if (this.TypeParameters.Count != Proc.TypeParameters.Count) { + tc.Error(this, "mismatched number of type parameters in procedure implementation: {0}", + this.Name); + } else { + // if the numbers of type parameters are different, it is + // difficult to compare the argument types + MatchFormals(this.InParams, Proc.InParams, "in", tc); + MatchFormals(this.OutParams, Proc.OutParams, "out", tc); + } + + foreach (Variable/*!*/ v in LocVars) { + Contract.Assert(v != null); + v.Typecheck(tc); + } + List oldFrame = tc.Frame; + bool oldYields = tc.Yields; + tc.Frame = Proc.Modifies; + tc.Yields = QKeyValue.FindBoolAttribute(Proc.Attributes, "yields"); + foreach (Block b in Blocks) { + b.Typecheck(tc); + } + Contract.Assert(tc.Frame == Proc.Modifies); + tc.Frame = oldFrame; + tc.Yields = oldYields; + } + void MatchFormals(List/*!*/ implFormals, List/*!*/ procFormals, string/*!*/ inout, TypecheckingContext/*!*/ tc) { + Contract.Requires(implFormals != null); + Contract.Requires(procFormals != null); + Contract.Requires(inout != null); + Contract.Requires(tc != null); + if (implFormals.Count != procFormals.Count) { + tc.Error(this, "mismatched number of {0}-parameters in procedure implementation: {1}", + inout, this.Name); + } else { + // unify the type parameters so that types can be compared + Contract.Assert(Proc != null); + Contract.Assert(this.TypeParameters.Count == Proc.TypeParameters.Count); + + IDictionary/*!*/ subst1 = + new Dictionary(); + IDictionary/*!*/ subst2 = + new Dictionary(); + + for (int i = 0; i < this.TypeParameters.Count; ++i) { + TypeVariable/*!*/ newVar = + new TypeVariable(Token.NoToken, Proc.TypeParameters[i].Name); + Contract.Assert(newVar != null); + subst1.Add(Proc.TypeParameters[i], newVar); + subst2.Add(this.TypeParameters[i], newVar); + } + + for (int i = 0; i < implFormals.Count; i++) { + // the names of the formals are allowed to change from the proc to the impl + + // but types must be identical + Type t = cce.NonNull((Variable)implFormals[i]).TypedIdent.Type.Substitute(subst2); + Type u = cce.NonNull((Variable)procFormals[i]).TypedIdent.Type.Substitute(subst1); + if (!t.Equals(u)) { + string/*!*/ a = cce.NonNull((Variable)implFormals[i]).Name; + Contract.Assert(a != null); + string/*!*/ b = cce.NonNull((Variable)procFormals[i]).Name; + Contract.Assert(b != null); + string/*!*/ c; + if (a == b) { + c = a; + } else { + c = String.Format("{0} (named {1} in implementation)", b, a); + } + tc.Error(this, "mismatched type of {0}-parameter in implementation {1}: {2}", inout, this.Name, c); + } + } + } + } + + private Dictionary/*?*/ formalMap = null; + public void ResetImplFormalMap() { + this.formalMap = null; + } + public Dictionary/*!*/ GetImplFormalMap() { + Contract.Ensures(Contract.Result>() != null); + + if (this.formalMap != null) + return this.formalMap; + else { + Dictionary/*!*/ map = new Dictionary (InParams.Count + OutParams.Count); + + Contract.Assume(this.Proc != null); + Contract.Assume(InParams.Count == Proc.InParams.Count); + for (int i = 0; i < InParams.Count; i++) { + Variable/*!*/ v = InParams[i]; + Contract.Assert(v != null); + IdentifierExpr ie = new IdentifierExpr(v.tok, v); + Variable/*!*/ pv = Proc.InParams[i]; + Contract.Assert(pv != null); + map.Add(pv, ie); + } + System.Diagnostics.Debug.Assert(OutParams.Count == Proc.OutParams.Count); + for (int i = 0; i < OutParams.Count; i++) { + Variable/*!*/ v = cce.NonNull(OutParams[i]); + IdentifierExpr ie = new IdentifierExpr(v.tok, v); + Variable pv = cce.NonNull(Proc.OutParams[i]); + map.Add(pv, ie); + } + this.formalMap = map; + + if (CommandLineOptions.Clo.PrintWithUniqueASTIds) { + Console.WriteLine("Implementation.GetImplFormalMap on {0}:", this.Name); + using (TokenTextWriter stream = new TokenTextWriter("", Console.Out, /*setTokens=*/false, /*pretty=*/ false)) { + foreach (var e in map) { + Console.Write(" "); + cce.NonNull((Variable/*!*/)e.Key).Emit(stream, 0); + Console.Write(" --> "); + cce.NonNull((Expr)e.Value).Emit(stream); + Console.WriteLine(); + } + } + } + + return map; + } + } + + /// + /// Return a collection of blocks that are reachable from the block passed as a parameter. + /// The block must be defined in the current implementation + /// + public ICollection GetConnectedComponents(Block startingBlock) { + Contract.Requires(startingBlock != null); + Contract.Ensures(cce.NonNullElements(Contract.Result>(), true)); + Contract.Assert(this.Blocks.Contains(startingBlock)); + + if (!this.BlockPredecessorsComputed) + ComputeStronglyConnectedComponents(); + +#if DEBUG_PRINT + System.Console.WriteLine("* Strongly connected components * \n{0} \n ** ", scc); +#endif + + foreach (ICollection component in cce.NonNull(this.scc)) { + foreach (Block/*!*/ b in component) { + Contract.Assert(b != null); + if (b == startingBlock) // We found the compontent that owns the startingblock + { + return component; + } + } + } + + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // if we are here, it means that the block is not in one of the components. This is an error. + } + + /// + /// Compute the strongly connected compontents of the blocks in the implementation. + /// As a side effect, it also computes the "predecessor" relation for the block in the implementation + /// + override public void ComputeStronglyConnectedComponents() { + if (!this.BlockPredecessorsComputed) + ComputePredecessorsForBlocks(); + + Adjacency next = new Adjacency(Successors); + Adjacency prev = new Adjacency(Predecessors); + + this.scc = new StronglyConnectedComponents(this.Blocks, next, prev); + scc.Compute(); + + + foreach (Block/*!*/ block in this.Blocks) { + Contract.Assert(block != null); + block.Predecessors = new List(); + } + + } + + /// + /// Reset the abstract stated computed before + /// + override public void ResetAbstractInterpretationState() { + foreach (Block/*!*/ b in this.Blocks) { + Contract.Assert(b != null); + b.ResetAbstractInterpretationState(); + } + } + + /// + /// A private method used as delegate for the strongly connected components. + /// It return, given a node, the set of its successors + /// + private IEnumerable/**//*!*/ Successors(Block node) { + Contract.Requires(node != null); + Contract.Ensures(Contract.Result() != null); + + GotoCmd gotoCmd = node.TransferCmd as GotoCmd; + + if (gotoCmd != null) { // If it is a gotoCmd + Contract.Assert(gotoCmd.labelTargets != null); + + return gotoCmd.labelTargets; + } else { // otherwise must be a ReturnCmd + Contract.Assert(node.TransferCmd is ReturnCmd); + + return new List(); + } + } + + /// + /// A private method used as delegate for the strongly connected components. + /// It return, given a node, the set of its predecessors + /// + private IEnumerable/**//*!*/ Predecessors(Block node) { + Contract.Requires(node != null); + Contract.Ensures(Contract.Result() != null); + + Contract.Assert(this.BlockPredecessorsComputed); + + return node.Predecessors; + } + + /// + /// Compute the predecessor informations for the blocks + /// + public void ComputePredecessorsForBlocks() { + foreach (Block b in this.Blocks) { + b.Predecessors = new List(); + } + foreach (Block b in this.Blocks) { + GotoCmd gtc = b.TransferCmd as GotoCmd; + if (gtc != null) { + Contract.Assert(gtc.labelTargets != null); + foreach (Block/*!*/ dest in gtc.labelTargets) { + Contract.Assert(dest != null); + dest.Predecessors.Add(b); + } + } + } + this.BlockPredecessorsComputed = true; + } + + public void PruneUnreachableBlocks() { + ArrayList /*Block!*/ visitNext = new ArrayList /*Block!*/ (); + List reachableBlocks = new List(); + HashSet reachable = new HashSet(); // the set of elements in "reachableBlocks" + + visitNext.Add(this.Blocks[0]); + while (visitNext.Count != 0) { + Block b = cce.NonNull((Block)visitNext[visitNext.Count - 1]); + visitNext.RemoveAt(visitNext.Count - 1); + if (!reachable.Contains(b)) { + reachableBlocks.Add(b); + reachable.Add(b); + if (b.TransferCmd is GotoCmd) { + if (CommandLineOptions.Clo.PruneInfeasibleEdges) { + foreach (Cmd/*!*/ s in b.Cmds) { + Contract.Assert(s != null); + if (s is PredicateCmd) { + LiteralExpr e = ((PredicateCmd)s).Expr as LiteralExpr; + if (e != null && e.IsFalse) { + // This statement sequence will never reach the end, because of this "assume false" or "assert false". + // Hence, it does not reach its successors. + b.TransferCmd = new ReturnCmd(b.TransferCmd.tok); + goto NEXT_BLOCK; + } + } + } + } + // it seems that the goto statement at the end may be reached + foreach (Block succ in cce.NonNull((GotoCmd)b.TransferCmd).labelTargets) { + Contract.Assume(succ != null); + visitNext.Add(succ); + } + } + } + NEXT_BLOCK: { + } + } + + this.Blocks = reachableBlocks; + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitImplementation(this); + } + + public void FreshenCaptureStates() { + + // Assume commands with the "captureState" attribute allow model states to be + // captured for error reporting. + // Some program transformations, such as loop unrolling, duplicate parts of the + // program, leading to "capture-state-assumes" being duplicated. This leads + // to ambiguity when getting a state from the model. + // This method replaces the key of every "captureState" attribute with something + // unique + + int FreshCounter = 0; + foreach(var b in Blocks) { + List newCmds = new List(); + for (int i = 0; i < b.Cmds.Count(); i++) { + var a = b.Cmds[i] as AssumeCmd; + if (a != null && (QKeyValue.FindStringAttribute(a.Attributes, "captureState") != null)) { + string StateName = QKeyValue.FindStringAttribute(a.Attributes, "captureState"); + newCmds.Add(new AssumeCmd(Token.NoToken, a.Expr, FreshenCaptureState(a.Attributes, FreshCounter))); + FreshCounter++; + } + else { + newCmds.Add(b.Cmds[i]); + } + } + b.Cmds = newCmds; + } + } + + private QKeyValue FreshenCaptureState(QKeyValue Attributes, int FreshCounter) { + // Returns attributes identical to Attributes, but: + // - reversed (for ease of implementation; should not matter) + // - with the value for "captureState" replaced by a fresh value + Contract.Requires(QKeyValue.FindStringAttribute(Attributes, "captureState") != null); + string FreshValue = QKeyValue.FindStringAttribute(Attributes, "captureState") + "$renamed$" + Name + "$" + FreshCounter; + + QKeyValue result = null; + while (Attributes != null) { + if (Attributes.Key.Equals("captureState")) { + result = new QKeyValue(Token.NoToken, Attributes.Key, new List() { FreshValue }, result); + } else { + result = new QKeyValue(Token.NoToken, Attributes.Key, Attributes.Params, result); + } + Attributes = Attributes.Next; + } + return result; + } + + } + + + public class TypedIdent : Absy { + public const string NoName = ""; + + private string/*!*/ _name; + + public string/*!*/ Name { + get { + Contract.Ensures(Contract.Result() != null); + return this._name; + } + set { + Contract.Requires(value != null); + this._name = value; + } + } + + private Type/*!*/ _type; + + public Type/*!*/ Type { + get { + Contract.Ensures(Contract.Result() != null); + return this._type; + } + set { + Contract.Requires(value != null); + this._type = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._name != null); + Contract.Invariant(this._type != null); + } + + public Expr WhereExpr; + // [NotDelayed] + public TypedIdent(IToken/*!*/ tok, string/*!*/ name, Type/*!*/ type) + : this(tok, name, type, null) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + Contract.Requires(type != null); + Contract.Ensures(this.WhereExpr == null); //PM: needed to verify BoogiePropFactory.FreshBoundVariable + //:this(tok, name, type, null); // here for aesthetic reasons + } + // [NotDelayed] + public TypedIdent(IToken/*!*/ tok, string/*!*/ name, Type/*!*/ type, Expr whereExpr) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + Contract.Requires(type != null); + Contract.Ensures(this.WhereExpr == whereExpr); + this._name = name; + this._type = type; + this.WhereExpr = whereExpr; + } + public bool HasName { + get { + return this.Name != NoName; + } + } + public void Emit(TokenTextWriter stream) { + Contract.Requires(stream != null); + stream.SetToken(this); + stream.push(); + if (this.Name != NoName) { + stream.Write("{0}: ", TokenTextWriter.SanitizeIdentifier(this.Name)); + } + this.Type.Emit(stream); + if (this.WhereExpr != null) { + stream.sep(); + stream.Write(" where "); + this.WhereExpr.Emit(stream); + } + stream.pop(); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + // NOTE: WhereExpr needs to be resolved by the caller, because the caller must provide a modified ResolutionContext + this.Type = this.Type.ResolveType(rc); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + // type variables can occur when working with polymorphic functions/procedures + // if (!this.Type.IsClosed) + // tc.Error(this, "free variables in type of an identifier: {0}", + // this.Type.FreeVariables); + if (this.WhereExpr != null) { + this.WhereExpr.Typecheck(tc); + Contract.Assert(this.WhereExpr.Type != null); // follows from postcondition of Expr.Typecheck + if (!this.WhereExpr.Type.Unify(Type.Bool)) { + tc.Error(this, "where clauses must be of type bool"); + } + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitTypedIdent(this); + } + } + + #region Helper methods for generic Sequences + + public static class TypeVariableSeqAlgorithms { + public static void AppendWithoutDups(this List tvs, List s1) { + Contract.Requires(s1 != null); + for (int i = 0; i < s1.Count; i++) { + TypeVariable/*!*/ next = s1[i]; + Contract.Assert(next != null); + if (!tvs.Contains(next)) + tvs.Add(next); + } + } + } + + public static class Emitter { + + public static void Emit(this List/*!*/ decls, TokenTextWriter stream) { + Contract.Requires(stream != null); + Contract.Requires(cce.NonNullElements(decls)); + bool first = true; + foreach (Declaration d in decls) { + if (d == null) + continue; + if (first) { + first = false; + } else { + stream.WriteLine(); + } + d.Emit(stream, 0); + } + } + + public static void Emit(this List ss, TokenTextWriter stream) { + Contract.Requires(stream != null); + string sep = ""; + foreach (string/*!*/ s in ss) { + Contract.Assert(s != null); + stream.Write(sep); + sep = ", "; + stream.Write(s); + } + } + + public static void Emit(this IList ts, TokenTextWriter stream) { + Contract.Requires(stream != null); + string sep = ""; + stream.push(); + foreach (Expr/*!*/ e in ts) { + Contract.Assert(e != null); + stream.Write(sep); + sep = ", "; + stream.sep(); + e.Emit(stream); + } + stream.pop(); + } + + public static void Emit(this List ids, TokenTextWriter stream, bool printWhereComments) { + Contract.Requires(stream != null); + string sep = ""; + foreach (IdentifierExpr/*!*/ e in ids) { + Contract.Assert(e != null); + stream.Write(sep); + sep = ", "; + e.Emit(stream); + + if (printWhereComments && e.Decl != null && e.Decl.TypedIdent.WhereExpr != null) { + stream.Write(" /* where "); + e.Decl.TypedIdent.WhereExpr.Emit(stream); + stream.Write(" */"); + } + } + } + + public static void Emit(this List vs, TokenTextWriter stream, bool emitAttributes) { + Contract.Requires(stream != null); + string sep = ""; + stream.push(); + foreach (Variable/*!*/ v in vs) { + Contract.Assert(v != null); + stream.Write(sep); + sep = ", "; + stream.sep(); + v.EmitVitals(stream, 0, emitAttributes); + } + stream.pop(); + } + + public static void Emit(this List tys, TokenTextWriter stream, string separator) { + Contract.Requires(separator != null); + Contract.Requires(stream != null); + string sep = ""; + foreach (Type/*!*/ v in tys) { + Contract.Assert(v != null); + stream.Write(sep); + sep = separator; + v.Emit(stream); + } + } + + public static void Emit(this List tvs, TokenTextWriter stream, string separator) { + Contract.Requires(separator != null); + Contract.Requires(stream != null); + string sep = ""; + foreach (TypeVariable/*!*/ v in tvs) { + Contract.Assert(v != null); + stream.Write(sep); + sep = separator; + v.Emit(stream); + } + } + + } + #endregion + + + #region Regular Expressions + // a data structure to recover the "program structure" from the flow graph + public abstract class RE : Cmd { + public RE() + : base(Token.NoToken) { + } + public override void AddAssignedVariables(List vars) { + //Contract.Requires(vars != null); + throw new NotImplementedException(); + } + } + public class AtomicRE : RE { + private Block/*!*/ _b; + + public Block b + { + get + { + Contract.Ensures(Contract.Result() != null); + return this._b; + } + set + { + Contract.Requires(value != null); + this._b = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._b != null); + } + + public AtomicRE(Block block) { + Contract.Requires(block != null); + this._b = block; + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + b.Resolve(rc); + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + b.Typecheck(tc); + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + b.Emit(stream, level); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitAtomicRE(this); + } + } + public abstract class CompoundRE : RE { + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + return; + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + return; + } + } + public class Sequential : CompoundRE { + private RE/*!*/ _first; + + public RE/*!*/ first { + get { + Contract.Ensures(Contract.Result() != null); + return this._first; + } + set { + Contract.Requires(value != null); + this._first = value; + } + } + + private RE/*!*/ _second; + + public RE/*!*/ second { + get { + Contract.Ensures(Contract.Result() != null); + return this._second; + } + set { + Contract.Requires(value != null); + this._second = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._first != null); + Contract.Invariant(this._second != null); + } + + public Sequential(RE first, RE second) { + Contract.Requires(first != null); + Contract.Requires(second != null); + this._first = first; + this._second = second; + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.WriteLine(); + stream.WriteLine("{0};", Indent(stream.UseForComputingChecksums ? 0 : level)); + first.Emit(stream, level + 1); + second.Emit(stream, level + 1); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitSequential(this); + } + } + public class Choice : CompoundRE { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._rs != null); + } + + private List/*!*/ _rs; + + public List/*!*/ rs { //Rename this (and _rs) if possible + get { + Contract.Ensures(Contract.Result>() != null); + return this._rs; + } + set { + Contract.Requires(value != null); + this._rs = value; + } + } + + public Choice(List operands) { + Contract.Requires(operands != null); + this._rs = operands; + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.WriteLine(); + stream.WriteLine("{0}[]", Indent(stream.UseForComputingChecksums ? 0 : level)); + foreach (RE/*!*/ r in rs) { + Contract.Assert(r != null); + r.Emit(stream, level + 1); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitChoice(this); + } + } + public class DAG2RE { + public static RE Transform(Block b) { + Contract.Requires(b != null); + Contract.Ensures(Contract.Result() != null); + TransferCmd tc = b.TransferCmd; + if (tc is ReturnCmd) { + return new AtomicRE(b); + } else if (tc is GotoCmd) { + GotoCmd/*!*/ g = (GotoCmd)tc; + Contract.Assert(g != null); + Contract.Assume(g.labelTargets != null); + if (g.labelTargets.Count == 1) { + return new Sequential(new AtomicRE(b), Transform(cce.NonNull(g.labelTargets[0]))); + } else { + List rs = new List(); + foreach (Block/*!*/ target in g.labelTargets) { + Contract.Assert(target != null); + RE r = Transform(target); + rs.Add(r); + } + RE second = new Choice(rs); + return new Sequential(new AtomicRE(b), second); + } + } else { + Contract.Assume(false); + throw new cce.UnreachableException(); + } + } + } + + #endregion + + // NOTE: This class is here for convenience, since this file's + // classes are used pretty much everywhere. + + public class BoogieDebug { + public static bool DoPrinting = false; + + public static void Write(string format, params object[] args) { + Contract.Requires(args != null); + Contract.Requires(format != null); + if (DoPrinting) { + Console.Error.Write(format, args); + } + } + + public static void WriteLine(string format, params object[] args) { + Contract.Requires(args != null); + Contract.Requires(format != null); + if (DoPrinting) { + Console.Error.WriteLine(format, args); + } + } + + public static void WriteLine() { + if (DoPrinting) { + Console.Error.WriteLine(); + } + } + } +} diff --git a/Source/Core/AbsyCmd.cs b/Source/Core/AbsyCmd.cs index b5581ea6..2e33e1dd 100644 --- a/Source/Core/AbsyCmd.cs +++ b/Source/Core/AbsyCmd.cs @@ -1,3496 +1,3500 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -//--------------------------------------------------------------------------------------------- -// BoogiePL - Absy.cs -//--------------------------------------------------------------------------------------------- - -namespace Microsoft.Boogie { - using System; - using System.Collections; - using System.Diagnostics; - using System.Collections.Generic; - using System.Linq; - using Microsoft.Boogie.AbstractInterpretation; - using System.Diagnostics.Contracts; - using Set = GSet; - - - //--------------------------------------------------------------------- - // BigBlock - public class BigBlock { - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(tok != null); - Contract.Invariant(Anonymous || this.labelName != null); - Contract.Invariant(this._ec == null || this._tc == null); - Contract.Invariant(this._simpleCmds != null); - } - - public readonly IToken/*!*/ tok; - - public readonly bool Anonymous; - - private string labelName; - - public string LabelName - { - get - { - Contract.Ensures(Anonymous || Contract.Result() != null); - return this.labelName; - } - set - { - Contract.Requires(Anonymous || value != null); - this.labelName = value; - } - } - - [Rep] - private List/*!*/ _simpleCmds; - - public List/*!*/ simpleCmds - { - get - { - Contract.Ensures(Contract.Result>() != null); - return this._simpleCmds; - } - set - { - Contract.Requires(value != null); - this._simpleCmds = value; - } - } - - private StructuredCmd _ec; - - public StructuredCmd ec - { - get - { - return this._ec; - } - set - { - Contract.Requires(value == null || this.tc == null); - this._ec = value; - } - } - - private TransferCmd _tc; - - public TransferCmd tc - { - get - { - return this._tc; - } - set - { - Contract.Requires(value == null || this.ec == null); - this._tc = value; - } - } - - public BigBlock successorBigBlock; // semantic successor (may be a back-edge, pointing back to enclosing while statement); null if successor is end of procedure body (or if field has not yet been initialized) - - public BigBlock(IToken tok, string labelName, [Captured] List simpleCmds, StructuredCmd ec, TransferCmd tc) { - Contract.Requires(simpleCmds != null); - Contract.Requires(tok != null); - Contract.Requires(ec == null || tc == null); - this.tok = tok; - this.Anonymous = labelName == null; - this.labelName = labelName; - this._simpleCmds = simpleCmds; - this._ec = ec; - this._tc = tc; - } - - public void Emit(TokenTextWriter stream, int level) { - Contract.Requires(stream != null); - if (!Anonymous) { - stream.WriteLine(level, "{0}:", - CommandLineOptions.Clo.PrintWithUniqueASTIds ? String.Format("h{0}^^{1}", this.GetHashCode(), this.LabelName) : this.LabelName); - } - - foreach (Cmd/*!*/ c in this.simpleCmds) { - Contract.Assert(c != null); - c.Emit(stream, level + 1); - } - - if (this.ec != null) { - this.ec.Emit(stream, level + 1); - } else if (this.tc != null) { - this.tc.Emit(stream, level + 1); - } - } - } - - public class StmtList { - [Rep] - private readonly List/*!*/ bigBlocks; - - public IList/*!*/ BigBlocks - { - get - { - Contract.Ensures(Contract.Result>() != null); - Contract.Ensures(Contract.Result>().IsReadOnly); - return this.bigBlocks.AsReadOnly(); - } - } - - public List PrefixCommands; - public readonly IToken/*!*/ EndCurly; - public StmtList ParentContext; - public BigBlock ParentBigBlock; - - private readonly HashSet/*!*/ labels = new HashSet(); - - public void AddLabel(string label) - { - labels.Add(label); - } - - public IEnumerable/*!*/ Labels - { - get - { - Contract.Ensures(cce.NonNullElements(Contract.Result/*!*/>())); - return this.labels.AsEnumerable(); - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(EndCurly != null); - Contract.Invariant(cce.NonNullElements(this.bigBlocks)); - Contract.Invariant(cce.NonNullElements(this.labels)); - } - - public StmtList(IList/*!*/ bigblocks, IToken endCurly) { - Contract.Requires(endCurly != null); - Contract.Requires(cce.NonNullElements(bigblocks)); - Contract.Requires(bigblocks.Count > 0); - this.bigBlocks = new List(bigblocks); - this.EndCurly = endCurly; - } - - // prints the list of statements, not the surrounding curly braces - public void Emit(TokenTextWriter stream, int level) { - Contract.Requires(stream != null); - bool needSeperator = false; - foreach (BigBlock b in BigBlocks) { - Contract.Assert(b != null); - Contract.Assume(cce.IsPeerConsistent(b)); - if (needSeperator) { - stream.WriteLine(); - } - b.Emit(stream, level); - needSeperator = true; - } - } - - /// - /// Tries to insert the commands "prefixCmds" at the beginning of the first block - /// of the StmtList, and returns "true" iff it succeeded. - /// In the event of success, the "suggestedLabel" returns as the name of the - /// block inside StmtList where "prefixCmds" were inserted. This name may be the - /// same as the one passed in, in case this StmtList has no preference as to what - /// to call its first block. In the event of failure, "suggestedLabel" is returned - /// as its input value. - /// Note, to be conservative (that is, ignoring the possible optimization that this - /// method enables), this method can do nothing and return false. - /// - public bool PrefixFirstBlock([Captured] List prefixCmds, ref string suggestedLabel) { - Contract.Requires(suggestedLabel != null); - Contract.Requires(prefixCmds != null); - Contract.Ensures(Contract.Result() || cce.Owner.None(prefixCmds)); // "prefixCmds" is captured only on success - Contract.Assume(PrefixCommands == null); // prefix has not been used - - BigBlock bb0 = BigBlocks[0]; - if (prefixCmds.Count == 0) { - // This is always a success, since there is nothing to insert. Now, decide - // which name to use for the first block. - if (bb0.Anonymous) { - bb0.LabelName = suggestedLabel; - } else { - Contract.Assert(bb0.LabelName != null); - suggestedLabel = bb0.LabelName; - } - return true; - - } else { - // There really is something to insert. We can do this inline only if the first - // block is anonymous (which implies there is no branch to it from within the block). - if (bb0.Anonymous) { - PrefixCommands = prefixCmds; - bb0.LabelName = suggestedLabel; - return true; - } else { - return false; - } - } - } - } - - /// - /// The AST for Boogie structured commands was designed to support backward compatibility with - /// the Boogie unstructured commands. This has made the structured commands hard to construct. - /// The StmtListBuilder class makes it easier to build structured commands. - /// - public class StmtListBuilder { - List/*!*/ bigBlocks = new List(); - string label; - List simpleCmds; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(cce.NonNullElements(bigBlocks)); - } - - void Dump(StructuredCmd scmd, TransferCmd tcmd) { - Contract.Requires(scmd == null || tcmd == null); - Contract.Ensures(label == null && simpleCmds == null); - if (label == null && simpleCmds == null && scmd == null && tcmd == null) { - // nothing to do - } else { - if (simpleCmds == null) { - simpleCmds = new List(); - } - bigBlocks.Add(new BigBlock(Token.NoToken, label, simpleCmds, scmd, tcmd)); - label = null; - simpleCmds = null; - } - } - - /// - /// Collects the StmtList built so far and returns it. The StmtListBuilder should no longer - /// be used once this method has been invoked. - /// - public StmtList Collect(IToken endCurlyBrace) { - Contract.Requires(endCurlyBrace != null); - Contract.Ensures(Contract.Result() != null); - Dump(null, null); - if (bigBlocks.Count == 0) { - simpleCmds = new List(); // the StmtList constructor doesn't like an empty list of BigBlock's - Dump(null, null); - } - return new StmtList(bigBlocks, endCurlyBrace); - } - - public void Add(Cmd cmd) { - Contract.Requires(cmd != null); - if (simpleCmds == null) { - simpleCmds = new List(); - } - simpleCmds.Add(cmd); - } - - public void Add(StructuredCmd scmd) { - Contract.Requires(scmd != null); - Dump(scmd, null); - } - - public void Add(TransferCmd tcmd) { - Contract.Requires(tcmd != null); - Dump(null, tcmd); - } - - public void AddLabelCmd(string label) { - Contract.Requires(label != null); - Dump(null, null); - this.label = label; - } - - public void AddLocalVariable(string name) { - Contract.Requires(name != null); - // TODO - } - } - - class BigBlocksResolutionContext { - StmtList/*!*/ stmtList; - [Peer] - List blocks; - string/*!*/ prefix = "anon"; - int anon = 0; - int FreshAnon() - { - return anon++; - } - HashSet allLabels = new HashSet(); - Errors/*!*/ errorHandler; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(stmtList != null); - Contract.Invariant(cce.NonNullElements(blocks, true)); - Contract.Invariant(prefix != null); - Contract.Invariant(cce.NonNullElements(allLabels, true)); - Contract.Invariant(errorHandler != null); - } - - private void ComputeAllLabels(StmtList stmts) { - if (stmts == null) return; - foreach (BigBlock bb in stmts.BigBlocks) { - if (bb.LabelName != null) { - allLabels.Add(bb.LabelName); - } - ComputeAllLabels(bb.ec); - } - } - - private void ComputeAllLabels(StructuredCmd cmd) { - if (cmd == null) return; - if (cmd is IfCmd) { - IfCmd ifCmd = (IfCmd)cmd; - ComputeAllLabels(ifCmd.thn); - ComputeAllLabels(ifCmd.elseIf); - ComputeAllLabels(ifCmd.elseBlock); - } - else if (cmd is WhileCmd) { - WhileCmd whileCmd = (WhileCmd)cmd; - ComputeAllLabels(whileCmd.Body); - } - } - - public BigBlocksResolutionContext(StmtList stmtList, Errors errorHandler) { - Contract.Requires(errorHandler != null); - Contract.Requires(stmtList != null); - this.stmtList = stmtList; - this.errorHandler = errorHandler; - ComputeAllLabels(stmtList); - } - - public List/*!*/ Blocks { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - if (blocks == null) { - blocks = new List(); - - int startErrorCount = this.errorHandler.count; - // Check that all goto statements go to a label in allLabels, and no break statement to a non-enclosing loop. - // Also, determine a good value for "prefix". - CheckLegalLabels(stmtList, null, null); - - // fill in names of anonymous blocks - NameAnonymousBlocks(stmtList); - - // determine successor blocks - RecordSuccessors(stmtList, null); - - if (this.errorHandler.count == startErrorCount) { - // generate blocks from the big blocks - CreateBlocks(stmtList, null); - } - } - return blocks; - } - } - - void CheckLegalLabels(StmtList stmtList, StmtList parentContext, BigBlock parentBigBlock) { - Contract.Requires(stmtList != null); - Contract.Requires((parentContext == null) == (parentBigBlock == null)); - Contract.Requires(stmtList.ParentContext == null); // it hasn't been set yet - //modifies stmtList.*; - Contract.Ensures(stmtList.ParentContext == parentContext); - stmtList.ParentContext = parentContext; - stmtList.ParentBigBlock = parentBigBlock; - - // record the labels declared in this StmtList - foreach (BigBlock b in stmtList.BigBlocks) { - if (b.LabelName != null) { - string n = b.LabelName; - if (n.StartsWith(prefix)) { - if (prefix.Length < n.Length && n[prefix.Length] == '0') { - prefix += "1"; - } else { - prefix += "0"; - } - } - stmtList.AddLabel(b.LabelName); - } - } - - // check that labels in this and nested StmtList's are legal - foreach (BigBlock b in stmtList.BigBlocks) { - // goto's must reference blocks in enclosing blocks - if (b.tc is GotoCmd) { - GotoCmd g = (GotoCmd)b.tc; - foreach (string/*!*/ lbl in cce.NonNull(g.labelNames)) { - Contract.Assert(lbl != null); - /* - bool found = false; - for (StmtList sl = stmtList; sl != null; sl = sl.ParentContext) { - if (sl.Labels.Contains(lbl)) { - found = true; - break; - } - } - if (!found) { - this.errorHandler.SemErr(g.tok, "Error: goto label '" + lbl + "' is undefined or out of reach"); - } - */ - if (!allLabels.Contains(lbl)) { - this.errorHandler.SemErr(g.tok, "Error: goto label '" + lbl + "' is undefined"); - } - } - } - - // break labels must refer to an enclosing while statement - else if (b.ec is BreakCmd) { - BreakCmd bcmd = (BreakCmd)b.ec; - Contract.Assert(bcmd.BreakEnclosure == null); // it hasn't been initialized yet - bool found = false; - for (StmtList sl = stmtList; sl.ParentBigBlock != null; sl = sl.ParentContext) { - cce.LoopInvariant(sl != null); - BigBlock bb = sl.ParentBigBlock; - - if (bcmd.Label == null) { - // a label-less break statement breaks out of the innermost enclosing while statement - if (bb.ec is WhileCmd) { - bcmd.BreakEnclosure = bb; - found = true; - break; - } - } else if (bcmd.Label == bb.LabelName) { - // a break statement with a label can break out of both if statements and while statements - if (bb.simpleCmds.Count == 0) { - // this is a good target: the label refers to the if/while statement - bcmd.BreakEnclosure = bb; - } else { - // the label of bb refers to the first statement of bb, which in which case is a simple statement, not an if/while statement - this.errorHandler.SemErr(bcmd.tok, "Error: break label '" + bcmd.Label + "' must designate an enclosing statement"); - } - found = true; // don't look any further, since we've found a matching label - break; - } - } - if (!found) { - if (bcmd.Label == null) { - this.errorHandler.SemErr(bcmd.tok, "Error: break statement is not inside a loop"); - } else { - this.errorHandler.SemErr(bcmd.tok, "Error: break label '" + bcmd.Label + "' must designate an enclosing statement"); - } - } - } - - // recurse - else if (b.ec is WhileCmd) { - WhileCmd wcmd = (WhileCmd)b.ec; - CheckLegalLabels(wcmd.Body, stmtList, b); - } else { - for (IfCmd ifcmd = b.ec as IfCmd; ifcmd != null; ifcmd = ifcmd.elseIf) { - CheckLegalLabels(ifcmd.thn, stmtList, b); - if (ifcmd.elseBlock != null) { - CheckLegalLabels(ifcmd.elseBlock, stmtList, b); - } - } - } - } - } - - void NameAnonymousBlocks(StmtList stmtList) { - Contract.Requires(stmtList != null); - foreach (BigBlock b in stmtList.BigBlocks) { - if (b.LabelName == null) { - b.LabelName = prefix + FreshAnon(); - } - if (b.ec is WhileCmd) { - WhileCmd wcmd = (WhileCmd)b.ec; - NameAnonymousBlocks(wcmd.Body); - } else { - for (IfCmd ifcmd = b.ec as IfCmd; ifcmd != null; ifcmd = ifcmd.elseIf) { - NameAnonymousBlocks(ifcmd.thn); - if (ifcmd.elseBlock != null) { - NameAnonymousBlocks(ifcmd.elseBlock); - } - } - } - } - } - - void RecordSuccessors(StmtList stmtList, BigBlock successor) { - Contract.Requires(stmtList != null); - for (int i = stmtList.BigBlocks.Count; 0 <= --i; ) { - BigBlock big = stmtList.BigBlocks[i]; - big.successorBigBlock = successor; - - if (big.ec is WhileCmd) { - WhileCmd wcmd = (WhileCmd)big.ec; - RecordSuccessors(wcmd.Body, big); - } else { - for (IfCmd ifcmd = big.ec as IfCmd; ifcmd != null; ifcmd = ifcmd.elseIf) { - RecordSuccessors(ifcmd.thn, successor); - if (ifcmd.elseBlock != null) { - RecordSuccessors(ifcmd.elseBlock, successor); - } - } - } - - successor = big; - } - } - - // If the enclosing context is a loop, then "runOffTheEndLabel" is the loop head label; - // otherwise, it is null. - void CreateBlocks(StmtList stmtList, string runOffTheEndLabel) { - Contract.Requires(stmtList != null); - Contract.Requires(blocks != null); - List cmdPrefixToApply = stmtList.PrefixCommands; - - int n = stmtList.BigBlocks.Count; - foreach (BigBlock b in stmtList.BigBlocks) { - n--; - Contract.Assert(b.LabelName != null); - List theSimpleCmds; - if (cmdPrefixToApply == null) { - theSimpleCmds = b.simpleCmds; - } else { - theSimpleCmds = new List(); - theSimpleCmds.AddRange(cmdPrefixToApply); - theSimpleCmds.AddRange(b.simpleCmds); - cmdPrefixToApply = null; // now, we've used 'em up - } - - if (b.tc != null) { - // this BigBlock has the very same components as a Block - Contract.Assert(b.ec == null); - Block block = new Block(b.tok, b.LabelName, theSimpleCmds, b.tc); - blocks.Add(block); - - } else if (b.ec == null) { - TransferCmd trCmd; - if (n == 0 && runOffTheEndLabel != null) { - // goto the given label instead of the textual successor block - trCmd = new GotoCmd(stmtList.EndCurly, new List { runOffTheEndLabel }); - } else { - trCmd = GotoSuccessor(stmtList.EndCurly, b); - } - Block block = new Block(b.tok, b.LabelName, theSimpleCmds, trCmd); - blocks.Add(block); - - } else if (b.ec is BreakCmd) { - BreakCmd bcmd = (BreakCmd)b.ec; - Contract.Assert(bcmd.BreakEnclosure != null); - Block block = new Block(b.tok, b.LabelName, theSimpleCmds, GotoSuccessor(b.ec.tok, bcmd.BreakEnclosure)); - blocks.Add(block); - - } else if (b.ec is WhileCmd) { - WhileCmd wcmd = (WhileCmd)b.ec; - var a = FreshAnon(); - string loopHeadLabel = prefix + a + "_LoopHead"; - string/*!*/ loopBodyLabel = prefix + a + "_LoopBody"; - string loopDoneLabel = prefix + a + "_LoopDone"; - - List ssBody = new List(); - List ssDone = new List(); - if (wcmd.Guard != null) { - var ac = new AssumeCmd(wcmd.tok, wcmd.Guard); - ac.Attributes = new QKeyValue(wcmd.tok, "partition", new List(), null); - ssBody.Add(ac); - - ac = new AssumeCmd(wcmd.tok, Expr.Not(wcmd.Guard)); - ac.Attributes = new QKeyValue(wcmd.tok, "partition", new List(), null); - ssDone.Add(ac); - } - - // Try to squeeze in ssBody into the first block of wcmd.Body - bool bodyGuardTakenCareOf = wcmd.Body.PrefixFirstBlock(ssBody, ref loopBodyLabel); - - // ... goto LoopHead; - Block block = new Block(b.tok, b.LabelName, theSimpleCmds, new GotoCmd(wcmd.tok, new List { loopHeadLabel })); - blocks.Add(block); - - // LoopHead: assert/assume loop_invariant; goto LoopDone, LoopBody; - List ssHead = new List(); - foreach (PredicateCmd inv in wcmd.Invariants) { - ssHead.Add(inv); - } - block = new Block(wcmd.tok, loopHeadLabel, ssHead, new GotoCmd(wcmd.tok, new List { loopDoneLabel, loopBodyLabel })); - blocks.Add(block); - - if (!bodyGuardTakenCareOf) { - // LoopBody: assume guard; goto firstLoopBlock; - block = new Block(wcmd.tok, loopBodyLabel, ssBody, new GotoCmd(wcmd.tok, new List { wcmd.Body.BigBlocks[0].LabelName })); - blocks.Add(block); - } - - // recurse to create the blocks for the loop body - CreateBlocks(wcmd.Body, loopHeadLabel); - - // LoopDone: assume !guard; goto loopSuccessor; - TransferCmd trCmd; - if (n == 0 && runOffTheEndLabel != null) { - // goto the given label instead of the textual successor block - trCmd = new GotoCmd(wcmd.tok, new List { runOffTheEndLabel }); - } else { - trCmd = GotoSuccessor(wcmd.tok, b); - } - block = new Block(wcmd.tok, loopDoneLabel, ssDone, trCmd); - blocks.Add(block); - - } else { - IfCmd ifcmd = (IfCmd)b.ec; - string predLabel = b.LabelName; - List predCmds = theSimpleCmds; - - for (; ifcmd != null; ifcmd = ifcmd.elseIf) { - var a = FreshAnon(); - string thenLabel = prefix + a + "_Then"; - Contract.Assert(thenLabel != null); - string elseLabel = prefix + a + "_Else"; - Contract.Assert(elseLabel != null); - - List ssThen = new List(); - List ssElse = new List(); - if (ifcmd.Guard != null) { - var ac = new AssumeCmd(ifcmd.tok, ifcmd.Guard); - ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List(), null); - ssThen.Add(ac); - - ac = new AssumeCmd(ifcmd.tok, Expr.Not(ifcmd.Guard)); - ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List(), null); - ssElse.Add(ac); - } - - // Try to squeeze in ssThen/ssElse into the first block of ifcmd.thn/ifcmd.elseBlock - bool thenGuardTakenCareOf = ifcmd.thn.PrefixFirstBlock(ssThen, ref thenLabel); - bool elseGuardTakenCareOf = false; - if (ifcmd.elseBlock != null) { - elseGuardTakenCareOf = ifcmd.elseBlock.PrefixFirstBlock(ssElse, ref elseLabel); - } - - // ... goto Then, Else; - Block block = new Block(b.tok, predLabel, predCmds, - new GotoCmd(ifcmd.tok, new List { thenLabel, elseLabel })); - blocks.Add(block); - - if (!thenGuardTakenCareOf) { - // Then: assume guard; goto firstThenBlock; - block = new Block(ifcmd.tok, thenLabel, ssThen, new GotoCmd(ifcmd.tok, new List { ifcmd.thn.BigBlocks[0].LabelName })); - blocks.Add(block); - } - - // recurse to create the blocks for the then branch - CreateBlocks(ifcmd.thn, n == 0 ? runOffTheEndLabel : null); - - if (ifcmd.elseBlock != null) { - Contract.Assert(ifcmd.elseIf == null); - if (!elseGuardTakenCareOf) { - // Else: assume !guard; goto firstElseBlock; - block = new Block(ifcmd.tok, elseLabel, ssElse, new GotoCmd(ifcmd.tok, new List { ifcmd.elseBlock.BigBlocks[0].LabelName })); - blocks.Add(block); - } - - // recurse to create the blocks for the else branch - CreateBlocks(ifcmd.elseBlock, n == 0 ? runOffTheEndLabel : null); - - } else if (ifcmd.elseIf != null) { - // this is an "else if" - predLabel = elseLabel; - predCmds = new List(); - if (ifcmd.Guard != null) { - var ac = new AssumeCmd(ifcmd.tok, Expr.Not(ifcmd.Guard)); - ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List(), null); - predCmds.Add(ac); - } - - } else { - // no else alternative is specified, so else branch is just "skip" - // Else: assume !guard; goto ifSuccessor; - TransferCmd trCmd; - if (n == 0 && runOffTheEndLabel != null) { - // goto the given label instead of the textual successor block - trCmd = new GotoCmd(ifcmd.tok, new List { runOffTheEndLabel }); - } else { - trCmd = GotoSuccessor(ifcmd.tok, b); - } - block = new Block(ifcmd.tok, elseLabel, ssElse, trCmd); - blocks.Add(block); - } - } - } - } - } - - TransferCmd GotoSuccessor(IToken tok, BigBlock b) { - Contract.Requires(b != null); - Contract.Requires(tok != null); - Contract.Ensures(Contract.Result() != null); - if (b.successorBigBlock != null) { - return new GotoCmd(tok, new List { b.successorBigBlock.LabelName }); - } else { - return new ReturnCmd(tok); - } - } - } - - [ContractClass(typeof(StructuredCmdContracts))] - public abstract class StructuredCmd { - private IToken/*!*/ _tok; - - public IToken/*!*/ tok - { - get - { - Contract.Ensures(Contract.Result() != null); - return this._tok; - } - set - { - Contract.Requires(value != null); - this._tok = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._tok != null); - } - - public StructuredCmd(IToken tok) { - Contract.Requires(tok != null); - this._tok = tok; - } - - public abstract void Emit(TokenTextWriter/*!*/ stream, int level); - } - [ContractClassFor(typeof(StructuredCmd))] - public abstract class StructuredCmdContracts : StructuredCmd { - public override void Emit(TokenTextWriter stream, int level) { - Contract.Requires(stream != null); - throw new NotImplementedException(); - } - public StructuredCmdContracts() :base(null){ - - } - } - - public class IfCmd : StructuredCmd { - public Expr Guard; - - private StmtList/*!*/ _thn; - - public StmtList/*!*/ thn - { - get - { - Contract.Ensures(Contract.Result() != null); - return this._thn; - } - set - { - Contract.Requires(value != null); - this._thn = value; - } - } - - private IfCmd _elseIf; - - public IfCmd elseIf - { - get - { - return this._elseIf; - } - set - { - Contract.Requires(value == null || this.elseBlock == null); - this._elseIf = value; - } - } - - private StmtList _elseBlock; - - public StmtList elseBlock - { - get - { - return this._elseBlock; - } - set - { - Contract.Requires(value == null || this.elseIf == null); - this._elseBlock = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._thn != null); - Contract.Invariant(this._elseIf == null || this._elseBlock == null); - } - - public IfCmd(IToken/*!*/ tok, Expr guard, StmtList/*!*/ thn, IfCmd elseIf, StmtList elseBlock) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(thn != null); - Contract.Requires(elseIf == null || elseBlock == null); - this.Guard = guard; - this._thn = thn; - this._elseIf = elseIf; - this._elseBlock = elseBlock; - } - - public override void Emit(TokenTextWriter stream, int level) { - stream.Write(level, "if ("); - IfCmd/*!*/ ifcmd = this; - while (true) { - if (ifcmd.Guard == null) { - stream.Write("*"); - } else { - ifcmd.Guard.Emit(stream); - } - stream.WriteLine(")"); - - stream.WriteLine(level, "{"); - ifcmd.thn.Emit(stream, level + 1); - stream.WriteLine(level, "}"); - - if (ifcmd.elseIf != null) { - stream.Write(level, "else if ("); - ifcmd = ifcmd.elseIf; - continue; - } else if (ifcmd.elseBlock != null) { - stream.WriteLine(level, "else"); - stream.WriteLine(level, "{"); - ifcmd.elseBlock.Emit(stream, level + 1); - stream.WriteLine(level, "}"); - } - break; - } - } - } - - public class WhileCmd : StructuredCmd { - [Peer] - public Expr Guard; - public List/*!*/ Invariants; - public StmtList/*!*/ Body; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Body != null); - Contract.Invariant(cce.NonNullElements(Invariants)); - } - - - public WhileCmd(IToken tok, [Captured] Expr guard, List/*!*/ invariants, StmtList/*!*/ body) - : base(tok) { - Contract.Requires(cce.NonNullElements(invariants)); - Contract.Requires(body != null); - Contract.Requires(tok != null); - this.Guard = guard; - this.Invariants = invariants; - this.Body = body; - } - - public override void Emit(TokenTextWriter stream, int level) { - stream.Write(level, "while ("); - if (Guard == null) { - stream.Write("*"); - } else { - Guard.Emit(stream); - } - stream.WriteLine(")"); - - foreach (PredicateCmd inv in Invariants) { - if (inv is AssumeCmd) { - stream.Write(level + 1, "free invariant "); - } else { - stream.Write(level + 1, "invariant "); - } - Cmd.EmitAttributes(stream, inv.Attributes); - inv.Expr.Emit(stream); - stream.WriteLine(";"); - } - - stream.WriteLine(level, "{"); - Body.Emit(stream, level + 1); - stream.WriteLine(level, "}"); - } - } - - public class BreakCmd : StructuredCmd { - public string Label; - public BigBlock BreakEnclosure; - - public BreakCmd(IToken tok, string label) - : base(tok) { - Contract.Requires(tok != null); - this.Label = label; - } - - public override void Emit(TokenTextWriter stream, int level) { - - if (Label == null) { - stream.WriteLine(level, "break;"); - } else { - stream.WriteLine(level, "break {0};", Label); - } - } - } - - //--------------------------------------------------------------------- - // Block - public sealed class Block : Absy { - private string/*!*/ label; // Note, Label is mostly readonly, but it can change to the name of a nearby block during block coalescing and empty-block removal - - public string/*!*/ Label - { - get - { - Contract.Ensures(Contract.Result() != null); - return this.label; - } - set - { - Contract.Requires(value != null); - this.label = value; - } - } - - [Rep] - [ElementsPeer] - public List/*!*/ cmds; - - public List/*!*/ Cmds - { - get - { - Contract.Ensures(Contract.Result>() != null); - return this.cmds; - } - set - { - Contract.Requires(value != null); - this.cmds = value; - } - } - - [Rep] //PM: needed to verify Traverse.Visit - public TransferCmd TransferCmd; // maybe null only because we allow deferred initialization (necessary for cyclic structures) - - public byte[] Checksum; - - // Abstract interpretation - - // public bool currentlyTraversed; - - public enum VisitState { - ToVisit, - BeingVisited, - AlreadyVisited - }; // used by WidenPoints.Compute - public VisitState TraversingStatus; - - public int aiId; // block ID used by the abstract interpreter, which may change these numbers with each AI run - public bool widenBlock; - public int iterations; // Count the number of time we visited the block during fixpoint computation. Used to decide if we widen or not - - // VC generation and SCC computation - public List/*!*/ Predecessors; - - // This field is used during passification to null-out entries in block2Incartion hashtable early - public int succCount; - - private HashSet _liveVarsBefore; - - public IEnumerable liveVarsBefore - { - get - { - Contract.Ensures(cce.NonNullElements(Contract.Result>(), true)); - if (this._liveVarsBefore == null) - return null; - else - return this._liveVarsBefore.AsEnumerable(); - } - set - { - Contract.Requires(cce.NonNullElements(value, true)); - if (value == null) - this._liveVarsBefore = null; - else - this._liveVarsBefore = new HashSet(value); - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this.label != null); - Contract.Invariant(this.cmds != null); - Contract.Invariant(cce.NonNullElements(this._liveVarsBefore, true)); - } - - public bool IsLive(Variable v) { - Contract.Requires(v != null); - if (liveVarsBefore == null) - return true; - return liveVarsBefore.Contains(v); - } - - public Block() - : this(Token.NoToken, "", new List(), new ReturnCmd(Token.NoToken)) { - - } - - public Block(IToken tok, string/*!*/ label, List/*!*/ cmds, TransferCmd transferCmd) - : base(tok) { - Contract.Requires(label != null); - Contract.Requires(cmds != null); - Contract.Requires(tok != null); - this.label = label; - this.cmds = cmds; - this.TransferCmd = transferCmd; - this.Predecessors = new List(); - this._liveVarsBefore = null; - this.TraversingStatus = VisitState.ToVisit; - this.iterations = 0; - } - - public void Emit(TokenTextWriter stream, int level) { - Contract.Requires(stream != null); - stream.WriteLine(); - stream.WriteLine( - this, - level, - "{0}:{1}", - CommandLineOptions.Clo.PrintWithUniqueASTIds ? String.Format("h{0}^^{1}", this.GetHashCode(), this.Label) : this.Label, - this.widenBlock ? " // cut point" : ""); - - foreach (Cmd/*!*/ c in this.Cmds) { - Contract.Assert(c != null); - c.Emit(stream, level + 1); - } - Contract.Assume(this.TransferCmd != null); - this.TransferCmd.Emit(stream, level + 1); - } - - public void Register(ResolutionContext rc) { - Contract.Requires(rc != null); - rc.AddBlock(this); - } - - public override void Resolve(ResolutionContext rc) { - - - foreach (Cmd/*!*/ c in Cmds) { - Contract.Assert(c != null); - c.Resolve(rc); - } - Contract.Assume(this.TransferCmd != null); - TransferCmd.Resolve(rc); - } - - public override void Typecheck(TypecheckingContext tc) { - - foreach (Cmd/*!*/ c in Cmds) { - Contract.Assert(c != null); - c.Typecheck(tc); - } - Contract.Assume(this.TransferCmd != null); - TransferCmd.Typecheck(tc); - } - - /// - /// Reset the abstract intepretation state of this block. It does this by putting the iterations to 0 and the pre and post states to null - /// - public void ResetAbstractInterpretationState() { - // this.currentlyTraversed = false; - this.TraversingStatus = VisitState.ToVisit; - this.iterations = 0; - } - - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - return this.Label + (this.widenBlock ? "[w]" : ""); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - - Contract.Ensures(Contract.Result() != null); - return visitor.VisitBlock(this); - } - } - - //--------------------------------------------------------------------- - // Commands - [ContractClassFor(typeof(Cmd))] - public abstract class CmdContracts : Cmd { - public CmdContracts() :base(null){ - - } - public override void Emit(TokenTextWriter stream, int level) { - Contract.Requires(stream != null); - throw new NotImplementedException(); - } - public override void AddAssignedVariables(List vars) { - Contract.Requires(vars != null); - throw new NotImplementedException(); - } - } - - public static class ChecksumHelper - { - public static void ComputeChecksums(Cmd cmd, Implementation impl, ISet usedVariables, byte[] currentChecksum = null) - { - if (CommandLineOptions.Clo.VerifySnapshots < 2) - { - return; - } - - var assumeCmd = cmd as AssumeCmd; - if (assumeCmd != null - && QKeyValue.FindBoolAttribute(assumeCmd.Attributes, "assumption_variable_initialization")) - { - // Ignore assumption variable initializations. - assumeCmd.Checksum = currentChecksum; - return; - } - - using (var strWr = new System.IO.StringWriter()) - using (var tokTxtWr = new TokenTextWriter("", strWr, false, false)) - { - tokTxtWr.UseForComputingChecksums = true; - var havocCmd = cmd as HavocCmd; - if (havocCmd != null) - { - tokTxtWr.Write("havoc "); - var relevantVars = havocCmd.Vars.Where(e => usedVariables.Contains(e.Decl) && !e.Decl.Name.StartsWith("a##post##")).OrderBy(e => e.Name).ToList(); - relevantVars.Emit(tokTxtWr, true); - tokTxtWr.WriteLine(";"); - } - else - { - cmd.Emit(tokTxtWr, 0); - } - var md5 = System.Security.Cryptography.MD5.Create(); - var str = strWr.ToString(); - if (str.Any()) - { - var data = System.Text.Encoding.UTF8.GetBytes(str); - var checksum = md5.ComputeHash(data); - currentChecksum = currentChecksum != null ? CombineChecksums(currentChecksum, checksum) : checksum; - } - cmd.Checksum = currentChecksum; - } - - var assertCmd = cmd as AssertCmd; - if (assertCmd != null && assertCmd.Checksum != null) - { - var assertRequiresCmd = assertCmd as AssertRequiresCmd; - if (assertRequiresCmd != null) - { - impl.AddAssertionChecksum(assertRequiresCmd.Checksum); - impl.AddAssertionChecksum(assertRequiresCmd.Call.Checksum); - assertRequiresCmd.SugaredCmdChecksum = assertRequiresCmd.Call.Checksum; - } - else - { - impl.AddAssertionChecksum(assertCmd.Checksum); - } - } - - var sugaredCmd = cmd as SugaredCmd; - if (sugaredCmd != null) - { - // The checksum of a sugared command should not depend on the desugaring itself. - var stateCmd = sugaredCmd.Desugaring as StateCmd; - if (stateCmd != null) - { - foreach (var c in stateCmd.Cmds) - { - ComputeChecksums(c, impl, usedVariables, currentChecksum); - currentChecksum = c.Checksum; - if (c.SugaredCmdChecksum == null) - { - c.SugaredCmdChecksum = cmd.Checksum; - } - } - } - else - { - ComputeChecksums(sugaredCmd.Desugaring, impl, usedVariables, currentChecksum); - } - } - } - - public static byte[] CombineChecksums(byte[] first, byte[] second, bool unordered = false) - { - Contract.Requires(first != null && (second == null || first.Length == second.Length)); - - var result = (byte[])(first.Clone()); - for (int i = 0; second != null && i < second.Length; i++) - { - if (unordered) - { - result[i] += second[i]; - } - else - { - result[i] = (byte)(result[i] * 31 ^ second[i]); - } - } - return result; - } - } - - [ContractClass(typeof(CmdContracts))] - public abstract class Cmd : Absy { - public byte[] Checksum { get; internal set; } - public byte[] SugaredCmdChecksum { get; internal set; } - - public Cmd(IToken/*!*/ tok) - : base(tok) { - Contract.Assert(tok != null); - } - public abstract void Emit(TokenTextWriter/*!*/ stream, int level); - public abstract void AddAssignedVariables(List/*!*/ vars); - public void CheckAssignments(TypecheckingContext tc) - { - Contract.Requires(tc != null); - List/*!*/ vars = new List(); - this.AddAssignedVariables(vars); - foreach (Variable/*!*/ v in vars) - { - Contract.Assert(v != null); - if (!v.IsMutable) - { - tc.Error(this, "command assigns to an immutable variable: {0}", v.Name); - } - else if (!CommandLineOptions.Clo.DoModSetAnalysis && v is GlobalVariable) - { - if (tc.Yields) { - // a yielding procedure is allowed to modify any global variable - } - else if (tc.Frame == null) - { - tc.Error(this, "update to a global variable allowed only inside an atomic action of a yielding procedure"); - } - else if (!tc.InFrame(v)) - { - tc.Error(this, "command assigns to a global variable that is not in the enclosing procedure's modifies clause: {0}", v.Name); - } - } - } - } - - // Methods to simulate the old SimpleAssignCmd and MapAssignCmd - public static AssignCmd SimpleAssign(IToken tok, IdentifierExpr lhs, Expr rhs) { - Contract.Requires(rhs != null); - Contract.Requires(lhs != null); - Contract.Requires(tok != null); - Contract.Ensures(Contract.Result() != null); - List/*!*/ lhss = new List(); - List/*!*/ rhss = new List(); - - lhss.Add(new SimpleAssignLhs(lhs.tok, lhs)); - rhss.Add(rhs); - - return new AssignCmd(tok, lhss, rhss); - } - - public static AssignCmd/*!*/ MapAssign(IToken tok, - IdentifierExpr/*!*/ map, - List/*!*/ indexes, Expr/*!*/ rhs) { - - Contract.Requires(tok != null); - Contract.Requires(map != null); - Contract.Requires(indexes != null); - Contract.Requires(rhs != null); - Contract.Ensures(Contract.Result() != null); - List/*!*/ lhss = new List(); - List/*!*/ rhss = new List(); - List/*!*/ indexesList = new List(); - - - - foreach (Expr e in indexes) - indexesList.Add(cce.NonNull(e)); - - lhss.Add(new MapAssignLhs(map.tok, - new SimpleAssignLhs(map.tok, map), - indexesList)); - rhss.Add(rhs); - - return new AssignCmd(tok, lhss, rhss); - } - - public static AssignCmd/*!*/ MapAssign(IToken tok, - IdentifierExpr/*!*/ map, - params Expr[]/*!*/ args) { - Contract.Requires(tok != null); - Contract.Requires(map != null); - Contract.Requires(args != null); - Contract.Requires(args.Length > 0); // at least the rhs - Contract.Requires(Contract.ForAll(args, i => i != null)); - Contract.Ensures(Contract.Result() != null); - - List/*!*/ lhss = new List(); - List/*!*/ rhss = new List(); - List/*!*/ indexesList = new List(); - - for (int i = 0; i < args.Length - 1; ++i) - indexesList.Add(cce.NonNull(args[i])); - - lhss.Add(new MapAssignLhs(map.tok, - new SimpleAssignLhs(map.tok, map), - indexesList)); - rhss.Add(cce.NonNull(args[args.Length - 1])); - - return new AssignCmd(tok, lhss, rhss); - } - - /// - /// This is a helper routine for printing a linked list of attributes. Each attribute - /// is terminated by a space. - /// - public static void EmitAttributes(TokenTextWriter stream, QKeyValue attributes) { - Contract.Requires(stream != null); - - if (stream.UseForComputingChecksums) { return; } - - for (QKeyValue kv = attributes; kv != null; kv = kv.Next) { - kv.Emit(stream); - stream.Write(" "); - } - } - public static void ResolveAttributes(QKeyValue attributes, ResolutionContext rc) { - Contract.Requires(rc != null); - for (QKeyValue kv = attributes; kv != null; kv = kv.Next) { - kv.Resolve(rc); - } - } - public static void TypecheckAttributes(QKeyValue attributes, TypecheckingContext tc) { - Contract.Requires(tc != null); - for (QKeyValue kv = attributes; kv != null; kv = kv.Next) { - kv.Typecheck(tc); - } - } - - [Pure] - public override string ToString() - { - Contract.Ensures(Contract.Result() != null); - System.IO.StringWriter buffer = new System.IO.StringWriter(); - using (TokenTextWriter stream = new TokenTextWriter("", buffer, /*setTokens=*/ false , /*pretty=*/ false)) { - this.Emit(stream, 0); - } - return buffer.ToString(); - } - } - - public class YieldCmd : Cmd - { - public YieldCmd(IToken/*!*/ tok) - : base(tok) - { - Contract.Requires(tok != null); - } - public override void Emit(TokenTextWriter stream, int level) - { - //Contract.Requires(stream != null); - stream.WriteLine(this, level, "yield;"); - } - public override void Resolve(ResolutionContext rc) - { - // nothing to resolve - } - public override void Typecheck(TypecheckingContext tc) - { - if (!CommandLineOptions.Clo.DoModSetAnalysis && !tc.Yields) - { - tc.Error(this, "enclosing procedure of a yield command must yield"); - } - } - public override void AddAssignedVariables(List vars) - { - // nothing to add - } - public override Absy StdDispatch(StandardVisitor visitor) - { - Contract.Ensures(Contract.Result() != null); - return visitor.VisitYieldCmd(this); - } - } - - public class CommentCmd : Cmd // just a convenience for debugging - { - public readonly string/*!*/ Comment; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Comment != null); - } - - public CommentCmd(string c) - : base(Token.NoToken) { - Contract.Requires(c != null); - Comment = c; - } - public override void Emit(TokenTextWriter stream, int level) { - if (stream.UseForComputingChecksums) { return; } - - if (this.Comment.Contains("\n")) { - stream.WriteLine(this, level, "/* {0} */", this.Comment); - } else { - stream.WriteLine(this, level, "// {0}", this.Comment); - } - } - public override void Resolve(ResolutionContext rc) { - - } - public override void AddAssignedVariables(List vars) { - - } - public override void Typecheck(TypecheckingContext tc) { - - } - - public override Absy StdDispatch(StandardVisitor visitor) { - - - return visitor.VisitCommentCmd(this); - } - } - - // class for parallel assignments, which subsumes both the old - // SimpleAssignCmd and the old MapAssignCmd - public class AssignCmd : Cmd { - private List/*!*/ _lhss; - - public IList/*!*/ Lhss { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - Contract.Ensures(Contract.Result>().IsReadOnly); - return this._lhss.AsReadOnly(); - } - set { - Contract.Requires(cce.NonNullElements(value)); - this._lhss = new List(value); - } - } - - internal void SetLhs(int index, AssignLhs lhs) - { - Contract.Requires(0 <= index && index < this.Lhss.Count); - Contract.Requires(lhs != null); - Contract.Ensures(this.Lhss[index] == lhs); - this._lhss[index] = lhs; - } - - private List/*!*/ _rhss; - - public IList/*!*/ Rhss { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - Contract.Ensures(Contract.Result>().IsReadOnly); - return this._rhss.AsReadOnly(); - } - set { - Contract.Requires(cce.NonNullElements(value)); - this._rhss = new List(value); - } - } - - internal void SetRhs(int index, Expr rhs) - { - Contract.Requires(0 <= index && index < this.Rhss.Count); - Contract.Requires(rhs != null); - Contract.Ensures(this.Rhss[index] == rhs); - this._rhss[index] = rhs; - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(cce.NonNullElements(this._lhss)); - Contract.Invariant(cce.NonNullElements(this._rhss)); - } - - - public AssignCmd(IToken tok, IList/*!*/ lhss, IList/*!*/ rhss) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(cce.NonNullElements(rhss)); - Contract.Requires(cce.NonNullElements(lhss)); - this._lhss = new List(lhss); - this._rhss = new List(rhss); - } - - public override void Emit(TokenTextWriter stream, int level) { - if (stream.UseForComputingChecksums) - { - var lhs = Lhss.FirstOrDefault() as SimpleAssignLhs; - if (lhs != null - && lhs.AssignedVariable.Decl != null - && (QKeyValue.FindBoolAttribute(lhs.AssignedVariable.Decl.Attributes, "assumption") - || lhs.AssignedVariable.Decl.Name.Contains("##old##"))) - { - return; - } - } - - stream.Write(this, level, ""); - - string/*!*/ sep = ""; - foreach (AssignLhs/*!*/ l in Lhss) { - Contract.Assert(l != null); - stream.Write(sep); - sep = ", "; - l.Emit(stream); - } - - stream.Write(" := "); - - sep = ""; - foreach (Expr/*!*/ e in Rhss) { - Contract.Assert(e != null); - stream.Write(sep); - sep = ", "; - e.Emit(stream); - } - - stream.WriteLine(";"); - } - - public override void Resolve(ResolutionContext rc) { - - if (Lhss.Count != Rhss.Count) - rc.Error(this, - "number of left-hand sides does not match number of right-hand sides"); - - foreach (AssignLhs/*!*/ e in Lhss) { - Contract.Assert(e != null); - e.Resolve(rc); - } - foreach (Expr/*!*/ e in Rhss) { - Contract.Assert(e != null); - e.Resolve(rc); - } - - // check for double occurrences of assigned variables - // (could be optimised) - for (int i = 0; i < Lhss.Count; ++i) { - for (int j = i + 1; j < Lhss.Count; ++j) { - if (cce.NonNull(Lhss[i].DeepAssignedVariable).Equals( - Lhss[j].DeepAssignedVariable)) - rc.Error(Lhss[j], - "variable {0} is assigned more than once in parallel assignment", - Lhss[j].DeepAssignedVariable); - } - } - - for (int i = 0; i < Lhss.Count; i++) - { - var lhs = Lhss[i].AsExpr as IdentifierExpr; - if (lhs != null && lhs.Decl != null && QKeyValue.FindBoolAttribute(lhs.Decl.Attributes, "assumption")) - { - var rhs = Rhss[i] as NAryExpr; - if (rhs == null - || !(rhs.Fun is BinaryOperator) - || ((BinaryOperator)(rhs.Fun)).Op != BinaryOperator.Opcode.And - || !(rhs.Args[0] is IdentifierExpr) - || ((IdentifierExpr)(rhs.Args[0])).Name != lhs.Name) - { - rc.Error(tok, string.Format("RHS of assignment to assumption variable {0} must match expression \"{0} && \"", lhs.Name)); - } - else if (rc.HasVariableBeenAssigned(lhs.Decl.Name)) - { - rc.Error(tok, "assumption variable may not be assigned to more than once"); - } - else - { - rc.MarkVariableAsAssigned(lhs.Decl.Name); - } - } - } - } - - public override void Typecheck(TypecheckingContext tc) { - - foreach (AssignLhs/*!*/ e in Lhss) { - Contract.Assert(e != null); - e.Typecheck(tc); - } - foreach (Expr/*!*/ e in Rhss) { - Contract.Assert(e != null); - e.Typecheck(tc); - } - - this.CheckAssignments(tc); - - for (int i = 0; i < Lhss.Count; ++i) { - Type ltype = Lhss[i].Type; - Type rtype = Rhss[i].Type; - if (ltype != null && rtype != null) { - // otherwise, there has already been an error when - // typechecking the lhs or rhs - if (!ltype.Unify(rtype)) - tc.Error(Lhss[i], - "mismatched types in assignment command (cannot assign {0} to {1})", - rtype, ltype); - } - } - } - - public override void AddAssignedVariables(List vars) { - - foreach (AssignLhs/*!*/ l in Lhss) { - Contract.Assert(l != null); - vars.Add(l.DeepAssignedVariable); - } - } - - // transform away the syntactic sugar of map assignments and - // determine an equivalent assignment in which all rhs are simple - // variables - public AssignCmd/*!*/ AsSimpleAssignCmd { - get { - Contract.Ensures(Contract.Result() != null); - - List/*!*/ newLhss = new List(); - List/*!*/ newRhss = new List(); - - for (int i = 0; i < Lhss.Count; ++i) { - IdentifierExpr/*!*/ newLhs; - Expr/*!*/ newRhs; - Lhss[i].AsSimpleAssignment(Rhss[i], out newLhs, out newRhs); - newLhss.Add(new SimpleAssignLhs(Token.NoToken, newLhs)); - newRhss.Add(newRhs); - } - - return new AssignCmd(Token.NoToken, newLhss, newRhss); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - - - return visitor.VisitAssignCmd(this); - } - } - - // There are two different kinds of left-hand sides in assignments: - // simple variables (identifiers), or locations of a map - [ContractClass(typeof(AssignLhsContracts))] - public abstract class AssignLhs : Absy { - // The type of the lhs is determined during typechecking - public abstract Type Type { - get; - } - // Determine the variable that is actually assigned in this lhs - public abstract IdentifierExpr/*!*/ DeepAssignedIdentifier { - get; - } - public abstract Variable DeepAssignedVariable { - get; - } - - public AssignLhs(IToken/*!*/ tok) - : base(tok) { - Contract.Requires(tok != null); - } - public abstract void Emit(TokenTextWriter/*!*/ stream); - - public abstract Expr/*!*/ AsExpr { - get; - } - - // transform away the syntactic sugar of map assignments and - // determine an equivalent simple assignment - internal abstract void AsSimpleAssignment(Expr/*!*/ rhs, - out IdentifierExpr/*!*/ simpleLhs, - out Expr/*!*/ simpleRhs); - } - [ContractClassFor(typeof(AssignLhs))] - public abstract class AssignLhsContracts : AssignLhs { - public AssignLhsContracts():base(null) - { - - }public override IdentifierExpr DeepAssignedIdentifier { - - get { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - public override Expr AsExpr { - get { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - - } - internal override void AsSimpleAssignment(Expr rhs, out IdentifierExpr simpleLhs, out Expr simpleRhs) { - Contract.Requires(rhs != null); - Contract.Ensures(Contract.ValueAtReturn(out simpleLhs) != null); - Contract.Ensures(Contract.ValueAtReturn(out simpleRhs) != null); - - throw new NotImplementedException(); - } - } - - public class SimpleAssignLhs : AssignLhs { - public IdentifierExpr/*!*/ AssignedVariable; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(AssignedVariable != null); - } - - - public override Type Type { - get { - return AssignedVariable.Type; - } - } - - public override IdentifierExpr/*!*/ DeepAssignedIdentifier { - get { - Contract.Ensures(Contract.Result() != null); - return AssignedVariable; - } - } - - public override Variable DeepAssignedVariable { - get { - return AssignedVariable.Decl; - } - } - - public SimpleAssignLhs(IToken tok, IdentifierExpr assignedVariable) - : base(tok) { - Contract.Requires(assignedVariable != null); - Contract.Requires(tok != null); - AssignedVariable = assignedVariable; - } - public override void Resolve(ResolutionContext rc) { - - AssignedVariable.Resolve(rc); - } - public override void Typecheck(TypecheckingContext tc) { - - AssignedVariable.Typecheck(tc); - } - public override void Emit(TokenTextWriter stream) { - - AssignedVariable.Emit(stream); - } - public override Expr/*!*/ AsExpr { - get { - Contract.Ensures(Contract.Result() != null); - - return AssignedVariable; - } - } - internal override void AsSimpleAssignment(Expr rhs, - out IdentifierExpr/*!*/ simpleLhs, - out Expr/*!*/ simpleRhs) { - - - - simpleLhs = AssignedVariable; - simpleRhs = rhs; - } - - public override Absy StdDispatch(StandardVisitor visitor) { - - - return visitor.VisitSimpleAssignLhs(this); - } - } - - // A map-assignment-lhs (m[t1, t2, ...] := ...) is quite similar to - // a map select expression, but it is cleaner to keep those two - // things separate - public class MapAssignLhs : AssignLhs { - public AssignLhs/*!*/ Map; - - public List/*!*/ Indexes; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Map != null); - Contract.Invariant(cce.NonNullElements(Indexes)); - } - - - // The instantiation of type parameters of the map that is - // determined during type checking. - public TypeParamInstantiation TypeParameters = null; - - private Type TypeAttr = null; - - public override Type Type { - get { - return TypeAttr; - } - } - - public override IdentifierExpr/*!*/ DeepAssignedIdentifier { - get { - Contract.Ensures(Contract.Result() != null); - - return Map.DeepAssignedIdentifier; - } - } - - public override Variable DeepAssignedVariable { - get { - return Map.DeepAssignedVariable; - } - } - - public MapAssignLhs(IToken tok, AssignLhs map, List/*!*/ indexes) - : base(tok) { - Contract.Requires(map != null); - Contract.Requires(tok != null); - Contract.Requires(cce.NonNullElements(indexes)); - - Map = map; - Indexes = indexes; - } - public override void Resolve(ResolutionContext rc) { - - Map.Resolve(rc); - foreach (Expr/*!*/ e in Indexes) { - Contract.Assert(e != null); - e.Resolve(rc); - } - } - public override void Typecheck(TypecheckingContext tc) { - - Map.Typecheck(tc); - foreach (Expr/*!*/ e in Indexes) { - Contract.Assert(e != null); - e.Typecheck(tc); - } - - // we use the same typechecking code as in MapSelect - List/*!*/ selectArgs = new List(); - foreach (Expr/*!*/ e in Indexes) { - Contract.Assert(e != null); - selectArgs.Add(e); - } - TypeParamInstantiation/*!*/ tpInsts; - TypeAttr = - MapSelect.Typecheck(cce.NonNull(Map.Type), Map, - selectArgs, out tpInsts, tc, tok, "map assignment"); - TypeParameters = tpInsts; - } - public override void Emit(TokenTextWriter stream) { - - Map.Emit(stream); - stream.Write("["); - string/*!*/ sep = ""; - foreach (Expr/*!*/ e in Indexes) { - Contract.Assert(e != null); - stream.Write(sep); - sep = ", "; - e.Emit(stream); - } - stream.Write("]"); - } - public override Expr/*!*/ AsExpr { - get { - Contract.Ensures(Contract.Result() != null); - - NAryExpr/*!*/ res = Expr.Select(Map.AsExpr, Indexes); - Contract.Assert(res != null); - res.TypeParameters = this.TypeParameters; - res.Type = this.Type; - return res; - } - } - internal override void AsSimpleAssignment(Expr rhs, - out IdentifierExpr/*!*/ simpleLhs, - out Expr/*!*/ simpleRhs) { //Contract.Requires(rhs != null); - Contract.Ensures(Contract.ValueAtReturn(out simpleLhs) != null); - Contract.Ensures(Contract.ValueAtReturn(out simpleRhs) != null); - - NAryExpr/*!*/ newRhs = Expr.Store(Map.AsExpr, Indexes, rhs); - Contract.Assert(newRhs != null); - newRhs.TypeParameters = this.TypeParameters; - newRhs.Type = Map.Type; - Map.AsSimpleAssignment(newRhs, out simpleLhs, out simpleRhs); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitMapAssignLhs(this); - } - } - - /// - /// A StateCmd is like an imperative-let binding around a sequence of commands. - /// There is no user syntax for a StateCmd. Instead, a StateCmd is only used - /// temporarily during the desugaring phase inside the VC generator. - /// - public class StateCmd : Cmd { - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._locals != null); - Contract.Invariant(this._cmds != null); - } - - private List _locals; - - public /*readonly, except for the StandardVisitor*/ List/*!*/ Locals { - get { - Contract.Ensures(Contract.Result>() != null); - return this._locals; - } - internal set { - Contract.Requires(value != null); - this._locals = value; - } - } - - private List _cmds; - - public /*readonly, except for the StandardVisitor*/ List/*!*/ Cmds { - get { - Contract.Ensures(Contract.Result>() != null); - return this._cmds; - } - set { - Contract.Requires(value != null); - this._cmds = value; - } - } - - public StateCmd(IToken tok, List/*!*/ locals, List/*!*/ cmds) - : base(tok) { - Contract.Requires(locals != null); - Contract.Requires(cmds != null); - Contract.Requires(tok != null); - this._locals = locals; - this._cmds = cmds; - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.PushVarContext(); - foreach (Variable/*!*/ v in Locals) { - Contract.Assert(v != null); - rc.AddVariable(v, false); - } - foreach (Cmd/*!*/ cmd in Cmds) { - Contract.Assert(cmd != null); - cmd.Resolve(rc); - } - rc.PopVarContext(); - } - - public override void AddAssignedVariables(List vars) { - //Contract.Requires(vars != null); - List/*!*/ vs = new List(); - foreach (Cmd/*!*/ cmd in this.Cmds) { - Contract.Assert(cmd != null); - cmd.AddAssignedVariables(vs); - } - System.Collections.Hashtable/*!*/ localsSet = new System.Collections.Hashtable(); - foreach (Variable/*!*/ local in this.Locals) { - Contract.Assert(local != null); - localsSet[local] = bool.TrueString; - } - foreach (Variable/*!*/ v in vs) { - Contract.Assert(v != null); - if (!localsSet.ContainsKey(v)) { - vars.Add(v); - } - } - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - foreach (Cmd/*!*/ cmd in Cmds) { - Contract.Assert(cmd != null); - cmd.Typecheck(tc); - } - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.WriteLine(this, level, "{"); - foreach (Variable/*!*/ v in Locals) { - Contract.Assert(v != null); - v.Emit(stream, level + 1); - } - foreach (Cmd/*!*/ c in Cmds) { - Contract.Assert(c != null); - c.Emit(stream, level + 1); - } - stream.WriteLine(level, "}"); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitStateCmd(this); - } - } - [ContractClass(typeof(SugaredCmdContracts))] - abstract public class SugaredCmd : Cmd { - private Cmd desugaring; // null until desugared - - public SugaredCmd(IToken/*!*/ tok) - : base(tok) { - Contract.Requires(tok != null); - } - - public Cmd/*!*/ Desugaring { - get { - Contract.Ensures(Contract.Result() != null); - - if (desugaring == null) { - desugaring = ComputeDesugaring(); - } - return desugaring; - } - } - /// - /// This method invokes "visitor.Visit" on the desugaring, and then updates the - /// desugaring to the result thereof. The method's intended use is for subclasses - /// of StandardVisitor that need to also visit the desugaring. Note, since the - /// "desugaring" field is updated, this is not an appropriate method to be called - /// be a ReadOnlyVisitor; such visitors should instead just call - /// visitor.Visit(sugaredCmd.Desugaring). - /// - public void VisitDesugaring(StandardVisitor visitor) { - Contract.Requires(visitor != null && !(visitor is ReadOnlyVisitor)); - if (desugaring != null) { - desugaring = (Cmd)visitor.Visit(desugaring); - } - } - protected abstract Cmd/*!*/ ComputeDesugaring(); - - public void ExtendDesugaring(IEnumerable before, IEnumerable beforePreconditionCheck, IEnumerable after) - { - var desug = Desugaring; - var stCmd = desug as StateCmd; - if (stCmd != null) - { - stCmd.Cmds.InsertRange(0, before); - var idx = stCmd.Cmds.FindIndex(c => c is AssertCmd || c is HavocCmd || c is AssumeCmd); - if (idx < 0) - { - idx = 0; - } - stCmd.Cmds.InsertRange(idx, beforePreconditionCheck); - stCmd.Cmds.AddRange(after); - } - else if (desug != null) - { - var cmds = new List(before); - cmds.Add(desug); - cmds.AddRange(after); - desugaring = new StateCmd(Token.NoToken, new List(), cmds); - } - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - if (CommandLineOptions.Clo.PrintDesugarings && !stream.UseForComputingChecksums) { - stream.WriteLine(this, level, "/*** desugaring:"); - Desugaring.Emit(stream, level); - stream.WriteLine(level, "**** end desugaring */"); - } - } - } - [ContractClassFor(typeof(SugaredCmd))] - public abstract class SugaredCmdContracts : SugaredCmd { - public SugaredCmdContracts() :base(null){ - - } - protected override Cmd ComputeDesugaring() { - Contract.Ensures(Contract.Result() != null); - - throw new NotImplementedException(); - } - } - - public abstract class CallCommonality : SugaredCmd { - public QKeyValue Attributes; - - private bool isFree = false; - public bool IsFree { - get { - return isFree; - } - set { - isFree = value; - } - } - - private bool isAsync = false; - public bool IsAsync - { - get - { - return isAsync; - } - set - { - isAsync = value; - } - } - - protected CallCommonality(IToken tok, QKeyValue kv) - : base(tok) { - Contract.Requires(tok != null); - Attributes = kv; - } - - protected enum TempVarKind { - Formal, - Old, - Bound - } - - // We have to give the type explicitly, because the type of the formal "likeThisOne" can contain type variables - protected Variable CreateTemporaryVariable(List tempVars, Variable likeThisOne, Type ty, TempVarKind kind, ref int uniqueId) { - Contract.Requires(ty != null); - Contract.Requires(likeThisOne != null); - Contract.Requires(tempVars != null); - Contract.Ensures(Contract.Result() != null); - string/*!*/ tempNamePrefix; - switch (kind) { - case TempVarKind.Formal: - tempNamePrefix = "formal@"; - break; - case TempVarKind.Old: - tempNamePrefix = "old@"; - break; - case TempVarKind.Bound: - tempNamePrefix = "forall@"; - break; - default: { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // unexpected kind - } - TypedIdent ti = likeThisOne.TypedIdent; - // KLM: uniqueId was messing up FixedPointVC for unknown reason. - // I reverted this change for FixedPointVC only. - int id = CommandLineOptions.Clo.FixedPointEngine != null ? UniqueId : (uniqueId++); - TypedIdent newTi = new TypedIdent(ti.tok, "call" + id + tempNamePrefix + ti.Name, ty); - Variable/*!*/ v; - if (kind == TempVarKind.Bound) { - v = new BoundVariable(likeThisOne.tok, newTi); - } else { - v = new LocalVariable(likeThisOne.tok, newTi); - tempVars.Add(v); - } - return v; - } - } - - public class ParCallCmd : CallCommonality, IPotentialErrorNode - { - public List CallCmds; - public ParCallCmd(IToken tok, List callCmds) - : base(tok, null) - { - this.CallCmds = callCmds; - } - public ParCallCmd(IToken tok, List callCmds, QKeyValue kv) - : base(tok, kv) - { - this.CallCmds = callCmds; - } - protected override Cmd ComputeDesugaring() - { - throw new NotImplementedException(); - } - private object errorData; - public object ErrorData - { - get - { - return errorData; - } - set - { - errorData = value; - } - } - public override void Resolve(ResolutionContext rc) - { - ResolveAttributes(Attributes, rc); - foreach (CallCmd callCmd in CallCmds) - { - callCmd.Resolve(rc); - } - HashSet parallelCallLhss = new HashSet(); - foreach (CallCmd callCmd in CallCmds) - { - foreach (IdentifierExpr ie in callCmd.Outs) - { - if (parallelCallLhss.Contains(ie.Decl)) - { - rc.Error(this, "left-hand side of parallel call command contains variable twice: {0}", ie.Name); - } - else - { - parallelCallLhss.Add(ie.Decl); - } - } - } - } - public override void Typecheck(TypecheckingContext tc) - { - TypecheckAttributes(Attributes, tc); - if (!CommandLineOptions.Clo.DoModSetAnalysis) - { - if (!tc.Yields) - { - tc.Error(this, "enclosing procedure of a parallel call must yield"); - } - foreach (CallCmd callCmd in CallCmds) - { - if (!QKeyValue.FindBoolAttribute(callCmd.Proc.Attributes, "yields")) - { - tc.Error(callCmd, "target procedure of a parallel call must yield"); - } - } - } - foreach (CallCmd callCmd in CallCmds) - { - callCmd.Typecheck(tc); - } - } - public override void AddAssignedVariables(List vars) - { - foreach (CallCmd callCmd in CallCmds) - { - callCmd.AddAssignedVariables(vars); - } - } - public override Absy StdDispatch(StandardVisitor visitor) - { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitParCallCmd(this); - } - } - - public class CallCmd : CallCommonality, IPotentialErrorNode - { - public string/*!*/ callee { get; set; } - public Procedure Proc; - public LocalVariable AssignedAssumptionVariable; - - // Element of the following lists can be null, which means that - // the call happens with * as these parameters - public List/*!*/ Ins; - public List/*!*/ Outs; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(callee != null); - Contract.Invariant(Ins != null); - Contract.Invariant(Outs != null); - } - - //public Lattice.Element StateAfterCall; - - // The instantiation of type parameters that is determined during - // type checking - public TypeParamInstantiation TypeParameters = null; - - // TODO: convert to use generics - private object errorData; - public object ErrorData { - get { - return errorData; - } - set { - errorData = value; - } - } - public CallCmd(IToken tok, string callee, List ins, List outs) - : base(tok, null) { - Contract.Requires(outs != null); - Contract.Requires(ins != null); - Contract.Requires(callee != null); - Contract.Requires(tok != null); - this.callee = callee; - this.Ins = ins; - this.Outs = outs; - } - public CallCmd(IToken tok, string callee, List ins, List outs, QKeyValue kv) - : base(tok, kv) { - Contract.Requires(outs != null); - Contract.Requires(ins != null); - Contract.Requires(callee != null); - Contract.Requires(tok != null); - this.callee = callee; - this.Ins = ins; - this.Outs = outs; - } - - public CallCmd(IToken tok, string callee, List ins, List outs, QKeyValue kv, bool IsAsync) - : base(tok, kv) - { - Contract.Requires(outs != null); - Contract.Requires(ins != null); - Contract.Requires(callee != null); - Contract.Requires(tok != null); - this.callee = callee; - this.Ins = ins; - this.Outs = outs; - this.IsAsync = IsAsync; - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, ""); - if (IsFree) { - stream.Write("free "); - } - if (IsAsync) { - stream.Write("async "); - } - stream.Write("call "); - EmitAttributes(stream, Attributes); - string sep = ""; - if (Outs.Count > 0) { - foreach (Expr arg in Outs) { - stream.Write(sep); - sep = ", "; - if (arg == null) { - stream.Write("*"); - } else { - arg.Emit(stream); - } - } - stream.Write(" := "); - } - stream.Write(TokenTextWriter.SanitizeIdentifier(callee)); - stream.Write("("); - sep = ""; - foreach (Expr arg in Ins) { - stream.Write(sep); - sep = ", "; - if (arg == null) { - stream.Write("*"); - } else { - arg.Emit(stream); - } - } - stream.WriteLine(");"); - base.Emit(stream, level); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - if (Proc != null) { - // already resolved - return; - } - ResolveAttributes(Attributes, rc); - Proc = rc.LookUpProcedure(callee) as Procedure; - if (Proc == null) { - rc.Error(this, "call to undeclared procedure: {0}", callee); - } - foreach (Expr e in Ins) { - if (e != null) { - e.Resolve(rc); - } - } - HashSet actualOuts = new HashSet(); - foreach (IdentifierExpr ide in Outs) { - if (ide != null) { - ide.Resolve(rc); - if (ide.Decl != null) { - if (actualOuts.Contains(ide.Decl)) { - rc.Error(this, "left-hand side of call command contains variable twice: {0}", ide.Name); - } else { - actualOuts.Add(ide.Decl); - } - } - } - } - - if (Proc == null) - return; - - // first make sure that the right number of parameters is given - // (a similar check is in CheckArgumentTypes, but we are not - // able to call this method because it cannot cope with Ins/Outs - // that are null) - if (Ins.Count != Proc.InParams.Count) { - rc.Error(this.tok, - "wrong number of arguments in call to {0}: {1}", - callee, Ins.Count); - return; - } - if (Outs.Count != Proc.OutParams.Count) { - rc.Error(this.tok, - "wrong number of result variables in call to {0}: {1}", - callee, Outs.Count); - return; - } - if (IsAsync) { - if (Proc.OutParams.Count > 0) { - rc.Error(this.tok, "a procedure called asynchronously can have no output parameters"); - return; - } - } - - // Check that type parameters can be determined using the given - // actual i/o arguments. This is done already during resolution - // because CheckBoundVariableOccurrences needs a resolution - // context - List/*!*/ formalInTypes = new List(); - List/*!*/ formalOutTypes = new List(); - for (int i = 0; i < Ins.Count; ++i) - if (Ins[i] != null) - formalInTypes.Add(cce.NonNull(Proc.InParams[i]).TypedIdent.Type); - for (int i = 0; i < Outs.Count; ++i) - if (Outs[i] != null) - formalOutTypes.Add(cce.NonNull(Proc.OutParams[i]).TypedIdent.Type); - - // we need to bind the type parameters for this - // (this is expected by CheckBoundVariableOccurrences) - int previousTypeBinderState = rc.TypeBinderState; - try { - foreach (TypeVariable/*!*/ v in Proc.TypeParameters) { - Contract.Assert(v != null); - rc.AddTypeBinder(v); - } - Type.CheckBoundVariableOccurrences(Proc.TypeParameters, - formalInTypes, formalOutTypes, - this.tok, "types of given arguments", - rc); - } finally { - rc.TypeBinderState = previousTypeBinderState; - } - } - - public override void AddAssignedVariables(List vars) { - if (this.IsAsync) - return; - foreach (IdentifierExpr e in Outs) { - if (e != null) { - vars.Add(e.Decl); - } - } - Contract.Assume(this.Proc != null); - foreach (IdentifierExpr/*!*/ e in this.Proc.Modifies) { - Contract.Assert(e != null); - vars.Add(e.Decl); - } - if (AssignedAssumptionVariable != null) - { - vars.Add(AssignedAssumptionVariable); - } - } - - public override void Typecheck(TypecheckingContext tc) - { - //Contract.Requires(tc != null); - Contract.Assume(this.Proc != null); // we assume the CallCmd has been successfully resolved before calling this Typecheck method - - TypecheckAttributes(Attributes, tc); - - // typecheck in-parameters - foreach (Expr e in Ins) - if (e != null) - e.Typecheck(tc); - foreach (Expr e in Outs) - if (e != null) - e.Typecheck(tc); - this.CheckAssignments(tc); - - List/*!*/ formalInTypes = new List(); - List/*!*/ formalOutTypes = new List(); - List/*!*/ actualIns = new List(); - List/*!*/ actualOuts = new List(); - for (int i = 0; i < Ins.Count; ++i) - { - if (Ins[i] != null) - { - formalInTypes.Add(cce.NonNull(Proc.InParams[i]).TypedIdent.Type); - actualIns.Add(Ins[i]); - } - } - for (int i = 0; i < Outs.Count; ++i) - { - if (Outs[i] != null) - { - formalOutTypes.Add(cce.NonNull(Proc.OutParams[i]).TypedIdent.Type); - actualOuts.Add(Outs[i]); - } - } - - // match actuals with formals - List/*!*/ actualTypeParams; - Type.CheckArgumentTypes(Proc.TypeParameters, - out actualTypeParams, - formalInTypes, actualIns, - formalOutTypes, actualOuts, - this.tok, - "call to " + callee, - tc); - Contract.Assert(cce.NonNullElements(actualTypeParams)); - TypeParameters = SimpleTypeParamInstantiation.From(Proc.TypeParameters, - actualTypeParams); - - if (!CommandLineOptions.Clo.DoModSetAnalysis && IsAsync) - { - if (!tc.Yields) - { - tc.Error(this, "enclosing procedure of an async call must yield"); - } - if (!QKeyValue.FindBoolAttribute(Proc.Attributes, "yields")) - { - tc.Error(this, "target procedure of an async call must yield"); - } - } - } - - private IDictionary/*!*/ TypeParamSubstitution() { - Contract.Ensures(cce.NonNullDictionaryAndValues(Contract.Result>())); - Contract.Assume(TypeParameters != null); - IDictionary/*!*/ res = new Dictionary(); - foreach (TypeVariable/*!*/ v in TypeParameters.FormalTypeParams) { - Contract.Assert(v != null); - res.Add(v, TypeParameters[v]); - } - return res; - } - - protected override Cmd ComputeDesugaring() { - Contract.Ensures(Contract.Result() != null); - - int uniqueId = 0; - List newBlockBody = new List(); - Dictionary substMap = new Dictionary(); - Dictionary substMapOld = new Dictionary(); - Dictionary substMapBound = new Dictionary(); - List/*!*/ tempVars = new List(); - - // proc P(ins) returns (outs) - // requires Pre - // //modifies frame - // ensures Post - // - // call aouts := P(ains) - - // ins : formal in parameters of procedure - // frame : a list of global variables from the modifies clause - // outs : formal out parameters of procedure - // ains : actual in arguments passed to call - // aouts : actual variables assigned to from call - // cins : new variables created just for this call, one per ains - // cframe : new variables created just for this call, to keep track of OLD values - // couts : new variables created just for this call, one per aouts - // WildcardVars : new variables created just for this call, one per null in ains - - #region Create cins; each one is an incarnation of the corresponding in parameter - List/*!*/ cins = new List(); - List wildcardVars = new List(); - Contract.Assume(this.Proc != null); - for (int i = 0; i < this.Proc.InParams.Count; ++i) { - Variable/*!*/ param = cce.NonNull(this.Proc.InParams[i]); - bool isWildcard = this.Ins[i] == null; - - Type/*!*/ actualType; - if (isWildcard) - actualType = param.TypedIdent.Type.Substitute(TypeParamSubstitution()); - else - // during type checking, we have ensured that the type of the actual - // parameter Ins[i] is correct, so we can use it here - actualType = cce.NonNull(cce.NonNull(Ins[i]).Type); - - Variable cin = CreateTemporaryVariable(tempVars, param, actualType, - TempVarKind.Formal, ref uniqueId); - cins.Add(cin); - IdentifierExpr ie = new IdentifierExpr(cin.tok, cin); - substMap.Add(param, ie); - if (isWildcard) { - cin = CreateTemporaryVariable(tempVars, param, - actualType, TempVarKind.Bound, ref uniqueId); - wildcardVars.Add(cin); - ie = new IdentifierExpr(cin.tok, cin); - } - substMapBound.Add(param, ie); - } - #endregion - #region call aouts := P(ains) becomes: (open outlining one level to see) - #region cins := ains (or havoc cin when ain is null) - for (int i = 0, n = this.Ins.Count; i < n; i++) { - IdentifierExpr/*!*/ cin_exp = new IdentifierExpr(cce.NonNull(cins[i]).tok, cce.NonNull(cins[i])); - Contract.Assert(cin_exp != null); - if (this.Ins[i] != null) { - AssignCmd assign = Cmd.SimpleAssign(Token.NoToken, cin_exp, cce.NonNull(this.Ins[i])); - newBlockBody.Add(assign); - } else { - List/*!*/ ies = new List(); - ies.Add(cin_exp); - HavocCmd havoc = new HavocCmd(Token.NoToken, ies); - newBlockBody.Add(havoc); - } - } - #endregion - - #region assert (exists wildcardVars :: Pre[ins := cins]) - Substitution s = Substituter.SubstitutionFromHashtable(substMapBound); - bool hasWildcard = (wildcardVars.Count != 0); - Expr preConjunction = null; - for (int i = 0; i < this.Proc.Requires.Count; i++) { - Requires/*!*/ req = cce.NonNull(this.Proc.Requires[i]); - if (!req.Free && !IsFree) { - if (hasWildcard) { - Expr pre = Substituter.Apply(s, req.Condition); - if (preConjunction == null) { - preConjunction = pre; - } else { - preConjunction = Expr.And(preConjunction, pre); - } - } else { - Requires/*!*/ reqCopy = (Requires/*!*/)cce.NonNull(req.Clone()); - reqCopy.Condition = Substituter.Apply(s, req.Condition); - AssertCmd/*!*/ a = new AssertRequiresCmd(this, reqCopy); - Contract.Assert(a != null); - a.ErrorDataEnhanced = reqCopy.ErrorDataEnhanced; - newBlockBody.Add(a); - } - } - else if (CommandLineOptions.Clo.StratifiedInlining > 0) - { - // inject free requires as assume statements at the call site - AssumeCmd/*!*/ a = new AssumeCmd(req.tok, Substituter.Apply(s, req.Condition)); - Contract.Assert(a != null); - newBlockBody.Add(a); - } - } - if (hasWildcard) { - if (preConjunction == null) { - preConjunction = Expr.True; - } - Expr/*!*/ expr = new ExistsExpr(tok, wildcardVars, preConjunction); - Contract.Assert(expr != null); - AssertCmd/*!*/ a = new AssertCmd(tok, expr); - Contract.Assert(a != null); - a.ErrorDataEnhanced = AssertCmd.GenerateBoundVarMiningStrategy(expr); - newBlockBody.Add(a); - } - #endregion - - #region assume Pre[ins := cins] with formal paramters - if (hasWildcard) { - s = Substituter.SubstitutionFromHashtable(substMap); - for (int i = 0; i < this.Proc.Requires.Count; i++) { - Requires/*!*/ req = cce.NonNull(this.Proc.Requires[i]); - if (!req.Free) { - Requires/*!*/ reqCopy = (Requires/*!*/)cce.NonNull(req.Clone()); - reqCopy.Condition = Substituter.Apply(s, req.Condition); - AssumeCmd/*!*/ a = new AssumeCmd(tok, reqCopy.Condition); - Contract.Assert(a != null); - newBlockBody.Add(a); - } - } - } - #endregion - - #region cframe := frame (to hold onto frame values in case they are referred to in the postcondition) - List havocVarExprs = new List(); - - foreach (IdentifierExpr/*!*/ f in this.Proc.Modifies) { - Contract.Assert(f != null); - Contract.Assume(f.Decl != null); - Contract.Assert(f.Type != null); - Variable v = CreateTemporaryVariable(tempVars, f.Decl, f.Type, TempVarKind.Old, ref uniqueId); - IdentifierExpr v_exp = new IdentifierExpr(v.tok, v); - substMapOld.Add(f.Decl, v_exp); // this assumes no duplicates in this.Proc.Modifies - AssignCmd assign = Cmd.SimpleAssign(f.tok, v_exp, f); - newBlockBody.Add(assign); - - // fra - if (!havocVarExprs.Contains(f)) - havocVarExprs.Add(f); - } - #endregion - #region Create couts - List/*!*/ couts = new List(); - for (int i = 0; i < this.Proc.OutParams.Count; ++i) { - Variable/*!*/ param = cce.NonNull(this.Proc.OutParams[i]); - bool isWildcard = this.Outs[i] == null; - - Type/*!*/ actualType; - if (isWildcard) - actualType = param.TypedIdent.Type.Substitute(TypeParamSubstitution()); - else - // during type checking, we have ensured that the type of the actual - // out parameter Outs[i] is correct, so we can use it here - actualType = cce.NonNull(cce.NonNull(Outs[i]).Type); - - Variable cout = CreateTemporaryVariable(tempVars, param, actualType, - TempVarKind.Formal, ref uniqueId); - couts.Add(cout); - IdentifierExpr ie = new IdentifierExpr(cout.tok, cout); - substMap.Add(param, ie); - - if (!havocVarExprs.Contains(ie)) - havocVarExprs.Add(ie); - } - // add the where clauses, now that we have the entire substitution map - foreach (Variable/*!*/ param in this.Proc.OutParams) { - Contract.Assert(param != null); - Expr w = param.TypedIdent.WhereExpr; - if (w != null) { - IdentifierExpr ie = (IdentifierExpr/*!*/)cce.NonNull(substMap[param]); - Contract.Assert(ie.Decl != null); - ie.Decl.TypedIdent.WhereExpr = Substituter.Apply(Substituter.SubstitutionFromHashtable(substMap), w); - } - } - #endregion - - #region havoc frame, couts - // pass on this's token - HavocCmd hc = new HavocCmd(this.tok, havocVarExprs); - newBlockBody.Add(hc); - #endregion - - #region assume Post[ins, outs, old(frame) := cins, couts, cframe] - calleeSubstitution = Substituter.SubstitutionFromHashtable(substMap, true, Proc); - calleeSubstitutionOld = Substituter.SubstitutionFromHashtable(substMapOld, true, Proc); - foreach (Ensures/*!*/ e in this.Proc.Ensures) { - Contract.Assert(e != null); - Expr copy = Substituter.ApplyReplacingOldExprs(calleeSubstitution, calleeSubstitutionOld, e.Condition); - AssumeCmd assume = new AssumeCmd(this.tok, copy); - #region stratified inlining support - if (QKeyValue.FindBoolAttribute(e.Attributes, "si_fcall")) - { - assume.Attributes = Attributes; - } - if (QKeyValue.FindBoolAttribute(e.Attributes, "candidate")) - { - assume.Attributes = new QKeyValue(Token.NoToken, "candidate", new List(), assume.Attributes); - assume.Attributes.AddParam(this.callee); - } - #endregion - newBlockBody.Add(assume); - } - #endregion - - #region aouts := couts - for (int i = 0, n = this.Outs.Count; i < n; i++) { - if (this.Outs[i] != null) { - Variable/*!*/ param_i = cce.NonNull(this.Proc.OutParams[i]); - Expr/*!*/ cout_exp = new IdentifierExpr(cce.NonNull(couts[i]).tok, cce.NonNull(couts[i])); - Contract.Assert(cout_exp != null); - AssignCmd assign = Cmd.SimpleAssign(param_i.tok, cce.NonNull(this.Outs[i]), cout_exp); - newBlockBody.Add(assign); - } - } - #endregion - #endregion - - return new StateCmd(this.tok, tempVars, newBlockBody); - } - - class NameEqualityComparer : EqualityComparer - { - public override bool Equals(IdentifierExpr x, IdentifierExpr y) - { - return x.Name.Equals(y.Name); - } - - public override int GetHashCode(IdentifierExpr obj) - { - return obj.Name.GetHashCode(); - } - } - - NameEqualityComparer comparer = new NameEqualityComparer(); - - public Substitution calleeSubstitution; - public Substitution calleeSubstitutionOld; - - public IEnumerable UnmodifiedBefore(Procedure oldProcedure) - { - Contract.Requires(oldProcedure != null); - - return Proc.Modifies.Except(oldProcedure.Modifies, comparer).Select(e => new IdentifierExpr(Token.NoToken, e.Decl)); - } - - public IEnumerable ModifiedBefore(Procedure oldProcedure) - { - Contract.Requires(oldProcedure != null); - - return oldProcedure.Modifies.Except(Proc.Modifies, comparer).Select(e => new IdentifierExpr(Token.NoToken, e.Decl)); - } - - public Expr Postcondition(Procedure procedure, List modifies, Dictionary oldSubst, Program program, Func extract) - { - Contract.Requires(calleeSubstitution != null && calleeSubstitutionOld != null && modifies != null && oldSubst != null && program != null && extract != null); - - Substitution substOldCombined = v => { Expr s; if (oldSubst.TryGetValue(v, out s)) { return s; } return calleeSubstitutionOld(v); }; - - var clauses = procedure.Ensures.Select(e => Substituter.FunctionCallReresolvingApplyReplacingOldExprs(calleeSubstitution, substOldCombined, e.Condition, program)).Concat(modifies); - // TODO(wuestholz): Try extracting a function for each clause: - // return Conjunction(clauses.Select(c => extract(c))); - var conj = Conjunction(clauses); - return conj != null ? extract(conj) : conj; - } - - public Expr CheckedPrecondition(Procedure procedure, Program program, Func extract) - { - Contract.Requires(calleeSubstitution != null && calleeSubstitutionOld != null && program != null && extract != null); - - var clauses = procedure.Requires.Where(r => !r.Free).Select(r => Substituter.FunctionCallReresolvingApplyReplacingOldExprs(calleeSubstitution, calleeSubstitutionOld, r.Condition, program)); - // TODO(wuestholz): Try extracting a function for each clause: - // return Conjunction(clauses.Select(c => extract(c))); - var conj = Conjunction(clauses); - return conj != null ? extract(conj) : conj; - } - - private static Expr Conjunction(IEnumerable conjuncts) - { - // TODO(wuestholz): Maybe we should use 'LiteralExpr.BinaryTreeAnd' instead. - Expr result = null; - foreach (var c in conjuncts) - { - if (result != null) - { - result = LiteralExpr.And(result, c); - result.Type = Type.Bool; - } - else - { - result = c; - result.Type = Type.Bool; - } - } - return result; - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitCallCmd(this); - } - } - - public abstract class PredicateCmd : Cmd { - public QKeyValue Attributes; - public /*readonly--except in StandardVisitor*/ Expr/*!*/ Expr; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Expr != null); - } - - public PredicateCmd(IToken/*!*/ tok, Expr/*!*/ expr) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - Expr = expr; - } - public PredicateCmd(IToken/*!*/ tok, Expr/*!*/ expr, QKeyValue kv) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - Expr = expr; - Attributes = kv; - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - Expr.Resolve(rc); - } - public override void AddAssignedVariables(List vars) { - //Contract.Requires(vars != null); - } - } - - public abstract class MiningStrategy { - // abstract class to bind all MiningStrategys, i.e., all types of enhanced error data - // types together - } - - public class ListOfMiningStrategies : MiningStrategy { - - private List/*!*/ _msList; - - public List/*!*/ msList - { - get - { - Contract.Ensures(Contract.Result>() != null); - return this._msList; - } - set - { - Contract.Requires(value != null); - this._msList = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._msList != null); - } - - public ListOfMiningStrategies(List l) { - Contract.Requires(l != null); - this._msList = l; - } - } - - public class EEDTemplate : MiningStrategy { - private string/*!*/ _reason; - public string/*!*/ reason - { - get - { - Contract.Ensures(Contract.Result() != null); - return this._reason; - } - set - { - Contract.Requires(value != null); - this._reason = value; - } - } - - private List/*!*/ exprList; - public IEnumerable Expressions - { - get - { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return this.exprList.AsReadOnly(); - } - set - { - Contract.Requires(cce.NonNullElements(value)); - this.exprList = new List(value); - } - } - - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._reason != null); - Contract.Invariant(cce.NonNullElements(this.exprList)); - } - - public EEDTemplate(string reason, List/*!*/ exprList) { - Contract.Requires(reason != null); - Contract.Requires(cce.NonNullElements(exprList)); - this._reason = reason; - this.exprList = exprList; - } - } - - public class AssertCmd : PredicateCmd, IPotentialErrorNode - { - public Expr OrigExpr; - public Dictionary IncarnationMap; - - Expr verifiedUnder; - public Expr VerifiedUnder - { - get - { - if (verifiedUnder != null) - { - return verifiedUnder; - } - verifiedUnder = QKeyValue.FindExprAttribute(Attributes, "verified_under"); - return verifiedUnder; - } - } - - public void MarkAsVerifiedUnder(Expr expr) - { - Attributes = new QKeyValue(tok, "verified_under", new List { expr }, Attributes); - verifiedUnder = expr; - } - - // TODO: convert to use generics - private object errorData; - public object ErrorData { - get { - return errorData; - } - set { - errorData = value; - } - } - - public string ErrorMessage { - get { - return QKeyValue.FindStringAttribute(Attributes, "msg"); - } - } - - private MiningStrategy errorDataEnhanced; - public MiningStrategy ErrorDataEnhanced { - get { - return errorDataEnhanced; - } - set { - errorDataEnhanced = value; - } - } - - public AssertCmd(IToken/*!*/ tok, Expr/*!*/ expr) - : base(tok, expr) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - errorDataEnhanced = GenerateBoundVarMiningStrategy(expr); - } - - public AssertCmd(IToken/*!*/ tok, Expr/*!*/ expr, QKeyValue kv) - : base(tok, expr, kv) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - errorDataEnhanced = GenerateBoundVarMiningStrategy(expr); - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, "assert "); - EmitAttributes(stream, Attributes); - this.Expr.Emit(stream); - stream.WriteLine(";"); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - ResolveAttributes(Attributes, rc); - base.Resolve(rc); - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - TypecheckAttributes(Attributes, tc); - Expr.Typecheck(tc); - Contract.Assert(Expr.Type != null); // follows from Expr.Typecheck postcondition - if (!Expr.Type.Unify(Type.Bool)) { - tc.Error(this, "an asserted expression must be of type bool (got: {0})", Expr.Type); - } - } - - public static MiningStrategy GenerateBoundVarMiningStrategy(Expr expr) { - Contract.Requires(expr != null); - List l = new List(); - if (expr != null) { - l = GenerateBoundVarListForMining(expr, l); - } - return new ListOfMiningStrategies(l); - } - - public static List/*!*/ GenerateBoundVarListForMining(Expr expr, List l) { - Contract.Requires(l != null); - Contract.Requires(expr != null); - Contract.Ensures(Contract.Result>() != null); - - // go through the origExpr and identify all bound variables in the AST. - if (expr is LiteralExpr || expr is IdentifierExpr) { - //end recursion - } else if (expr is NAryExpr) { - NAryExpr e = (NAryExpr)expr; - foreach (Expr/*!*/ arg in e.Args) { - Contract.Assert(arg != null); - l = GenerateBoundVarListForMining(arg, l); - } - } else if (expr is OldExpr) { - OldExpr e = (OldExpr)expr; - l = GenerateBoundVarListForMining(e.Expr, l); - } else if (expr is QuantifierExpr) { - QuantifierExpr qe = (QuantifierExpr)expr; - List vs = qe.Dummies; - foreach (Variable/*!*/ x in vs) { - Contract.Assert(x != null); - string name = x.Name; - if (name.StartsWith("^")) { - name = name.Substring(1); - List exprList = new List(); - exprList.Add(new IdentifierExpr(Token.NoToken, x.ToString(), x.TypedIdent.Type)); - MiningStrategy eed = new EEDTemplate("The bound variable " + name + " has the value {0}.", exprList); - l.Add(eed); - } - } - l = GenerateBoundVarListForMining(qe.Body, l); - } - return l; - } - - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitAssertCmd(this); - } - } - - // An AssertCmd that is a loop invariant check before the loop iteration starts - public class LoopInitAssertCmd : AssertCmd { - public LoopInitAssertCmd(IToken/*!*/ tok, Expr/*!*/ expr) - : base(tok, expr) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - } - } - - // An AssertCmd that is a loop invariant check to maintain the invariant after iteration - public class LoopInvMaintainedAssertCmd : AssertCmd { - public LoopInvMaintainedAssertCmd(IToken/*!*/ tok, Expr/*!*/ expr) - : base(tok, expr) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - } - } - - /// - /// An AssertCmd that is introduced in translation from the requires on a call. - /// - public class AssertRequiresCmd : AssertCmd { - public CallCmd/*!*/ Call; - public Requires/*!*/ Requires; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Call != null); - Contract.Invariant(Requires != null); - } - - - public AssertRequiresCmd(CallCmd/*!*/ call, Requires/*!*/ requires) - : base(call.tok, requires.Condition) { - Contract.Requires(call != null); - Contract.Requires(requires != null); - this.Call = call; - this.Requires = requires; - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitAssertRequiresCmd(this); - } - } - - /// - /// An AssertCmd that is introduced in translation from an ensures - /// declaration. - /// - public class AssertEnsuresCmd : AssertCmd { - public Ensures/*!*/ Ensures; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Ensures != null); - } - - public AssertEnsuresCmd(Ensures/*!*/ ens) - : base(ens.tok, ens.Condition) { - Contract.Requires(ens != null); - this.Ensures = ens; - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitAssertEnsuresCmd(this); - } - } - - public class AssumeCmd : PredicateCmd { - public AssumeCmd(IToken/*!*/ tok, Expr/*!*/ expr) - : base(tok, expr) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - } - public AssumeCmd(IToken/*!*/ tok, Expr/*!*/ expr, QKeyValue kv) - : base(tok, expr, kv) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - } - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - - if (stream.UseForComputingChecksums && QKeyValue.FindBoolAttribute(Attributes, "precondition_previous_snapshot")) { return; } - - stream.Write(this, level, "assume "); - EmitAttributes(stream, Attributes); - this.Expr.Emit(stream); - stream.WriteLine(";"); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - Expr.Typecheck(tc); - Contract.Assert(Expr.Type != null); // follows from Expr.Typecheck postcondition - if (!Expr.Type.Unify(Type.Bool)) { - tc.Error(this, "an assumed expression must be of type bool (got: {0})", Expr.Type); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitAssumeCmd(this); - } - } - - public class ReturnExprCmd : ReturnCmd { - public Expr/*!*/ Expr; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Expr != null); - } - - public ReturnExprCmd(IToken/*!*/ tok, Expr/*!*/ expr) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - Expr = expr; - } - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, "return "); - this.Expr.Emit(stream); - stream.WriteLine(";"); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - Expr.Typecheck(tc); - Contract.Assert(Expr.Type != null); // follows from Expr.Typecheck postcondition - if (!Expr.Type.Unify(Type.Bool)) { - tc.Error(this, "a return expression must be of type bool (got: {0})", Expr.Type); - } - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - Expr.Resolve(rc); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitReturnExprCmd(this); - } - } - - public class HavocCmd : Cmd { - private List/*!*/ _vars; - - public List/*!*/ Vars { - get { - Contract.Ensures(Contract.Result>() != null); - return this._vars; - } - set { - Contract.Requires(value != null); - this._vars = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._vars != null); - } - - public HavocCmd(IToken/*!*/ tok, List/*!*/ vars) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(vars != null); - this._vars = vars; - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, "havoc "); - Vars.Emit(stream, true); - stream.WriteLine(";"); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - foreach (IdentifierExpr/*!*/ ide in Vars) { - Contract.Assert(ide != null); - ide.Resolve(rc); - } - } - public override void AddAssignedVariables(List vars) { - //Contract.Requires(vars != null); - foreach (IdentifierExpr/*!*/ e in this.Vars) { - Contract.Assert(e != null); - vars.Add(e.Decl); - } - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - foreach (IdentifierExpr ie in Vars) - { - ie.Typecheck(tc); - } - this.CheckAssignments(tc); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitHavocCmd(this); - } - } - - //--------------------------------------------------------------------- - // Transfer commands - [ContractClass(typeof(TransferCmdContracts))] - public abstract class TransferCmd : Absy { - internal TransferCmd(IToken/*!*/ tok) - : base(tok) { - Contract.Requires(tok != null); - } - public abstract void Emit(TokenTextWriter/*!*/ stream, int level); - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - // nothing to typecheck - } - - public override string ToString() - { - Contract.Ensures(Contract.Result() != null); - System.IO.StringWriter buffer = new System.IO.StringWriter(); - using (TokenTextWriter stream = new TokenTextWriter("", buffer, /*setTokens=*/ false , /*pretty=*/ false)) { - this.Emit(stream, 0); - } - return buffer.ToString(); - } - } - [ContractClassFor(typeof(TransferCmd))] - public abstract class TransferCmdContracts : TransferCmd { - public TransferCmdContracts() :base(null){ - - } - public override void Emit(TokenTextWriter stream, int level) { - Contract.Requires(stream != null); - throw new NotImplementedException(); - } - } - - public class ReturnCmd : TransferCmd { - public ReturnCmd(IToken/*!*/ tok) - : base(tok) { - Contract.Requires(tok != null); - } - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.WriteLine(this, level, "return;"); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - // nothing to resolve - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitReturnCmd(this); - } - } - - public class GotoCmd : TransferCmd { - [Rep] - public List labelNames; - [Rep] - public List labelTargets; - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(labelNames == null || labelTargets == null || labelNames.Count == labelTargets.Count); - } - - [NotDelayed] - public GotoCmd(IToken/*!*/ tok, List/*!*/ labelSeq) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(labelSeq != null); - this.labelNames = labelSeq; - } - public GotoCmd(IToken/*!*/ tok, List/*!*/ labelSeq, List/*!*/ blockSeq) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(labelSeq != null); - Contract.Requires(blockSeq != null); - Debug.Assert(labelSeq.Count == blockSeq.Count); - for (int i = 0; i < labelSeq.Count; i++) { - Debug.Assert(Equals(labelSeq[i], cce.NonNull(blockSeq[i]).Label)); - } - - this.labelNames = labelSeq; - this.labelTargets = blockSeq; - } - public GotoCmd(IToken/*!*/ tok, List/*!*/ blockSeq) - : base(tok) { //requires (blockSeq[i] != null ==> blockSeq[i].Label != null); - Contract.Requires(tok != null); - Contract.Requires(blockSeq != null); - List labelSeq = new List(); - for (int i = 0; i < blockSeq.Count; i++) - labelSeq.Add(cce.NonNull(blockSeq[i]).Label); - this.labelNames = labelSeq; - this.labelTargets = blockSeq; - } - public void AddTarget(Block b) { - Contract.Requires(b != null); - Contract.Requires(b.Label != null); - Contract.Requires(this.labelTargets != null); - Contract.Requires(this.labelNames != null); - this.labelTargets.Add(b); - this.labelNames.Add(b.Label); - } - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - Contract.Assume(this.labelNames != null); - stream.Write(this, level, "goto "); - if (CommandLineOptions.Clo.PrintWithUniqueASTIds) { - if (labelTargets == null) { - string sep = ""; - foreach (string name in labelNames) { - stream.Write("{0}{1}^^{2}", sep, "NoDecl", name); - sep = ", "; - } - } else { - string sep = ""; - foreach (Block/*!*/ b in labelTargets) { - Contract.Assert(b != null); - stream.Write("{0}h{1}^^{2}", sep, b.GetHashCode(), b.Label); - sep = ", "; - } - } - } else { - labelNames.Emit(stream); - } - stream.WriteLine(";"); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - Contract.Ensures(labelTargets != null); - if (labelTargets != null) { - // already resolved - return; - } - Contract.Assume(this.labelNames != null); - labelTargets = new List(); - foreach (string/*!*/ lbl in labelNames) { - Contract.Assert(lbl != null); - Block b = rc.LookUpBlock(lbl); - if (b == null) { - rc.Error(this, "goto to unknown block: {0}", lbl); - } else { - labelTargets.Add(b); - } - } - Debug.Assert(rc.ErrorCount > 0 || labelTargets.Count == labelNames.Count); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitGotoCmd(this); - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- +// BoogiePL - Absy.cs +//--------------------------------------------------------------------------------------------- + +namespace Microsoft.Boogie { + using System; + using System.Collections; + using System.Diagnostics; + using System.Collections.Generic; + using System.Linq; + using Microsoft.Boogie.AbstractInterpretation; + using System.Diagnostics.Contracts; + using Set = GSet; + + + //--------------------------------------------------------------------- + // BigBlock + public class BigBlock { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(tok != null); + Contract.Invariant(Anonymous || this.labelName != null); + Contract.Invariant(this._ec == null || this._tc == null); + Contract.Invariant(this._simpleCmds != null); + } + + public readonly IToken/*!*/ tok; + + public readonly bool Anonymous; + + private string labelName; + + public string LabelName + { + get + { + Contract.Ensures(Anonymous || Contract.Result() != null); + return this.labelName; + } + set + { + Contract.Requires(Anonymous || value != null); + this.labelName = value; + } + } + + [Rep] + private List/*!*/ _simpleCmds; + + public List/*!*/ simpleCmds + { + get + { + Contract.Ensures(Contract.Result>() != null); + return this._simpleCmds; + } + set + { + Contract.Requires(value != null); + this._simpleCmds = value; + } + } + + private StructuredCmd _ec; + + public StructuredCmd ec + { + get + { + return this._ec; + } + set + { + Contract.Requires(value == null || this.tc == null); + this._ec = value; + } + } + + private TransferCmd _tc; + + public TransferCmd tc + { + get + { + return this._tc; + } + set + { + Contract.Requires(value == null || this.ec == null); + this._tc = value; + } + } + + public BigBlock successorBigBlock; // semantic successor (may be a back-edge, pointing back to enclosing while statement); null if successor is end of procedure body (or if field has not yet been initialized) + + public BigBlock(IToken tok, string labelName, [Captured] List simpleCmds, StructuredCmd ec, TransferCmd tc) { + Contract.Requires(simpleCmds != null); + Contract.Requires(tok != null); + Contract.Requires(ec == null || tc == null); + this.tok = tok; + this.Anonymous = labelName == null; + this.labelName = labelName; + this._simpleCmds = simpleCmds; + this._ec = ec; + this._tc = tc; + } + + public void Emit(TokenTextWriter stream, int level) { + Contract.Requires(stream != null); + if (!Anonymous) { + stream.WriteLine(level, "{0}:", + CommandLineOptions.Clo.PrintWithUniqueASTIds ? String.Format("h{0}^^{1}", this.GetHashCode(), this.LabelName) : this.LabelName); + } + + foreach (Cmd/*!*/ c in this.simpleCmds) { + Contract.Assert(c != null); + c.Emit(stream, level + 1); + } + + if (this.ec != null) { + this.ec.Emit(stream, level + 1); + } else if (this.tc != null) { + this.tc.Emit(stream, level + 1); + } + } + } + + public class StmtList { + [Rep] + private readonly List/*!*/ bigBlocks; + + public IList/*!*/ BigBlocks + { + get + { + Contract.Ensures(Contract.Result>() != null); + Contract.Ensures(Contract.Result>().IsReadOnly); + return this.bigBlocks.AsReadOnly(); + } + } + + public List PrefixCommands; + public readonly IToken/*!*/ EndCurly; + public StmtList ParentContext; + public BigBlock ParentBigBlock; + + private readonly HashSet/*!*/ labels = new HashSet(); + + public void AddLabel(string label) + { + labels.Add(label); + } + + public IEnumerable/*!*/ Labels + { + get + { + Contract.Ensures(cce.NonNullElements(Contract.Result/*!*/>())); + return this.labels.AsEnumerable(); + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(EndCurly != null); + Contract.Invariant(cce.NonNullElements(this.bigBlocks)); + Contract.Invariant(cce.NonNullElements(this.labels)); + } + + public StmtList(IList/*!*/ bigblocks, IToken endCurly) { + Contract.Requires(endCurly != null); + Contract.Requires(cce.NonNullElements(bigblocks)); + Contract.Requires(bigblocks.Count > 0); + this.bigBlocks = new List(bigblocks); + this.EndCurly = endCurly; + } + + // prints the list of statements, not the surrounding curly braces + public void Emit(TokenTextWriter stream, int level) { + Contract.Requires(stream != null); + bool needSeperator = false; + foreach (BigBlock b in BigBlocks) { + Contract.Assert(b != null); + Contract.Assume(cce.IsPeerConsistent(b)); + if (needSeperator) { + stream.WriteLine(); + } + b.Emit(stream, level); + needSeperator = true; + } + } + + /// + /// Tries to insert the commands "prefixCmds" at the beginning of the first block + /// of the StmtList, and returns "true" iff it succeeded. + /// In the event of success, the "suggestedLabel" returns as the name of the + /// block inside StmtList where "prefixCmds" were inserted. This name may be the + /// same as the one passed in, in case this StmtList has no preference as to what + /// to call its first block. In the event of failure, "suggestedLabel" is returned + /// as its input value. + /// Note, to be conservative (that is, ignoring the possible optimization that this + /// method enables), this method can do nothing and return false. + /// + public bool PrefixFirstBlock([Captured] List prefixCmds, ref string suggestedLabel) { + Contract.Requires(suggestedLabel != null); + Contract.Requires(prefixCmds != null); + Contract.Ensures(Contract.Result() || cce.Owner.None(prefixCmds)); // "prefixCmds" is captured only on success + Contract.Assume(PrefixCommands == null); // prefix has not been used + + BigBlock bb0 = BigBlocks[0]; + if (prefixCmds.Count == 0) { + // This is always a success, since there is nothing to insert. Now, decide + // which name to use for the first block. + if (bb0.Anonymous) { + bb0.LabelName = suggestedLabel; + } else { + Contract.Assert(bb0.LabelName != null); + suggestedLabel = bb0.LabelName; + } + return true; + + } else { + // There really is something to insert. We can do this inline only if the first + // block is anonymous (which implies there is no branch to it from within the block). + if (bb0.Anonymous) { + PrefixCommands = prefixCmds; + bb0.LabelName = suggestedLabel; + return true; + } else { + return false; + } + } + } + } + + /// + /// The AST for Boogie structured commands was designed to support backward compatibility with + /// the Boogie unstructured commands. This has made the structured commands hard to construct. + /// The StmtListBuilder class makes it easier to build structured commands. + /// + public class StmtListBuilder { + List/*!*/ bigBlocks = new List(); + string label; + List simpleCmds; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cce.NonNullElements(bigBlocks)); + } + + void Dump(StructuredCmd scmd, TransferCmd tcmd) { + Contract.Requires(scmd == null || tcmd == null); + Contract.Ensures(label == null && simpleCmds == null); + if (label == null && simpleCmds == null && scmd == null && tcmd == null) { + // nothing to do + } else { + if (simpleCmds == null) { + simpleCmds = new List(); + } + bigBlocks.Add(new BigBlock(Token.NoToken, label, simpleCmds, scmd, tcmd)); + label = null; + simpleCmds = null; + } + } + + /// + /// Collects the StmtList built so far and returns it. The StmtListBuilder should no longer + /// be used once this method has been invoked. + /// + public StmtList Collect(IToken endCurlyBrace) { + Contract.Requires(endCurlyBrace != null); + Contract.Ensures(Contract.Result() != null); + Dump(null, null); + if (bigBlocks.Count == 0) { + simpleCmds = new List(); // the StmtList constructor doesn't like an empty list of BigBlock's + Dump(null, null); + } + return new StmtList(bigBlocks, endCurlyBrace); + } + + public void Add(Cmd cmd) { + Contract.Requires(cmd != null); + if (simpleCmds == null) { + simpleCmds = new List(); + } + simpleCmds.Add(cmd); + } + + public void Add(StructuredCmd scmd) { + Contract.Requires(scmd != null); + Dump(scmd, null); + } + + public void Add(TransferCmd tcmd) { + Contract.Requires(tcmd != null); + Dump(null, tcmd); + } + + public void AddLabelCmd(string label) { + Contract.Requires(label != null); + Dump(null, null); + this.label = label; + } + + public void AddLocalVariable(string name) { + Contract.Requires(name != null); + // TODO + } + } + + class BigBlocksResolutionContext { + StmtList/*!*/ stmtList; + [Peer] + List blocks; + string/*!*/ prefix = "anon"; + int anon = 0; + int FreshAnon() + { + return anon++; + } + HashSet allLabels = new HashSet(); + Errors/*!*/ errorHandler; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(stmtList != null); + Contract.Invariant(cce.NonNullElements(blocks, true)); + Contract.Invariant(prefix != null); + Contract.Invariant(cce.NonNullElements(allLabels, true)); + Contract.Invariant(errorHandler != null); + } + + private void ComputeAllLabels(StmtList stmts) { + if (stmts == null) return; + foreach (BigBlock bb in stmts.BigBlocks) { + if (bb.LabelName != null) { + allLabels.Add(bb.LabelName); + } + ComputeAllLabels(bb.ec); + } + } + + private void ComputeAllLabels(StructuredCmd cmd) { + if (cmd == null) return; + if (cmd is IfCmd) { + IfCmd ifCmd = (IfCmd)cmd; + ComputeAllLabels(ifCmd.thn); + ComputeAllLabels(ifCmd.elseIf); + ComputeAllLabels(ifCmd.elseBlock); + } + else if (cmd is WhileCmd) { + WhileCmd whileCmd = (WhileCmd)cmd; + ComputeAllLabels(whileCmd.Body); + } + } + + public BigBlocksResolutionContext(StmtList stmtList, Errors errorHandler) { + Contract.Requires(errorHandler != null); + Contract.Requires(stmtList != null); + this.stmtList = stmtList; + this.errorHandler = errorHandler; + ComputeAllLabels(stmtList); + } + + public List/*!*/ Blocks { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + if (blocks == null) { + blocks = new List(); + + int startErrorCount = this.errorHandler.count; + // Check that all goto statements go to a label in allLabels, and no break statement to a non-enclosing loop. + // Also, determine a good value for "prefix". + CheckLegalLabels(stmtList, null, null); + + // fill in names of anonymous blocks + NameAnonymousBlocks(stmtList); + + // determine successor blocks + RecordSuccessors(stmtList, null); + + if (this.errorHandler.count == startErrorCount) { + // generate blocks from the big blocks + CreateBlocks(stmtList, null); + } + } + return blocks; + } + } + + void CheckLegalLabels(StmtList stmtList, StmtList parentContext, BigBlock parentBigBlock) { + Contract.Requires(stmtList != null); + Contract.Requires((parentContext == null) == (parentBigBlock == null)); + Contract.Requires(stmtList.ParentContext == null); // it hasn't been set yet + //modifies stmtList.*; + Contract.Ensures(stmtList.ParentContext == parentContext); + stmtList.ParentContext = parentContext; + stmtList.ParentBigBlock = parentBigBlock; + + // record the labels declared in this StmtList + foreach (BigBlock b in stmtList.BigBlocks) { + if (b.LabelName != null) { + string n = b.LabelName; + if (n.StartsWith(prefix)) { + if (prefix.Length < n.Length && n[prefix.Length] == '0') { + prefix += "1"; + } else { + prefix += "0"; + } + } + stmtList.AddLabel(b.LabelName); + } + } + + // check that labels in this and nested StmtList's are legal + foreach (BigBlock b in stmtList.BigBlocks) { + // goto's must reference blocks in enclosing blocks + if (b.tc is GotoCmd) { + GotoCmd g = (GotoCmd)b.tc; + foreach (string/*!*/ lbl in cce.NonNull(g.labelNames)) { + Contract.Assert(lbl != null); + /* + bool found = false; + for (StmtList sl = stmtList; sl != null; sl = sl.ParentContext) { + if (sl.Labels.Contains(lbl)) { + found = true; + break; + } + } + if (!found) { + this.errorHandler.SemErr(g.tok, "Error: goto label '" + lbl + "' is undefined or out of reach"); + } + */ + if (!allLabels.Contains(lbl)) { + this.errorHandler.SemErr(g.tok, "Error: goto label '" + lbl + "' is undefined"); + } + } + } + + // break labels must refer to an enclosing while statement + else if (b.ec is BreakCmd) { + BreakCmd bcmd = (BreakCmd)b.ec; + Contract.Assert(bcmd.BreakEnclosure == null); // it hasn't been initialized yet + bool found = false; + for (StmtList sl = stmtList; sl.ParentBigBlock != null; sl = sl.ParentContext) { + cce.LoopInvariant(sl != null); + BigBlock bb = sl.ParentBigBlock; + + if (bcmd.Label == null) { + // a label-less break statement breaks out of the innermost enclosing while statement + if (bb.ec is WhileCmd) { + bcmd.BreakEnclosure = bb; + found = true; + break; + } + } else if (bcmd.Label == bb.LabelName) { + // a break statement with a label can break out of both if statements and while statements + if (bb.simpleCmds.Count == 0) { + // this is a good target: the label refers to the if/while statement + bcmd.BreakEnclosure = bb; + } else { + // the label of bb refers to the first statement of bb, which in which case is a simple statement, not an if/while statement + this.errorHandler.SemErr(bcmd.tok, "Error: break label '" + bcmd.Label + "' must designate an enclosing statement"); + } + found = true; // don't look any further, since we've found a matching label + break; + } + } + if (!found) { + if (bcmd.Label == null) { + this.errorHandler.SemErr(bcmd.tok, "Error: break statement is not inside a loop"); + } else { + this.errorHandler.SemErr(bcmd.tok, "Error: break label '" + bcmd.Label + "' must designate an enclosing statement"); + } + } + } + + // recurse + else if (b.ec is WhileCmd) { + WhileCmd wcmd = (WhileCmd)b.ec; + CheckLegalLabels(wcmd.Body, stmtList, b); + } else { + for (IfCmd ifcmd = b.ec as IfCmd; ifcmd != null; ifcmd = ifcmd.elseIf) { + CheckLegalLabels(ifcmd.thn, stmtList, b); + if (ifcmd.elseBlock != null) { + CheckLegalLabels(ifcmd.elseBlock, stmtList, b); + } + } + } + } + } + + void NameAnonymousBlocks(StmtList stmtList) { + Contract.Requires(stmtList != null); + foreach (BigBlock b in stmtList.BigBlocks) { + if (b.LabelName == null) { + b.LabelName = prefix + FreshAnon(); + } + if (b.ec is WhileCmd) { + WhileCmd wcmd = (WhileCmd)b.ec; + NameAnonymousBlocks(wcmd.Body); + } else { + for (IfCmd ifcmd = b.ec as IfCmd; ifcmd != null; ifcmd = ifcmd.elseIf) { + NameAnonymousBlocks(ifcmd.thn); + if (ifcmd.elseBlock != null) { + NameAnonymousBlocks(ifcmd.elseBlock); + } + } + } + } + } + + void RecordSuccessors(StmtList stmtList, BigBlock successor) { + Contract.Requires(stmtList != null); + for (int i = stmtList.BigBlocks.Count; 0 <= --i; ) { + BigBlock big = stmtList.BigBlocks[i]; + big.successorBigBlock = successor; + + if (big.ec is WhileCmd) { + WhileCmd wcmd = (WhileCmd)big.ec; + RecordSuccessors(wcmd.Body, big); + } else { + for (IfCmd ifcmd = big.ec as IfCmd; ifcmd != null; ifcmd = ifcmd.elseIf) { + RecordSuccessors(ifcmd.thn, successor); + if (ifcmd.elseBlock != null) { + RecordSuccessors(ifcmd.elseBlock, successor); + } + } + } + + successor = big; + } + } + + // If the enclosing context is a loop, then "runOffTheEndLabel" is the loop head label; + // otherwise, it is null. + void CreateBlocks(StmtList stmtList, string runOffTheEndLabel) { + Contract.Requires(stmtList != null); + Contract.Requires(blocks != null); + List cmdPrefixToApply = stmtList.PrefixCommands; + + int n = stmtList.BigBlocks.Count; + foreach (BigBlock b in stmtList.BigBlocks) { + n--; + Contract.Assert(b.LabelName != null); + List theSimpleCmds; + if (cmdPrefixToApply == null) { + theSimpleCmds = b.simpleCmds; + } else { + theSimpleCmds = new List(); + theSimpleCmds.AddRange(cmdPrefixToApply); + theSimpleCmds.AddRange(b.simpleCmds); + cmdPrefixToApply = null; // now, we've used 'em up + } + + if (b.tc != null) { + // this BigBlock has the very same components as a Block + Contract.Assert(b.ec == null); + Block block = new Block(b.tok, b.LabelName, theSimpleCmds, b.tc); + blocks.Add(block); + + } else if (b.ec == null) { + TransferCmd trCmd; + if (n == 0 && runOffTheEndLabel != null) { + // goto the given label instead of the textual successor block + trCmd = new GotoCmd(stmtList.EndCurly, new List { runOffTheEndLabel }); + } else { + trCmd = GotoSuccessor(stmtList.EndCurly, b); + } + Block block = new Block(b.tok, b.LabelName, theSimpleCmds, trCmd); + blocks.Add(block); + + } else if (b.ec is BreakCmd) { + BreakCmd bcmd = (BreakCmd)b.ec; + Contract.Assert(bcmd.BreakEnclosure != null); + Block block = new Block(b.tok, b.LabelName, theSimpleCmds, GotoSuccessor(b.ec.tok, bcmd.BreakEnclosure)); + blocks.Add(block); + + } else if (b.ec is WhileCmd) { + WhileCmd wcmd = (WhileCmd)b.ec; + var a = FreshAnon(); + string loopHeadLabel = prefix + a + "_LoopHead"; + string/*!*/ loopBodyLabel = prefix + a + "_LoopBody"; + string loopDoneLabel = prefix + a + "_LoopDone"; + + List ssBody = new List(); + List ssDone = new List(); + if (wcmd.Guard != null) { + var ac = new AssumeCmd(wcmd.tok, wcmd.Guard); + ac.Attributes = new QKeyValue(wcmd.tok, "partition", new List(), null); + ssBody.Add(ac); + + ac = new AssumeCmd(wcmd.tok, Expr.Not(wcmd.Guard)); + ac.Attributes = new QKeyValue(wcmd.tok, "partition", new List(), null); + ssDone.Add(ac); + } + + // Try to squeeze in ssBody into the first block of wcmd.Body + bool bodyGuardTakenCareOf = wcmd.Body.PrefixFirstBlock(ssBody, ref loopBodyLabel); + + // ... goto LoopHead; + Block block = new Block(b.tok, b.LabelName, theSimpleCmds, new GotoCmd(wcmd.tok, new List { loopHeadLabel })); + blocks.Add(block); + + // LoopHead: assert/assume loop_invariant; goto LoopDone, LoopBody; + List ssHead = new List(); + foreach (PredicateCmd inv in wcmd.Invariants) { + ssHead.Add(inv); + } + block = new Block(wcmd.tok, loopHeadLabel, ssHead, new GotoCmd(wcmd.tok, new List { loopDoneLabel, loopBodyLabel })); + blocks.Add(block); + + if (!bodyGuardTakenCareOf) { + // LoopBody: assume guard; goto firstLoopBlock; + block = new Block(wcmd.tok, loopBodyLabel, ssBody, new GotoCmd(wcmd.tok, new List { wcmd.Body.BigBlocks[0].LabelName })); + blocks.Add(block); + } + + // recurse to create the blocks for the loop body + CreateBlocks(wcmd.Body, loopHeadLabel); + + // LoopDone: assume !guard; goto loopSuccessor; + TransferCmd trCmd; + if (n == 0 && runOffTheEndLabel != null) { + // goto the given label instead of the textual successor block + trCmd = new GotoCmd(wcmd.tok, new List { runOffTheEndLabel }); + } else { + trCmd = GotoSuccessor(wcmd.tok, b); + } + block = new Block(wcmd.tok, loopDoneLabel, ssDone, trCmd); + blocks.Add(block); + + } else { + IfCmd ifcmd = (IfCmd)b.ec; + string predLabel = b.LabelName; + List predCmds = theSimpleCmds; + + for (; ifcmd != null; ifcmd = ifcmd.elseIf) { + var a = FreshAnon(); + string thenLabel = prefix + a + "_Then"; + Contract.Assert(thenLabel != null); + string elseLabel = prefix + a + "_Else"; + Contract.Assert(elseLabel != null); + + List ssThen = new List(); + List ssElse = new List(); + if (ifcmd.Guard != null) { + var ac = new AssumeCmd(ifcmd.tok, ifcmd.Guard); + ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List(), null); + ssThen.Add(ac); + + ac = new AssumeCmd(ifcmd.tok, Expr.Not(ifcmd.Guard)); + ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List(), null); + ssElse.Add(ac); + } + + // Try to squeeze in ssThen/ssElse into the first block of ifcmd.thn/ifcmd.elseBlock + bool thenGuardTakenCareOf = ifcmd.thn.PrefixFirstBlock(ssThen, ref thenLabel); + bool elseGuardTakenCareOf = false; + if (ifcmd.elseBlock != null) { + elseGuardTakenCareOf = ifcmd.elseBlock.PrefixFirstBlock(ssElse, ref elseLabel); + } + + // ... goto Then, Else; + Block block = new Block(b.tok, predLabel, predCmds, + new GotoCmd(ifcmd.tok, new List { thenLabel, elseLabel })); + blocks.Add(block); + + if (!thenGuardTakenCareOf) { + // Then: assume guard; goto firstThenBlock; + block = new Block(ifcmd.tok, thenLabel, ssThen, new GotoCmd(ifcmd.tok, new List { ifcmd.thn.BigBlocks[0].LabelName })); + blocks.Add(block); + } + + // recurse to create the blocks for the then branch + CreateBlocks(ifcmd.thn, n == 0 ? runOffTheEndLabel : null); + + if (ifcmd.elseBlock != null) { + Contract.Assert(ifcmd.elseIf == null); + if (!elseGuardTakenCareOf) { + // Else: assume !guard; goto firstElseBlock; + block = new Block(ifcmd.tok, elseLabel, ssElse, new GotoCmd(ifcmd.tok, new List { ifcmd.elseBlock.BigBlocks[0].LabelName })); + blocks.Add(block); + } + + // recurse to create the blocks for the else branch + CreateBlocks(ifcmd.elseBlock, n == 0 ? runOffTheEndLabel : null); + + } else if (ifcmd.elseIf != null) { + // this is an "else if" + predLabel = elseLabel; + predCmds = new List(); + if (ifcmd.Guard != null) { + var ac = new AssumeCmd(ifcmd.tok, Expr.Not(ifcmd.Guard)); + ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List(), null); + predCmds.Add(ac); + } + + } else { + // no else alternative is specified, so else branch is just "skip" + // Else: assume !guard; goto ifSuccessor; + TransferCmd trCmd; + if (n == 0 && runOffTheEndLabel != null) { + // goto the given label instead of the textual successor block + trCmd = new GotoCmd(ifcmd.tok, new List { runOffTheEndLabel }); + } else { + trCmd = GotoSuccessor(ifcmd.tok, b); + } + block = new Block(ifcmd.tok, elseLabel, ssElse, trCmd); + blocks.Add(block); + } + } + } + } + } + + TransferCmd GotoSuccessor(IToken tok, BigBlock b) { + Contract.Requires(b != null); + Contract.Requires(tok != null); + Contract.Ensures(Contract.Result() != null); + if (b.successorBigBlock != null) { + return new GotoCmd(tok, new List { b.successorBigBlock.LabelName }); + } else { + return new ReturnCmd(tok); + } + } + } + + [ContractClass(typeof(StructuredCmdContracts))] + public abstract class StructuredCmd { + private IToken/*!*/ _tok; + + public IToken/*!*/ tok + { + get + { + Contract.Ensures(Contract.Result() != null); + return this._tok; + } + set + { + Contract.Requires(value != null); + this._tok = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._tok != null); + } + + public StructuredCmd(IToken tok) { + Contract.Requires(tok != null); + this._tok = tok; + } + + public abstract void Emit(TokenTextWriter/*!*/ stream, int level); + } + [ContractClassFor(typeof(StructuredCmd))] + public abstract class StructuredCmdContracts : StructuredCmd { + public override void Emit(TokenTextWriter stream, int level) { + Contract.Requires(stream != null); + throw new NotImplementedException(); + } + public StructuredCmdContracts() :base(null){ + + } + } + + public class IfCmd : StructuredCmd { + public Expr Guard; + + private StmtList/*!*/ _thn; + + public StmtList/*!*/ thn + { + get + { + Contract.Ensures(Contract.Result() != null); + return this._thn; + } + set + { + Contract.Requires(value != null); + this._thn = value; + } + } + + private IfCmd _elseIf; + + public IfCmd elseIf + { + get + { + return this._elseIf; + } + set + { + Contract.Requires(value == null || this.elseBlock == null); + this._elseIf = value; + } + } + + private StmtList _elseBlock; + + public StmtList elseBlock + { + get + { + return this._elseBlock; + } + set + { + Contract.Requires(value == null || this.elseIf == null); + this._elseBlock = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._thn != null); + Contract.Invariant(this._elseIf == null || this._elseBlock == null); + } + + public IfCmd(IToken/*!*/ tok, Expr guard, StmtList/*!*/ thn, IfCmd elseIf, StmtList elseBlock) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(thn != null); + Contract.Requires(elseIf == null || elseBlock == null); + this.Guard = guard; + this._thn = thn; + this._elseIf = elseIf; + this._elseBlock = elseBlock; + } + + public override void Emit(TokenTextWriter stream, int level) { + stream.Write(level, "if ("); + IfCmd/*!*/ ifcmd = this; + while (true) { + if (ifcmd.Guard == null) { + stream.Write("*"); + } else { + ifcmd.Guard.Emit(stream); + } + stream.WriteLine(")"); + + stream.WriteLine(level, "{"); + ifcmd.thn.Emit(stream, level + 1); + stream.WriteLine(level, "}"); + + if (ifcmd.elseIf != null) { + stream.Write(level, "else if ("); + ifcmd = ifcmd.elseIf; + continue; + } else if (ifcmd.elseBlock != null) { + stream.WriteLine(level, "else"); + stream.WriteLine(level, "{"); + ifcmd.elseBlock.Emit(stream, level + 1); + stream.WriteLine(level, "}"); + } + break; + } + } + } + + public class WhileCmd : StructuredCmd { + [Peer] + public Expr Guard; + public List/*!*/ Invariants; + public StmtList/*!*/ Body; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Body != null); + Contract.Invariant(cce.NonNullElements(Invariants)); + } + + + public WhileCmd(IToken tok, [Captured] Expr guard, List/*!*/ invariants, StmtList/*!*/ body) + : base(tok) { + Contract.Requires(cce.NonNullElements(invariants)); + Contract.Requires(body != null); + Contract.Requires(tok != null); + this.Guard = guard; + this.Invariants = invariants; + this.Body = body; + } + + public override void Emit(TokenTextWriter stream, int level) { + stream.Write(level, "while ("); + if (Guard == null) { + stream.Write("*"); + } else { + Guard.Emit(stream); + } + stream.WriteLine(")"); + + foreach (PredicateCmd inv in Invariants) { + if (inv is AssumeCmd) { + stream.Write(level + 1, "free invariant "); + } else { + stream.Write(level + 1, "invariant "); + } + Cmd.EmitAttributes(stream, inv.Attributes); + inv.Expr.Emit(stream); + stream.WriteLine(";"); + } + + stream.WriteLine(level, "{"); + Body.Emit(stream, level + 1); + stream.WriteLine(level, "}"); + } + } + + public class BreakCmd : StructuredCmd { + public string Label; + public BigBlock BreakEnclosure; + + public BreakCmd(IToken tok, string label) + : base(tok) { + Contract.Requires(tok != null); + this.Label = label; + } + + public override void Emit(TokenTextWriter stream, int level) { + + if (Label == null) { + stream.WriteLine(level, "break;"); + } else { + stream.WriteLine(level, "break {0};", Label); + } + } + } + + //--------------------------------------------------------------------- + // Block + public sealed class Block : Absy { + private string/*!*/ label; // Note, Label is mostly readonly, but it can change to the name of a nearby block during block coalescing and empty-block removal + + public string/*!*/ Label + { + get + { + Contract.Ensures(Contract.Result() != null); + return this.label; + } + set + { + Contract.Requires(value != null); + this.label = value; + } + } + + [Rep] + [ElementsPeer] + public List/*!*/ cmds; + + public List/*!*/ Cmds + { + get + { + Contract.Ensures(Contract.Result>() != null); + return this.cmds; + } + set + { + Contract.Requires(value != null); + this.cmds = value; + } + } + + [Rep] //PM: needed to verify Traverse.Visit + public TransferCmd TransferCmd; // maybe null only because we allow deferred initialization (necessary for cyclic structures) + + public byte[] Checksum; + + // Abstract interpretation + + // public bool currentlyTraversed; + + public enum VisitState { + ToVisit, + BeingVisited, + AlreadyVisited + }; // used by WidenPoints.Compute + public VisitState TraversingStatus; + + public int aiId; // block ID used by the abstract interpreter, which may change these numbers with each AI run + public bool widenBlock; + public int iterations; // Count the number of time we visited the block during fixpoint computation. Used to decide if we widen or not + + // VC generation and SCC computation + public List/*!*/ Predecessors; + + // This field is used during passification to null-out entries in block2Incartion hashtable early + public int succCount; + + private HashSet _liveVarsBefore; + + public IEnumerable liveVarsBefore + { + get + { + Contract.Ensures(cce.NonNullElements(Contract.Result>(), true)); + if (this._liveVarsBefore == null) + return null; + else + return this._liveVarsBefore.AsEnumerable(); + } + set + { + Contract.Requires(cce.NonNullElements(value, true)); + if (value == null) + this._liveVarsBefore = null; + else + this._liveVarsBefore = new HashSet(value); + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this.label != null); + Contract.Invariant(this.cmds != null); + Contract.Invariant(cce.NonNullElements(this._liveVarsBefore, true)); + } + + public bool IsLive(Variable v) { + Contract.Requires(v != null); + if (liveVarsBefore == null) + return true; + return liveVarsBefore.Contains(v); + } + + public Block() + : this(Token.NoToken, "", new List(), new ReturnCmd(Token.NoToken)) { + + } + + public Block(IToken tok, string/*!*/ label, List/*!*/ cmds, TransferCmd transferCmd) + : base(tok) { + Contract.Requires(label != null); + Contract.Requires(cmds != null); + Contract.Requires(tok != null); + this.label = label; + this.cmds = cmds; + this.TransferCmd = transferCmd; + this.Predecessors = new List(); + this._liveVarsBefore = null; + this.TraversingStatus = VisitState.ToVisit; + this.iterations = 0; + } + + public void Emit(TokenTextWriter stream, int level) { + Contract.Requires(stream != null); + stream.WriteLine(); + stream.WriteLine( + this, + level, + "{0}:{1}", + CommandLineOptions.Clo.PrintWithUniqueASTIds ? String.Format("h{0}^^{1}", this.GetHashCode(), this.Label) : this.Label, + this.widenBlock ? " // cut point" : ""); + + foreach (Cmd/*!*/ c in this.Cmds) { + Contract.Assert(c != null); + c.Emit(stream, level + 1); + } + Contract.Assume(this.TransferCmd != null); + this.TransferCmd.Emit(stream, level + 1); + } + + public void Register(ResolutionContext rc) { + Contract.Requires(rc != null); + rc.AddBlock(this); + } + + public override void Resolve(ResolutionContext rc) { + + + foreach (Cmd/*!*/ c in Cmds) { + Contract.Assert(c != null); + c.Resolve(rc); + } + Contract.Assume(this.TransferCmd != null); + TransferCmd.Resolve(rc); + } + + public override void Typecheck(TypecheckingContext tc) { + + foreach (Cmd/*!*/ c in Cmds) { + Contract.Assert(c != null); + c.Typecheck(tc); + } + Contract.Assume(this.TransferCmd != null); + TransferCmd.Typecheck(tc); + } + + /// + /// Reset the abstract intepretation state of this block. It does this by putting the iterations to 0 and the pre and post states to null + /// + public void ResetAbstractInterpretationState() { + // this.currentlyTraversed = false; + this.TraversingStatus = VisitState.ToVisit; + this.iterations = 0; + } + + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result() != null); + return this.Label + (this.widenBlock ? "[w]" : ""); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + + Contract.Ensures(Contract.Result() != null); + return visitor.VisitBlock(this); + } + } + + //--------------------------------------------------------------------- + // Commands + [ContractClassFor(typeof(Cmd))] + public abstract class CmdContracts : Cmd { + public CmdContracts() :base(null){ + + } + public override void Emit(TokenTextWriter stream, int level) { + Contract.Requires(stream != null); + throw new NotImplementedException(); + } + public override void AddAssignedVariables(List vars) { + Contract.Requires(vars != null); + throw new NotImplementedException(); + } + } + + public static class ChecksumHelper + { + public static void ComputeChecksums(Cmd cmd, Implementation impl, ISet usedVariables, byte[] currentChecksum = null) + { + if (CommandLineOptions.Clo.VerifySnapshots < 2) + { + return; + } + + if (cmd.IrrelevantForChecksumComputation) + { + cmd.Checksum = currentChecksum; + return; + } + + var assumeCmd = cmd as AssumeCmd; + if (assumeCmd != null + && QKeyValue.FindBoolAttribute(assumeCmd.Attributes, "assumption_variable_initialization")) + { + // Ignore assumption variable initializations. + assumeCmd.Checksum = currentChecksum; + return; + } + + using (var strWr = new System.IO.StringWriter()) + using (var tokTxtWr = new TokenTextWriter("", strWr, false, false)) + { + tokTxtWr.UseForComputingChecksums = true; + var havocCmd = cmd as HavocCmd; + if (havocCmd != null) + { + tokTxtWr.Write("havoc "); + var relevantVars = havocCmd.Vars.Where(e => usedVariables.Contains(e.Decl) && !e.Decl.Name.StartsWith("a##cached##")).OrderBy(e => e.Name).ToList(); + relevantVars.Emit(tokTxtWr, true); + tokTxtWr.WriteLine(";"); + } + else + { + cmd.Emit(tokTxtWr, 0); + } + var md5 = System.Security.Cryptography.MD5.Create(); + var str = strWr.ToString(); + if (str.Any()) + { + var data = System.Text.Encoding.UTF8.GetBytes(str); + var checksum = md5.ComputeHash(data); + currentChecksum = currentChecksum != null ? CombineChecksums(currentChecksum, checksum) : checksum; + } + cmd.Checksum = currentChecksum; + } + + var assertCmd = cmd as AssertCmd; + if (assertCmd != null && assertCmd.Checksum != null) + { + var assertRequiresCmd = assertCmd as AssertRequiresCmd; + if (assertRequiresCmd != null) + { + impl.AddAssertionChecksum(assertRequiresCmd.Checksum); + impl.AddAssertionChecksum(assertRequiresCmd.Call.Checksum); + assertRequiresCmd.SugaredCmdChecksum = assertRequiresCmd.Call.Checksum; + } + else + { + impl.AddAssertionChecksum(assertCmd.Checksum); + } + } + + var sugaredCmd = cmd as SugaredCmd; + if (sugaredCmd != null) + { + // The checksum of a sugared command should not depend on the desugaring itself. + var stateCmd = sugaredCmd.Desugaring as StateCmd; + if (stateCmd != null) + { + foreach (var c in stateCmd.Cmds) + { + ComputeChecksums(c, impl, usedVariables, currentChecksum); + currentChecksum = c.Checksum; + if (c.SugaredCmdChecksum == null) + { + c.SugaredCmdChecksum = cmd.Checksum; + } + } + } + else + { + ComputeChecksums(sugaredCmd.Desugaring, impl, usedVariables, currentChecksum); + } + } + } + + public static byte[] CombineChecksums(byte[] first, byte[] second, bool unordered = false) + { + Contract.Requires(first != null && (second == null || first.Length == second.Length)); + + var result = (byte[])(first.Clone()); + for (int i = 0; second != null && i < second.Length; i++) + { + if (unordered) + { + result[i] += second[i]; + } + else + { + result[i] = (byte)(result[i] * 31 ^ second[i]); + } + } + return result; + } + } + + [ContractClass(typeof(CmdContracts))] + public abstract class Cmd : Absy { + public byte[] Checksum { get; internal set; } + public byte[] SugaredCmdChecksum { get; internal set; } + public bool IrrelevantForChecksumComputation { get; set; } + + public Cmd(IToken/*!*/ tok) + : base(tok) { + Contract.Assert(tok != null); + } + public abstract void Emit(TokenTextWriter/*!*/ stream, int level); + public abstract void AddAssignedVariables(List/*!*/ vars); + public void CheckAssignments(TypecheckingContext tc) + { + Contract.Requires(tc != null); + List/*!*/ vars = new List(); + this.AddAssignedVariables(vars); + foreach (Variable/*!*/ v in vars) + { + Contract.Assert(v != null); + if (!v.IsMutable) + { + tc.Error(this, "command assigns to an immutable variable: {0}", v.Name); + } + else if (!CommandLineOptions.Clo.DoModSetAnalysis && v is GlobalVariable) + { + if (tc.Yields) { + // a yielding procedure is allowed to modify any global variable + } + else if (tc.Frame == null) + { + tc.Error(this, "update to a global variable allowed only inside an atomic action of a yielding procedure"); + } + else if (!tc.InFrame(v)) + { + tc.Error(this, "command assigns to a global variable that is not in the enclosing procedure's modifies clause: {0}", v.Name); + } + } + } + } + + // Methods to simulate the old SimpleAssignCmd and MapAssignCmd + public static AssignCmd SimpleAssign(IToken tok, IdentifierExpr lhs, Expr rhs) { + Contract.Requires(rhs != null); + Contract.Requires(lhs != null); + Contract.Requires(tok != null); + Contract.Ensures(Contract.Result() != null); + List/*!*/ lhss = new List(); + List/*!*/ rhss = new List(); + + lhss.Add(new SimpleAssignLhs(lhs.tok, lhs)); + rhss.Add(rhs); + + return new AssignCmd(tok, lhss, rhss); + } + + public static AssignCmd/*!*/ MapAssign(IToken tok, + IdentifierExpr/*!*/ map, + List/*!*/ indexes, Expr/*!*/ rhs) { + + Contract.Requires(tok != null); + Contract.Requires(map != null); + Contract.Requires(indexes != null); + Contract.Requires(rhs != null); + Contract.Ensures(Contract.Result() != null); + List/*!*/ lhss = new List(); + List/*!*/ rhss = new List(); + List/*!*/ indexesList = new List(); + + + + foreach (Expr e in indexes) + indexesList.Add(cce.NonNull(e)); + + lhss.Add(new MapAssignLhs(map.tok, + new SimpleAssignLhs(map.tok, map), + indexesList)); + rhss.Add(rhs); + + return new AssignCmd(tok, lhss, rhss); + } + + public static AssignCmd/*!*/ MapAssign(IToken tok, + IdentifierExpr/*!*/ map, + params Expr[]/*!*/ args) { + Contract.Requires(tok != null); + Contract.Requires(map != null); + Contract.Requires(args != null); + Contract.Requires(args.Length > 0); // at least the rhs + Contract.Requires(Contract.ForAll(args, i => i != null)); + Contract.Ensures(Contract.Result() != null); + + List/*!*/ lhss = new List(); + List/*!*/ rhss = new List(); + List/*!*/ indexesList = new List(); + + for (int i = 0; i < args.Length - 1; ++i) + indexesList.Add(cce.NonNull(args[i])); + + lhss.Add(new MapAssignLhs(map.tok, + new SimpleAssignLhs(map.tok, map), + indexesList)); + rhss.Add(cce.NonNull(args[args.Length - 1])); + + return new AssignCmd(tok, lhss, rhss); + } + + /// + /// This is a helper routine for printing a linked list of attributes. Each attribute + /// is terminated by a space. + /// + public static void EmitAttributes(TokenTextWriter stream, QKeyValue attributes) { + Contract.Requires(stream != null); + + if (stream.UseForComputingChecksums) { return; } + + for (QKeyValue kv = attributes; kv != null; kv = kv.Next) { + kv.Emit(stream); + stream.Write(" "); + } + } + public static void ResolveAttributes(QKeyValue attributes, ResolutionContext rc) { + Contract.Requires(rc != null); + for (QKeyValue kv = attributes; kv != null; kv = kv.Next) { + kv.Resolve(rc); + } + } + public static void TypecheckAttributes(QKeyValue attributes, TypecheckingContext tc) { + Contract.Requires(tc != null); + for (QKeyValue kv = attributes; kv != null; kv = kv.Next) { + kv.Typecheck(tc); + } + } + + [Pure] + public override string ToString() + { + Contract.Ensures(Contract.Result() != null); + System.IO.StringWriter buffer = new System.IO.StringWriter(); + using (TokenTextWriter stream = new TokenTextWriter("", buffer, /*setTokens=*/ false , /*pretty=*/ false)) { + this.Emit(stream, 0); + } + return buffer.ToString(); + } + } + + public class YieldCmd : Cmd + { + public YieldCmd(IToken/*!*/ tok) + : base(tok) + { + Contract.Requires(tok != null); + } + public override void Emit(TokenTextWriter stream, int level) + { + //Contract.Requires(stream != null); + stream.WriteLine(this, level, "yield;"); + } + public override void Resolve(ResolutionContext rc) + { + // nothing to resolve + } + public override void Typecheck(TypecheckingContext tc) + { + if (!CommandLineOptions.Clo.DoModSetAnalysis && !tc.Yields) + { + tc.Error(this, "enclosing procedure of a yield command must yield"); + } + } + public override void AddAssignedVariables(List vars) + { + // nothing to add + } + public override Absy StdDispatch(StandardVisitor visitor) + { + Contract.Ensures(Contract.Result() != null); + return visitor.VisitYieldCmd(this); + } + } + + public class CommentCmd : Cmd // just a convenience for debugging + { + public readonly string/*!*/ Comment; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Comment != null); + } + + public CommentCmd(string c) + : base(Token.NoToken) { + Contract.Requires(c != null); + Comment = c; + } + public override void Emit(TokenTextWriter stream, int level) { + if (stream.UseForComputingChecksums) { return; } + + if (this.Comment.Contains("\n")) { + stream.WriteLine(this, level, "/* {0} */", this.Comment); + } else { + stream.WriteLine(this, level, "// {0}", this.Comment); + } + } + public override void Resolve(ResolutionContext rc) { + + } + public override void AddAssignedVariables(List vars) { + + } + public override void Typecheck(TypecheckingContext tc) { + + } + + public override Absy StdDispatch(StandardVisitor visitor) { + + + return visitor.VisitCommentCmd(this); + } + } + + // class for parallel assignments, which subsumes both the old + // SimpleAssignCmd and the old MapAssignCmd + public class AssignCmd : Cmd { + private List/*!*/ _lhss; + + public IList/*!*/ Lhss { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + Contract.Ensures(Contract.Result>().IsReadOnly); + return this._lhss.AsReadOnly(); + } + set { + Contract.Requires(cce.NonNullElements(value)); + this._lhss = new List(value); + } + } + + internal void SetLhs(int index, AssignLhs lhs) + { + Contract.Requires(0 <= index && index < this.Lhss.Count); + Contract.Requires(lhs != null); + Contract.Ensures(this.Lhss[index] == lhs); + this._lhss[index] = lhs; + } + + private List/*!*/ _rhss; + + public IList/*!*/ Rhss { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + Contract.Ensures(Contract.Result>().IsReadOnly); + return this._rhss.AsReadOnly(); + } + set { + Contract.Requires(cce.NonNullElements(value)); + this._rhss = new List(value); + } + } + + internal void SetRhs(int index, Expr rhs) + { + Contract.Requires(0 <= index && index < this.Rhss.Count); + Contract.Requires(rhs != null); + Contract.Ensures(this.Rhss[index] == rhs); + this._rhss[index] = rhs; + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cce.NonNullElements(this._lhss)); + Contract.Invariant(cce.NonNullElements(this._rhss)); + } + + + public AssignCmd(IToken tok, IList/*!*/ lhss, IList/*!*/ rhss) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(cce.NonNullElements(rhss)); + Contract.Requires(cce.NonNullElements(lhss)); + this._lhss = new List(lhss); + this._rhss = new List(rhss); + } + + public override void Emit(TokenTextWriter stream, int level) { + stream.Write(this, level, ""); + + string/*!*/ sep = ""; + foreach (AssignLhs/*!*/ l in Lhss) { + Contract.Assert(l != null); + stream.Write(sep); + sep = ", "; + l.Emit(stream); + } + + stream.Write(" := "); + + sep = ""; + foreach (Expr/*!*/ e in Rhss) { + Contract.Assert(e != null); + stream.Write(sep); + sep = ", "; + e.Emit(stream); + } + + stream.WriteLine(";"); + } + + public override void Resolve(ResolutionContext rc) { + + if (Lhss.Count != Rhss.Count) + rc.Error(this, + "number of left-hand sides does not match number of right-hand sides"); + + foreach (AssignLhs/*!*/ e in Lhss) { + Contract.Assert(e != null); + e.Resolve(rc); + } + foreach (Expr/*!*/ e in Rhss) { + Contract.Assert(e != null); + e.Resolve(rc); + } + + // check for double occurrences of assigned variables + // (could be optimised) + for (int i = 0; i < Lhss.Count; ++i) { + for (int j = i + 1; j < Lhss.Count; ++j) { + if (cce.NonNull(Lhss[i].DeepAssignedVariable).Equals( + Lhss[j].DeepAssignedVariable)) + rc.Error(Lhss[j], + "variable {0} is assigned more than once in parallel assignment", + Lhss[j].DeepAssignedVariable); + } + } + + for (int i = 0; i < Lhss.Count; i++) + { + var lhs = Lhss[i].AsExpr as IdentifierExpr; + if (lhs != null && lhs.Decl != null && QKeyValue.FindBoolAttribute(lhs.Decl.Attributes, "assumption")) + { + var rhs = Rhss[i] as NAryExpr; + if (rhs == null + || !(rhs.Fun is BinaryOperator) + || ((BinaryOperator)(rhs.Fun)).Op != BinaryOperator.Opcode.And + || !(rhs.Args[0] is IdentifierExpr) + || ((IdentifierExpr)(rhs.Args[0])).Name != lhs.Name) + { + rc.Error(tok, string.Format("RHS of assignment to assumption variable {0} must match expression \"{0} && \"", lhs.Name)); + } + else if (rc.HasVariableBeenAssigned(lhs.Decl.Name)) + { + rc.Error(tok, "assumption variable may not be assigned to more than once"); + } + else + { + rc.MarkVariableAsAssigned(lhs.Decl.Name); + } + } + } + } + + public override void Typecheck(TypecheckingContext tc) { + + foreach (AssignLhs/*!*/ e in Lhss) { + Contract.Assert(e != null); + e.Typecheck(tc); + } + foreach (Expr/*!*/ e in Rhss) { + Contract.Assert(e != null); + e.Typecheck(tc); + } + + this.CheckAssignments(tc); + + for (int i = 0; i < Lhss.Count; ++i) { + Type ltype = Lhss[i].Type; + Type rtype = Rhss[i].Type; + if (ltype != null && rtype != null) { + // otherwise, there has already been an error when + // typechecking the lhs or rhs + if (!ltype.Unify(rtype)) + tc.Error(Lhss[i], + "mismatched types in assignment command (cannot assign {0} to {1})", + rtype, ltype); + } + } + } + + public override void AddAssignedVariables(List vars) { + + foreach (AssignLhs/*!*/ l in Lhss) { + Contract.Assert(l != null); + vars.Add(l.DeepAssignedVariable); + } + } + + // transform away the syntactic sugar of map assignments and + // determine an equivalent assignment in which all rhs are simple + // variables + public AssignCmd/*!*/ AsSimpleAssignCmd { + get { + Contract.Ensures(Contract.Result() != null); + + List/*!*/ newLhss = new List(); + List/*!*/ newRhss = new List(); + + for (int i = 0; i < Lhss.Count; ++i) { + IdentifierExpr/*!*/ newLhs; + Expr/*!*/ newRhs; + Lhss[i].AsSimpleAssignment(Rhss[i], out newLhs, out newRhs); + newLhss.Add(new SimpleAssignLhs(Token.NoToken, newLhs)); + newRhss.Add(newRhs); + } + + return new AssignCmd(Token.NoToken, newLhss, newRhss); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + + + return visitor.VisitAssignCmd(this); + } + } + + // There are two different kinds of left-hand sides in assignments: + // simple variables (identifiers), or locations of a map + [ContractClass(typeof(AssignLhsContracts))] + public abstract class AssignLhs : Absy { + // The type of the lhs is determined during typechecking + public abstract Type Type { + get; + } + // Determine the variable that is actually assigned in this lhs + public abstract IdentifierExpr/*!*/ DeepAssignedIdentifier { + get; + } + public abstract Variable DeepAssignedVariable { + get; + } + + public AssignLhs(IToken/*!*/ tok) + : base(tok) { + Contract.Requires(tok != null); + } + public abstract void Emit(TokenTextWriter/*!*/ stream); + + public abstract Expr/*!*/ AsExpr { + get; + } + + // transform away the syntactic sugar of map assignments and + // determine an equivalent simple assignment + internal abstract void AsSimpleAssignment(Expr/*!*/ rhs, + out IdentifierExpr/*!*/ simpleLhs, + out Expr/*!*/ simpleRhs); + } + [ContractClassFor(typeof(AssignLhs))] + public abstract class AssignLhsContracts : AssignLhs { + public AssignLhsContracts():base(null) + { + + }public override IdentifierExpr DeepAssignedIdentifier { + + get { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + public override Expr AsExpr { + get { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + + } + internal override void AsSimpleAssignment(Expr rhs, out IdentifierExpr simpleLhs, out Expr simpleRhs) { + Contract.Requires(rhs != null); + Contract.Ensures(Contract.ValueAtReturn(out simpleLhs) != null); + Contract.Ensures(Contract.ValueAtReturn(out simpleRhs) != null); + + throw new NotImplementedException(); + } + } + + public class SimpleAssignLhs : AssignLhs { + public IdentifierExpr/*!*/ AssignedVariable; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(AssignedVariable != null); + } + + + public override Type Type { + get { + return AssignedVariable.Type; + } + } + + public override IdentifierExpr/*!*/ DeepAssignedIdentifier { + get { + Contract.Ensures(Contract.Result() != null); + return AssignedVariable; + } + } + + public override Variable DeepAssignedVariable { + get { + return AssignedVariable.Decl; + } + } + + public SimpleAssignLhs(IToken tok, IdentifierExpr assignedVariable) + : base(tok) { + Contract.Requires(assignedVariable != null); + Contract.Requires(tok != null); + AssignedVariable = assignedVariable; + } + public override void Resolve(ResolutionContext rc) { + + AssignedVariable.Resolve(rc); + } + public override void Typecheck(TypecheckingContext tc) { + + AssignedVariable.Typecheck(tc); + } + public override void Emit(TokenTextWriter stream) { + + AssignedVariable.Emit(stream); + } + public override Expr/*!*/ AsExpr { + get { + Contract.Ensures(Contract.Result() != null); + + return AssignedVariable; + } + } + internal override void AsSimpleAssignment(Expr rhs, + out IdentifierExpr/*!*/ simpleLhs, + out Expr/*!*/ simpleRhs) { + + + + simpleLhs = AssignedVariable; + simpleRhs = rhs; + } + + public override Absy StdDispatch(StandardVisitor visitor) { + + + return visitor.VisitSimpleAssignLhs(this); + } + } + + // A map-assignment-lhs (m[t1, t2, ...] := ...) is quite similar to + // a map select expression, but it is cleaner to keep those two + // things separate + public class MapAssignLhs : AssignLhs { + public AssignLhs/*!*/ Map; + + public List/*!*/ Indexes; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Map != null); + Contract.Invariant(cce.NonNullElements(Indexes)); + } + + + // The instantiation of type parameters of the map that is + // determined during type checking. + public TypeParamInstantiation TypeParameters = null; + + private Type TypeAttr = null; + + public override Type Type { + get { + return TypeAttr; + } + } + + public override IdentifierExpr/*!*/ DeepAssignedIdentifier { + get { + Contract.Ensures(Contract.Result() != null); + + return Map.DeepAssignedIdentifier; + } + } + + public override Variable DeepAssignedVariable { + get { + return Map.DeepAssignedVariable; + } + } + + public MapAssignLhs(IToken tok, AssignLhs map, List/*!*/ indexes) + : base(tok) { + Contract.Requires(map != null); + Contract.Requires(tok != null); + Contract.Requires(cce.NonNullElements(indexes)); + + Map = map; + Indexes = indexes; + } + public override void Resolve(ResolutionContext rc) { + + Map.Resolve(rc); + foreach (Expr/*!*/ e in Indexes) { + Contract.Assert(e != null); + e.Resolve(rc); + } + } + public override void Typecheck(TypecheckingContext tc) { + + Map.Typecheck(tc); + foreach (Expr/*!*/ e in Indexes) { + Contract.Assert(e != null); + e.Typecheck(tc); + } + + // we use the same typechecking code as in MapSelect + List/*!*/ selectArgs = new List(); + foreach (Expr/*!*/ e in Indexes) { + Contract.Assert(e != null); + selectArgs.Add(e); + } + TypeParamInstantiation/*!*/ tpInsts; + TypeAttr = + MapSelect.Typecheck(cce.NonNull(Map.Type), Map, + selectArgs, out tpInsts, tc, tok, "map assignment"); + TypeParameters = tpInsts; + } + public override void Emit(TokenTextWriter stream) { + + Map.Emit(stream); + stream.Write("["); + string/*!*/ sep = ""; + foreach (Expr/*!*/ e in Indexes) { + Contract.Assert(e != null); + stream.Write(sep); + sep = ", "; + e.Emit(stream); + } + stream.Write("]"); + } + public override Expr/*!*/ AsExpr { + get { + Contract.Ensures(Contract.Result() != null); + + NAryExpr/*!*/ res = Expr.Select(Map.AsExpr, Indexes); + Contract.Assert(res != null); + res.TypeParameters = this.TypeParameters; + res.Type = this.Type; + return res; + } + } + internal override void AsSimpleAssignment(Expr rhs, + out IdentifierExpr/*!*/ simpleLhs, + out Expr/*!*/ simpleRhs) { //Contract.Requires(rhs != null); + Contract.Ensures(Contract.ValueAtReturn(out simpleLhs) != null); + Contract.Ensures(Contract.ValueAtReturn(out simpleRhs) != null); + + NAryExpr/*!*/ newRhs = Expr.Store(Map.AsExpr, Indexes, rhs); + Contract.Assert(newRhs != null); + newRhs.TypeParameters = this.TypeParameters; + newRhs.Type = Map.Type; + Map.AsSimpleAssignment(newRhs, out simpleLhs, out simpleRhs); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitMapAssignLhs(this); + } + } + + /// + /// A StateCmd is like an imperative-let binding around a sequence of commands. + /// There is no user syntax for a StateCmd. Instead, a StateCmd is only used + /// temporarily during the desugaring phase inside the VC generator. + /// + public class StateCmd : Cmd { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._locals != null); + Contract.Invariant(this._cmds != null); + } + + private List _locals; + + public /*readonly, except for the StandardVisitor*/ List/*!*/ Locals { + get { + Contract.Ensures(Contract.Result>() != null); + return this._locals; + } + internal set { + Contract.Requires(value != null); + this._locals = value; + } + } + + private List _cmds; + + public /*readonly, except for the StandardVisitor*/ List/*!*/ Cmds { + get { + Contract.Ensures(Contract.Result>() != null); + return this._cmds; + } + set { + Contract.Requires(value != null); + this._cmds = value; + } + } + + public StateCmd(IToken tok, List/*!*/ locals, List/*!*/ cmds) + : base(tok) { + Contract.Requires(locals != null); + Contract.Requires(cmds != null); + Contract.Requires(tok != null); + this._locals = locals; + this._cmds = cmds; + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.PushVarContext(); + foreach (Variable/*!*/ v in Locals) { + Contract.Assert(v != null); + rc.AddVariable(v, false); + } + foreach (Cmd/*!*/ cmd in Cmds) { + Contract.Assert(cmd != null); + cmd.Resolve(rc); + } + rc.PopVarContext(); + } + + public override void AddAssignedVariables(List vars) { + //Contract.Requires(vars != null); + List/*!*/ vs = new List(); + foreach (Cmd/*!*/ cmd in this.Cmds) { + Contract.Assert(cmd != null); + cmd.AddAssignedVariables(vs); + } + System.Collections.Hashtable/*!*/ localsSet = new System.Collections.Hashtable(); + foreach (Variable/*!*/ local in this.Locals) { + Contract.Assert(local != null); + localsSet[local] = bool.TrueString; + } + foreach (Variable/*!*/ v in vs) { + Contract.Assert(v != null); + if (!localsSet.ContainsKey(v)) { + vars.Add(v); + } + } + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + foreach (Cmd/*!*/ cmd in Cmds) { + Contract.Assert(cmd != null); + cmd.Typecheck(tc); + } + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.WriteLine(this, level, "{"); + foreach (Variable/*!*/ v in Locals) { + Contract.Assert(v != null); + v.Emit(stream, level + 1); + } + foreach (Cmd/*!*/ c in Cmds) { + Contract.Assert(c != null); + c.Emit(stream, level + 1); + } + stream.WriteLine(level, "}"); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitStateCmd(this); + } + } + [ContractClass(typeof(SugaredCmdContracts))] + abstract public class SugaredCmd : Cmd { + private Cmd desugaring; // null until desugared + + public SugaredCmd(IToken/*!*/ tok) + : base(tok) { + Contract.Requires(tok != null); + } + + public Cmd/*!*/ Desugaring { + get { + Contract.Ensures(Contract.Result() != null); + + if (desugaring == null) { + desugaring = ComputeDesugaring(); + } + return desugaring; + } + } + /// + /// This method invokes "visitor.Visit" on the desugaring, and then updates the + /// desugaring to the result thereof. The method's intended use is for subclasses + /// of StandardVisitor that need to also visit the desugaring. Note, since the + /// "desugaring" field is updated, this is not an appropriate method to be called + /// be a ReadOnlyVisitor; such visitors should instead just call + /// visitor.Visit(sugaredCmd.Desugaring). + /// + public void VisitDesugaring(StandardVisitor visitor) { + Contract.Requires(visitor != null && !(visitor is ReadOnlyVisitor)); + if (desugaring != null) { + desugaring = (Cmd)visitor.Visit(desugaring); + } + } + protected abstract Cmd/*!*/ ComputeDesugaring(); + + public void ExtendDesugaring(IEnumerable before, IEnumerable beforePreconditionCheck, IEnumerable after) + { + var desug = Desugaring; + var stCmd = desug as StateCmd; + if (stCmd != null) + { + stCmd.Cmds.InsertRange(0, before); + var idx = stCmd.Cmds.FindIndex(c => c is AssertCmd || c is HavocCmd || c is AssumeCmd); + if (idx < 0) + { + idx = 0; + } + stCmd.Cmds.InsertRange(idx, beforePreconditionCheck); + stCmd.Cmds.AddRange(after); + } + else if (desug != null) + { + var cmds = new List(before); + cmds.Add(desug); + cmds.AddRange(after); + desugaring = new StateCmd(Token.NoToken, new List(), cmds); + } + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + if (CommandLineOptions.Clo.PrintDesugarings && !stream.UseForComputingChecksums) { + stream.WriteLine(this, level, "/*** desugaring:"); + Desugaring.Emit(stream, level); + stream.WriteLine(level, "**** end desugaring */"); + } + } + } + [ContractClassFor(typeof(SugaredCmd))] + public abstract class SugaredCmdContracts : SugaredCmd { + public SugaredCmdContracts() :base(null){ + + } + protected override Cmd ComputeDesugaring() { + Contract.Ensures(Contract.Result() != null); + + throw new NotImplementedException(); + } + } + + public abstract class CallCommonality : SugaredCmd { + public QKeyValue Attributes; + + private bool isFree = false; + public bool IsFree { + get { + return isFree; + } + set { + isFree = value; + } + } + + private bool isAsync = false; + public bool IsAsync + { + get + { + return isAsync; + } + set + { + isAsync = value; + } + } + + protected CallCommonality(IToken tok, QKeyValue kv) + : base(tok) { + Contract.Requires(tok != null); + Attributes = kv; + } + + protected enum TempVarKind { + Formal, + Old, + Bound + } + + // We have to give the type explicitly, because the type of the formal "likeThisOne" can contain type variables + protected Variable CreateTemporaryVariable(List tempVars, Variable likeThisOne, Type ty, TempVarKind kind, ref int uniqueId) { + Contract.Requires(ty != null); + Contract.Requires(likeThisOne != null); + Contract.Requires(tempVars != null); + Contract.Ensures(Contract.Result() != null); + string/*!*/ tempNamePrefix; + switch (kind) { + case TempVarKind.Formal: + tempNamePrefix = "formal@"; + break; + case TempVarKind.Old: + tempNamePrefix = "old@"; + break; + case TempVarKind.Bound: + tempNamePrefix = "forall@"; + break; + default: { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // unexpected kind + } + TypedIdent ti = likeThisOne.TypedIdent; + // KLM: uniqueId was messing up FixedPointVC for unknown reason. + // I reverted this change for FixedPointVC only. + int id = CommandLineOptions.Clo.FixedPointEngine != null ? UniqueId : (uniqueId++); + TypedIdent newTi = new TypedIdent(ti.tok, "call" + id + tempNamePrefix + ti.Name, ty); + Variable/*!*/ v; + if (kind == TempVarKind.Bound) { + v = new BoundVariable(likeThisOne.tok, newTi); + } else { + v = new LocalVariable(likeThisOne.tok, newTi); + tempVars.Add(v); + } + return v; + } + } + + public class ParCallCmd : CallCommonality, IPotentialErrorNode + { + public List CallCmds; + public ParCallCmd(IToken tok, List callCmds) + : base(tok, null) + { + this.CallCmds = callCmds; + } + public ParCallCmd(IToken tok, List callCmds, QKeyValue kv) + : base(tok, kv) + { + this.CallCmds = callCmds; + } + protected override Cmd ComputeDesugaring() + { + throw new NotImplementedException(); + } + private object errorData; + public object ErrorData + { + get + { + return errorData; + } + set + { + errorData = value; + } + } + public override void Resolve(ResolutionContext rc) + { + ResolveAttributes(Attributes, rc); + foreach (CallCmd callCmd in CallCmds) + { + callCmd.Resolve(rc); + } + HashSet parallelCallLhss = new HashSet(); + foreach (CallCmd callCmd in CallCmds) + { + foreach (IdentifierExpr ie in callCmd.Outs) + { + if (parallelCallLhss.Contains(ie.Decl)) + { + rc.Error(this, "left-hand side of parallel call command contains variable twice: {0}", ie.Name); + } + else + { + parallelCallLhss.Add(ie.Decl); + } + } + } + } + public override void Typecheck(TypecheckingContext tc) + { + TypecheckAttributes(Attributes, tc); + if (!CommandLineOptions.Clo.DoModSetAnalysis) + { + if (!tc.Yields) + { + tc.Error(this, "enclosing procedure of a parallel call must yield"); + } + foreach (CallCmd callCmd in CallCmds) + { + if (!QKeyValue.FindBoolAttribute(callCmd.Proc.Attributes, "yields")) + { + tc.Error(callCmd, "target procedure of a parallel call must yield"); + } + } + } + foreach (CallCmd callCmd in CallCmds) + { + callCmd.Typecheck(tc); + } + } + public override void AddAssignedVariables(List vars) + { + foreach (CallCmd callCmd in CallCmds) + { + callCmd.AddAssignedVariables(vars); + } + } + public override Absy StdDispatch(StandardVisitor visitor) + { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitParCallCmd(this); + } + } + + public class CallCmd : CallCommonality, IPotentialErrorNode + { + public string/*!*/ callee { get; set; } + public Procedure Proc; + public LocalVariable AssignedAssumptionVariable; + + // Element of the following lists can be null, which means that + // the call happens with * as these parameters + public List/*!*/ Ins; + public List/*!*/ Outs; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(callee != null); + Contract.Invariant(Ins != null); + Contract.Invariant(Outs != null); + } + + //public Lattice.Element StateAfterCall; + + // The instantiation of type parameters that is determined during + // type checking + public TypeParamInstantiation TypeParameters = null; + + // TODO: convert to use generics + private object errorData; + public object ErrorData { + get { + return errorData; + } + set { + errorData = value; + } + } + public CallCmd(IToken tok, string callee, List ins, List outs) + : base(tok, null) { + Contract.Requires(outs != null); + Contract.Requires(ins != null); + Contract.Requires(callee != null); + Contract.Requires(tok != null); + this.callee = callee; + this.Ins = ins; + this.Outs = outs; + } + public CallCmd(IToken tok, string callee, List ins, List outs, QKeyValue kv) + : base(tok, kv) { + Contract.Requires(outs != null); + Contract.Requires(ins != null); + Contract.Requires(callee != null); + Contract.Requires(tok != null); + this.callee = callee; + this.Ins = ins; + this.Outs = outs; + } + + public CallCmd(IToken tok, string callee, List ins, List outs, QKeyValue kv, bool IsAsync) + : base(tok, kv) + { + Contract.Requires(outs != null); + Contract.Requires(ins != null); + Contract.Requires(callee != null); + Contract.Requires(tok != null); + this.callee = callee; + this.Ins = ins; + this.Outs = outs; + this.IsAsync = IsAsync; + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, ""); + if (IsFree) { + stream.Write("free "); + } + if (IsAsync) { + stream.Write("async "); + } + stream.Write("call "); + EmitAttributes(stream, Attributes); + string sep = ""; + if (Outs.Count > 0) { + foreach (Expr arg in Outs) { + stream.Write(sep); + sep = ", "; + if (arg == null) { + stream.Write("*"); + } else { + arg.Emit(stream); + } + } + stream.Write(" := "); + } + stream.Write(TokenTextWriter.SanitizeIdentifier(callee)); + stream.Write("("); + sep = ""; + foreach (Expr arg in Ins) { + stream.Write(sep); + sep = ", "; + if (arg == null) { + stream.Write("*"); + } else { + arg.Emit(stream); + } + } + stream.WriteLine(");"); + base.Emit(stream, level); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + if (Proc != null) { + // already resolved + return; + } + ResolveAttributes(Attributes, rc); + Proc = rc.LookUpProcedure(callee) as Procedure; + if (Proc == null) { + rc.Error(this, "call to undeclared procedure: {0}", callee); + } + foreach (Expr e in Ins) { + if (e != null) { + e.Resolve(rc); + } + } + HashSet actualOuts = new HashSet(); + foreach (IdentifierExpr ide in Outs) { + if (ide != null) { + ide.Resolve(rc); + if (ide.Decl != null) { + if (actualOuts.Contains(ide.Decl)) { + rc.Error(this, "left-hand side of call command contains variable twice: {0}", ide.Name); + } else { + actualOuts.Add(ide.Decl); + } + } + } + } + + if (Proc == null) + return; + + // first make sure that the right number of parameters is given + // (a similar check is in CheckArgumentTypes, but we are not + // able to call this method because it cannot cope with Ins/Outs + // that are null) + if (Ins.Count != Proc.InParams.Count) { + rc.Error(this.tok, + "wrong number of arguments in call to {0}: {1}", + callee, Ins.Count); + return; + } + if (Outs.Count != Proc.OutParams.Count) { + rc.Error(this.tok, + "wrong number of result variables in call to {0}: {1}", + callee, Outs.Count); + return; + } + if (IsAsync) { + if (Proc.OutParams.Count > 0) { + rc.Error(this.tok, "a procedure called asynchronously can have no output parameters"); + return; + } + } + + // Check that type parameters can be determined using the given + // actual i/o arguments. This is done already during resolution + // because CheckBoundVariableOccurrences needs a resolution + // context + List/*!*/ formalInTypes = new List(); + List/*!*/ formalOutTypes = new List(); + for (int i = 0; i < Ins.Count; ++i) + if (Ins[i] != null) + formalInTypes.Add(cce.NonNull(Proc.InParams[i]).TypedIdent.Type); + for (int i = 0; i < Outs.Count; ++i) + if (Outs[i] != null) + formalOutTypes.Add(cce.NonNull(Proc.OutParams[i]).TypedIdent.Type); + + // we need to bind the type parameters for this + // (this is expected by CheckBoundVariableOccurrences) + int previousTypeBinderState = rc.TypeBinderState; + try { + foreach (TypeVariable/*!*/ v in Proc.TypeParameters) { + Contract.Assert(v != null); + rc.AddTypeBinder(v); + } + Type.CheckBoundVariableOccurrences(Proc.TypeParameters, + formalInTypes, formalOutTypes, + this.tok, "types of given arguments", + rc); + } finally { + rc.TypeBinderState = previousTypeBinderState; + } + + var id = QKeyValue.FindStringAttribute(Attributes, "id"); + if (id != null) + { + rc.AddStatementId(tok, id); + } + } + + public override void AddAssignedVariables(List vars) { + if (this.IsAsync) + return; + foreach (IdentifierExpr e in Outs) { + if (e != null) { + vars.Add(e.Decl); + } + } + Contract.Assume(this.Proc != null); + foreach (IdentifierExpr/*!*/ e in this.Proc.Modifies) { + Contract.Assert(e != null); + vars.Add(e.Decl); + } + if (AssignedAssumptionVariable != null) + { + vars.Add(AssignedAssumptionVariable); + } + } + + public override void Typecheck(TypecheckingContext tc) + { + //Contract.Requires(tc != null); + Contract.Assume(this.Proc != null); // we assume the CallCmd has been successfully resolved before calling this Typecheck method + + TypecheckAttributes(Attributes, tc); + + // typecheck in-parameters + foreach (Expr e in Ins) + if (e != null) + e.Typecheck(tc); + foreach (Expr e in Outs) + if (e != null) + e.Typecheck(tc); + this.CheckAssignments(tc); + + List/*!*/ formalInTypes = new List(); + List/*!*/ formalOutTypes = new List(); + List/*!*/ actualIns = new List(); + List/*!*/ actualOuts = new List(); + for (int i = 0; i < Ins.Count; ++i) + { + if (Ins[i] != null) + { + formalInTypes.Add(cce.NonNull(Proc.InParams[i]).TypedIdent.Type); + actualIns.Add(Ins[i]); + } + } + for (int i = 0; i < Outs.Count; ++i) + { + if (Outs[i] != null) + { + formalOutTypes.Add(cce.NonNull(Proc.OutParams[i]).TypedIdent.Type); + actualOuts.Add(Outs[i]); + } + } + + // match actuals with formals + List/*!*/ actualTypeParams; + Type.CheckArgumentTypes(Proc.TypeParameters, + out actualTypeParams, + formalInTypes, actualIns, + formalOutTypes, actualOuts, + this.tok, + "call to " + callee, + tc); + Contract.Assert(cce.NonNullElements(actualTypeParams)); + TypeParameters = SimpleTypeParamInstantiation.From(Proc.TypeParameters, + actualTypeParams); + + if (!CommandLineOptions.Clo.DoModSetAnalysis && IsAsync) + { + if (!tc.Yields) + { + tc.Error(this, "enclosing procedure of an async call must yield"); + } + if (!QKeyValue.FindBoolAttribute(Proc.Attributes, "yields")) + { + tc.Error(this, "target procedure of an async call must yield"); + } + } + } + + private IDictionary/*!*/ TypeParamSubstitution() { + Contract.Ensures(cce.NonNullDictionaryAndValues(Contract.Result>())); + Contract.Assume(TypeParameters != null); + IDictionary/*!*/ res = new Dictionary(); + foreach (TypeVariable/*!*/ v in TypeParameters.FormalTypeParams) { + Contract.Assert(v != null); + res.Add(v, TypeParameters[v]); + } + return res; + } + + protected override Cmd ComputeDesugaring() { + Contract.Ensures(Contract.Result() != null); + + int uniqueId = 0; + List newBlockBody = new List(); + Dictionary substMap = new Dictionary(); + Dictionary substMapOld = new Dictionary(); + Dictionary substMapBound = new Dictionary(); + List/*!*/ tempVars = new List(); + + // proc P(ins) returns (outs) + // requires Pre + // //modifies frame + // ensures Post + // + // call aouts := P(ains) + + // ins : formal in parameters of procedure + // frame : a list of global variables from the modifies clause + // outs : formal out parameters of procedure + // ains : actual in arguments passed to call + // aouts : actual variables assigned to from call + // cins : new variables created just for this call, one per ains + // cframe : new variables created just for this call, to keep track of OLD values + // couts : new variables created just for this call, one per aouts + // WildcardVars : new variables created just for this call, one per null in ains + + #region Create cins; each one is an incarnation of the corresponding in parameter + List/*!*/ cins = new List(); + List wildcardVars = new List(); + Contract.Assume(this.Proc != null); + for (int i = 0; i < this.Proc.InParams.Count; ++i) { + Variable/*!*/ param = cce.NonNull(this.Proc.InParams[i]); + bool isWildcard = this.Ins[i] == null; + + Type/*!*/ actualType; + if (isWildcard) + actualType = param.TypedIdent.Type.Substitute(TypeParamSubstitution()); + else + // during type checking, we have ensured that the type of the actual + // parameter Ins[i] is correct, so we can use it here + actualType = cce.NonNull(cce.NonNull(Ins[i]).Type); + + Variable cin = CreateTemporaryVariable(tempVars, param, actualType, + TempVarKind.Formal, ref uniqueId); + cins.Add(cin); + IdentifierExpr ie = new IdentifierExpr(cin.tok, cin); + substMap.Add(param, ie); + if (isWildcard) { + cin = CreateTemporaryVariable(tempVars, param, + actualType, TempVarKind.Bound, ref uniqueId); + wildcardVars.Add(cin); + ie = new IdentifierExpr(cin.tok, cin); + } + substMapBound.Add(param, ie); + } + #endregion + #region call aouts := P(ains) becomes: (open outlining one level to see) + #region cins := ains (or havoc cin when ain is null) + for (int i = 0, n = this.Ins.Count; i < n; i++) { + IdentifierExpr/*!*/ cin_exp = new IdentifierExpr(cce.NonNull(cins[i]).tok, cce.NonNull(cins[i])); + Contract.Assert(cin_exp != null); + if (this.Ins[i] != null) { + AssignCmd assign = Cmd.SimpleAssign(Token.NoToken, cin_exp, cce.NonNull(this.Ins[i])); + newBlockBody.Add(assign); + } else { + List/*!*/ ies = new List(); + ies.Add(cin_exp); + HavocCmd havoc = new HavocCmd(Token.NoToken, ies); + newBlockBody.Add(havoc); + } + } + #endregion + + #region assert (exists wildcardVars :: Pre[ins := cins]) + Substitution s = Substituter.SubstitutionFromHashtable(substMapBound); + bool hasWildcard = (wildcardVars.Count != 0); + Expr preConjunction = null; + for (int i = 0; i < this.Proc.Requires.Count; i++) { + Requires/*!*/ req = cce.NonNull(this.Proc.Requires[i]); + if (!req.Free && !IsFree) { + if (hasWildcard) { + Expr pre = Substituter.Apply(s, req.Condition); + if (preConjunction == null) { + preConjunction = pre; + } else { + preConjunction = Expr.And(preConjunction, pre); + } + } else { + Requires/*!*/ reqCopy = (Requires/*!*/)cce.NonNull(req.Clone()); + reqCopy.Condition = Substituter.Apply(s, req.Condition); + AssertCmd/*!*/ a = new AssertRequiresCmd(this, reqCopy); + Contract.Assert(a != null); + if (Attributes != null) + { + // Inherit attributes of call. + var attrCopy = (QKeyValue)cce.NonNull(Attributes.Clone()); + attrCopy = Substituter.Apply(s, attrCopy); + a.Attributes = attrCopy; + } + a.ErrorDataEnhanced = reqCopy.ErrorDataEnhanced; + newBlockBody.Add(a); + } + } + else if (CommandLineOptions.Clo.StratifiedInlining > 0) + { + // inject free requires as assume statements at the call site + AssumeCmd/*!*/ a = new AssumeCmd(req.tok, Substituter.Apply(s, req.Condition)); + Contract.Assert(a != null); + newBlockBody.Add(a); + } + } + if (hasWildcard) { + if (preConjunction == null) { + preConjunction = Expr.True; + } + Expr/*!*/ expr = new ExistsExpr(tok, wildcardVars, preConjunction); + Contract.Assert(expr != null); + AssertCmd/*!*/ a = new AssertCmd(tok, expr); + Contract.Assert(a != null); + if (Attributes != null) + { + // Inherit attributes of call. + var attrCopy = (QKeyValue)cce.NonNull(Attributes.Clone()); + attrCopy = Substituter.Apply(s, attrCopy); + a.Attributes = attrCopy; + } + a.ErrorDataEnhanced = AssertCmd.GenerateBoundVarMiningStrategy(expr); + newBlockBody.Add(a); + } + #endregion + + #region assume Pre[ins := cins] with formal paramters + if (hasWildcard) { + s = Substituter.SubstitutionFromHashtable(substMap); + for (int i = 0; i < this.Proc.Requires.Count; i++) { + Requires/*!*/ req = cce.NonNull(this.Proc.Requires[i]); + if (!req.Free) { + Requires/*!*/ reqCopy = (Requires/*!*/)cce.NonNull(req.Clone()); + reqCopy.Condition = Substituter.Apply(s, req.Condition); + AssumeCmd/*!*/ a = new AssumeCmd(tok, reqCopy.Condition); + Contract.Assert(a != null); + newBlockBody.Add(a); + } + } + } + #endregion + + #region cframe := frame (to hold onto frame values in case they are referred to in the postcondition) + List havocVarExprs = new List(); + + foreach (IdentifierExpr/*!*/ f in this.Proc.Modifies) { + Contract.Assert(f != null); + Contract.Assume(f.Decl != null); + Contract.Assert(f.Type != null); + Variable v = CreateTemporaryVariable(tempVars, f.Decl, f.Type, TempVarKind.Old, ref uniqueId); + IdentifierExpr v_exp = new IdentifierExpr(v.tok, v); + substMapOld.Add(f.Decl, v_exp); // this assumes no duplicates in this.Proc.Modifies + AssignCmd assign = Cmd.SimpleAssign(f.tok, v_exp, f); + newBlockBody.Add(assign); + + // fra + if (!havocVarExprs.Contains(f)) + havocVarExprs.Add(f); + } + #endregion + #region Create couts + List/*!*/ couts = new List(); + for (int i = 0; i < this.Proc.OutParams.Count; ++i) { + Variable/*!*/ param = cce.NonNull(this.Proc.OutParams[i]); + bool isWildcard = this.Outs[i] == null; + + Type/*!*/ actualType; + if (isWildcard) + actualType = param.TypedIdent.Type.Substitute(TypeParamSubstitution()); + else + // during type checking, we have ensured that the type of the actual + // out parameter Outs[i] is correct, so we can use it here + actualType = cce.NonNull(cce.NonNull(Outs[i]).Type); + + Variable cout = CreateTemporaryVariable(tempVars, param, actualType, + TempVarKind.Formal, ref uniqueId); + couts.Add(cout); + IdentifierExpr ie = new IdentifierExpr(cout.tok, cout); + substMap.Add(param, ie); + + if (!havocVarExprs.Contains(ie)) + havocVarExprs.Add(ie); + } + // add the where clauses, now that we have the entire substitution map + foreach (Variable/*!*/ param in this.Proc.OutParams) { + Contract.Assert(param != null); + Expr w = param.TypedIdent.WhereExpr; + if (w != null) { + IdentifierExpr ie = (IdentifierExpr/*!*/)cce.NonNull(substMap[param]); + Contract.Assert(ie.Decl != null); + ie.Decl.TypedIdent.WhereExpr = Substituter.Apply(Substituter.SubstitutionFromHashtable(substMap), w); + } + } + #endregion + + #region havoc frame, couts + // pass on this's token + HavocCmd hc = new HavocCmd(this.tok, havocVarExprs); + newBlockBody.Add(hc); + #endregion + + #region assume Post[ins, outs, old(frame) := cins, couts, cframe] + calleeSubstitution = Substituter.SubstitutionFromHashtable(substMap, true, Proc); + calleeSubstitutionOld = Substituter.SubstitutionFromHashtable(substMapOld, true, Proc); + foreach (Ensures/*!*/ e in this.Proc.Ensures) { + Contract.Assert(e != null); + Expr copy = Substituter.ApplyReplacingOldExprs(calleeSubstitution, calleeSubstitutionOld, e.Condition); + AssumeCmd assume = new AssumeCmd(this.tok, copy); + #region stratified inlining support + if (QKeyValue.FindBoolAttribute(e.Attributes, "si_fcall")) + { + assume.Attributes = Attributes; + } + if (QKeyValue.FindBoolAttribute(e.Attributes, "candidate")) + { + assume.Attributes = new QKeyValue(Token.NoToken, "candidate", new List(), assume.Attributes); + assume.Attributes.AddParam(this.callee); + } + #endregion + newBlockBody.Add(assume); + } + #endregion + + #region aouts := couts + for (int i = 0, n = this.Outs.Count; i < n; i++) { + if (this.Outs[i] != null) { + Variable/*!*/ param_i = cce.NonNull(this.Proc.OutParams[i]); + Expr/*!*/ cout_exp = new IdentifierExpr(cce.NonNull(couts[i]).tok, cce.NonNull(couts[i])); + Contract.Assert(cout_exp != null); + AssignCmd assign = Cmd.SimpleAssign(param_i.tok, cce.NonNull(this.Outs[i]), cout_exp); + newBlockBody.Add(assign); + } + } + #endregion + #endregion + + return new StateCmd(this.tok, tempVars, newBlockBody); + } + + class NameEqualityComparer : EqualityComparer + { + public override bool Equals(IdentifierExpr x, IdentifierExpr y) + { + return x.Name.Equals(y.Name); + } + + public override int GetHashCode(IdentifierExpr obj) + { + return obj.Name.GetHashCode(); + } + } + + NameEqualityComparer comparer = new NameEqualityComparer(); + + public Substitution calleeSubstitution; + public Substitution calleeSubstitutionOld; + + public IEnumerable UnmodifiedBefore(Procedure oldProcedure) + { + Contract.Requires(oldProcedure != null); + + return Proc.Modifies.Except(oldProcedure.Modifies, comparer).Select(e => new IdentifierExpr(Token.NoToken, e.Decl)); + } + + public IEnumerable ModifiedBefore(Procedure oldProcedure) + { + Contract.Requires(oldProcedure != null); + + return oldProcedure.Modifies.Except(Proc.Modifies, comparer).Select(e => new IdentifierExpr(Token.NoToken, e.Decl)); + } + + public Expr Postcondition(Procedure procedure, List modifies, Dictionary oldSubst, Program program, Func extract) + { + Contract.Requires(calleeSubstitution != null && calleeSubstitutionOld != null && modifies != null && oldSubst != null && program != null && extract != null); + + Substitution substOldCombined = v => { Expr s; if (oldSubst.TryGetValue(v, out s)) { return s; } return calleeSubstitutionOld(v); }; + + var clauses = procedure.Ensures.Select(e => Substituter.FunctionCallReresolvingApplyReplacingOldExprs(calleeSubstitution, substOldCombined, e.Condition, program)).Concat(modifies); + // TODO(wuestholz): Try extracting a function for each clause: + // return Conjunction(clauses.Select(c => extract(c))); + var conj = Expr.And(clauses, true); + return conj != null ? extract(conj) : conj; + } + + public Expr CheckedPrecondition(Procedure procedure, Program program, Func extract) + { + Contract.Requires(calleeSubstitution != null && calleeSubstitutionOld != null && program != null && extract != null); + + var clauses = procedure.Requires.Where(r => !r.Free).Select(r => Substituter.FunctionCallReresolvingApplyReplacingOldExprs(calleeSubstitution, calleeSubstitutionOld, r.Condition, program)); + // TODO(wuestholz): Try extracting a function for each clause: + // return Conjunction(clauses.Select(c => extract(c))); + var conj = Expr.And(clauses, true); + return conj != null ? extract(conj) : conj; + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitCallCmd(this); + } + } + + public abstract class PredicateCmd : Cmd { + public QKeyValue Attributes; + public /*readonly--except in StandardVisitor*/ Expr/*!*/ Expr; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Expr != null); + } + + public PredicateCmd(IToken/*!*/ tok, Expr/*!*/ expr) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + Expr = expr; + } + public PredicateCmd(IToken/*!*/ tok, Expr/*!*/ expr, QKeyValue kv) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + Expr = expr; + Attributes = kv; + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + Expr.Resolve(rc); + + var id = QKeyValue.FindStringAttribute(Attributes, "id"); + if (id != null) + { + rc.AddStatementId(tok, id); + } + } + public override void AddAssignedVariables(List vars) { + //Contract.Requires(vars != null); + } + } + + public abstract class MiningStrategy { + // abstract class to bind all MiningStrategys, i.e., all types of enhanced error data + // types together + } + + public class ListOfMiningStrategies : MiningStrategy { + + private List/*!*/ _msList; + + public List/*!*/ msList + { + get + { + Contract.Ensures(Contract.Result>() != null); + return this._msList; + } + set + { + Contract.Requires(value != null); + this._msList = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._msList != null); + } + + public ListOfMiningStrategies(List l) { + Contract.Requires(l != null); + this._msList = l; + } + } + + public class EEDTemplate : MiningStrategy { + private string/*!*/ _reason; + public string/*!*/ reason + { + get + { + Contract.Ensures(Contract.Result() != null); + return this._reason; + } + set + { + Contract.Requires(value != null); + this._reason = value; + } + } + + private List/*!*/ exprList; + public IEnumerable Expressions + { + get + { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return this.exprList.AsReadOnly(); + } + set + { + Contract.Requires(cce.NonNullElements(value)); + this.exprList = new List(value); + } + } + + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._reason != null); + Contract.Invariant(cce.NonNullElements(this.exprList)); + } + + public EEDTemplate(string reason, List/*!*/ exprList) { + Contract.Requires(reason != null); + Contract.Requires(cce.NonNullElements(exprList)); + this._reason = reason; + this.exprList = exprList; + } + } + + public class AssertCmd : PredicateCmd, IPotentialErrorNode + { + public Expr OrigExpr; + public Dictionary IncarnationMap; + + Expr verifiedUnder; + public Expr VerifiedUnder + { + get + { + if (verifiedUnder != null) + { + return verifiedUnder; + } + verifiedUnder = QKeyValue.FindExprAttribute(Attributes, "verified_under"); + return verifiedUnder; + } + } + + public void MarkAsVerifiedUnder(Expr expr) + { + Attributes = new QKeyValue(tok, "verified_under", new List { expr }, Attributes); + verifiedUnder = expr; + } + + // TODO: convert to use generics + private object errorData; + public object ErrorData { + get { + return errorData; + } + set { + errorData = value; + } + } + + public string ErrorMessage { + get { + return QKeyValue.FindStringAttribute(Attributes, "msg"); + } + } + + private MiningStrategy errorDataEnhanced; + public MiningStrategy ErrorDataEnhanced { + get { + return errorDataEnhanced; + } + set { + errorDataEnhanced = value; + } + } + + public AssertCmd(IToken/*!*/ tok, Expr/*!*/ expr) + : base(tok, expr) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + errorDataEnhanced = GenerateBoundVarMiningStrategy(expr); + } + + public AssertCmd(IToken/*!*/ tok, Expr/*!*/ expr, QKeyValue kv) + : base(tok, expr, kv) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + errorDataEnhanced = GenerateBoundVarMiningStrategy(expr); + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "assert "); + EmitAttributes(stream, Attributes); + this.Expr.Emit(stream); + stream.WriteLine(";"); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + ResolveAttributes(Attributes, rc); + base.Resolve(rc); + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + TypecheckAttributes(Attributes, tc); + Expr.Typecheck(tc); + Contract.Assert(Expr.Type != null); // follows from Expr.Typecheck postcondition + if (!Expr.Type.Unify(Type.Bool)) { + tc.Error(this, "an asserted expression must be of type bool (got: {0})", Expr.Type); + } + } + + public static MiningStrategy GenerateBoundVarMiningStrategy(Expr expr) { + Contract.Requires(expr != null); + List l = new List(); + if (expr != null) { + l = GenerateBoundVarListForMining(expr, l); + } + return new ListOfMiningStrategies(l); + } + + public static List/*!*/ GenerateBoundVarListForMining(Expr expr, List l) { + Contract.Requires(l != null); + Contract.Requires(expr != null); + Contract.Ensures(Contract.Result>() != null); + + // go through the origExpr and identify all bound variables in the AST. + if (expr is LiteralExpr || expr is IdentifierExpr) { + //end recursion + } else if (expr is NAryExpr) { + NAryExpr e = (NAryExpr)expr; + foreach (Expr/*!*/ arg in e.Args) { + Contract.Assert(arg != null); + l = GenerateBoundVarListForMining(arg, l); + } + } else if (expr is OldExpr) { + OldExpr e = (OldExpr)expr; + l = GenerateBoundVarListForMining(e.Expr, l); + } else if (expr is QuantifierExpr) { + QuantifierExpr qe = (QuantifierExpr)expr; + List vs = qe.Dummies; + foreach (Variable/*!*/ x in vs) { + Contract.Assert(x != null); + string name = x.Name; + if (name.StartsWith("^")) { + name = name.Substring(1); + List exprList = new List(); + exprList.Add(new IdentifierExpr(Token.NoToken, x.ToString(), x.TypedIdent.Type)); + MiningStrategy eed = new EEDTemplate("The bound variable " + name + " has the value {0}.", exprList); + l.Add(eed); + } + } + l = GenerateBoundVarListForMining(qe.Body, l); + } + return l; + } + + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitAssertCmd(this); + } + } + + // An AssertCmd that is a loop invariant check before the loop iteration starts + public class LoopInitAssertCmd : AssertCmd { + public LoopInitAssertCmd(IToken/*!*/ tok, Expr/*!*/ expr) + : base(tok, expr) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + } + } + + // An AssertCmd that is a loop invariant check to maintain the invariant after iteration + public class LoopInvMaintainedAssertCmd : AssertCmd { + public LoopInvMaintainedAssertCmd(IToken/*!*/ tok, Expr/*!*/ expr) + : base(tok, expr) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + } + } + + /// + /// An AssertCmd that is introduced in translation from the requires on a call. + /// + public class AssertRequiresCmd : AssertCmd { + public CallCmd/*!*/ Call; + public Requires/*!*/ Requires; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Call != null); + Contract.Invariant(Requires != null); + } + + + public AssertRequiresCmd(CallCmd/*!*/ call, Requires/*!*/ requires) + : base(call.tok, requires.Condition) { + Contract.Requires(call != null); + Contract.Requires(requires != null); + this.Call = call; + this.Requires = requires; + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitAssertRequiresCmd(this); + } + } + + /// + /// An AssertCmd that is introduced in translation from an ensures + /// declaration. + /// + public class AssertEnsuresCmd : AssertCmd { + public Ensures/*!*/ Ensures; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Ensures != null); + } + + public AssertEnsuresCmd(Ensures/*!*/ ens) + : base(ens.tok, ens.Condition) { + Contract.Requires(ens != null); + this.Ensures = ens; + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitAssertEnsuresCmd(this); + } + } + + public class AssumeCmd : PredicateCmd { + public AssumeCmd(IToken/*!*/ tok, Expr/*!*/ expr) + : base(tok, expr) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + } + public AssumeCmd(IToken/*!*/ tok, Expr/*!*/ expr, QKeyValue kv) + : base(tok, expr, kv) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + } + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "assume "); + EmitAttributes(stream, Attributes); + this.Expr.Emit(stream); + stream.WriteLine(";"); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + ResolveAttributes(Attributes, rc); + base.Resolve(rc); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + TypecheckAttributes(Attributes, tc); + Expr.Typecheck(tc); + Contract.Assert(Expr.Type != null); // follows from Expr.Typecheck postcondition + if (!Expr.Type.Unify(Type.Bool)) { + tc.Error(this, "an assumed expression must be of type bool (got: {0})", Expr.Type); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitAssumeCmd(this); + } + } + + public class ReturnExprCmd : ReturnCmd { + public Expr/*!*/ Expr; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Expr != null); + } + + public ReturnExprCmd(IToken/*!*/ tok, Expr/*!*/ expr) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + Expr = expr; + } + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "return "); + this.Expr.Emit(stream); + stream.WriteLine(";"); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + Expr.Typecheck(tc); + Contract.Assert(Expr.Type != null); // follows from Expr.Typecheck postcondition + if (!Expr.Type.Unify(Type.Bool)) { + tc.Error(this, "a return expression must be of type bool (got: {0})", Expr.Type); + } + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + Expr.Resolve(rc); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitReturnExprCmd(this); + } + } + + public class HavocCmd : Cmd { + private List/*!*/ _vars; + + public List/*!*/ Vars { + get { + Contract.Ensures(Contract.Result>() != null); + return this._vars; + } + set { + Contract.Requires(value != null); + this._vars = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._vars != null); + } + + public HavocCmd(IToken/*!*/ tok, List/*!*/ vars) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(vars != null); + this._vars = vars; + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "havoc "); + Vars.Emit(stream, true); + stream.WriteLine(";"); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + foreach (IdentifierExpr/*!*/ ide in Vars) { + Contract.Assert(ide != null); + ide.Resolve(rc); + } + } + public override void AddAssignedVariables(List vars) { + //Contract.Requires(vars != null); + foreach (IdentifierExpr/*!*/ e in this.Vars) { + Contract.Assert(e != null); + vars.Add(e.Decl); + } + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + foreach (IdentifierExpr ie in Vars) + { + ie.Typecheck(tc); + } + this.CheckAssignments(tc); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitHavocCmd(this); + } + } + + //--------------------------------------------------------------------- + // Transfer commands + [ContractClass(typeof(TransferCmdContracts))] + public abstract class TransferCmd : Absy { + internal TransferCmd(IToken/*!*/ tok) + : base(tok) { + Contract.Requires(tok != null); + } + public abstract void Emit(TokenTextWriter/*!*/ stream, int level); + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + // nothing to typecheck + } + + public override string ToString() + { + Contract.Ensures(Contract.Result() != null); + System.IO.StringWriter buffer = new System.IO.StringWriter(); + using (TokenTextWriter stream = new TokenTextWriter("", buffer, /*setTokens=*/ false , /*pretty=*/ false)) { + this.Emit(stream, 0); + } + return buffer.ToString(); + } + } + [ContractClassFor(typeof(TransferCmd))] + public abstract class TransferCmdContracts : TransferCmd { + public TransferCmdContracts() :base(null){ + + } + public override void Emit(TokenTextWriter stream, int level) { + Contract.Requires(stream != null); + throw new NotImplementedException(); + } + } + + public class ReturnCmd : TransferCmd { + public ReturnCmd(IToken/*!*/ tok) + : base(tok) { + Contract.Requires(tok != null); + } + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.WriteLine(this, level, "return;"); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + // nothing to resolve + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitReturnCmd(this); + } + } + + public class GotoCmd : TransferCmd { + [Rep] + public List labelNames; + [Rep] + public List labelTargets; + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(labelNames == null || labelTargets == null || labelNames.Count == labelTargets.Count); + } + + [NotDelayed] + public GotoCmd(IToken/*!*/ tok, List/*!*/ labelSeq) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(labelSeq != null); + this.labelNames = labelSeq; + } + public GotoCmd(IToken/*!*/ tok, List/*!*/ labelSeq, List/*!*/ blockSeq) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(labelSeq != null); + Contract.Requires(blockSeq != null); + Debug.Assert(labelSeq.Count == blockSeq.Count); + for (int i = 0; i < labelSeq.Count; i++) { + Debug.Assert(Equals(labelSeq[i], cce.NonNull(blockSeq[i]).Label)); + } + + this.labelNames = labelSeq; + this.labelTargets = blockSeq; + } + public GotoCmd(IToken/*!*/ tok, List/*!*/ blockSeq) + : base(tok) { //requires (blockSeq[i] != null ==> blockSeq[i].Label != null); + Contract.Requires(tok != null); + Contract.Requires(blockSeq != null); + List labelSeq = new List(); + for (int i = 0; i < blockSeq.Count; i++) + labelSeq.Add(cce.NonNull(blockSeq[i]).Label); + this.labelNames = labelSeq; + this.labelTargets = blockSeq; + } + public void AddTarget(Block b) { + Contract.Requires(b != null); + Contract.Requires(b.Label != null); + Contract.Requires(this.labelTargets != null); + Contract.Requires(this.labelNames != null); + this.labelTargets.Add(b); + this.labelNames.Add(b.Label); + } + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + Contract.Assume(this.labelNames != null); + stream.Write(this, level, "goto "); + if (CommandLineOptions.Clo.PrintWithUniqueASTIds) { + if (labelTargets == null) { + string sep = ""; + foreach (string name in labelNames) { + stream.Write("{0}{1}^^{2}", sep, "NoDecl", name); + sep = ", "; + } + } else { + string sep = ""; + foreach (Block/*!*/ b in labelTargets) { + Contract.Assert(b != null); + stream.Write("{0}h{1}^^{2}", sep, b.GetHashCode(), b.Label); + sep = ", "; + } + } + } else { + labelNames.Emit(stream); + } + stream.WriteLine(";"); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + Contract.Ensures(labelTargets != null); + if (labelTargets != null) { + // already resolved + return; + } + Contract.Assume(this.labelNames != null); + labelTargets = new List(); + foreach (string/*!*/ lbl in labelNames) { + Contract.Assert(lbl != null); + Block b = rc.LookUpBlock(lbl); + if (b == null) { + rc.Error(this, "goto to unknown block: {0}", lbl); + } else { + labelTargets.Add(b); + } + } + Debug.Assert(rc.ErrorCount > 0 || labelTargets.Count == labelNames.Count); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitGotoCmd(this); + } + } +} diff --git a/Source/Core/AbsyExpr.cs b/Source/Core/AbsyExpr.cs index 6b2e1201..b980a22b 100644 --- a/Source/Core/AbsyExpr.cs +++ b/Source/Core/AbsyExpr.cs @@ -1,3320 +1,3351 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -//--------------------------------------------------------------------------------------------- -// BoogiePL - Absy.cs -//--------------------------------------------------------------------------------------------- - -namespace Microsoft.Boogie { - using System; - using System.Collections; - using System.Diagnostics; - using System.Collections.Generic; - using Microsoft.Boogie.AbstractInterpretation; - using System.Diagnostics.Contracts; - using System.Linq; - using Microsoft.Basetypes; - - using Set = GSet; // not that the set used is not a set of Variable only, as it also contains TypeVariables - - - //--------------------------------------------------------------------- - // Expressions - // - // For expressions, we override the Equals and GetHashCode method to - // implement structural equality. Note this is not logical equivalence - // and is not modulo alpha-renaming. - //--------------------------------------------------------------------- - - - [ContractClass(typeof(ExprContracts))] - public abstract class Expr : Absy { - public Expr(IToken/*!*/ tok, bool immutable) - : base(tok) { - Contract.Requires(tok != null); - this.Immutable = immutable; - } - - public void Emit(TokenTextWriter stream) { - Contract.Requires(stream != null); - Emit(stream, 0, false); - } - - /// - /// If true the client is making a promise that this Expr will be - /// treated immutably (i.e. once constructed it is never changed). - /// This is currently not enforced but it should be! - /// - /// This allows the Expr's hash code to be cached making calls to - /// GetHashCode() very cheap. - /// - /// true if immutable; otherwise, false. - public bool Immutable { - get; - private set; - } - - /// - /// Computes the hash code of this Expr skipping any cache. - /// - /// Sub classes should place their implementation of computing their hashcode - /// here (making sure to call GetHashCode() not ComputeHashCode() on Expr for performance reasons) - /// and have GetHashCode() use a cached result from ComputeHashCode() if the - /// Expr was constructed to be immutable. - /// - /// The hash code. - public abstract int ComputeHashCode(); - protected int CachedHashCode = 0; - - public abstract void Emit(TokenTextWriter/*!*/ wr, int contextBindingStrength, bool fragileContext); - - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - System.IO.StringWriter buffer = new System.IO.StringWriter(); - using (TokenTextWriter stream = new TokenTextWriter("", buffer, /*setTokens=*/ false, /*pretty=*/ false)) { - this.Emit(stream, 0, false); - } - return buffer.ToString(); - } - - /// - /// Add to "freeVars" the free variables in the expression. - /// - public abstract void ComputeFreeVariables(Set /*Variable*//*!*/ freeVars); - - /// - /// Filled in by the Typecheck method. A value of "null" means a succeeding - /// call to Typecheck has not taken place (that is, either Typecheck hasn't - /// been called or Typecheck encountered an error in the expression to be - /// typechecked). - /// - private Type _Type = null; - public Type Type { - get { - return _Type; - } - set { - if (_Type == null) { - // Expr has never been type checked so always allow this - _Type = value; - } else { - if (Immutable && !_Type.Equals(value)) - throw new InvalidOperationException("Cannot change the Type of an Immutable Expr"); - - // Once the Type has been set (i.e. no longer null) we never change the reference - // if this Expr is immutable, even if the Type is equivalent (i.e. _Type.Equals(newType)) - if (!Immutable) - _Type = value; - } - } - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - Contract.Ensures(Type != null); - // This body is added only because C# insists on it. It should really be left out, as if TypeCheck still were abstract. - // The reason for mentioning the method here at all is to give TypeCheck a postcondition for all expressions. - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } - } - - /// - /// Returns the type of the expression, supposing that all its subexpressions are well typed. - /// - public abstract Type/*!*/ ShallowType { - get; - } - - // Handy syntactic sugar follows: - - public static NAryExpr Unary(IToken x, UnaryOperator.Opcode op, Expr e1) { - Contract.Requires(e1 != null); - Contract.Requires(x != null); - Contract.Ensures(Contract.Result() != null); - return new NAryExpr(x, new UnaryOperator(x, op), new List { e1 }); - } - - public static NAryExpr Binary(IToken x, BinaryOperator.Opcode op, Expr e0, Expr e1) { - Contract.Requires(e1 != null); - Contract.Requires(e0 != null); - Contract.Requires(x != null); - Contract.Ensures(Contract.Result() != null); - return new NAryExpr(x, new BinaryOperator(x, op), new List { e0, e1 }); - } - - public static NAryExpr Binary(BinaryOperator.Opcode op, Expr e0, Expr e1) { - Contract.Requires(e1 != null); - Contract.Requires(e0 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(Token.NoToken, op, e0, e1); - } - - public static NAryExpr Eq(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Eq, e1, e2); - } - public static NAryExpr Neq(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Neq, e1, e2); - } - public static NAryExpr Le(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Le, e1, e2); - } - public static NAryExpr Ge(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Ge, e1, e2); - } - public static NAryExpr Lt(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Lt, e1, e2); - } - public static NAryExpr Gt(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Gt, e1, e2); - } - public static Expr And(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - if (e1 == true_) { - return e2; - } else if (e2 == true_) { - return e1; - } else if (e1 == false_ || e2 == false_) { - return false_; - } else { - var res = Binary(BinaryOperator.Opcode.And, e1, e2); - res.Type = Microsoft.Boogie.Type.Bool; - res.TypeParameters = SimpleTypeParamInstantiation.EMPTY; - return res; - } - } - public static Expr Or(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - if (e1 == false_) { - return e2; - } else if (e2 == false_) { - return e1; - } else if (e1 == true_ || e2 == true_) { - return true_; - } else { - return Binary(BinaryOperator.Opcode.Or, e1, e2); - } - } - public static Expr Not(Expr e1) { - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - NAryExpr nary = e1 as NAryExpr; - - if (e1 == true_) { - return false_; - } else if (e1 == false_) { - return true_; - } else if (nary != null) { - if (nary.Fun is UnaryOperator) { - UnaryOperator op = (UnaryOperator)nary.Fun; - if (op.Op == UnaryOperator.Opcode.Not) { - return cce.NonNull(nary.Args[0]); - } - } else if (nary.Fun is BinaryOperator) { - BinaryOperator op = (BinaryOperator)nary.Fun; - Expr arg0 = cce.NonNull(nary.Args[0]); - Expr arg1 = cce.NonNull(nary.Args[1]); - if (op.Op == BinaryOperator.Opcode.Eq) { - return Neq(arg0, arg1); - } else if (op.Op == BinaryOperator.Opcode.Neq) { - return Eq(arg0, arg1); - } else if (op.Op == BinaryOperator.Opcode.Lt) { - return Le(arg1, arg0); - } else if (op.Op == BinaryOperator.Opcode.Le) { - return Lt(arg1, arg0); - } else if (op.Op == BinaryOperator.Opcode.Ge) { - return Gt(arg1, arg0); - } else if (op.Op == BinaryOperator.Opcode.Gt) { - return Ge(arg1, arg0); - } - } - } - - return Unary(Token.NoToken, UnaryOperator.Opcode.Not, e1); - } - - public static Expr Neg(Expr e1) { - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Unary(Token.NoToken, UnaryOperator.Opcode.Neg, e1); - } - - public static NAryExpr Imp(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Imp, e1, e2); - } - public static NAryExpr Iff(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Iff, e1, e2); - } - public static NAryExpr Add(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Add, e1, e2); - } - public static NAryExpr Sub(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Sub, e1, e2); - } - public static NAryExpr Mul(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Mul, e1, e2); - } - public static NAryExpr Div(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Div, e1, e2); - } - public static NAryExpr Mod(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Mod, e1, e2); - } - public static NAryExpr RealDiv(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.RealDiv, e1, e2); - } - public static NAryExpr FloatDiv(Expr e1, Expr e2) - { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.FloatDiv, e1, e2); - } - public static NAryExpr Pow(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Pow, e1, e2); - } - public static NAryExpr Subtype(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Subtype, e1, e2); - } - - public static IdentifierExpr Ident(string name, Type type) { - Contract.Requires(type != null); - Contract.Requires(name != null); - Contract.Ensures(Contract.Result() != null); - return new IdentifierExpr(Token.NoToken, name, type); - } - - public static IdentifierExpr Ident(Variable decl) { - Contract.Requires(decl != null); - Contract.Ensures(Contract.Result() != null); - IdentifierExpr result = new IdentifierExpr(Token.NoToken, decl); - return result; - } - - public static LiteralExpr Literal(bool value) { - Contract.Ensures(Contract.Result() != null); - return new LiteralExpr(Token.NoToken, value); - } - public static LiteralExpr Literal(int value) { - Contract.Ensures(Contract.Result() != null); - return new LiteralExpr(Token.NoToken, BigNum.FromInt(value)); - } - public static LiteralExpr Literal(BigNum value) { - Contract.Ensures(Contract.Result() != null); - return new LiteralExpr(Token.NoToken, value); - } - public static LiteralExpr Literal(BigDec value) { - Contract.Ensures(Contract.Result() != null); - return new LiteralExpr(Token.NoToken, value); - } - public static LiteralExpr Literal(BigFloat value) - { - Contract.Ensures(Contract.Result() != null); - return new LiteralExpr(Token.NoToken, value); - } - - private static LiteralExpr/*!*/ true_ = Literal(true); - public static LiteralExpr/*!*/ True { - get { - Contract.Ensures(Contract.Result() != null); - return true_; - } - } - - private static LiteralExpr/*!*/ false_ = Literal(false); - public static LiteralExpr/*!*/ False { - get { - Contract.Ensures(Contract.Result() != null); - return false_; - } - } - - - public static NAryExpr Select(Expr map, params Expr[] args) { - Contract.Requires(args != null); - Contract.Requires(map != null); - Contract.Ensures(Contract.Result() != null); - return SelectTok(Token.NoToken, map, args); - } - - public static NAryExpr Select(Expr map, List/*!*/ args) { - Contract.Requires(map != null); - Contract.Requires(cce.NonNullElements(args)); - Contract.Ensures(Contract.Result() != null); - return Select(map, args.ToArray()); - } - - // use a different name for this variant of the method - // (-> some bug prevents overloading in this case) - public static NAryExpr SelectTok(IToken x, Expr map, params Expr[] args) { - Contract.Requires(args != null); - Contract.Requires(map != null); - Contract.Requires(x != null); - Contract.Ensures(Contract.Result() != null); - List/*!*/ allArgs = new List(); - allArgs.Add(map); - foreach (Expr/*!*/ a in args) { - Contract.Assert(a != null); - allArgs.Add(a); - } - return new NAryExpr(x, new MapSelect(Token.NoToken, args.Length), allArgs); - } - - public static NAryExpr Store(Expr map, params Expr[] args) { - Contract.Requires(args != null); - Contract.Requires(map != null); - Contract.Ensures(Contract.Result() != null); - return StoreTok(Token.NoToken, map, args); - } - - public static NAryExpr Store(Expr map, List/*!*/ indexes, Expr rhs) { - Contract.Requires(rhs != null); - Contract.Requires(map != null); - Contract.Requires(cce.NonNullElements(indexes)); - Contract.Ensures(Contract.Result() != null); - Expr[]/*!*/ allArgs = new Expr[indexes.Count + 1]; - for (int i = 0; i < indexes.Count; ++i) - allArgs[i] = indexes[i]; - allArgs[indexes.Count] = rhs; - return Store(map, allArgs); - } - - // use a different name for this variant of the method - // (-> some bug prevents overloading in this case) - public static NAryExpr/*!*/ StoreTok(IToken x, Expr map, params Expr[] args) { - Contract.Requires(args != null); - Contract.Requires(map != null); - Contract.Requires(x != null); - Contract.Requires(args.Length > 0); // zero or more indices, plus the value - Contract.Ensures(Contract.Result() != null); - - List/*!*/ allArgs = new List(); - allArgs.Add(map); - foreach (Expr/*!*/ a in args) { - Contract.Assert(a != null); - allArgs.Add(a); - } - return new NAryExpr(x, new MapStore(Token.NoToken, args.Length - 1), allArgs); - } - - public static NAryExpr CoerceType(IToken x, Expr subexpr, Type type) { - Contract.Requires(type != null); - Contract.Requires(subexpr != null); - Contract.Requires(x != null); - Contract.Ensures(Contract.Result() != null); - List/*!*/ args = new List(); - args.Add(subexpr); - return new NAryExpr(x, new TypeCoercion(x, type), args); - } - - public static Expr BinaryTreeAnd(List terms) - { - return BinaryTreeAnd(terms, 0, terms.Count - 1); - } - - private static Expr BinaryTreeAnd(List terms, int start, int end) - { - if (start > end) - return Expr.True; - if (start == end) - return terms[start]; - if (start + 1 == end) - return Expr.And(terms[start], terms[start + 1]); - var mid = (start + end) / 2; - return Expr.And(BinaryTreeAnd(terms, start, mid), BinaryTreeAnd(terms, mid + 1, end)); - } - } - [ContractClassFor(typeof(Expr))] - public abstract class ExprContracts : Expr { - public ExprContracts() :base(null, /*immutable=*/ false){ - - } - public override void Emit(TokenTextWriter wr, int contextBindingStrength, bool fragileContext) { - Contract.Requires(wr != null); - throw new NotImplementedException(); - } - public override void ComputeFreeVariables(Set freeVars) { - Contract.Requires(freeVars != null); - throw new NotImplementedException(); - } - public override Type ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - throw new NotImplementedException(); - } - } - } - - public class LiteralExpr : Expr { - public readonly object/*!*/ Val; // false, true, a BigNum, a BigDec, a BigFloat, or a BvConst - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Val != null); - } - - /// - /// Creates a literal expression for the boolean value "b". - /// - /// - /// - public LiteralExpr(IToken/*!*/ tok, bool b, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Val = b; - Type = Type.Bool; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - - /// - /// Creates a literal expression for the integer value "v". - /// - /// - /// - public LiteralExpr(IToken/*!*/ tok, BigNum v, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Val = v; - Type = Type.Int; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - - /// - /// Creates a literal expression for the real value "v". - /// - /// - /// - public LiteralExpr(IToken/*!*/ tok, BigDec v, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Val = v; - Type = Type.Real; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - - /// - /// Creates a literal expression for the floating point value "v". - /// - /// - /// - public LiteralExpr(IToken/*!*/ tok, BigFloat v, bool immutable = false) - : base(tok, immutable) - { - Contract.Requires(tok != null); - Val = v; - Type = Type.GetFloatType(v.ExponentSize, v.SignificandSize); - if (immutable) - CachedHashCode = ComputeHashCode(); - } - - /// - /// Creates a literal expression for the bitvector value "v". - /// - public LiteralExpr(IToken/*!*/ tok, BigNum v, int b, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Contract.Requires(0 <= b); - Val = new BvConst(v, b); - Type = Type.GetBvType(b); - if (immutable) - CachedHashCode = ComputeHashCode(); - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is LiteralExpr)) - return false; - - LiteralExpr other = (LiteralExpr)obj; - return object.Equals(this.Val, other.Val); - } - - [Pure] - public override int GetHashCode() { - if (Immutable) - return this.CachedHashCode; - else - return ComputeHashCode(); - } - - [Pure] - public override int ComputeHashCode() { - return this.Val.GetHashCode(); - } - - public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - stream.SetToken(this); - if (this.Val is bool) { - stream.Write((bool)this.Val ? "true" : "false"); // correct capitalization - } else { - stream.Write(cce.NonNull(this.Val.ToString())); - } - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - // nothing to resolve - } - public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { - //Contract.Requires(freeVars != null); - // no free variables to add - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - this.Type = ShallowType; - } - - public override Type/*!*/ ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - if (Val is bool) { - return Type.Bool; - } else if (Val is BigNum) { - return Type.Int; - } else if (Val is BigDec) { - return Type.Real; - } else if (Val is BigFloat) { - BigFloat temp = (BigFloat)Val; - return Type.GetFloatType(temp.ExponentSize, temp.SignificandSize); - } else if (Val is BvConst) { - return Type.GetBvType(((BvConst)Val).Bits); - } else { - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // like, where did this value come from?! - } - } - } - - public bool IsFalse { - get { - return Val is bool && ((bool)Val) == false; - } - } - public bool IsTrue { - get { - return Val is bool && ((bool)Val) == true; - } - } - - // should be eliminated after converting everything to BigNums - private int asInt { - get { - return asBigNum.ToIntSafe; - } - } - - public bool isBigNum { - get { - return Val is BigNum; - } - } - - public BigNum asBigNum { - get { - Contract.Assert(isBigNum); - return (BigNum)cce.NonNull(Val); - } - } - - public bool isBigDec { - get { - return Val is BigDec; - } - } - - public bool isBigFloat - { - get - { - return Val is BigFloat; - } - } - - public BigDec asBigDec { - get { - Contract.Assert(isBigDec); - return (BigDec)cce.NonNull(Val); - } - } - - public BigFloat asBigFloat { - get { - Contract.Assert(isBigFloat); - return (BigFloat)cce.NonNull(Val); - } - } - - public bool isBool { - get { - return Val is bool; - } - } - - public bool asBool { - get { - Contract.Assert(isBool); - return (bool)cce.NonNull(Val); - } - } - - public bool isBvConst { - get { - return Val is BvConst; - } - } - - public BvConst asBvConst { - get { - Contract.Assert(isBvConst); - return (BvConst)cce.NonNull(Val); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitLiteralExpr(this); - } - } - - public class BvConst { - public readonly BigNum Value; - public readonly int Bits; - - public BvConst(BigNum v, int b) { - Contract.Assert(v.Signum >= 0); - Value = v; - Bits = b; - } - - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - return Value + "bv" + Bits; - } - - [Pure] - public string ToReadableString() { - Contract.Ensures(Contract.Result() != null); - if (Value > BigNum.FromInt(10000)) { - string val = cce.NonNull(Value.ToString("x")); - int pos = val.Length % 4; - string res = "0x" + val.Substring(0, pos); - Contract.Assert(res != null); - while (pos < val.Length) { - res += "." + val.Substring(pos, 4); - pos += 4; - } - return res + ".bv" + Bits; - } else - return ToString(); - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - BvConst other = obj as BvConst; - if (other == null) - return false; - - return Bits == other.Bits && Value == other.Value; - } - - [Pure] - public override int GetHashCode() { - unchecked { - return Value.GetHashCode() ^ Bits; - } - } - } - - public class IdentifierExpr : Expr { - private string _Name; - public string Name { // identifier symbol - get { - return _Name; - } - set { - if (Immutable) - throw new InvalidOperationException("Cannot change Name on Immutable Expr"); - - _Name = value; - } - } - private Variable _Decl; - public Variable Decl { // identifier declaration - get { - return _Decl; - } - set { - if (Immutable) - throw new InvalidOperationException("Cannot change Decl on Immutable Expr"); - - _Decl = value; - } - } - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Name != null); - } - - - /// - /// Creates an unresolved identifier expression. This constructor is intended to be called - /// only from within the parser; for use inside the translation, use another constructor, which - /// specifies the type of the expression. - /// - /// - /// - internal IdentifierExpr(IToken/*!*/ tok, string/*!*/ name, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - _Name = name; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - /// - /// Creates an unresolved identifier expression. - /// - /// - /// - /// - public IdentifierExpr(IToken/*!*/ tok, string/*!*/ name, Type/*!*/ type, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - Contract.Requires(type != null); - _Name = name; - Type = type; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - - /// - /// Creates a resolved identifier expression. - /// - /// - /// - public IdentifierExpr(IToken/*!*/ tok, Variable/*!*/ d, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Contract.Requires(d != null); - _Name = cce.NonNull(d.Name); - _Decl = d; - Type = d.TypedIdent.Type; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is IdentifierExpr)) - return false; - - IdentifierExpr other = (IdentifierExpr)obj; - return object.Equals(this.Name, other.Name) && object.Equals(this.Decl, other.Decl); - } - - [Pure] - public override int GetHashCode() { - if (Immutable) - return this.CachedHashCode; - else - return ComputeHashCode(); - } - - [Pure] - public override int ComputeHashCode() { - int h = this.Name == null ? 0 : this.Name.GetHashCode(); - h ^= this.Decl == null ? 0 : this.Decl.GetHashCode(); - return h; - } - - public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - if (CommandLineOptions.Clo.PrintWithUniqueASTIds && !stream.UseForComputingChecksums) { - stream.Write("{0}^^", this.Decl == null ? "NoDecl" : "h" + this.Decl.GetHashCode()); - } - stream.Write(this, "{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - if (Decl != null) { - // already resolved, but re-resolve type just in case it came from an unresolved type - if (Type != null) { - Type = Type.ResolveType(rc); - } - return; - } - Decl = rc.LookUpVariable(Name); - if (Decl == null) { - rc.Error(this, "undeclared identifier: {0}", Name); - } else if (rc.StateMode == ResolutionContext.State.StateLess && Decl is GlobalVariable) { - rc.Error(this, "cannot refer to a global variable in this context: {0}", Name); - } - if (Type != null) { - Type = Type.ResolveType(rc); - } - } - public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { - //Contract.Requires(freeVars != null); - Contract.Assume(this.Decl != null); - freeVars.Add(Decl); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - if (this.Decl != null) { - // sanity check - if (Type != null && !Type.Equals(Decl.TypedIdent.Type)) { - tc.Error(this, "internal error, shallow-type assignment was done incorrectly, {0}:{1} != {2}", - Name, Type, Decl.TypedIdent.Type); - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } - } - Type = Decl.TypedIdent.Type; - } - } - - public override Type/*!*/ ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - Contract.Assert(Type != null); - return Type; - } - } - - public sealed class ConstantFunApp { - private IdentifierExpr/*!*/ identifierExpr; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(identifierExpr != null); - Contract.Invariant(emptyArgs != null); - } - - public IdentifierExpr/*!*/ IdentifierExpr { - get { - Contract.Requires(IdentifierExpr != null); - return identifierExpr; - } - } - - private static IList/*!*/ emptyArgs = ArrayList.ReadOnly(cce.NonNull((IList/*!*/)new ArrayList())); - public IList/*!*/ Arguments { - get { - Contract.Ensures(Contract.Result() != null); - return emptyArgs; - } - } - - public ConstantFunApp(IdentifierExpr ie, Constant c) { - Contract.Requires(c != null); - Contract.Requires(ie != null); - this.identifierExpr = ie; - } - - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitIdentifierExpr(this); - } - } - - public class OldExpr : Expr - { - private Expr _Expr; - public Expr/*!*/ Expr { - get { - return _Expr; - } - set { - if (Immutable) - throw new InvalidOperationException("Cannot change Expr of an Immutable OldExpr"); - - _Expr = value; - } - } - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Expr != null); - } - - public OldExpr(IToken/*!*/ tok, Expr/*!*/ expr, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - _Expr = expr; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is OldExpr)) - return false; - - OldExpr other = (OldExpr)obj; - return object.Equals(this.Expr, other.Expr); - } - [Pure] - public override int GetHashCode() { - if (Immutable) - return this.CachedHashCode; - else - return ComputeHashCode (); - } - public override int ComputeHashCode() { - // FIXME: This is wrong, it's as if the OldExpr node isn't there at all - return this.Expr == null ? 0 : this.Expr.GetHashCode(); - } - - public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - stream.Write(this, "old("); - this.Expr.Emit(stream); - stream.Write(")"); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - if (rc.StateMode != ResolutionContext.State.Two) { - rc.Error(this, "old expressions allowed only in two-state contexts"); - } - Expr.Resolve(rc); - } - public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { - //Contract.Requires(freeVars != null); - Expr.ComputeFreeVariables(freeVars); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - Expr.Typecheck(tc); - Type = Expr.Type; - } - public override Type/*!*/ ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - return Expr.ShallowType; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitOldExpr(this); - } - } - [ContractClass(typeof(IAppliableVisitorContracts<>))] - public interface IAppliableVisitor { - T Visit(UnaryOperator/*!*/ unaryOperator); - T Visit(BinaryOperator/*!*/ binaryOperator); - T Visit(FunctionCall/*!*/ functionCall); - T Visit(MapSelect/*!*/ mapSelect); - T Visit(MapStore/*!*/ mapStore); - T Visit(TypeCoercion/*!*/ typeCoercion); - T Visit(ArithmeticCoercion/*!*/ arithCoercion); - T Visit(IfThenElse/*!*/ ifThenElse); - } - [ContractClassFor(typeof(IAppliableVisitor<>))] - public abstract class IAppliableVisitorContracts : IAppliableVisitor { - - #region IAppliableVisitor Members - - public T Visit(UnaryOperator unaryOperator) { - Contract.Requires(unaryOperator != null); - throw new NotImplementedException(); - } - - public T Visit(BinaryOperator binaryOperator) { - Contract.Requires(binaryOperator != null); - throw new NotImplementedException(); - } - - public T Visit(FunctionCall functionCall) { - Contract.Requires(functionCall != null); - throw new NotImplementedException(); - } - - public T Visit(MapSelect mapSelect) { - Contract.Requires(mapSelect != null); - throw new NotImplementedException(); - } - - public T Visit(MapStore mapStore) { - Contract.Requires(mapStore != null); - throw new NotImplementedException(); - } - - public T Visit(TypeCoercion typeCoercion) { - Contract.Requires(typeCoercion != null); - throw new NotImplementedException(); - } - - public T Visit(ArithmeticCoercion arithCoercion) { - Contract.Requires(arithCoercion != null); - throw new NotImplementedException(); - } - - public T Visit(IfThenElse ifThenElse) { - Contract.Requires(ifThenElse != null); - throw new NotImplementedException(); - } - - #endregion - } - - [ContractClass(typeof(IAppliableContracts))] - public interface IAppliable { - string/*!*/ FunctionName { - get; - } - - /// - /// Emits to "stream" the operator applied to the given arguments. - /// The length of "args" can be anything that the parser allows for this appliable operator - /// (but can be nothing else). - /// - /// - /// - /// - /// - void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, int contextBindingStrength, bool fragileContext); - - void Resolve(ResolutionContext/*!*/ rc, Expr/*!*/ subjectForErrorReporting); - - /// - /// Requires the object to have been properly resolved. - /// - int ArgumentCount { - get; - } - - /// - /// Typechecks the arguments "args" for the Appliable. If the arguments are - /// appropriate, returns the result type; otherwise returns null. - /// As result of the type checking, the values of type parameters of the - /// appliable can be returned (which are then stored in the NAryExpr and later - /// also used in the VCExprAST). - /// Requires the object to have been successfully resolved. - /// Requires args.Length == ArgumentCount. - /// Requires all elements of "args" to have a non-null Type field. - /// - /// - /// - Type Typecheck(IList/*!*/ args, out TypeParamInstantiation/*!*/ tpInstantiation, TypecheckingContext/*!*/ tc); - - // Contract.Requires( Microsoft.SpecSharp.Collections.Reductions.Forall{Expr! arg in args; arg.Type != null}); - - /// - /// Returns the result type of the IAppliable, supposing the argument are of the correct types. - /// - Type/*!*/ ShallowType(IList/*!*/ args); - - T Dispatch(IAppliableVisitor/*!*/ visitor); - } - [ContractClassFor(typeof(IAppliable))] - abstract class IAppliableContracts : IAppliable { - - #region IAppliable Members - - public string FunctionName { - get { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - - public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - Contract.Requires(args != null); - Contract.Requires(stream != null); - throw new NotImplementedException(); - } - - public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { - Contract.Requires(rc != null); - Contract.Requires(subjectForErrorReporting != null); - throw new NotImplementedException(); - } - - public int ArgumentCount { - get { - throw new NotImplementedException(); - } - } - - public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { - Contract.Requires(args != null); - Contract.Requires(tc != null); - Contract.Ensures(Contract.ValueAtReturn(out args) != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - Contract.Ensures(args.Count == Contract.OldValue(args.Count)); - throw new NotImplementedException(); - } - - public Type ShallowType(IList args) { - Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - - throw new NotImplementedException(); - } - - public T Dispatch(IAppliableVisitor visitor) { - Contract.Requires(visitor != null); - throw new NotImplementedException(); - } - - #endregion - } - - - [ContractClass(typeof(IOverloadedAppliableContracts))] - public interface IOverloadedAppliable { - void ResolveOverloading(NAryExpr/*!*/ expr); - bool DoNotResolveOverloading { get; set; } - } - [ContractClassFor(typeof(IOverloadedAppliable))] - public abstract class IOverloadedAppliableContracts : IOverloadedAppliable { - - #region IOverloadedAppliable Members - - void IOverloadedAppliable.ResolveOverloading(NAryExpr expr) { - Contract.Requires(expr != null); - throw new NotImplementedException(); - } - - public bool DoNotResolveOverloading - { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } - } - - #endregion - } - - public class UnaryOperator : IAppliable { - private IToken/*!*/ tok; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(tok != null); - } - - public enum Opcode { - Neg, - Not - }; - private Opcode op; - public Opcode Op { - get { - return op; - } - } - public UnaryOperator(IToken tok, Opcode op) { - Contract.Requires(tok != null); - this.tok = tok; - this.op = op; - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is UnaryOperator)) - return false; - - UnaryOperator other = (UnaryOperator)obj; - return object.Equals(this.op, other.op); - } - [Pure] - public override int GetHashCode() { - return (int)this.op; - } - - public string/*!*/ FunctionName { - get { - Contract.Ensures(Contract.Result() != null); - - switch (this.op) { - case Opcode.Neg: - return "-"; - case Opcode.Not: - return "!"; - } - System.Diagnostics.Debug.Fail("unknown unary operator: " + op.ToString()); - throw new Exception(); - } - } - - public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - //Contract.Requires(args != null); - stream.SetToken(ref this.tok); - Contract.Assert(args.Count == 1); - // determine if parens are needed - int opBindingStrength = 0x70; - bool parensNeeded = opBindingStrength < contextBindingStrength || - (fragileContext && opBindingStrength == contextBindingStrength); - - if (parensNeeded) { - stream.Write("("); - } - stream.Write(FunctionName); - cce.NonNull(args[0]).Emit(stream, opBindingStrength, false); - if (parensNeeded) { - stream.Write(")"); - } - } - - public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { - //Contract.Requires(subjectForErrorReporting != null); - //Contract.Requires(rc != null); - if (rc.TriggerMode && this.op == Opcode.Not) { - rc.Error(subjectForErrorReporting, "boolean operators are not allowed in triggers"); - } - } - - public int ArgumentCount { - get { - return 1; - } - } - - public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { - //Contract.Requires(tc != null); - //Contract.Requires(args != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - Contract.Ensures(Contract.ValueAtReturn(out args) != null); - - Contract.Assume(args.Count == 1); - tpInstantiation = SimpleTypeParamInstantiation.EMPTY; - Type arg0type = cce.NonNull(cce.NonNull(args[0]).Type); - switch (this.op) { - case Opcode.Neg: - if (arg0type.Unify(Type.Int)) { - return Type.Int; - } - if (arg0type.Unify(Type.Real)) { - return Type.Real; - } - //if (arg0type.Unify(Type.Float)) { - //return Type.Float; - //} - goto BAD_TYPE; - case Opcode.Not: - if (arg0type.Unify(Type.Bool)) { - return Type.Bool; - } - goto BAD_TYPE; - } - System.Diagnostics.Debug.Fail("unknown unary operator: " + op.ToString()); - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } - BAD_TYPE: - tc.Error(this.tok, "invalid argument type ({1}) to unary operator {0}", - this.FunctionName, arg0type); - return null; - } - public Type ShallowType(IList args) { - //Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - switch (this.op) { - case Opcode.Neg: - return cce.NonNull(cce.NonNull(args[0]).Type); - case Opcode.Not: - return Type.Bool; - default: { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // unexpected unary operator - } - } - - public object Evaluate(object argument) { - if (argument == null) { - return null; - } - switch (this.op) { - case Opcode.Neg: - if (argument is BigNum) { - return -((BigNum)argument); - } - if (argument is BigDec) { - return -((BigDec)argument); - } - if (argument is BigFloat) { - return -((BigFloat)argument); - } - break; - case Opcode.Not: - if (argument is bool) { - return !((bool)argument); - } - throw new System.InvalidOperationException("unary Not only applies to bool"); - } - return null; // unreachable - } - - public T Dispatch(IAppliableVisitor visitor) { - //Contract.Requires(visitor != null); - return visitor.Visit(this); - } - } - - public class BinaryOperator : IAppliable, IOverloadedAppliable { - private IToken/*!*/ tok; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(tok != null); - } - - public bool DoNotResolveOverloading { get; set; } - - public enum Opcode { - Add, - Sub, - Mul, - Div, - Mod, - RealDiv, - FloatDiv, - Pow, - Eq, - Neq, - Gt, - Ge, - Lt, - Le, - And, - Or, - Imp, - Iff, - Subtype - }; - private Opcode op; - public Opcode Op { - get { - return op; - } - } - public BinaryOperator(IToken tok, Opcode op) { - Contract.Requires(tok != null); - this.tok = tok; - this.op = op; - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is BinaryOperator)) - return false; - - BinaryOperator other = (BinaryOperator)obj; - return object.Equals(this.op, other.op); - } - - [Pure] - public override int GetHashCode() { - return (int)this.op << 1; - } - - public string/*!*/ FunctionName { - get { - Contract.Ensures(Contract.Result() != null); - - switch (this.op) { - case Opcode.Add: - return "+"; - case Opcode.Sub: - return "-"; - case Opcode.Mul: - return "*"; - case Opcode.Div: - return "div"; - case Opcode.Mod: - return "mod"; - case Opcode.RealDiv: - return "/"; - case Opcode.Pow: - return "**"; - case Opcode.Eq: - return "=="; - case Opcode.Neq: - return "!="; - case Opcode.Gt: - return ">"; - case Opcode.Ge: - return ">="; - case Opcode.Lt: - return "<"; - case Opcode.Le: - return "<="; - case Opcode.And: - return "&&"; - case Opcode.Or: - return "||"; - case Opcode.Imp: - return "==>"; - case Opcode.Iff: - return "<==>"; - case Opcode.Subtype: - return "<:"; - } - System.Diagnostics.Debug.Fail("unknown binary operator: " + op.ToString()); - throw new Exception(); - } - } - - public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - //Contract.Requires(args != null); - stream.SetToken(ref this.tok); - Contract.Assert(args.Count == 2); - // determine if parens are needed - int opBindingStrength; - bool fragileLeftContext = false; // false means "allow same binding power on left without parens" - bool fragileRightContext = false; // false means "allow same binding power on right without parens" - switch (this.op) { - case Opcode.Add: - opBindingStrength = 0x40; - break; - case Opcode.Sub: - opBindingStrength = 0x40; - fragileRightContext = true; - break; - case Opcode.Mul: - opBindingStrength = 0x50; - break; - case Opcode.Div: - opBindingStrength = 0x50; - fragileRightContext = true; - break; - case Opcode.Mod: - opBindingStrength = 0x50; - fragileRightContext = true; - break; - case Opcode.RealDiv: - opBindingStrength = 0x50; - fragileRightContext = true; - break; - case Opcode.Pow: - opBindingStrength = 0x60; - fragileRightContext = true; - break; - case Opcode.Eq: - case Opcode.Neq: - case Opcode.Gt: - case Opcode.Ge: - case Opcode.Lt: - case Opcode.Le: - case Opcode.Subtype: - opBindingStrength = 0x30; - fragileLeftContext = fragileRightContext = true; - break; - case Opcode.And: - opBindingStrength = 0x20; - break; - case Opcode.Or: - opBindingStrength = 0x21; - break; - case Opcode.Imp: - opBindingStrength = 0x10; - fragileLeftContext = true; - break; - case Opcode.Iff: - opBindingStrength = 0x00; - break; - default: - System.Diagnostics.Debug.Fail("unknown binary operator: " + op.ToString()); - opBindingStrength = -1; // to please compiler, which refuses to consider whether or not all enumeration cases have been considered! - break; - } - int opBS = opBindingStrength & 0xF0; - int ctxtBS = contextBindingStrength & 0xF0; - bool parensNeeded = opBS < ctxtBS || - (opBS == ctxtBS && (opBindingStrength != contextBindingStrength || fragileContext)); - - var pop = stream.push(FunctionName); - if (parensNeeded) { - stream.Write("("); - } - cce.NonNull(args[0]).Emit(stream, opBindingStrength, fragileLeftContext); - stream.sep(); - stream.Write(" {0} ", FunctionName); - cce.NonNull(args[1]).Emit(stream, opBindingStrength, fragileRightContext); - if (parensNeeded) { - stream.Write(")"); - } - stream.pop(pop); - } - public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { - //Contract.Requires(subjectForErrorReporting != null); - //Contract.Requires(rc != null); - if (rc.TriggerMode) { - switch (this.op) { - case Opcode.Add: - case Opcode.Sub: - case Opcode.Mul: - case Opcode.Div: - case Opcode.Mod: - case Opcode.RealDiv: - case Opcode.Pow: - case Opcode.Neq: // Neq is allowed, but not Eq - case Opcode.Subtype: - // These are fine - break; - - case Opcode.Eq: - rc.Error(subjectForErrorReporting, "equality is not allowed in triggers"); - break; - - case Opcode.Gt: - case Opcode.Ge: - case Opcode.Lt: - case Opcode.Le: - rc.Error(subjectForErrorReporting, "arithmetic comparisons are not allowed in triggers"); - break; - - case Opcode.And: - case Opcode.Or: - case Opcode.Imp: - case Opcode.Iff: - rc.Error(subjectForErrorReporting, "boolean operators are not allowed in triggers"); - break; - - default: - System.Diagnostics.Debug.Fail("unknown binary operator: " + this.op.ToString()); - break; - } - } - } - public int ArgumentCount { - get { - return 2; - } - } - public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { - //Contract.Requires(tc != null); - //Contract.Requires(args != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - Contract.Ensures(args != null); - Contract.Assert(args.Count == 2); - // the default; the only binary operator with a type parameter is equality, but right - // we don't store this parameter because it does not appear necessary - tpInstantiation = SimpleTypeParamInstantiation.EMPTY; - Expr arg0 = cce.NonNull(args[0]); - Expr arg1 = cce.NonNull(args[1]); - Type arg0type = cce.NonNull(arg0.Type); - Type arg1type = cce.NonNull(arg1.Type); - switch (this.op) { - case Opcode.Add: - case Opcode.Sub: - case Opcode.Mul: - if (arg0type.Unify(Type.Int) && arg1type.Unify(Type.Int)) { - return Type.Int; - } - if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { - return Type.Real; - } - if (arg0type.IsFloat && arg0type.Unify(arg1type)) { - return Type.GetFloatType(arg0.Type.FloatExponent, arg0.Type.FloatMantissa); - } - if (arg1type.IsFloat && arg1type.Unify(arg0type)) { - return Type.GetFloatType(arg1.Type.FloatExponent, arg1.Type.FloatMantissa); - } - goto BAD_TYPE; - case Opcode.Div: - case Opcode.Mod: - if (arg0type.Unify(Type.Int) && arg1type.Unify(Type.Int)) { - return Type.Int; - } - goto BAD_TYPE; - case Opcode.RealDiv: - if ((arg0type.Unify(Type.Int) || arg0type.Unify(Type.Real)) && - (arg1type.Unify(Type.Int) || arg1type.Unify(Type.Real))) { - return Type.Real; - } - if (arg0type.IsFloat && arg0type.Unify(arg1type)) { - return Type.GetFloatType(arg0.Type.FloatExponent, arg0.Type.FloatMantissa); - } - if (arg1type.IsFloat && arg1type.Unify(arg0type)) { - return Type.GetFloatType(arg1.Type.FloatExponent, arg1.Type.FloatMantissa); - } - goto BAD_TYPE; - case Opcode.Pow: - if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { - return Type.Real; - } - goto BAD_TYPE; - case Opcode.Eq: - case Opcode.Neq: - // Comparison is allowed if the argument types are unifiable - // (i.e., if there is any chance that the values of the arguments are - // in the same domain) - if (arg0type.Equals(arg1type)) { - // quick path - return Type.Bool; - } - List/*!*/ unifiable = new List(); - unifiable.AddRange(arg0type.FreeVariables); - unifiable.AddRange(arg1type.FreeVariables); - - if (arg0type.Unify(arg1type, unifiable, new Dictionary())) - return Type.Bool; - goto BAD_TYPE; - case Opcode.Gt: - case Opcode.Ge: - case Opcode.Lt: - case Opcode.Le: - if (arg0type.Unify(Type.Int) && arg1type.Unify(Type.Int)) { - return Type.Bool; - } - if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { - return Type.Bool; - } - if ((arg0type.IsFloat && arg0type.Unify(arg1type)) || (arg1type.IsFloat && arg1type.Unify(arg0type))) { - return Type.Bool; - } - goto BAD_TYPE; - case Opcode.And: - case Opcode.Or: - case Opcode.Imp: - case Opcode.Iff: - if (arg0type.Unify(Type.Bool) && arg1type.Unify(Type.Bool)) { - return Type.Bool; - } - goto BAD_TYPE; - case Opcode.Subtype: - // Subtype is polymorphically typed and can compare things of - // arbitrary types (but both arguments must have the same type) - if (arg0type.Unify(arg1type)) { - return Type.Bool; - } - goto BAD_TYPE; - } - System.Diagnostics.Debug.Fail("unknown binary operator: " + op.ToString()); - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } - BAD_TYPE: - tc.Error(this.tok, "invalid argument types ({1} and {2}) to binary operator {0}", this.FunctionName, arg0type, arg1type); - return null; - } - - public Type ShallowType(IList args) { - //Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - switch (this.op) { - case Opcode.Add: - case Opcode.Sub: - case Opcode.Mul: - return cce.NonNull(args[0]).ShallowType; - - case Opcode.Div: - case Opcode.Mod: - return Type.Int; - - case Opcode.RealDiv: - case Opcode.Pow: - return Type.Real; - - case Opcode.Eq: - case Opcode.Neq: - case Opcode.Gt: - case Opcode.Ge: - case Opcode.Lt: - case Opcode.Le: - case Opcode.And: - case Opcode.Or: - case Opcode.Imp: - case Opcode.Iff: - case Opcode.Subtype: - return Type.Bool; - - default: { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // unexpected binary operator - } - } - - public void ResolveOverloading(NAryExpr expr) { - //Contract.Requires(expr != null); - - // immutable Expr must not be modified - if (DoNotResolveOverloading || expr.Immutable) - { - return; - } - - Expr arg0 = cce.NonNull(expr.Args[0]); - Expr arg1 = cce.NonNull(expr.Args[1]); - switch (op) { - case Opcode.Eq: - if (arg0.Type != null && arg0.Type.IsBool && arg1.Type != null && arg1.Type.IsBool) { - expr.Fun = new BinaryOperator(tok, Opcode.Iff); - } - break; - case Opcode.Neq: - if (arg0.Type != null && arg0.Type.IsBool && arg1.Type != null && arg1.Type.IsBool) { - expr.Fun = new BinaryOperator(tok, Opcode.Iff); - var arg1New = new NAryExpr(expr.tok, new UnaryOperator(tok, UnaryOperator.Opcode.Not), new List { arg1 }); - - // ugly ... there should be some more general approach, - // e.g., to typecheck the whole expression again - arg1New.Type = Type.Bool; - arg1New.TypeParameters = SimpleTypeParamInstantiation.EMPTY; - - expr.Args[1] = arg1New; - } - break; - } - } - - public object Evaluate(object e1, object e2) { - if (e1 == null || e2 == null) { - return null; - } - - switch (this.op) { - case Opcode.Add: - if (e1 is BigNum && e2 is BigNum) { - return ((BigNum)e1) + ((BigNum)e2); - } - if (e1 is BigDec && e2 is BigDec) { - return ((BigDec)e1) + ((BigDec)e2); - } - if (e1 is BigFloat && e2 is BigFloat) { - return ((BigFloat)e1) + ((BigFloat)e2); - } - break; - case Opcode.Sub: - if (e1 is BigNum && e2 is BigNum) { - return ((BigNum)e1) - ((BigNum)e2); - } - if (e1 is BigDec && e2 is BigDec) { - return ((BigDec)e1) - ((BigDec)e2); - } - if (e1 is BigFloat && e2 is BigFloat) { - return ((BigFloat)e1) - ((BigFloat)e2); - } - break; - case Opcode.Mul: - if (e1 is BigNum && e2 is BigNum) { - return ((BigNum)e1) * ((BigNum)e2); - } - if (e1 is BigDec && e2 is BigDec) { - return ((BigDec)e1) * ((BigDec)e2); - } - if (e1 is BigFloat && e2 is BigFloat) { - return ((BigFloat)e1) * ((BigFloat)e2); - } - break; - case Opcode.Div: - if (e1 is BigNum && e2 is BigNum) { - return /* TODO: right semantics? */ ((BigNum)e1) / ((BigNum)e2); - } - break; - case Opcode.Mod: - if (e1 is BigNum && e2 is BigNum) { - return /* TODO: right semantics? */ ((BigNum)e1) % ((BigNum)e2); - } - break; - case Opcode.RealDiv: - // TODO: add partial evaluation fro real division - break; - case Opcode.FloatDiv: - //TODO: add float division - break; - case Opcode.Pow: - // TODO: add partial evaluation fro real exponentiation - break; - case Opcode.Lt: - if (e1 is BigNum && e2 is BigNum) { - return ((BigNum)e1) < ((BigNum)e2); - } - if (e1 is BigDec && e2 is BigDec) { - return ((BigDec)e1) < ((BigDec)e2); - } - if (e1 is BigFloat && e2 is BigFloat) { - return ((BigFloat)e1) < ((BigFloat)e2); - } - break; - case Opcode.Le: - if (e1 is BigNum && e2 is BigNum) { - return ((BigNum)e1) <= ((BigNum)e2); - } - if (e1 is BigDec && e2 is BigDec) { - return ((BigDec)e1) <= ((BigDec)e2); - } - if (e1 is BigFloat && e2 is BigFloat) { - return ((BigFloat)e1) <= ((BigFloat)e2); - } - break; - case Opcode.Gt: - if (e1 is BigNum && e2 is BigNum) { - return ((BigNum)e1) > ((BigNum)e2); - } - if (e1 is BigDec && e2 is BigDec) { - return ((BigDec)e1) > ((BigDec)e2); - } - if (e1 is BigFloat && e2 is BigFloat) { - return ((BigFloat)e1) > ((BigFloat)e2); - } - break; - case Opcode.Ge: - if (e1 is BigNum && e2 is BigNum) { - return ((BigNum)e1) >= ((BigNum)e2); - } - if (e1 is BigDec && e2 is BigDec) { - return ((BigDec)e1) >= ((BigDec)e2); - } - if (e1 is BigFloat && e2 is BigFloat) { - return ((BigFloat)e1) >= ((BigFloat)e2); - } - break; - - case Opcode.And: - if (e1 is bool && e2 is bool) { - return (bool)e1 && (bool)e2; - } - break; - case Opcode.Or: - if (e1 is bool && e2 is bool) { - return (bool)e1 || (bool)e2; - } - break; - case Opcode.Imp: - if (e1 is bool && e2 is bool) { - return !(bool)e1 || (bool)e2; - } - break; - case Opcode.Iff: - if (e1 is bool && e2 is bool) { - return e1 == e2; - } - break; - - case Opcode.Eq: - return Equals(e1, e2); - case Opcode.Neq: - return !Equals(e1, e2); - - case Opcode.Subtype: - throw new System.NotImplementedException(); - } - throw new System.InvalidOperationException("bad types to binary operator " + this.op); - } - - public T Dispatch(IAppliableVisitor visitor) { - //Contract.Requires(visitor != null); - return visitor.Visit(this); - } - - } - - public class FunctionCall : IAppliable { - private IdentifierExpr/*!*/ name; - public Function Func; - public FunctionCall(IdentifierExpr name) { - Contract.Requires(name != null); - this.name = name; - } - public FunctionCall(Function f) { - Contract.Requires(f != null); - this.Func = f; - this.name = new IdentifierExpr(Token.NoToken, f.Name); - - // We need set the type of this IdentifierExpr so ShallowType() works - Debug.Assert(f.OutParams.Count > 0); - this.name.Type = f.OutParams[0].TypedIdent.Type; - } - public string/*!*/ FunctionName { - get { - Contract.Ensures(Contract.Result() != null); - return this.name.Name; - } - } - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(name != null); - } - - public FunctionCall createUnresolvedCopy() - { - return new FunctionCall(new IdentifierExpr(name.tok, name.Name, name.Type)); - } - - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - return name.Name; - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object other) { - FunctionCall fc = other as FunctionCall; - return fc != null && this.Func == fc.Func; - } - [Pure] - public override int GetHashCode() { - Contract.Assume(this.Func != null); - return Func.GetHashCode(); - } - - virtual public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - //Contract.Requires(args != null); - this.name.Emit(stream, 0xF0, false); - if (stream.UseForComputingChecksums) - { - var c = Func.DependencyChecksum; - if (c != null) - { - stream.Write(string.Format("[dependency_checksum:{0}]", c)); - } - } - stream.Write("("); - args.Emit(stream); - stream.Write(")"); - } - public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { - //Contract.Requires(subjectForErrorReporting != null); - //Contract.Requires(rc != null); - if (Func != null) { - // already resolved - return; - } - Func = rc.LookUpProcedure(name.Name) as Function; - if (Func == null) { - rc.Error(this.name, "use of undeclared function: {0}", name.Name); - } - else if (name.Type == null) { - // We need set the type of this IdentifierExpr so ShallowType() works - Debug.Assert(name.Type == null); - Debug.Assert(Func.OutParams.Count > 0); - name.Type = Func.OutParams[0].TypedIdent.Type; - } - } - public virtual int ArgumentCount { - get { - Contract.Assume(Func != null); // ArgumentCount requires object to be properly resolved. - return Func.InParams.Count; - } - } - public virtual Type Typecheck(IList actuals, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { - //Contract.Requires(tc != null); - //Contract.Requires(actuals != null); - Contract.Ensures(Contract.ValueAtReturn(out actuals) != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - Contract.Assume(this.Func != null); - Contract.Assume(actuals.Count == Func.InParams.Count); - Contract.Assume(Func.OutParams.Count == 1); - - List/*!*/ resultingTypeArgs; - List actualResultType = - Type.CheckArgumentTypes(Func.TypeParameters, - out resultingTypeArgs, - new List(Func.InParams.Select(Item => Item.TypedIdent.Type).ToArray()), - actuals, - new List(Func.OutParams.Select(Item => Item.TypedIdent.Type).ToArray()), - null, - // we need some token to report a possibly wrong number of - // arguments - actuals.Count > 0 ? cce.NonNull(actuals[0]).tok : Token.NoToken, - "application of " + name.Name, - tc); - - if (actualResultType == null) { - tpInstantiation = SimpleTypeParamInstantiation.EMPTY; - return null; - } else { - Contract.Assert(actualResultType.Count == 1); - tpInstantiation = - SimpleTypeParamInstantiation.From(Func.TypeParameters, resultingTypeArgs); - return actualResultType[0]; - } - } - public Type ShallowType(IList args) { - //Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - Contract.Assume(name.Type != null); - return name.Type; - } - - public virtual T Dispatch(IAppliableVisitor visitor) { - //Contract.Requires(visitor != null); - return visitor.Visit(this); - } - } - - public class TypeCoercion : IAppliable { - private IToken/*!*/ tok; - public Type/*!*/ Type; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(tok != null); - } - - public TypeCoercion(IToken tok, Type type) { - Contract.Requires(type != null); - Contract.Requires(tok != null); - this.tok = tok; - this.Type = type; - } - - public override bool Equals(object obj) { - TypeCoercion other = obj as TypeCoercion; - if (other == null) { - return false; - } else { - return object.Equals(Type, other.Type); - } - } - - - - public - string/*!*/ FunctionName { - get { - Contract.Ensures(Contract.Result() != null); - - return ":"; - } - } - - public void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, - int contextBindingStrength, bool fragileContext) { - //Contract.Requires(args != null); - //Contract.Requires(stream != null); - stream.SetToken(ref this.tok); - Contract.Assert(args.Count == 1); - // determine if parens are needed - int opBindingStrength = 0x80; - bool parensNeeded = opBindingStrength < contextBindingStrength || - (fragileContext && opBindingStrength == contextBindingStrength); - - if (parensNeeded) - stream.Write("("); - - cce.NonNull(args[0]).Emit(stream, opBindingStrength, false); - stream.Write("{0} ", FunctionName); - Type.Emit(stream, 0); - - if (parensNeeded) - stream.Write(")"); - } - - public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { - //Contract.Requires(subjectForErrorReporting != null); - //Contract.Requires(rc != null); - this.Type = this.Type.ResolveType(rc); - } - - public int ArgumentCount { - get { - return 1; - } - } - - public Type Typecheck(IList/*!*/ args, - out TypeParamInstantiation/*!*/ tpInstantiation, - TypecheckingContext/*!*/ tc) { - //Contract.Requires(args != null); - //Contract.Requires(tc != null); - Contract.Ensures(args != null); - - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - - Contract.Assume(args.Count == 1); - tpInstantiation = SimpleTypeParamInstantiation.EMPTY; - - if (!this.Type.Unify(cce.NonNull(cce.NonNull(args[0]).Type))) - tc.Error(this.tok, "{0} cannot be coerced to {1}", - cce.NonNull(args[0]).Type, this.Type); - return this.Type; - } - - public Type ShallowType(IList args) { - //Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - return this.Type; - } - - public T Dispatch(IAppliableVisitor visitor) { - //Contract.Requires(visitor != null); - return visitor.Visit(this); - } - - } - - public class ArithmeticCoercion : IAppliable { - public enum CoercionType { - ToInt, - ToReal, - ToFloat - } - - private IToken/*!*/ tok; - public readonly CoercionType Coercion; - private readonly string name; - private readonly Type type; - private readonly Type argType; - private readonly Type argType2; - private readonly int hashCode; - - public ArithmeticCoercion(IToken tok, CoercionType coercion) { - this.tok = tok; - this.Coercion = coercion; - - switch (coercion) { - case CoercionType.ToInt: - this.name = "int"; - this.type = Type.Int; - this.argType = Type.Real; - this.hashCode = 1; - break; - case CoercionType.ToReal: - this.name = "real"; - this.type = Type.Real; - this.argType = Type.Int; - this.hashCode = 2; - break; - default: - Contract.Assert(false); - break; - } - } - - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - return this.name; - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object other) { - ArithmeticCoercion ac = other as ArithmeticCoercion; - return ac != null && this.Coercion == ac.Coercion; - } - - [Pure] - public override int GetHashCode() { - return this.hashCode; - } - - public string/*!*/ FunctionName { - get { - return this.name; - } - } - - public int ArgumentCount { - get { - return 1; - } - } - - virtual public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - //Contract.Requires(args != null); - stream.Write(this.name); - stream.Write("("); - args.Emit(stream); - stream.Write(")"); - } - - public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { - //Contract.Requires(subjectForErrorReporting != null); - //Contract.Requires(rc != null); - } - - public virtual Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { - //Contract.Requires(tc != null); - //Contract.Requires(args != null); - Contract.Ensures(args != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - - Contract.Assert(args.Count == 1); - - tpInstantiation = SimpleTypeParamInstantiation.EMPTY; - - if (!(cce.NonNull(cce.NonNull(args[0]).Type).Unify(argType) || cce.NonNull(cce.NonNull(args[0]).Type).Unify(argType2))) - { - tc.Error(this.tok, "argument type {0} does not match expected type {1} or type {2}", cce.NonNull(args[0]).Type, this.argType, this.argType2); - } - - return this.type; - } - - public Type ShallowType(IList args) { - //Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - return this.type; - } - - public virtual T Dispatch(IAppliableVisitor visitor) { - //Contract.Requires(visitor != null); - return visitor.Visit(this); - } - } - - public class NAryExpr : Expr { - [Additive] - [Peer] - private IAppliable _Fun; - public IAppliable/*!*/ Fun { - get { - return _Fun; - } - set { - if (Immutable) - throw new InvalidOperationException("Cannot change Function used by Immutable NAryExpr"); - - _Fun = value; - } - } - private List _Args; - public IList Args { - get { - if (Immutable) - return _Args.AsReadOnly(); - else - return _Args; - } - set { - if (Immutable) - throw new InvalidOperationException("Cannot change Args of Immutable NAryExpr"); - - _Args = value as List; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Fun != null); - Contract.Invariant(Args != null); - } - - - // The instantiation of type parameters that is determined during type checking. - // Which type parameters are available depends on the IAppliable - public TypeParamInstantiation TypeParameters = null; - - [Captured] - public NAryExpr(IToken/*!*/ tok, IAppliable/*!*/ fun, IList/*!*/ args, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Contract.Requires(fun != null); - Contract.Requires(args != null); - _Fun = fun; - Contract.Assert(Contract.ForAll(0, args.Count, index => args[index] != null)); - if (immutable) { - // We need to make a new list because the client might be holding - // references to the list that they gave us which could be used to - // circumvent the immutability enforcement - _Args = new List(args); - CachedHashCode = ComputeHashCode(); - } else { - if (args is List) { - // Preserve NAryExpr's old behaviour, we take ownership of the List. - // We can only do this if the type matches - _Args = args as List; - } - else { - // Otherwise we must make a copy - _Args = new List (args); - } - } - } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is NAryExpr)) - return false; - - NAryExpr other = (NAryExpr)obj; - return object.Equals(this.Fun, other.Fun) && this.Args.SequenceEqual(other.Args); - } - - [Pure] - public override int GetHashCode() { - if (Immutable) - return this.CachedHashCode; - else - return ComputeHashCode(); - } - - [Pure] - public override int ComputeHashCode() { - int h = this.Fun.GetHashCode(); - // DO NOT USE Args.GetHashCode() because that uses Object.GetHashCode() which uses references - // We want structural equality - foreach (var arg in Args) { - h = (97*h) + arg.GetHashCode(); - } - return h; - } - public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - stream.SetToken(this); - Fun.Emit(Args, stream, contextBindingStrength, fragileContext); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - Fun.Resolve(rc, this); - foreach (Expr/*!*/ e in Args) { - Contract.Assert(e != null); - e.Resolve(rc); - } - } - public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { - //Contract.Requires(freeVars != null); - foreach (Expr/*!*/ e in Args) { - Contract.Assert(e != null); - e.ComputeFreeVariables(freeVars); - } - // also add the free type variables - if (TypeParameters != null) { - foreach (TypeVariable/*!*/ var in TypeParameters.FormalTypeParams) { - Contract.Assert(var != null); - foreach (TypeVariable/*!*/ w in TypeParameters[var].FreeVariables) { - Contract.Assert(w != null); - freeVars.Add(w); - } - } - } - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - int prevErrorCount = tc.ErrorCount; - foreach (Expr/*!*/ e in Args) { - Contract.Assert(e != null); - e.Typecheck(tc); - } - if (Fun.ArgumentCount != Args.Count) { - tc.Error(this, "wrong number of arguments to function: {0} ({1} instead of {2})", - Fun.FunctionName, Args.Count, Fun.ArgumentCount); - } else if (tc.ErrorCount == prevErrorCount && - // if the type parameters are set, this node has already been - // typechecked and does not need to be checked again - TypeParameters == null) { - TypeParamInstantiation tpInsts; - Type = Fun.Typecheck(Args, out tpInsts, tc); // Make sure we pass Args so if this Expr is immutable it is protected - TypeParameters = tpInsts; - } - IOverloadedAppliable oa = Fun as IOverloadedAppliable; - if (oa != null) { - oa.ResolveOverloading(this); - } - if (Type == null) { - // set Type to some non-null value - Type = new TypeProxy(this.tok, "type_checking_error"); - } - } - public override Type/*!*/ ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - return Fun.ShallowType(Args); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitNAryExpr(this); - } - } - - public class MapSelect : IAppliable { - - public readonly int Arity; - private readonly IToken/*!*/ tok; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(tok != null); - } - - - public MapSelect(IToken tok, int arity) { - Contract.Requires(tok != null); - this.tok = tok; - this.Arity = arity; - } - - public string/*!*/ FunctionName { - get { - Contract.Ensures(Contract.Result() != null); - - return "MapSelect"; - } - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (!(obj is MapSelect)) - return false; - - MapSelect other = (MapSelect)obj; - return this.Arity == other.Arity; - } - - [Pure] - public override int GetHashCode() { - return Arity.GetHashCode() * 2823; - } - - public void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, - int contextBindingStrength, bool fragileContext) { - //Contract.Requires(args != null); - //Contract.Requires(stream != null); - Contract.Assume(args.Count == Arity + 1); - Emit(args, stream, contextBindingStrength, fragileContext, false); - } - - public static void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, - int contextBindingStrength, bool fragileContext, - bool withRhs) { - Contract.Requires(args != null); - Contract.Requires(stream != null); - const int opBindingStrength = 0x90; - bool parensNeeded = opBindingStrength < contextBindingStrength || - (fragileContext && opBindingStrength == contextBindingStrength); - - if (parensNeeded) { - stream.Write("("); - } - cce.NonNull(args[0]).Emit(stream, opBindingStrength, false); - stream.Write("["); - - string sep = ""; - int lastIndex = withRhs ? args.Count - 1 : args.Count; - for (int i = 1; i < lastIndex; ++i) { - stream.Write(sep); - sep = ", "; - cce.NonNull(args[i]).Emit(stream); - } - - if (withRhs) { - stream.Write(" := "); - cce.NonNull(args.Last()).Emit(stream); - } - - stream.Write("]"); - if (parensNeeded) { - stream.Write(")"); - } - } - - public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { - //Contract.Requires(subjectForErrorReporting != null); - //Contract.Requires(rc != null); - // PR: nothing? - } - - public int ArgumentCount { - get { - return Arity + 1; - } - } - - // it is assumed that each of the arguments has already been typechecked - public static Type Typecheck(Type/*!*/ mapType, - // we just pass an Absy, because in - // the AssignCmd maps can also be - // represented by non-expressions - Absy/*!*/ map, - List/*!*/ indexes, - // the type parameters, in this context, are the parameters of the - // potentially polymorphic map type. Because it might happen that - // the whole map type is unknown and represented using a MapTypeProxy, - // the instantiations given in the following out-parameter are subject - // to change if further unifications are done. - out TypeParamInstantiation/*!*/ tpInstantiation, - TypecheckingContext/*!*/ tc, - IToken/*!*/ typeCheckingSubject, - string/*!*/ opName) { - Contract.Requires(mapType != null); - Contract.Requires(map != null); - Contract.Requires(indexes != null); - Contract.Requires(tc != null); - Contract.Requires(typeCheckingSubject != null); - Contract.Requires(opName != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - - mapType = mapType.Expanded; - if (mapType.IsMap && mapType.MapArity != indexes.Count) { - tc.Error(typeCheckingSubject, "wrong number of arguments in {0}: {1} instead of {2}", - opName, indexes.Count, mapType.MapArity); - tpInstantiation = SimpleTypeParamInstantiation.EMPTY; - return null; - } else if (!mapType.Unify(new MapTypeProxy(map.tok, "select", indexes.Count))) { - tc.Error(map.tok, "{0} applied to a non-map: {1}", opName, map); - tpInstantiation = SimpleTypeParamInstantiation.EMPTY; - return null; - } - mapType = TypeProxy.FollowProxy(mapType); - - if (mapType is MapType) { - MapType mt = (MapType)mapType; - return mt.CheckArgumentTypes(indexes, out tpInstantiation, - typeCheckingSubject, opName, tc); - } else { - MapTypeProxy mt = (MapTypeProxy)mapType; - return mt.CheckArgumentTypes(indexes, out tpInstantiation, - typeCheckingSubject, opName, tc); - } - } - - public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { - //Contract.Requires(tc != null); - //Contract.Requires(args != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - Contract.Assume(args.Count == Arity + 1); - - // FIXME: Wny are we passing a copy? - List actualArgs = new List(); - for (int i = 1; i < args.Count; ++i) - actualArgs.Add(args[i]); - - return Typecheck(cce.NonNull(cce.NonNull(args[0]).Type), cce.NonNull(args[0]), - actualArgs, out tpInstantiation, tc, this.tok, "map select"); - } - - /// - /// Returns the result type of the IAppliable, supposing the argument are of the correct types. - /// - public Type ShallowType(IList args) { - //Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - Expr a0 = cce.NonNull(args[0]); - Type a0Type = a0.ShallowType; - if (a0Type == null || !a0Type.IsMap) { - // we are unable to determine the type of the select, so just return an arbitrary type - return Type.Int; - } - MapType mapType = a0Type.AsMap; - List actualArgTypes = new List(); - for (int i = 1; i < args.Count; ++i) { - actualArgTypes.Add(cce.NonNull(args[i]).ShallowType); - } - return Type.InferValueType(mapType.TypeParameters, mapType.Arguments, mapType.Result, actualArgTypes); - } - - public T Dispatch(IAppliableVisitor visitor) { - //Contract.Requires(visitor != null); - return visitor.Visit(this); - } - } - - public class MapStore : IAppliable { - - public readonly int Arity; - public readonly IToken/*!*/ tok; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(tok != null); - } - - - public MapStore(IToken tok, int arity) { - Contract.Requires(tok != null); - this.tok = tok; - this.Arity = arity; - } - - public string/*!*/ FunctionName { - get { - Contract.Ensures(Contract.Result() != null); - - return "MapStore"; - } - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (!(obj is MapStore)) - return false; - - MapStore other = (MapStore)obj; - return this.Arity == other.Arity; - } - - [Pure] - public override int GetHashCode() { - return Arity.GetHashCode() * 28231; - } - - public void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, - int contextBindingStrength, bool fragileContext) { - //Contract.Requires(args != null); - //Contract.Requires(stream != null); - Contract.Assert(args.Count == Arity + 2); - MapSelect.Emit(args, stream, contextBindingStrength, fragileContext, true); - } - - public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { - //Contract.Requires(subjectForErrorReporting != null); - //Contract.Requires(rc != null); - // PR: nothing? - } - - public int ArgumentCount { - get { - return Arity + 2; - } - } - - // it is assumed that each of the arguments has already been typechecked - public static Type Typecheck(IList/*!*/ args, out TypeParamInstantiation/*!*/ tpInstantiation, - TypecheckingContext/*!*/ tc, - IToken/*!*/ typeCheckingSubject, - string/*!*/ opName) { - Contract.Requires(args != null); - Contract.Requires(tc != null); - Contract.Requires(typeCheckingSubject != null); - Contract.Requires(opName != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - - // part of the type checking works exactly as for MapSelect - List selectArgs = new List(); - for (int i = 1; i < args.Count - 1; ++i) - selectArgs.Add(args[i]); - Type resultType = - MapSelect.Typecheck(cce.NonNull(cce.NonNull(args[0]).Type), cce.NonNull(args[0]), - selectArgs, out tpInstantiation, tc, typeCheckingSubject, opName); - - // check the the rhs has the right type - if (resultType == null) { - // error messages have already been created by MapSelect.Typecheck - return null; - } - Type rhsType = cce.NonNull(cce.NonNull(args.Last()).Type); - if (!resultType.Unify(rhsType)) { - tc.Error(cce.NonNull(args.Last()).tok, - "right-hand side in {0} with wrong type: {1} (expected: {2})", - opName, rhsType, resultType); - return null; - } - - return cce.NonNull(args[0]).Type; - } - - public Type Typecheck(IList/*!*/ args, - out TypeParamInstantiation/*!*/ tpInstantiation, - TypecheckingContext/*!*/ tc) { - //Contract.Requires(args != null); - //Contract.Requires(tc != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - Contract.Ensures(Contract.ValueAtReturn(out args) != null); - Contract.Assert(args.Count == Arity + 2); - return Typecheck(args, out tpInstantiation, tc, this.tok, "map store"); - } - - /// - /// Returns the result type of the IAppliable, supposing the argument are of the correct types. - /// - public Type ShallowType(IList args) { - //Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - return cce.NonNull(args[0]).ShallowType; - } - - public T Dispatch(IAppliableVisitor visitor) { - //Contract.Requires(visitor != null); - return visitor.Visit(this); - } - } - - - public class IfThenElse : IAppliable { - - private IToken/*!*/ _tok; - - public IToken/*!*/ tok - { - get - { - Contract.Ensures(Contract.Result() != null); - return this._tok; - } - set - { - Contract.Requires(value != null); - this._tok = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._tok != null); - } - - public IfThenElse(IToken tok) { - Contract.Requires(tok != null); - this._tok = tok; - } - - public string/*!*/ FunctionName { - get { - Contract.Ensures(Contract.Result() != null); - - return "if-then-else"; - } - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (!(obj is IfThenElse)) - return false; - return true; - } - - [Pure] - public override int GetHashCode() { - return 1; - } - - public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - //Contract.Requires(args != null); - stream.SetToken(this); - Contract.Assert(args.Count == 3); - stream.push(); - stream.Write("(if "); - cce.NonNull(args[0]).Emit(stream, 0x00, false); - stream.sep(); - stream.Write(" then "); - cce.NonNull(args[1]).Emit(stream, 0x00, false); - stream.sep(); - stream.Write(" else "); - cce.NonNull(args[2]).Emit(stream, 0x00, false); - stream.Write(")"); - stream.pop(); - } - - public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { - //Contract.Requires(subjectForErrorReporting != null); - //Contract.Requires(rc != null); - // PR: nothing? - } - - public int ArgumentCount { - get { - return 3; - } - } - - public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { - //Contract.Requires(tc != null); - //Contract.Requires(args != null); - Contract.Ensures(args != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - Contract.Assert(args.Count == 3); - // the default; the only binary operator with a type parameter is equality, but right - // we don't store this parameter because it does not appear necessary - tpInstantiation = SimpleTypeParamInstantiation.EMPTY; - Expr arg0 = cce.NonNull(args[0]); - Expr arg1 = cce.NonNull(args[1]); - Expr arg2 = cce.NonNull(args[2]); - - if (!cce.NonNull(arg0.Type).Unify(Type.Bool)) { - tc.Error(this.tok, "the first argument to if-then-else should be bool, not {0}", arg0.Type); - } else if (!cce.NonNull(arg1.Type).Unify(cce.NonNull(arg2.Type))) { - tc.Error(this.tok, "branches of if-then-else have incompatible types {0} and {1}", arg1.Type, arg2.Type); - } else { - return arg1.Type; - } - - return null; - } - - /// - /// Returns the result type of the IAppliable, supposing the argument are of the correct types. - /// - public Type ShallowType(IList args) { - //Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - return cce.NonNull(args[1]).ShallowType; - } - - public T Dispatch(IAppliableVisitor visitor) { - //Contract.Requires(visitor != null); - return visitor.Visit(this); - } - } - - - - public class CodeExpr : Expr { - public List/*!*/ LocVars; - [Rep] - public List/*!*/ Blocks; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(LocVars != null); - Contract.Invariant(cce.NonNullElements(Blocks)); - } - - public CodeExpr(List/*!*/ localVariables, List/*!*/ blocks, bool immutable=false) - : base(Token.NoToken, immutable) { - Contract.Requires(localVariables != null); - Contract.Requires(cce.NonNullElements(blocks)); - Contract.Requires(0 < blocks.Count); - LocVars = localVariables; - Blocks = blocks; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - - // FIXME: This seems wrong we don't want reference equality, we want structural equality - [Pure] - public override bool Equals(object obj) - { - return base.Equals(obj); - } - - [Pure] - public override int GetHashCode() - { - if (Immutable) - return CachedHashCode; - else - return ComputeHashCode(); - } - - [Pure] - public override int ComputeHashCode() { - return base.GetHashCode(); - } - - - public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { - //Contract.Requires(freeVars != null); - // Treat a BlockEexpr as if it has no free variables at all - } - public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - //level++; - int level = 0; - stream.WriteLine(level, "|{"); - - if (this.LocVars.Count > 0) { - stream.Write(level + 1, "var "); - this.LocVars.Emit(stream, true); - stream.WriteLine(";"); - } - - foreach (Block/*!*/ b in this.Blocks) { - Contract.Assert(b != null); - b.Emit(stream, level + 1); - } - - stream.WriteLine(); - stream.WriteLine(level, "}|"); - - stream.WriteLine(); - stream.WriteLine(); - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - - rc.PushVarContext(); - foreach (Variable/*!*/ v in LocVars) { - Contract.Assert(v != null); - v.Register(rc); - v.Resolve(rc); - } - - rc.PushProcedureContext(); - foreach (Block/*!*/ b in Blocks) { - Contract.Assert(b != null); - b.Register(rc); - } - - foreach (Block/*!*/ b in Blocks) { - Contract.Assert(b != null); - b.Resolve(rc); - } - - rc.PopProcedureContext(); - rc.PopVarContext(); - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - foreach (Variable/*!*/ v in LocVars) { - Contract.Assert(v != null); - v.Typecheck(tc); - } - foreach (Block/*!*/ b in Blocks) { - Contract.Assert(b != null); - b.Typecheck(tc); - } - this.Type = Type.Bool; - } - public override Type/*!*/ ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - return Type.Bool; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitCodeExpr(this); - } - } - - public class BvExtractExpr : Expr { - private /*readonly--except in StandardVisitor*/ Expr/*!*/ _Bitvector; - public Expr Bitvector { - get { - return _Bitvector; - } - set { - if (Immutable) - throw new InvalidOperationException("Cannot change BitVector field of an immutable BvExtractExpr"); - - _Bitvector = value; - } - } - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(_Bitvector != null); - } - - public readonly int Start, End; - - public BvExtractExpr(IToken/*!*/ tok, Expr/*!*/ bv, int end, int start, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Contract.Requires(bv != null); - _Bitvector = bv; - Start = start; - End = end; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is BvExtractExpr)) - return false; - - BvExtractExpr other = (BvExtractExpr)obj; - return object.Equals(this.Bitvector, other.Bitvector) && - this.Start.Equals(other.Start) && this.End.Equals(other.End); - } - - [Pure] - public override int GetHashCode() { - if (Immutable) - return CachedHashCode; - else - return ComputeHashCode(); - } - - [Pure] - public override int ComputeHashCode() { - int h = this.Bitvector.GetHashCode(); - h ^= Start * 17 ^ End * 13; - return h; - } - public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - stream.SetToken(this); - int opBindingStrength = 0x90; - bool parensNeeded = opBindingStrength < contextBindingStrength || - (fragileContext && opBindingStrength == contextBindingStrength); - - if (parensNeeded) { - stream.Write("("); - } - Bitvector.Emit(stream, opBindingStrength, false); - stream.Write("[" + End + ":" + Start + "]"); - if (parensNeeded) { - stream.Write(")"); - } - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - Bitvector.Resolve(rc); - } - public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { - //Contract.Requires(freeVars != null); - Bitvector.ComputeFreeVariables(freeVars); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - Bitvector.Typecheck(tc); - Contract.Assert(Bitvector.Type != null); // follows from postcondition of Expr.Typecheck - - if (Start < 0) { - tc.Error(this, "start index in extract must not be negative"); - } else if (End < 0) { - tc.Error(this, "end index in extract must not be negative"); - } else if (End < Start) { - tc.Error(this, "start index in extract must be no bigger than the end index"); - } else { - Type typeConstraint = new BvTypeProxy(this.tok, "extract", End - Start); - if (typeConstraint.Unify(Bitvector.Type)) { - Type = Type.GetBvType(End - Start); - } else { - tc.Error(this, "extract operand must be a bitvector of at least {0} bits (got {1})", End - Start, Bitvector.Type); - } - } - if (Type == null) { - Type = new TypeProxy(this.tok, "type_checking_error"); - } - } - - public override Type/*!*/ ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - return Type.GetBvType(End - Start); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitBvExtractExpr(this); - } - } - - public class BvConcatExpr : Expr { - private /*readonly--except in StandardVisitor*/ Expr/*!*/ _E0, _E1; - public Expr E0 { - get { - return _E0; - } - set { - if (Immutable) - throw new InvalidOperationException("Can't change E0 reference on immutable Expr"); - - _E0 = value; - } - } - public Expr E1 { - get { - return _E1; - } - set { - if (Immutable) - throw new InvalidOperationException("Can't change E1 reference on immutable Expr"); - - _E1 = value; - } - } - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(E0 != null); - Contract.Invariant(E1 != null); - } - - - public BvConcatExpr(IToken/*!*/ tok, Expr/*!*/ e0, Expr/*!*/ e1, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Contract.Requires(e0 != null); - Contract.Requires(e1 != null); - _E0 = e0; - _E1 = e1; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is BvConcatExpr)) - return false; - - BvConcatExpr other = (BvConcatExpr)obj; - return object.Equals(this.E0, other.E0) && object.Equals(this.E1, other.E1); - } - - [Pure] - public override int GetHashCode() - { - if (Immutable) - return CachedHashCode; - else - return ComputeHashCode(); - } - - [Pure] - public override int ComputeHashCode() { - int h = this.E0.GetHashCode() ^ this.E1.GetHashCode() * 17; - return h; - } - - public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - stream.SetToken(this); - int opBindingStrength = 0x32; - bool parensNeeded = opBindingStrength < contextBindingStrength || - (fragileContext && opBindingStrength == contextBindingStrength); - - if (parensNeeded) { - stream.Write("("); - } - E0.Emit(stream, opBindingStrength, false); - stream.Write(" ++ "); - // while this operator is associative, our incomplete axioms in int translation don't - // make much use of it, so better stick to the actual tree shape - E1.Emit(stream, opBindingStrength, true); - if (parensNeeded) { - stream.Write(")"); - } - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - E0.Resolve(rc); - E1.Resolve(rc); - } - public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { - //Contract.Requires(freeVars != null); - E0.ComputeFreeVariables(freeVars); - E1.ComputeFreeVariables(freeVars); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - E0.Typecheck(tc); - Contract.Assert(E0.Type != null); // follows from postcondition of Expr.Typecheck - E1.Typecheck(tc); - Contract.Assert(E1.Type != null); // follows from postcondition of Expr.Typecheck - - if (E0.Type.Unify(new BvTypeProxy(this.tok, "concat0", 0)) && E1.Type.Unify(new BvTypeProxy(this.tok, "concat1", 0))) { - Type = new BvTypeProxy(this.tok, "concat", E0.Type, E1.Type); - } else { - tc.Error(this, "++ operands need to be bitvectors (got {0}, {1})", E0.Type, E1.Type); - } - if (Type == null) { - Type = new TypeProxy(this.tok, "type_checking_error"); - } - } - - public override Type/*!*/ ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - Type t0 = E0.ShallowType; - Type t1 = E1.ShallowType; - int len0 = t0.IsBv ? t0.BvBits : /*expression is not type correct, so just pick an arbitrary number of bits*/0; - int len1 = t1.IsBv ? t1.BvBits : /*expression is not type correct, so just pick an arbitrary number of bits*/0; - return Type.GetBvType(len0 + len1); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitBvConcatExpr(this); - } - } -} - +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- +// BoogiePL - Absy.cs +//--------------------------------------------------------------------------------------------- + +namespace Microsoft.Boogie { + using System; + using System.Collections; + using System.Diagnostics; + using System.Collections.Generic; + using Microsoft.Boogie.AbstractInterpretation; + using System.Diagnostics.Contracts; + using System.Linq; + using Microsoft.Basetypes; + + using Set = GSet; // not that the set used is not a set of Variable only, as it also contains TypeVariables + + + //--------------------------------------------------------------------- + // Expressions + // + // For expressions, we override the Equals and GetHashCode method to + // implement structural equality. Note this is not logical equivalence + // and is not modulo alpha-renaming. + //--------------------------------------------------------------------- + + + [ContractClass(typeof(ExprContracts))] + public abstract class Expr : Absy { + public Expr(IToken/*!*/ tok, bool immutable) + : base(tok) { + Contract.Requires(tok != null); + this.Immutable = immutable; + } + + public void Emit(TokenTextWriter stream) { + Contract.Requires(stream != null); + Emit(stream, 0, false); + } + + /// + /// If true the client is making a promise that this Expr will be + /// treated immutably (i.e. once constructed it is never changed). + /// This is currently not enforced but it should be! + /// + /// This allows the Expr's hash code to be cached making calls to + /// GetHashCode() very cheap. + /// + /// true if immutable; otherwise, false. + public bool Immutable { + get; + private set; + } + + /// + /// Computes the hash code of this Expr skipping any cache. + /// + /// Sub classes should place their implementation of computing their hashcode + /// here (making sure to call GetHashCode() not ComputeHashCode() on Expr for performance reasons) + /// and have GetHashCode() use a cached result from ComputeHashCode() if the + /// Expr was constructed to be immutable. + /// + /// The hash code. + public abstract int ComputeHashCode(); + protected int CachedHashCode = 0; + + public abstract void Emit(TokenTextWriter/*!*/ wr, int contextBindingStrength, bool fragileContext); + + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result() != null); + System.IO.StringWriter buffer = new System.IO.StringWriter(); + using (TokenTextWriter stream = new TokenTextWriter("", buffer, /*setTokens=*/ false, /*pretty=*/ false)) { + this.Emit(stream, 0, false); + } + return buffer.ToString(); + } + + /// + /// Add to "freeVars" the free variables in the expression. + /// + public abstract void ComputeFreeVariables(Set /*Variable*//*!*/ freeVars); + + /// + /// Filled in by the Typecheck method. A value of "null" means a succeeding + /// call to Typecheck has not taken place (that is, either Typecheck hasn't + /// been called or Typecheck encountered an error in the expression to be + /// typechecked). + /// + private Type _Type = null; + public Type Type { + get { + return _Type; + } + set { + if (_Type == null) { + // Expr has never been type checked so always allow this + _Type = value; + } else { + if (Immutable && !_Type.Equals(value)) + throw new InvalidOperationException("Cannot change the Type of an Immutable Expr"); + + // Once the Type has been set (i.e. no longer null) we never change the reference + // if this Expr is immutable, even if the Type is equivalent (i.e. _Type.Equals(newType)) + if (!Immutable) + _Type = value; + } + } + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + Contract.Ensures(Type != null); + // This body is added only because C# insists on it. It should really be left out, as if TypeCheck still were abstract. + // The reason for mentioning the method here at all is to give TypeCheck a postcondition for all expressions. + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } + } + + /// + /// Returns the type of the expression, supposing that all its subexpressions are well typed. + /// + public abstract Type/*!*/ ShallowType { + get; + } + + // Handy syntactic sugar follows: + + public static NAryExpr Unary(IToken x, UnaryOperator.Opcode op, Expr e1) { + Contract.Requires(e1 != null); + Contract.Requires(x != null); + Contract.Ensures(Contract.Result() != null); + return new NAryExpr(x, new UnaryOperator(x, op), new List { e1 }); + } + + public static NAryExpr Binary(IToken x, BinaryOperator.Opcode op, Expr e0, Expr e1) { + Contract.Requires(e1 != null); + Contract.Requires(e0 != null); + Contract.Requires(x != null); + Contract.Ensures(Contract.Result() != null); + return new NAryExpr(x, new BinaryOperator(x, op), new List { e0, e1 }); + } + + public static NAryExpr Binary(BinaryOperator.Opcode op, Expr e0, Expr e1) { + Contract.Requires(e1 != null); + Contract.Requires(e0 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(Token.NoToken, op, e0, e1); + } + + public static NAryExpr Eq(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Eq, e1, e2); + } + public static NAryExpr Neq(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Neq, e1, e2); + } + public static NAryExpr Le(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Le, e1, e2); + } + public static NAryExpr Ge(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Ge, e1, e2); + } + public static NAryExpr Lt(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Lt, e1, e2); + } + public static NAryExpr Gt(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Gt, e1, e2); + } + public static Expr And(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + if (e1 == true_) { + return e2; + } else if (e2 == true_) { + return e1; + } else if (e1 == false_ || e2 == false_) { + return false_; + } else { + var res = Binary(BinaryOperator.Opcode.And, e1, e2); + res.Type = Microsoft.Boogie.Type.Bool; + res.TypeParameters = SimpleTypeParamInstantiation.EMPTY; + return res; + } + } + public static Expr Or(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + if (e1 == false_) { + return e2; + } else if (e2 == false_) { + return e1; + } else if (e1 == true_ || e2 == true_) { + return true_; + } else { + return Binary(BinaryOperator.Opcode.Or, e1, e2); + } + } + public static Expr Not(Expr e1) { + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + NAryExpr nary = e1 as NAryExpr; + + if (e1 == true_) { + return false_; + } else if (e1 == false_) { + return true_; + } else if (nary != null) { + if (nary.Fun is UnaryOperator) { + UnaryOperator op = (UnaryOperator)nary.Fun; + if (op.Op == UnaryOperator.Opcode.Not) { + return cce.NonNull(nary.Args[0]); + } + } else if (nary.Fun is BinaryOperator) { + BinaryOperator op = (BinaryOperator)nary.Fun; + Expr arg0 = cce.NonNull(nary.Args[0]); + Expr arg1 = cce.NonNull(nary.Args[1]); + if (op.Op == BinaryOperator.Opcode.Eq) { + return Neq(arg0, arg1); + } else if (op.Op == BinaryOperator.Opcode.Neq) { + return Eq(arg0, arg1); + } else if (op.Op == BinaryOperator.Opcode.Lt) { + return Le(arg1, arg0); + } else if (op.Op == BinaryOperator.Opcode.Le) { + return Lt(arg1, arg0); + } else if (op.Op == BinaryOperator.Opcode.Ge) { + return Gt(arg1, arg0); + } else if (op.Op == BinaryOperator.Opcode.Gt) { + return Ge(arg1, arg0); + } + } + } + + return Unary(Token.NoToken, UnaryOperator.Opcode.Not, e1); + } + + public static Expr Neg(Expr e1) { + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Unary(Token.NoToken, UnaryOperator.Opcode.Neg, e1); + } + + public static NAryExpr Imp(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Imp, e1, e2); + } + public static NAryExpr Iff(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Iff, e1, e2); + } + public static NAryExpr Add(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Add, e1, e2); + } + public static NAryExpr Sub(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Sub, e1, e2); + } + public static NAryExpr Mul(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Mul, e1, e2); + } + public static NAryExpr Div(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Div, e1, e2); + } + public static NAryExpr Mod(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Mod, e1, e2); + } + public static NAryExpr RealDiv(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.RealDiv, e1, e2); + } + public static NAryExpr FloatDiv(Expr e1, Expr e2) + { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.FloatDiv, e1, e2); + } + public static NAryExpr Pow(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Pow, e1, e2); + } + public static NAryExpr Subtype(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Subtype, e1, e2); + } + + public static IdentifierExpr Ident(string name, Type type) { + Contract.Requires(type != null); + Contract.Requires(name != null); + Contract.Ensures(Contract.Result() != null); + return new IdentifierExpr(Token.NoToken, name, type); + } + + public static IdentifierExpr Ident(Variable decl) { + Contract.Requires(decl != null); + Contract.Ensures(Contract.Result() != null); + IdentifierExpr result = new IdentifierExpr(Token.NoToken, decl); + return result; + } + + public static LiteralExpr Literal(bool value) { + Contract.Ensures(Contract.Result() != null); + return new LiteralExpr(Token.NoToken, value); + } + public static LiteralExpr Literal(int value) { + Contract.Ensures(Contract.Result() != null); + return new LiteralExpr(Token.NoToken, BigNum.FromInt(value)); + } + public static LiteralExpr Literal(BigNum value) { + Contract.Ensures(Contract.Result() != null); + return new LiteralExpr(Token.NoToken, value); + } + public static LiteralExpr Literal(BigDec value) { + Contract.Ensures(Contract.Result() != null); + return new LiteralExpr(Token.NoToken, value); + } + public static LiteralExpr Literal(BigFloat value) + { + Contract.Ensures(Contract.Result() != null); + return new LiteralExpr(Token.NoToken, value); + } + + private static LiteralExpr/*!*/ true_ = Literal(true); + public static LiteralExpr/*!*/ True { + get { + Contract.Ensures(Contract.Result() != null); + return true_; + } + } + + private static LiteralExpr/*!*/ false_ = Literal(false); + public static LiteralExpr/*!*/ False { + get { + Contract.Ensures(Contract.Result() != null); + return false_; + } + } + + + public static NAryExpr Select(Expr map, params Expr[] args) { + Contract.Requires(args != null); + Contract.Requires(map != null); + Contract.Ensures(Contract.Result() != null); + return SelectTok(Token.NoToken, map, args); + } + + public static NAryExpr Select(Expr map, List/*!*/ args) { + Contract.Requires(map != null); + Contract.Requires(cce.NonNullElements(args)); + Contract.Ensures(Contract.Result() != null); + return Select(map, args.ToArray()); + } + + // use a different name for this variant of the method + // (-> some bug prevents overloading in this case) + public static NAryExpr SelectTok(IToken x, Expr map, params Expr[] args) { + Contract.Requires(args != null); + Contract.Requires(map != null); + Contract.Requires(x != null); + Contract.Ensures(Contract.Result() != null); + List/*!*/ allArgs = new List(); + allArgs.Add(map); + foreach (Expr/*!*/ a in args) { + Contract.Assert(a != null); + allArgs.Add(a); + } + return new NAryExpr(x, new MapSelect(Token.NoToken, args.Length), allArgs); + } + + public static NAryExpr Store(Expr map, params Expr[] args) { + Contract.Requires(args != null); + Contract.Requires(map != null); + Contract.Ensures(Contract.Result() != null); + return StoreTok(Token.NoToken, map, args); + } + + public static NAryExpr Store(Expr map, List/*!*/ indexes, Expr rhs) { + Contract.Requires(rhs != null); + Contract.Requires(map != null); + Contract.Requires(cce.NonNullElements(indexes)); + Contract.Ensures(Contract.Result() != null); + Expr[]/*!*/ allArgs = new Expr[indexes.Count + 1]; + for (int i = 0; i < indexes.Count; ++i) + allArgs[i] = indexes[i]; + allArgs[indexes.Count] = rhs; + return Store(map, allArgs); + } + + // use a different name for this variant of the method + // (-> some bug prevents overloading in this case) + public static NAryExpr/*!*/ StoreTok(IToken x, Expr map, params Expr[] args) { + Contract.Requires(args != null); + Contract.Requires(map != null); + Contract.Requires(x != null); + Contract.Requires(args.Length > 0); // zero or more indices, plus the value + Contract.Ensures(Contract.Result() != null); + + List/*!*/ allArgs = new List(); + allArgs.Add(map); + foreach (Expr/*!*/ a in args) { + Contract.Assert(a != null); + allArgs.Add(a); + } + return new NAryExpr(x, new MapStore(Token.NoToken, args.Length - 1), allArgs); + } + + public static NAryExpr CoerceType(IToken x, Expr subexpr, Type type) { + Contract.Requires(type != null); + Contract.Requires(subexpr != null); + Contract.Requires(x != null); + Contract.Ensures(Contract.Result() != null); + List/*!*/ args = new List(); + args.Add(subexpr); + return new NAryExpr(x, new TypeCoercion(x, type), args); + } + + public static Expr BinaryTreeAnd(List terms) + { + return BinaryTreeAnd(terms, 0, terms.Count - 1); + } + + private static Expr BinaryTreeAnd(List terms, int start, int end) + { + if (start > end) + return Expr.True; + if (start == end) + return terms[start]; + if (start + 1 == end) + return Expr.And(terms[start], terms[start + 1]); + var mid = (start + end) / 2; + return Expr.And(BinaryTreeAnd(terms, start, mid), BinaryTreeAnd(terms, mid + 1, end)); + } + + public static Expr And(IEnumerable conjuncts, bool returnNullIfEmpty = false) + { + Expr result = null; + foreach (var c in conjuncts) + { + if (result != null) + { + result = LiteralExpr.And(result, c); + result.Type = Type.Bool; + } + else + { + result = c; + result.Type = Type.Bool; + } + } + if (result == null && !returnNullIfEmpty) + { + result = Expr.True; + } + return result; + } + } + [ContractClassFor(typeof(Expr))] + public abstract class ExprContracts : Expr { + public ExprContracts() :base(null, /*immutable=*/ false){ + + } + public override void Emit(TokenTextWriter wr, int contextBindingStrength, bool fragileContext) { + Contract.Requires(wr != null); + throw new NotImplementedException(); + } + public override void ComputeFreeVariables(Set freeVars) { + Contract.Requires(freeVars != null); + throw new NotImplementedException(); + } + public override Type ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + throw new NotImplementedException(); + } + } + } + + public class LiteralExpr : Expr { + public readonly object/*!*/ Val; // false, true, a BigNum, a BigDec, a BigFloat, or a BvConst + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Val != null); + } + + /// + /// Creates a literal expression for the boolean value "b". + /// + /// + /// + public LiteralExpr(IToken/*!*/ tok, bool b, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Val = b; + Type = Type.Bool; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + + /// + /// Creates a literal expression for the integer value "v". + /// + /// + /// + public LiteralExpr(IToken/*!*/ tok, BigNum v, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Val = v; + Type = Type.Int; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + + /// + /// Creates a literal expression for the real value "v". + /// + /// + /// + public LiteralExpr(IToken/*!*/ tok, BigDec v, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Val = v; + Type = Type.Real; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + + /// + /// Creates a literal expression for the floating point value "v". + /// + /// + /// + public LiteralExpr(IToken/*!*/ tok, BigFloat v, bool immutable = false) + : base(tok, immutable) + { + Contract.Requires(tok != null); + Val = v; + Type = Type.GetFloatType(v.ExponentSize, v.SignificandSize); + if (immutable) + CachedHashCode = ComputeHashCode(); + } + + /// + /// Creates a literal expression for the bitvector value "v". + /// + public LiteralExpr(IToken/*!*/ tok, BigNum v, int b, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Contract.Requires(0 <= b); + Val = new BvConst(v, b); + Type = Type.GetBvType(b); + if (immutable) + CachedHashCode = ComputeHashCode(); + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is LiteralExpr)) + return false; + + LiteralExpr other = (LiteralExpr)obj; + return object.Equals(this.Val, other.Val); + } + + [Pure] + public override int GetHashCode() { + if (Immutable) + return this.CachedHashCode; + else + return ComputeHashCode(); + } + + [Pure] + public override int ComputeHashCode() { + return this.Val.GetHashCode(); + } + + public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + stream.SetToken(this); + if (this.Val is bool) { + stream.Write((bool)this.Val ? "true" : "false"); // correct capitalization + } else { + stream.Write(cce.NonNull(this.Val.ToString())); + } + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + // nothing to resolve + } + public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { + //Contract.Requires(freeVars != null); + // no free variables to add + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + this.Type = ShallowType; + } + + public override Type/*!*/ ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + if (Val is bool) { + return Type.Bool; + } else if (Val is BigNum) { + return Type.Int; + } else if (Val is BigDec) { + return Type.Real; + } else if (Val is BigFloat) { + BigFloat temp = (BigFloat)Val; + return Type.GetFloatType(temp.ExponentSize, temp.SignificandSize); + } else if (Val is BvConst) { + return Type.GetBvType(((BvConst)Val).Bits); + } else { + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // like, where did this value come from?! + } + } + } + + public bool IsFalse { + get { + return Val is bool && ((bool)Val) == false; + } + } + public bool IsTrue { + get { + return Val is bool && ((bool)Val) == true; + } + } + + // should be eliminated after converting everything to BigNums + private int asInt { + get { + return asBigNum.ToIntSafe; + } + } + + public bool isBigNum { + get { + return Val is BigNum; + } + } + + public BigNum asBigNum { + get { + Contract.Assert(isBigNum); + return (BigNum)cce.NonNull(Val); + } + } + + public bool isBigDec { + get { + return Val is BigDec; + } + } + + public bool isBigFloat + { + get + { + return Val is BigFloat; + } + } + + public BigDec asBigDec { + get { + Contract.Assert(isBigDec); + return (BigDec)cce.NonNull(Val); + } + } + + public BigFloat asBigFloat { + get { + Contract.Assert(isBigFloat); + return (BigFloat)cce.NonNull(Val); + } + } + + public bool isBool { + get { + return Val is bool; + } + } + + public bool asBool { + get { + Contract.Assert(isBool); + return (bool)cce.NonNull(Val); + } + } + + public bool isBvConst { + get { + return Val is BvConst; + } + } + + public BvConst asBvConst { + get { + Contract.Assert(isBvConst); + return (BvConst)cce.NonNull(Val); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitLiteralExpr(this); + } + } + + public class BvConst { + public readonly BigNum Value; + public readonly int Bits; + + public BvConst(BigNum v, int b) { + Contract.Assert(v.Signum >= 0); + Value = v; + Bits = b; + } + + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result() != null); + return Value + "bv" + Bits; + } + + [Pure] + public string ToReadableString() { + Contract.Ensures(Contract.Result() != null); + if (Value > BigNum.FromInt(10000)) { + string val = cce.NonNull(Value.ToString("x")); + int pos = val.Length % 4; + string res = "0x" + val.Substring(0, pos); + Contract.Assert(res != null); + while (pos < val.Length) { + res += "." + val.Substring(pos, 4); + pos += 4; + } + return res + ".bv" + Bits; + } else + return ToString(); + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + BvConst other = obj as BvConst; + if (other == null) + return false; + + return Bits == other.Bits && Value == other.Value; + } + + [Pure] + public override int GetHashCode() { + unchecked { + return Value.GetHashCode() ^ Bits; + } + } + } + + public class IdentifierExpr : Expr { + private string _Name; + public string Name { // identifier symbol + get { + return _Name; + } + set { + if (Immutable) + throw new InvalidOperationException("Cannot change Name on Immutable Expr"); + + _Name = value; + } + } + private Variable _Decl; + public Variable Decl { // identifier declaration + get { + return _Decl; + } + set { + if (Immutable) + throw new InvalidOperationException("Cannot change Decl on Immutable Expr"); + + _Decl = value; + } + } + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Name != null); + } + + + /// + /// Creates an unresolved identifier expression. This constructor is intended to be called + /// only from within the parser; for use inside the translation, use another constructor, which + /// specifies the type of the expression. + /// + /// + /// + internal IdentifierExpr(IToken/*!*/ tok, string/*!*/ name, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + _Name = name; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + /// + /// Creates an unresolved identifier expression. + /// + /// + /// + /// + public IdentifierExpr(IToken/*!*/ tok, string/*!*/ name, Type/*!*/ type, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + Contract.Requires(type != null); + _Name = name; + Type = type; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + + /// + /// Creates a resolved identifier expression. + /// + /// + /// + public IdentifierExpr(IToken/*!*/ tok, Variable/*!*/ d, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Contract.Requires(d != null); + _Name = cce.NonNull(d.Name); + _Decl = d; + Type = d.TypedIdent.Type; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is IdentifierExpr)) + return false; + + IdentifierExpr other = (IdentifierExpr)obj; + return object.Equals(this.Name, other.Name) && object.Equals(this.Decl, other.Decl); + } + + [Pure] + public override int GetHashCode() { + if (Immutable) + return this.CachedHashCode; + else + return ComputeHashCode(); + } + + [Pure] + public override int ComputeHashCode() { + int h = this.Name == null ? 0 : this.Name.GetHashCode(); + h ^= this.Decl == null ? 0 : this.Decl.GetHashCode(); + return h; + } + + public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + if (CommandLineOptions.Clo.PrintWithUniqueASTIds && !stream.UseForComputingChecksums) { + stream.Write("{0}^^", this.Decl == null ? "NoDecl" : "h" + this.Decl.GetHashCode()); + } + stream.Write(this, "{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + if (Decl != null) { + // already resolved, but re-resolve type just in case it came from an unresolved type + if (Type != null) { + Type = Type.ResolveType(rc); + } + return; + } + Decl = rc.LookUpVariable(Name); + if (Decl == null) { + rc.Error(this, "undeclared identifier: {0}", Name); + } else if (rc.StateMode == ResolutionContext.State.StateLess && Decl is GlobalVariable) { + rc.Error(this, "cannot refer to a global variable in this context: {0}", Name); + } + if (Type != null) { + Type = Type.ResolveType(rc); + } + } + public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { + //Contract.Requires(freeVars != null); + Contract.Assume(this.Decl != null); + freeVars.Add(Decl); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + if (this.Decl != null) { + // sanity check + if (Type != null && !Type.Equals(Decl.TypedIdent.Type)) { + tc.Error(this, "internal error, shallow-type assignment was done incorrectly, {0}:{1} != {2}", + Name, Type, Decl.TypedIdent.Type); + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } + } + Type = Decl.TypedIdent.Type; + } + } + + public override Type/*!*/ ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + Contract.Assert(Type != null); + return Type; + } + } + + public sealed class ConstantFunApp { + private IdentifierExpr/*!*/ identifierExpr; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(identifierExpr != null); + Contract.Invariant(emptyArgs != null); + } + + public IdentifierExpr/*!*/ IdentifierExpr { + get { + Contract.Requires(IdentifierExpr != null); + return identifierExpr; + } + } + + private static IList/*!*/ emptyArgs = ArrayList.ReadOnly(cce.NonNull((IList/*!*/)new ArrayList())); + public IList/*!*/ Arguments { + get { + Contract.Ensures(Contract.Result() != null); + return emptyArgs; + } + } + + public ConstantFunApp(IdentifierExpr ie, Constant c) { + Contract.Requires(c != null); + Contract.Requires(ie != null); + this.identifierExpr = ie; + } + + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitIdentifierExpr(this); + } + } + + public class OldExpr : Expr + { + private Expr _Expr; + public Expr/*!*/ Expr { + get { + return _Expr; + } + set { + if (Immutable) + throw new InvalidOperationException("Cannot change Expr of an Immutable OldExpr"); + + _Expr = value; + } + } + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Expr != null); + } + + public OldExpr(IToken/*!*/ tok, Expr/*!*/ expr, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + _Expr = expr; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is OldExpr)) + return false; + + OldExpr other = (OldExpr)obj; + return object.Equals(this.Expr, other.Expr); + } + [Pure] + public override int GetHashCode() { + if (Immutable) + return this.CachedHashCode; + else + return ComputeHashCode (); + } + public override int ComputeHashCode() { + // FIXME: This is wrong, it's as if the OldExpr node isn't there at all + return this.Expr == null ? 0 : this.Expr.GetHashCode(); + } + + public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + stream.Write(this, "old("); + this.Expr.Emit(stream); + stream.Write(")"); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + if (rc.StateMode != ResolutionContext.State.Two) { + rc.Error(this, "old expressions allowed only in two-state contexts"); + } + Expr.Resolve(rc); + } + public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { + //Contract.Requires(freeVars != null); + Expr.ComputeFreeVariables(freeVars); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + Expr.Typecheck(tc); + Type = Expr.Type; + } + public override Type/*!*/ ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + return Expr.ShallowType; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitOldExpr(this); + } + } + [ContractClass(typeof(IAppliableVisitorContracts<>))] + public interface IAppliableVisitor { + T Visit(UnaryOperator/*!*/ unaryOperator); + T Visit(BinaryOperator/*!*/ binaryOperator); + T Visit(FunctionCall/*!*/ functionCall); + T Visit(MapSelect/*!*/ mapSelect); + T Visit(MapStore/*!*/ mapStore); + T Visit(TypeCoercion/*!*/ typeCoercion); + T Visit(ArithmeticCoercion/*!*/ arithCoercion); + T Visit(IfThenElse/*!*/ ifThenElse); + } + [ContractClassFor(typeof(IAppliableVisitor<>))] + public abstract class IAppliableVisitorContracts : IAppliableVisitor { + + #region IAppliableVisitor Members + + public T Visit(UnaryOperator unaryOperator) { + Contract.Requires(unaryOperator != null); + throw new NotImplementedException(); + } + + public T Visit(BinaryOperator binaryOperator) { + Contract.Requires(binaryOperator != null); + throw new NotImplementedException(); + } + + public T Visit(FunctionCall functionCall) { + Contract.Requires(functionCall != null); + throw new NotImplementedException(); + } + + public T Visit(MapSelect mapSelect) { + Contract.Requires(mapSelect != null); + throw new NotImplementedException(); + } + + public T Visit(MapStore mapStore) { + Contract.Requires(mapStore != null); + throw new NotImplementedException(); + } + + public T Visit(TypeCoercion typeCoercion) { + Contract.Requires(typeCoercion != null); + throw new NotImplementedException(); + } + + public T Visit(ArithmeticCoercion arithCoercion) { + Contract.Requires(arithCoercion != null); + throw new NotImplementedException(); + } + + public T Visit(IfThenElse ifThenElse) { + Contract.Requires(ifThenElse != null); + throw new NotImplementedException(); + } + + #endregion + } + + [ContractClass(typeof(IAppliableContracts))] + public interface IAppliable { + string/*!*/ FunctionName { + get; + } + + /// + /// Emits to "stream" the operator applied to the given arguments. + /// The length of "args" can be anything that the parser allows for this appliable operator + /// (but can be nothing else). + /// + /// + /// + /// + /// + void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, int contextBindingStrength, bool fragileContext); + + void Resolve(ResolutionContext/*!*/ rc, Expr/*!*/ subjectForErrorReporting); + + /// + /// Requires the object to have been properly resolved. + /// + int ArgumentCount { + get; + } + + /// + /// Typechecks the arguments "args" for the Appliable. If the arguments are + /// appropriate, returns the result type; otherwise returns null. + /// As result of the type checking, the values of type parameters of the + /// appliable can be returned (which are then stored in the NAryExpr and later + /// also used in the VCExprAST). + /// Requires the object to have been successfully resolved. + /// Requires args.Length == ArgumentCount. + /// Requires all elements of "args" to have a non-null Type field. + /// + /// + /// + Type Typecheck(IList/*!*/ args, out TypeParamInstantiation/*!*/ tpInstantiation, TypecheckingContext/*!*/ tc); + + // Contract.Requires( Microsoft.SpecSharp.Collections.Reductions.Forall{Expr! arg in args; arg.Type != null}); + + /// + /// Returns the result type of the IAppliable, supposing the argument are of the correct types. + /// + Type/*!*/ ShallowType(IList/*!*/ args); + + T Dispatch(IAppliableVisitor/*!*/ visitor); + } + [ContractClassFor(typeof(IAppliable))] + abstract class IAppliableContracts : IAppliable { + + #region IAppliable Members + + public string FunctionName { + get { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + + public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + Contract.Requires(args != null); + Contract.Requires(stream != null); + throw new NotImplementedException(); + } + + public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { + Contract.Requires(rc != null); + Contract.Requires(subjectForErrorReporting != null); + throw new NotImplementedException(); + } + + public int ArgumentCount { + get { + throw new NotImplementedException(); + } + } + + public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { + Contract.Requires(args != null); + Contract.Requires(tc != null); + Contract.Ensures(Contract.ValueAtReturn(out args) != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + Contract.Ensures(args.Count == Contract.OldValue(args.Count)); + throw new NotImplementedException(); + } + + public Type ShallowType(IList args) { + Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + + throw new NotImplementedException(); + } + + public T Dispatch(IAppliableVisitor visitor) { + Contract.Requires(visitor != null); + throw new NotImplementedException(); + } + + #endregion + } + + + [ContractClass(typeof(IOverloadedAppliableContracts))] + public interface IOverloadedAppliable { + void ResolveOverloading(NAryExpr/*!*/ expr); + bool DoNotResolveOverloading { get; set; } + } + [ContractClassFor(typeof(IOverloadedAppliable))] + public abstract class IOverloadedAppliableContracts : IOverloadedAppliable { + + #region IOverloadedAppliable Members + + void IOverloadedAppliable.ResolveOverloading(NAryExpr expr) { + Contract.Requires(expr != null); + throw new NotImplementedException(); + } + + public bool DoNotResolveOverloading + { + get + { + throw new NotImplementedException(); + } + set + { + throw new NotImplementedException(); + } + } + + #endregion + } + + public class UnaryOperator : IAppliable { + private IToken/*!*/ tok; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(tok != null); + } + + public enum Opcode { + Neg, + Not + }; + private Opcode op; + public Opcode Op { + get { + return op; + } + } + public UnaryOperator(IToken tok, Opcode op) { + Contract.Requires(tok != null); + this.tok = tok; + this.op = op; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is UnaryOperator)) + return false; + + UnaryOperator other = (UnaryOperator)obj; + return object.Equals(this.op, other.op); + } + [Pure] + public override int GetHashCode() { + return (int)this.op; + } + + public string/*!*/ FunctionName { + get { + Contract.Ensures(Contract.Result() != null); + + switch (this.op) { + case Opcode.Neg: + return "-"; + case Opcode.Not: + return "!"; + } + System.Diagnostics.Debug.Fail("unknown unary operator: " + op.ToString()); + throw new Exception(); + } + } + + public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + //Contract.Requires(args != null); + stream.SetToken(ref this.tok); + Contract.Assert(args.Count == 1); + // determine if parens are needed + int opBindingStrength = 0x70; + bool parensNeeded = opBindingStrength < contextBindingStrength || + (fragileContext && opBindingStrength == contextBindingStrength); + + if (parensNeeded) { + stream.Write("("); + } + stream.Write(FunctionName); + cce.NonNull(args[0]).Emit(stream, opBindingStrength, false); + if (parensNeeded) { + stream.Write(")"); + } + } + + public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { + //Contract.Requires(subjectForErrorReporting != null); + //Contract.Requires(rc != null); + if (rc.TriggerMode && this.op == Opcode.Not) { + rc.Error(subjectForErrorReporting, "boolean operators are not allowed in triggers"); + } + } + + public int ArgumentCount { + get { + return 1; + } + } + + public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { + //Contract.Requires(tc != null); + //Contract.Requires(args != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + Contract.Ensures(Contract.ValueAtReturn(out args) != null); + + Contract.Assume(args.Count == 1); + tpInstantiation = SimpleTypeParamInstantiation.EMPTY; + Type arg0type = cce.NonNull(cce.NonNull(args[0]).Type); + switch (this.op) { + case Opcode.Neg: + if (arg0type.Unify(Type.Int)) { + return Type.Int; + } + if (arg0type.Unify(Type.Real)) { + return Type.Real; + } + //if (arg0type.Unify(Type.Float)) { + //return Type.Float; + //} + goto BAD_TYPE; + case Opcode.Not: + if (arg0type.Unify(Type.Bool)) { + return Type.Bool; + } + goto BAD_TYPE; + } + System.Diagnostics.Debug.Fail("unknown unary operator: " + op.ToString()); + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } + BAD_TYPE: + tc.Error(this.tok, "invalid argument type ({1}) to unary operator {0}", + this.FunctionName, arg0type); + return null; + } + public Type ShallowType(IList args) { + //Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + switch (this.op) { + case Opcode.Neg: + return cce.NonNull(cce.NonNull(args[0]).Type); + case Opcode.Not: + return Type.Bool; + default: { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // unexpected unary operator + } + } + + public object Evaluate(object argument) { + if (argument == null) { + return null; + } + switch (this.op) { + case Opcode.Neg: + if (argument is BigNum) { + return -((BigNum)argument); + } + if (argument is BigDec) { + return -((BigDec)argument); + } + if (argument is BigFloat) { + return -((BigFloat)argument); + } + break; + case Opcode.Not: + if (argument is bool) { + return !((bool)argument); + } + throw new System.InvalidOperationException("unary Not only applies to bool"); + } + return null; // unreachable + } + + public T Dispatch(IAppliableVisitor visitor) { + //Contract.Requires(visitor != null); + return visitor.Visit(this); + } + } + + public class BinaryOperator : IAppliable, IOverloadedAppliable { + private IToken/*!*/ tok; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(tok != null); + } + + public bool DoNotResolveOverloading { get; set; } + + public enum Opcode { + Add, + Sub, + Mul, + Div, + Mod, + RealDiv, + FloatDiv, + Pow, + Eq, + Neq, + Gt, + Ge, + Lt, + Le, + And, + Or, + Imp, + Iff, + Subtype + }; + private Opcode op; + public Opcode Op { + get { + return op; + } + } + public BinaryOperator(IToken tok, Opcode op) { + Contract.Requires(tok != null); + this.tok = tok; + this.op = op; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is BinaryOperator)) + return false; + + BinaryOperator other = (BinaryOperator)obj; + return object.Equals(this.op, other.op); + } + + [Pure] + public override int GetHashCode() { + return (int)this.op << 1; + } + + public string/*!*/ FunctionName { + get { + Contract.Ensures(Contract.Result() != null); + + switch (this.op) { + case Opcode.Add: + return "+"; + case Opcode.Sub: + return "-"; + case Opcode.Mul: + return "*"; + case Opcode.Div: + return "div"; + case Opcode.Mod: + return "mod"; + case Opcode.RealDiv: + return "/"; + case Opcode.Pow: + return "**"; + case Opcode.Eq: + return "=="; + case Opcode.Neq: + return "!="; + case Opcode.Gt: + return ">"; + case Opcode.Ge: + return ">="; + case Opcode.Lt: + return "<"; + case Opcode.Le: + return "<="; + case Opcode.And: + return "&&"; + case Opcode.Or: + return "||"; + case Opcode.Imp: + return "==>"; + case Opcode.Iff: + return "<==>"; + case Opcode.Subtype: + return "<:"; + } + System.Diagnostics.Debug.Fail("unknown binary operator: " + op.ToString()); + throw new Exception(); + } + } + + public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + //Contract.Requires(args != null); + stream.SetToken(ref this.tok); + Contract.Assert(args.Count == 2); + // determine if parens are needed + int opBindingStrength; + bool fragileLeftContext = false; // false means "allow same binding power on left without parens" + bool fragileRightContext = false; // false means "allow same binding power on right without parens" + switch (this.op) { + case Opcode.Add: + opBindingStrength = 0x40; + break; + case Opcode.Sub: + opBindingStrength = 0x40; + fragileRightContext = true; + break; + case Opcode.Mul: + opBindingStrength = 0x50; + break; + case Opcode.Div: + opBindingStrength = 0x50; + fragileRightContext = true; + break; + case Opcode.Mod: + opBindingStrength = 0x50; + fragileRightContext = true; + break; + case Opcode.RealDiv: + opBindingStrength = 0x50; + fragileRightContext = true; + break; + case Opcode.Pow: + opBindingStrength = 0x60; + fragileRightContext = true; + break; + case Opcode.Eq: + case Opcode.Neq: + case Opcode.Gt: + case Opcode.Ge: + case Opcode.Lt: + case Opcode.Le: + case Opcode.Subtype: + opBindingStrength = 0x30; + fragileLeftContext = fragileRightContext = true; + break; + case Opcode.And: + opBindingStrength = 0x20; + break; + case Opcode.Or: + opBindingStrength = 0x21; + break; + case Opcode.Imp: + opBindingStrength = 0x10; + fragileLeftContext = true; + break; + case Opcode.Iff: + opBindingStrength = 0x00; + break; + default: + System.Diagnostics.Debug.Fail("unknown binary operator: " + op.ToString()); + opBindingStrength = -1; // to please compiler, which refuses to consider whether or not all enumeration cases have been considered! + break; + } + int opBS = opBindingStrength & 0xF0; + int ctxtBS = contextBindingStrength & 0xF0; + bool parensNeeded = opBS < ctxtBS || + (opBS == ctxtBS && (opBindingStrength != contextBindingStrength || fragileContext)); + + var pop = stream.push(FunctionName); + if (parensNeeded) { + stream.Write("("); + } + cce.NonNull(args[0]).Emit(stream, opBindingStrength, fragileLeftContext); + stream.sep(); + stream.Write(" {0} ", FunctionName); + cce.NonNull(args[1]).Emit(stream, opBindingStrength, fragileRightContext); + if (parensNeeded) { + stream.Write(")"); + } + stream.pop(pop); + } + public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { + //Contract.Requires(subjectForErrorReporting != null); + //Contract.Requires(rc != null); + if (rc.TriggerMode) { + switch (this.op) { + case Opcode.Add: + case Opcode.Sub: + case Opcode.Mul: + case Opcode.Div: + case Opcode.Mod: + case Opcode.RealDiv: + case Opcode.Pow: + case Opcode.Neq: // Neq is allowed, but not Eq + case Opcode.Subtype: + // These are fine + break; + + case Opcode.Eq: + rc.Error(subjectForErrorReporting, "equality is not allowed in triggers"); + break; + + case Opcode.Gt: + case Opcode.Ge: + case Opcode.Lt: + case Opcode.Le: + rc.Error(subjectForErrorReporting, "arithmetic comparisons are not allowed in triggers"); + break; + + case Opcode.And: + case Opcode.Or: + case Opcode.Imp: + case Opcode.Iff: + rc.Error(subjectForErrorReporting, "boolean operators are not allowed in triggers"); + break; + + default: + System.Diagnostics.Debug.Fail("unknown binary operator: " + this.op.ToString()); + break; + } + } + } + public int ArgumentCount { + get { + return 2; + } + } + public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { + //Contract.Requires(tc != null); + //Contract.Requires(args != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + Contract.Ensures(args != null); + Contract.Assert(args.Count == 2); + // the default; the only binary operator with a type parameter is equality, but right + // we don't store this parameter because it does not appear necessary + tpInstantiation = SimpleTypeParamInstantiation.EMPTY; + Expr arg0 = cce.NonNull(args[0]); + Expr arg1 = cce.NonNull(args[1]); + Type arg0type = cce.NonNull(arg0.Type); + Type arg1type = cce.NonNull(arg1.Type); + switch (this.op) { + case Opcode.Add: + case Opcode.Sub: + case Opcode.Mul: + if (arg0type.Unify(Type.Int) && arg1type.Unify(Type.Int)) { + return Type.Int; + } + if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { + return Type.Real; + } + if (arg0type.IsFloat && arg0type.Unify(arg1type)) { + return Type.GetFloatType(arg0.Type.FloatExponent, arg0.Type.FloatMantissa); + } + if (arg1type.IsFloat && arg1type.Unify(arg0type)) { + return Type.GetFloatType(arg1.Type.FloatExponent, arg1.Type.FloatMantissa); + } + goto BAD_TYPE; + case Opcode.Div: + case Opcode.Mod: + if (arg0type.Unify(Type.Int) && arg1type.Unify(Type.Int)) { + return Type.Int; + } + goto BAD_TYPE; + case Opcode.RealDiv: + if ((arg0type.Unify(Type.Int) || arg0type.Unify(Type.Real)) && + (arg1type.Unify(Type.Int) || arg1type.Unify(Type.Real))) { + return Type.Real; + } + if (arg0type.IsFloat && arg0type.Unify(arg1type)) { + return Type.GetFloatType(arg0.Type.FloatExponent, arg0.Type.FloatMantissa); + } + if (arg1type.IsFloat && arg1type.Unify(arg0type)) { + return Type.GetFloatType(arg1.Type.FloatExponent, arg1.Type.FloatMantissa); + } + goto BAD_TYPE; + case Opcode.Pow: + if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { + return Type.Real; + } + goto BAD_TYPE; + case Opcode.Eq: + case Opcode.Neq: + // Comparison is allowed if the argument types are unifiable + // (i.e., if there is any chance that the values of the arguments are + // in the same domain) + if (arg0type.Equals(arg1type)) { + // quick path + return Type.Bool; + } + List/*!*/ unifiable = new List(); + unifiable.AddRange(arg0type.FreeVariables); + unifiable.AddRange(arg1type.FreeVariables); + + if (arg0type.Unify(arg1type, unifiable, new Dictionary())) + return Type.Bool; + goto BAD_TYPE; + case Opcode.Gt: + case Opcode.Ge: + case Opcode.Lt: + case Opcode.Le: + if (arg0type.Unify(Type.Int) && arg1type.Unify(Type.Int)) { + return Type.Bool; + } + if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { + return Type.Bool; + } + if ((arg0type.IsFloat && arg0type.Unify(arg1type)) || (arg1type.IsFloat && arg1type.Unify(arg0type))) { + return Type.Bool; + } + goto BAD_TYPE; + case Opcode.And: + case Opcode.Or: + case Opcode.Imp: + case Opcode.Iff: + if (arg0type.Unify(Type.Bool) && arg1type.Unify(Type.Bool)) { + return Type.Bool; + } + goto BAD_TYPE; + case Opcode.Subtype: + // Subtype is polymorphically typed and can compare things of + // arbitrary types (but both arguments must have the same type) + if (arg0type.Unify(arg1type)) { + return Type.Bool; + } + goto BAD_TYPE; + } + System.Diagnostics.Debug.Fail("unknown binary operator: " + op.ToString()); + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } + BAD_TYPE: + tc.Error(this.tok, "invalid argument types ({1} and {2}) to binary operator {0}", this.FunctionName, arg0type, arg1type); + return null; + } + + public Type ShallowType(IList args) { + //Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + switch (this.op) { + case Opcode.Add: + case Opcode.Sub: + case Opcode.Mul: + return cce.NonNull(args[0]).ShallowType; + + case Opcode.Div: + case Opcode.Mod: + return Type.Int; + + case Opcode.RealDiv: + case Opcode.Pow: + return Type.Real; + + case Opcode.Eq: + case Opcode.Neq: + case Opcode.Gt: + case Opcode.Ge: + case Opcode.Lt: + case Opcode.Le: + case Opcode.And: + case Opcode.Or: + case Opcode.Imp: + case Opcode.Iff: + case Opcode.Subtype: + return Type.Bool; + + default: { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // unexpected binary operator + } + } + + public void ResolveOverloading(NAryExpr expr) { + //Contract.Requires(expr != null); + + // immutable Expr must not be modified + if (DoNotResolveOverloading || expr.Immutable) + { + return; + } + + Expr arg0 = cce.NonNull(expr.Args[0]); + Expr arg1 = cce.NonNull(expr.Args[1]); + switch (op) { + case Opcode.Eq: + if (arg0.Type != null && arg0.Type.IsBool && arg1.Type != null && arg1.Type.IsBool) { + expr.Fun = new BinaryOperator(tok, Opcode.Iff); + } + break; + case Opcode.Neq: + if (arg0.Type != null && arg0.Type.IsBool && arg1.Type != null && arg1.Type.IsBool) { + expr.Fun = new BinaryOperator(tok, Opcode.Iff); + var arg1New = new NAryExpr(expr.tok, new UnaryOperator(tok, UnaryOperator.Opcode.Not), new List { arg1 }); + + // ugly ... there should be some more general approach, + // e.g., to typecheck the whole expression again + arg1New.Type = Type.Bool; + arg1New.TypeParameters = SimpleTypeParamInstantiation.EMPTY; + + expr.Args[1] = arg1New; + } + break; + } + } + + public object Evaluate(object e1, object e2) { + if (e1 == null || e2 == null) { + return null; + } + + switch (this.op) { + case Opcode.Add: + if (e1 is BigNum && e2 is BigNum) { + return ((BigNum)e1) + ((BigNum)e2); + } + if (e1 is BigDec && e2 is BigDec) { + return ((BigDec)e1) + ((BigDec)e2); + } + if (e1 is BigFloat && e2 is BigFloat) { + return ((BigFloat)e1) + ((BigFloat)e2); + } + break; + case Opcode.Sub: + if (e1 is BigNum && e2 is BigNum) { + return ((BigNum)e1) - ((BigNum)e2); + } + if (e1 is BigDec && e2 is BigDec) { + return ((BigDec)e1) - ((BigDec)e2); + } + if (e1 is BigFloat && e2 is BigFloat) { + return ((BigFloat)e1) - ((BigFloat)e2); + } + break; + case Opcode.Mul: + if (e1 is BigNum && e2 is BigNum) { + return ((BigNum)e1) * ((BigNum)e2); + } + if (e1 is BigDec && e2 is BigDec) { + return ((BigDec)e1) * ((BigDec)e2); + } + if (e1 is BigFloat && e2 is BigFloat) { + return ((BigFloat)e1) * ((BigFloat)e2); + } + break; + case Opcode.Div: + if (e1 is BigNum && e2 is BigNum) { + return /* TODO: right semantics? */ ((BigNum)e1) / ((BigNum)e2); + } + break; + case Opcode.Mod: + if (e1 is BigNum && e2 is BigNum) { + return /* TODO: right semantics? */ ((BigNum)e1) % ((BigNum)e2); + } + break; + case Opcode.RealDiv: + // TODO: add partial evaluation fro real division + break; + case Opcode.FloatDiv: + //TODO: add float division + break; + case Opcode.Pow: + // TODO: add partial evaluation fro real exponentiation + break; + case Opcode.Lt: + if (e1 is BigNum && e2 is BigNum) { + return ((BigNum)e1) < ((BigNum)e2); + } + if (e1 is BigDec && e2 is BigDec) { + return ((BigDec)e1) < ((BigDec)e2); + } + if (e1 is BigFloat && e2 is BigFloat) { + return ((BigFloat)e1) < ((BigFloat)e2); + } + break; + case Opcode.Le: + if (e1 is BigNum && e2 is BigNum) { + return ((BigNum)e1) <= ((BigNum)e2); + } + if (e1 is BigDec && e2 is BigDec) { + return ((BigDec)e1) <= ((BigDec)e2); + } + if (e1 is BigFloat && e2 is BigFloat) { + return ((BigFloat)e1) <= ((BigFloat)e2); + } + break; + case Opcode.Gt: + if (e1 is BigNum && e2 is BigNum) { + return ((BigNum)e1) > ((BigNum)e2); + } + if (e1 is BigDec && e2 is BigDec) { + return ((BigDec)e1) > ((BigDec)e2); + } + if (e1 is BigFloat && e2 is BigFloat) { + return ((BigFloat)e1) > ((BigFloat)e2); + } + break; + case Opcode.Ge: + if (e1 is BigNum && e2 is BigNum) { + return ((BigNum)e1) >= ((BigNum)e2); + } + if (e1 is BigDec && e2 is BigDec) { + return ((BigDec)e1) >= ((BigDec)e2); + } + if (e1 is BigFloat && e2 is BigFloat) { + return ((BigFloat)e1) >= ((BigFloat)e2); + } + break; + + case Opcode.And: + if (e1 is bool && e2 is bool) { + return (bool)e1 && (bool)e2; + } + break; + case Opcode.Or: + if (e1 is bool && e2 is bool) { + return (bool)e1 || (bool)e2; + } + break; + case Opcode.Imp: + if (e1 is bool && e2 is bool) { + return !(bool)e1 || (bool)e2; + } + break; + case Opcode.Iff: + if (e1 is bool && e2 is bool) { + return e1 == e2; + } + break; + + case Opcode.Eq: + return Equals(e1, e2); + case Opcode.Neq: + return !Equals(e1, e2); + + case Opcode.Subtype: + throw new System.NotImplementedException(); + } + throw new System.InvalidOperationException("bad types to binary operator " + this.op); + } + + public T Dispatch(IAppliableVisitor visitor) { + //Contract.Requires(visitor != null); + return visitor.Visit(this); + } + + } + + public class FunctionCall : IAppliable { + private IdentifierExpr/*!*/ name; + public Function Func; + public FunctionCall(IdentifierExpr name) { + Contract.Requires(name != null); + this.name = name; + } + public FunctionCall(Function f) { + Contract.Requires(f != null); + this.Func = f; + this.name = new IdentifierExpr(Token.NoToken, f.Name); + + // We need set the type of this IdentifierExpr so ShallowType() works + Debug.Assert(f.OutParams.Count > 0); + this.name.Type = f.OutParams[0].TypedIdent.Type; + } + public string/*!*/ FunctionName { + get { + Contract.Ensures(Contract.Result() != null); + return this.name.Name; + } + } + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(name != null); + } + + public FunctionCall createUnresolvedCopy() + { + return new FunctionCall(new IdentifierExpr(name.tok, name.Name, name.Type)); + } + + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result() != null); + return name.Name; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object other) { + FunctionCall fc = other as FunctionCall; + return fc != null && this.Func == fc.Func; + } + [Pure] + public override int GetHashCode() { + Contract.Assume(this.Func != null); + return Func.GetHashCode(); + } + + virtual public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + //Contract.Requires(args != null); + + if (stream.UseForComputingChecksums && Func.OriginalLambdaExprAsString != null) + { + stream.Write(Func.OriginalLambdaExprAsString); + } + else + { + this.name.Emit(stream, 0xF0, false); + } + if (stream.UseForComputingChecksums) + { + var c = Func.DependencyChecksum; + if (c != null) + { + stream.Write(string.Format("[dependency_checksum:{0}]", c)); + } + } + stream.Write("("); + args.Emit(stream); + stream.Write(")"); + } + public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { + //Contract.Requires(subjectForErrorReporting != null); + //Contract.Requires(rc != null); + if (Func != null) { + // already resolved + return; + } + Func = rc.LookUpProcedure(name.Name) as Function; + if (Func == null) { + rc.Error(this.name, "use of undeclared function: {0}", name.Name); + } + else if (name.Type == null) { + // We need set the type of this IdentifierExpr so ShallowType() works + Debug.Assert(name.Type == null); + Debug.Assert(Func.OutParams.Count > 0); + name.Type = Func.OutParams[0].TypedIdent.Type; + } + } + public virtual int ArgumentCount { + get { + Contract.Assume(Func != null); // ArgumentCount requires object to be properly resolved. + return Func.InParams.Count; + } + } + public virtual Type Typecheck(IList actuals, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { + //Contract.Requires(tc != null); + //Contract.Requires(actuals != null); + Contract.Ensures(Contract.ValueAtReturn(out actuals) != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + Contract.Assume(this.Func != null); + Contract.Assume(actuals.Count == Func.InParams.Count); + Contract.Assume(Func.OutParams.Count == 1); + + List/*!*/ resultingTypeArgs; + List actualResultType = + Type.CheckArgumentTypes(Func.TypeParameters, + out resultingTypeArgs, + new List(Func.InParams.Select(Item => Item.TypedIdent.Type).ToArray()), + actuals, + new List(Func.OutParams.Select(Item => Item.TypedIdent.Type).ToArray()), + null, + // we need some token to report a possibly wrong number of + // arguments + actuals.Count > 0 ? cce.NonNull(actuals[0]).tok : Token.NoToken, + "application of " + name.Name, + tc); + + if (actualResultType == null) { + tpInstantiation = SimpleTypeParamInstantiation.EMPTY; + return null; + } else { + Contract.Assert(actualResultType.Count == 1); + tpInstantiation = + SimpleTypeParamInstantiation.From(Func.TypeParameters, resultingTypeArgs); + return actualResultType[0]; + } + } + public Type ShallowType(IList args) { + //Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + Contract.Assume(name.Type != null); + return name.Type; + } + + public virtual T Dispatch(IAppliableVisitor visitor) { + //Contract.Requires(visitor != null); + return visitor.Visit(this); + } + } + + public class TypeCoercion : IAppliable { + private IToken/*!*/ tok; + public Type/*!*/ Type; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(tok != null); + } + + public TypeCoercion(IToken tok, Type type) { + Contract.Requires(type != null); + Contract.Requires(tok != null); + this.tok = tok; + this.Type = type; + } + + public override bool Equals(object obj) { + TypeCoercion other = obj as TypeCoercion; + if (other == null) { + return false; + } else { + return object.Equals(Type, other.Type); + } + } + + + + public + string/*!*/ FunctionName { + get { + Contract.Ensures(Contract.Result() != null); + + return ":"; + } + } + + public void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, + int contextBindingStrength, bool fragileContext) { + //Contract.Requires(args != null); + //Contract.Requires(stream != null); + stream.SetToken(ref this.tok); + Contract.Assert(args.Count == 1); + // determine if parens are needed + int opBindingStrength = 0x80; + bool parensNeeded = opBindingStrength < contextBindingStrength || + (fragileContext && opBindingStrength == contextBindingStrength); + + if (parensNeeded) + stream.Write("("); + + cce.NonNull(args[0]).Emit(stream, opBindingStrength, false); + stream.Write("{0} ", FunctionName); + Type.Emit(stream, 0); + + if (parensNeeded) + stream.Write(")"); + } + + public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { + //Contract.Requires(subjectForErrorReporting != null); + //Contract.Requires(rc != null); + this.Type = this.Type.ResolveType(rc); + } + + public int ArgumentCount { + get { + return 1; + } + } + + public Type Typecheck(IList/*!*/ args, + out TypeParamInstantiation/*!*/ tpInstantiation, + TypecheckingContext/*!*/ tc) { + //Contract.Requires(args != null); + //Contract.Requires(tc != null); + Contract.Ensures(args != null); + + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + + Contract.Assume(args.Count == 1); + tpInstantiation = SimpleTypeParamInstantiation.EMPTY; + + if (!this.Type.Unify(cce.NonNull(cce.NonNull(args[0]).Type))) + tc.Error(this.tok, "{0} cannot be coerced to {1}", + cce.NonNull(args[0]).Type, this.Type); + return this.Type; + } + + public Type ShallowType(IList args) { + //Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + return this.Type; + } + + public T Dispatch(IAppliableVisitor visitor) { + //Contract.Requires(visitor != null); + return visitor.Visit(this); + } + + } + + public class ArithmeticCoercion : IAppliable { + public enum CoercionType { + ToInt, + ToReal, + ToFloat + } + + private IToken/*!*/ tok; + public readonly CoercionType Coercion; + private readonly string name; + private readonly Type type; + private readonly Type argType; + private readonly Type argType2; + private readonly int hashCode; + + public ArithmeticCoercion(IToken tok, CoercionType coercion) { + this.tok = tok; + this.Coercion = coercion; + + switch (coercion) { + case CoercionType.ToInt: + this.name = "int"; + this.type = Type.Int; + this.argType = Type.Real; + this.hashCode = 1; + break; + case CoercionType.ToReal: + this.name = "real"; + this.type = Type.Real; + this.argType = Type.Int; + this.hashCode = 2; + break; + default: + Contract.Assert(false); + break; + } + } + + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result() != null); + return this.name; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object other) { + ArithmeticCoercion ac = other as ArithmeticCoercion; + return ac != null && this.Coercion == ac.Coercion; + } + + [Pure] + public override int GetHashCode() { + return this.hashCode; + } + + public string/*!*/ FunctionName { + get { + return this.name; + } + } + + public int ArgumentCount { + get { + return 1; + } + } + + virtual public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + //Contract.Requires(args != null); + stream.Write(this.name); + stream.Write("("); + args.Emit(stream); + stream.Write(")"); + } + + public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { + //Contract.Requires(subjectForErrorReporting != null); + //Contract.Requires(rc != null); + } + + public virtual Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { + //Contract.Requires(tc != null); + //Contract.Requires(args != null); + Contract.Ensures(args != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + + Contract.Assert(args.Count == 1); + + tpInstantiation = SimpleTypeParamInstantiation.EMPTY; + + if (!(cce.NonNull(cce.NonNull(args[0]).Type).Unify(argType) || cce.NonNull(cce.NonNull(args[0]).Type).Unify(argType2))) + { + tc.Error(this.tok, "argument type {0} does not match expected type {1} or type {2}", cce.NonNull(args[0]).Type, this.argType, this.argType2); + } + + return this.type; + } + + public Type ShallowType(IList args) { + //Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + return this.type; + } + + public virtual T Dispatch(IAppliableVisitor visitor) { + //Contract.Requires(visitor != null); + return visitor.Visit(this); + } + } + + public class NAryExpr : Expr { + [Additive] + [Peer] + private IAppliable _Fun; + public IAppliable/*!*/ Fun { + get { + return _Fun; + } + set { + if (Immutable) + throw new InvalidOperationException("Cannot change Function used by Immutable NAryExpr"); + + _Fun = value; + } + } + private List _Args; + public IList Args { + get { + if (Immutable) + return _Args.AsReadOnly(); + else + return _Args; + } + set { + if (Immutable) + throw new InvalidOperationException("Cannot change Args of Immutable NAryExpr"); + + _Args = value as List; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Fun != null); + Contract.Invariant(Args != null); + } + + + // The instantiation of type parameters that is determined during type checking. + // Which type parameters are available depends on the IAppliable + public TypeParamInstantiation TypeParameters = null; + + [Captured] + public NAryExpr(IToken/*!*/ tok, IAppliable/*!*/ fun, IList/*!*/ args, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Contract.Requires(fun != null); + Contract.Requires(args != null); + _Fun = fun; + Contract.Assert(Contract.ForAll(0, args.Count, index => args[index] != null)); + if (immutable) { + // We need to make a new list because the client might be holding + // references to the list that they gave us which could be used to + // circumvent the immutability enforcement + _Args = new List(args); + CachedHashCode = ComputeHashCode(); + } else { + if (args is List) { + // Preserve NAryExpr's old behaviour, we take ownership of the List. + // We can only do this if the type matches + _Args = args as List; + } + else { + // Otherwise we must make a copy + _Args = new List (args); + } + } + } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is NAryExpr)) + return false; + + NAryExpr other = (NAryExpr)obj; + return object.Equals(this.Fun, other.Fun) && this.Args.SequenceEqual(other.Args); + } + + [Pure] + public override int GetHashCode() { + if (Immutable) + return this.CachedHashCode; + else + return ComputeHashCode(); + } + + [Pure] + public override int ComputeHashCode() { + int h = this.Fun.GetHashCode(); + // DO NOT USE Args.GetHashCode() because that uses Object.GetHashCode() which uses references + // We want structural equality + foreach (var arg in Args) { + h = (97*h) + arg.GetHashCode(); + } + return h; + } + public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + stream.SetToken(this); + Fun.Emit(Args, stream, contextBindingStrength, fragileContext); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + Fun.Resolve(rc, this); + foreach (Expr/*!*/ e in Args) { + Contract.Assert(e != null); + e.Resolve(rc); + } + } + public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { + //Contract.Requires(freeVars != null); + foreach (Expr/*!*/ e in Args) { + Contract.Assert(e != null); + e.ComputeFreeVariables(freeVars); + } + // also add the free type variables + if (TypeParameters != null) { + foreach (TypeVariable/*!*/ var in TypeParameters.FormalTypeParams) { + Contract.Assert(var != null); + foreach (TypeVariable/*!*/ w in TypeParameters[var].FreeVariables) { + Contract.Assert(w != null); + freeVars.Add(w); + } + } + } + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + int prevErrorCount = tc.ErrorCount; + foreach (Expr/*!*/ e in Args) { + Contract.Assert(e != null); + e.Typecheck(tc); + } + if (Fun.ArgumentCount != Args.Count) { + tc.Error(this, "wrong number of arguments to function: {0} ({1} instead of {2})", + Fun.FunctionName, Args.Count, Fun.ArgumentCount); + } else if (tc.ErrorCount == prevErrorCount && + // if the type parameters are set, this node has already been + // typechecked and does not need to be checked again + TypeParameters == null) { + TypeParamInstantiation tpInsts; + Type = Fun.Typecheck(Args, out tpInsts, tc); // Make sure we pass Args so if this Expr is immutable it is protected + TypeParameters = tpInsts; + } + IOverloadedAppliable oa = Fun as IOverloadedAppliable; + if (oa != null) { + oa.ResolveOverloading(this); + } + if (Type == null) { + // set Type to some non-null value + Type = new TypeProxy(this.tok, "type_checking_error"); + } + } + public override Type/*!*/ ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + return Fun.ShallowType(Args); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitNAryExpr(this); + } + } + + public class MapSelect : IAppliable { + + public readonly int Arity; + private readonly IToken/*!*/ tok; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(tok != null); + } + + + public MapSelect(IToken tok, int arity) { + Contract.Requires(tok != null); + this.tok = tok; + this.Arity = arity; + } + + public string/*!*/ FunctionName { + get { + Contract.Ensures(Contract.Result() != null); + + return "MapSelect"; + } + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (!(obj is MapSelect)) + return false; + + MapSelect other = (MapSelect)obj; + return this.Arity == other.Arity; + } + + [Pure] + public override int GetHashCode() { + return Arity.GetHashCode() * 2823; + } + + public void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, + int contextBindingStrength, bool fragileContext) { + //Contract.Requires(args != null); + //Contract.Requires(stream != null); + Contract.Assume(args.Count == Arity + 1); + Emit(args, stream, contextBindingStrength, fragileContext, false); + } + + public static void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, + int contextBindingStrength, bool fragileContext, + bool withRhs) { + Contract.Requires(args != null); + Contract.Requires(stream != null); + const int opBindingStrength = 0x90; + bool parensNeeded = opBindingStrength < contextBindingStrength || + (fragileContext && opBindingStrength == contextBindingStrength); + + if (parensNeeded) { + stream.Write("("); + } + cce.NonNull(args[0]).Emit(stream, opBindingStrength, false); + stream.Write("["); + + string sep = ""; + int lastIndex = withRhs ? args.Count - 1 : args.Count; + for (int i = 1; i < lastIndex; ++i) { + stream.Write(sep); + sep = ", "; + cce.NonNull(args[i]).Emit(stream); + } + + if (withRhs) { + stream.Write(" := "); + cce.NonNull(args.Last()).Emit(stream); + } + + stream.Write("]"); + if (parensNeeded) { + stream.Write(")"); + } + } + + public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { + //Contract.Requires(subjectForErrorReporting != null); + //Contract.Requires(rc != null); + // PR: nothing? + } + + public int ArgumentCount { + get { + return Arity + 1; + } + } + + // it is assumed that each of the arguments has already been typechecked + public static Type Typecheck(Type/*!*/ mapType, + // we just pass an Absy, because in + // the AssignCmd maps can also be + // represented by non-expressions + Absy/*!*/ map, + List/*!*/ indexes, + // the type parameters, in this context, are the parameters of the + // potentially polymorphic map type. Because it might happen that + // the whole map type is unknown and represented using a MapTypeProxy, + // the instantiations given in the following out-parameter are subject + // to change if further unifications are done. + out TypeParamInstantiation/*!*/ tpInstantiation, + TypecheckingContext/*!*/ tc, + IToken/*!*/ typeCheckingSubject, + string/*!*/ opName) { + Contract.Requires(mapType != null); + Contract.Requires(map != null); + Contract.Requires(indexes != null); + Contract.Requires(tc != null); + Contract.Requires(typeCheckingSubject != null); + Contract.Requires(opName != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + + mapType = mapType.Expanded; + if (mapType.IsMap && mapType.MapArity != indexes.Count) { + tc.Error(typeCheckingSubject, "wrong number of arguments in {0}: {1} instead of {2}", + opName, indexes.Count, mapType.MapArity); + tpInstantiation = SimpleTypeParamInstantiation.EMPTY; + return null; + } else if (!mapType.Unify(new MapTypeProxy(map.tok, "select", indexes.Count))) { + tc.Error(map.tok, "{0} applied to a non-map: {1}", opName, map); + tpInstantiation = SimpleTypeParamInstantiation.EMPTY; + return null; + } + mapType = TypeProxy.FollowProxy(mapType); + + if (mapType is MapType) { + MapType mt = (MapType)mapType; + return mt.CheckArgumentTypes(indexes, out tpInstantiation, + typeCheckingSubject, opName, tc); + } else { + MapTypeProxy mt = (MapTypeProxy)mapType; + return mt.CheckArgumentTypes(indexes, out tpInstantiation, + typeCheckingSubject, opName, tc); + } + } + + public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { + //Contract.Requires(tc != null); + //Contract.Requires(args != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + Contract.Assume(args.Count == Arity + 1); + + // FIXME: Wny are we passing a copy? + List actualArgs = new List(); + for (int i = 1; i < args.Count; ++i) + actualArgs.Add(args[i]); + + return Typecheck(cce.NonNull(cce.NonNull(args[0]).Type), cce.NonNull(args[0]), + actualArgs, out tpInstantiation, tc, this.tok, "map select"); + } + + /// + /// Returns the result type of the IAppliable, supposing the argument are of the correct types. + /// + public Type ShallowType(IList args) { + //Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + Expr a0 = cce.NonNull(args[0]); + Type a0Type = a0.ShallowType; + if (a0Type == null || !a0Type.IsMap) { + // we are unable to determine the type of the select, so just return an arbitrary type + return Type.Int; + } + MapType mapType = a0Type.AsMap; + List actualArgTypes = new List(); + for (int i = 1; i < args.Count; ++i) { + actualArgTypes.Add(cce.NonNull(args[i]).ShallowType); + } + return Type.InferValueType(mapType.TypeParameters, mapType.Arguments, mapType.Result, actualArgTypes); + } + + public T Dispatch(IAppliableVisitor visitor) { + //Contract.Requires(visitor != null); + return visitor.Visit(this); + } + } + + public class MapStore : IAppliable { + + public readonly int Arity; + public readonly IToken/*!*/ tok; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(tok != null); + } + + + public MapStore(IToken tok, int arity) { + Contract.Requires(tok != null); + this.tok = tok; + this.Arity = arity; + } + + public string/*!*/ FunctionName { + get { + Contract.Ensures(Contract.Result() != null); + + return "MapStore"; + } + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (!(obj is MapStore)) + return false; + + MapStore other = (MapStore)obj; + return this.Arity == other.Arity; + } + + [Pure] + public override int GetHashCode() { + return Arity.GetHashCode() * 28231; + } + + public void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, + int contextBindingStrength, bool fragileContext) { + //Contract.Requires(args != null); + //Contract.Requires(stream != null); + Contract.Assert(args.Count == Arity + 2); + MapSelect.Emit(args, stream, contextBindingStrength, fragileContext, true); + } + + public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { + //Contract.Requires(subjectForErrorReporting != null); + //Contract.Requires(rc != null); + // PR: nothing? + } + + public int ArgumentCount { + get { + return Arity + 2; + } + } + + // it is assumed that each of the arguments has already been typechecked + public static Type Typecheck(IList/*!*/ args, out TypeParamInstantiation/*!*/ tpInstantiation, + TypecheckingContext/*!*/ tc, + IToken/*!*/ typeCheckingSubject, + string/*!*/ opName) { + Contract.Requires(args != null); + Contract.Requires(tc != null); + Contract.Requires(typeCheckingSubject != null); + Contract.Requires(opName != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + + // part of the type checking works exactly as for MapSelect + List selectArgs = new List(); + for (int i = 1; i < args.Count - 1; ++i) + selectArgs.Add(args[i]); + Type resultType = + MapSelect.Typecheck(cce.NonNull(cce.NonNull(args[0]).Type), cce.NonNull(args[0]), + selectArgs, out tpInstantiation, tc, typeCheckingSubject, opName); + + // check the the rhs has the right type + if (resultType == null) { + // error messages have already been created by MapSelect.Typecheck + return null; + } + Type rhsType = cce.NonNull(cce.NonNull(args.Last()).Type); + if (!resultType.Unify(rhsType)) { + tc.Error(cce.NonNull(args.Last()).tok, + "right-hand side in {0} with wrong type: {1} (expected: {2})", + opName, rhsType, resultType); + return null; + } + + return cce.NonNull(args[0]).Type; + } + + public Type Typecheck(IList/*!*/ args, + out TypeParamInstantiation/*!*/ tpInstantiation, + TypecheckingContext/*!*/ tc) { + //Contract.Requires(args != null); + //Contract.Requires(tc != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + Contract.Ensures(Contract.ValueAtReturn(out args) != null); + Contract.Assert(args.Count == Arity + 2); + return Typecheck(args, out tpInstantiation, tc, this.tok, "map store"); + } + + /// + /// Returns the result type of the IAppliable, supposing the argument are of the correct types. + /// + public Type ShallowType(IList args) { + //Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + return cce.NonNull(args[0]).ShallowType; + } + + public T Dispatch(IAppliableVisitor visitor) { + //Contract.Requires(visitor != null); + return visitor.Visit(this); + } + } + + + public class IfThenElse : IAppliable { + + private IToken/*!*/ _tok; + + public IToken/*!*/ tok + { + get + { + Contract.Ensures(Contract.Result() != null); + return this._tok; + } + set + { + Contract.Requires(value != null); + this._tok = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._tok != null); + } + + public IfThenElse(IToken tok) { + Contract.Requires(tok != null); + this._tok = tok; + } + + public string/*!*/ FunctionName { + get { + Contract.Ensures(Contract.Result() != null); + + return "if-then-else"; + } + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (!(obj is IfThenElse)) + return false; + return true; + } + + [Pure] + public override int GetHashCode() { + return 1; + } + + public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + //Contract.Requires(args != null); + stream.SetToken(this); + Contract.Assert(args.Count == 3); + stream.push(); + stream.Write("(if "); + cce.NonNull(args[0]).Emit(stream, 0x00, false); + stream.sep(); + stream.Write(" then "); + cce.NonNull(args[1]).Emit(stream, 0x00, false); + stream.sep(); + stream.Write(" else "); + cce.NonNull(args[2]).Emit(stream, 0x00, false); + stream.Write(")"); + stream.pop(); + } + + public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { + //Contract.Requires(subjectForErrorReporting != null); + //Contract.Requires(rc != null); + // PR: nothing? + } + + public int ArgumentCount { + get { + return 3; + } + } + + public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { + //Contract.Requires(tc != null); + //Contract.Requires(args != null); + Contract.Ensures(args != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + Contract.Assert(args.Count == 3); + // the default; the only binary operator with a type parameter is equality, but right + // we don't store this parameter because it does not appear necessary + tpInstantiation = SimpleTypeParamInstantiation.EMPTY; + Expr arg0 = cce.NonNull(args[0]); + Expr arg1 = cce.NonNull(args[1]); + Expr arg2 = cce.NonNull(args[2]); + + if (!cce.NonNull(arg0.Type).Unify(Type.Bool)) { + tc.Error(this.tok, "the first argument to if-then-else should be bool, not {0}", arg0.Type); + } else if (!cce.NonNull(arg1.Type).Unify(cce.NonNull(arg2.Type))) { + tc.Error(this.tok, "branches of if-then-else have incompatible types {0} and {1}", arg1.Type, arg2.Type); + } else { + return arg1.Type; + } + + return null; + } + + /// + /// Returns the result type of the IAppliable, supposing the argument are of the correct types. + /// + public Type ShallowType(IList args) { + //Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + return cce.NonNull(args[1]).ShallowType; + } + + public T Dispatch(IAppliableVisitor visitor) { + //Contract.Requires(visitor != null); + return visitor.Visit(this); + } + } + + + + public class CodeExpr : Expr { + public List/*!*/ LocVars; + [Rep] + public List/*!*/ Blocks; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(LocVars != null); + Contract.Invariant(cce.NonNullElements(Blocks)); + } + + public CodeExpr(List/*!*/ localVariables, List/*!*/ blocks, bool immutable=false) + : base(Token.NoToken, immutable) { + Contract.Requires(localVariables != null); + Contract.Requires(cce.NonNullElements(blocks)); + Contract.Requires(0 < blocks.Count); + LocVars = localVariables; + Blocks = blocks; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + + // FIXME: This seems wrong we don't want reference equality, we want structural equality + [Pure] + public override bool Equals(object obj) + { + return base.Equals(obj); + } + + [Pure] + public override int GetHashCode() + { + if (Immutable) + return CachedHashCode; + else + return ComputeHashCode(); + } + + [Pure] + public override int ComputeHashCode() { + return base.GetHashCode(); + } + + + public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { + //Contract.Requires(freeVars != null); + // Treat a BlockEexpr as if it has no free variables at all + } + public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + //level++; + int level = 0; + stream.WriteLine(level, "|{"); + + if (this.LocVars.Count > 0) { + stream.Write(level + 1, "var "); + this.LocVars.Emit(stream, true); + stream.WriteLine(";"); + } + + foreach (Block/*!*/ b in this.Blocks) { + Contract.Assert(b != null); + b.Emit(stream, level + 1); + } + + stream.WriteLine(); + stream.WriteLine(level, "}|"); + + stream.WriteLine(); + stream.WriteLine(); + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + + rc.PushVarContext(); + foreach (Variable/*!*/ v in LocVars) { + Contract.Assert(v != null); + v.Register(rc); + v.Resolve(rc); + } + + rc.PushProcedureContext(); + foreach (Block/*!*/ b in Blocks) { + Contract.Assert(b != null); + b.Register(rc); + } + + foreach (Block/*!*/ b in Blocks) { + Contract.Assert(b != null); + b.Resolve(rc); + } + + rc.PopProcedureContext(); + rc.PopVarContext(); + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + foreach (Variable/*!*/ v in LocVars) { + Contract.Assert(v != null); + v.Typecheck(tc); + } + foreach (Block/*!*/ b in Blocks) { + Contract.Assert(b != null); + b.Typecheck(tc); + } + this.Type = Type.Bool; + } + public override Type/*!*/ ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + return Type.Bool; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitCodeExpr(this); + } + } + + public class BvExtractExpr : Expr { + private /*readonly--except in StandardVisitor*/ Expr/*!*/ _Bitvector; + public Expr Bitvector { + get { + return _Bitvector; + } + set { + if (Immutable) + throw new InvalidOperationException("Cannot change BitVector field of an immutable BvExtractExpr"); + + _Bitvector = value; + } + } + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(_Bitvector != null); + } + + public readonly int Start, End; + + public BvExtractExpr(IToken/*!*/ tok, Expr/*!*/ bv, int end, int start, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Contract.Requires(bv != null); + _Bitvector = bv; + Start = start; + End = end; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is BvExtractExpr)) + return false; + + BvExtractExpr other = (BvExtractExpr)obj; + return object.Equals(this.Bitvector, other.Bitvector) && + this.Start.Equals(other.Start) && this.End.Equals(other.End); + } + + [Pure] + public override int GetHashCode() { + if (Immutable) + return CachedHashCode; + else + return ComputeHashCode(); + } + + [Pure] + public override int ComputeHashCode() { + int h = this.Bitvector.GetHashCode(); + h ^= Start * 17 ^ End * 13; + return h; + } + public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + stream.SetToken(this); + int opBindingStrength = 0x90; + bool parensNeeded = opBindingStrength < contextBindingStrength || + (fragileContext && opBindingStrength == contextBindingStrength); + + if (parensNeeded) { + stream.Write("("); + } + Bitvector.Emit(stream, opBindingStrength, false); + stream.Write("[" + End + ":" + Start + "]"); + if (parensNeeded) { + stream.Write(")"); + } + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + Bitvector.Resolve(rc); + } + public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { + //Contract.Requires(freeVars != null); + Bitvector.ComputeFreeVariables(freeVars); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + Bitvector.Typecheck(tc); + Contract.Assert(Bitvector.Type != null); // follows from postcondition of Expr.Typecheck + + if (Start < 0) { + tc.Error(this, "start index in extract must not be negative"); + } else if (End < 0) { + tc.Error(this, "end index in extract must not be negative"); + } else if (End < Start) { + tc.Error(this, "start index in extract must be no bigger than the end index"); + } else { + Type typeConstraint = new BvTypeProxy(this.tok, "extract", End - Start); + if (typeConstraint.Unify(Bitvector.Type)) { + Type = Type.GetBvType(End - Start); + } else { + tc.Error(this, "extract operand must be a bitvector of at least {0} bits (got {1})", End - Start, Bitvector.Type); + } + } + if (Type == null) { + Type = new TypeProxy(this.tok, "type_checking_error"); + } + } + + public override Type/*!*/ ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + return Type.GetBvType(End - Start); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitBvExtractExpr(this); + } + } + + public class BvConcatExpr : Expr { + private /*readonly--except in StandardVisitor*/ Expr/*!*/ _E0, _E1; + public Expr E0 { + get { + return _E0; + } + set { + if (Immutable) + throw new InvalidOperationException("Can't change E0 reference on immutable Expr"); + + _E0 = value; + } + } + public Expr E1 { + get { + return _E1; + } + set { + if (Immutable) + throw new InvalidOperationException("Can't change E1 reference on immutable Expr"); + + _E1 = value; + } + } + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(E0 != null); + Contract.Invariant(E1 != null); + } + + + public BvConcatExpr(IToken/*!*/ tok, Expr/*!*/ e0, Expr/*!*/ e1, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); + _E0 = e0; + _E1 = e1; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is BvConcatExpr)) + return false; + + BvConcatExpr other = (BvConcatExpr)obj; + return object.Equals(this.E0, other.E0) && object.Equals(this.E1, other.E1); + } + + [Pure] + public override int GetHashCode() + { + if (Immutable) + return CachedHashCode; + else + return ComputeHashCode(); + } + + [Pure] + public override int ComputeHashCode() { + int h = this.E0.GetHashCode() ^ this.E1.GetHashCode() * 17; + return h; + } + + public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + stream.SetToken(this); + int opBindingStrength = 0x32; + bool parensNeeded = opBindingStrength < contextBindingStrength || + (fragileContext && opBindingStrength == contextBindingStrength); + + if (parensNeeded) { + stream.Write("("); + } + E0.Emit(stream, opBindingStrength, false); + stream.Write(" ++ "); + // while this operator is associative, our incomplete axioms in int translation don't + // make much use of it, so better stick to the actual tree shape + E1.Emit(stream, opBindingStrength, true); + if (parensNeeded) { + stream.Write(")"); + } + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + E0.Resolve(rc); + E1.Resolve(rc); + } + public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { + //Contract.Requires(freeVars != null); + E0.ComputeFreeVariables(freeVars); + E1.ComputeFreeVariables(freeVars); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + E0.Typecheck(tc); + Contract.Assert(E0.Type != null); // follows from postcondition of Expr.Typecheck + E1.Typecheck(tc); + Contract.Assert(E1.Type != null); // follows from postcondition of Expr.Typecheck + + if (E0.Type.Unify(new BvTypeProxy(this.tok, "concat0", 0)) && E1.Type.Unify(new BvTypeProxy(this.tok, "concat1", 0))) { + Type = new BvTypeProxy(this.tok, "concat", E0.Type, E1.Type); + } else { + tc.Error(this, "++ operands need to be bitvectors (got {0}, {1})", E0.Type, E1.Type); + } + if (Type == null) { + Type = new TypeProxy(this.tok, "type_checking_error"); + } + } + + public override Type/*!*/ ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + Type t0 = E0.ShallowType; + Type t1 = E1.ShallowType; + int len0 = t0.IsBv ? t0.BvBits : /*expression is not type correct, so just pick an arbitrary number of bits*/0; + int len1 = t1.IsBv ? t1.BvBits : /*expression is not type correct, so just pick an arbitrary number of bits*/0; + return Type.GetBvType(len0 + len1); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitBvConcatExpr(this); + } + } +} + diff --git a/Source/Core/AbsyQuant.cs b/Source/Core/AbsyQuant.cs index 2258e553..3a27eddf 100644 --- a/Source/Core/AbsyQuant.cs +++ b/Source/Core/AbsyQuant.cs @@ -1,930 +1,953 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -//--------------------------------------------------------------------------------------------- -// BoogiePL - AbsyQuant.cs -//--------------------------------------------------------------------------------------------- - -namespace Microsoft.Boogie { - using System; - using System.Collections; - using System.Diagnostics; - using System.Collections.Generic; - using System.Linq; - using Microsoft.Boogie.AbstractInterpretation; - using System.Diagnostics.Contracts; - using Microsoft.Basetypes; - - using Set = GSet; - - //--------------------------------------------------------------------- - // Quantifiers and general binders - //--------------------------------------------------------------------- - - public enum BinderKind { - Forall, - Exists, - Lambda - } - [ContractClassFor(typeof(BinderExpr))] - abstract class BinderExprContracts : BinderExpr { - public override BinderKind Kind { - get { - throw new NotImplementedException(); - } - } - public BinderExprContracts():base(null,null,null,null,null,false){ - } - - public override Type ShallowType { - get { - throw new NotImplementedException(); - } - } - } - [ContractClass(typeof(BinderExprContracts))] - public abstract class BinderExpr : Expr { - public List/*!*/ TypeParameters; - public List/*!*/ Dummies; - public QKeyValue Attributes; - // FIXME: Protect the above Fields - public Expr _Body; - public Expr/*!*/ Body { - get { - return _Body; - } - set { - if (Immutable) - throw new InvalidOperationException ("Cannot change the Body of an immutable BinderExpr"); - - _Body = value; - } - } - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(TypeParameters != null); - Contract.Invariant(Dummies != null); - Contract.Invariant(Body != null); - } - - public BinderExpr(IToken/*!*/ tok, List/*!*/ typeParameters, - List/*!*/ dummies, QKeyValue kv, Expr/*!*/ body, bool immutable) - : base(tok, immutable) { - Contract.Requires(tok != null); - Contract.Requires(typeParameters != null); - Contract.Requires(dummies != null); - Contract.Requires(body != null); - Contract.Requires(dummies.Count + typeParameters.Count > 0); - TypeParameters = typeParameters; - Dummies = dummies; - Attributes = kv; - _Body = body; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - - abstract public BinderKind Kind { - get; - } - - protected static bool CompareAttributesAndTriggers = false; - - public static bool EqualWithAttributesAndTriggers(object a, object b) { - CompareAttributesAndTriggers = true; - var res = object.Equals(a, b); - Contract.Assert(CompareAttributesAndTriggers); - CompareAttributesAndTriggers = false; - return res; - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - return BinderEquals(obj); - } - - public bool BinderEquals(object obj) { - if (obj == null) { - return false; - } - if (!(obj is BinderExpr) || - this.Kind != ((BinderExpr) obj).Kind) { - return false; - } - - var other = (BinderExpr) obj; - - return this.TypeParameters.SequenceEqual(other.TypeParameters) - && this.Dummies.SequenceEqual(other.Dummies) - && (!CompareAttributesAndTriggers || object.Equals(this.Attributes, other.Attributes)) - && object.Equals(this.Body, other.Body); - } - - [Pure] - public override int GetHashCode() - { - if (Immutable) - return CachedHashCode; - else - return ComputeHashCode(); - } - - [Pure] - public override int ComputeHashCode() { - // Note, we don't hash triggers and attributes - - // DO NOT USE Dummies.GetHashCode() because we want structurally - // identical Expr to have the same hash code **not** identical references - // to have the same hash code. - int h = 0; - foreach (var dummyVar in this.Dummies) { - h = ( 53 * h ) + dummyVar.GetHashCode(); - } - - h ^= this.Body.GetHashCode(); - - // DO NOT USE TypeParameters.GetHashCode() because we want structural - // identical Expr to have the same hash code **not** identical references - // to have the same hash code. - int h2 = 0; - foreach (var typeParam in this.TypeParameters) { - h2 = ( 97 * h2 ) + typeParam.GetHashCode(); - } - - h = h * 5 + h2; - h *= ((int)Kind + 1); - return h; - } - - protected virtual void EmitTypeHint(TokenTextWriter stream) { - Contract.Requires(stream != null); - } - - protected virtual void EmitTriggers(TokenTextWriter stream) { - Contract.Requires(stream != null); - } - - public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - stream.push(); - stream.Write(this, "({0}", Kind.ToString().ToLower()); - this.EmitTypeHint(stream); - Type.EmitOptionalTypeParams(stream, TypeParameters); - stream.Write(this, " "); - this.Dummies.Emit(stream, true); - stream.Write(" :: "); - stream.sep(); - for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { - kv.Emit(stream); - stream.Write(" "); - } - this.EmitTriggers(stream); - stream.sep(); - - this.Body.Emit(stream); - stream.Write(")"); - stream.pop(); - } - - protected virtual void ResolveTriggers(ResolutionContext rc) { - Contract.Requires(rc != null); - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - if (rc.TriggerMode) { - rc.Error(this, "quantifiers are not allowed in triggers"); - } - - int previousTypeBinderState = rc.TypeBinderState; - try { - foreach (TypeVariable/*!*/ v in TypeParameters) { - Contract.Assert(v != null); - rc.AddTypeBinder(v); - } - - rc.PushVarContext(); - foreach (Variable/*!*/ v in Dummies) { - Contract.Assert(v != null); - v.Register(rc); - v.Resolve(rc); - } - for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { - kv.Resolve(rc); - } - this.ResolveTriggers(rc); - Body.Resolve(rc); - rc.PopVarContext(); - - // establish a canonical order of the type parameters - this.TypeParameters = Type.SortTypeParams(TypeParameters, new List(Dummies.Select(Item => Item.TypedIdent.Type).ToArray()), null); - - } finally { - rc.TypeBinderState = previousTypeBinderState; - } - } - - public override void ComputeFreeVariables(Set freeVars) { - //Contract.Requires(freeVars != null); - ComputeBinderFreeVariables(TypeParameters, Dummies, Body, Attributes, freeVars); - } - - public static void ComputeBinderFreeVariables(List typeParameters, List dummies, Expr body, QKeyValue attributes, Set freeVars) { - Contract.Requires(dummies != null); - Contract.Requires(body != null); - - foreach (var v in dummies) { - Contract.Assert(v != null); - Contract.Assert(!freeVars[v]); - } - body.ComputeFreeVariables(freeVars); - for (var a = attributes; a != null; a = a.Next) { - foreach (var o in a.Params) { - var e = o as Expr; - if (e != null) { - e.ComputeFreeVariables(freeVars); - } - } - } - foreach (var v in dummies) { - freeVars.AddRange(v.TypedIdent.Type.FreeVariables); - } - freeVars.RemoveRange(dummies); - freeVars.RemoveRange(typeParameters); - } - - protected List GetUnmentionedTypeParameters() { - Contract.Ensures(Contract.Result>() != null); - List/*!*/ dummyParameters = Type.FreeVariablesIn(new List(Dummies.Select(Item => Item.TypedIdent.Type).ToArray())); - Contract.Assert(dummyParameters != null); - List/*!*/ unmentionedParameters = new List(); - foreach (TypeVariable/*!*/ var in TypeParameters) { - Contract.Assert(var != null); - if (!dummyParameters.Contains(var)) - unmentionedParameters.Add(var); - } - return unmentionedParameters; - } - } - - public class QKeyValue : Absy { - public readonly string/*!*/ Key; - private readonly List/*!*/ _params; // each element is either a string or an Expr - - public void AddParam(object p) - { - Contract.Requires(p != null); - this._params.Add(p); - } - - public void AddParams(IEnumerable ps) - { - Contract.Requires(cce.NonNullElements(ps)); - this._params.AddRange(ps); - } - - public void ClearParams() - { - this._params.Clear(); - } - - public IList Params - { - get - { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - Contract.Ensures(Contract.Result>().IsReadOnly); - return this._params.AsReadOnly(); - } - } - - public QKeyValue Next; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Key != null); - Contract.Invariant(cce.NonNullElements(this._params)); - } - - public QKeyValue(IToken tok, string key, IList/*!*/ parameters, QKeyValue next) - : base(tok) { - Contract.Requires(key != null); - Contract.Requires(tok != null); - Contract.Requires(cce.NonNullElements(parameters)); - Key = key; - this._params = new List(parameters); - Next = next; - } - - public void Emit(TokenTextWriter stream) { - Contract.Requires(stream != null); - stream.Write("{:"); - stream.Write(Key); - string sep = " "; - foreach (object p in Params) { - stream.Write(sep); - sep = ", "; - if (p is string) { - stream.Write("\""); - stream.Write((string)p); - stream.Write("\""); - } else { - ((Expr)p).Emit(stream); - } - } - stream.Write("}"); - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - foreach (object p in Params) { - if (p is Expr) { - ((Expr)p).Resolve(rc); - } - } - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - foreach (object p in Params) { - if (p is Expr) { - ((Expr)p).Typecheck(tc); - } - } - } - public void AddLast(QKeyValue other) { - Contract.Requires(other != null); - QKeyValue current = this; - while (current.Next != null) { - current = current.Next; - } - current.Next = other; - } - // Look for {:name string} in list of attributes. - [Pure] - public static string FindStringAttribute(QKeyValue kv, string name) { - Contract.Requires(name != null); - for (; kv != null; kv = kv.Next) { - if (kv.Key == name) { - if (kv.Params.Count == 1 && kv.Params[0] is string) { - return (string)kv.Params[0]; - } - } - } - return null; - } - // Look for {:name expr} in list of attributes. - public static Expr FindExprAttribute(QKeyValue kv, string name) { - Contract.Requires(name != null); - for (; kv != null; kv = kv.Next) { - if (kv.Key == name) { - if (kv.Params.Count == 1 && kv.Params[0] is Expr) { - return (Expr)kv.Params[0]; - } - } - } - return null; - } - // Return 'true' if {:name true} or {:name} is an attribute in 'kv' - public static bool FindBoolAttribute(QKeyValue kv, string name) { - Contract.Requires(name != null); - for (; kv != null; kv = kv.Next) { - if (kv.Key == name) { - return kv.Params.Count == 0 || - (kv.Params.Count == 1 && kv.Params[0] is LiteralExpr && ((LiteralExpr)kv.Params[0]).IsTrue); - } - } - return false; - } - - public static int FindIntAttribute(QKeyValue kv, string name, int defl) { - Contract.Requires(name != null); - Expr e = FindExprAttribute(kv, name); - LiteralExpr l = e as LiteralExpr; - if (l != null && l.isBigNum) - return l.asBigNum.ToIntSafe; - return defl; - } - - public override Absy Clone() { - List newParams = new List(); - foreach (object o in Params) - newParams.Add(o); - return new QKeyValue(tok, Key, newParams, (Next == null) ? null : (QKeyValue)Next.Clone()); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - return visitor.VisitQKeyValue(this); - } - - public override bool Equals(object obj) { - var other = obj as QKeyValue; - if (other == null) { - return false; - } else { - return Key == other.Key && object.Equals(Params, other.Params) && - (Next == null - ? other.Next == null - : object.Equals(Next, other.Next)); - } - } - - public override int GetHashCode() { - throw new NotImplementedException(); - } - } - - public class Trigger : Absy { - public readonly bool Pos; - [Rep] - private List/*!*/ tr; - - public IList/*!*/ Tr - { - get - { - Contract.Ensures(Contract.Result>() != null); - Contract.Ensures(Contract.Result>().Count >= 1); - Contract.Ensures(this.Pos || Contract.Result>().Count == 1); - return this.tr.AsReadOnly(); - } - set - { - Contract.Requires(value != null); - Contract.Requires(value.Count >= 1); - Contract.Requires(this.Pos || value.Count == 1); - this.tr = new List(value); - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this.tr != null); - Contract.Invariant(this.tr.Count >= 1); - Contract.Invariant(Pos || this.tr.Count == 1); - } - - public Trigger Next; - - public Trigger(IToken/*!*/ tok, bool pos, IEnumerable/*!*/ tr, Trigger next = null) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(tr != null); - Contract.Requires(tr.Count() >= 1); - Contract.Requires(pos || tr.Count() == 1); - this.Pos = pos; - this.Tr = new List(tr); - this.Next = next; - } - - public void Emit(TokenTextWriter stream) { - Contract.Requires(stream != null); - stream.SetToken(this); - Contract.Assert(this.Tr.Count >= 1); - string/*!*/ sep = Pos ? "{ " : "{:nopats "; - foreach (Expr/*!*/ e in this.Tr) { - Contract.Assert(e != null); - stream.Write(sep); - sep = ", "; - e.Emit(stream); - } - stream.Write(" }"); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.TriggerMode = true; - foreach (Expr/*!*/ e in this.Tr) { - Contract.Assert(e != null); - e.Resolve(rc); - - // just a variable by itself is not allowed - if (e is IdentifierExpr) { - rc.Error(e, "a matching pattern must be more than just a variable by itself: {0}", e); - } - - // the free-variable check is performed in the surrounding quantifier expression (because that's - // where the bound variables are known) - } - rc.TriggerMode = false; - } - - /// - /// Add to "freeVars" the free variables in the triggering expressions. - /// - public void ComputeFreeVariables(Set /*Variable*/ freeVars) { - Contract.Requires(freeVars != null); - foreach (Expr/*!*/ e in this.Tr) { - Contract.Assert(e != null); - e.ComputeFreeVariables(freeVars); - } - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - foreach (Expr/*!*/ e in this.Tr) { - Contract.Assert(e != null); - e.Typecheck(tc); - } - } - - public void AddLast(Trigger other) { - Trigger current = this; - while (current.Next != null) { - current = current.Next; - } - current.Next = other; - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitTrigger(this); - } - - public override bool Equals(object obj) { - var other = obj as Trigger; - if (other == null) { - return false; - } else { - return this.Tr.SequenceEqual(other.Tr) && - (Next == null ? other.Next == null : object.Equals(Next, other.Next)); - } - } - - public override int GetHashCode() { - throw new NotImplementedException(); - } - } - - public class ForallExpr : QuantifierExpr { - public ForallExpr(IToken/*!*/ tok, List/*!*/ typeParams, - List/*!*/ dummies, QKeyValue kv, Trigger triggers, Expr/*!*/ body, bool immutable=false) - : base(tok, typeParams, dummies, kv, triggers, body, immutable) { - Contract.Requires(tok != null); - Contract.Requires(typeParams != null); - Contract.Requires(dummies != null); - Contract.Requires(body != null); - Contract.Requires(dummies.Count + typeParams.Count > 0); - } - public ForallExpr(IToken tok, List dummies, Trigger triggers, Expr body, bool immutable=false) - : base(tok, new List(), dummies, null, triggers, body, immutable) { - Contract.Requires(body != null); - Contract.Requires(dummies != null); - Contract.Requires(tok != null); - Contract.Requires(dummies.Count > 0); - } - public ForallExpr(IToken tok, List dummies, Expr body, bool immutable=false) - : base(tok, new List(), dummies, null, null, body, immutable) { - Contract.Requires(body != null); - Contract.Requires(dummies != null); - Contract.Requires(tok != null); - Contract.Requires(dummies.Count > 0); - } - public ForallExpr(IToken tok, List typeParams, List dummies, Expr body, bool immutable=false) - : base(tok, typeParams, dummies, null, null, body, immutable) { - Contract.Requires(body != null); - Contract.Requires(dummies != null); - Contract.Requires(typeParams != null); - Contract.Requires(tok != null); - Contract.Requires(dummies.Count + typeParams.Count > 0); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitForallExpr(this); - } - - public override BinderKind Kind { - get { - return BinderKind.Forall; - } - } - } - - public class ExistsExpr : QuantifierExpr { - public ExistsExpr(IToken/*!*/ tok, List/*!*/ typeParams, List/*!*/ dummies, - QKeyValue kv, Trigger triggers, Expr/*!*/ body, bool immutable=false) - : base(tok, typeParams, dummies, kv, triggers, body, immutable) { - Contract.Requires(tok != null); - Contract.Requires(typeParams != null); - Contract.Requires(dummies != null); - Contract.Requires(body != null); - Contract.Requires(dummies.Count + typeParams.Count > 0); - } - public ExistsExpr(IToken tok, List dummies, Trigger triggers, Expr body, bool immutable=false) - : base(tok, new List(), dummies, null, triggers, body, immutable) { - Contract.Requires(body != null); - Contract.Requires(dummies != null); - Contract.Requires(tok != null); - Contract.Requires(dummies.Count > 0); - } - public ExistsExpr(IToken tok, List dummies, Expr body, bool immutable=false) - : base(tok, new List(), dummies, null, null, body, immutable) { - Contract.Requires(body != null); - Contract.Requires(dummies != null); - Contract.Requires(tok != null); - Contract.Requires(dummies.Count > 0); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitExistsExpr(this); - } - - public override BinderKind Kind { - get { - return BinderKind.Exists; - } - } - } - - public abstract class QuantifierExpr : BinderExpr { - public Trigger Triggers; - - static int SkolemIds = -1; - public static int GetNextSkolemId() { - return System.Threading.Interlocked.Increment(ref SkolemIds); - } - - public readonly int SkolemId; - - public QuantifierExpr(IToken/*!*/ tok, List/*!*/ typeParameters, - List/*!*/ dummies, QKeyValue kv, Trigger triggers, Expr/*!*/ body, bool immutable) - : base(tok, typeParameters, dummies, kv, body, immutable) { - Contract.Requires(tok != null); - Contract.Requires(typeParameters != null); - Contract.Requires(dummies != null); - Contract.Requires(body != null); - Contract.Requires(dummies.Count + typeParameters.Count > 0); - - Contract.Assert((this is ForallExpr) || (this is ExistsExpr)); - - Triggers = triggers; - SkolemId = GetNextSkolemId(); - } - - protected override void EmitTriggers(TokenTextWriter stream) { - //Contract.Requires(stream != null); - stream.push(); - for (Trigger tr = this.Triggers; tr != null; tr = tr.Next) { - tr.Emit(stream); - stream.Write(" "); - stream.sep(); - } - stream.pop(); - } - - // if the user says ( forall x :: forall y :: ... ) and specifies *no* triggers, we transform it to - // (forall x, y :: ... ) which may help the prover to pick trigger terms - // - // (Note: there used to be a different criterion here, which allowed merging when triggers were specified, which could cause prover errors due to resulting unbound variables in the triggers) - private void MergeAdjecentQuantifier() { - QuantifierExpr qbody = Body as QuantifierExpr; - if (!(qbody != null && (qbody is ForallExpr) == (this is ForallExpr) && Triggers == null)) { - return; - } - qbody.MergeAdjecentQuantifier(); - if (this.Triggers != null || qbody.Triggers != null) { - return; - } - Body = qbody.Body; - TypeParameters.AddRange(qbody.TypeParameters); - Dummies.AddRange(qbody.Dummies); - Triggers = qbody.Triggers; - if (qbody.Attributes != null) { - if (Attributes == null) { - Attributes = qbody.Attributes; - } else { - QKeyValue p = Attributes; - while (p.Next != null) { - p = p.Next; - } - p.Next = qbody.Attributes; - } - } - } - - #region never triggers - private class NeverTriggerCollector : ReadOnlyVisitor { - QuantifierExpr/*!*/ parent; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(parent != null); - } - - public NeverTriggerCollector(QuantifierExpr p) { - Contract.Requires(p != null); - parent = p; - } - - public override Expr VisitNAryExpr(NAryExpr node) { - //Contract.Requires(node != null); - Contract.Ensures(Contract.Result() != null); - FunctionCall fn = node.Fun as FunctionCall; - if (fn != null && cce.NonNull(fn.Func).NeverTrigger) { - parent.Triggers = new Trigger(fn.Func.tok, false, new List { node} , parent.Triggers); - } - return base.VisitNAryExpr(node); - } - public override QuantifierExpr VisitQuantifierExpr(QuantifierExpr node) { - // don't go into quantifier expression or its triggers, since the terms in there may have more bound variables - // (note, with only the VisitBinderExpr override below, we'd still be visiting triggers, which we don't want to do) - return node; - } - public override BinderExpr VisitBinderExpr(BinderExpr node) { - // don't go into binder expression, since the terms in there may have more bound variables - return node; - } - } - - private bool neverTriggerApplied; - private void ApplyNeverTriggers() { - if (neverTriggerApplied) { - return; - } - neverTriggerApplied = true; - - for (Trigger t = Triggers; t != null; t = t.Next) { - if (t.Pos) { - return; - } - } - - NeverTriggerCollector visitor = new NeverTriggerCollector(this); - visitor.VisitExpr(Body); - } - #endregion - - protected override void ResolveTriggers(ResolutionContext rc) { - //Contract.Requires(rc != null); - for (Trigger tr = this.Triggers; tr != null; tr = tr.Next) { - int prevErrorCount = rc.ErrorCount; - tr.Resolve(rc); - if (prevErrorCount == rc.ErrorCount) { - // for positive triggers, make sure all bound variables are mentioned - if (tr.Pos) { - Set /*Variable*/ freeVars = new Set /*Variable*/ (); - tr.ComputeFreeVariables(freeVars); - foreach (Variable/*!*/ v in Dummies) { - Contract.Assert(v != null); - if (!freeVars[v]) { - rc.Error(tr, "trigger must mention all quantified variables, but does not mention: {0}", v); - } - } - } - } - } - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - int oldErrorCount = rc.ErrorCount; - - this.MergeAdjecentQuantifier(); - - base.Resolve(rc); - - if (oldErrorCount == rc.ErrorCount) { - this.ApplyNeverTriggers(); - } - } - - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { - kv.Typecheck(tc); - } - for (Trigger tr = this.Triggers; tr != null; tr = tr.Next) { - tr.Typecheck(tc); - } - Body.Typecheck(tc); - Contract.Assert(Body.Type != null); // follows from postcondition of Expr.Typecheck - if (!Body.Type.Unify(Type.Bool)) { - tc.Error(this, "quantifier body must be of type bool"); - } - this.Type = Type.Bool; - - // Check that type parameters occur in the types of the - // dummies, or otherwise in the triggers. This can only be - // done after typechecking - List/*!*/ unmentionedParameters = GetUnmentionedTypeParameters(); - Contract.Assert(unmentionedParameters != null); - - if (unmentionedParameters.Count > 0) { - // all the type parameters that do not occur in dummy types - // have to occur in triggers - - for (Trigger tr = this.Triggers; tr != null; tr = tr.Next) { - // for positive triggers, make sure all bound variables are mentioned - if (tr.Pos) { - Set /*Variable*/ freeVars = new Set /*Variable*/ (); - tr.ComputeFreeVariables(freeVars); - foreach (TypeVariable/*!*/ v in unmentionedParameters) { - Contract.Assert(v != null); - if (!freeVars[v]) - tc.Error(tr, - "trigger does not mention {0}, which does not occur in variables types either", - v); - } - } - } - } - } - public override Type/*!*/ ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - return Type.Bool; - } - } - - public override bool Equals(object obj) { - var other = obj as QuantifierExpr; - if (other == null) { - return false; - } else { - return this.BinderEquals(obj) && - (!CompareAttributesAndTriggers || object.Equals(Triggers, other.Triggers)); - } - } - } - - - public class LambdaExpr : BinderExpr { - public LambdaExpr(IToken/*!*/ tok, List/*!*/ typeParameters, - List/*!*/ dummies, QKeyValue kv, Expr/*!*/ body, bool immutable=false) - : base(tok, typeParameters, dummies, kv, body, immutable) { - Contract.Requires(tok != null); - Contract.Requires(typeParameters != null); - Contract.Requires(dummies != null); - Contract.Requires(body != null); - Contract.Requires(dummies.Count + typeParameters.Count > 0); - } - - public override BinderKind Kind { - get { - return BinderKind.Lambda; - } - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - base.Resolve(rc); - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { - kv.Typecheck(tc); - } - Body.Typecheck(tc); - Contract.Assert(Body.Type != null); // follows from postcondition of Expr.Typecheck - - List/*!*/ argTypes = new List(); - foreach (Variable/*!*/ v in Dummies) { - Contract.Assert(v != null); - argTypes.Add(v.TypedIdent.Type); - } - this.Type = new MapType(this.tok, this.TypeParameters, argTypes, Body.Type); - - // Check that type parameters occur in the types of the - // dummies, or otherwise in the triggers. This can only be - // done after typechecking - List/*!*/ unmentionedParameters = GetUnmentionedTypeParameters(); - Contract.Assert(unmentionedParameters != null); - - if (unmentionedParameters.Count > 0) { - tc.Error(this, "the type variable {0} does not occur in types of the lambda parameters", unmentionedParameters[0]); - } - } - - private Type mapType; - public override Type/*!*/ ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - if (mapType == null) { - List/*!*/ argTypes = new List(); - foreach (Variable/*!*/ v in Dummies) { - Contract.Assert(v != null); - argTypes.Add(v.TypedIdent.Type); - } - mapType = new MapType(this.tok, this.TypeParameters, argTypes, Body.ShallowType); - } - - return mapType; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitLambdaExpr(this); - } - - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- +// BoogiePL - AbsyQuant.cs +//--------------------------------------------------------------------------------------------- + +namespace Microsoft.Boogie { + using System; + using System.Collections; + using System.Diagnostics; + using System.Collections.Generic; + using System.Linq; + using Microsoft.Boogie.AbstractInterpretation; + using System.Diagnostics.Contracts; + using Microsoft.Basetypes; + + using Set = GSet; + + //--------------------------------------------------------------------- + // Quantifiers and general binders + //--------------------------------------------------------------------- + + public enum BinderKind { + Forall, + Exists, + Lambda + } + [ContractClassFor(typeof(BinderExpr))] + abstract class BinderExprContracts : BinderExpr { + public override BinderKind Kind { + get { + throw new NotImplementedException(); + } + } + public BinderExprContracts():base(null,null,null,null,null,false){ + } + + public override Type ShallowType { + get { + throw new NotImplementedException(); + } + } + } + [ContractClass(typeof(BinderExprContracts))] + public abstract class BinderExpr : Expr { + public List/*!*/ TypeParameters; + public List/*!*/ Dummies; + public QKeyValue Attributes; + // FIXME: Protect the above Fields + public Expr _Body; + public Expr/*!*/ Body { + get { + return _Body; + } + set { + if (Immutable) + throw new InvalidOperationException ("Cannot change the Body of an immutable BinderExpr"); + + _Body = value; + } + } + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(TypeParameters != null); + Contract.Invariant(Dummies != null); + Contract.Invariant(Body != null); + } + + public BinderExpr(IToken/*!*/ tok, List/*!*/ typeParameters, + List/*!*/ dummies, QKeyValue kv, Expr/*!*/ body, bool immutable) + : base(tok, immutable) { + Contract.Requires(tok != null); + Contract.Requires(typeParameters != null); + Contract.Requires(dummies != null); + Contract.Requires(body != null); + Contract.Requires(dummies.Count + typeParameters.Count > 0); + TypeParameters = typeParameters; + Dummies = dummies; + Attributes = kv; + _Body = body; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + + abstract public BinderKind Kind { + get; + } + + protected static bool CompareAttributesAndTriggers = false; + + public static bool EqualWithAttributesAndTriggers(object a, object b) { + CompareAttributesAndTriggers = true; + var res = object.Equals(a, b); + Contract.Assert(CompareAttributesAndTriggers); + CompareAttributesAndTriggers = false; + return res; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + return BinderEquals(obj); + } + + public bool BinderEquals(object obj) { + if (obj == null) { + return false; + } + if (!(obj is BinderExpr) || + this.Kind != ((BinderExpr) obj).Kind) { + return false; + } + + var other = (BinderExpr) obj; + + return this.TypeParameters.SequenceEqual(other.TypeParameters) + && this.Dummies.SequenceEqual(other.Dummies) + && (!CompareAttributesAndTriggers || object.Equals(this.Attributes, other.Attributes)) + && object.Equals(this.Body, other.Body); + } + + [Pure] + public override int GetHashCode() + { + if (Immutable) + return CachedHashCode; + else + return ComputeHashCode(); + } + + [Pure] + public override int ComputeHashCode() { + // Note, we don't hash triggers and attributes + + // DO NOT USE Dummies.GetHashCode() because we want structurally + // identical Expr to have the same hash code **not** identical references + // to have the same hash code. + int h = 0; + foreach (var dummyVar in this.Dummies) { + h = ( 53 * h ) + dummyVar.GetHashCode(); + } + + h ^= this.Body.GetHashCode(); + + // DO NOT USE TypeParameters.GetHashCode() because we want structural + // identical Expr to have the same hash code **not** identical references + // to have the same hash code. + int h2 = 0; + foreach (var typeParam in this.TypeParameters) { + h2 = ( 97 * h2 ) + typeParam.GetHashCode(); + } + + h = h * 5 + h2; + h *= ((int)Kind + 1); + return h; + } + + protected virtual void EmitTypeHint(TokenTextWriter stream) { + Contract.Requires(stream != null); + } + + protected virtual void EmitTriggers(TokenTextWriter stream) { + Contract.Requires(stream != null); + } + + public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + stream.push(); + stream.Write(this, "({0}", Kind.ToString().ToLower()); + this.EmitTypeHint(stream); + Type.EmitOptionalTypeParams(stream, TypeParameters); + stream.Write(this, " "); + this.Dummies.Emit(stream, true); + stream.Write(" :: "); + stream.sep(); + for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { + kv.Emit(stream); + stream.Write(" "); + } + this.EmitTriggers(stream); + stream.sep(); + + this.Body.Emit(stream); + stream.Write(")"); + stream.pop(); + } + + protected virtual void ResolveTriggers(ResolutionContext rc) { + Contract.Requires(rc != null); + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + if (rc.TriggerMode) { + rc.Error(this, "quantifiers are not allowed in triggers"); + } + + int previousTypeBinderState = rc.TypeBinderState; + try { + foreach (TypeVariable/*!*/ v in TypeParameters) { + Contract.Assert(v != null); + rc.AddTypeBinder(v); + } + + rc.PushVarContext(); + foreach (Variable/*!*/ v in Dummies) { + Contract.Assert(v != null); + v.Register(rc); + v.Resolve(rc); + } + for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { + kv.Resolve(rc); + } + this.ResolveTriggers(rc); + Body.Resolve(rc); + rc.PopVarContext(); + + // establish a canonical order of the type parameters + this.TypeParameters = Type.SortTypeParams(TypeParameters, new List(Dummies.Select(Item => Item.TypedIdent.Type).ToArray()), null); + + } finally { + rc.TypeBinderState = previousTypeBinderState; + } + } + + public override void ComputeFreeVariables(Set freeVars) { + //Contract.Requires(freeVars != null); + ComputeBinderFreeVariables(TypeParameters, Dummies, Body, Attributes, freeVars); + } + + public static void ComputeBinderFreeVariables(List typeParameters, List dummies, Expr body, QKeyValue attributes, Set freeVars) { + Contract.Requires(dummies != null); + Contract.Requires(body != null); + + foreach (var v in dummies) { + Contract.Assert(v != null); + Contract.Assert(!freeVars[v]); + } + body.ComputeFreeVariables(freeVars); + for (var a = attributes; a != null; a = a.Next) { + foreach (var o in a.Params) { + var e = o as Expr; + if (e != null) { + e.ComputeFreeVariables(freeVars); + } + } + } + foreach (var v in dummies) { + freeVars.AddRange(v.TypedIdent.Type.FreeVariables); + } + freeVars.RemoveRange(dummies); + freeVars.RemoveRange(typeParameters); + } + + protected List GetUnmentionedTypeParameters() { + Contract.Ensures(Contract.Result>() != null); + List/*!*/ dummyParameters = Type.FreeVariablesIn(new List(Dummies.Select(Item => Item.TypedIdent.Type).ToArray())); + Contract.Assert(dummyParameters != null); + List/*!*/ unmentionedParameters = new List(); + foreach (TypeVariable/*!*/ var in TypeParameters) { + Contract.Assert(var != null); + if (!dummyParameters.Contains(var)) + unmentionedParameters.Add(var); + } + return unmentionedParameters; + } + } + + public class QKeyValue : Absy { + public readonly string/*!*/ Key; + private readonly List/*!*/ _params; // each element is either a string or an Expr + + public void AddParam(object p) + { + Contract.Requires(p != null); + this._params.Add(p); + } + + public void AddParams(IEnumerable ps) + { + Contract.Requires(cce.NonNullElements(ps)); + this._params.AddRange(ps); + } + + public void ClearParams() + { + this._params.Clear(); + } + + public IList Params + { + get + { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + Contract.Ensures(Contract.Result>().IsReadOnly); + return this._params.AsReadOnly(); + } + } + + public QKeyValue Next; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Key != null); + Contract.Invariant(cce.NonNullElements(this._params)); + } + + public QKeyValue(IToken tok, string key, IList/*!*/ parameters, QKeyValue next) + : base(tok) { + Contract.Requires(key != null); + Contract.Requires(tok != null); + Contract.Requires(cce.NonNullElements(parameters)); + Key = key; + this._params = new List(parameters); + Next = next; + } + + public void Emit(TokenTextWriter stream) { + Contract.Requires(stream != null); + stream.Write("{:"); + stream.Write(Key); + string sep = " "; + foreach (object p in Params) { + stream.Write(sep); + sep = ", "; + if (p is string) { + stream.Write("\""); + stream.Write((string)p); + stream.Write("\""); + } else { + ((Expr)p).Emit(stream); + } + } + stream.Write("}"); + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + + if ((Key == "minimize" || Key == "maximize") && Params.Count != 1) + { + rc.Error(this, "attributes :minimize and :maximize accept only one argument"); + } + + if (Key == "verified_under" && Params.Count != 1) + { + rc.Error(this, "attribute :verified_under accepts only one argument"); + } + + foreach (object p in Params) { + if (p is Expr) { + ((Expr)p).Resolve(rc); + } + } + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + foreach (object p in Params) { + var expr = p as Expr; + if (expr != null) { + expr.Typecheck(tc); + } + if ((Key == "minimize" || Key == "maximize") + && (expr == null || !(expr.Type.IsInt || expr.Type.IsReal || expr.Type.IsBv))) + { + tc.Error(this, "attributes :minimize and :maximize accept only one argument of type int, real or bv"); + break; + } + if (Key == "verified_under" && (expr == null || !expr.Type.IsBool)) + { + tc.Error(this, "attribute :verified_under accepts only one argument of type bool"); + break; + } + } + } + public void AddLast(QKeyValue other) { + Contract.Requires(other != null); + QKeyValue current = this; + while (current.Next != null) { + current = current.Next; + } + current.Next = other; + } + // Look for {:name string} in list of attributes. + [Pure] + public static string FindStringAttribute(QKeyValue kv, string name) { + Contract.Requires(name != null); + for (; kv != null; kv = kv.Next) { + if (kv.Key == name) { + if (kv.Params.Count == 1 && kv.Params[0] is string) { + return (string)kv.Params[0]; + } + } + } + return null; + } + // Look for {:name expr} in list of attributes. + public static Expr FindExprAttribute(QKeyValue kv, string name) { + Contract.Requires(name != null); + for (; kv != null; kv = kv.Next) { + if (kv.Key == name) { + if (kv.Params.Count == 1 && kv.Params[0] is Expr) { + return (Expr)kv.Params[0]; + } + } + } + return null; + } + // Return 'true' if {:name true} or {:name} is an attribute in 'kv' + public static bool FindBoolAttribute(QKeyValue kv, string name) { + Contract.Requires(name != null); + for (; kv != null; kv = kv.Next) { + if (kv.Key == name) { + return kv.Params.Count == 0 || + (kv.Params.Count == 1 && kv.Params[0] is LiteralExpr && ((LiteralExpr)kv.Params[0]).IsTrue); + } + } + return false; + } + + public static int FindIntAttribute(QKeyValue kv, string name, int defl) { + Contract.Requires(name != null); + Expr e = FindExprAttribute(kv, name); + LiteralExpr l = e as LiteralExpr; + if (l != null && l.isBigNum) + return l.asBigNum.ToIntSafe; + return defl; + } + + public override Absy Clone() { + List newParams = new List(); + foreach (object o in Params) + newParams.Add(o); + return new QKeyValue(tok, Key, newParams, (Next == null) ? null : (QKeyValue)Next.Clone()); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + return visitor.VisitQKeyValue(this); + } + + public override bool Equals(object obj) { + var other = obj as QKeyValue; + if (other == null) { + return false; + } else { + return Key == other.Key && object.Equals(Params, other.Params) && + (Next == null + ? other.Next == null + : object.Equals(Next, other.Next)); + } + } + + public override int GetHashCode() { + throw new NotImplementedException(); + } + } + + public class Trigger : Absy { + public readonly bool Pos; + [Rep] + private List/*!*/ tr; + + public IList/*!*/ Tr + { + get + { + Contract.Ensures(Contract.Result>() != null); + Contract.Ensures(Contract.Result>().Count >= 1); + Contract.Ensures(this.Pos || Contract.Result>().Count == 1); + return this.tr.AsReadOnly(); + } + set + { + Contract.Requires(value != null); + Contract.Requires(value.Count >= 1); + Contract.Requires(this.Pos || value.Count == 1); + this.tr = new List(value); + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this.tr != null); + Contract.Invariant(this.tr.Count >= 1); + Contract.Invariant(Pos || this.tr.Count == 1); + } + + public Trigger Next; + + public Trigger(IToken/*!*/ tok, bool pos, IEnumerable/*!*/ tr, Trigger next = null) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(tr != null); + Contract.Requires(tr.Count() >= 1); + Contract.Requires(pos || tr.Count() == 1); + this.Pos = pos; + this.Tr = new List(tr); + this.Next = next; + } + + public void Emit(TokenTextWriter stream) { + Contract.Requires(stream != null); + stream.SetToken(this); + Contract.Assert(this.Tr.Count >= 1); + string/*!*/ sep = Pos ? "{ " : "{:nopats "; + foreach (Expr/*!*/ e in this.Tr) { + Contract.Assert(e != null); + stream.Write(sep); + sep = ", "; + e.Emit(stream); + } + stream.Write(" }"); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.TriggerMode = true; + foreach (Expr/*!*/ e in this.Tr) { + Contract.Assert(e != null); + e.Resolve(rc); + + // just a variable by itself is not allowed + if (e is IdentifierExpr) { + rc.Error(e, "a matching pattern must be more than just a variable by itself: {0}", e); + } + + // the free-variable check is performed in the surrounding quantifier expression (because that's + // where the bound variables are known) + } + rc.TriggerMode = false; + } + + /// + /// Add to "freeVars" the free variables in the triggering expressions. + /// + public void ComputeFreeVariables(Set /*Variable*/ freeVars) { + Contract.Requires(freeVars != null); + foreach (Expr/*!*/ e in this.Tr) { + Contract.Assert(e != null); + e.ComputeFreeVariables(freeVars); + } + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + foreach (Expr/*!*/ e in this.Tr) { + Contract.Assert(e != null); + e.Typecheck(tc); + } + } + + public void AddLast(Trigger other) { + Trigger current = this; + while (current.Next != null) { + current = current.Next; + } + current.Next = other; + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitTrigger(this); + } + + public override bool Equals(object obj) { + var other = obj as Trigger; + if (other == null) { + return false; + } else { + return this.Tr.SequenceEqual(other.Tr) && + (Next == null ? other.Next == null : object.Equals(Next, other.Next)); + } + } + + public override int GetHashCode() { + throw new NotImplementedException(); + } + } + + public class ForallExpr : QuantifierExpr { + public ForallExpr(IToken/*!*/ tok, List/*!*/ typeParams, + List/*!*/ dummies, QKeyValue kv, Trigger triggers, Expr/*!*/ body, bool immutable=false) + : base(tok, typeParams, dummies, kv, triggers, body, immutable) { + Contract.Requires(tok != null); + Contract.Requires(typeParams != null); + Contract.Requires(dummies != null); + Contract.Requires(body != null); + Contract.Requires(dummies.Count + typeParams.Count > 0); + } + public ForallExpr(IToken tok, List dummies, Trigger triggers, Expr body, bool immutable=false) + : base(tok, new List(), dummies, null, triggers, body, immutable) { + Contract.Requires(body != null); + Contract.Requires(dummies != null); + Contract.Requires(tok != null); + Contract.Requires(dummies.Count > 0); + } + public ForallExpr(IToken tok, List dummies, Expr body, bool immutable=false) + : base(tok, new List(), dummies, null, null, body, immutable) { + Contract.Requires(body != null); + Contract.Requires(dummies != null); + Contract.Requires(tok != null); + Contract.Requires(dummies.Count > 0); + } + public ForallExpr(IToken tok, List typeParams, List dummies, Expr body, bool immutable=false) + : base(tok, typeParams, dummies, null, null, body, immutable) { + Contract.Requires(body != null); + Contract.Requires(dummies != null); + Contract.Requires(typeParams != null); + Contract.Requires(tok != null); + Contract.Requires(dummies.Count + typeParams.Count > 0); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitForallExpr(this); + } + + public override BinderKind Kind { + get { + return BinderKind.Forall; + } + } + } + + public class ExistsExpr : QuantifierExpr { + public ExistsExpr(IToken/*!*/ tok, List/*!*/ typeParams, List/*!*/ dummies, + QKeyValue kv, Trigger triggers, Expr/*!*/ body, bool immutable=false) + : base(tok, typeParams, dummies, kv, triggers, body, immutable) { + Contract.Requires(tok != null); + Contract.Requires(typeParams != null); + Contract.Requires(dummies != null); + Contract.Requires(body != null); + Contract.Requires(dummies.Count + typeParams.Count > 0); + } + public ExistsExpr(IToken tok, List dummies, Trigger triggers, Expr body, bool immutable=false) + : base(tok, new List(), dummies, null, triggers, body, immutable) { + Contract.Requires(body != null); + Contract.Requires(dummies != null); + Contract.Requires(tok != null); + Contract.Requires(dummies.Count > 0); + } + public ExistsExpr(IToken tok, List dummies, Expr body, bool immutable=false) + : base(tok, new List(), dummies, null, null, body, immutable) { + Contract.Requires(body != null); + Contract.Requires(dummies != null); + Contract.Requires(tok != null); + Contract.Requires(dummies.Count > 0); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitExistsExpr(this); + } + + public override BinderKind Kind { + get { + return BinderKind.Exists; + } + } + } + + public abstract class QuantifierExpr : BinderExpr { + public Trigger Triggers; + + static int SkolemIds = -1; + public static int GetNextSkolemId() { + return System.Threading.Interlocked.Increment(ref SkolemIds); + } + + public readonly int SkolemId; + + public QuantifierExpr(IToken/*!*/ tok, List/*!*/ typeParameters, + List/*!*/ dummies, QKeyValue kv, Trigger triggers, Expr/*!*/ body, bool immutable) + : base(tok, typeParameters, dummies, kv, body, immutable) { + Contract.Requires(tok != null); + Contract.Requires(typeParameters != null); + Contract.Requires(dummies != null); + Contract.Requires(body != null); + Contract.Requires(dummies.Count + typeParameters.Count > 0); + + Contract.Assert((this is ForallExpr) || (this is ExistsExpr)); + + Triggers = triggers; + SkolemId = GetNextSkolemId(); + } + + protected override void EmitTriggers(TokenTextWriter stream) { + //Contract.Requires(stream != null); + stream.push(); + for (Trigger tr = this.Triggers; tr != null; tr = tr.Next) { + tr.Emit(stream); + stream.Write(" "); + stream.sep(); + } + stream.pop(); + } + + // if the user says ( forall x :: forall y :: ... ) and specifies *no* triggers, we transform it to + // (forall x, y :: ... ) which may help the prover to pick trigger terms + // + // (Note: there used to be a different criterion here, which allowed merging when triggers were specified, which could cause prover errors due to resulting unbound variables in the triggers) + private void MergeAdjecentQuantifier() { + QuantifierExpr qbody = Body as QuantifierExpr; + if (!(qbody != null && (qbody is ForallExpr) == (this is ForallExpr) && Triggers == null)) { + return; + } + qbody.MergeAdjecentQuantifier(); + if (this.Triggers != null || qbody.Triggers != null) { + return; + } + Body = qbody.Body; + TypeParameters.AddRange(qbody.TypeParameters); + Dummies.AddRange(qbody.Dummies); + Triggers = qbody.Triggers; + if (qbody.Attributes != null) { + if (Attributes == null) { + Attributes = qbody.Attributes; + } else { + QKeyValue p = Attributes; + while (p.Next != null) { + p = p.Next; + } + p.Next = qbody.Attributes; + } + } + } + + #region never triggers + private class NeverTriggerCollector : ReadOnlyVisitor { + QuantifierExpr/*!*/ parent; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(parent != null); + } + + public NeverTriggerCollector(QuantifierExpr p) { + Contract.Requires(p != null); + parent = p; + } + + public override Expr VisitNAryExpr(NAryExpr node) { + //Contract.Requires(node != null); + Contract.Ensures(Contract.Result() != null); + FunctionCall fn = node.Fun as FunctionCall; + if (fn != null && cce.NonNull(fn.Func).NeverTrigger) { + parent.Triggers = new Trigger(fn.Func.tok, false, new List { node} , parent.Triggers); + } + return base.VisitNAryExpr(node); + } + public override QuantifierExpr VisitQuantifierExpr(QuantifierExpr node) { + // don't go into quantifier expression or its triggers, since the terms in there may have more bound variables + // (note, with only the VisitBinderExpr override below, we'd still be visiting triggers, which we don't want to do) + return node; + } + public override BinderExpr VisitBinderExpr(BinderExpr node) { + // don't go into binder expression, since the terms in there may have more bound variables + return node; + } + } + + private bool neverTriggerApplied; + private void ApplyNeverTriggers() { + if (neverTriggerApplied) { + return; + } + neverTriggerApplied = true; + + for (Trigger t = Triggers; t != null; t = t.Next) { + if (t.Pos) { + return; + } + } + + NeverTriggerCollector visitor = new NeverTriggerCollector(this); + visitor.VisitExpr(Body); + } + #endregion + + protected override void ResolveTriggers(ResolutionContext rc) { + //Contract.Requires(rc != null); + for (Trigger tr = this.Triggers; tr != null; tr = tr.Next) { + int prevErrorCount = rc.ErrorCount; + tr.Resolve(rc); + if (prevErrorCount == rc.ErrorCount) { + // for positive triggers, make sure all bound variables are mentioned + if (tr.Pos) { + Set /*Variable*/ freeVars = new Set /*Variable*/ (); + tr.ComputeFreeVariables(freeVars); + foreach (Variable/*!*/ v in Dummies) { + Contract.Assert(v != null); + if (!freeVars[v]) { + rc.Error(tr, "trigger must mention all quantified variables, but does not mention: {0}", v); + } + } + } + } + } + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + int oldErrorCount = rc.ErrorCount; + + this.MergeAdjecentQuantifier(); + + base.Resolve(rc); + + if (oldErrorCount == rc.ErrorCount) { + this.ApplyNeverTriggers(); + } + } + + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { + kv.Typecheck(tc); + } + for (Trigger tr = this.Triggers; tr != null; tr = tr.Next) { + tr.Typecheck(tc); + } + Body.Typecheck(tc); + Contract.Assert(Body.Type != null); // follows from postcondition of Expr.Typecheck + if (!Body.Type.Unify(Type.Bool)) { + tc.Error(this, "quantifier body must be of type bool"); + } + this.Type = Type.Bool; + + // Check that type parameters occur in the types of the + // dummies, or otherwise in the triggers. This can only be + // done after typechecking + List/*!*/ unmentionedParameters = GetUnmentionedTypeParameters(); + Contract.Assert(unmentionedParameters != null); + + if (unmentionedParameters.Count > 0) { + // all the type parameters that do not occur in dummy types + // have to occur in triggers + + for (Trigger tr = this.Triggers; tr != null; tr = tr.Next) { + // for positive triggers, make sure all bound variables are mentioned + if (tr.Pos) { + Set /*Variable*/ freeVars = new Set /*Variable*/ (); + tr.ComputeFreeVariables(freeVars); + foreach (TypeVariable/*!*/ v in unmentionedParameters) { + Contract.Assert(v != null); + if (!freeVars[v]) + tc.Error(tr, + "trigger does not mention {0}, which does not occur in variables types either", + v); + } + } + } + } + } + public override Type/*!*/ ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + return Type.Bool; + } + } + + public override bool Equals(object obj) { + var other = obj as QuantifierExpr; + if (other == null) { + return false; + } else { + return this.BinderEquals(obj) && + (!CompareAttributesAndTriggers || object.Equals(Triggers, other.Triggers)); + } + } + } + + + public class LambdaExpr : BinderExpr { + public LambdaExpr(IToken/*!*/ tok, List/*!*/ typeParameters, + List/*!*/ dummies, QKeyValue kv, Expr/*!*/ body, bool immutable=false) + : base(tok, typeParameters, dummies, kv, body, immutable) { + Contract.Requires(tok != null); + Contract.Requires(typeParameters != null); + Contract.Requires(dummies != null); + Contract.Requires(body != null); + Contract.Requires(dummies.Count + typeParameters.Count > 0); + } + + public override BinderKind Kind { + get { + return BinderKind.Lambda; + } + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + base.Resolve(rc); + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { + kv.Typecheck(tc); + } + Body.Typecheck(tc); + Contract.Assert(Body.Type != null); // follows from postcondition of Expr.Typecheck + + List/*!*/ argTypes = new List(); + foreach (Variable/*!*/ v in Dummies) { + Contract.Assert(v != null); + argTypes.Add(v.TypedIdent.Type); + } + this.Type = new MapType(this.tok, this.TypeParameters, argTypes, Body.Type); + + // Check that type parameters occur in the types of the + // dummies, or otherwise in the triggers. This can only be + // done after typechecking + List/*!*/ unmentionedParameters = GetUnmentionedTypeParameters(); + Contract.Assert(unmentionedParameters != null); + + if (unmentionedParameters.Count > 0) { + tc.Error(this, "the type variable {0} does not occur in types of the lambda parameters", unmentionedParameters[0]); + } + } + + private Type mapType; + public override Type/*!*/ ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + if (mapType == null) { + List/*!*/ argTypes = new List(); + foreach (Variable/*!*/ v in Dummies) { + Contract.Assert(v != null); + argTypes.Add(v.TypedIdent.Type); + } + mapType = new MapType(this.tok, this.TypeParameters, argTypes, Body.ShallowType); + } + + return mapType; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitLambdaExpr(this); + } + + } +} diff --git a/Source/Core/AbsyType.cs b/Source/Core/AbsyType.cs index 5d41a8dd..96de5c0b 100644 --- a/Source/Core/AbsyType.cs +++ b/Source/Core/AbsyType.cs @@ -1,3907 +1,3907 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -//--------------------------------------------------------------------------------------------- -// BoogiePL - Absy.cs -//--------------------------------------------------------------------------------------------- - -namespace Microsoft.Boogie { - using System; - using System.Collections; - using System.Diagnostics; - using System.Linq; - using System.Collections.Generic; - using Microsoft.Boogie.AbstractInterpretation; - using System.Diagnostics.Contracts; - - //===================================================================== - //--------------------------------------------------------------------- - // Types - [ContractClass(typeof(TypeContracts))] - public abstract class Type : Absy { - public Type(IToken/*!*/ token) - : base(token) { - Contract.Requires(token != null); - } - - //----------- Cloning ---------------------------------- - // We implement our own clone-method, because bound type variables - // have to be created in the right way. It is /not/ ok to just clone - // everything recursively. Applying Clone to a type will return - // a type in which all bound variables have been replaced with new - // variables, whereas free variables have not changed - - public override Absy Clone() { - Contract.Ensures(Contract.Result() != null); - return this.Clone(new Dictionary()); - } - - public abstract Type/*!*/ Clone(IDictionary/*!*/ varMap); - - /// - /// Clones the type, but only syntactically. Anything resolved in the source - /// type is left unresolved (that is, with just the name) in the destination type. - /// - public abstract Type/*!*/ CloneUnresolved(); - - //----------- Linearisation ---------------------------------- - - public void Emit(TokenTextWriter stream) { - Contract.Requires(stream != null); - this.Emit(stream, 0); - } - - public abstract void Emit(TokenTextWriter/*!*/ stream, int contextBindingStrength); - - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - System.IO.StringWriter buffer = new System.IO.StringWriter(); - using (TokenTextWriter stream = new TokenTextWriter("", buffer, /*setTokens=*/false, /*pretty=*/ false)) { - this.Emit(stream); - } - return buffer.ToString(); - } - - //----------- Equality ---------------------------------- - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (ReferenceEquals(this, that)) - return true; - Type thatType = that as Type; - return thatType != null && this.Equals(thatType, - new List(), - new List()); - } - - [Pure] - public abstract bool Equals(Type/*!*/ that, - List/*!*/ thisBoundVariables, - List/*!*/ thatBoundVariables); - - // used to skip leading type annotations (subexpressions of the - // resulting type might still contain annotations) - internal virtual Type/*!*/ Expanded { - get { - Contract.Ensures(Contract.Result() != null); - - return this; - } - } - - //----------- Unification of types ----------- - - /// - /// Add a constraint that this==that, if possible, and return true. - /// If not possible, return false (which may have added some partial constraints). - /// No error is printed. - /// - public bool Unify(Type that) { - Contract.Requires(that != null); - return Unify(that, new List(), new Dictionary()); - } - - public abstract bool Unify(Type/*!*/ that, - List/*!*/ unifiableVariables, - // an idempotent substitution that describes the - // unification result up to a certain point - IDictionary/*!*/ unifier); - - - [Pure] - public static bool IsIdempotent(IDictionary/*!*/ unifier) { - Contract.Requires(cce.NonNullDictionaryAndValues(unifier)); - return unifier.Values.All(val => val.FreeVariables.All(var => !unifier.ContainsKey(var))); - } - - -#if OLD_UNIFICATION - // Compute a most general unification of two types. null is returned if - // no such unifier exists. The unifier is not allowed to subtitute any - // type variables other than the ones in "unifiableVariables" - public IDictionary Unify(Type! that, - List! unifiableVariables) { - Dictionary! result = new Dictionary (); - try { - this.Unify(that, unifiableVariables, - new List (), new List (), result); - } catch (UnificationFailedException) { - return null; - } - return result; - } - - // Compute an idempotent most general unifier and add the result to the argument - // unifier. The result is true iff the unification succeeded - public bool Unify(Type! that, - List! unifiableVariables, - // given mappings that need to be taken into account - // the old unifier has to be idempotent as well - IDictionary! unifier) - { - Contract.Requires(Contract.ForAll(unifier.Keys , key=> unifiableVariables.Has(key))); - Contract.Requires(IsIdempotent(unifier)); - try { - this.Unify(that, unifiableVariables, - new List (), new List (), unifier); - } catch (UnificationFailedException) { - return false; - } - return true; - } - - public abstract void Unify(Type! that, - List! unifiableVariables, - List! thisBoundVariables, - List! thatBoundVariables, - // an idempotent substitution that describes the - // unification result up to a certain point - IDictionary! result); -#endif - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public abstract Type/*!*/ Substitute(IDictionary/*!*/ subst); - - //----------- Hashcodes ---------------------------------- - - // Hack to be able to access the hashcode of superclasses further up - // (from the subclasses of this class) - [Pure] - protected int GetBaseHashCode() { - return base.GetHashCode(); - } - - [Pure] - public override int GetHashCode() { - return this.GetHashCode(new List()); - } - - [Pure] - public abstract int GetHashCode(List/*!*/ boundVariables); - - //----------- Resolution ---------------------------------- - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - System.Diagnostics.Debug.Fail("Type.Resolve should never be called." + - " Use Type.ResolveType instead"); - } - - public abstract Type/*!*/ ResolveType(ResolutionContext/*!*/ rc); - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - System.Diagnostics.Debug.Fail("Type.Typecheck should never be called"); - } - - // determine the free variables in a type, in the order in which the variables occur - public abstract List/*!*/ FreeVariables { - get; - } - - // determine the free type proxies in a type, in the order in which they occur - public abstract List/*!*/ FreeProxies { - get; - } - - protected static void AppendWithoutDups(List a, List b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - foreach (A x in b) - if (!a.Contains(x)) - a.Add(x); - } - - public bool IsClosed { - get { - return FreeVariables.Count == 0; - } - } - - //----------- Getters/Issers ---------------------------------- - - // the following methods should be used instead of simple casts or the - // C# "is" operator, because they handle type synonym annotations and - // type proxies correctly - - public virtual bool IsBasic { - get { - return false; - } - } - public virtual bool IsInt { - get { - return false; - } - } - public virtual bool IsReal { - get { - return false; - } - } - public virtual bool IsFloat { - get { - return false; - } - } - public virtual bool IsBool { - get { - return false; - } - } - - public virtual bool IsVariable { - get { - return false; - } - } - public virtual TypeVariable/*!*/ AsVariable { - get { - Contract.Ensures(Contract.Result() != null); - - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // Type.AsVariable should never be called - } - } - public virtual bool IsCtor { - get { - return false; - } - } - public virtual CtorType/*!*/ AsCtor { - get { - Contract.Ensures(Contract.Result() != null); - - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // Type.AsCtor should never be called - } - } - public virtual bool IsMap { - get { - return false; - } - } - public virtual MapType/*!*/ AsMap { - get { - Contract.Ensures(Contract.Result() != null); - - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // Type.AsMap should never be called - } - } - public virtual int MapArity { - get { - - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // Type.MapArity should never be called - } - } - public virtual bool IsUnresolved { - get { - return false; - } - } - public virtual UnresolvedTypeIdentifier/*!*/ AsUnresolved { - get { - Contract.Ensures(Contract.Result() != null); - - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // Type.AsUnresolved should never be called - } - } - - public virtual bool isFloat { - get { - return false; - } - } - public virtual int FloatExponent - { - get - { - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // Type.FloatExponent should never be called - } - } - public virtual int FloatMantissa { - get { - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // Type.FloatMantissa should never be called - } - } - public virtual bool IsBv { - get { - return false; - } - } - public virtual int BvBits { - get { - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // Type.BvBits should never be called - } - } - - public static readonly Type/*!*/ Int = new BasicType(SimpleType.Int); - public static readonly Type/*!*/ Real = new BasicType(SimpleType.Real); - public static readonly Type/*!*/ Bool = new BasicType(SimpleType.Bool); - private static BvType[] bvtypeCache; - - static public BvType GetBvType(int sz) { - Contract.Requires(0 <= sz); - Contract.Ensures(Contract.Result() != null); - - if (bvtypeCache == null) { - bvtypeCache = new BvType[128]; - } - if (sz < bvtypeCache.Length) { - BvType t = bvtypeCache[sz]; - if (t == null) { - t = new BvType(sz); - bvtypeCache[sz] = t; - } - return t; - } else { - return new BvType(sz); - } - } - - static public FloatType GetFloatType(int exp, int man) { - Contract.Requires(0 <= exp); - Contract.Requires(0 <= man); - Contract.Ensures(Contract.Result() != null); - - return new FloatType(exp, man); - } - - //------------ Match formal argument types on actual argument types - //------------ and return the resulting substitution of type variables - -#if OLD_UNIFICATION - public static IDictionary! - MatchArgumentTypes(List! typeParams, - List! formalArgs, - List! actualArgs, - List formalOuts, - List actualOuts, - string! opName, - TypecheckingContext! tc) - { - Contract.Requires(formalArgs.Length == actualArgs.Length); - Contract.Requires(formalOuts == null <==> actualOuts == null); - Contract.Requires(formalOuts != null ==> formalOuts.Length == actualOuts.Length); - List! boundVarSeq0 = new List (); - List! boundVarSeq1 = new List (); - Dictionary! subst = new Dictionary(); - - for (int i = 0; i < formalArgs.Length; ++i) { - try { - Type! actualType = cce.NonNull((!)actualArgs[i]).Type; - // if the type variables to be matched occur in the actual - // argument types, something has gone very wrong - Contract.Assert(forall{TypeVariable! var in typeParams); - !actualType.FreeVariables.Has(var)}; - formalArgs[i].Unify(actualType, - typeParams, - boundVarSeq0, boundVarSeq1, - subst); - } catch (UnificationFailedException) { - tc.Error(actualArgs[i], - "invalid type for argument {0} in {1}: {2} (expected: {3})", - i, opName, actualArgs[i].Type, - // we insert the type parameters that have already been - // chosen to get a more precise error message - formalArgs[i].Substitute(subst)); - // the bound variable sequences should be empty ... - // so that we can continue with the unification - Contract.Assert(boundVarSeq0.Length == 0 && boundVarSeq1.Length == 0); - } - } - - if (formalOuts != null) { - for (int i = 0; i < formalOuts.Length; ++i) { - try { - Type! actualType = cce.NonNull((!)actualOuts[i]).Type; - // if the type variables to be matched occur in the actual - // argument types, something has gone very wrong - Contract.Assert(forall{TypeVariable! var in typeParams); - !actualType.FreeVariables.Has(var)}; - formalOuts[i].Unify(actualType, - typeParams, - boundVarSeq0, boundVarSeq1, - subst); - } catch (UnificationFailedException) { - tc.Error(actualOuts[i], - "invalid type for result {0} in {1}: {2} (expected: {3})", - i, opName, actualOuts[i].Type, - // we insert the type parameters that have already been - // chosen to get a more precise error message - formalOuts[i].Substitute(subst)); - // the bound variable sequences should be empty ... - // so that we can continue with the unification - Contract.Assert(boundVarSeq0.Length == 0 && boundVarSeq1.Length == 0); - } - } - } - - // we only allow type parameters to be substituted - Contract.Assert(Contract.ForAll(subst.Keys , var=> typeParams.Has(var))); - - return subst; - } -#else - public static IDictionary/*!*/ - MatchArgumentTypes(List/*!*/ typeParams, - List/*!*/ formalArgs, - IList/*!*/ actualArgs, - List formalOuts, - List actualOuts, - string/*!*/ opName, - TypecheckingContext/*!*/ tc) { - Contract.Requires(typeParams != null); - Contract.Requires(formalArgs != null); - Contract.Requires(actualArgs != null); - Contract.Requires(opName != null); - Contract.Requires(tc != null); - Contract.Requires(formalArgs.Count == actualArgs.Count); - Contract.Requires((formalOuts == null) == (actualOuts == null)); - Contract.Requires(formalOuts == null || formalOuts.Count == cce.NonNull(actualOuts).Count); - Contract.Requires(tc == null || opName != null);//Redundant - Contract.Ensures(cce.NonNullDictionaryAndValues(Contract.Result>())); - - // requires "actualArgs" and "actualOuts" to have been type checked - - Dictionary subst = new Dictionary(); - foreach (TypeVariable/*!*/ tv in typeParams) { - Contract.Assert(tv != null); - TypeProxy proxy = new TypeProxy(Token.NoToken, tv.Name); - subst.Add(tv, proxy); - } - - for (int i = 0; i < formalArgs.Count; i++) { - Type formal = formalArgs[i].Substitute(subst); - Type actual = cce.NonNull(cce.NonNull(actualArgs[i]).Type); - // if the type variables to be matched occur in the actual - // argument types, something has gone very wrong - Contract.Assert(Contract.ForAll(0, typeParams.Count, index => !actual.FreeVariables.Contains(typeParams[index]))); - - if (!formal.Unify(actual)) { - Contract.Assume(tc != null); // caller expected no errors - Contract.Assert(opName != null); // follows from precondition - tc.Error(cce.NonNull(actualArgs[i]), - "invalid type for argument {0} in {1}: {2} (expected: {3})", - i, opName, actual, formalArgs[i]); - } - } - - if (formalOuts != null) { - for (int i = 0; i < formalOuts.Count; ++i) { - Type formal = formalOuts[i].Substitute(subst); - Type actual = cce.NonNull(cce.NonNull(actualOuts)[i].Type); - // if the type variables to be matched occur in the actual - // argument types, something has gone very wrong - Contract.Assert(Contract.ForAll(0, typeParams.Count, var => !actual.FreeVariables.Contains(typeParams[var]))); - - if (!formal.Unify(actual)) { - Contract.Assume(tc != null); // caller expected no errors - Contract.Assert(opName != null); // follows from precondition - tc.Error(actualOuts[i], - "invalid type for out-parameter {0} in {1}: {2} (expected: {3})", - i, opName, actual, formal); - } - } - } - - return subst; - } -#endif - - //------------ Match formal argument types of a function or map - //------------ on concrete types, substitute the result into the - //------------ result type. Null is returned for type errors - - public static List CheckArgumentTypes(List/*!*/ typeParams, - out List/*!*/ actualTypeParams, - List/*!*/ formalIns, - IList/*!*/ actualIns, - List/*!*/ formalOuts, - List actualOuts, - IToken/*!*/ typeCheckingSubject, - string/*!*/ opName, - TypecheckingContext/*!*/ tc) - // requires "actualIns" and "actualOuts" to have been type checked - { - Contract.Requires(typeParams != null); - - Contract.Requires(formalIns != null); - Contract.Requires(formalOuts != null); - Contract.Requires(actualIns != null); - Contract.Requires(typeCheckingSubject != null); - Contract.Requires(opName != null);Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out actualTypeParams))); - actualTypeParams = new List(); - - if (formalIns.Count != actualIns.Count) { - tc.Error(typeCheckingSubject, "wrong number of arguments in {0}: {1}", - opName, actualIns.Count); - // if there are no type parameters, we can still return the result - // type and hope that the type checking proceeds - return typeParams.Count == 0 ? formalOuts : null; - } else if (actualOuts != null && formalOuts.Count != actualOuts.Count) { - tc.Error(typeCheckingSubject, "wrong number of result variables in {0}: {1}", - opName, actualOuts.Count); - // if there are no type parameters, we can still return the result - // type and hope that the type checking proceeds - actualTypeParams = new List(); - return typeParams.Count == 0 ? formalOuts : null; - } - - int previousErrorCount = tc.ErrorCount; - IDictionary subst = - MatchArgumentTypes(typeParams, formalIns, actualIns, - actualOuts != null ? formalOuts : null, actualOuts, opName, tc); - Contract.Assert(cce.NonNullDictionaryAndValues(subst)); - foreach (TypeVariable/*!*/ var in typeParams) { - Contract.Assert(var != null); - actualTypeParams.Add(subst[var]); - } - - List/*!*/ actualResults = new List(); - foreach (Type/*!*/ t in formalOuts) { - Contract.Assert(t != null); - actualResults.Add(t.Substitute(subst)); - } - List resultFreeVars = FreeVariablesIn(actualResults); - if (previousErrorCount != tc.ErrorCount) { - // errors occured when matching the formal arguments - // in case we have been able to substitute all type parameters, - // we can still return the result type and hope that the - // type checking proceeds in a meaningful manner - if (typeParams.All(param => !resultFreeVars.Contains(param))) - return actualResults; - else - // otherwise there is no point in returning the result type, - // type checking would only get confused even further - return null; - } - - Contract.Assert(Contract.ForAll(0, typeParams.Count, index => !resultFreeVars.Contains(typeParams[index]))); - return actualResults; - } - - /////////////////////////////////////////////////////////////////////////// - - // about the same as Type.CheckArgumentTypes, but without - // detailed error reports - public static Type/*!*/ InferValueType(List/*!*/ typeParams, - List/*!*/ formalArgs, - Type/*!*/ formalResult, - List/*!*/ actualArgs) { - Contract.Requires(typeParams != null); - Contract.Requires(formalArgs != null); - Contract.Requires(formalResult != null); - Contract.Requires(actualArgs != null); - Contract.Ensures(Contract.Result() != null); - - IDictionary/*!*/ subst = - InferTypeParameters(typeParams, formalArgs, actualArgs); - Contract.Assert(cce.NonNullDictionaryAndValues(subst)); - - Type/*!*/ res = formalResult.Substitute(subst); - Contract.Assert(res != null); - // all type parameters have to be substituted with concrete types - List/*!*/ resFreeVars = res.FreeVariables; - Contract.Assert(resFreeVars != null); - Contract.Assert(Contract.ForAll(0, typeParams.Count, var => !resFreeVars.Contains(typeParams[var]))); - return res; - } - -#if OLD_UNIFICATION - public static IDictionary! - InferTypeParameters(List! typeParams, - List! formalArgs, - List! actualArgs) - { - Contract.Requires(formalArgs.Length == actualArgs.Length); - - List! boundVarSeq0 = new List (); - List! boundVarSeq1 = new List (); - Dictionary! subst = new Dictionary(); - - for (int i = 0; i < formalArgs.Length; ++i) { - try { - Contract.Assert(forall{TypeVariable! var in typeParams); - !actualArgs[i].FreeVariables.Has(var)}; - formalArgs[i].Unify(actualArgs[i], typeParams, - boundVarSeq0, boundVarSeq1, subst); - } catch (UnificationFailedException) { - System.Diagnostics.Debug.Fail("Type unification failed: " + - formalArgs[i] + " vs " + actualArgs[i]); - } - } - - // we only allow type parameters to be substituted - Contract.Assert(Contract.ForAll(subst.Keys , var=> typeParams.Has(var))); - return subst; - } -#else - /// - /// like Type.CheckArgumentTypes, but assumes no errors - /// (and only does arguments, not results; and takes actuals as List, not List) - /// - public static IDictionary/*!*/ - InferTypeParameters(List/*!*/ typeParams, - List/*!*/ formalArgs, - List/*!*/ actualArgs) { - Contract.Requires(typeParams != null); - Contract.Requires(formalArgs != null); - Contract.Requires(actualArgs != null);Contract.Requires(formalArgs.Count == actualArgs.Count); - Contract.Ensures(cce.NonNullDictionaryAndValues(Contract.Result>())); - - - List proxies = new List(); - Dictionary/*!*/ subst = new Dictionary(); - foreach (TypeVariable/*!*/ tv in typeParams) { - Contract.Assert(tv != null); - TypeProxy proxy = new TypeProxy(Token.NoToken, tv.Name); - proxies.Add(proxy); - subst.Add(tv, proxy); - } - - for (int i = 0; i < formalArgs.Count; i++) { - Type formal = formalArgs[i].Substitute(subst); - Type actual = actualArgs[i]; - // if the type variables to be matched occur in the actual - // argument types, something has gone very wrong - Contract.Assert(Contract.ForAll(0, typeParams.Count, index => !actual.FreeVariables.Contains(typeParams[index]))); - - if (!formal.Unify(actual)) { - Contract.Assume(false); // caller expected no errors - } - } - - return subst; - } -#endif - - //----------- Helper methods to deal with bound type variables --------------- - - public static void EmitOptionalTypeParams(TokenTextWriter stream, List typeParams) { - Contract.Requires(typeParams != null); - Contract.Requires(stream != null); - if (typeParams.Count > 0) { - stream.Write("<"); - typeParams.Emit(stream, ","); // default binding strength of 0 is ok - stream.Write(">"); - } - } - - // Sort the type parameters according to the order of occurrence in the argument types - public static List/*!*/ SortTypeParams(List/*!*/ typeParams, List/*!*/ argumentTypes, Type resultType) { - Contract.Requires(typeParams != null); - Contract.Requires(argumentTypes != null); - Contract.Ensures(Contract.Result>() != null); - - Contract.Ensures(Contract.Result>().Count == typeParams.Count); - if (typeParams.Count == 0) { - return typeParams; - } - - List freeVarsInUse = FreeVariablesIn(argumentTypes); - if (resultType != null) { - freeVarsInUse.AppendWithoutDups(resultType.FreeVariables); - } - // "freeVarsInUse" is already sorted, but it may contain type variables not in "typeParams". - // So, project "freeVarsInUse" onto "typeParams": - List sortedTypeParams = new List(); - foreach (TypeVariable/*!*/ var in freeVarsInUse) { - Contract.Assert(var != null); - if (typeParams.Contains(var)) { - sortedTypeParams.Add(var); - } - } - - if (sortedTypeParams.Count < typeParams.Count) - // add the type parameters not mentioned in "argumentTypes" in - // the end of the list (this can happen for quantifiers) - sortedTypeParams.AppendWithoutDups(typeParams); - - return sortedTypeParams; - } - - // Check that each of the type parameters occurs in at least one argument type. - // Return true if some type parameters appear only among "moreArgumentTypes" and - // not in "argumentTypes". - [Pure] - public static bool CheckBoundVariableOccurrences(List/*!*/ typeParams, - List/*!*/ argumentTypes, - List moreArgumentTypes, - IToken/*!*/ resolutionSubject, - string/*!*/ subjectName, - ResolutionContext/*!*/ rc) { - Contract.Requires(typeParams != null); - Contract.Requires(argumentTypes != null); - Contract.Requires(resolutionSubject != null); - Contract.Requires(subjectName != null); - Contract.Requires(rc != null); - List freeVarsInArgs = FreeVariablesIn(argumentTypes); - List moFreeVarsInArgs = moreArgumentTypes == null ? null : FreeVariablesIn(moreArgumentTypes); - bool someTypeParamsAppearOnlyAmongMo = false; - foreach (TypeVariable/*!*/ var in typeParams) { - Contract.Assert(var != null); - if (rc.LookUpTypeBinder(var.Name) == var) // avoid to complain twice about variables that are bound multiple times - { - if (freeVarsInArgs.Contains(var)) { - // cool - } else if (moFreeVarsInArgs != null && moFreeVarsInArgs.Contains(var)) { - someTypeParamsAppearOnlyAmongMo = true; - } else { - rc.Error(resolutionSubject, - "type variable must occur in {0}: {1}", - subjectName, var); - } - } - } - return someTypeParamsAppearOnlyAmongMo; - } - - [Pure] - public static List FreeVariablesIn(List arguments) { - Contract.Requires(arguments != null); - Contract.Ensures(Contract.Result>() != null); - List/*!*/ res = new List(); - foreach (Type/*!*/ t in arguments) { - Contract.Assert(t != null); - res.AppendWithoutDups(t.FreeVariables); - } - return res; - } - } - [ContractClassFor(typeof(Type))] - public abstract class TypeContracts : Type { - public TypeContracts() :base(null){ - - } - public override List FreeProxies { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - throw new NotImplementedException(); - } - } - public override List FreeVariables { - get { - Contract.Ensures(Contract.Result>() != null); - throw new NotImplementedException(); - } - } - public override Type Clone(IDictionary varMap) { - Contract.Requires(cce.NonNullDictionaryAndValues(varMap)); - Contract.Ensures(Contract.Result() != null); - - throw new NotImplementedException(); - } - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - - throw new NotImplementedException(); - } - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - Contract.Requires(stream != null); - throw new NotImplementedException(); - } - public override bool Equals(Type that, List thisBoundVariables, List thatBoundVariables) { - Contract.Requires(that != null); - Contract.Requires(thisBoundVariables != null); - Contract.Requires(thatBoundVariables != null); - throw new NotImplementedException(); - } - public override bool Unify(Type that, List unifiableVariables, IDictionary unifier) { - Contract.Requires(that != null); - Contract.Requires(unifiableVariables != null); - Contract.Requires(cce.NonNullDictionaryAndValues(unifier)); - Contract.Requires(Contract.ForAll(unifier.Keys, key => unifiableVariables.Contains(key))); - Contract.Requires(IsIdempotent(unifier)); - throw new NotImplementedException(); - } - public override Type Substitute(IDictionary subst) { - Contract.Requires(cce.NonNullDictionaryAndValues(subst)); - Contract.Ensures(Contract.Result() != null); - - throw new NotImplementedException(); - } - public override Type ResolveType(ResolutionContext rc) { - Contract.Requires(rc != null); - Contract.Ensures(Contract.Result() != null); - - throw new NotImplementedException(); - } - public override int GetHashCode(List boundVariables) { - Contract.Requires(boundVariables != null); - throw new NotImplementedException(); - } - } - //===================================================================== - - public class BasicType : Type { - public readonly SimpleType T; - public BasicType(IToken/*!*/ token, SimpleType t) - : base(token) { - Contract.Requires(token != null); - T = t; - } - public BasicType(SimpleType t) - : base(Token.NoToken) { - T = t; - } - - //----------- Cloning ---------------------------------- - // We implement our own clone-method, because bound type variables - // have to be created in the right way. It is /not/ ok to just clone - // everything recursively. - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - // BasicTypes are immutable anyway, we do not clone - return this; - } - - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - return this; - } - - //----------- Linearisation ---------------------------------- - - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - //Contract.Requires(stream != null); - // no parentheses are necessary for basic types - stream.SetToken(this); - stream.Write("{0}", this); - } - - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - switch (T) { - case SimpleType.Int: - return "int"; - case SimpleType.Real: - return "real"; - case SimpleType.Bool: - return "bool"; - } - Debug.Assert(false, "bad type " + T); - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // make compiler happy - } - - //----------- Equality ---------------------------------- - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - // shortcut - Type thatType = that as Type; - if (thatType == null) - return false; - BasicType thatBasicType = TypeProxy.FollowProxy(thatType.Expanded) as BasicType; - return thatBasicType != null && this.T == thatBasicType.T; - } - - [Pure] - public override bool Equals(Type that, List thisBoundVariables, List thatBoundVariables) { - //Contract.Requires(thatBoundVariables != null); - //Contract.Requires(thisBoundVariables != null); - //Contract.Requires(that != null); - return this.Equals(that); - } - - //----------- Unification of types ----------- - - public override bool Unify(Type that, List unifiableVariables, IDictionary/*!*/ unifier) { - //Contract.Requires(unifiableVariables != null); - //Contract.Requires(that != null); - //Contract.Requires(cce.NonNullElements(unifier)); - // an idempotent substitution that describes the - // unification result up to a certain point - - that = that.Expanded; - if (that is TypeProxy || that is TypeVariable) { - return that.Unify(this, unifiableVariables, unifier); - } else { - return this.Equals(that); - } - } - -#if OLD_UNIFICATION - public override void Unify(Type! that, - List! unifiableVariables, - List! thisBoundVariables, - List! thatBoundVariables, - IDictionary! result) { - that = that.Expanded; - if (that is TypeVariable) { - that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); - } else { - if (!this.Equals(that)) - throw UNIFICATION_FAILED; - } - } -#endif - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - return this; - } - - //----------- Hashcodes ---------------------------------- - - [Pure] - public override int GetHashCode(List boundVariables) { - //Contract.Requires(boundVariables != null); - return this.T.GetHashCode(); - } - - //----------- Resolution ---------------------------------- - - public override Type ResolveType(ResolutionContext rc) { - //Contract.Requires(rc != null); - Contract.Ensures(Contract.Result() != null); - // nothing to resolve - return this; - } - - // determine the free variables in a type, in the order in which the variables occur - public override List/*!*/ FreeVariables { - get { - Contract.Ensures(Contract.Result>() != null); - - return new List(); // basic type are closed - } - } - - public override List/*!*/ FreeProxies { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return new List(); - } - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsBasic { - get { - return true; - } - } - public override bool IsInt { - get { - return this.T == SimpleType.Int; - } - } - public override bool IsReal { - get { - return this.T == SimpleType.Real; - } - } - public override bool IsBool { - get { - return this.T == SimpleType.Bool; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitBasicType(this); - } - } - - //===================================================================== - - //Note that the functions in this class were directly copied from the BV class just below - public class FloatType : Type { - public readonly int Mantissa; //Size of mantissa in bits - public readonly int Exponent; //Size of exponent in bits - - public FloatType(IToken token, int exponent, int mantissa) - : base(token) { - Contract.Requires(token != null); - Exponent = exponent; - Mantissa = mantissa; - } - - public FloatType(int exponent, int mantissa) - : base(Token.NoToken) { - Exponent = exponent; - Mantissa = mantissa; - } - - //----------- Cloning ---------------------------------- - // We implement our own clone-method, because bound type variables - // have to be created in the right way. It is /not/ ok to just clone - // everything recursively. - - public override Type Clone(IDictionary/*!*/ varMap) - { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - // FloatTypes are immutable anyway, we do not clone - return this; - } - - public override Type CloneUnresolved() - { - Contract.Ensures(Contract.Result() != null); - return this; - } - - //----------- Linearisation ---------------------------------- - - public override void Emit(TokenTextWriter stream, int contextBindingStrength) - { - //Contract.Requires(stream != null); - // no parentheses are necessary for bitvector-types - stream.SetToken(this); - stream.Write("{0}", this); - } - - public override string ToString() - { - Contract.Ensures(Contract.Result() != null); - return "float (" + Exponent + " " + Mantissa + ")"; - } - - //----------- Equality ---------------------------------- - - [Pure] - public override bool Equals(Type/*!*/ that, - List/*!*/ thisBoundVariables, - List/*!*/ thatBoundVariables) - { - FloatType thatFloatType = TypeProxy.FollowProxy(that.Expanded) as FloatType; - return thatFloatType != null && this.Mantissa == thatFloatType.Mantissa && this.Exponent == thatFloatType.Exponent; - } - - //----------- Unification of types ----------- - - public override bool Unify(Type/*!*/ that, - List/*!*/ unifiableVariables, - // an idempotent substitution that describes the - // unification result up to a certain point - IDictionary/*!*/ unifier) - { - //Contract.Requires(that != null); - //Contract.Requires(unifiableVariables != null); - //Contract.Requires(cce.NonNullElements(unifier)); - that = that.Expanded; - if (that is TypeProxy || that is TypeVariable) { - return that.Unify(this, unifiableVariables, unifier); - } - else { - return this.Equals(that); - } - } - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public override Type Substitute(IDictionary/*!*/ subst) - { - Contract.Ensures(Contract.Result() != null); - return this; - } - - //----------- Hashcodes ---------------------------------- - - [Pure] - public override int GetHashCode(List boundVariables) - { - return this.Mantissa.GetHashCode() + this.Exponent.GetHashCode(); - } - - //----------- Resolution ---------------------------------- - - public override Type ResolveType(ResolutionContext rc) - { - //Contract.Requires(rc != null); - Contract.Ensures(Contract.Result() != null); - // nothing to resolve - return this; - } - - // determine the free variables in a type, in the order in which the variables occur - public override List/*!*/ FreeVariables - { - get - { - Contract.Ensures(Contract.Result>() != null); - - return new List(); // bitvector-type are closed - } - } - - public override List/*!*/ FreeProxies - { - get - { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return new List(); - } - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsFloat { - get { - return true; - } - } - public override int FloatMantissa { - get { - return Mantissa; - } - } - public override int FloatExponent { - get { - return Exponent; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) - { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitFloatType(this); - } - - } - - //===================================================================== - - public class BvType : Type { - public readonly int Bits; - - public BvType(IToken token, int bits) - : base(token) { - Contract.Requires(token != null); - Bits = bits; - } - - public BvType(int bits) - : base(Token.NoToken) { - Bits = bits; - } - - //----------- Cloning ---------------------------------- - // We implement our own clone-method, because bound type variables - // have to be created in the right way. It is /not/ ok to just clone - // everything recursively. - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - // BvTypes are immutable anyway, we do not clone - return this; - } - - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - return this; - } - - //----------- Linearisation ---------------------------------- - - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - //Contract.Requires(stream != null); - // no parentheses are necessary for bitvector-types - stream.SetToken(this); - stream.Write("{0}", this); - } - - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - return "bv" + Bits; - } - - //----------- Equality ---------------------------------- - - [Pure] - public override bool Equals(Type/*!*/ that, - List/*!*/ thisBoundVariables, - List/*!*/ thatBoundVariables) { - //Contract.Requires(thisBoundVariables != null); - //Contract.Requires(thatBoundVariables != null); - //Contract.Requires(that != null); - BvType thatBvType = TypeProxy.FollowProxy(that.Expanded) as BvType; - return thatBvType != null && this.Bits == thatBvType.Bits; - } - - //----------- Unification of types ----------- - - public override bool Unify(Type/*!*/ that, - List/*!*/ unifiableVariables, - // an idempotent substitution that describes the - // unification result up to a certain point - IDictionary/*!*/ unifier) { - //Contract.Requires(that != null); - //Contract.Requires(unifiableVariables != null); - //Contract.Requires(cce.NonNullElements(unifier)); - that = that.Expanded; - if (that is TypeProxy || that is TypeVariable) { - return that.Unify(this, unifiableVariables, unifier); - } else { - return this.Equals(that); - } - } - -#if OLD_UNIFICATION - public override void Unify(Type that, - List! unifiableVariables, - List! thisBoundVariables, - List! thatBoundVariables, - IDictionary result){ -Contract.Requires(result != null); -Contract.Requires(that != null); - that = that.Expanded; - if (that is TypeVariable) { - that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); - } else { - if (!this.Equals(that)) - throw UNIFICATION_FAILED; - } - } -#endif - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - return this; - } - - //----------- Hashcodes ---------------------------------- - - [Pure] - public override int GetHashCode(List boundVariables) { - //Contract.Requires(boundVariables != null); - return this.Bits.GetHashCode(); - } - - //----------- Resolution ---------------------------------- - - public override Type ResolveType(ResolutionContext rc) { - //Contract.Requires(rc != null); - Contract.Ensures(Contract.Result() != null); - // nothing to resolve - return this; - } - - // determine the free variables in a type, in the order in which the variables occur - public override List/*!*/ FreeVariables { - get { - Contract.Ensures(Contract.Result>() != null); - - return new List(); // bitvector-type are closed - } - } - - public override List/*!*/ FreeProxies { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return new List(); - } - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsBv { - get { - return true; - } - } - public override int BvBits { - get { - return Bits; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitBvType(this); - } - } - - //===================================================================== - - // An AST node containing an identifier and a sequence of type arguments, which - // will be turned either into a TypeVariable, into a CtorType or into a BvType - // during the resolution phase - public class UnresolvedTypeIdentifier : Type { - public readonly string/*!*/ Name; - public readonly List/*!*/ Arguments; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Name != null); - Contract.Invariant(Arguments != null); - } - - - public UnresolvedTypeIdentifier(IToken token, string name) - : this(token, name, new List()) { - Contract.Requires(name != null); - Contract.Requires(token != null); - } - - public UnresolvedTypeIdentifier(IToken token, string name, List arguments) - : base(token) { - Contract.Requires(arguments != null); - Contract.Requires(name != null); - Contract.Requires(token != null); - this.Name = name; - this.Arguments = arguments; - } - - //----------- Cloning ---------------------------------- - // We implement our own clone-method, because bound type variables - // have to be created in the right way. It is /not/ ok to just clone - // everything recursively - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - List/*!*/ newArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - newArgs.Add(t.Clone(varMap)); - } - return new UnresolvedTypeIdentifier(tok, Name, newArgs); - } - - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - List/*!*/ newArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - newArgs.Add(t.CloneUnresolved()); - } - return new UnresolvedTypeIdentifier(tok, Name, newArgs); - } - - //----------- Equality ---------------------------------- - - [Pure] - public override bool Equals(Type that, - List/*!*/ thisBoundVariables, - List/*!*/ thatBoundVariables) { - //Contract.Requires(thisBoundVariables != null); - //Contract.Requires(thatBoundVariables != null); - //Contract.Requires(that != null); - System.Diagnostics.Debug.Fail("UnresolvedTypeIdentifier.Equals should never be called"); - return false; // to make the compiler happy - } - - //----------- Unification of types ----------- - - public override bool Unify(Type that, - List/*!*/ unifiableVariables, - IDictionary result) { - //Contract.Requires(unifiableVariables != null); - //Contract.Requires(cce.NonNullElements(result)); - //Contract.Requires(that != null); - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // UnresolvedTypeIdentifier.Unify should never be called - } - -#if OLD_UNIFICATION - public override void Unify(Type that, - List! unifiableVariables, - List! thisBoundVariables, - List! thatBoundVariables, - IDictionary result){ -Contract.Requires(result != null); -Contract.Requires(that != null); - System.Diagnostics.Debug.Fail("UnresolvedTypeIdentifier.Unify should never be called"); - } -#endif - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // UnresolvedTypeIdentifier.Substitute should never be called - } - - //----------- Hashcodes ---------------------------------- - - [Pure] - public override int GetHashCode(List boundVariables) { - //Contract.Requires(boundVariables != null); - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // UnresolvedTypeIdentifier.GetHashCode should never be called - } - - //----------- Resolution ---------------------------------- - - public override Type ResolveType(ResolutionContext rc) { - //Contract.Requires(rc != null); - Contract.Ensures(Contract.Result() != null); - // first case: the type name denotes a bitvector-type - if (Name.StartsWith("bv") && Name.Length > 2) { - bool is_bv = true; - for (int i = 2; i < Name.Length; ++i) { - if (!char.IsDigit(Name[i])) { - is_bv = false; - break; - } - } - if (is_bv) { - if (Arguments.Count > 0) { - rc.Error(this, - "bitvector types must not be applied to arguments: {0}", - Name); - } - return new BvType(tok, int.Parse(Name.Substring(2))); - } - } - - // second case: the identifier is resolved to a type variable - TypeVariable var = rc.LookUpTypeBinder(Name); - if (var != null) { - if (Arguments.Count > 0) { - rc.Error(this, - "type variables must not be applied to arguments: {0}", - var); - } - return var; - } - - // third case: the identifier denotes a type constructor and we - // recursively resolve the arguments - TypeCtorDecl ctorDecl = rc.LookUpType(Name); - if (ctorDecl != null) { - if (Arguments.Count != ctorDecl.Arity) { - rc.Error(this, - "type constructor received wrong number of arguments: {0}", - ctorDecl); - return this; - } - return new CtorType(tok, ctorDecl, ResolveArguments(rc)); - } - - // fourth case: the identifier denotes a type synonym - TypeSynonymDecl synDecl = rc.LookUpTypeSynonym(Name); - if (synDecl != null) { - if (Arguments.Count != synDecl.TypeParameters.Count) { - rc.Error(this, - "type synonym received wrong number of arguments: {0}", - synDecl); - return this; - } - List/*!*/ resolvedArgs = ResolveArguments(rc); - Contract.Assert(resolvedArgs != null); - - return new TypeSynonymAnnotation(this.tok, synDecl, resolvedArgs); - - } - - // otherwise: this name is not declared anywhere - rc.Error(this, "undeclared type: {0}", Name); - return this; - } - - private List ResolveArguments(ResolutionContext rc) { - Contract.Requires(rc != null); - Contract.Ensures(Contract.Result>() != null); - List/*!*/ resolvedArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - resolvedArgs.Add(t.ResolveType(rc)); - } - return resolvedArgs; - } - - public override List/*!*/ FreeVariables { - get { - Contract.Ensures(Contract.Result>() != null); - - return new List(); - } - } - - public override List/*!*/ FreeProxies { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return new List(); - } - } - - //----------- Linearisation ---------------------------------- - - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - //Contract.Requires(stream != null); - stream.SetToken(this); - // PR: should unresolved types be syntactically distinguished from resolved types? - CtorType.EmitCtorType(this.Name, Arguments, stream, contextBindingStrength); - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsUnresolved { - get { - return true; - } - } - public override UnresolvedTypeIdentifier/*!*/ AsUnresolved { - get { - Contract.Ensures(Contract.Result() != null); - return this; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitUnresolvedTypeIdentifier(this); - } - } - - //===================================================================== - - public class TypeVariable : Type { - public readonly string/*!*/ Name; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Name != null); - } - - - public TypeVariable(IToken token, string name) - : base(token) { - Contract.Requires(name != null); - Contract.Requires(token != null); - this.Name = name; - } - - //----------- Cloning ---------------------------------- - // We implement our own clone-method, because bound type variables - // have to be created in the right way. It is /not/ ok to just clone - // everything recursively - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - // if this variable is mapped to some new variable, we take the new one - // otherwise, return this - TypeVariable res; - varMap.TryGetValue(this, out res); - if (res == null) - return this; - else - return res; - } - - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - return this; - } - - //----------- Equality ---------------------------------- - - [Pure] - public override bool Equals(Type that, - List/*!*/ thisBoundVariables, - List/*!*/ thatBoundVariables) { - //Contract.Requires(thisBoundVariables != null); - //Contract.Requires(thatBoundVariables != null); - //Contract.Requires(that != null); - TypeVariable thatAsTypeVar = TypeProxy.FollowProxy(that.Expanded) as TypeVariable; - - if (thatAsTypeVar == null) - return false; - - int thisIndex = thisBoundVariables.LastIndexOf(this); - int thatIndex = thatBoundVariables.LastIndexOf(thatAsTypeVar); - return (thisIndex >= 0 && thisIndex == thatIndex) || - (thisIndex == -1 && thatIndex == -1 && - Object.ReferenceEquals(this, thatAsTypeVar)); - } - - //----------- Unification of types ----------- - - public override bool Unify(Type/*!*/ that, - List/*!*/ unifiableVariables, - // an idempotent substitution that describes the - // unification result up to a certain point - IDictionary/*!*/ unifier) { - //Contract.Requires(that != null); - //Contract.Requires(unifiableVariables != null); - //Contract.Requires(cce.NonNullElements(unifier)); - that = that.Expanded; - if (that is TypeProxy && !(that is ConstrainedProxy)) - return that.Unify(this, unifiableVariables, unifier); - - if (this.Equals(that)) - return true; - - if (unifiableVariables.Contains(this)) { - Type previousSubst; - unifier.TryGetValue(this, out previousSubst); - if (previousSubst == null) { - return addSubstitution(unifier, that); - } else { - // we have to unify the old instantiation with the new one - return previousSubst.Unify(that, unifiableVariables, unifier); - } - } - - // this cannot be instantiated with anything - // but that possibly can ... - - TypeVariable tv = that as TypeVariable; - - return tv != null && - unifiableVariables.Contains(tv) && - that.Unify(this, unifiableVariables, unifier); - } - - // TODO: the following might cause problems, because when applying substitutions - // to type proxies the substitutions are not propagated to the proxy - // constraints (right now at least) - private bool addSubstitution(IDictionary/*!*/ oldSolution, - // the type that "this" is instantiated with - Type/*!*/ newSubst) { - Contract.Requires(cce.NonNullDictionaryAndValues(oldSolution)); - Contract.Requires(newSubst != null); - Contract.Requires(!oldSolution.ContainsKey(this)); - - Dictionary/*!*/ newMapping = new Dictionary(); - // apply the old (idempotent) substitution to the new instantiation - Type/*!*/ substSubst = newSubst.Substitute(oldSolution); - Contract.Assert(substSubst != null); - // occurs check - if (substSubst.FreeVariables.Contains(this)) - return false; - newMapping.Add(this, substSubst); - - // apply the new substitution to the old ones to ensure idempotence - List/*!*/ keys = new List(); - keys.AddRange(oldSolution.Keys); - foreach (TypeVariable/*!*/ var in keys) { - Contract.Assert(var != null); - oldSolution[var] = oldSolution[var].Substitute(newMapping); - } - oldSolution.Add(this, substSubst); - - Contract.Assert(IsIdempotent(oldSolution)); - return true; - } - -#if OLD_UNIFICATION - public override void Unify(Type that, - List! unifiableVariables, - List! thisBoundVariables, - List! thatBoundVariables, - IDictionary result){ -Contract.Requires(result != null); -Contract.Requires(that != null); - that = that.Expanded; - int thisIndex = thisBoundVariables.LastIndexOf(this); - if (thisIndex == -1) { - // this is not a bound variable and can possibly be matched on that - // that must not contain any bound variables - List! thatFreeVars = that.FreeVariables; - if (thatBoundVariables.Any(var=> thatFreeVars.Has(var))) - throw UNIFICATION_FAILED; - - // otherwise, in case that is a typevariable it cannot be bound and - // we can just check for equality - if (this.Equals(that)) - return; - - if (!unifiableVariables.Has(this)) { - // this cannot be instantiated with anything - // but that possibly can ... - if ((that is TypeVariable) && - unifiableVariables.Has(that as TypeVariable)) { - that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); - return; - } else { - throw UNIFICATION_FAILED; - } - } - - Type previousSubst; - result.TryGetValue(this, out previousSubst); - if (previousSubst == null) { - addSubstitution(result, that); - } else { - // we have to unify the old instantiation with the new one - previousSubst.Unify(that, unifiableVariables, thisBoundVariables, thatBoundVariables, result); - } - } else { - // this is a bound variable, that also has to be one (with the same index) - if (!(that is TypeVariable) || - thatBoundVariables.LastIndexOf(that) != thisIndex) - throw UNIFICATION_FAILED; - } - } - -#endif - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - Type res; - if (subst.TryGetValue(this, out res)) { - Contract.Assert(res != null); - return res; - } else { - return this; - } - } - - //----------- Hashcodes ---------------------------------- - - [Pure] - public override int GetHashCode(List boundVariables) { - //Contract.Requires(boundVariables != null); - int thisIndex = boundVariables.LastIndexOf(this); - if (thisIndex == -1) - return GetBaseHashCode(); - return thisIndex * 27473671; - } - - //----------- Linearisation ---------------------------------- - - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - //Contract.Requires(stream != null); - // never put parentheses around variables - stream.SetToken(this); - stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); - } - - //----------- Resolution ---------------------------------- - - public override Type ResolveType(ResolutionContext rc) { - //Contract.Requires(rc != null); - //Contract.Ensures(Contract.Result() != null); - // nothing to resolve - return this; - } - - public override List/*!*/ FreeVariables { - get { - Contract.Ensures(Contract.Result>() != null); - return new List { this }; - } - } - - public override List/*!*/ FreeProxies { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return new List(); - } - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsVariable { - get { - return true; - } - } - public override TypeVariable/*!*/ AsVariable { - get { - Contract.Ensures(Contract.Result() != null); - return this; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - //Contract.Ensures(Contract.Result() != null); - return visitor.VisitTypeVariable(this); - } - } - - //===================================================================== - - public class TypeProxy : Type { - static int proxies = 0; - protected readonly string/*!*/ Name; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Name != null); - } - - - public TypeProxy(IToken token, string givenName) - : this(token, givenName, "proxy") { - Contract.Requires(givenName != null); - Contract.Requires(token != null); - } - - protected TypeProxy(IToken token, string givenName, string kind) - : base(token) { - Contract.Requires(kind != null); - Contract.Requires(givenName != null); - Contract.Requires(token != null); - Name = givenName + "$" + kind + "#" + proxies; - proxies++; - } - - private Type proxyFor; - public Type ProxyFor { - // apply path shortening, and then return the value of proxyFor - get { - TypeProxy anotherProxy = proxyFor as TypeProxy; - if (anotherProxy != null && anotherProxy.proxyFor != null) { - // apply path shortening by bypassing "anotherProxy" (and possibly others) - proxyFor = anotherProxy.ProxyFor; - Contract.Assert(proxyFor != null); - } - return proxyFor; - } - } - - [Pure] - [Reads(ReadsAttribute.Reads.Everything)] - public static Type FollowProxy(Type t) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); - Contract.Ensures(!(Contract.Result() is TypeProxy) || ((TypeProxy)Contract.Result()).proxyFor == null); - if (t is TypeProxy) { - Type p = ((TypeProxy)t).ProxyFor; - if (p != null) { - return p; - } - } - return t; - } - - protected void DefineProxy(Type ty) { - Contract.Requires(ty != null); - Contract.Requires(ProxyFor == null); - // follow ty down to the leaf level, so that we can avoid creating a cycle - ty = FollowProxy(ty); - if (!object.ReferenceEquals(this, ty)) { - proxyFor = ty; - } - } - - //----------- Cloning ---------------------------------- - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - Type p = ProxyFor; - if (p != null) { - return p.Clone(varMap); - } else { - return new TypeProxy(this.tok, this.Name); // the clone will have a name that ends with $proxy$proxy - } - } - - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - return new TypeProxy(this.tok, this.Name); // the clone will have a name that ends with $proxy$proxy - } - - //----------- Equality ---------------------------------- - - [Pure] - public override bool Equals(Type that, - List/*!*/ thisBoundVariables, - List/*!*/ thatBoundVariables) { - //Contract.Requires(thisBoundVariables != null); - //Contract.Requires(thatBoundVariables != null); - //Contract.Requires(that != null); - if (object.ReferenceEquals(this, that)) { - return true; - } - Type p = ProxyFor; - if (p != null) { - return p.Equals(that, thisBoundVariables, thatBoundVariables); - } else { - // This proxy could be made to be equal to anything, so what to return? - return false; - } - } - - //----------- Unification of types ----------- - - // determine whether the occurs check fails: this is a strict subtype of that - protected bool ReallyOccursIn(Type that) { - Contract.Requires(that != null); - that = FollowProxy(that.Expanded); - return that.FreeProxies.Contains(this) && - (that.IsCtor || that.IsMap && this != that && this.ProxyFor != that); - } - - public override bool Unify(Type that, - List/*!*/ unifiableVariables, - IDictionary result) { - //Contract.Requires(cce.NonNullElements(result)); - //Contract.Requires(unifiableVariables != null); - //Contract.Requires(that != null); - Type p = ProxyFor; - if (p != null) { - return p.Unify(that, unifiableVariables, result); - } else { - // unify this with that - if (this.ReallyOccursIn(that)) - return false; - DefineProxy(that.Expanded); - return true; - } - } - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - Type p = ProxyFor; - if (p != null) { - return p.Substitute(subst); - } else { - return this; - } - } - - //----------- Hashcodes ---------------------------------- - - [Pure] - public override int GetHashCode(List boundVariables) { - //Contract.Requires(boundVariables != null); - Type p = ProxyFor; - if (p != null) { - return p.GetHashCode(boundVariables); - } else { - return GetBaseHashCode(); - } - } - - //----------- Linearisation ---------------------------------- - - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - //Contract.Requires(stream != null); - Type p = ProxyFor; - if (p != null) { - p.Emit(stream, contextBindingStrength); - } else { - // no need for parentheses - stream.SetToken(this); - stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); - } - } - - //----------- Resolution ---------------------------------- - - public override Type ResolveType(ResolutionContext rc) { - //Contract.Requires(rc != null); - Contract.Ensures(Contract.Result() != null); - Type p = ProxyFor; - if (p != null) { - return p.ResolveType(rc); - } else { - return this; - } - } - - public override List/*!*/ FreeVariables { - get { - Contract.Ensures(Contract.Result>() != null); - - Type p = ProxyFor; - if (p != null) { - return p.FreeVariables; - } else { - return new List(); - } - } - } - - public override List/*!*/ FreeProxies { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - Type p = ProxyFor; - if (p != null) { - return p.FreeProxies; - } else { - List/*!*/ res = new List(); - res.Add(this); - return res; - } - } - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsBasic { - get { - Type p = ProxyFor; - return p != null && p.IsBasic; - } - } - public override bool IsInt { - get { - Type p = ProxyFor; - return p != null && p.IsInt; - } - } - public override bool IsReal { - get { - Type p = ProxyFor; - return p != null && p.IsReal; - } - } - public override bool IsFloat { - get { - Type p = ProxyFor; - return p != null && p.IsFloat; - } - } - public override bool IsBool { - get { - Type p = ProxyFor; - return p != null && p.IsBool; - } - } - - public override bool IsVariable { - get { - Type p = ProxyFor; - return p != null && p.IsVariable; - } - } - public override TypeVariable/*!*/ AsVariable { - get { - Contract.Ensures(Contract.Result() != null); - - Type p = ProxyFor; - Contract.Assume(p != null); - return p.AsVariable; - } - } - - public override bool IsCtor { - get { - Type p = ProxyFor; - return p != null && p.IsCtor; - } - } - public override CtorType/*!*/ AsCtor { - get { - Contract.Ensures(Contract.Result() != null); - - Type p = ProxyFor; - Contract.Assume(p != null); - return p.AsCtor; - } - } - public override bool IsMap { - get { - Type p = ProxyFor; - return p != null && p.IsMap; - } - } - public override MapType/*!*/ AsMap { - get { - Contract.Ensures(Contract.Result() != null); - - Type p = ProxyFor; - Contract.Assume(p != null); - return p.AsMap; - } - } - public override int MapArity { - get { - Type p = ProxyFor; - Contract.Assume(p != null); - return p.MapArity; - } - } - public override bool IsUnresolved { - get { - Type p = ProxyFor; - return p != null && p.IsUnresolved; - } - } - public override UnresolvedTypeIdentifier/*!*/ AsUnresolved { - get { - Contract.Ensures(Contract.Result() != null); - - Type p = ProxyFor; - Contract.Assume(p != null); - return p.AsUnresolved; - } - } - - public override bool IsBv { - get { - Type p = ProxyFor; - return p != null && p.IsBv; - } - } - public override int BvBits { - get { - Type p = ProxyFor; - Contract.Assume(p != null); - return p.BvBits; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitTypeProxy(this); - } - } - - public abstract class ConstrainedProxy : TypeProxy { - protected ConstrainedProxy(IToken token, string givenName, string kind) - : base(token, givenName, kind) { - Contract.Requires(kind != null); - Contract.Requires(givenName != null); - Contract.Requires(token != null); - } - } - - /// - /// Each instance of this class represents a set of bitvector types. In particular, it represents - /// a bitvector type bvN iff - /// minBits ATMOST N and - /// foreach constraint (t0,t1), the types represented by t0 and t1 are bitvector types whose - /// number of bits add up to N. - /// This means that the size of a BvTypeProxy p is constrained not only by p.minBits, but also - /// by the size of various t0 and t1 types that are transitively part of BvTypeProxy constraints. - /// If such a t0 or t1 were to get its ProxyFor field defined, then p would have to be further - /// constrained too. This doesn't seem like it would ever occur in a Boogie 2 program, because: - /// the only place where a BvTypeProxy with constraints can occur is as the type of a - /// BvConcatExpr, and - /// the types of all local variables are explicitly declared, which means that the types of - /// subexpressions of a BvConcatExpr are not going to change other than via the type of the - /// BvConcatExpr. - /// So, this implementation of BvTypeProxy does not keep track of where a BvTypeProxy may occur - /// transitively in some other BvTypeProxy's constraints. - /// - public class BvTypeProxy : ConstrainedProxy { - public int MinBits; - List constraints; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(cce.NonNullElements(constraints, true)); - } - - class BvTypeConstraint { - public Type/*!*/ T0; - public Type/*!*/ T1; - public BvTypeConstraint(Type t0, Type t1) { - Contract.Requires(t1 != null); - Contract.Requires(t0 != null); - Contract.Requires(t0.IsBv && t1.IsBv); - T0 = t0; - T1 = t1; - } - } - - public BvTypeProxy(IToken token, string name, int minBits) - : base(token, name, "bv" + minBits + "proxy") { - Contract.Requires(name != null); - Contract.Requires(token != null); - this.MinBits = minBits; - } - - /// - /// Requires that any further constraints to be placed on t0 and t1 go via the object to - /// be constructed. - /// - public BvTypeProxy(IToken token, string name, Type t0, Type t1) - : base(token, name, "bvproxy") { - Contract.Requires(t1 != null); - Contract.Requires(t0 != null); - Contract.Requires(name != null); - Contract.Requires(token != null); - Contract.Requires(t0.IsBv && t1.IsBv); - t0 = FollowProxy(t0); - t1 = FollowProxy(t1); - this.MinBits = MinBitsFor(t0) + MinBitsFor(t1); - List list = new List(); - list.Add(new BvTypeConstraint(t0, t1)); - this.constraints = list; - } - - /// - /// Construct a BvTypeProxy like p, but with minBits. - /// - private BvTypeProxy(BvTypeProxy p, int minBits) - : base(p.tok, p.Name, "") { - Contract.Requires(p != null); - this.MinBits = minBits; - this.constraints = p.constraints; - } - - private BvTypeProxy(IToken token, string name, int minBits, List constraints) - : base(token, name, "") { - Contract.Requires(cce.NonNullElements(constraints, true)); - Contract.Requires(name != null); - Contract.Requires(token != null); - this.MinBits = minBits; - this.constraints = constraints; - } - - [Pure] - [Reads(ReadsAttribute.Reads.Everything)] - private static int MinBitsFor(Type t) { - Contract.Requires(t != null); - Contract.Requires(t.IsBv); - Contract.Ensures(0 <= Contract.Result()); - - if (t is TypeSynonymAnnotation) { - return MinBitsFor(((TypeSynonymAnnotation)t).ExpandedType); - } - - if (t is BvType) { - return t.BvBits; - } else { - return ((BvTypeProxy)t).MinBits; - } - } - - //----------- Cloning ---------------------------------- - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - Type p = ProxyFor; - if (p != null) { - return p.Clone(varMap); - } else { - return new BvTypeProxy(this.tok, this.Name, this.MinBits, this.constraints); // the clone will have a name that ends with $bvproxy$bvproxy - } - } - - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - return new BvTypeProxy(this.tok, this.Name, this.MinBits, this.constraints); // the clone will have a name that ends with $bvproxy$bvproxy - } - - //----------- Unification of types ----------- - - public override bool Unify(Type that, - List unifiableVariables, - IDictionary result) { - //Contract.Requires(cce.NonNullElements(result)); - //Contract.Requires(unifiableVariables != null); - //Contract.Requires(that != null); - Type p = ProxyFor; - if (p != null) { - return p.Unify(that, unifiableVariables, result); - } - - // unify this with that, if possible - that = that.Expanded; - that = FollowProxy(that); - - if (this.ReallyOccursIn(that)) - return false; - - TypeVariable tv = that as TypeVariable; - - if (tv != null && unifiableVariables.Contains(tv)) - return that.Unify(this, unifiableVariables, result); - - if (object.ReferenceEquals(this, that)) { - return true; - } else if (that is BvType) { - if (MinBits <= that.BvBits) { - if (constraints != null) { - foreach (BvTypeConstraint btc in constraints) { - int minT1 = MinBitsFor(btc.T1); - int left = IncreaseBits(btc.T0, that.BvBits - minT1); - left = IncreaseBits(btc.T1, minT1 + left); - Contract.Assert(left == 0); // because it should always be possible to increase the total size of a BvTypeConstraint pair (t0,t1) arbitrarily - } - } - DefineProxy(that); - return true; - } - } else if (that is BvTypeProxy) { - BvTypeProxy bt = (BvTypeProxy)that; - // keep the proxy with the stronger constraint (that is, the higher minBits), but if either - // has a constraints list, then concatenate both constraints lists and define the previous - // proxies to the new one - if (this.constraints != null || bt.constraints != null) { - List list = new List(); - if (this.constraints != null) { - list.AddRange(this.constraints); - } - if (bt.constraints != null) { - list.AddRange(bt.constraints); - } - BvTypeProxy np = new BvTypeProxy(this.tok, this.Name, Math.Max(this.MinBits, bt.MinBits), list); - this.DefineProxy(np); - bt.DefineProxy(np); - } else if (this.MinBits <= bt.MinBits) { - this.DefineProxy(bt); - } else { - bt.DefineProxy(this); - } - return true; - } else if (that is ConstrainedProxy) { - // only bitvector proxies can be unified with this BvTypeProxy - return false; - } else if (that is TypeProxy) { - // define: that.ProxyFor := this; - return that.Unify(this, unifiableVariables, result); - } - return false; - } - - private static int IncreaseBits(Type t, int to) { - Contract.Requires(t != null); - Contract.Requires(t.IsBv && 0 <= to && MinBitsFor(t) <= to); - Contract.Ensures(0 <= Contract.Result() && Contract.Result() <= to); - - if(t is TypeSynonymAnnotation) { - return IncreaseBits(((TypeSynonymAnnotation)t).ExpandedType, to); - } - - t = FollowProxy(t); - if (t is BvType) { - return to - t.BvBits; - } else { - BvTypeProxy p = (BvTypeProxy)t; - Contract.Assert(p.MinBits <= to); - if (p.MinBits < to) { - BvTypeProxy q = new BvTypeProxy(p, to); - p.DefineProxy(q); - } - return 0; // we were able to satisfy the request completely - } - } - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - if (this.ProxyFor == null) { - // check that the constraints are clean and do not contain any - // of the substituted variables (otherwise, we are in big trouble) - Contract.Assert(Contract.ForAll(constraints, c => - Contract.ForAll(subst.Keys, var => - !c.T0.FreeVariables.Contains(var) && !c.T1.FreeVariables.Contains(var)))); - } - return base.Substitute(subst); - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsBv { - get { - return true; - } - } - public override int BvBits { - get { - // This method is supposed to return the number of bits supplied, but unless the proxy has been resolved, - // we only have a lower bound on the number of bits supplied. But this method is not supposed to be - // called until type checking has finished, at which time the minBits is stable. - Type p = ProxyFor; - if (p != null) { - return p.BvBits; - } else { - return MinBits; - } - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitBvTypeProxy(this); - } - } - - // Proxy representing map types with a certain arity. Apart from the arity, - // a number of constraints on the index and value type of the map type may - // be known (such constraints result from applied select and store operations). - // Because map type can be polymorphic (in the most general case, each index or - // value type is described by a separate type parameter) any combination of - // constraints can be satisfied. - public class MapTypeProxy : ConstrainedProxy { - public readonly int Arity; - private readonly List/*!*/ constraints = new List(); - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(constraints != null); - } - - - // each constraint specifies that the given combination of argument/result - // types must be a possible instance of the formal map argument/result types - private struct Constraint { - public readonly List/*!*/ Arguments; - public readonly Type/*!*/ Result; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Arguments != null); - Contract.Invariant(Result != null); - } - - - public Constraint(List arguments, Type result) { - Contract.Requires(result != null); - Contract.Requires(arguments != null); - Arguments = arguments; - Result = result; - } - - public Constraint Clone(IDictionary/*!*/ varMap) { - Contract.Requires(cce.NonNullDictionaryAndValues(varMap)); - List/*!*/ args = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - args.Add(t.Clone(varMap)); - } - Type/*!*/ res = Result.Clone(varMap); - Contract.Assert(res != null); - return new Constraint(args, res); - } - - public bool Unify(MapType that, - List/*!*/ unifiableVariables, - IDictionary/*!*/ result) { - Contract.Requires(unifiableVariables != null); - Contract.Requires(cce.NonNullDictionaryAndValues(result)); - Contract.Requires(that != null); - Contract.Requires(Arguments.Count == that.Arguments.Count); - Dictionary/*!*/ subst = new Dictionary(); - foreach (TypeVariable/*!*/ tv in that.TypeParameters) { - Contract.Assert(tv != null); - TypeProxy proxy = new TypeProxy(Token.NoToken, tv.Name); - subst.Add(tv, proxy); - } - - bool good = true; - for (int i = 0; i < that.Arguments.Count; i++) { - Type t0 = that.Arguments[i].Substitute(subst); - Type t1 = this.Arguments[i]; - good &= t0.Unify(t1, unifiableVariables, result); - } - good &= that.Result.Substitute(subst).Unify(this.Result, unifiableVariables, result); - return good; - } - } - - public MapTypeProxy(IToken token, string name, int arity) - : base(token, name, "mapproxy") { - Contract.Requires(name != null); - Contract.Requires(token != null); - Contract.Requires(0 <= arity); - this.Arity = arity; - } - - private void AddConstraint(Constraint c) { - Contract.Requires(c.Arguments.Count == Arity); - - Type f = ProxyFor; - MapType mf = f as MapType; - if (mf != null) { - bool success = c.Unify(mf, new List(), new Dictionary()); - Contract.Assert(success); - return; - } - - MapTypeProxy mpf = f as MapTypeProxy; - if (mpf != null) { - mpf.AddConstraint(c); - return; - } - - Contract.Assert(f == null); // no other types should occur as specialisations of this proxy - - constraints.Add(c); - } - - public Type CheckArgumentTypes(List/*!*/ actualArgs, - out TypeParamInstantiation/*!*/ tpInstantiation, - IToken/*!*/ typeCheckingSubject, - string/*!*/ opName, - TypecheckingContext/*!*/ tc) { - Contract.Requires(actualArgs != null); - Contract.Requires(typeCheckingSubject != null); - Contract.Requires(opName != null); - Contract.Requires(tc != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - - - - Type f = ProxyFor; - MapType mf = f as MapType; - if (mf != null) - return mf.CheckArgumentTypes(actualArgs, out tpInstantiation, typeCheckingSubject, opName, tc); - - MapTypeProxy mpf = f as MapTypeProxy; - if (mpf != null) - return mpf.CheckArgumentTypes(actualArgs, out tpInstantiation, typeCheckingSubject, opName, tc); - - Contract.Assert(f == null); // no other types should occur as specialisations of this proxy - - // otherwise, we just record the constraints given by this usage of the map type - List/*!*/ arguments = new List(); - foreach (Expr/*!*/ e in actualArgs) { - Contract.Assert(e != null); - arguments.Add(e.Type); - } - Type/*!*/ result = new TypeProxy(tok, "result"); - Contract.Assert(result != null); - AddConstraint(new Constraint(arguments, result)); - - List/*!*/ argumentsResult = new List(); - foreach (Expr/*!*/ e in actualArgs) { - Contract.Assert(e != null); - argumentsResult.Add(e.Type); - } - argumentsResult.Add(result); - - tpInstantiation = new MapTypeProxyParamInstantiation(this, argumentsResult); - return result; - } - - //----------- Cloning ---------------------------------- - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - Type p = ProxyFor; - if (p != null) { - return p.Clone(varMap); - } else { - MapTypeProxy p2 = new MapTypeProxy(tok, Name, Arity); - foreach (Constraint c in constraints) - p2.AddConstraint(c.Clone(varMap)); - return p2; // the clone will have a name that ends with $mapproxy$mapproxy (hopefully) - } - } - - //----------- Linearisation ---------------------------------- - - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - //Contract.Requires(stream != null); - Type p = ProxyFor; - if (p != null) { - p.Emit(stream, contextBindingStrength); - } else { - stream.Write("["); - string/*!*/ sep = ""; - for (int i = 0; i < Arity; ++i) { - stream.Write(sep); - sep = ", "; - stream.Write("?"); - } - stream.Write("]?"); - } - } - - //----------- Unification of types ----------- - - public override bool Unify(Type/*!*/ that, - List/*!*/ unifiableVariables, - IDictionary/*!*/ result) { - //Contract.Requires(that != null); - //Contract.Requires(unifiableVariables != null); - //Contract.Requires(cce.NonNullElements(result)); - Type p = ProxyFor; - if (p != null) { - return p.Unify(that, unifiableVariables, result); - } - - // unify this with that, if possible - that = that.Expanded; - that = FollowProxy(that); - - if (this.ReallyOccursIn(that)) - return false; - - TypeVariable tv = that as TypeVariable; - - if (tv != null && unifiableVariables.Contains(tv)) - return that.Unify(this, unifiableVariables, result); - - if (object.ReferenceEquals(this, that)) { - return true; - } else if (that is MapType) { - MapType mapType = (MapType)that; - if (mapType.Arguments.Count == Arity) { - bool good = true; - foreach (Constraint c in constraints) - good &= c.Unify(mapType, unifiableVariables, result); - if (good) { - DefineProxy(mapType); - return true; - } - } - } else if (that is MapTypeProxy) { - MapTypeProxy mt = (MapTypeProxy)that; - if (mt.Arity == this.Arity) { - // we propagate the constraints of this proxy to the more specific one - foreach (Constraint c in constraints) - mt.AddConstraint(c); - DefineProxy(mt); - return true; - } - } else if (that is ConstrainedProxy) { - // only map-type proxies can be unified with this MapTypeProxy - return false; - } else if (that is TypeProxy) { - // define: that.ProxyFor := this; - return that.Unify(this, unifiableVariables, result); - } - return false; - } - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - if (this.ProxyFor == null) { - // check that the constraints are clean and do not contain any - // of the substituted variables (otherwise, we are in big trouble) - Contract.Assert(Contract.ForAll(constraints, c => - Contract.ForAll(subst.Keys, var => - Contract.ForAll(0, c.Arguments.Count, t => !c.Arguments[t].FreeVariables.Contains(var)) && - !c.Result.FreeVariables.Contains(var)))); - } - return base.Substitute(subst); - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsMap { - get { - return true; - } - } - public override MapType/*!*/ AsMap { - get { - Contract.Ensures(Contract.Result() != null); - - Type p = ProxyFor; - if (p != null) { - return p.AsMap; - } else { - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // what to do now? - } - } - } - public override int MapArity { - get { - return Arity; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitMapTypeProxy(this); - } - } - - //===================================================================== - - // Used to annotate types with type synoyms that were used in the - // original unresolved types. Such types should be considered as - // equivalent to ExpandedType, the annotations are only used to enable - // better pretty-printing - public class TypeSynonymAnnotation : Type { - public Type/*!*/ ExpandedType; - - public readonly List/*!*/ Arguments; - // is set during resolution and determines whether the right number of arguments is given - public readonly TypeSynonymDecl/*!*/ Decl; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(ExpandedType != null); - Contract.Invariant(Arguments != null); - Contract.Invariant(Decl != null); - } - - - public TypeSynonymAnnotation(IToken/*!*/ token, TypeSynonymDecl/*!*/ decl, List/*!*/ arguments) - : base(token) { - Contract.Requires(token != null); - Contract.Requires(decl != null); - Contract.Requires(arguments != null); - Contract.Requires(arguments.Count == decl.TypeParameters.Count); - this.Decl = decl; - this.Arguments = arguments; - - // build a substitution that can be applied to the definition of - // the type synonym - IDictionary/*!*/ subst = - new Dictionary(); - for (int i = 0; i < arguments.Count; ++i) - subst.Add(decl.TypeParameters[i], arguments[i]); - - ExpandedType = decl.Body.Substitute(subst); - } - - private TypeSynonymAnnotation(IToken/*!*/ token, TypeSynonymDecl/*!*/ decl, List/*!*/ arguments, - Type/*!*/ expandedType) - : base(token) { - Contract.Requires(token != null); - Contract.Requires(decl != null); - Contract.Requires(arguments != null); - Contract.Requires(expandedType != null); - - this.Decl = decl; - this.Arguments = arguments; - this.ExpandedType = expandedType; - } - - //----------- Cloning ---------------------------------- - // We implement our own clone-method, because bound type variables - // have to be created in the right way. It is /not/ ok to just clone - // everything recursively - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - List/*!*/ newArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - newArgs.Add(t.Clone(varMap)); - } - Type/*!*/ newExpandedType = ExpandedType.Clone(varMap); - Contract.Assert(newExpandedType != null); - return new TypeSynonymAnnotation(tok, Decl, newArgs, newExpandedType); - } - - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - List/*!*/ newArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - newArgs.Add(t.CloneUnresolved()); - } - return new TypeSynonymAnnotation(tok, Decl, newArgs); - } - - //----------- Equality ---------------------------------- - - [Pure] - public override bool Equals(Type/*!*/ that, - List/*!*/ thisBoundVariables, - List/*!*/ thatBoundVariables) { - //Contract.Requires(that != null); - //Contract.Requires(thisBoundVariables != null); - //Contract.Requires(thatBoundVariables != null); - return ExpandedType.Equals(that, thisBoundVariables, thatBoundVariables); - } - - // used to skip leading type annotations - internal override Type/*!*/ Expanded { - get { - Contract.Ensures(Contract.Result() != null); - - return ExpandedType.Expanded; - } - } - - //----------- Unification of types ----------- - - public override bool Unify(Type/*!*/ that, - List/*!*/ unifiableVariables, - IDictionary/*!*/ result) { - //Contract.Requires(that != null); - //Contract.Requires(unifiableVariables != null); - //Contract.Requires(cce.NonNullElements(result)); - return ExpandedType.Unify(that, unifiableVariables, result); - } - -#if OLD_UNIFICATION - public override void Unify(Type! that, - List! unifiableVariables, - List! thisBoundVariables, - List! thatBoundVariables, - IDictionary! result) { - ExpandedType.Unify(that, unifiableVariables, - thisBoundVariables, thatBoundVariables, result); - } -#endif - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - if (subst.Count == 0) - return this; - List newArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - newArgs.Add(t.Substitute(subst)); - } - Type/*!*/ newExpandedType = ExpandedType.Substitute(subst); - Contract.Assert(newExpandedType != null); - return new TypeSynonymAnnotation(tok, Decl, newArgs, newExpandedType); - } - - //----------- Hashcodes ---------------------------------- - - [Pure] - public override int GetHashCode(List boundVariables) { - //Contract.Requires(boundVariables != null); - return ExpandedType.GetHashCode(boundVariables); - } - - //----------- Linearisation ---------------------------------- - - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - //Contract.Requires(stream != null); - stream.SetToken(this); - CtorType.EmitCtorType(this.Decl.Name, Arguments, stream, contextBindingStrength); - } - - //----------- Resolution ---------------------------------- - - public override Type ResolveType(ResolutionContext rc) { - //Contract.Requires(rc != null); - Contract.Ensures(Contract.Result() != null); - List resolvedArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - resolvedArgs.Add(t.ResolveType(rc)); - } - return new TypeSynonymAnnotation(tok, Decl, resolvedArgs); - } - - public override List/*!*/ FreeVariables { - get { - Contract.Ensures(Contract.Result>() != null); - - return ExpandedType.FreeVariables; - } - } - - public override List/*!*/ FreeProxies { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return ExpandedType.FreeProxies; - } - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsBasic { - get { - return ExpandedType.IsBasic; - } - } - public override bool IsInt { - get { - return ExpandedType.IsInt; - } - } - public override bool IsReal - { - get - { - return ExpandedType.IsReal; - } - } - public override bool IsFloat - { - get - { - return ExpandedType.IsFloat; - } - } - public override bool IsBool { - get { - return ExpandedType.IsBool; - } - } - - public override bool IsVariable { - get { - return ExpandedType.IsVariable; - } - } - public override TypeVariable/*!*/ AsVariable { - get { - Contract.Ensures(Contract.Result() != null); - return ExpandedType.AsVariable; - } - } - public override bool IsCtor { - get { - return ExpandedType.IsCtor; - } - } - public override CtorType/*!*/ AsCtor { - get { - Contract.Ensures(Contract.Result() != null); - return ExpandedType.AsCtor; - } - } - public override bool IsMap { - get { - return ExpandedType.IsMap; - } - } - public override MapType/*!*/ AsMap { - get { - Contract.Ensures(Contract.Result() != null); - return ExpandedType.AsMap; - } - } - public override bool IsUnresolved { - get { - return ExpandedType.IsUnresolved; - } - } - public override UnresolvedTypeIdentifier/*!*/ AsUnresolved { - get { - Contract.Ensures(Contract.Result() != null); - - return ExpandedType.AsUnresolved; - } - } - - public override bool IsBv { - get { - return ExpandedType.IsBv; - } - } - public override int BvBits { - get { - return ExpandedType.BvBits; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitTypeSynonymAnnotation(this); - } - } - - //===================================================================== - - public class CtorType : Type { - public readonly List/*!*/ Arguments; - // is set during resolution and determines whether the right number of arguments is given - public readonly TypeCtorDecl/*!*/ Decl; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Arguments != null); - Contract.Invariant(Decl != null); - } - - - public CtorType(IToken/*!*/ token, TypeCtorDecl/*!*/ decl, List/*!*/ arguments) - : base(token) { - Contract.Requires(token != null); - Contract.Requires(decl != null); - Contract.Requires(arguments != null); - Contract.Requires(arguments.Count == decl.Arity); - this.Decl = decl; - this.Arguments = arguments; - } - - public bool IsDatatype() { - return QKeyValue.FindBoolAttribute(Decl.Attributes, "datatype"); - } - - //----------- Cloning ---------------------------------- - // We implement our own clone-method, because bound type variables - // have to be created in the right way. It is /not/ ok to just clone - // everything recursively - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - List/*!*/ newArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - newArgs.Add(t.Clone(varMap)); - } - return new CtorType(tok, Decl, newArgs); - } - - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - List/*!*/ newArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - newArgs.Add(t.CloneUnresolved()); - } - return new CtorType(tok, Decl, newArgs); - } - - //----------- Equality ---------------------------------- - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - Type thatType = that as Type; - if (thatType == null) - return false; - thatType = TypeProxy.FollowProxy(thatType.Expanded); - // shortcut - CtorType thatCtorType = thatType as CtorType; - if (thatCtorType == null || !this.Decl.Equals(thatCtorType.Decl)) - return false; - if (Arguments.Count == 0) - return true; - return base.Equals(thatType); - } - - [Pure] - public override bool Equals(Type/*!*/ that, - List/*!*/ thisBoundVariables, - List/*!*/ thatBoundVariables) { - that = TypeProxy.FollowProxy(that.Expanded); - CtorType thatCtorType = that as CtorType; - if (thatCtorType == null || !this.Decl.Equals(thatCtorType.Decl)) - return false; - for (int i = 0; i < Arguments.Count; ++i) { - if (!Arguments[i].Equals(thatCtorType.Arguments[i], - thisBoundVariables, thatBoundVariables)) - return false; - } - return true; - } - - //----------- Unification of types ----------- - - public override bool Unify(Type/*!*/ that, - List/*!*/ unifiableVariables, - IDictionary/*!*/ result) { - that = that.Expanded; - if (that is TypeProxy || that is TypeVariable) - return that.Unify(this, unifiableVariables, result); - - CtorType thatCtorType = that as CtorType; - if (thatCtorType == null || !thatCtorType.Decl.Equals(Decl)) { - return false; - } else { - bool good = true; - for (int i = 0; i < Arguments.Count; ++i) - good &= Arguments[i].Unify(thatCtorType.Arguments[i], unifiableVariables, result); - return good; - } - } - -#if OLD_UNIFICATION - public override void Unify(Type! that, - List! unifiableVariables, - List! thisBoundVariables, - List! thatBoundVariables, - IDictionary! result) { - that = that.Expanded; - if (that is TypeVariable) { - that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); - return; - } - - CtorType thatCtorType = that as CtorType; - if (thatCtorType == null || !thatCtorType.Decl.Equals(Decl)) - throw UNIFICATION_FAILED; - for (int i = 0; i < Arguments.Length; ++i) - Arguments[i].Unify(thatCtorType.Arguments[i], - unifiableVariables, - thisBoundVariables, thatBoundVariables, - result); - } -#endif - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - if (subst.Count == 0) - return this; - List newArgs = new List(); - lock (Arguments) - { - foreach (Type/*!*/ t in Arguments) - { - Contract.Assert(t != null); - newArgs.Add(t.Substitute(subst)); - } - } - return new CtorType(tok, Decl, newArgs); - } - - //----------- Hashcodes ---------------------------------- - - [Pure] - public override int GetHashCode(List boundVariables) { - //Contract.Requires(boundVariables != null); - int res = 1637643879 * Decl.GetHashCode(); - foreach (Type/*!*/ t in Arguments.ToArray()) { - Contract.Assert(t != null); - res = res * 3 + t.GetHashCode(boundVariables); - } - return res; - } - - //----------- Linearisation ---------------------------------- - - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - //Contract.Requires(stream != null); - stream.SetToken(this); - EmitCtorType(this.Decl.Name, Arguments, stream, contextBindingStrength); - } - - internal static void EmitCtorType(string name, List args, TokenTextWriter stream, int contextBindingStrength) { - Contract.Requires(stream != null); - Contract.Requires(args != null); - Contract.Requires(name != null); - int opBindingStrength = args.Count > 0 ? 0 : 2; - if (opBindingStrength < contextBindingStrength) - stream.Write("("); - - stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(name)); - int i = args.Count; - foreach (Type/*!*/ t in args) { - Contract.Assert(t != null); - stream.Write(" "); - // use a lower binding strength for the last argument - // to allow map-types without parentheses - t.Emit(stream, i == 1 ? 1 : 2); - i = i - 1; - } - - if (opBindingStrength < contextBindingStrength) - stream.Write(")"); - } - - //----------- Resolution ---------------------------------- - - public override Type ResolveType(ResolutionContext rc) { - //Contract.Requires(rc != null); - Contract.Ensures(Contract.Result() != null); - List resolvedArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - resolvedArgs.Add(t.ResolveType(rc)); - } - return new CtorType(tok, Decl, resolvedArgs); - } - - public override List/*!*/ FreeVariables { - get { - List/*!*/ res = new List(); - foreach (Type/*!*/ t in Arguments.ToArray()) { - Contract.Assert(t != null); - res.AppendWithoutDups(t.FreeVariables); - } - return res; - } - } - - public override List/*!*/ FreeProxies { - get { - List/*!*/ res = new List(); - foreach (Type/*!*/ t in Arguments.ToArray()) { - Contract.Assert(t != null); - AppendWithoutDups(res, t.FreeProxies); - } - return res; - } - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsCtor { - get { - return true; - } - } - public override CtorType/*!*/ AsCtor { - get { - return this; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitCtorType(this); - } - } - - //===================================================================== - - public class MapType : Type { - // an invariant is that each of the type parameters has to occur as - // free variable in at least one of the arguments - public readonly List/*!*/ TypeParameters; - public readonly List/*!*/ Arguments; - public Type/*!*/ Result; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(TypeParameters != null); - Contract.Invariant(Arguments != null); - Contract.Invariant(Result != null); - } - - - public MapType(IToken/*!*/ token, List/*!*/ typeParameters, List/*!*/ arguments, Type/*!*/ result) - : base(token) { - Contract.Requires(token != null); - Contract.Requires(typeParameters != null); - Contract.Requires(arguments != null); - Contract.Requires(result != null); - - this.TypeParameters = typeParameters; - this.Result = result; - this.Arguments = arguments; - } - - //----------- Cloning ---------------------------------- - // We implement our own clone-method, because bound type variables - // have to be created in the right way. It is /not/ ok to just clone - // everything recursively - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - IDictionary/*!*/ newVarMap = - new Dictionary(); - foreach (KeyValuePair p in varMap) { - Contract.Assert(cce.NonNullElements(p)); - if (!TypeParameters.Contains(p.Key)) - newVarMap.Add(p); - } - - List/*!*/ newTypeParams = new List(); - foreach (TypeVariable/*!*/ var in TypeParameters) { - Contract.Assert(var != null); - TypeVariable/*!*/ newVar = new TypeVariable(var.tok, var.Name); - Contract.Assert(newVar != null); - newVarMap.Add(var, newVar); - newTypeParams.Add(newVar); - } - - List/*!*/ newArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - newArgs.Add(t.Clone(newVarMap)); - } - Type/*!*/ newResult = Result.Clone(newVarMap); - Contract.Assert(newResult != null); - - return new MapType(this.tok, newTypeParams, newArgs, newResult); - } - - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - List/*!*/ newTypeParams = new List(); - foreach (TypeVariable/*!*/ var in TypeParameters) { - Contract.Assert(var != null); - TypeVariable/*!*/ newVar = new TypeVariable(var.tok, var.Name); - Contract.Assert(newVar != null); - newTypeParams.Add(newVar); - } - - List/*!*/ newArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - newArgs.Add(t.CloneUnresolved()); - } - Type/*!*/ newResult = Result.CloneUnresolved(); - Contract.Assert(newResult != null); - - return new MapType(this.tok, newTypeParams, newArgs, newResult); - } - - //----------- Equality ---------------------------------- - - [Pure] - public override bool Equals(Type/*!*/ that, - List/*!*/ thisBoundVariables, - List/*!*/ thatBoundVariables) - { - that = TypeProxy.FollowProxy(that.Expanded); - MapType thatMapType = that as MapType; - if (thatMapType == null || - this.TypeParameters.Count != thatMapType.TypeParameters.Count || - this.Arguments.Count != thatMapType.Arguments.Count) - return false; - - thisBoundVariables = thisBoundVariables.ToList(); - foreach (TypeVariable/*!*/ var in this.TypeParameters) - { - Contract.Assert(var != null); - thisBoundVariables.Add(var); - } - thatBoundVariables = thatBoundVariables.ToList(); - foreach (TypeVariable/*!*/ var in thatMapType.TypeParameters) - { - Contract.Assert(var != null); - thatBoundVariables.Add(var); - } - - for (int i = 0; i < Arguments.Count; ++i) - { - if (!Arguments[i].Equals(thatMapType.Arguments[i], - thisBoundVariables, thatBoundVariables)) - return false; - } - - return this.Result.Equals(thatMapType.Result, - thisBoundVariables, thatBoundVariables); - } - - //----------- Unification of types ----------- - - public override bool Unify(Type/*!*/ that, - List/*!*/ unifiableVariables, - IDictionary/*!*/ result) { - that = that.Expanded; - if (that is TypeProxy || that is TypeVariable) - return that.Unify(this, unifiableVariables, result); - - MapType thatMapType = that as MapType; - if (thatMapType == null || - this.TypeParameters.Count != thatMapType.TypeParameters.Count || - this.Arguments.Count != thatMapType.Arguments.Count) - return false; - - // treat the bound variables of the two map types as equal... - Dictionary/*!*/ subst0 = - new Dictionary(); - Dictionary/*!*/ subst1 = - new Dictionary(); - List freshies = new List(); - for (int i = 0; i < this.TypeParameters.Count; i++) { - TypeVariable tp0 = this.TypeParameters[i]; - TypeVariable tp1 = thatMapType.TypeParameters[i]; - TypeVariable freshVar = new TypeVariable(tp0.tok, tp0.Name); - freshies.Add(freshVar); - subst0.Add(tp0, freshVar); - subst1.Add(tp1, freshVar); - } - // ... and then unify the domain and range types - bool good = true; - for (int i = 0; i < this.Arguments.Count; i++) { - Type t0 = this.Arguments[i].Substitute(subst0); - Type t1 = thatMapType.Arguments[i].Substitute(subst1); - good &= t0.Unify(t1, unifiableVariables, result); - } - Type r0 = this.Result.Substitute(subst0); - Type r1 = thatMapType.Result.Substitute(subst1); - good &= r0.Unify(r1, unifiableVariables, result); - - // Finally, check that none of the bound variables has escaped - if (good && freshies.Count != 0) { - // This is done by looking for occurrences of the fresh variables in the - // non-substituted types ... - List freeVars = this.FreeVariables; - foreach (TypeVariable fr in freshies) - if (freeVars.Contains(fr)) { - return false; - } // fresh variable escaped - freeVars = thatMapType.FreeVariables; - foreach (TypeVariable fr in freshies) - if (freeVars.Contains(fr)) { - return false; - } // fresh variable escaped - - // ... and in the resulting unifier of type variables - foreach (KeyValuePair pair in result) { - Contract.Assert(cce.NonNullElements(pair)); - freeVars = pair.Value.FreeVariables; - foreach (TypeVariable fr in freshies) - if (freeVars.Contains(fr)) { - return false; - } // fresh variable escaped - } - } - - return good; - } - -#if OLD_UNIFICATION - public override void Unify(Type! that, - List! unifiableVariables, - List! thisBoundVariables, - List! thatBoundVariables, - IDictionary! result) { - that = that.Expanded; - if (that is TypeVariable) { - that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); - return; - } - - MapType thatMapType = that as MapType; - if (thatMapType == null || - this.TypeParameters.Length != thatMapType.TypeParameters.Length || - this.Arguments.Length != thatMapType.Arguments.Length) - throw UNIFICATION_FAILED; - - // ensure that no collisions occur - if (this.collisionsPossible(result)) { - ((MapType)this.Clone()) - .Unify(that, unifiableVariables, - thisBoundVariables, thatBoundVariables, result); - return; - } - if (thatMapType.collisionsPossible(result)) - thatMapType = (MapType)that.Clone(); - - foreach(TypeVariable/*!*/ var in this.TypeParameters){ -Contract.Assert(var != null); - thisBoundVariables.Add(var);} - foreach(TypeVariable/*!*/ var in thatMapType.TypeParameters){ -Contract.Assert(var != null); - thatBoundVariables.Add(var);} - - try { - - for (int i = 0; i < Arguments.Length; ++i) - Arguments[i].Unify(thatMapType.Arguments[i], - unifiableVariables, - thisBoundVariables, thatBoundVariables, - result); - Result.Unify(thatMapType.Result, - unifiableVariables, - thisBoundVariables, thatBoundVariables, - result); - - } finally { - // make sure that the bound variables are removed again - for (int i = 0; i < this.TypeParameters.Length; ++i) { - thisBoundVariables.Remove(); - thatBoundVariables.Remove(); - } - } - } -#endif - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - [Pure] - private bool collisionsPossible(IDictionary/*!*/ subst) { - Contract.Requires(cce.NonNullDictionaryAndValues(subst)); - // PR: could be written more efficiently - return TypeParameters.Any(param => subst.ContainsKey(param) || subst.Values.Any(val => val.FreeVariables.Contains(param))); - } - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - if (subst.Count == 0) - return this; - - // there are two cases in which we have to be careful: - // * a variable to be substituted is shadowed by a variable binder - // * a substituted term contains variables that are bound in the - // type (variable capture) - // - // in both cases, we first clone the type to ensure that bound - // variables are fresh - - if (collisionsPossible(subst)) { - MapType/*!*/ newType = (MapType)this.Clone(); - Contract.Assert(newType != null); - Contract.Assert(newType.Equals(this) && !newType.collisionsPossible(subst)); - return newType.Substitute(subst); - } - - List newArgs = new List(); - lock (Arguments) - { - foreach (Type/*!*/ t in Arguments) - { - Contract.Assert(t != null); - newArgs.Add(t.Substitute(subst)); - } - } - Type/*!*/ newResult = Result.Substitute(subst); - Contract.Assert(newResult != null); - - return new MapType(tok, TypeParameters, newArgs, newResult); - } - - //----------- Hashcodes ---------------------------------- - - [Pure] - public override int GetHashCode(List boundVariables) { - //Contract.Requires(boundVariables != null); - int res = 7643761 * TypeParameters.Count + 65121 * Arguments.Count; - - boundVariables = boundVariables.ToList(); - foreach (TypeVariable/*!*/ var in this.TypeParameters) { - Contract.Assert(var != null); - boundVariables.Add(var); - } - - foreach (Type/*!*/ t in Arguments.ToArray()) { - Contract.Assert(t != null); - res = res * 5 + t.GetHashCode(boundVariables); - } - res = res * 7 + Result.GetHashCode(boundVariables); - - return res; - } - - //----------- Linearisation ---------------------------------- - - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - //Contract.Requires(stream != null); - stream.SetToken(this); - - const int opBindingStrength = 1; - if (opBindingStrength < contextBindingStrength) - stream.Write("("); - - EmitOptionalTypeParams(stream, TypeParameters); - - stream.Write("["); - Arguments.Emit(stream, ","); // default binding strength of 0 is ok - stream.Write("]"); - Result.Emit(stream); // default binding strength of 0 is ok - - if (opBindingStrength < contextBindingStrength) - stream.Write(")"); - } - - //----------- Resolution ---------------------------------- - - public override Type ResolveType(ResolutionContext rc) { - //Contract.Requires(rc != null); - Contract.Ensures(Contract.Result() != null); - int previousState = rc.TypeBinderState; - try { - foreach (TypeVariable/*!*/ v in TypeParameters) { - Contract.Assert(v != null); - rc.AddTypeBinder(v); - } - - List resolvedArgs = new List(); - foreach (Type/*!*/ ty in Arguments) { - Contract.Assert(ty != null); - resolvedArgs.Add(ty.ResolveType(rc)); - } - - Type resolvedResult = Result.ResolveType(rc); - - CheckBoundVariableOccurrences(TypeParameters, - resolvedArgs, new List { resolvedResult }, - this.tok, "map arguments", - rc); - - // sort the type parameters so that they are bound in the order of occurrence - List/*!*/ sortedTypeParams = SortTypeParams(TypeParameters, resolvedArgs, resolvedResult); - Contract.Assert(sortedTypeParams != null); - return new MapType(tok, sortedTypeParams, resolvedArgs, resolvedResult); - } finally { - rc.TypeBinderState = previousState; - } - } - - public override List/*!*/ FreeVariables { - get { - List/*!*/ res = FreeVariablesIn(Arguments.ToList()); - Contract.Assert(res != null); - res.AppendWithoutDups(Result.FreeVariables); - foreach (TypeVariable/*!*/ v in TypeParameters.ToArray()) { - Contract.Assert(v != null); - res.Remove(v); - } - return res; - } - } - - public override List/*!*/ FreeProxies { - get { - List/*!*/ res = new List(); - foreach (Type/*!*/ t in Arguments.ToArray()) { - Contract.Assert(t != null); - AppendWithoutDups(res, t.FreeProxies); - } - AppendWithoutDups(res, Result.FreeProxies); - return res; - } - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsMap { - get { - return true; - } - } - public override MapType/*!*/ AsMap { - get { - return this; - } - } - public override int MapArity { - get { - return Arguments.Count; - } - } - - //------------ Match formal argument types of the map - //------------ on concrete types, substitute the result into the - //------------ result type. Null is returned if so many type checking - //------------ errors occur that the situation is hopeless - - public Type CheckArgumentTypes(List/*!*/ actualArgs, - out TypeParamInstantiation/*!*/ tpInstantiation, - IToken/*!*/ typeCheckingSubject, - string/*!*/ opName, - TypecheckingContext/*!*/ tc) { - Contract.Requires(actualArgs != null); - Contract.Requires(typeCheckingSubject != null); - - Contract.Requires(opName != null); - Contract.Requires(tc != null); -Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - List/*!*/ actualTypeParams; - List actualResult = - Type.CheckArgumentTypes(TypeParameters, out actualTypeParams, Arguments, actualArgs, - new List { Result }, null, typeCheckingSubject, opName, tc); - if (actualResult == null) { - tpInstantiation = SimpleTypeParamInstantiation.EMPTY; - return null; - } else { - Contract.Assert(actualResult.Count == 1); - tpInstantiation = SimpleTypeParamInstantiation.From(TypeParameters, actualTypeParams); - return actualResult[0]; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitMapType(this); - } - } - - //--------------------------------------------------------------------- - - public enum SimpleType { - Int, - Real, - Bool - }; - - - //===================================================================== - - // Interface for representing the instantiations of type parameters of - // polymorphic functions or maps. We introduce an own interface for this - // instead of using a simple list or dictionary, because in some cases - // (due to the type proxies for map types) the actual number and instantiation - // of type parameters can only be determined very late. - [ContractClass(typeof(TypeParamInstantiationContracts))] - public interface TypeParamInstantiation { - // return what formal type parameters there are - List/*!*/ FormalTypeParams { - get; - } - // given a formal type parameter, return the actual instantiation - Type/*!*/ this[TypeVariable/*!*/ var] { - get; - } - } - [ContractClassFor(typeof(TypeParamInstantiation))] - public abstract class TypeParamInstantiationContracts : TypeParamInstantiation { - #region TypeParamInstantiation Members - - public List FormalTypeParams { - - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - throw new NotImplementedException(); - } - } - - public Type this[TypeVariable var] { - get { - Contract.Requires(var != null); - Contract.Ensures(Contract.Result() != null); - - throw new NotImplementedException(); - } - } - - #endregion - } - - - public class SimpleTypeParamInstantiation : TypeParamInstantiation { - private readonly List/*!*/ TypeParams; - [ContractInvariantMethod] - void TypeParamsInvariantMethod() { - Contract.Invariant(cce.NonNullElements(TypeParams)); - } - private readonly IDictionary/*!*/ Instantiations; - [ContractInvariantMethod] - void InstantiationsInvariantMethod() { - Contract.Invariant(cce.NonNullDictionaryAndValues(Instantiations)); - } - - public SimpleTypeParamInstantiation(List/*!*/ typeParams, - IDictionary/*!*/ instantiations) { - Contract.Requires(cce.NonNullElements(typeParams)); - Contract.Requires(cce.NonNullDictionaryAndValues(instantiations)); - this.TypeParams = typeParams; - this.Instantiations = instantiations; - } - - public static TypeParamInstantiation/*!*/ From(List typeParams, List/*!*/ actualTypeParams) { - Contract.Requires(cce.NonNullElements(actualTypeParams)); - Contract.Requires(typeParams != null); - Contract.Requires(typeParams.Count == actualTypeParams.Count); - Contract.Ensures(Contract.Result() != null); - - if (typeParams.Count == 0) - return EMPTY; - - List/*!*/ typeParamList = new List(); - IDictionary/*!*/ dict = new Dictionary(); - for (int i = 0; i < typeParams.Count; ++i) { - typeParamList.Add(typeParams[i]); - dict.Add(typeParams[i], actualTypeParams[i]); - } - return new SimpleTypeParamInstantiation(typeParamList, dict); - } - - public static readonly TypeParamInstantiation EMPTY = - new SimpleTypeParamInstantiation(new List(), - new Dictionary()); - - // return what formal type parameters there are - public List/*!*/ FormalTypeParams { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return TypeParams; - } - } - // given a formal type parameter, return the actual instantiation - public Type/*!*/ this[TypeVariable/*!*/ var] { - get { - return Instantiations[var]; - } - } - } - - // Implementation of TypeParamInstantiation that refers to the current - // value of a MapTypeProxy. This means that the values return by the - // methods of this implementation can change in case the MapTypeProxy - // receives further unifications. - class MapTypeProxyParamInstantiation : TypeParamInstantiation { - private readonly MapTypeProxy/*!*/ Proxy; - - // the argument and result type of this particular usage of the map - // type. these are necessary to derive the values of the type parameters - private readonly List/*!*/ ArgumentsResult; - - // field that is initialised once all necessary information is available - // (the MapTypeProxy is instantiated to an actual type) and the instantiation - // of a type parameter is queried - private IDictionary Instantiations = null; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Proxy != null); - Contract.Invariant(ArgumentsResult != null); - Contract.Invariant(Instantiations == null || cce.NonNullDictionaryAndValues(Instantiations)); - } - - - public MapTypeProxyParamInstantiation(MapTypeProxy/*!*/ proxy, - List/*!*/ argumentsResult) { - Contract.Requires(proxy != null); - Contract.Requires(argumentsResult != null); - this.Proxy = proxy; - this.ArgumentsResult = argumentsResult; - } - - // return what formal type parameters there are - public List/*!*/ FormalTypeParams { - get { - MapType realType = Proxy.ProxyFor as MapType; - if (realType == null) - // no instantiation of the map type is known, which means - // that the map type is assumed to be monomorphic - return new List(); - else - return realType.TypeParameters.ToList(); - } - } - - // given a formal type parameter, return the actual instantiation - public Type/*!*/ this[TypeVariable/*!*/ var] { - get { - // then there has to be an instantiation that is a polymorphic map type - if (Instantiations == null) { - MapType realType = Proxy.ProxyFor as MapType; - Contract.Assert(realType != null); - List/*!*/ formalArgs = new List(); - foreach (Type/*!*/ t in realType.Arguments) { - Contract.Assert(t != null); - formalArgs.Add(t); - } - formalArgs.Add(realType.Result); - Instantiations = - Type.InferTypeParameters(realType.TypeParameters, formalArgs, ArgumentsResult); - } - return Instantiations[var]; - } - } - } +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- +// BoogiePL - Absy.cs +//--------------------------------------------------------------------------------------------- + +namespace Microsoft.Boogie { + using System; + using System.Collections; + using System.Diagnostics; + using System.Linq; + using System.Collections.Generic; + using Microsoft.Boogie.AbstractInterpretation; + using System.Diagnostics.Contracts; + + //===================================================================== + //--------------------------------------------------------------------- + // Types + [ContractClass(typeof(TypeContracts))] + public abstract class Type : Absy { + public Type(IToken/*!*/ token) + : base(token) { + Contract.Requires(token != null); + } + + //----------- Cloning ---------------------------------- + // We implement our own clone-method, because bound type variables + // have to be created in the right way. It is /not/ ok to just clone + // everything recursively. Applying Clone to a type will return + // a type in which all bound variables have been replaced with new + // variables, whereas free variables have not changed + + public override Absy Clone() { + Contract.Ensures(Contract.Result() != null); + return this.Clone(new Dictionary()); + } + + public abstract Type/*!*/ Clone(IDictionary/*!*/ varMap); + + /// + /// Clones the type, but only syntactically. Anything resolved in the source + /// type is left unresolved (that is, with just the name) in the destination type. + /// + public abstract Type/*!*/ CloneUnresolved(); + + //----------- Linearisation ---------------------------------- + + public void Emit(TokenTextWriter stream) { + Contract.Requires(stream != null); + this.Emit(stream, 0); + } + + public abstract void Emit(TokenTextWriter/*!*/ stream, int contextBindingStrength); + + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result() != null); + System.IO.StringWriter buffer = new System.IO.StringWriter(); + using (TokenTextWriter stream = new TokenTextWriter("", buffer, /*setTokens=*/false, /*pretty=*/ false)) { + this.Emit(stream); + } + return buffer.ToString(); + } + + //----------- Equality ---------------------------------- + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (ReferenceEquals(this, that)) + return true; + Type thatType = that as Type; + return thatType != null && this.Equals(thatType, + new List(), + new List()); + } + + [Pure] + public abstract bool Equals(Type/*!*/ that, + List/*!*/ thisBoundVariables, + List/*!*/ thatBoundVariables); + + // used to skip leading type annotations (subexpressions of the + // resulting type might still contain annotations) + internal virtual Type/*!*/ Expanded { + get { + Contract.Ensures(Contract.Result() != null); + + return this; + } + } + + //----------- Unification of types ----------- + + /// + /// Add a constraint that this==that, if possible, and return true. + /// If not possible, return false (which may have added some partial constraints). + /// No error is printed. + /// + public bool Unify(Type that) { + Contract.Requires(that != null); + return Unify(that, new List(), new Dictionary()); + } + + public abstract bool Unify(Type/*!*/ that, + List/*!*/ unifiableVariables, + // an idempotent substitution that describes the + // unification result up to a certain point + IDictionary/*!*/ unifier); + + + [Pure] + public static bool IsIdempotent(IDictionary/*!*/ unifier) { + Contract.Requires(cce.NonNullDictionaryAndValues(unifier)); + return unifier.Values.All(val => val.FreeVariables.All(var => !unifier.ContainsKey(var))); + } + + +#if OLD_UNIFICATION + // Compute a most general unification of two types. null is returned if + // no such unifier exists. The unifier is not allowed to subtitute any + // type variables other than the ones in "unifiableVariables" + public IDictionary Unify(Type! that, + List! unifiableVariables) { + Dictionary! result = new Dictionary (); + try { + this.Unify(that, unifiableVariables, + new List (), new List (), result); + } catch (UnificationFailedException) { + return null; + } + return result; + } + + // Compute an idempotent most general unifier and add the result to the argument + // unifier. The result is true iff the unification succeeded + public bool Unify(Type! that, + List! unifiableVariables, + // given mappings that need to be taken into account + // the old unifier has to be idempotent as well + IDictionary! unifier) + { + Contract.Requires(Contract.ForAll(unifier.Keys , key=> unifiableVariables.Has(key))); + Contract.Requires(IsIdempotent(unifier)); + try { + this.Unify(that, unifiableVariables, + new List (), new List (), unifier); + } catch (UnificationFailedException) { + return false; + } + return true; + } + + public abstract void Unify(Type! that, + List! unifiableVariables, + List! thisBoundVariables, + List! thatBoundVariables, + // an idempotent substitution that describes the + // unification result up to a certain point + IDictionary! result); +#endif + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public abstract Type/*!*/ Substitute(IDictionary/*!*/ subst); + + //----------- Hashcodes ---------------------------------- + + // Hack to be able to access the hashcode of superclasses further up + // (from the subclasses of this class) + [Pure] + protected int GetBaseHashCode() { + return base.GetHashCode(); + } + + [Pure] + public override int GetHashCode() { + return this.GetHashCode(new List()); + } + + [Pure] + public abstract int GetHashCode(List/*!*/ boundVariables); + + //----------- Resolution ---------------------------------- + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + System.Diagnostics.Debug.Fail("Type.Resolve should never be called." + + " Use Type.ResolveType instead"); + } + + public abstract Type/*!*/ ResolveType(ResolutionContext/*!*/ rc); + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + System.Diagnostics.Debug.Fail("Type.Typecheck should never be called"); + } + + // determine the free variables in a type, in the order in which the variables occur + public abstract List/*!*/ FreeVariables { + get; + } + + // determine the free type proxies in a type, in the order in which they occur + public abstract List/*!*/ FreeProxies { + get; + } + + protected static void AppendWithoutDups(List a, List b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + foreach (A x in b) + if (!a.Contains(x)) + a.Add(x); + } + + public bool IsClosed { + get { + return FreeVariables.Count == 0; + } + } + + //----------- Getters/Issers ---------------------------------- + + // the following methods should be used instead of simple casts or the + // C# "is" operator, because they handle type synonym annotations and + // type proxies correctly + + public virtual bool IsBasic { + get { + return false; + } + } + public virtual bool IsInt { + get { + return false; + } + } + public virtual bool IsReal { + get { + return false; + } + } + public virtual bool IsFloat { + get { + return false; + } + } + public virtual bool IsBool { + get { + return false; + } + } + + public virtual bool IsVariable { + get { + return false; + } + } + public virtual TypeVariable/*!*/ AsVariable { + get { + Contract.Ensures(Contract.Result() != null); + + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // Type.AsVariable should never be called + } + } + public virtual bool IsCtor { + get { + return false; + } + } + public virtual CtorType/*!*/ AsCtor { + get { + Contract.Ensures(Contract.Result() != null); + + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // Type.AsCtor should never be called + } + } + public virtual bool IsMap { + get { + return false; + } + } + public virtual MapType/*!*/ AsMap { + get { + Contract.Ensures(Contract.Result() != null); + + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // Type.AsMap should never be called + } + } + public virtual int MapArity { + get { + + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // Type.MapArity should never be called + } + } + public virtual bool IsUnresolved { + get { + return false; + } + } + public virtual UnresolvedTypeIdentifier/*!*/ AsUnresolved { + get { + Contract.Ensures(Contract.Result() != null); + + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // Type.AsUnresolved should never be called + } + } + + public virtual bool isFloat { + get { + return false; + } + } + public virtual int FloatExponent + { + get + { + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // Type.FloatExponent should never be called + } + } + public virtual int FloatMantissa { + get { + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // Type.FloatMantissa should never be called + } + } + public virtual bool IsBv { + get { + return false; + } + } + public virtual int BvBits { + get { + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // Type.BvBits should never be called + } + } + + public static readonly Type/*!*/ Int = new BasicType(SimpleType.Int); + public static readonly Type/*!*/ Real = new BasicType(SimpleType.Real); + public static readonly Type/*!*/ Bool = new BasicType(SimpleType.Bool); + private static BvType[] bvtypeCache; + + static public BvType GetBvType(int sz) { + Contract.Requires(0 <= sz); + Contract.Ensures(Contract.Result() != null); + + if (bvtypeCache == null) { + bvtypeCache = new BvType[128]; + } + if (sz < bvtypeCache.Length) { + BvType t = bvtypeCache[sz]; + if (t == null) { + t = new BvType(sz); + bvtypeCache[sz] = t; + } + return t; + } else { + return new BvType(sz); + } + } + + static public FloatType GetFloatType(int exp, int man) { + Contract.Requires(0 <= exp); + Contract.Requires(0 <= man); + Contract.Ensures(Contract.Result() != null); + + return new FloatType(exp, man); + } + + //------------ Match formal argument types on actual argument types + //------------ and return the resulting substitution of type variables + +#if OLD_UNIFICATION + public static IDictionary! + MatchArgumentTypes(List! typeParams, + List! formalArgs, + List! actualArgs, + List formalOuts, + List actualOuts, + string! opName, + TypecheckingContext! tc) + { + Contract.Requires(formalArgs.Length == actualArgs.Length); + Contract.Requires(formalOuts == null <==> actualOuts == null); + Contract.Requires(formalOuts != null ==> formalOuts.Length == actualOuts.Length); + List! boundVarSeq0 = new List (); + List! boundVarSeq1 = new List (); + Dictionary! subst = new Dictionary(); + + for (int i = 0; i < formalArgs.Length; ++i) { + try { + Type! actualType = cce.NonNull((!)actualArgs[i]).Type; + // if the type variables to be matched occur in the actual + // argument types, something has gone very wrong + Contract.Assert(forall{TypeVariable! var in typeParams); + !actualType.FreeVariables.Has(var)}; + formalArgs[i].Unify(actualType, + typeParams, + boundVarSeq0, boundVarSeq1, + subst); + } catch (UnificationFailedException) { + tc.Error(actualArgs[i], + "invalid type for argument {0} in {1}: {2} (expected: {3})", + i, opName, actualArgs[i].Type, + // we insert the type parameters that have already been + // chosen to get a more precise error message + formalArgs[i].Substitute(subst)); + // the bound variable sequences should be empty ... + // so that we can continue with the unification + Contract.Assert(boundVarSeq0.Length == 0 && boundVarSeq1.Length == 0); + } + } + + if (formalOuts != null) { + for (int i = 0; i < formalOuts.Length; ++i) { + try { + Type! actualType = cce.NonNull((!)actualOuts[i]).Type; + // if the type variables to be matched occur in the actual + // argument types, something has gone very wrong + Contract.Assert(forall{TypeVariable! var in typeParams); + !actualType.FreeVariables.Has(var)}; + formalOuts[i].Unify(actualType, + typeParams, + boundVarSeq0, boundVarSeq1, + subst); + } catch (UnificationFailedException) { + tc.Error(actualOuts[i], + "invalid type for result {0} in {1}: {2} (expected: {3})", + i, opName, actualOuts[i].Type, + // we insert the type parameters that have already been + // chosen to get a more precise error message + formalOuts[i].Substitute(subst)); + // the bound variable sequences should be empty ... + // so that we can continue with the unification + Contract.Assert(boundVarSeq0.Length == 0 && boundVarSeq1.Length == 0); + } + } + } + + // we only allow type parameters to be substituted + Contract.Assert(Contract.ForAll(subst.Keys , var=> typeParams.Has(var))); + + return subst; + } +#else + public static IDictionary/*!*/ + MatchArgumentTypes(List/*!*/ typeParams, + List/*!*/ formalArgs, + IList/*!*/ actualArgs, + List formalOuts, + List actualOuts, + string/*!*/ opName, + TypecheckingContext/*!*/ tc) { + Contract.Requires(typeParams != null); + Contract.Requires(formalArgs != null); + Contract.Requires(actualArgs != null); + Contract.Requires(opName != null); + Contract.Requires(tc != null); + Contract.Requires(formalArgs.Count == actualArgs.Count); + Contract.Requires((formalOuts == null) == (actualOuts == null)); + Contract.Requires(formalOuts == null || formalOuts.Count == cce.NonNull(actualOuts).Count); + Contract.Requires(tc == null || opName != null);//Redundant + Contract.Ensures(cce.NonNullDictionaryAndValues(Contract.Result>())); + + // requires "actualArgs" and "actualOuts" to have been type checked + + Dictionary subst = new Dictionary(); + foreach (TypeVariable/*!*/ tv in typeParams) { + Contract.Assert(tv != null); + TypeProxy proxy = new TypeProxy(Token.NoToken, tv.Name); + subst.Add(tv, proxy); + } + + for (int i = 0; i < formalArgs.Count; i++) { + Type formal = formalArgs[i].Substitute(subst); + Type actual = cce.NonNull(cce.NonNull(actualArgs[i]).Type); + // if the type variables to be matched occur in the actual + // argument types, something has gone very wrong + Contract.Assert(Contract.ForAll(0, typeParams.Count, index => !actual.FreeVariables.Contains(typeParams[index]))); + + if (!formal.Unify(actual)) { + Contract.Assume(tc != null); // caller expected no errors + Contract.Assert(opName != null); // follows from precondition + tc.Error(cce.NonNull(actualArgs[i]), + "invalid type for argument {0} in {1}: {2} (expected: {3})", + i, opName, actual, formalArgs[i]); + } + } + + if (formalOuts != null) { + for (int i = 0; i < formalOuts.Count; ++i) { + Type formal = formalOuts[i].Substitute(subst); + Type actual = cce.NonNull(cce.NonNull(actualOuts)[i].Type); + // if the type variables to be matched occur in the actual + // argument types, something has gone very wrong + Contract.Assert(Contract.ForAll(0, typeParams.Count, var => !actual.FreeVariables.Contains(typeParams[var]))); + + if (!formal.Unify(actual)) { + Contract.Assume(tc != null); // caller expected no errors + Contract.Assert(opName != null); // follows from precondition + tc.Error(actualOuts[i], + "invalid type for out-parameter {0} in {1}: {2} (expected: {3})", + i, opName, actual, formal); + } + } + } + + return subst; + } +#endif + + //------------ Match formal argument types of a function or map + //------------ on concrete types, substitute the result into the + //------------ result type. Null is returned for type errors + + public static List CheckArgumentTypes(List/*!*/ typeParams, + out List/*!*/ actualTypeParams, + List/*!*/ formalIns, + IList/*!*/ actualIns, + List/*!*/ formalOuts, + List actualOuts, + IToken/*!*/ typeCheckingSubject, + string/*!*/ opName, + TypecheckingContext/*!*/ tc) + // requires "actualIns" and "actualOuts" to have been type checked + { + Contract.Requires(typeParams != null); + + Contract.Requires(formalIns != null); + Contract.Requires(formalOuts != null); + Contract.Requires(actualIns != null); + Contract.Requires(typeCheckingSubject != null); + Contract.Requires(opName != null);Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out actualTypeParams))); + actualTypeParams = new List(); + + if (formalIns.Count != actualIns.Count) { + tc.Error(typeCheckingSubject, "wrong number of arguments in {0}: {1}", + opName, actualIns.Count); + // if there are no type parameters, we can still return the result + // type and hope that the type checking proceeds + return typeParams.Count == 0 ? formalOuts : null; + } else if (actualOuts != null && formalOuts.Count != actualOuts.Count) { + tc.Error(typeCheckingSubject, "wrong number of result variables in {0}: {1}", + opName, actualOuts.Count); + // if there are no type parameters, we can still return the result + // type and hope that the type checking proceeds + actualTypeParams = new List(); + return typeParams.Count == 0 ? formalOuts : null; + } + + int previousErrorCount = tc.ErrorCount; + IDictionary subst = + MatchArgumentTypes(typeParams, formalIns, actualIns, + actualOuts != null ? formalOuts : null, actualOuts, opName, tc); + Contract.Assert(cce.NonNullDictionaryAndValues(subst)); + foreach (TypeVariable/*!*/ var in typeParams) { + Contract.Assert(var != null); + actualTypeParams.Add(subst[var]); + } + + List/*!*/ actualResults = new List(); + foreach (Type/*!*/ t in formalOuts) { + Contract.Assert(t != null); + actualResults.Add(t.Substitute(subst)); + } + List resultFreeVars = FreeVariablesIn(actualResults); + if (previousErrorCount != tc.ErrorCount) { + // errors occured when matching the formal arguments + // in case we have been able to substitute all type parameters, + // we can still return the result type and hope that the + // type checking proceeds in a meaningful manner + if (typeParams.All(param => !resultFreeVars.Contains(param))) + return actualResults; + else + // otherwise there is no point in returning the result type, + // type checking would only get confused even further + return null; + } + + Contract.Assert(Contract.ForAll(0, typeParams.Count, index => !resultFreeVars.Contains(typeParams[index]))); + return actualResults; + } + + /////////////////////////////////////////////////////////////////////////// + + // about the same as Type.CheckArgumentTypes, but without + // detailed error reports + public static Type/*!*/ InferValueType(List/*!*/ typeParams, + List/*!*/ formalArgs, + Type/*!*/ formalResult, + List/*!*/ actualArgs) { + Contract.Requires(typeParams != null); + Contract.Requires(formalArgs != null); + Contract.Requires(formalResult != null); + Contract.Requires(actualArgs != null); + Contract.Ensures(Contract.Result() != null); + + IDictionary/*!*/ subst = + InferTypeParameters(typeParams, formalArgs, actualArgs); + Contract.Assert(cce.NonNullDictionaryAndValues(subst)); + + Type/*!*/ res = formalResult.Substitute(subst); + Contract.Assert(res != null); + // all type parameters have to be substituted with concrete types + List/*!*/ resFreeVars = res.FreeVariables; + Contract.Assert(resFreeVars != null); + Contract.Assert(Contract.ForAll(0, typeParams.Count, var => !resFreeVars.Contains(typeParams[var]))); + return res; + } + +#if OLD_UNIFICATION + public static IDictionary! + InferTypeParameters(List! typeParams, + List! formalArgs, + List! actualArgs) + { + Contract.Requires(formalArgs.Length == actualArgs.Length); + + List! boundVarSeq0 = new List (); + List! boundVarSeq1 = new List (); + Dictionary! subst = new Dictionary(); + + for (int i = 0; i < formalArgs.Length; ++i) { + try { + Contract.Assert(forall{TypeVariable! var in typeParams); + !actualArgs[i].FreeVariables.Has(var)}; + formalArgs[i].Unify(actualArgs[i], typeParams, + boundVarSeq0, boundVarSeq1, subst); + } catch (UnificationFailedException) { + System.Diagnostics.Debug.Fail("Type unification failed: " + + formalArgs[i] + " vs " + actualArgs[i]); + } + } + + // we only allow type parameters to be substituted + Contract.Assert(Contract.ForAll(subst.Keys , var=> typeParams.Has(var))); + return subst; + } +#else + /// + /// like Type.CheckArgumentTypes, but assumes no errors + /// (and only does arguments, not results; and takes actuals as List, not List) + /// + public static IDictionary/*!*/ + InferTypeParameters(List/*!*/ typeParams, + List/*!*/ formalArgs, + List/*!*/ actualArgs) { + Contract.Requires(typeParams != null); + Contract.Requires(formalArgs != null); + Contract.Requires(actualArgs != null);Contract.Requires(formalArgs.Count == actualArgs.Count); + Contract.Ensures(cce.NonNullDictionaryAndValues(Contract.Result>())); + + + List proxies = new List(); + Dictionary/*!*/ subst = new Dictionary(); + foreach (TypeVariable/*!*/ tv in typeParams) { + Contract.Assert(tv != null); + TypeProxy proxy = new TypeProxy(Token.NoToken, tv.Name); + proxies.Add(proxy); + subst.Add(tv, proxy); + } + + for (int i = 0; i < formalArgs.Count; i++) { + Type formal = formalArgs[i].Substitute(subst); + Type actual = actualArgs[i]; + // if the type variables to be matched occur in the actual + // argument types, something has gone very wrong + Contract.Assert(Contract.ForAll(0, typeParams.Count, index => !actual.FreeVariables.Contains(typeParams[index]))); + + if (!formal.Unify(actual)) { + Contract.Assume(false); // caller expected no errors + } + } + + return subst; + } +#endif + + //----------- Helper methods to deal with bound type variables --------------- + + public static void EmitOptionalTypeParams(TokenTextWriter stream, List typeParams) { + Contract.Requires(typeParams != null); + Contract.Requires(stream != null); + if (typeParams.Count > 0) { + stream.Write("<"); + typeParams.Emit(stream, ","); // default binding strength of 0 is ok + stream.Write(">"); + } + } + + // Sort the type parameters according to the order of occurrence in the argument types + public static List/*!*/ SortTypeParams(List/*!*/ typeParams, List/*!*/ argumentTypes, Type resultType) { + Contract.Requires(typeParams != null); + Contract.Requires(argumentTypes != null); + Contract.Ensures(Contract.Result>() != null); + + Contract.Ensures(Contract.Result>().Count == typeParams.Count); + if (typeParams.Count == 0) { + return typeParams; + } + + List freeVarsInUse = FreeVariablesIn(argumentTypes); + if (resultType != null) { + freeVarsInUse.AppendWithoutDups(resultType.FreeVariables); + } + // "freeVarsInUse" is already sorted, but it may contain type variables not in "typeParams". + // So, project "freeVarsInUse" onto "typeParams": + List sortedTypeParams = new List(); + foreach (TypeVariable/*!*/ var in freeVarsInUse) { + Contract.Assert(var != null); + if (typeParams.Contains(var)) { + sortedTypeParams.Add(var); + } + } + + if (sortedTypeParams.Count < typeParams.Count) + // add the type parameters not mentioned in "argumentTypes" in + // the end of the list (this can happen for quantifiers) + sortedTypeParams.AppendWithoutDups(typeParams); + + return sortedTypeParams; + } + + // Check that each of the type parameters occurs in at least one argument type. + // Return true if some type parameters appear only among "moreArgumentTypes" and + // not in "argumentTypes". + [Pure] + public static bool CheckBoundVariableOccurrences(List/*!*/ typeParams, + List/*!*/ argumentTypes, + List moreArgumentTypes, + IToken/*!*/ resolutionSubject, + string/*!*/ subjectName, + ResolutionContext/*!*/ rc) { + Contract.Requires(typeParams != null); + Contract.Requires(argumentTypes != null); + Contract.Requires(resolutionSubject != null); + Contract.Requires(subjectName != null); + Contract.Requires(rc != null); + List freeVarsInArgs = FreeVariablesIn(argumentTypes); + List moFreeVarsInArgs = moreArgumentTypes == null ? null : FreeVariablesIn(moreArgumentTypes); + bool someTypeParamsAppearOnlyAmongMo = false; + foreach (TypeVariable/*!*/ var in typeParams) { + Contract.Assert(var != null); + if (rc.LookUpTypeBinder(var.Name) == var) // avoid to complain twice about variables that are bound multiple times + { + if (freeVarsInArgs.Contains(var)) { + // cool + } else if (moFreeVarsInArgs != null && moFreeVarsInArgs.Contains(var)) { + someTypeParamsAppearOnlyAmongMo = true; + } else { + rc.Error(resolutionSubject, + "type variable must occur in {0}: {1}", + subjectName, var); + } + } + } + return someTypeParamsAppearOnlyAmongMo; + } + + [Pure] + public static List FreeVariablesIn(List arguments) { + Contract.Requires(arguments != null); + Contract.Ensures(Contract.Result>() != null); + List/*!*/ res = new List(); + foreach (Type/*!*/ t in arguments) { + Contract.Assert(t != null); + res.AppendWithoutDups(t.FreeVariables); + } + return res; + } + } + [ContractClassFor(typeof(Type))] + public abstract class TypeContracts : Type { + public TypeContracts() :base(null){ + + } + public override List FreeProxies { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + throw new NotImplementedException(); + } + } + public override List FreeVariables { + get { + Contract.Ensures(Contract.Result>() != null); + throw new NotImplementedException(); + } + } + public override Type Clone(IDictionary varMap) { + Contract.Requires(cce.NonNullDictionaryAndValues(varMap)); + Contract.Ensures(Contract.Result() != null); + + throw new NotImplementedException(); + } + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + + throw new NotImplementedException(); + } + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + Contract.Requires(stream != null); + throw new NotImplementedException(); + } + public override bool Equals(Type that, List thisBoundVariables, List thatBoundVariables) { + Contract.Requires(that != null); + Contract.Requires(thisBoundVariables != null); + Contract.Requires(thatBoundVariables != null); + throw new NotImplementedException(); + } + public override bool Unify(Type that, List unifiableVariables, IDictionary unifier) { + Contract.Requires(that != null); + Contract.Requires(unifiableVariables != null); + Contract.Requires(cce.NonNullDictionaryAndValues(unifier)); + Contract.Requires(Contract.ForAll(unifier.Keys, key => unifiableVariables.Contains(key))); + Contract.Requires(IsIdempotent(unifier)); + throw new NotImplementedException(); + } + public override Type Substitute(IDictionary subst) { + Contract.Requires(cce.NonNullDictionaryAndValues(subst)); + Contract.Ensures(Contract.Result() != null); + + throw new NotImplementedException(); + } + public override Type ResolveType(ResolutionContext rc) { + Contract.Requires(rc != null); + Contract.Ensures(Contract.Result() != null); + + throw new NotImplementedException(); + } + public override int GetHashCode(List boundVariables) { + Contract.Requires(boundVariables != null); + throw new NotImplementedException(); + } + } + //===================================================================== + + public class BasicType : Type { + public readonly SimpleType T; + public BasicType(IToken/*!*/ token, SimpleType t) + : base(token) { + Contract.Requires(token != null); + T = t; + } + public BasicType(SimpleType t) + : base(Token.NoToken) { + T = t; + } + + //----------- Cloning ---------------------------------- + // We implement our own clone-method, because bound type variables + // have to be created in the right way. It is /not/ ok to just clone + // everything recursively. + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + // BasicTypes are immutable anyway, we do not clone + return this; + } + + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + return this; + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + //Contract.Requires(stream != null); + // no parentheses are necessary for basic types + stream.SetToken(this); + stream.Write("{0}", this); + } + + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result() != null); + switch (T) { + case SimpleType.Int: + return "int"; + case SimpleType.Real: + return "real"; + case SimpleType.Bool: + return "bool"; + } + Debug.Assert(false, "bad type " + T); + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // make compiler happy + } + + //----------- Equality ---------------------------------- + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + // shortcut + Type thatType = that as Type; + if (thatType == null) + return false; + BasicType thatBasicType = TypeProxy.FollowProxy(thatType.Expanded) as BasicType; + return thatBasicType != null && this.T == thatBasicType.T; + } + + [Pure] + public override bool Equals(Type that, List thisBoundVariables, List thatBoundVariables) { + //Contract.Requires(thatBoundVariables != null); + //Contract.Requires(thisBoundVariables != null); + //Contract.Requires(that != null); + return this.Equals(that); + } + + //----------- Unification of types ----------- + + public override bool Unify(Type that, List unifiableVariables, IDictionary/*!*/ unifier) { + //Contract.Requires(unifiableVariables != null); + //Contract.Requires(that != null); + //Contract.Requires(cce.NonNullElements(unifier)); + // an idempotent substitution that describes the + // unification result up to a certain point + + that = that.Expanded; + if (that is TypeProxy || that is TypeVariable) { + return that.Unify(this, unifiableVariables, unifier); + } else { + return this.Equals(that); + } + } + +#if OLD_UNIFICATION + public override void Unify(Type! that, + List! unifiableVariables, + List! thisBoundVariables, + List! thatBoundVariables, + IDictionary! result) { + that = that.Expanded; + if (that is TypeVariable) { + that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); + } else { + if (!this.Equals(that)) + throw UNIFICATION_FAILED; + } + } +#endif + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + return this; + } + + //----------- Hashcodes ---------------------------------- + + [Pure] + public override int GetHashCode(List boundVariables) { + //Contract.Requires(boundVariables != null); + return this.T.GetHashCode(); + } + + //----------- Resolution ---------------------------------- + + public override Type ResolveType(ResolutionContext rc) { + //Contract.Requires(rc != null); + Contract.Ensures(Contract.Result() != null); + // nothing to resolve + return this; + } + + // determine the free variables in a type, in the order in which the variables occur + public override List/*!*/ FreeVariables { + get { + Contract.Ensures(Contract.Result>() != null); + + return new List(); // basic type are closed + } + } + + public override List/*!*/ FreeProxies { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return new List(); + } + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsBasic { + get { + return true; + } + } + public override bool IsInt { + get { + return this.T == SimpleType.Int; + } + } + public override bool IsReal { + get { + return this.T == SimpleType.Real; + } + } + public override bool IsBool { + get { + return this.T == SimpleType.Bool; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitBasicType(this); + } + } + + //===================================================================== + + //Note that the functions in this class were directly copied from the BV class just below + public class FloatType : Type { + public readonly int Mantissa; //Size of mantissa in bits + public readonly int Exponent; //Size of exponent in bits + + public FloatType(IToken token, int exponent, int mantissa) + : base(token) { + Contract.Requires(token != null); + Exponent = exponent; + Mantissa = mantissa; + } + + public FloatType(int exponent, int mantissa) + : base(Token.NoToken) { + Exponent = exponent; + Mantissa = mantissa; + } + + //----------- Cloning ---------------------------------- + // We implement our own clone-method, because bound type variables + // have to be created in the right way. It is /not/ ok to just clone + // everything recursively. + + public override Type Clone(IDictionary/*!*/ varMap) + { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + // FloatTypes are immutable anyway, we do not clone + return this; + } + + public override Type CloneUnresolved() + { + Contract.Ensures(Contract.Result() != null); + return this; + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) + { + //Contract.Requires(stream != null); + // no parentheses are necessary for bitvector-types + stream.SetToken(this); + stream.Write("{0}", this); + } + + public override string ToString() + { + Contract.Ensures(Contract.Result() != null); + return "float (" + Exponent + " " + Mantissa + ")"; + } + + //----------- Equality ---------------------------------- + + [Pure] + public override bool Equals(Type/*!*/ that, + List/*!*/ thisBoundVariables, + List/*!*/ thatBoundVariables) + { + FloatType thatFloatType = TypeProxy.FollowProxy(that.Expanded) as FloatType; + return thatFloatType != null && this.Mantissa == thatFloatType.Mantissa && this.Exponent == thatFloatType.Exponent; + } + + //----------- Unification of types ----------- + + public override bool Unify(Type/*!*/ that, + List/*!*/ unifiableVariables, + // an idempotent substitution that describes the + // unification result up to a certain point + IDictionary/*!*/ unifier) + { + //Contract.Requires(that != null); + //Contract.Requires(unifiableVariables != null); + //Contract.Requires(cce.NonNullElements(unifier)); + that = that.Expanded; + if (that is TypeProxy || that is TypeVariable) { + return that.Unify(this, unifiableVariables, unifier); + } + else { + return this.Equals(that); + } + } + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) + { + Contract.Ensures(Contract.Result() != null); + return this; + } + + //----------- Hashcodes ---------------------------------- + + [Pure] + public override int GetHashCode(List boundVariables) + { + return this.Mantissa.GetHashCode() + this.Exponent.GetHashCode(); + } + + //----------- Resolution ---------------------------------- + + public override Type ResolveType(ResolutionContext rc) + { + //Contract.Requires(rc != null); + Contract.Ensures(Contract.Result() != null); + // nothing to resolve + return this; + } + + // determine the free variables in a type, in the order in which the variables occur + public override List/*!*/ FreeVariables + { + get + { + Contract.Ensures(Contract.Result>() != null); + + return new List(); // bitvector-type are closed + } + } + + public override List/*!*/ FreeProxies + { + get + { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return new List(); + } + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsFloat { + get { + return true; + } + } + public override int FloatMantissa { + get { + return Mantissa; + } + } + public override int FloatExponent { + get { + return Exponent; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) + { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitFloatType(this); + } + + } + + //===================================================================== + + public class BvType : Type { + public readonly int Bits; + + public BvType(IToken token, int bits) + : base(token) { + Contract.Requires(token != null); + Bits = bits; + } + + public BvType(int bits) + : base(Token.NoToken) { + Bits = bits; + } + + //----------- Cloning ---------------------------------- + // We implement our own clone-method, because bound type variables + // have to be created in the right way. It is /not/ ok to just clone + // everything recursively. + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + // BvTypes are immutable anyway, we do not clone + return this; + } + + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + return this; + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + //Contract.Requires(stream != null); + // no parentheses are necessary for bitvector-types + stream.SetToken(this); + stream.Write("{0}", this); + } + + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result() != null); + return "bv" + Bits; + } + + //----------- Equality ---------------------------------- + + [Pure] + public override bool Equals(Type/*!*/ that, + List/*!*/ thisBoundVariables, + List/*!*/ thatBoundVariables) { + //Contract.Requires(thisBoundVariables != null); + //Contract.Requires(thatBoundVariables != null); + //Contract.Requires(that != null); + BvType thatBvType = TypeProxy.FollowProxy(that.Expanded) as BvType; + return thatBvType != null && this.Bits == thatBvType.Bits; + } + + //----------- Unification of types ----------- + + public override bool Unify(Type/*!*/ that, + List/*!*/ unifiableVariables, + // an idempotent substitution that describes the + // unification result up to a certain point + IDictionary/*!*/ unifier) { + //Contract.Requires(that != null); + //Contract.Requires(unifiableVariables != null); + //Contract.Requires(cce.NonNullElements(unifier)); + that = that.Expanded; + if (that is TypeProxy || that is TypeVariable) { + return that.Unify(this, unifiableVariables, unifier); + } else { + return this.Equals(that); + } + } + +#if OLD_UNIFICATION + public override void Unify(Type that, + List! unifiableVariables, + List! thisBoundVariables, + List! thatBoundVariables, + IDictionary result){ +Contract.Requires(result != null); +Contract.Requires(that != null); + that = that.Expanded; + if (that is TypeVariable) { + that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); + } else { + if (!this.Equals(that)) + throw UNIFICATION_FAILED; + } + } +#endif + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + return this; + } + + //----------- Hashcodes ---------------------------------- + + [Pure] + public override int GetHashCode(List boundVariables) { + //Contract.Requires(boundVariables != null); + return this.Bits.GetHashCode(); + } + + //----------- Resolution ---------------------------------- + + public override Type ResolveType(ResolutionContext rc) { + //Contract.Requires(rc != null); + Contract.Ensures(Contract.Result() != null); + // nothing to resolve + return this; + } + + // determine the free variables in a type, in the order in which the variables occur + public override List/*!*/ FreeVariables { + get { + Contract.Ensures(Contract.Result>() != null); + + return new List(); // bitvector-type are closed + } + } + + public override List/*!*/ FreeProxies { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return new List(); + } + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsBv { + get { + return true; + } + } + public override int BvBits { + get { + return Bits; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitBvType(this); + } + } + + //===================================================================== + + // An AST node containing an identifier and a sequence of type arguments, which + // will be turned either into a TypeVariable, into a CtorType or into a BvType + // during the resolution phase + public class UnresolvedTypeIdentifier : Type { + public readonly string/*!*/ Name; + public readonly List/*!*/ Arguments; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Name != null); + Contract.Invariant(Arguments != null); + } + + + public UnresolvedTypeIdentifier(IToken token, string name) + : this(token, name, new List()) { + Contract.Requires(name != null); + Contract.Requires(token != null); + } + + public UnresolvedTypeIdentifier(IToken token, string name, List arguments) + : base(token) { + Contract.Requires(arguments != null); + Contract.Requires(name != null); + Contract.Requires(token != null); + this.Name = name; + this.Arguments = arguments; + } + + //----------- Cloning ---------------------------------- + // We implement our own clone-method, because bound type variables + // have to be created in the right way. It is /not/ ok to just clone + // everything recursively + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + List/*!*/ newArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + newArgs.Add(t.Clone(varMap)); + } + return new UnresolvedTypeIdentifier(tok, Name, newArgs); + } + + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + List/*!*/ newArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + newArgs.Add(t.CloneUnresolved()); + } + return new UnresolvedTypeIdentifier(tok, Name, newArgs); + } + + //----------- Equality ---------------------------------- + + [Pure] + public override bool Equals(Type that, + List/*!*/ thisBoundVariables, + List/*!*/ thatBoundVariables) { + //Contract.Requires(thisBoundVariables != null); + //Contract.Requires(thatBoundVariables != null); + //Contract.Requires(that != null); + System.Diagnostics.Debug.Fail("UnresolvedTypeIdentifier.Equals should never be called"); + return false; // to make the compiler happy + } + + //----------- Unification of types ----------- + + public override bool Unify(Type that, + List/*!*/ unifiableVariables, + IDictionary result) { + //Contract.Requires(unifiableVariables != null); + //Contract.Requires(cce.NonNullElements(result)); + //Contract.Requires(that != null); + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // UnresolvedTypeIdentifier.Unify should never be called + } + +#if OLD_UNIFICATION + public override void Unify(Type that, + List! unifiableVariables, + List! thisBoundVariables, + List! thatBoundVariables, + IDictionary result){ +Contract.Requires(result != null); +Contract.Requires(that != null); + System.Diagnostics.Debug.Fail("UnresolvedTypeIdentifier.Unify should never be called"); + } +#endif + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // UnresolvedTypeIdentifier.Substitute should never be called + } + + //----------- Hashcodes ---------------------------------- + + [Pure] + public override int GetHashCode(List boundVariables) { + //Contract.Requires(boundVariables != null); + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // UnresolvedTypeIdentifier.GetHashCode should never be called + } + + //----------- Resolution ---------------------------------- + + public override Type ResolveType(ResolutionContext rc) { + //Contract.Requires(rc != null); + Contract.Ensures(Contract.Result() != null); + // first case: the type name denotes a bitvector-type + if (Name.StartsWith("bv") && Name.Length > 2) { + bool is_bv = true; + for (int i = 2; i < Name.Length; ++i) { + if (!char.IsDigit(Name[i])) { + is_bv = false; + break; + } + } + if (is_bv) { + if (Arguments.Count > 0) { + rc.Error(this, + "bitvector types must not be applied to arguments: {0}", + Name); + } + return new BvType(tok, int.Parse(Name.Substring(2))); + } + } + + // second case: the identifier is resolved to a type variable + TypeVariable var = rc.LookUpTypeBinder(Name); + if (var != null) { + if (Arguments.Count > 0) { + rc.Error(this, + "type variables must not be applied to arguments: {0}", + var); + } + return var; + } + + // third case: the identifier denotes a type constructor and we + // recursively resolve the arguments + TypeCtorDecl ctorDecl = rc.LookUpType(Name); + if (ctorDecl != null) { + if (Arguments.Count != ctorDecl.Arity) { + rc.Error(this, + "type constructor received wrong number of arguments: {0}", + ctorDecl); + return this; + } + return new CtorType(tok, ctorDecl, ResolveArguments(rc)); + } + + // fourth case: the identifier denotes a type synonym + TypeSynonymDecl synDecl = rc.LookUpTypeSynonym(Name); + if (synDecl != null) { + if (Arguments.Count != synDecl.TypeParameters.Count) { + rc.Error(this, + "type synonym received wrong number of arguments: {0}", + synDecl); + return this; + } + List/*!*/ resolvedArgs = ResolveArguments(rc); + Contract.Assert(resolvedArgs != null); + + return new TypeSynonymAnnotation(this.tok, synDecl, resolvedArgs); + + } + + // otherwise: this name is not declared anywhere + rc.Error(this, "undeclared type: {0}", Name); + return this; + } + + private List ResolveArguments(ResolutionContext rc) { + Contract.Requires(rc != null); + Contract.Ensures(Contract.Result>() != null); + List/*!*/ resolvedArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + resolvedArgs.Add(t.ResolveType(rc)); + } + return resolvedArgs; + } + + public override List/*!*/ FreeVariables { + get { + Contract.Ensures(Contract.Result>() != null); + + return new List(); + } + } + + public override List/*!*/ FreeProxies { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return new List(); + } + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + //Contract.Requires(stream != null); + stream.SetToken(this); + // PR: should unresolved types be syntactically distinguished from resolved types? + CtorType.EmitCtorType(this.Name, Arguments, stream, contextBindingStrength); + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsUnresolved { + get { + return true; + } + } + public override UnresolvedTypeIdentifier/*!*/ AsUnresolved { + get { + Contract.Ensures(Contract.Result() != null); + return this; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitUnresolvedTypeIdentifier(this); + } + } + + //===================================================================== + + public class TypeVariable : Type { + public readonly string/*!*/ Name; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Name != null); + } + + + public TypeVariable(IToken token, string name) + : base(token) { + Contract.Requires(name != null); + Contract.Requires(token != null); + this.Name = name; + } + + //----------- Cloning ---------------------------------- + // We implement our own clone-method, because bound type variables + // have to be created in the right way. It is /not/ ok to just clone + // everything recursively + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + // if this variable is mapped to some new variable, we take the new one + // otherwise, return this + TypeVariable res; + varMap.TryGetValue(this, out res); + if (res == null) + return this; + else + return res; + } + + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + return this; + } + + //----------- Equality ---------------------------------- + + [Pure] + public override bool Equals(Type that, + List/*!*/ thisBoundVariables, + List/*!*/ thatBoundVariables) { + //Contract.Requires(thisBoundVariables != null); + //Contract.Requires(thatBoundVariables != null); + //Contract.Requires(that != null); + TypeVariable thatAsTypeVar = TypeProxy.FollowProxy(that.Expanded) as TypeVariable; + + if (thatAsTypeVar == null) + return false; + + int thisIndex = thisBoundVariables.LastIndexOf(this); + int thatIndex = thatBoundVariables.LastIndexOf(thatAsTypeVar); + return (thisIndex >= 0 && thisIndex == thatIndex) || + (thisIndex == -1 && thatIndex == -1 && + Object.ReferenceEquals(this, thatAsTypeVar)); + } + + //----------- Unification of types ----------- + + public override bool Unify(Type/*!*/ that, + List/*!*/ unifiableVariables, + // an idempotent substitution that describes the + // unification result up to a certain point + IDictionary/*!*/ unifier) { + //Contract.Requires(that != null); + //Contract.Requires(unifiableVariables != null); + //Contract.Requires(cce.NonNullElements(unifier)); + that = that.Expanded; + if (that is TypeProxy && !(that is ConstrainedProxy)) + return that.Unify(this, unifiableVariables, unifier); + + if (this.Equals(that)) + return true; + + if (unifiableVariables.Contains(this)) { + Type previousSubst; + unifier.TryGetValue(this, out previousSubst); + if (previousSubst == null) { + return addSubstitution(unifier, that); + } else { + // we have to unify the old instantiation with the new one + return previousSubst.Unify(that, unifiableVariables, unifier); + } + } + + // this cannot be instantiated with anything + // but that possibly can ... + + TypeVariable tv = that as TypeVariable; + + return tv != null && + unifiableVariables.Contains(tv) && + that.Unify(this, unifiableVariables, unifier); + } + + // TODO: the following might cause problems, because when applying substitutions + // to type proxies the substitutions are not propagated to the proxy + // constraints (right now at least) + private bool addSubstitution(IDictionary/*!*/ oldSolution, + // the type that "this" is instantiated with + Type/*!*/ newSubst) { + Contract.Requires(cce.NonNullDictionaryAndValues(oldSolution)); + Contract.Requires(newSubst != null); + Contract.Requires(!oldSolution.ContainsKey(this)); + + Dictionary/*!*/ newMapping = new Dictionary(); + // apply the old (idempotent) substitution to the new instantiation + Type/*!*/ substSubst = newSubst.Substitute(oldSolution); + Contract.Assert(substSubst != null); + // occurs check + if (substSubst.FreeVariables.Contains(this)) + return false; + newMapping.Add(this, substSubst); + + // apply the new substitution to the old ones to ensure idempotence + List/*!*/ keys = new List(); + keys.AddRange(oldSolution.Keys); + foreach (TypeVariable/*!*/ var in keys) { + Contract.Assert(var != null); + oldSolution[var] = oldSolution[var].Substitute(newMapping); + } + oldSolution.Add(this, substSubst); + + Contract.Assert(IsIdempotent(oldSolution)); + return true; + } + +#if OLD_UNIFICATION + public override void Unify(Type that, + List! unifiableVariables, + List! thisBoundVariables, + List! thatBoundVariables, + IDictionary result){ +Contract.Requires(result != null); +Contract.Requires(that != null); + that = that.Expanded; + int thisIndex = thisBoundVariables.LastIndexOf(this); + if (thisIndex == -1) { + // this is not a bound variable and can possibly be matched on that + // that must not contain any bound variables + List! thatFreeVars = that.FreeVariables; + if (thatBoundVariables.Any(var=> thatFreeVars.Has(var))) + throw UNIFICATION_FAILED; + + // otherwise, in case that is a typevariable it cannot be bound and + // we can just check for equality + if (this.Equals(that)) + return; + + if (!unifiableVariables.Has(this)) { + // this cannot be instantiated with anything + // but that possibly can ... + if ((that is TypeVariable) && + unifiableVariables.Has(that as TypeVariable)) { + that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); + return; + } else { + throw UNIFICATION_FAILED; + } + } + + Type previousSubst; + result.TryGetValue(this, out previousSubst); + if (previousSubst == null) { + addSubstitution(result, that); + } else { + // we have to unify the old instantiation with the new one + previousSubst.Unify(that, unifiableVariables, thisBoundVariables, thatBoundVariables, result); + } + } else { + // this is a bound variable, that also has to be one (with the same index) + if (!(that is TypeVariable) || + thatBoundVariables.LastIndexOf(that) != thisIndex) + throw UNIFICATION_FAILED; + } + } + +#endif + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + Type res; + if (subst.TryGetValue(this, out res)) { + Contract.Assert(res != null); + return res; + } else { + return this; + } + } + + //----------- Hashcodes ---------------------------------- + + [Pure] + public override int GetHashCode(List boundVariables) { + //Contract.Requires(boundVariables != null); + int thisIndex = boundVariables.LastIndexOf(this); + if (thisIndex == -1) + return GetBaseHashCode(); + return thisIndex * 27473671; + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + //Contract.Requires(stream != null); + // never put parentheses around variables + stream.SetToken(this); + stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); + } + + //----------- Resolution ---------------------------------- + + public override Type ResolveType(ResolutionContext rc) { + //Contract.Requires(rc != null); + //Contract.Ensures(Contract.Result() != null); + // nothing to resolve + return this; + } + + public override List/*!*/ FreeVariables { + get { + Contract.Ensures(Contract.Result>() != null); + return new List { this }; + } + } + + public override List/*!*/ FreeProxies { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return new List(); + } + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsVariable { + get { + return true; + } + } + public override TypeVariable/*!*/ AsVariable { + get { + Contract.Ensures(Contract.Result() != null); + return this; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + //Contract.Ensures(Contract.Result() != null); + return visitor.VisitTypeVariable(this); + } + } + + //===================================================================== + + public class TypeProxy : Type { + static int proxies = 0; + protected readonly string/*!*/ Name; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Name != null); + } + + + public TypeProxy(IToken token, string givenName) + : this(token, givenName, "proxy") { + Contract.Requires(givenName != null); + Contract.Requires(token != null); + } + + protected TypeProxy(IToken token, string givenName, string kind) + : base(token) { + Contract.Requires(kind != null); + Contract.Requires(givenName != null); + Contract.Requires(token != null); + Name = givenName + "$" + kind + "#" + proxies; + proxies++; + } + + private Type proxyFor; + public Type ProxyFor { + // apply path shortening, and then return the value of proxyFor + get { + TypeProxy anotherProxy = proxyFor as TypeProxy; + if (anotherProxy != null && anotherProxy.proxyFor != null) { + // apply path shortening by bypassing "anotherProxy" (and possibly others) + proxyFor = anotherProxy.ProxyFor; + Contract.Assert(proxyFor != null); + } + return proxyFor; + } + } + + [Pure] + [Reads(ReadsAttribute.Reads.Everything)] + public static Type FollowProxy(Type t) { + Contract.Requires(t != null); + Contract.Ensures(Contract.Result() != null); + Contract.Ensures(!(Contract.Result() is TypeProxy) || ((TypeProxy)Contract.Result()).proxyFor == null); + if (t is TypeProxy) { + Type p = ((TypeProxy)t).ProxyFor; + if (p != null) { + return p; + } + } + return t; + } + + protected void DefineProxy(Type ty) { + Contract.Requires(ty != null); + Contract.Requires(ProxyFor == null); + // follow ty down to the leaf level, so that we can avoid creating a cycle + ty = FollowProxy(ty); + if (!object.ReferenceEquals(this, ty)) { + proxyFor = ty; + } + } + + //----------- Cloning ---------------------------------- + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + Type p = ProxyFor; + if (p != null) { + return p.Clone(varMap); + } else { + return new TypeProxy(this.tok, this.Name); // the clone will have a name that ends with $proxy$proxy + } + } + + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + return new TypeProxy(this.tok, this.Name); // the clone will have a name that ends with $proxy$proxy + } + + //----------- Equality ---------------------------------- + + [Pure] + public override bool Equals(Type that, + List/*!*/ thisBoundVariables, + List/*!*/ thatBoundVariables) { + //Contract.Requires(thisBoundVariables != null); + //Contract.Requires(thatBoundVariables != null); + //Contract.Requires(that != null); + if (object.ReferenceEquals(this, that)) { + return true; + } + Type p = ProxyFor; + if (p != null) { + return p.Equals(that, thisBoundVariables, thatBoundVariables); + } else { + // This proxy could be made to be equal to anything, so what to return? + return false; + } + } + + //----------- Unification of types ----------- + + // determine whether the occurs check fails: this is a strict subtype of that + protected bool ReallyOccursIn(Type that) { + Contract.Requires(that != null); + that = FollowProxy(that.Expanded); + return that.FreeProxies.Contains(this) && + (that.IsCtor || that.IsMap && this != that && this.ProxyFor != that); + } + + public override bool Unify(Type that, + List/*!*/ unifiableVariables, + IDictionary result) { + //Contract.Requires(cce.NonNullElements(result)); + //Contract.Requires(unifiableVariables != null); + //Contract.Requires(that != null); + Type p = ProxyFor; + if (p != null) { + return p.Unify(that, unifiableVariables, result); + } else { + // unify this with that + if (this.ReallyOccursIn(that)) + return false; + DefineProxy(that.Expanded); + return true; + } + } + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + Type p = ProxyFor; + if (p != null) { + return p.Substitute(subst); + } else { + return this; + } + } + + //----------- Hashcodes ---------------------------------- + + [Pure] + public override int GetHashCode(List boundVariables) { + //Contract.Requires(boundVariables != null); + Type p = ProxyFor; + if (p != null) { + return p.GetHashCode(boundVariables); + } else { + return GetBaseHashCode(); + } + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + //Contract.Requires(stream != null); + Type p = ProxyFor; + if (p != null) { + p.Emit(stream, contextBindingStrength); + } else { + // no need for parentheses + stream.SetToken(this); + stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); + } + } + + //----------- Resolution ---------------------------------- + + public override Type ResolveType(ResolutionContext rc) { + //Contract.Requires(rc != null); + Contract.Ensures(Contract.Result() != null); + Type p = ProxyFor; + if (p != null) { + return p.ResolveType(rc); + } else { + return this; + } + } + + public override List/*!*/ FreeVariables { + get { + Contract.Ensures(Contract.Result>() != null); + + Type p = ProxyFor; + if (p != null) { + return p.FreeVariables; + } else { + return new List(); + } + } + } + + public override List/*!*/ FreeProxies { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + Type p = ProxyFor; + if (p != null) { + return p.FreeProxies; + } else { + List/*!*/ res = new List(); + res.Add(this); + return res; + } + } + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsBasic { + get { + Type p = ProxyFor; + return p != null && p.IsBasic; + } + } + public override bool IsInt { + get { + Type p = ProxyFor; + return p != null && p.IsInt; + } + } + public override bool IsReal { + get { + Type p = ProxyFor; + return p != null && p.IsReal; + } + } + public override bool IsFloat { + get { + Type p = ProxyFor; + return p != null && p.IsFloat; + } + } + public override bool IsBool { + get { + Type p = ProxyFor; + return p != null && p.IsBool; + } + } + + public override bool IsVariable { + get { + Type p = ProxyFor; + return p != null && p.IsVariable; + } + } + public override TypeVariable/*!*/ AsVariable { + get { + Contract.Ensures(Contract.Result() != null); + + Type p = ProxyFor; + Contract.Assume(p != null); + return p.AsVariable; + } + } + + public override bool IsCtor { + get { + Type p = ProxyFor; + return p != null && p.IsCtor; + } + } + public override CtorType/*!*/ AsCtor { + get { + Contract.Ensures(Contract.Result() != null); + + Type p = ProxyFor; + Contract.Assume(p != null); + return p.AsCtor; + } + } + public override bool IsMap { + get { + Type p = ProxyFor; + return p != null && p.IsMap; + } + } + public override MapType/*!*/ AsMap { + get { + Contract.Ensures(Contract.Result() != null); + + Type p = ProxyFor; + Contract.Assume(p != null); + return p.AsMap; + } + } + public override int MapArity { + get { + Type p = ProxyFor; + Contract.Assume(p != null); + return p.MapArity; + } + } + public override bool IsUnresolved { + get { + Type p = ProxyFor; + return p != null && p.IsUnresolved; + } + } + public override UnresolvedTypeIdentifier/*!*/ AsUnresolved { + get { + Contract.Ensures(Contract.Result() != null); + + Type p = ProxyFor; + Contract.Assume(p != null); + return p.AsUnresolved; + } + } + + public override bool IsBv { + get { + Type p = ProxyFor; + return p != null && p.IsBv; + } + } + public override int BvBits { + get { + Type p = ProxyFor; + Contract.Assume(p != null); + return p.BvBits; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitTypeProxy(this); + } + } + + public abstract class ConstrainedProxy : TypeProxy { + protected ConstrainedProxy(IToken token, string givenName, string kind) + : base(token, givenName, kind) { + Contract.Requires(kind != null); + Contract.Requires(givenName != null); + Contract.Requires(token != null); + } + } + + /// + /// Each instance of this class represents a set of bitvector types. In particular, it represents + /// a bitvector type bvN iff + /// minBits ATMOST N and + /// foreach constraint (t0,t1), the types represented by t0 and t1 are bitvector types whose + /// number of bits add up to N. + /// This means that the size of a BvTypeProxy p is constrained not only by p.minBits, but also + /// by the size of various t0 and t1 types that are transitively part of BvTypeProxy constraints. + /// If such a t0 or t1 were to get its ProxyFor field defined, then p would have to be further + /// constrained too. This doesn't seem like it would ever occur in a Boogie 2 program, because: + /// the only place where a BvTypeProxy with constraints can occur is as the type of a + /// BvConcatExpr, and + /// the types of all local variables are explicitly declared, which means that the types of + /// subexpressions of a BvConcatExpr are not going to change other than via the type of the + /// BvConcatExpr. + /// So, this implementation of BvTypeProxy does not keep track of where a BvTypeProxy may occur + /// transitively in some other BvTypeProxy's constraints. + /// + public class BvTypeProxy : ConstrainedProxy { + public int MinBits; + List constraints; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cce.NonNullElements(constraints, true)); + } + + class BvTypeConstraint { + public Type/*!*/ T0; + public Type/*!*/ T1; + public BvTypeConstraint(Type t0, Type t1) { + Contract.Requires(t1 != null); + Contract.Requires(t0 != null); + Contract.Requires(t0.IsBv && t1.IsBv); + T0 = t0; + T1 = t1; + } + } + + public BvTypeProxy(IToken token, string name, int minBits) + : base(token, name, "bv" + minBits + "proxy") { + Contract.Requires(name != null); + Contract.Requires(token != null); + this.MinBits = minBits; + } + + /// + /// Requires that any further constraints to be placed on t0 and t1 go via the object to + /// be constructed. + /// + public BvTypeProxy(IToken token, string name, Type t0, Type t1) + : base(token, name, "bvproxy") { + Contract.Requires(t1 != null); + Contract.Requires(t0 != null); + Contract.Requires(name != null); + Contract.Requires(token != null); + Contract.Requires(t0.IsBv && t1.IsBv); + t0 = FollowProxy(t0); + t1 = FollowProxy(t1); + this.MinBits = MinBitsFor(t0) + MinBitsFor(t1); + List list = new List(); + list.Add(new BvTypeConstraint(t0, t1)); + this.constraints = list; + } + + /// + /// Construct a BvTypeProxy like p, but with minBits. + /// + private BvTypeProxy(BvTypeProxy p, int minBits) + : base(p.tok, p.Name, "") { + Contract.Requires(p != null); + this.MinBits = minBits; + this.constraints = p.constraints; + } + + private BvTypeProxy(IToken token, string name, int minBits, List constraints) + : base(token, name, "") { + Contract.Requires(cce.NonNullElements(constraints, true)); + Contract.Requires(name != null); + Contract.Requires(token != null); + this.MinBits = minBits; + this.constraints = constraints; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Everything)] + private static int MinBitsFor(Type t) { + Contract.Requires(t != null); + Contract.Requires(t.IsBv); + Contract.Ensures(0 <= Contract.Result()); + + if (t is TypeSynonymAnnotation) { + return MinBitsFor(((TypeSynonymAnnotation)t).ExpandedType); + } + + if (t is BvType) { + return t.BvBits; + } else { + return ((BvTypeProxy)t).MinBits; + } + } + + //----------- Cloning ---------------------------------- + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + Type p = ProxyFor; + if (p != null) { + return p.Clone(varMap); + } else { + return new BvTypeProxy(this.tok, this.Name, this.MinBits, this.constraints); // the clone will have a name that ends with $bvproxy$bvproxy + } + } + + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + return new BvTypeProxy(this.tok, this.Name, this.MinBits, this.constraints); // the clone will have a name that ends with $bvproxy$bvproxy + } + + //----------- Unification of types ----------- + + public override bool Unify(Type that, + List unifiableVariables, + IDictionary result) { + //Contract.Requires(cce.NonNullElements(result)); + //Contract.Requires(unifiableVariables != null); + //Contract.Requires(that != null); + Type p = ProxyFor; + if (p != null) { + return p.Unify(that, unifiableVariables, result); + } + + // unify this with that, if possible + that = that.Expanded; + that = FollowProxy(that); + + if (this.ReallyOccursIn(that)) + return false; + + TypeVariable tv = that as TypeVariable; + + if (tv != null && unifiableVariables.Contains(tv)) + return that.Unify(this, unifiableVariables, result); + + if (object.ReferenceEquals(this, that)) { + return true; + } else if (that is BvType) { + if (MinBits <= that.BvBits) { + if (constraints != null) { + foreach (BvTypeConstraint btc in constraints) { + int minT1 = MinBitsFor(btc.T1); + int left = IncreaseBits(btc.T0, that.BvBits - minT1); + left = IncreaseBits(btc.T1, minT1 + left); + Contract.Assert(left == 0); // because it should always be possible to increase the total size of a BvTypeConstraint pair (t0,t1) arbitrarily + } + } + DefineProxy(that); + return true; + } + } else if (that is BvTypeProxy) { + BvTypeProxy bt = (BvTypeProxy)that; + // keep the proxy with the stronger constraint (that is, the higher minBits), but if either + // has a constraints list, then concatenate both constraints lists and define the previous + // proxies to the new one + if (this.constraints != null || bt.constraints != null) { + List list = new List(); + if (this.constraints != null) { + list.AddRange(this.constraints); + } + if (bt.constraints != null) { + list.AddRange(bt.constraints); + } + BvTypeProxy np = new BvTypeProxy(this.tok, this.Name, Math.Max(this.MinBits, bt.MinBits), list); + this.DefineProxy(np); + bt.DefineProxy(np); + } else if (this.MinBits <= bt.MinBits) { + this.DefineProxy(bt); + } else { + bt.DefineProxy(this); + } + return true; + } else if (that is ConstrainedProxy) { + // only bitvector proxies can be unified with this BvTypeProxy + return false; + } else if (that is TypeProxy) { + // define: that.ProxyFor := this; + return that.Unify(this, unifiableVariables, result); + } + return false; + } + + private static int IncreaseBits(Type t, int to) { + Contract.Requires(t != null); + Contract.Requires(t.IsBv && 0 <= to && MinBitsFor(t) <= to); + Contract.Ensures(0 <= Contract.Result() && Contract.Result() <= to); + + if(t is TypeSynonymAnnotation) { + return IncreaseBits(((TypeSynonymAnnotation)t).ExpandedType, to); + } + + t = FollowProxy(t); + if (t is BvType) { + return to - t.BvBits; + } else { + BvTypeProxy p = (BvTypeProxy)t; + Contract.Assert(p.MinBits <= to); + if (p.MinBits < to) { + BvTypeProxy q = new BvTypeProxy(p, to); + p.DefineProxy(q); + } + return 0; // we were able to satisfy the request completely + } + } + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + if (this.ProxyFor == null) { + // check that the constraints are clean and do not contain any + // of the substituted variables (otherwise, we are in big trouble) + Contract.Assert(Contract.ForAll(constraints, c => + Contract.ForAll(subst.Keys, var => + !c.T0.FreeVariables.Contains(var) && !c.T1.FreeVariables.Contains(var)))); + } + return base.Substitute(subst); + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsBv { + get { + return true; + } + } + public override int BvBits { + get { + // This method is supposed to return the number of bits supplied, but unless the proxy has been resolved, + // we only have a lower bound on the number of bits supplied. But this method is not supposed to be + // called until type checking has finished, at which time the minBits is stable. + Type p = ProxyFor; + if (p != null) { + return p.BvBits; + } else { + return MinBits; + } + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitBvTypeProxy(this); + } + } + + // Proxy representing map types with a certain arity. Apart from the arity, + // a number of constraints on the index and value type of the map type may + // be known (such constraints result from applied select and store operations). + // Because map type can be polymorphic (in the most general case, each index or + // value type is described by a separate type parameter) any combination of + // constraints can be satisfied. + public class MapTypeProxy : ConstrainedProxy { + public readonly int Arity; + private readonly List/*!*/ constraints = new List(); + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(constraints != null); + } + + + // each constraint specifies that the given combination of argument/result + // types must be a possible instance of the formal map argument/result types + private struct Constraint { + public readonly List/*!*/ Arguments; + public readonly Type/*!*/ Result; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Arguments != null); + Contract.Invariant(Result != null); + } + + + public Constraint(List arguments, Type result) { + Contract.Requires(result != null); + Contract.Requires(arguments != null); + Arguments = arguments; + Result = result; + } + + public Constraint Clone(IDictionary/*!*/ varMap) { + Contract.Requires(cce.NonNullDictionaryAndValues(varMap)); + List/*!*/ args = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + args.Add(t.Clone(varMap)); + } + Type/*!*/ res = Result.Clone(varMap); + Contract.Assert(res != null); + return new Constraint(args, res); + } + + public bool Unify(MapType that, + List/*!*/ unifiableVariables, + IDictionary/*!*/ result) { + Contract.Requires(unifiableVariables != null); + Contract.Requires(cce.NonNullDictionaryAndValues(result)); + Contract.Requires(that != null); + Contract.Requires(Arguments.Count == that.Arguments.Count); + Dictionary/*!*/ subst = new Dictionary(); + foreach (TypeVariable/*!*/ tv in that.TypeParameters) { + Contract.Assert(tv != null); + TypeProxy proxy = new TypeProxy(Token.NoToken, tv.Name); + subst.Add(tv, proxy); + } + + bool good = true; + for (int i = 0; i < that.Arguments.Count; i++) { + Type t0 = that.Arguments[i].Substitute(subst); + Type t1 = this.Arguments[i]; + good &= t0.Unify(t1, unifiableVariables, result); + } + good &= that.Result.Substitute(subst).Unify(this.Result, unifiableVariables, result); + return good; + } + } + + public MapTypeProxy(IToken token, string name, int arity) + : base(token, name, "mapproxy") { + Contract.Requires(name != null); + Contract.Requires(token != null); + Contract.Requires(0 <= arity); + this.Arity = arity; + } + + private void AddConstraint(Constraint c) { + Contract.Requires(c.Arguments.Count == Arity); + + Type f = ProxyFor; + MapType mf = f as MapType; + if (mf != null) { + bool success = c.Unify(mf, new List(), new Dictionary()); + Contract.Assert(success); + return; + } + + MapTypeProxy mpf = f as MapTypeProxy; + if (mpf != null) { + mpf.AddConstraint(c); + return; + } + + Contract.Assert(f == null); // no other types should occur as specialisations of this proxy + + constraints.Add(c); + } + + public Type CheckArgumentTypes(List/*!*/ actualArgs, + out TypeParamInstantiation/*!*/ tpInstantiation, + IToken/*!*/ typeCheckingSubject, + string/*!*/ opName, + TypecheckingContext/*!*/ tc) { + Contract.Requires(actualArgs != null); + Contract.Requires(typeCheckingSubject != null); + Contract.Requires(opName != null); + Contract.Requires(tc != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + + + + Type f = ProxyFor; + MapType mf = f as MapType; + if (mf != null) + return mf.CheckArgumentTypes(actualArgs, out tpInstantiation, typeCheckingSubject, opName, tc); + + MapTypeProxy mpf = f as MapTypeProxy; + if (mpf != null) + return mpf.CheckArgumentTypes(actualArgs, out tpInstantiation, typeCheckingSubject, opName, tc); + + Contract.Assert(f == null); // no other types should occur as specialisations of this proxy + + // otherwise, we just record the constraints given by this usage of the map type + List/*!*/ arguments = new List(); + foreach (Expr/*!*/ e in actualArgs) { + Contract.Assert(e != null); + arguments.Add(e.Type); + } + Type/*!*/ result = new TypeProxy(tok, "result"); + Contract.Assert(result != null); + AddConstraint(new Constraint(arguments, result)); + + List/*!*/ argumentsResult = new List(); + foreach (Expr/*!*/ e in actualArgs) { + Contract.Assert(e != null); + argumentsResult.Add(e.Type); + } + argumentsResult.Add(result); + + tpInstantiation = new MapTypeProxyParamInstantiation(this, argumentsResult); + return result; + } + + //----------- Cloning ---------------------------------- + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + Type p = ProxyFor; + if (p != null) { + return p.Clone(varMap); + } else { + MapTypeProxy p2 = new MapTypeProxy(tok, Name, Arity); + foreach (Constraint c in constraints) + p2.AddConstraint(c.Clone(varMap)); + return p2; // the clone will have a name that ends with $mapproxy$mapproxy (hopefully) + } + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + //Contract.Requires(stream != null); + Type p = ProxyFor; + if (p != null) { + p.Emit(stream, contextBindingStrength); + } else { + stream.Write("["); + string/*!*/ sep = ""; + for (int i = 0; i < Arity; ++i) { + stream.Write(sep); + sep = ", "; + stream.Write("?"); + } + stream.Write("]?"); + } + } + + //----------- Unification of types ----------- + + public override bool Unify(Type/*!*/ that, + List/*!*/ unifiableVariables, + IDictionary/*!*/ result) { + //Contract.Requires(that != null); + //Contract.Requires(unifiableVariables != null); + //Contract.Requires(cce.NonNullElements(result)); + Type p = ProxyFor; + if (p != null) { + return p.Unify(that, unifiableVariables, result); + } + + // unify this with that, if possible + that = that.Expanded; + that = FollowProxy(that); + + if (this.ReallyOccursIn(that)) + return false; + + TypeVariable tv = that as TypeVariable; + + if (tv != null && unifiableVariables.Contains(tv)) + return that.Unify(this, unifiableVariables, result); + + if (object.ReferenceEquals(this, that)) { + return true; + } else if (that is MapType) { + MapType mapType = (MapType)that; + if (mapType.Arguments.Count == Arity) { + bool good = true; + foreach (Constraint c in constraints) + good &= c.Unify(mapType, unifiableVariables, result); + if (good) { + DefineProxy(mapType); + return true; + } + } + } else if (that is MapTypeProxy) { + MapTypeProxy mt = (MapTypeProxy)that; + if (mt.Arity == this.Arity) { + // we propagate the constraints of this proxy to the more specific one + foreach (Constraint c in constraints) + mt.AddConstraint(c); + DefineProxy(mt); + return true; + } + } else if (that is ConstrainedProxy) { + // only map-type proxies can be unified with this MapTypeProxy + return false; + } else if (that is TypeProxy) { + // define: that.ProxyFor := this; + return that.Unify(this, unifiableVariables, result); + } + return false; + } + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + if (this.ProxyFor == null) { + // check that the constraints are clean and do not contain any + // of the substituted variables (otherwise, we are in big trouble) + Contract.Assert(Contract.ForAll(constraints, c => + Contract.ForAll(subst.Keys, var => + Contract.ForAll(0, c.Arguments.Count, t => !c.Arguments[t].FreeVariables.Contains(var)) && + !c.Result.FreeVariables.Contains(var)))); + } + return base.Substitute(subst); + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsMap { + get { + return true; + } + } + public override MapType/*!*/ AsMap { + get { + Contract.Ensures(Contract.Result() != null); + + Type p = ProxyFor; + if (p != null) { + return p.AsMap; + } else { + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // what to do now? + } + } + } + public override int MapArity { + get { + return Arity; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitMapTypeProxy(this); + } + } + + //===================================================================== + + // Used to annotate types with type synoyms that were used in the + // original unresolved types. Such types should be considered as + // equivalent to ExpandedType, the annotations are only used to enable + // better pretty-printing + public class TypeSynonymAnnotation : Type { + public Type/*!*/ ExpandedType; + + public readonly List/*!*/ Arguments; + // is set during resolution and determines whether the right number of arguments is given + public readonly TypeSynonymDecl/*!*/ Decl; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(ExpandedType != null); + Contract.Invariant(Arguments != null); + Contract.Invariant(Decl != null); + } + + + public TypeSynonymAnnotation(IToken/*!*/ token, TypeSynonymDecl/*!*/ decl, List/*!*/ arguments) + : base(token) { + Contract.Requires(token != null); + Contract.Requires(decl != null); + Contract.Requires(arguments != null); + Contract.Requires(arguments.Count == decl.TypeParameters.Count); + this.Decl = decl; + this.Arguments = arguments; + + // build a substitution that can be applied to the definition of + // the type synonym + IDictionary/*!*/ subst = + new Dictionary(); + for (int i = 0; i < arguments.Count; ++i) + subst.Add(decl.TypeParameters[i], arguments[i]); + + ExpandedType = decl.Body.Substitute(subst); + } + + private TypeSynonymAnnotation(IToken/*!*/ token, TypeSynonymDecl/*!*/ decl, List/*!*/ arguments, + Type/*!*/ expandedType) + : base(token) { + Contract.Requires(token != null); + Contract.Requires(decl != null); + Contract.Requires(arguments != null); + Contract.Requires(expandedType != null); + + this.Decl = decl; + this.Arguments = arguments; + this.ExpandedType = expandedType; + } + + //----------- Cloning ---------------------------------- + // We implement our own clone-method, because bound type variables + // have to be created in the right way. It is /not/ ok to just clone + // everything recursively + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + List/*!*/ newArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + newArgs.Add(t.Clone(varMap)); + } + Type/*!*/ newExpandedType = ExpandedType.Clone(varMap); + Contract.Assert(newExpandedType != null); + return new TypeSynonymAnnotation(tok, Decl, newArgs, newExpandedType); + } + + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + List/*!*/ newArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + newArgs.Add(t.CloneUnresolved()); + } + return new TypeSynonymAnnotation(tok, Decl, newArgs); + } + + //----------- Equality ---------------------------------- + + [Pure] + public override bool Equals(Type/*!*/ that, + List/*!*/ thisBoundVariables, + List/*!*/ thatBoundVariables) { + //Contract.Requires(that != null); + //Contract.Requires(thisBoundVariables != null); + //Contract.Requires(thatBoundVariables != null); + return ExpandedType.Equals(that, thisBoundVariables, thatBoundVariables); + } + + // used to skip leading type annotations + internal override Type/*!*/ Expanded { + get { + Contract.Ensures(Contract.Result() != null); + + return ExpandedType.Expanded; + } + } + + //----------- Unification of types ----------- + + public override bool Unify(Type/*!*/ that, + List/*!*/ unifiableVariables, + IDictionary/*!*/ result) { + //Contract.Requires(that != null); + //Contract.Requires(unifiableVariables != null); + //Contract.Requires(cce.NonNullElements(result)); + return ExpandedType.Unify(that, unifiableVariables, result); + } + +#if OLD_UNIFICATION + public override void Unify(Type! that, + List! unifiableVariables, + List! thisBoundVariables, + List! thatBoundVariables, + IDictionary! result) { + ExpandedType.Unify(that, unifiableVariables, + thisBoundVariables, thatBoundVariables, result); + } +#endif + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + if (subst.Count == 0) + return this; + List newArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + newArgs.Add(t.Substitute(subst)); + } + Type/*!*/ newExpandedType = ExpandedType.Substitute(subst); + Contract.Assert(newExpandedType != null); + return new TypeSynonymAnnotation(tok, Decl, newArgs, newExpandedType); + } + + //----------- Hashcodes ---------------------------------- + + [Pure] + public override int GetHashCode(List boundVariables) { + //Contract.Requires(boundVariables != null); + return ExpandedType.GetHashCode(boundVariables); + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + //Contract.Requires(stream != null); + stream.SetToken(this); + CtorType.EmitCtorType(this.Decl.Name, Arguments, stream, contextBindingStrength); + } + + //----------- Resolution ---------------------------------- + + public override Type ResolveType(ResolutionContext rc) { + //Contract.Requires(rc != null); + Contract.Ensures(Contract.Result() != null); + List resolvedArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + resolvedArgs.Add(t.ResolveType(rc)); + } + return new TypeSynonymAnnotation(tok, Decl, resolvedArgs); + } + + public override List/*!*/ FreeVariables { + get { + Contract.Ensures(Contract.Result>() != null); + + return ExpandedType.FreeVariables; + } + } + + public override List/*!*/ FreeProxies { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return ExpandedType.FreeProxies; + } + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsBasic { + get { + return ExpandedType.IsBasic; + } + } + public override bool IsInt { + get { + return ExpandedType.IsInt; + } + } + public override bool IsReal + { + get + { + return ExpandedType.IsReal; + } + } + public override bool IsFloat + { + get + { + return ExpandedType.IsFloat; + } + } + public override bool IsBool { + get { + return ExpandedType.IsBool; + } + } + + public override bool IsVariable { + get { + return ExpandedType.IsVariable; + } + } + public override TypeVariable/*!*/ AsVariable { + get { + Contract.Ensures(Contract.Result() != null); + return ExpandedType.AsVariable; + } + } + public override bool IsCtor { + get { + return ExpandedType.IsCtor; + } + } + public override CtorType/*!*/ AsCtor { + get { + Contract.Ensures(Contract.Result() != null); + return ExpandedType.AsCtor; + } + } + public override bool IsMap { + get { + return ExpandedType.IsMap; + } + } + public override MapType/*!*/ AsMap { + get { + Contract.Ensures(Contract.Result() != null); + return ExpandedType.AsMap; + } + } + public override bool IsUnresolved { + get { + return ExpandedType.IsUnresolved; + } + } + public override UnresolvedTypeIdentifier/*!*/ AsUnresolved { + get { + Contract.Ensures(Contract.Result() != null); + + return ExpandedType.AsUnresolved; + } + } + + public override bool IsBv { + get { + return ExpandedType.IsBv; + } + } + public override int BvBits { + get { + return ExpandedType.BvBits; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitTypeSynonymAnnotation(this); + } + } + + //===================================================================== + + public class CtorType : Type { + public readonly List/*!*/ Arguments; + // is set during resolution and determines whether the right number of arguments is given + public readonly TypeCtorDecl/*!*/ Decl; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Arguments != null); + Contract.Invariant(Decl != null); + } + + + public CtorType(IToken/*!*/ token, TypeCtorDecl/*!*/ decl, List/*!*/ arguments) + : base(token) { + Contract.Requires(token != null); + Contract.Requires(decl != null); + Contract.Requires(arguments != null); + Contract.Requires(arguments.Count == decl.Arity); + this.Decl = decl; + this.Arguments = arguments; + } + + public bool IsDatatype() { + return QKeyValue.FindBoolAttribute(Decl.Attributes, "datatype"); + } + + //----------- Cloning ---------------------------------- + // We implement our own clone-method, because bound type variables + // have to be created in the right way. It is /not/ ok to just clone + // everything recursively + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + List/*!*/ newArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + newArgs.Add(t.Clone(varMap)); + } + return new CtorType(tok, Decl, newArgs); + } + + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + List/*!*/ newArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + newArgs.Add(t.CloneUnresolved()); + } + return new CtorType(tok, Decl, newArgs); + } + + //----------- Equality ---------------------------------- + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + Type thatType = that as Type; + if (thatType == null) + return false; + thatType = TypeProxy.FollowProxy(thatType.Expanded); + // shortcut + CtorType thatCtorType = thatType as CtorType; + if (thatCtorType == null || !this.Decl.Equals(thatCtorType.Decl)) + return false; + if (Arguments.Count == 0) + return true; + return base.Equals(thatType); + } + + [Pure] + public override bool Equals(Type/*!*/ that, + List/*!*/ thisBoundVariables, + List/*!*/ thatBoundVariables) { + that = TypeProxy.FollowProxy(that.Expanded); + CtorType thatCtorType = that as CtorType; + if (thatCtorType == null || !this.Decl.Equals(thatCtorType.Decl)) + return false; + for (int i = 0; i < Arguments.Count; ++i) { + if (!Arguments[i].Equals(thatCtorType.Arguments[i], + thisBoundVariables, thatBoundVariables)) + return false; + } + return true; + } + + //----------- Unification of types ----------- + + public override bool Unify(Type/*!*/ that, + List/*!*/ unifiableVariables, + IDictionary/*!*/ result) { + that = that.Expanded; + if (that is TypeProxy || that is TypeVariable) + return that.Unify(this, unifiableVariables, result); + + CtorType thatCtorType = that as CtorType; + if (thatCtorType == null || !thatCtorType.Decl.Equals(Decl)) { + return false; + } else { + bool good = true; + for (int i = 0; i < Arguments.Count; ++i) + good &= Arguments[i].Unify(thatCtorType.Arguments[i], unifiableVariables, result); + return good; + } + } + +#if OLD_UNIFICATION + public override void Unify(Type! that, + List! unifiableVariables, + List! thisBoundVariables, + List! thatBoundVariables, + IDictionary! result) { + that = that.Expanded; + if (that is TypeVariable) { + that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); + return; + } + + CtorType thatCtorType = that as CtorType; + if (thatCtorType == null || !thatCtorType.Decl.Equals(Decl)) + throw UNIFICATION_FAILED; + for (int i = 0; i < Arguments.Length; ++i) + Arguments[i].Unify(thatCtorType.Arguments[i], + unifiableVariables, + thisBoundVariables, thatBoundVariables, + result); + } +#endif + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + if (subst.Count == 0) + return this; + List newArgs = new List(); + lock (Arguments) + { + foreach (Type/*!*/ t in Arguments) + { + Contract.Assert(t != null); + newArgs.Add(t.Substitute(subst)); + } + } + return new CtorType(tok, Decl, newArgs); + } + + //----------- Hashcodes ---------------------------------- + + [Pure] + public override int GetHashCode(List boundVariables) { + //Contract.Requires(boundVariables != null); + int res = 1637643879 * Decl.GetHashCode(); + foreach (Type/*!*/ t in Arguments.ToArray()) { + Contract.Assert(t != null); + res = res * 3 + t.GetHashCode(boundVariables); + } + return res; + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + //Contract.Requires(stream != null); + stream.SetToken(this); + EmitCtorType(this.Decl.Name, Arguments, stream, contextBindingStrength); + } + + internal static void EmitCtorType(string name, List args, TokenTextWriter stream, int contextBindingStrength) { + Contract.Requires(stream != null); + Contract.Requires(args != null); + Contract.Requires(name != null); + int opBindingStrength = args.Count > 0 ? 0 : 2; + if (opBindingStrength < contextBindingStrength) + stream.Write("("); + + stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(name)); + int i = args.Count; + foreach (Type/*!*/ t in args) { + Contract.Assert(t != null); + stream.Write(" "); + // use a lower binding strength for the last argument + // to allow map-types without parentheses + t.Emit(stream, i == 1 ? 1 : 2); + i = i - 1; + } + + if (opBindingStrength < contextBindingStrength) + stream.Write(")"); + } + + //----------- Resolution ---------------------------------- + + public override Type ResolveType(ResolutionContext rc) { + //Contract.Requires(rc != null); + Contract.Ensures(Contract.Result() != null); + List resolvedArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + resolvedArgs.Add(t.ResolveType(rc)); + } + return new CtorType(tok, Decl, resolvedArgs); + } + + public override List/*!*/ FreeVariables { + get { + List/*!*/ res = new List(); + foreach (Type/*!*/ t in Arguments.ToArray()) { + Contract.Assert(t != null); + res.AppendWithoutDups(t.FreeVariables); + } + return res; + } + } + + public override List/*!*/ FreeProxies { + get { + List/*!*/ res = new List(); + foreach (Type/*!*/ t in Arguments.ToArray()) { + Contract.Assert(t != null); + AppendWithoutDups(res, t.FreeProxies); + } + return res; + } + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsCtor { + get { + return true; + } + } + public override CtorType/*!*/ AsCtor { + get { + return this; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitCtorType(this); + } + } + + //===================================================================== + + public class MapType : Type { + // an invariant is that each of the type parameters has to occur as + // free variable in at least one of the arguments + public readonly List/*!*/ TypeParameters; + public readonly List/*!*/ Arguments; + public Type/*!*/ Result; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(TypeParameters != null); + Contract.Invariant(Arguments != null); + Contract.Invariant(Result != null); + } + + + public MapType(IToken/*!*/ token, List/*!*/ typeParameters, List/*!*/ arguments, Type/*!*/ result) + : base(token) { + Contract.Requires(token != null); + Contract.Requires(typeParameters != null); + Contract.Requires(arguments != null); + Contract.Requires(result != null); + + this.TypeParameters = typeParameters; + this.Result = result; + this.Arguments = arguments; + } + + //----------- Cloning ---------------------------------- + // We implement our own clone-method, because bound type variables + // have to be created in the right way. It is /not/ ok to just clone + // everything recursively + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + IDictionary/*!*/ newVarMap = + new Dictionary(); + foreach (KeyValuePair p in varMap) { + Contract.Assert(cce.NonNullElements(p)); + if (!TypeParameters.Contains(p.Key)) + newVarMap.Add(p); + } + + List/*!*/ newTypeParams = new List(); + foreach (TypeVariable/*!*/ var in TypeParameters) { + Contract.Assert(var != null); + TypeVariable/*!*/ newVar = new TypeVariable(var.tok, var.Name); + Contract.Assert(newVar != null); + newVarMap.Add(var, newVar); + newTypeParams.Add(newVar); + } + + List/*!*/ newArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + newArgs.Add(t.Clone(newVarMap)); + } + Type/*!*/ newResult = Result.Clone(newVarMap); + Contract.Assert(newResult != null); + + return new MapType(this.tok, newTypeParams, newArgs, newResult); + } + + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + List/*!*/ newTypeParams = new List(); + foreach (TypeVariable/*!*/ var in TypeParameters) { + Contract.Assert(var != null); + TypeVariable/*!*/ newVar = new TypeVariable(var.tok, var.Name); + Contract.Assert(newVar != null); + newTypeParams.Add(newVar); + } + + List/*!*/ newArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + newArgs.Add(t.CloneUnresolved()); + } + Type/*!*/ newResult = Result.CloneUnresolved(); + Contract.Assert(newResult != null); + + return new MapType(this.tok, newTypeParams, newArgs, newResult); + } + + //----------- Equality ---------------------------------- + + [Pure] + public override bool Equals(Type/*!*/ that, + List/*!*/ thisBoundVariables, + List/*!*/ thatBoundVariables) + { + that = TypeProxy.FollowProxy(that.Expanded); + MapType thatMapType = that as MapType; + if (thatMapType == null || + this.TypeParameters.Count != thatMapType.TypeParameters.Count || + this.Arguments.Count != thatMapType.Arguments.Count) + return false; + + thisBoundVariables = thisBoundVariables.ToList(); + foreach (TypeVariable/*!*/ var in this.TypeParameters) + { + Contract.Assert(var != null); + thisBoundVariables.Add(var); + } + thatBoundVariables = thatBoundVariables.ToList(); + foreach (TypeVariable/*!*/ var in thatMapType.TypeParameters) + { + Contract.Assert(var != null); + thatBoundVariables.Add(var); + } + + for (int i = 0; i < Arguments.Count; ++i) + { + if (!Arguments[i].Equals(thatMapType.Arguments[i], + thisBoundVariables, thatBoundVariables)) + return false; + } + + return this.Result.Equals(thatMapType.Result, + thisBoundVariables, thatBoundVariables); + } + + //----------- Unification of types ----------- + + public override bool Unify(Type/*!*/ that, + List/*!*/ unifiableVariables, + IDictionary/*!*/ result) { + that = that.Expanded; + if (that is TypeProxy || that is TypeVariable) + return that.Unify(this, unifiableVariables, result); + + MapType thatMapType = that as MapType; + if (thatMapType == null || + this.TypeParameters.Count != thatMapType.TypeParameters.Count || + this.Arguments.Count != thatMapType.Arguments.Count) + return false; + + // treat the bound variables of the two map types as equal... + Dictionary/*!*/ subst0 = + new Dictionary(); + Dictionary/*!*/ subst1 = + new Dictionary(); + List freshies = new List(); + for (int i = 0; i < this.TypeParameters.Count; i++) { + TypeVariable tp0 = this.TypeParameters[i]; + TypeVariable tp1 = thatMapType.TypeParameters[i]; + TypeVariable freshVar = new TypeVariable(tp0.tok, tp0.Name); + freshies.Add(freshVar); + subst0.Add(tp0, freshVar); + subst1.Add(tp1, freshVar); + } + // ... and then unify the domain and range types + bool good = true; + for (int i = 0; i < this.Arguments.Count; i++) { + Type t0 = this.Arguments[i].Substitute(subst0); + Type t1 = thatMapType.Arguments[i].Substitute(subst1); + good &= t0.Unify(t1, unifiableVariables, result); + } + Type r0 = this.Result.Substitute(subst0); + Type r1 = thatMapType.Result.Substitute(subst1); + good &= r0.Unify(r1, unifiableVariables, result); + + // Finally, check that none of the bound variables has escaped + if (good && freshies.Count != 0) { + // This is done by looking for occurrences of the fresh variables in the + // non-substituted types ... + List freeVars = this.FreeVariables; + foreach (TypeVariable fr in freshies) + if (freeVars.Contains(fr)) { + return false; + } // fresh variable escaped + freeVars = thatMapType.FreeVariables; + foreach (TypeVariable fr in freshies) + if (freeVars.Contains(fr)) { + return false; + } // fresh variable escaped + + // ... and in the resulting unifier of type variables + foreach (KeyValuePair pair in result) { + Contract.Assert(cce.NonNullElements(pair)); + freeVars = pair.Value.FreeVariables; + foreach (TypeVariable fr in freshies) + if (freeVars.Contains(fr)) { + return false; + } // fresh variable escaped + } + } + + return good; + } + +#if OLD_UNIFICATION + public override void Unify(Type! that, + List! unifiableVariables, + List! thisBoundVariables, + List! thatBoundVariables, + IDictionary! result) { + that = that.Expanded; + if (that is TypeVariable) { + that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); + return; + } + + MapType thatMapType = that as MapType; + if (thatMapType == null || + this.TypeParameters.Length != thatMapType.TypeParameters.Length || + this.Arguments.Length != thatMapType.Arguments.Length) + throw UNIFICATION_FAILED; + + // ensure that no collisions occur + if (this.collisionsPossible(result)) { + ((MapType)this.Clone()) + .Unify(that, unifiableVariables, + thisBoundVariables, thatBoundVariables, result); + return; + } + if (thatMapType.collisionsPossible(result)) + thatMapType = (MapType)that.Clone(); + + foreach(TypeVariable/*!*/ var in this.TypeParameters){ +Contract.Assert(var != null); + thisBoundVariables.Add(var);} + foreach(TypeVariable/*!*/ var in thatMapType.TypeParameters){ +Contract.Assert(var != null); + thatBoundVariables.Add(var);} + + try { + + for (int i = 0; i < Arguments.Length; ++i) + Arguments[i].Unify(thatMapType.Arguments[i], + unifiableVariables, + thisBoundVariables, thatBoundVariables, + result); + Result.Unify(thatMapType.Result, + unifiableVariables, + thisBoundVariables, thatBoundVariables, + result); + + } finally { + // make sure that the bound variables are removed again + for (int i = 0; i < this.TypeParameters.Length; ++i) { + thisBoundVariables.Remove(); + thatBoundVariables.Remove(); + } + } + } +#endif + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + [Pure] + private bool collisionsPossible(IDictionary/*!*/ subst) { + Contract.Requires(cce.NonNullDictionaryAndValues(subst)); + // PR: could be written more efficiently + return TypeParameters.Any(param => subst.ContainsKey(param) || subst.Values.Any(val => val.FreeVariables.Contains(param))); + } + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + if (subst.Count == 0) + return this; + + // there are two cases in which we have to be careful: + // * a variable to be substituted is shadowed by a variable binder + // * a substituted term contains variables that are bound in the + // type (variable capture) + // + // in both cases, we first clone the type to ensure that bound + // variables are fresh + + if (collisionsPossible(subst)) { + MapType/*!*/ newType = (MapType)this.Clone(); + Contract.Assert(newType != null); + Contract.Assert(newType.Equals(this) && !newType.collisionsPossible(subst)); + return newType.Substitute(subst); + } + + List newArgs = new List(); + lock (Arguments) + { + foreach (Type/*!*/ t in Arguments) + { + Contract.Assert(t != null); + newArgs.Add(t.Substitute(subst)); + } + } + Type/*!*/ newResult = Result.Substitute(subst); + Contract.Assert(newResult != null); + + return new MapType(tok, TypeParameters, newArgs, newResult); + } + + //----------- Hashcodes ---------------------------------- + + [Pure] + public override int GetHashCode(List boundVariables) { + //Contract.Requires(boundVariables != null); + int res = 7643761 * TypeParameters.Count + 65121 * Arguments.Count; + + boundVariables = boundVariables.ToList(); + foreach (TypeVariable/*!*/ var in this.TypeParameters) { + Contract.Assert(var != null); + boundVariables.Add(var); + } + + foreach (Type/*!*/ t in Arguments.ToArray()) { + Contract.Assert(t != null); + res = res * 5 + t.GetHashCode(boundVariables); + } + res = res * 7 + Result.GetHashCode(boundVariables); + + return res; + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + //Contract.Requires(stream != null); + stream.SetToken(this); + + const int opBindingStrength = 1; + if (opBindingStrength < contextBindingStrength) + stream.Write("("); + + EmitOptionalTypeParams(stream, TypeParameters); + + stream.Write("["); + Arguments.Emit(stream, ","); // default binding strength of 0 is ok + stream.Write("]"); + Result.Emit(stream); // default binding strength of 0 is ok + + if (opBindingStrength < contextBindingStrength) + stream.Write(")"); + } + + //----------- Resolution ---------------------------------- + + public override Type ResolveType(ResolutionContext rc) { + //Contract.Requires(rc != null); + Contract.Ensures(Contract.Result() != null); + int previousState = rc.TypeBinderState; + try { + foreach (TypeVariable/*!*/ v in TypeParameters) { + Contract.Assert(v != null); + rc.AddTypeBinder(v); + } + + List resolvedArgs = new List(); + foreach (Type/*!*/ ty in Arguments) { + Contract.Assert(ty != null); + resolvedArgs.Add(ty.ResolveType(rc)); + } + + Type resolvedResult = Result.ResolveType(rc); + + CheckBoundVariableOccurrences(TypeParameters, + resolvedArgs, new List { resolvedResult }, + this.tok, "map arguments", + rc); + + // sort the type parameters so that they are bound in the order of occurrence + List/*!*/ sortedTypeParams = SortTypeParams(TypeParameters, resolvedArgs, resolvedResult); + Contract.Assert(sortedTypeParams != null); + return new MapType(tok, sortedTypeParams, resolvedArgs, resolvedResult); + } finally { + rc.TypeBinderState = previousState; + } + } + + public override List/*!*/ FreeVariables { + get { + List/*!*/ res = FreeVariablesIn(Arguments.ToList()); + Contract.Assert(res != null); + res.AppendWithoutDups(Result.FreeVariables); + foreach (TypeVariable/*!*/ v in TypeParameters.ToArray()) { + Contract.Assert(v != null); + res.Remove(v); + } + return res; + } + } + + public override List/*!*/ FreeProxies { + get { + List/*!*/ res = new List(); + foreach (Type/*!*/ t in Arguments.ToArray()) { + Contract.Assert(t != null); + AppendWithoutDups(res, t.FreeProxies); + } + AppendWithoutDups(res, Result.FreeProxies); + return res; + } + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsMap { + get { + return true; + } + } + public override MapType/*!*/ AsMap { + get { + return this; + } + } + public override int MapArity { + get { + return Arguments.Count; + } + } + + //------------ Match formal argument types of the map + //------------ on concrete types, substitute the result into the + //------------ result type. Null is returned if so many type checking + //------------ errors occur that the situation is hopeless + + public Type CheckArgumentTypes(List/*!*/ actualArgs, + out TypeParamInstantiation/*!*/ tpInstantiation, + IToken/*!*/ typeCheckingSubject, + string/*!*/ opName, + TypecheckingContext/*!*/ tc) { + Contract.Requires(actualArgs != null); + Contract.Requires(typeCheckingSubject != null); + + Contract.Requires(opName != null); + Contract.Requires(tc != null); +Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + List/*!*/ actualTypeParams; + List actualResult = + Type.CheckArgumentTypes(TypeParameters, out actualTypeParams, Arguments, actualArgs, + new List { Result }, null, typeCheckingSubject, opName, tc); + if (actualResult == null) { + tpInstantiation = SimpleTypeParamInstantiation.EMPTY; + return null; + } else { + Contract.Assert(actualResult.Count == 1); + tpInstantiation = SimpleTypeParamInstantiation.From(TypeParameters, actualTypeParams); + return actualResult[0]; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitMapType(this); + } + } + + //--------------------------------------------------------------------- + + public enum SimpleType { + Int, + Real, + Bool + }; + + + //===================================================================== + + // Interface for representing the instantiations of type parameters of + // polymorphic functions or maps. We introduce an own interface for this + // instead of using a simple list or dictionary, because in some cases + // (due to the type proxies for map types) the actual number and instantiation + // of type parameters can only be determined very late. + [ContractClass(typeof(TypeParamInstantiationContracts))] + public interface TypeParamInstantiation { + // return what formal type parameters there are + List/*!*/ FormalTypeParams { + get; + } + // given a formal type parameter, return the actual instantiation + Type/*!*/ this[TypeVariable/*!*/ var] { + get; + } + } + [ContractClassFor(typeof(TypeParamInstantiation))] + public abstract class TypeParamInstantiationContracts : TypeParamInstantiation { + #region TypeParamInstantiation Members + + public List FormalTypeParams { + + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + throw new NotImplementedException(); + } + } + + public Type this[TypeVariable var] { + get { + Contract.Requires(var != null); + Contract.Ensures(Contract.Result() != null); + + throw new NotImplementedException(); + } + } + + #endregion + } + + + public class SimpleTypeParamInstantiation : TypeParamInstantiation { + private readonly List/*!*/ TypeParams; + [ContractInvariantMethod] + void TypeParamsInvariantMethod() { + Contract.Invariant(cce.NonNullElements(TypeParams)); + } + private readonly IDictionary/*!*/ Instantiations; + [ContractInvariantMethod] + void InstantiationsInvariantMethod() { + Contract.Invariant(cce.NonNullDictionaryAndValues(Instantiations)); + } + + public SimpleTypeParamInstantiation(List/*!*/ typeParams, + IDictionary/*!*/ instantiations) { + Contract.Requires(cce.NonNullElements(typeParams)); + Contract.Requires(cce.NonNullDictionaryAndValues(instantiations)); + this.TypeParams = typeParams; + this.Instantiations = instantiations; + } + + public static TypeParamInstantiation/*!*/ From(List typeParams, List/*!*/ actualTypeParams) { + Contract.Requires(cce.NonNullElements(actualTypeParams)); + Contract.Requires(typeParams != null); + Contract.Requires(typeParams.Count == actualTypeParams.Count); + Contract.Ensures(Contract.Result() != null); + + if (typeParams.Count == 0) + return EMPTY; + + List/*!*/ typeParamList = new List(); + IDictionary/*!*/ dict = new Dictionary(); + for (int i = 0; i < typeParams.Count; ++i) { + typeParamList.Add(typeParams[i]); + dict.Add(typeParams[i], actualTypeParams[i]); + } + return new SimpleTypeParamInstantiation(typeParamList, dict); + } + + public static readonly TypeParamInstantiation EMPTY = + new SimpleTypeParamInstantiation(new List(), + new Dictionary()); + + // return what formal type parameters there are + public List/*!*/ FormalTypeParams { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return TypeParams; + } + } + // given a formal type parameter, return the actual instantiation + public Type/*!*/ this[TypeVariable/*!*/ var] { + get { + return Instantiations[var]; + } + } + } + + // Implementation of TypeParamInstantiation that refers to the current + // value of a MapTypeProxy. This means that the values return by the + // methods of this implementation can change in case the MapTypeProxy + // receives further unifications. + class MapTypeProxyParamInstantiation : TypeParamInstantiation { + private readonly MapTypeProxy/*!*/ Proxy; + + // the argument and result type of this particular usage of the map + // type. these are necessary to derive the values of the type parameters + private readonly List/*!*/ ArgumentsResult; + + // field that is initialised once all necessary information is available + // (the MapTypeProxy is instantiated to an actual type) and the instantiation + // of a type parameter is queried + private IDictionary Instantiations = null; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Proxy != null); + Contract.Invariant(ArgumentsResult != null); + Contract.Invariant(Instantiations == null || cce.NonNullDictionaryAndValues(Instantiations)); + } + + + public MapTypeProxyParamInstantiation(MapTypeProxy/*!*/ proxy, + List/*!*/ argumentsResult) { + Contract.Requires(proxy != null); + Contract.Requires(argumentsResult != null); + this.Proxy = proxy; + this.ArgumentsResult = argumentsResult; + } + + // return what formal type parameters there are + public List/*!*/ FormalTypeParams { + get { + MapType realType = Proxy.ProxyFor as MapType; + if (realType == null) + // no instantiation of the map type is known, which means + // that the map type is assumed to be monomorphic + return new List(); + else + return realType.TypeParameters.ToList(); + } + } + + // given a formal type parameter, return the actual instantiation + public Type/*!*/ this[TypeVariable/*!*/ var] { + get { + // then there has to be an instantiation that is a polymorphic map type + if (Instantiations == null) { + MapType realType = Proxy.ProxyFor as MapType; + Contract.Assert(realType != null); + List/*!*/ formalArgs = new List(); + foreach (Type/*!*/ t in realType.Arguments) { + Contract.Assert(t != null); + formalArgs.Add(t); + } + formalArgs.Add(realType.Result); + Instantiations = + Type.InferTypeParameters(realType.TypeParameters, formalArgs, ArgumentsResult); + } + return Instantiations[var]; + } + } + } } \ No newline at end of file diff --git a/Source/Core/AlphaEquality.cs b/Source/Core/AlphaEquality.cs index 1d4a1d95..986cc4bd 100644 --- a/Source/Core/AlphaEquality.cs +++ b/Source/Core/AlphaEquality.cs @@ -1,162 +1,162 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- - -using System.ComponentModel; - -namespace Microsoft.Boogie -{ - - using System; - using System.IO; - using System.Collections; - using System.Collections.Generic; - using System.Diagnostics; - using System.Diagnostics.Contracts; - - public class AlphaEquality : IEqualityComparer - { - private readonly DeBruijnRenamer deBruijn = new DeBruijnRenamer(); - - bool IEqualityComparer.Equals(Expr x, Expr y) { - var nx = deBruijn.Rename(x); - var ny = deBruijn.Rename(y); - return BinderExpr.EqualWithAttributesAndTriggers(nx, ny); - } - - int IEqualityComparer.GetHashCode(Expr obj) { - return 0; - // Best we can do because GetHashCode for Expression don't respect its equality. - // When it does, we can instead use: - // return deBruijn.Rename(obj).GetHashCode(); - } - - // Renames expressions into deBruijn indicies, such as - // (lambda x : int :: x + a) - // into - // (lambda bv#0 : int :: bv#0 + fv#0) - // It does not handle type variables yet, but it could be added. - // - // This class could be made public, but it is not since the Rename method - // could then leak FreeVariables out of here. - private class DeBruijnRenamer : Duplicator - { - - // Maps from index positions and types to new variables - private readonly TypeDict boundVars = - new TypeDict("bv", ti => new BoundVariable(Token.NoToken, ti)); - - private readonly TypeDict freeVars = - new TypeDict("fv", ti => new FreeVariable(ti)); - - // These three variables are reset at the beginning of every renaming - private int boundVarCount, freeVarCount; - private Dictionary freeVarMap; - - // Cached, previous results - private readonly Dictionary cache = new Dictionary(); - - public Expr Rename(Expr e) { - Expr ne; - if (!cache.TryGetValue(e, out ne)) { - boundVarCount = 0; - freeVarCount = 0; - freeVarMap = new Dictionary(); - - ne = VisitExpr(e); - cache[e] = ne; -#if DEBUG_ALPHA_RENAMING - var wr = new TokenTextWriter("", Console.Out, true); - Console.Write("nm( "); - e.Emit(wr); - Console.WriteLine(" )"); - Console.Write(" = "); - ne.Emit(wr); - Console.WriteLine(""); - Console.WriteLine("h = " + ne.GetHashCode()); -#endif - } - return ne; - } - - public override BinderExpr VisitBinderExpr(BinderExpr node) { - var subst = new Dictionary(); - var newBound = new List(); - foreach (var bv in node.Dummies) { - var bvNew = boundVars[boundVarCount++, bv.TypedIdent.Type]; - newBound.Add(bvNew); - subst[bv] = new IdentifierExpr(Token.NoToken, bvNew); - } - node.Dummies = this.VisitVariableSeq(newBound); - node.Body = this.VisitExpr(Substituter.Apply(Substituter.SubstitutionFromHashtable(subst), node.Body)); - return node; - } - - public override Variable VisitVariable(Variable node) { - FreeVariable fv; - var bv = node as BoundVariable; - if (boundVars.ContainsValue(bv)) { - return node; - } else if (freeVarMap.TryGetValue(node, out fv)) { - return fv; - } else { - return freeVarMap[node] = freeVars[freeVarCount++, node.TypedIdent.Type]; - } - } - - public override Expr VisitIdentifierExpr(IdentifierExpr node) { - var ie = (IdentifierExpr) base.VisitIdentifierExpr(node); - // Need to fix up the name, since IdentifierExpr's equality also checks the name - ie.Name = ie.Decl.TypedIdent.Name; - return ie; - } - - private class TypeDict - { - private readonly Dictionary, A> vars = new Dictionary, A>(); - - private readonly string Prefix; // either "bv" or "fv" - private readonly Func Mk; // either new BoundVar or new FreeVar - - public TypeDict(string prefix, Func mk) { - Prefix = prefix; - Mk = mk; - } - - // For debugging purposes, we create unique names when types differ, but the index are the same. - private int created = 0; - - // Make sure that this index and this type is always mapped to the same variable - public A this[int i, Type t] { - get { - A v; - if (!vars.TryGetValue(Tuple.Create(i, t), out v)) { - v = Mk(new TypedIdent(Token.NoToken, Prefix + i + "#" + created++, t)); - vars[Tuple.Create(i, t)] = v; - } - return v; - } - } - - public bool ContainsValue(A a) { - return vars.ContainsValue(a); - } - } - - private class FreeVariable : Variable - { - public FreeVariable(TypedIdent ti) : base(Token.NoToken, ti) {} - - public override bool IsMutable { - get { throw new cce.UnreachableException(); } - } - - public override void Register(ResolutionContext rc) { - throw new cce.UnreachableException(); - } - } - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- + +using System.ComponentModel; + +namespace Microsoft.Boogie +{ + + using System; + using System.IO; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + using System.Diagnostics.Contracts; + + public class AlphaEquality : IEqualityComparer + { + private readonly DeBruijnRenamer deBruijn = new DeBruijnRenamer(); + + bool IEqualityComparer.Equals(Expr x, Expr y) { + var nx = deBruijn.Rename(x); + var ny = deBruijn.Rename(y); + return BinderExpr.EqualWithAttributesAndTriggers(nx, ny); + } + + int IEqualityComparer.GetHashCode(Expr obj) { + return 0; + // Best we can do because GetHashCode for Expression don't respect its equality. + // When it does, we can instead use: + // return deBruijn.Rename(obj).GetHashCode(); + } + + // Renames expressions into deBruijn indicies, such as + // (lambda x : int :: x + a) + // into + // (lambda bv#0 : int :: bv#0 + fv#0) + // It does not handle type variables yet, but it could be added. + // + // This class could be made public, but it is not since the Rename method + // could then leak FreeVariables out of here. + private class DeBruijnRenamer : Duplicator + { + + // Maps from index positions and types to new variables + private readonly TypeDict boundVars = + new TypeDict("bv", ti => new BoundVariable(Token.NoToken, ti)); + + private readonly TypeDict freeVars = + new TypeDict("fv", ti => new FreeVariable(ti)); + + // These three variables are reset at the beginning of every renaming + private int boundVarCount, freeVarCount; + private Dictionary freeVarMap; + + // Cached, previous results + private readonly Dictionary cache = new Dictionary(); + + public Expr Rename(Expr e) { + Expr ne; + if (!cache.TryGetValue(e, out ne)) { + boundVarCount = 0; + freeVarCount = 0; + freeVarMap = new Dictionary(); + + ne = VisitExpr(e); + cache[e] = ne; +#if DEBUG_ALPHA_RENAMING + var wr = new TokenTextWriter("", Console.Out, true); + Console.Write("nm( "); + e.Emit(wr); + Console.WriteLine(" )"); + Console.Write(" = "); + ne.Emit(wr); + Console.WriteLine(""); + Console.WriteLine("h = " + ne.GetHashCode()); +#endif + } + return ne; + } + + public override BinderExpr VisitBinderExpr(BinderExpr node) { + var subst = new Dictionary(); + var newBound = new List(); + foreach (var bv in node.Dummies) { + var bvNew = boundVars[boundVarCount++, bv.TypedIdent.Type]; + newBound.Add(bvNew); + subst[bv] = new IdentifierExpr(Token.NoToken, bvNew); + } + node.Dummies = this.VisitVariableSeq(newBound); + node.Body = this.VisitExpr(Substituter.Apply(Substituter.SubstitutionFromHashtable(subst), node.Body)); + return node; + } + + public override Variable VisitVariable(Variable node) { + FreeVariable fv; + var bv = node as BoundVariable; + if (boundVars.ContainsValue(bv)) { + return node; + } else if (freeVarMap.TryGetValue(node, out fv)) { + return fv; + } else { + return freeVarMap[node] = freeVars[freeVarCount++, node.TypedIdent.Type]; + } + } + + public override Expr VisitIdentifierExpr(IdentifierExpr node) { + var ie = (IdentifierExpr) base.VisitIdentifierExpr(node); + // Need to fix up the name, since IdentifierExpr's equality also checks the name + ie.Name = ie.Decl.TypedIdent.Name; + return ie; + } + + private class TypeDict + { + private readonly Dictionary, A> vars = new Dictionary, A>(); + + private readonly string Prefix; // either "bv" or "fv" + private readonly Func Mk; // either new BoundVar or new FreeVar + + public TypeDict(string prefix, Func mk) { + Prefix = prefix; + Mk = mk; + } + + // For debugging purposes, we create unique names when types differ, but the index are the same. + private int created = 0; + + // Make sure that this index and this type is always mapped to the same variable + public A this[int i, Type t] { + get { + A v; + if (!vars.TryGetValue(Tuple.Create(i, t), out v)) { + v = Mk(new TypedIdent(Token.NoToken, Prefix + i + "#" + created++, t)); + vars[Tuple.Create(i, t)] = v; + } + return v; + } + } + + public bool ContainsValue(A a) { + return vars.ContainsValue(a); + } + } + + private class FreeVariable : Variable + { + public FreeVariable(TypedIdent ti) : base(Token.NoToken, ti) {} + + public override bool IsMutable { + get { throw new cce.UnreachableException(); } + } + + public override void Register(ResolutionContext rc) { + throw new cce.UnreachableException(); + } + } + } + } +} diff --git a/Source/Core/BoogiePL.atg b/Source/Core/BoogiePL.atg index 644a5d3d..091ceeb0 100644 --- a/Source/Core/BoogiePL.atg +++ b/Source/Core/BoogiePL.atg @@ -1,1511 +1,1511 @@ - -/*--------------------------------------------------------------------------- -// BoogiePL - -//--------------------------------------------------------------------------*/ - -/*using System;*/ -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Text; -using Microsoft.Boogie; -using Microsoft.Basetypes; -using Bpl = Microsoft.Boogie; - - -COMPILER BoogiePL - -/*--------------------------------------------------------------------------*/ - -readonly Program/*!*/ Pgm; - -readonly Expr/*!*/ dummyExpr; -readonly Cmd/*!*/ dummyCmd; -readonly Block/*!*/ dummyBlock; -readonly Bpl.Type/*!*/ dummyType; -readonly List/*!*/ dummyExprSeq; -readonly TransferCmd/*!*/ dummyTransferCmd; -readonly StructuredCmd/*!*/ dummyStructuredCmd; - -/// -///Returns the number of parsing errors encountered. If 0, "program" returns as -///the parsed program. -/// -public static int Parse (string/*!*/ filename, /*maybe null*/ List defines, out /*maybe null*/ Program program, bool useBaseName=false) /* throws System.IO.IOException */ { - Contract.Requires(filename != null); - Contract.Requires(cce.NonNullElements(defines,true)); - - if (defines == null) { - defines = new List(); - } - - if (filename == "stdin.bpl") { - var s = ParserHelper.Fill(Console.In, defines); - return Parse(s, filename, out program, useBaseName); - } else { - FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); - var s = ParserHelper.Fill(stream, defines); - var ret = Parse(s, filename, out program, useBaseName); - stream.Close(); - return ret; - } -} - - -public static int Parse (string s, string/*!*/ filename, out /*maybe null*/ Program program, bool useBaseName=false) /* throws System.IO.IOException */ { - Contract.Requires(s != null); - Contract.Requires(filename != null); - - byte[]/*!*/ buffer = cce.NonNull(UTF8Encoding.Default.GetBytes(s)); - MemoryStream ms = new MemoryStream(buffer,false); - Errors errors = new Errors(); - Scanner scanner = new Scanner(ms, errors, filename, useBaseName); - - Parser parser = new Parser(scanner, errors, false); - parser.Parse(); - if (parser.errors.count == 0) - { - program = parser.Pgm; - program.ProcessDatatypeConstructors(); - return 0; - } - else - { - program = null; - return parser.errors.count; - } -} - -public Parser(Scanner/*!*/ scanner, Errors/*!*/ errors, bool disambiguation) - : this(scanner, errors) -{ - // initialize readonly fields - Pgm = new Program(); - dummyExpr = new LiteralExpr(Token.NoToken, false); - dummyCmd = new AssumeCmd(Token.NoToken, dummyExpr); - dummyBlock = new Block(Token.NoToken, "dummyBlock", new List(), new ReturnCmd(Token.NoToken)); - dummyType = new BasicType(Token.NoToken, SimpleType.Bool); - dummyExprSeq = new List (); - dummyTransferCmd = new ReturnCmd(Token.NoToken); - dummyStructuredCmd = new BreakCmd(Token.NoToken, null); -} - -// Class to represent the bounds of a bitvector expression t[a:b]. -// Objects of this class only exist during parsing and are directly -// turned into BvExtract before they get anywhere else -private class BvBounds : Expr { - public BigNum Lower; - public BigNum Upper; - public BvBounds(IToken/*!*/ tok, BigNum lower, BigNum upper) - : base(tok) { - Contract.Requires(tok != null); - this.Lower = lower; - this.Upper = upper; - } - public override Bpl.Type/*!*/ ShallowType { get {Contract.Ensures(Contract.Result() != null); return Bpl.Type.Int; } } - public override void Resolve(ResolutionContext/*!*/ rc) { - // Contract.Requires(rc != null); - rc.Error(this, "bitvector bounds in illegal position"); - } - public override void Emit(TokenTextWriter/*!*/ stream, - int contextBindingStrength, bool fragileContext) { - Contract.Assert(false);throw new cce.UnreachableException(); - } - public override void ComputeFreeVariables(GSet/*!*/ freeVars) { Contract.Assert(false);throw new cce.UnreachableException(); } -} - -/*--------------------------------------------------------------------------*/ -CHARACTERS - letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". - digit = "0123456789". - special = "'~#$^_.?`". - glyph = "`~!@#$%^&*()-_=+[{]}|;:',<.>/?\\". - - cr = '\r'. - lf = '\n'. - tab = '\t'. - - space = ' '. - quote = '"'. - - newLine = cr + lf. - regularStringChar = ANY - quote - newLine. - - nondigit = letter + special. - nonquote = letter + digit + space + glyph. - - -/*------------------------------------------------------------------------*/ -TOKENS - ident = [ '\\' ] nondigit {nondigit | digit}. - bvlit = digit {digit} 'b' 'v' digit {digit}. - digits = digit {digit}. - - string = quote { regularStringChar | "\\\"" } quote. - - decimal = digit {digit} 'e' [ '-' ] digit {digit} . - float = digit {digit} '.' digit {digit} [ 'e' [ '-' ] digit {digit} ] . - -COMMENTS FROM "/*" TO "*/" NESTED -COMMENTS FROM "//" TO lf - -IGNORE cr + lf + tab - - -/*------------------------------------------------------------------------*/ -PRODUCTIONS - - -/*------------------------------------------------------------------------*/ -BoogiePL -= (. List/*!*/ vs; - List/*!*/ ds; - Axiom/*!*/ ax; - List/*!*/ ts; - Procedure/*!*/ pr; - Implementation im; - Implementation/*!*/ nnim; - .) - { Consts (. foreach(Bpl.Variable/*!*/ v in vs){ - Contract.Assert(v != null); - Pgm.AddTopLevelDeclaration(v); - } - .) - | Function (. foreach(Bpl.Declaration/*!*/ d in ds){ - Contract.Assert(d != null); - Pgm.AddTopLevelDeclaration(d); - } - .) - | Axiom (. Pgm.AddTopLevelDeclaration(ax); .) - | UserDefinedTypes (. foreach(Declaration/*!*/ td in ts){ - Contract.Assert(td != null); - Pgm.AddTopLevelDeclaration(td); - } - .) - | GlobalVars (. foreach(Bpl.Variable/*!*/ v in vs){ - Contract.Assert(v != null); - Pgm.AddTopLevelDeclaration(v); - } - .) - | Procedure (. Pgm.AddTopLevelDeclaration(pr); - if (im != null) { - Pgm.AddTopLevelDeclaration(im); - } - .) - | Implementation (. Pgm.AddTopLevelDeclaration(nnim); .) - } - EOF - . - -/*------------------------------------------------------------------------*/ -GlobalVars<.out List/*!*/ ds.> -= (. - Contract.Ensures(Contract.ValueAtReturn(out ds) != null); - QKeyValue kv = null; - ds = new List(); - var dsx = ds; - .) - "var" - { Attribute } - IdsTypeWheres ";" - . - -LocalVars<.List/*!*/ ds.> -= (. - Contract.Ensures(Contract.ValueAtReturn(out ds) != null); - QKeyValue kv = null; - .) - "var" - { Attribute } - IdsTypeWheres ";" - . - -ProcFormals<.bool incoming, bool allowWhereClauses, out List/*!*/ ds.> -= (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null); - ds = new List(); - var dsx = ds; - var context = allowWhereClauses ? "procedure formals" : "the 'implementation' copies of formals"; - .) - "(" - [ AttrsIdsTypeWheres - ] - ")" - . - -BoundVars<.IToken/*!*/ x, out List/*!*/ ds.> -= (. - Contract.Requires(x != null); - Contract.Ensures(Contract.ValueAtReturn(out ds) != null); - List/*!*/ tyds = new List(); - ds = new List(); - var dsx = ds; - .) - AttrsIdsTypeWheres - . - -/*------------------------------------------------------------------------*/ -/* IdsType is used with const declarations */ -IdsType<.out List/*!*/ tyds.> -= (. Contract.Ensures(Contract.ValueAtReturn(out tyds) != null); List/*!*/ ids; Bpl.Type/*!*/ ty; .) - Idents ":" Type - (. tyds = new List(); - foreach(Token/*!*/ id in ids){ - Contract.Assert(id != null); - tyds.Add(new TypedIdent(id, id.val, ty, null)); - } - .) - . - -/* AttrsIdsTypeWheres is used with the declarations of formals and bound variables */ -AttrsIdsTypeWheres<. bool allowAttributes, bool allowWhereClauses, string context, System.Action action .> -= - AttributesIdsTypeWhere - { "," AttributesIdsTypeWhere } - . - -IdsTypeWheres<. bool allowWhereClauses, string context, System.Action action .> -= - IdsTypeWhere - { "," IdsTypeWhere } - . - -AttributesIdsTypeWhere<. bool allowAttributes, bool allowWhereClauses, string context, System.Action action .> -= (. QKeyValue kv = null; .) - { Attribute (. if (!allowAttributes) { - kv = null; - this.SemErr("attributes are not allowed on " + context); - } - .) - } - IdsTypeWhere - . - -/* context is allowed to be null if allowWhereClauses is true */ -IdsTypeWhere<. bool allowWhereClauses, string context, System.Action action .> -= (. List/*!*/ ids; Bpl.Type/*!*/ ty; Expr wh = null; Expr/*!*/ nne; .) - Idents ":" Type - [ "where" Expression (. if (!allowWhereClauses) { - this.SemErr("where clause not allowed on " + context); - } else { - wh = nne; - } - .) - ] - (. foreach(Token/*!*/ id in ids){ - Contract.Assert(id != null); - action(new TypedIdent(id, id.val, ty, wh)); - } - .) - . - -/*------------------------------------------------------------------------*/ -Type -= (.Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken/*!*/ tok; ty = dummyType; .) - ( - TypeAtom - | - Ident (. List/*!*/ args = new List (); .) - [ TypeArgs ] (. ty = new UnresolvedTypeIdentifier (tok, tok.val, args); .) - | - MapType - ) - . - -TypeArgs<.List/*!*/ ts.> -= (.Contract.Requires(ts != null); IToken/*!*/ tok; Bpl.Type/*!*/ ty; .) - ( - TypeAtom (. ts.Add(ty); .) - [ TypeArgs ] - | - Ident (. List/*!*/ args = new List (); - ts.Add(new UnresolvedTypeIdentifier (tok, tok.val, args)); .) - [ TypeArgs ] - | - MapType (. ts.Add(ty); .) - ) - . - -TypeAtom -= (.Contract.Ensures(Contract.ValueAtReturn(out ty) != null); ty = dummyType; .) - ( "int" (. ty = new BasicType(t, SimpleType.Int); .) - | "real" (. ty = new BasicType(t, SimpleType.Real); .) - | "bool" (. ty = new BasicType(t, SimpleType.Bool); .) - /* note: bitvectors are handled in UnresolvedTypeIdentifier */ - | - "(" - Type - ")" - ) - . - -MapType -= (.Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken tok = null; - IToken/*!*/ nnTok; - List/*!*/ arguments = new List(); - Bpl.Type/*!*/ result; - List/*!*/ typeParameters = new List(); - .) - [ TypeParams (. tok = nnTok; .) ] - "[" (. if (tok == null) tok = t; .) - [ Types ] - "]" - Type - (. - ty = new MapType(tok, typeParameters, arguments, result); - .) - . - -TypeParams<.out IToken/*!*/ tok, out List/*!*/ typeParams.> -= (.Contract.Ensures(Contract.ValueAtReturn(out tok) != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); List/*!*/ typeParamToks; .) - "<" (. tok = t; .) - Idents - ">" - (. - typeParams = new List (); - foreach(Token/*!*/ id in typeParamToks){ - Contract.Assert(id != null); - typeParams.Add(new TypeVariable(id, id.val));} - .) - . - -Types<.List/*!*/ ts.> -= (. Contract.Requires(ts != null); Bpl.Type/*!*/ ty; .) - Type (. ts.Add(ty); .) - { "," Type (. ts.Add(ty); .) - } - . - - -/*------------------------------------------------------------------------*/ -Consts<.out List/*!*/ ds.> -= (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null); IToken/*!*/ y; List/*!*/ xs; - ds = new List(); - bool u = false; QKeyValue kv = null; - bool ChildrenComplete = false; - List Parents = null; .) - "const" (. y = t; .) - { Attribute } - [ "unique" (. u = true; .) - ] - IdsType - [ OrderSpec ] - (. bool makeClone = false; - foreach(TypedIdent/*!*/ x in xs){ - Contract.Assert(x != null); - - // ensure that no sharing is introduced - List ParentsClone; - if (makeClone && Parents != null) { - ParentsClone = new List (); - foreach (ConstantParent/*!*/ p in Parents){ - Contract.Assert(p != null); - ParentsClone.Add(new ConstantParent ( - new IdentifierExpr (p.Parent.tok, p.Parent.Name), - p.Unique));} - } else { - ParentsClone = Parents; - } - makeClone = true; - - ds.Add(new Constant(y, x, u, ParentsClone, ChildrenComplete, kv)); - } - .) - ";" - . - -OrderSpec<.out bool ChildrenComplete, out List Parents.> -= (.Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out Parents),true)); ChildrenComplete = false; - Parents = null; - bool u; - IToken/*!*/ parent; .) - "extends" (. Parents = new List (); - u = false; .) - [ - [ "unique" (. u = true; .) - ] - Ident (. Parents.Add(new ConstantParent ( - new IdentifierExpr(parent, parent.val), u)); .) - { - "," (. u = false; .) - [ "unique" (. u = true; .) - ] - Ident (. Parents.Add(new ConstantParent ( - new IdentifierExpr(parent, parent.val), u)); .) - } - ] - [ "complete" (. ChildrenComplete = true; .) - ] - . - -/*------------------------------------------------------------------------*/ -Function<.out List/*!*/ ds.> -= (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null); - ds = new List(); IToken/*!*/ z; - IToken/*!*/ typeParamTok; - var typeParams = new List(); - var arguments = new List(); - TypedIdent/*!*/ tyd; - TypedIdent retTyd = null; - Bpl.Type/*!*/ retTy; - QKeyValue argKv = null; - QKeyValue kv = null; - Expr definition = null; - Expr/*!*/ tmp; - .) - "function" { Attribute } Ident - [ TypeParams ] - "(" - [ VarOrType (. arguments.Add(new Formal(tyd.tok, tyd, true, argKv)); .) - { "," VarOrType (. arguments.Add(new Formal(tyd.tok, tyd, true, argKv)); .) - } ] ")" - (. argKv = null; .) - ( - "returns" "(" VarOrType ")" - | - ":" Type (. retTyd = new TypedIdent(retTy.tok, TypedIdent.NoName, retTy); .) - ) - ( "{" Expression (. definition = tmp; .) "}" | ";" ) - (. - if (retTyd == null) { - // construct a dummy type for the case of syntax error - retTyd = new TypedIdent(t, TypedIdent.NoName, new BasicType(t, SimpleType.Int)); - } - Function/*!*/ func = new Function(z, z.val, typeParams, arguments, - new Formal(retTyd.tok, retTyd, false, argKv), null, kv); - Contract.Assert(func != null); - ds.Add(func); - bool allUnnamed = true; - foreach(Formal/*!*/ f in arguments){ - Contract.Assert(f != null); - if (f.TypedIdent.HasName) { - allUnnamed = false; - break; - } - } - if (!allUnnamed) { - Bpl.Type prevType = null; - for (int i = arguments.Count; 0 <= --i; ) { - TypedIdent/*!*/ curr = cce.NonNull(arguments[i]).TypedIdent; - if (curr.HasName) { - // the argument was given as both an identifier and a type - prevType = curr.Type; - } else { - // the argument was given as just one "thing", which syntactically parsed as a type - if (prevType == null) { - this.errors.SemErr(curr.tok, "the type of the last parameter is unspecified"); - break; - } - Bpl.Type ty = curr.Type; - var uti = ty as UnresolvedTypeIdentifier; - if (uti != null && uti.Arguments.Count == 0) { - // the given "thing" was just an identifier, so let's use it as the name of the parameter - curr.Name = uti.Name; - curr.Type = prevType; - } else { - this.errors.SemErr(curr.tok, "expecting an identifier as parameter name"); - } - } - } - } - if (definition != null) { - // generate either an axiom or a function body - if (QKeyValue.FindBoolAttribute(kv, "inline")) { - func.Body = definition; - } else { - ds.Add(func.CreateDefinitionAxiom(definition, kv)); - } - } - .) - . - -VarOrType -= (. - Contract.Ensures(Contract.ValueAtReturn(out tyd) != null); - string/*!*/ varName = TypedIdent.NoName; - Bpl.Type/*!*/ ty; - IToken/*!*/ tok; - kv = null; - .) - { Attribute } - Type (. tok = ty.tok; .) - [ ":" (. var uti = ty as UnresolvedTypeIdentifier; - if (uti != null && uti.Arguments.Count == 0) { - varName = uti.Name; - } else { - this.SemErr("expected identifier before ':'"); - } - .) - Type - ] - (. tyd = new TypedIdent(tok, varName, ty); .) - . - -/*------------------------------------------------------------------------*/ -Axiom -= (.Contract.Ensures(Contract.ValueAtReturn(out m) != null); Expr/*!*/ e; QKeyValue kv = null; .) - "axiom" - { Attribute } - (. IToken/*!*/ x = t; .) - Proposition ";" (. m = new Axiom(x,e, null, kv); .) - . - -/*------------------------------------------------------------------------*/ -UserDefinedTypes<.out List/*!*/ ts.> -= (. Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out ts))); Declaration/*!*/ decl; QKeyValue kv = null; ts = new List (); .) - "type" - { Attribute } - UserDefinedType (. ts.Add(decl); .) - { "," UserDefinedType (. ts.Add(decl); .) } - ";" - . - -UserDefinedType -= (. Contract.Ensures(Contract.ValueAtReturn(out decl) != null); IToken/*!*/ id; List/*!*/ paramTokens = new List (); - Bpl.Type/*!*/ body = dummyType; bool synonym = false; .) - Ident - [ WhiteSpaceIdents ] - [ - "=" Type - (. synonym = true; .) - ] - (. - if (synonym) { - List/*!*/ typeParams = new List(); - foreach(Token/*!*/ t in paramTokens){ - Contract.Assert(t != null); - typeParams.Add(new TypeVariable(t, t.val));} - decl = new TypeSynonymDecl(id, id.val, typeParams, body, kv); - } else { - decl = new TypeCtorDecl(id, id.val, paramTokens.Count, kv); - } - .) - . - - -/*------------------------------------------------------------------------*/ -Procedure -= (. Contract.Ensures(Contract.ValueAtReturn(out proc) != null); IToken/*!*/ x; - List/*!*/ typeParams; - List/*!*/ ins, outs; - List/*!*/ pre = new List(); - List/*!*/ mods = new List(); - List/*!*/ post = new List(); - - List/*!*/ locals = new List(); - StmtList/*!*/ stmtList; - QKeyValue kv = null; - impl = null; - .) - - "procedure" - ProcSignature - ( ";" - { Spec } - | { Spec } - ImplBody - (. - impl = new Implementation(x, x.val, typeParams, - Formal.StripWhereClauses(ins), Formal.StripWhereClauses(outs), locals, stmtList, kv == null ? null : (QKeyValue)kv.Clone(), this.errors); - .) - ) - (. proc = new Procedure(x, x.val, typeParams, ins, outs, pre, mods, post, kv); .) - . - - -Implementation -= (. Contract.Ensures(Contract.ValueAtReturn(out impl) != null); IToken/*!*/ x; - List/*!*/ typeParams; - List/*!*/ ins, outs; - List/*!*/ locals; - StmtList/*!*/ stmtList; - QKeyValue kv; - .) - - "implementation" - ProcSignature - ImplBody - (. impl = new Implementation(x, x.val, typeParams, ins, outs, locals, stmtList, kv, this.errors); .) - . - - -ProcSignature<.bool allowWhereClausesOnFormals, out IToken/*!*/ name, out List/*!*/ typeParams, - out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv.> -= (. Contract.Ensures(Contract.ValueAtReturn(out name) != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); Contract.Ensures(Contract.ValueAtReturn(out ins) != null); Contract.Ensures(Contract.ValueAtReturn(out outs) != null); - IToken/*!*/ typeParamTok; typeParams = new List(); - outs = new List(); kv = null; .) - { Attribute } - Ident - [ TypeParams ] - ProcFormals - [ "returns" ProcFormals ] - . - - -Spec<.List/*!*/ pre, List/*!*/ mods, List/*!*/ post.> -= (.Contract.Requires(pre != null); Contract.Requires(mods != null); Contract.Requires(post != null); List/*!*/ ms; .) - ( "modifies" - [ Idents (. foreach(IToken/*!*/ m in ms){ - Contract.Assert(m != null); - mods.Add(new IdentifierExpr(m, m.val)); - } - .) - ] ";" - | "free" SpecPrePost - | SpecPrePost - ) - . - -SpecPrePost<.bool free, List/*!*/ pre, List/*!*/ post.> -= (. Contract.Requires(pre != null); Contract.Requires(post != null); Expr/*!*/ e; Token tok = null; QKeyValue kv = null; .) - ( "requires" (. tok = t; .) - { Attribute } - Proposition ";" (. pre.Add(new Requires(tok, free, e, null, kv)); .) - | "ensures" (. tok = t; .) - { Attribute } - Proposition ";" (. post.Add(new Ensures(tok, free, e, null, kv)); .) - ) - . - -/*------------------------------------------------------------------------*/ - -ImplBody<.out List/*!*/ locals, out StmtList/*!*/ stmtList.> -= (. Contract.Ensures(Contract.ValueAtReturn(out locals) != null); Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); locals = new List(); .) - "{" - { LocalVars } - StmtList - . - -/* the StmtList also reads the final curly brace */ -StmtList -= (. Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); List bigblocks = new List(); - /* built-up state for the current BigBlock: */ - IToken startToken = null; string currentLabel = null; - List cs = null; /* invariant: startToken != null ==> cs != null */ - /* temporary variables: */ - IToken label; Cmd c; BigBlock b; - StructuredCmd ec = null; StructuredCmd/*!*/ ecn; - TransferCmd tc = null; TransferCmd/*!*/ tcn; - .) - - { - ( LabelOrCmd - (. if (c != null) { - // LabelOrCmd read a Cmd - Contract.Assert(label == null); - if (startToken == null) { startToken = c.tok; cs = new List(); } - Contract.Assert(cs != null); - cs.Add(c); - } else { - // LabelOrCmd read a label - Contract.Assert(label != null); - if (startToken != null) { - Contract.Assert(cs != null); - // dump the built-up state into a BigBlock - b = new BigBlock(startToken, currentLabel, cs, null, null); - bigblocks.Add(b); - cs = null; - } - startToken = label; - currentLabel = label.val; - cs = new List(); - } - .) - - | StructuredCmd - (. ec = ecn; - if (startToken == null) { startToken = ec.tok; cs = new List(); } - Contract.Assert(cs != null); - b = new BigBlock(startToken, currentLabel, cs, ec, null); - bigblocks.Add(b); - startToken = null; currentLabel = null; cs = null; - .) - - | TransferCmd - (. tc = tcn; - if (startToken == null) { startToken = tc.tok; cs = new List(); } - Contract.Assert(cs != null); - b = new BigBlock(startToken, currentLabel, cs, null, tc); - bigblocks.Add(b); - startToken = null; currentLabel = null; cs = null; - .) - - ) - } - "}" - (. IToken/*!*/ endCurly = t; - if (startToken == null && bigblocks.Count == 0) { - startToken = t; cs = new List(); - } - if (startToken != null) { - Contract.Assert(cs != null); - b = new BigBlock(startToken, currentLabel, cs, null, null); - bigblocks.Add(b); - } - - stmtList = new StmtList(bigblocks, endCurly); - .) - . - -TransferCmd -= (. Contract.Ensures(Contract.ValueAtReturn(out tc) != null); tc = dummyTransferCmd; - Token y; List/*!*/ xs; - List ss = new List(); - .) - ( "goto" (. y = t; .) - Idents (. foreach(IToken/*!*/ s in xs){ - Contract.Assert(s != null); - ss.Add(s.val); } - tc = new GotoCmd(y, ss); - .) - | "return" (. tc = new ReturnCmd(t); .) - ) ";" - . - -StructuredCmd -= (. Contract.Ensures(Contract.ValueAtReturn(out ec) != null); ec = dummyStructuredCmd; Contract.Assume(cce.IsPeerConsistent(ec)); - IfCmd/*!*/ ifcmd; WhileCmd/*!*/ wcmd; BreakCmd/*!*/ bcmd; - .) - ( IfCmd (. ec = ifcmd; .) - | WhileCmd (. ec = wcmd; .) - | BreakCmd (. ec = bcmd; .) - ) - . - -IfCmd -= (. Contract.Ensures(Contract.ValueAtReturn(out ifcmd) != null); IToken/*!*/ x; - Expr guard; - StmtList/*!*/ thn; - IfCmd/*!*/ elseIf; IfCmd elseIfOption = null; - StmtList/*!*/ els; StmtList elseOption = null; - .) - "if" (. x = t; .) - Guard - "{" StmtList - [ "else" - ( IfCmd (. elseIfOption = elseIf; .) - | "{" - StmtList (. elseOption = els; .) - ) - ] - (. ifcmd = new IfCmd(x, guard, thn, elseIfOption, elseOption); .) - . - -WhileCmd -= (. Contract.Ensures(Contract.ValueAtReturn(out wcmd) != null); IToken/*!*/ x; Token z; - Expr guard; Expr/*!*/ e; bool isFree; - List invariants = new List(); - StmtList/*!*/ body; - QKeyValue kv = null; - .) - "while" (. x = t; .) - Guard (. Contract.Assume(guard == null || cce.Owner.None(guard)); .) - { (. isFree = false; z = la/*lookahead token*/; .) - [ "free" (. isFree = true; .) - ] - "invariant" - { Attribute } - Expression (. if (isFree) { - invariants.Add(new AssumeCmd(z, e, kv)); - } else { - invariants.Add(new AssertCmd(z, e, kv)); - } - kv = null; - .) - ";" - } - "{" - StmtList (. wcmd = new WhileCmd(x, guard, invariants, body); .) - . - -Guard -= (. Expr/*!*/ ee; e = null; .) - "(" - ( "*" (. e = null; .) - | Expression (. e = ee; .) - ) - ")" - . - -BreakCmd -= (.Contract.Ensures(Contract.ValueAtReturn(out bcmd) != null); IToken/*!*/ x; IToken/*!*/ y; - string breakLabel = null; - .) - "break" (. x = t; .) - [ Ident (. breakLabel = y.val; .) - ] ";" (. bcmd = new BreakCmd(x, breakLabel); .) - . - -/*------------------------------------------------------------------------*/ - -LabelOrCmd -/* ensures (c == null) != (label != null) */ -= (. IToken/*!*/ x; Expr/*!*/ e; - List/*!*/ xs; - List ids; - c = dummyCmd; label = null; - Cmd/*!*/ cn; - QKeyValue kv = null; - .) - ( LabelOrAssign - | "assert" (. x = t; .) - { Attribute } - Proposition (. c = new AssertCmd(x, e, kv); .) - ";" - | "assume" (. x = t; .) - { Attribute } - Proposition (. c = new AssumeCmd(x, e, kv); .) - ";" - | "havoc" (. x = t; .) - Idents ";" (. ids = new List(); - foreach(IToken/*!*/ y in xs){ - Contract.Assert(y != null); - ids.Add(new IdentifierExpr(y, y.val)); - } - c = new HavocCmd(x,ids); - .) - | CallCmd ";" (. c = cn; .) - | ParCallCmd (. c = cn; .) - | "yield" (. x = t; .) - ";" (. c = new YieldCmd(x); .) - ) - . - -/*------------------------------------------------------------------------*/ - -LabelOrAssign -/* ensures (c == null) != (label != null) */ -= (. IToken/*!*/ id; IToken/*!*/ x, y; Expr/*!*/ e0; - c = dummyCmd; label = null; - AssignLhs/*!*/ lhs; - List/*!*/ lhss; - List/*!*/ rhss; - List/*!*/ indexes; - .) - Ident (. x = t; .) - ( ":" (. c = null; label = x; .) - - | (. lhss = new List(); .) - (. lhs = new SimpleAssignLhs(id, new IdentifierExpr(id, id.val)); .) - - { MapAssignIndex (. lhs = new MapAssignLhs(y, lhs, indexes); .) } - (. lhss.Add(lhs); .) - - { "," - Ident - (. lhs = new SimpleAssignLhs(id, new IdentifierExpr(id, id.val)); .) - { MapAssignIndex (. lhs = new MapAssignLhs(y, lhs, indexes); .) } - (. lhss.Add(lhs); .) - } - - ":=" (. x = t; /* use location of := */ .) - Expression (. rhss = new List (); - rhss.Add(e0); .) - { "," - Expression (. rhss.Add(e0); .) - } - ";" (. c = new AssignCmd(x, lhss, rhss); .) - ) - . - -MapAssignIndex<.out IToken/*!*/ x, out List/*!*/ indexes.> -= (.Contract.Ensures(Contract.ValueAtReturn(out x) != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out indexes))); indexes = new List (); - Expr/*!*/ e; - .) - "[" (. x = t; .) - [ - Expression (. indexes.Add(e); .) - { "," - Expression (. indexes.Add(e); .) - } - ] - "]" - . - -/*------------------------------------------------------------------------*/ -CallCmd -= (. Contract.Ensures(Contract.ValueAtReturn(out c) != null); - IToken x; - bool isAsync = false; - bool isFree = false; - QKeyValue kv = null; - c = null; - .) - [ "async" (. isAsync = true; .) - ] - [ "free" (. isFree = true; .) - ] - "call" (. x = t; .) - { Attribute } - CallParams (. .) - . - -ParCallCmd -= (. Contract.Ensures(Contract.ValueAtReturn(out d) != null); - IToken x; - QKeyValue kv = null; - Cmd c = null; - List callCmds = new List(); - .) - "par" (. x = t; .) - { Attribute } - CallParams (. callCmds.Add((CallCmd)c); .) - { "|" CallParams (. callCmds.Add((CallCmd)c); .) - } - ";" (. d = new ParCallCmd(x, callCmds, kv); .) - . - -CallParams -= (. - List ids = new List(); - List es = new List(); - Expr en; - IToken first; - IToken p; - c = null; - .) - Ident - ( "(" - [ Expression (. es.Add(en); .) - { "," Expression (. es.Add(en); .) - } - ] - ")" (. c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync; .) - | - (. ids.Add(new IdentifierExpr(first, first.val)); .) - [ "," Ident (. ids.Add(new IdentifierExpr(p, p.val)); .) - { "," Ident (. ids.Add(new IdentifierExpr(p, p.val)); .) - } - ] ":=" - Ident "(" - [ Expression (. es.Add(en); .) - { "," Expression (. es.Add(en); .) - } - ] - ")" (. c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync; .) - ) - . - -/*------------------------------------------------------------------------*/ -Proposition -=(.Contract.Ensures(Contract.ValueAtReturn(out e) != null);.) - Expression - . - -/*------------------------------------------------------------------------*/ -Idents<.out List/*!*/ xs.> -= (.Contract.Ensures(Contract.ValueAtReturn(out xs) != null); IToken/*!*/ id; xs = new List(); .) - Ident (. xs.Add(id); .) - { "," Ident (. xs.Add(id); .) - } - . - -/*------------------------------------------------------------------------*/ -WhiteSpaceIdents<.out List/*!*/ xs.> -= (. Contract.Ensures(Contract.ValueAtReturn(out xs) != null); IToken/*!*/ id; xs = new List(); .) - Ident (. xs.Add(id); .) - { Ident (. xs.Add(id); .) - } - . - -/*------------------------------------------------------------------------*/ -Expressions<.out List/*!*/ es.> -= (. Contract.Ensures(Contract.ValueAtReturn(out es) != null); Expr/*!*/ e; es = new List(); .) - Expression (. es.Add(e); .) - { "," Expression (. es.Add(e); .) - } - . - -/*------------------------------------------------------------------------*/ -Expression<.out Expr/*!*/ e0.> -= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) - ImpliesExpression - { EquivOp (. x = t; .) - ImpliesExpression - (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Iff, e0, e1); .) - } - . - -EquivOp = "<==>" | '\u21d4'. - -/*------------------------------------------------------------------------*/ -ImpliesExpression -= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) - LogicalExpression - [ - ImpliesOp (. x = t; .) - /* recurse because implication is right-associative */ - ImpliesExpression - (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e0, e1); .) - | - ExpliesOp (. if (noExplies) - this.SemErr("illegal mixture of ==> and <==, use parentheses to disambiguate"); - x = t; .) - LogicalExpression - (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e1, e0); .) - /* loop because explies is left-associative */ - { - ExpliesOp (. x = t; .) - LogicalExpression - (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e1, e0); .) - } - ] - . - -ImpliesOp = "==>" | '\u21d2'. -ExpliesOp = "<==" | '\u21d0'. - -/*------------------------------------------------------------------------*/ -LogicalExpression -= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) - RelationalExpression - [ AndOp (. x = t; .) - RelationalExpression - (. e0 = Expr.Binary(x, BinaryOperator.Opcode.And, e0, e1); .) - { AndOp (. x = t; .) - RelationalExpression - (. e0 = Expr.Binary(x, BinaryOperator.Opcode.And, e0, e1); .) - } - | OrOp (. x = t; .) - RelationalExpression - (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Or, e0, e1); .) - { OrOp (. x = t; .) - RelationalExpression - (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Or, e0, e1); .) - } - ] - . - -AndOp = "&&" | '\u2227'. -OrOp = "||" | '\u2228'. - -/*------------------------------------------------------------------------*/ -RelationalExpression -= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .) - BvTerm - [ RelOp - BvTerm (. e0 = Expr.Binary(x, op, e0, e1); .) - ] - . - -RelOp -= (.Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/; .) - ( "==" (. x = t; op=BinaryOperator.Opcode.Eq; .) - | "<" (. x = t; op=BinaryOperator.Opcode.Lt; .) - | ">" (. x = t; op=BinaryOperator.Opcode.Gt; .) - | "<=" (. x = t; op=BinaryOperator.Opcode.Le; .) - | ">=" (. x = t; op=BinaryOperator.Opcode.Ge; .) - | "!=" (. x = t; op=BinaryOperator.Opcode.Neq; .) - | "<:" (. x = t; op=BinaryOperator.Opcode.Subtype; .) - | '\u2260' (. x = t; op=BinaryOperator.Opcode.Neq; .) - | '\u2264' (. x = t; op=BinaryOperator.Opcode.Le; .) - | '\u2265' (. x = t; op=BinaryOperator.Opcode.Ge; .) - ) - . - -/*------------------------------------------------------------------------*/ -BvTerm -= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) - Term - { "++" (. x = t; .) - Term (. e0 = new BvConcatExpr(x, e0, e1); .) - } - . - - -/*------------------------------------------------------------------------*/ -Term -= (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .) - Factor - { AddOp - Factor (. e0 = Expr.Binary(x, op, e0, e1); .) - } - . - -AddOp -= (.Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/; .) - ( "+" (. x = t; op=BinaryOperator.Opcode.Add; .) - | "-" (. x = t; op=BinaryOperator.Opcode.Sub; .) - ) - . - -/*------------------------------------------------------------------------*/ -Factor -= (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .) - Power - { MulOp - Power (. e0 = Expr.Binary(x, op, e0, e1); .) - } - . - -MulOp -= (. Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/; .) - ( "*" (. x = t; op=BinaryOperator.Opcode.Mul; .) - | "div" (. x = t; op=BinaryOperator.Opcode.Div; .) - | "mod" (. x = t; op=BinaryOperator.Opcode.Mod; .) - | "/" (. x = t; op=BinaryOperator.Opcode.RealDiv; .) - ) - . - -/*------------------------------------------------------------------------*/ -Power -= (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) - UnaryExpression - [ - "**" (. x = t; .) - /* recurse because exponentation is right-associative */ - Power (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Pow, e0, e1); .) - ] - . - -/*------------------------------------------------------------------------*/ -UnaryExpression -= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; - e = dummyExpr; - .) - ( "-" (. x = t; .) - UnaryExpression (. e = Expr.Unary(x, UnaryOperator.Opcode.Neg, e); .) - | NegOp (. x = t; .) - UnaryExpression (. e = Expr.Unary(x, UnaryOperator.Opcode.Not, e); .) - | CoercionExpression - ) - . - -NegOp = "!" | '\u00ac'. - -/*------------------------------------------------------------------------*/ - -/* This production creates ambiguities, because types can start with "<" - (polymorphic map types), but can also be followed by "<" (inequalities). - Coco deals with these ambiguities in a reasonable way by preferring to read - further types (type arguments) over relational symbols. E.g., "5 : C < 0" - will cause a parse error because "<" is treated as the beginning of a - map type. */ - -CoercionExpression -= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; - Bpl.Type/*!*/ coercedTo; - BigNum bn; - .) - ArrayExpression - { ":" (. x = t; .) - ( - Type (. e = Expr.CoerceType(x, e, coercedTo); .) - | - Nat /* This means that we really look at a bitvector - expression t[a:b] */ - (. if (!(e is LiteralExpr) || !((LiteralExpr)e).isBigNum) { - this.SemErr("arguments of extract need to be integer literals"); - e = new BvBounds(x, bn, BigNum.ZERO); - } else { - e = new BvBounds(x, bn, ((LiteralExpr)e).asBigNum); - } - .) - ) - } - . - -/*------------------------------------------------------------------------*/ -ArrayExpression -= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; - Expr/*!*/ index0 = dummyExpr; Expr/*!*/ e1; - bool store; bool bvExtract; - List/*!*/ allArgs = dummyExprSeq; - .) - AtomExpression - { "[" (. x = t; allArgs = new List (); - allArgs.Add(e); - store = false; bvExtract = false; .) - [ - Expression - (. if (index0 is BvBounds) - bvExtract = true; - else - allArgs.Add(index0); - .) - { "," Expression - (. if (bvExtract || e1 is BvBounds) - this.SemErr("bitvectors only have one dimension"); - allArgs.Add(e1); - .) - } - [ ":=" Expression - (. if (bvExtract || e1 is BvBounds) - this.SemErr("assignment to bitvectors is not possible"); - allArgs.Add(e1); store = true; - .) - ] - | ":=" Expression (. allArgs.Add(e1); store = true; .) - ] - "]" - (. if (store) - e = new NAryExpr(x, new MapStore(x, allArgs.Count - 2), allArgs); - else if (bvExtract) - e = new BvExtractExpr(x, e, - ((BvBounds)index0).Upper.ToIntSafe, - ((BvBounds)index0).Lower.ToIntSafe); - else - e = new NAryExpr(x, new MapSelect(x, allArgs.Count - 1), allArgs); - .) - } - . - - -/*------------------------------------------------------------------------*/ -AtomExpression -= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; int n; BigNum bn; BigDec bd; - List/*!*/ es; List/*!*/ ds; Trigger trig; - List/*!*/ typeParams; - IdentifierExpr/*!*/ id; - QKeyValue kv; - e = dummyExpr; - List/*!*/ locals; - List/*!*/ blocks; - .) - ( "false" (. e = new LiteralExpr(t, false); .) - | "true" (. e = new LiteralExpr(t, true); .) - | Nat (. e = new LiteralExpr(t, bn); .) - | Dec (. e = new LiteralExpr(t, bd); .) - | BvLit (. e = new LiteralExpr(t, bn, n); .) - - | Ident (. id = new IdentifierExpr(x, x.val); e = id; .) - [ "(" - ( Expressions (. e = new NAryExpr(x, new FunctionCall(id), es); .) - | /* empty */ (. e = new NAryExpr(x, new FunctionCall(id), new List()); .) - ) - ")" - ] - - | "old" (. x = t; .) - "(" - Expression - ")" (. e = new OldExpr(x, e); .) - - | "int" (. x = t; .) - "(" - Expression - ")" (. e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToInt), new List{ e }); .) - - | "real" (. x = t; .) - "(" - Expression - ")" (. e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToReal), new List{ e }); .) - - | "(" ( Expression (. if (e is BvBounds) - this.SemErr("parentheses around bitvector bounds " + - "are not allowed"); .) - | Forall (. x = t; .) - QuantifierBody - (. if (typeParams.Count + ds.Count > 0) - e = new ForallExpr(x, typeParams, ds, kv, trig, e); .) - | Exists (. x = t; .) - QuantifierBody - (. if (typeParams.Count + ds.Count > 0) - e = new ExistsExpr(x, typeParams, ds, kv, trig, e); .) - | Lambda (. x = t; .) - QuantifierBody - (. if (trig != null) - SemErr("triggers not allowed in lambda expressions"); - if (typeParams.Count + ds.Count > 0) - e = new LambdaExpr(x, typeParams, ds, kv, e); .) - ) - ")" - | IfThenElseExpression - | CodeExpression (. e = new CodeExpr(locals, blocks); .) - ) - . - -CodeExpression<.out List/*!*/ locals, out List/*!*/ blocks.> -= (. Contract.Ensures(Contract.ValueAtReturn(out locals) != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out blocks))); locals = new List(); Block/*!*/ b; - blocks = new List(); - .) - "|{" - { LocalVars } - SpecBlock (. blocks.Add(b); .) - { SpecBlock (. blocks.Add(b); .) - } - "}|" - . - -SpecBlock -= (. Contract.Ensures(Contract.ValueAtReturn(out b) != null); IToken/*!*/ x; IToken/*!*/ y; - Cmd c; IToken label; - List cs = new List(); - List/*!*/ xs; - List ss = new List(); - b = dummyBlock; - Expr/*!*/ e; - .) - Ident ":" - { LabelOrCmd - (. if (c != null) { - Contract.Assert(label == null); - cs.Add(c); - } else { - Contract.Assert(label != null); - SemErr("SpecBlock's can only have one label"); - } - .) - } - ( "goto" (. y = t; .) - Idents (. foreach(IToken/*!*/ s in xs){ - Contract.Assert(s != null); - ss.Add(s.val); } - b = new Block(x,x.val,cs,new GotoCmd(y,ss)); - .) - | "return" Expression - (. b = new Block(x,x.val,cs,new ReturnExprCmd(t,e)); .) - ) - ";" - . - -Attribute -= (. Trigger trig = null; .) - AttributeOrTrigger (. if (trig != null) this.SemErr("only attributes, not triggers, allowed here"); .) -. - -AttributeOrTrigger -= (. IToken/*!*/ tok; Expr/*!*/ e; List/*!*/ es; - string key; - List parameters; object/*!*/ param; - .) - "{" (. tok = t; .) - ( - ":" ident (. key = t.val; parameters = new List(); .) - [ AttributeParameter (. parameters.Add(param); .) - { "," AttributeParameter (. parameters.Add(param); .) - } - ] - (. if (key == "nopats") { - if (parameters.Count == 1 && parameters[0] is Expr) { - e = (Expr)parameters[0]; - if(trig==null){ - trig = new Trigger(tok, false, new List { e }, null); - } else { - trig.AddLast(new Trigger(tok, false, new List { e }, null)); - } - } else { - this.SemErr("the 'nopats' quantifier attribute expects a string-literal parameter"); - } - } else { - if (kv==null) { - kv = new QKeyValue(tok, key, parameters, null); - } else { - kv.AddLast(new QKeyValue(tok, key, parameters, null)); - } - } - .) - | - Expression (. es = new List { e }; .) - { "," Expression (. es.Add(e); .) - } (. if (trig==null) { - trig = new Trigger(tok, true, es, null); - } else { - trig.AddLast(new Trigger(tok, true, es, null)); - } - .) - ) - "}" - . - -AttributeParameter -= (. Contract.Ensures(Contract.ValueAtReturn(out o) != null); - o = "error"; - Expr/*!*/ e; - .) - ( string (. o = t.val.Substring(1, t.val.Length-2); .) - | Expression (. o = e; .) - ) - . - -IfThenElseExpression -= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); - IToken/*!*/ tok; - Expr/*!*/ e0, e1, e2; - e = dummyExpr; .) - "if" (. tok = t; .) Expression "then" Expression "else" Expression - (. e = new NAryExpr(tok, new IfThenElse(tok), new List{ e0, e1, e2 }); .) - . - - -QuantifierBody<.IToken/*!*/ q, out List/*!*/ typeParams, out List/*!*/ ds, - out QKeyValue kv, out Trigger trig, out Expr/*!*/ body.> -= (. Contract.Requires(q != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); Contract.Ensures(Contract.ValueAtReturn(out ds) != null); Contract.Ensures(Contract.ValueAtReturn(out body) != null); - trig = null; typeParams = new List (); - IToken/*!*/ tok; - kv = null; - ds = new List (); - .) - ( - TypeParams - [ BoundVars ] - | - BoundVars - ) - QSep - { AttributeOrTrigger } - Expression - . - -Forall = "forall" | '\u2200'. -Exists = "exists" | '\u2203'. -Lambda = "lambda" | '\u03bb'. -QSep = "::" | '\u2022'. - -/*------------------------------------------------------------------------*/ -Ident -=(.Contract.Ensures(Contract.ValueAtReturn(out x) != null);.) - ident (. x = t; - if (x.val.StartsWith("\\")) - x.val = x.val.Substring(1); - .) - . - -/*------------------------------------------------------------------------*/ -Nat -= - digits - (. try { - n = BigNum.FromString(t.val); - } catch (FormatException) { - this.SemErr("incorrectly formatted number"); - n = BigNum.ZERO; - } - .) - . - -/*------------------------------------------------------------------------*/ -Dec -= (. string s = ""; .) - ( - decimal (. s = t.val; .) - | - float (. s = t.val; .) - ) - (. try { - n = BigDec.FromString(s); - } catch (FormatException) { - this.SemErr("incorrectly formatted number"); - n = BigDec.ZERO; - } - .) - . - -/*------------------------------------------------------------------------*/ -BvLit -= - bvlit - (. - int pos = t.val.IndexOf("bv"); - string a = t.val.Substring(0, pos); - string b = t.val.Substring(pos + 2); - try { - n = BigNum.FromString(a); - m = Convert.ToInt32(b); - } catch (FormatException) { - this.SemErr("incorrectly formatted bitvector"); - n = BigNum.ZERO; - m = 0; - } - .) - . -END BoogiePL. + +/*--------------------------------------------------------------------------- +// BoogiePL - +//--------------------------------------------------------------------------*/ + +/*using System;*/ +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Microsoft.Boogie; +using Microsoft.Basetypes; +using Bpl = Microsoft.Boogie; + + +COMPILER BoogiePL + +/*--------------------------------------------------------------------------*/ + +readonly Program/*!*/ Pgm; + +readonly Expr/*!*/ dummyExpr; +readonly Cmd/*!*/ dummyCmd; +readonly Block/*!*/ dummyBlock; +readonly Bpl.Type/*!*/ dummyType; +readonly List/*!*/ dummyExprSeq; +readonly TransferCmd/*!*/ dummyTransferCmd; +readonly StructuredCmd/*!*/ dummyStructuredCmd; + +/// +///Returns the number of parsing errors encountered. If 0, "program" returns as +///the parsed program. +/// +public static int Parse (string/*!*/ filename, /*maybe null*/ List defines, out /*maybe null*/ Program program, bool useBaseName=false) /* throws System.IO.IOException */ { + Contract.Requires(filename != null); + Contract.Requires(cce.NonNullElements(defines,true)); + + if (defines == null) { + defines = new List(); + } + + if (filename == "stdin.bpl") { + var s = ParserHelper.Fill(Console.In, defines); + return Parse(s, filename, out program, useBaseName); + } else { + FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); + var s = ParserHelper.Fill(stream, defines); + var ret = Parse(s, filename, out program, useBaseName); + stream.Close(); + return ret; + } +} + + +public static int Parse (string s, string/*!*/ filename, out /*maybe null*/ Program program, bool useBaseName=false) /* throws System.IO.IOException */ { + Contract.Requires(s != null); + Contract.Requires(filename != null); + + byte[]/*!*/ buffer = cce.NonNull(UTF8Encoding.Default.GetBytes(s)); + MemoryStream ms = new MemoryStream(buffer,false); + Errors errors = new Errors(); + Scanner scanner = new Scanner(ms, errors, filename, useBaseName); + + Parser parser = new Parser(scanner, errors, false); + parser.Parse(); + if (parser.errors.count == 0) + { + program = parser.Pgm; + program.ProcessDatatypeConstructors(); + return 0; + } + else + { + program = null; + return parser.errors.count; + } +} + +public Parser(Scanner/*!*/ scanner, Errors/*!*/ errors, bool disambiguation) + : this(scanner, errors) +{ + // initialize readonly fields + Pgm = new Program(); + dummyExpr = new LiteralExpr(Token.NoToken, false); + dummyCmd = new AssumeCmd(Token.NoToken, dummyExpr); + dummyBlock = new Block(Token.NoToken, "dummyBlock", new List(), new ReturnCmd(Token.NoToken)); + dummyType = new BasicType(Token.NoToken, SimpleType.Bool); + dummyExprSeq = new List (); + dummyTransferCmd = new ReturnCmd(Token.NoToken); + dummyStructuredCmd = new BreakCmd(Token.NoToken, null); +} + +// Class to represent the bounds of a bitvector expression t[a:b]. +// Objects of this class only exist during parsing and are directly +// turned into BvExtract before they get anywhere else +private class BvBounds : Expr { + public BigNum Lower; + public BigNum Upper; + public BvBounds(IToken/*!*/ tok, BigNum lower, BigNum upper) + : base(tok) { + Contract.Requires(tok != null); + this.Lower = lower; + this.Upper = upper; + } + public override Bpl.Type/*!*/ ShallowType { get {Contract.Ensures(Contract.Result() != null); return Bpl.Type.Int; } } + public override void Resolve(ResolutionContext/*!*/ rc) { + // Contract.Requires(rc != null); + rc.Error(this, "bitvector bounds in illegal position"); + } + public override void Emit(TokenTextWriter/*!*/ stream, + int contextBindingStrength, bool fragileContext) { + Contract.Assert(false);throw new cce.UnreachableException(); + } + public override void ComputeFreeVariables(GSet/*!*/ freeVars) { Contract.Assert(false);throw new cce.UnreachableException(); } +} + +/*--------------------------------------------------------------------------*/ +CHARACTERS + letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". + digit = "0123456789". + special = "'~#$^_.?`". + glyph = "`~!@#$%^&*()-_=+[{]}|;:',<.>/?\\". + + cr = '\r'. + lf = '\n'. + tab = '\t'. + + space = ' '. + quote = '"'. + + newLine = cr + lf. + regularStringChar = ANY - quote - newLine. + + nondigit = letter + special. + nonquote = letter + digit + space + glyph. + + +/*------------------------------------------------------------------------*/ +TOKENS + ident = [ '\\' ] nondigit {nondigit | digit}. + bvlit = digit {digit} 'b' 'v' digit {digit}. + digits = digit {digit}. + + string = quote { regularStringChar | "\\\"" } quote. + + decimal = digit {digit} 'e' [ '-' ] digit {digit} . + float = digit {digit} '.' digit {digit} [ 'e' [ '-' ] digit {digit} ] . + +COMMENTS FROM "/*" TO "*/" NESTED +COMMENTS FROM "//" TO lf + +IGNORE cr + lf + tab + + +/*------------------------------------------------------------------------*/ +PRODUCTIONS + + +/*------------------------------------------------------------------------*/ +BoogiePL += (. List/*!*/ vs; + List/*!*/ ds; + Axiom/*!*/ ax; + List/*!*/ ts; + Procedure/*!*/ pr; + Implementation im; + Implementation/*!*/ nnim; + .) + { Consts (. foreach(Bpl.Variable/*!*/ v in vs){ + Contract.Assert(v != null); + Pgm.AddTopLevelDeclaration(v); + } + .) + | Function (. foreach(Bpl.Declaration/*!*/ d in ds){ + Contract.Assert(d != null); + Pgm.AddTopLevelDeclaration(d); + } + .) + | Axiom (. Pgm.AddTopLevelDeclaration(ax); .) + | UserDefinedTypes (. foreach(Declaration/*!*/ td in ts){ + Contract.Assert(td != null); + Pgm.AddTopLevelDeclaration(td); + } + .) + | GlobalVars (. foreach(Bpl.Variable/*!*/ v in vs){ + Contract.Assert(v != null); + Pgm.AddTopLevelDeclaration(v); + } + .) + | Procedure (. Pgm.AddTopLevelDeclaration(pr); + if (im != null) { + Pgm.AddTopLevelDeclaration(im); + } + .) + | Implementation (. Pgm.AddTopLevelDeclaration(nnim); .) + } + EOF + . + +/*------------------------------------------------------------------------*/ +GlobalVars<.out List/*!*/ ds.> += (. + Contract.Ensures(Contract.ValueAtReturn(out ds) != null); + QKeyValue kv = null; + ds = new List(); + var dsx = ds; + .) + "var" + { Attribute } + IdsTypeWheres ";" + . + +LocalVars<.List/*!*/ ds.> += (. + Contract.Ensures(Contract.ValueAtReturn(out ds) != null); + QKeyValue kv = null; + .) + "var" + { Attribute } + IdsTypeWheres ";" + . + +ProcFormals<.bool incoming, bool allowWhereClauses, out List/*!*/ ds.> += (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null); + ds = new List(); + var dsx = ds; + var context = allowWhereClauses ? "procedure formals" : "the 'implementation' copies of formals"; + .) + "(" + [ AttrsIdsTypeWheres + ] + ")" + . + +BoundVars<.IToken/*!*/ x, out List/*!*/ ds.> += (. + Contract.Requires(x != null); + Contract.Ensures(Contract.ValueAtReturn(out ds) != null); + List/*!*/ tyds = new List(); + ds = new List(); + var dsx = ds; + .) + AttrsIdsTypeWheres + . + +/*------------------------------------------------------------------------*/ +/* IdsType is used with const declarations */ +IdsType<.out List/*!*/ tyds.> += (. Contract.Ensures(Contract.ValueAtReturn(out tyds) != null); List/*!*/ ids; Bpl.Type/*!*/ ty; .) + Idents ":" Type + (. tyds = new List(); + foreach(Token/*!*/ id in ids){ + Contract.Assert(id != null); + tyds.Add(new TypedIdent(id, id.val, ty, null)); + } + .) + . + +/* AttrsIdsTypeWheres is used with the declarations of formals and bound variables */ +AttrsIdsTypeWheres<. bool allowAttributes, bool allowWhereClauses, string context, System.Action action .> += + AttributesIdsTypeWhere + { "," AttributesIdsTypeWhere } + . + +IdsTypeWheres<. bool allowWhereClauses, string context, System.Action action .> += + IdsTypeWhere + { "," IdsTypeWhere } + . + +AttributesIdsTypeWhere<. bool allowAttributes, bool allowWhereClauses, string context, System.Action action .> += (. QKeyValue kv = null; .) + { Attribute (. if (!allowAttributes) { + kv = null; + this.SemErr("attributes are not allowed on " + context); + } + .) + } + IdsTypeWhere + . + +/* context is allowed to be null if allowWhereClauses is true */ +IdsTypeWhere<. bool allowWhereClauses, string context, System.Action action .> += (. List/*!*/ ids; Bpl.Type/*!*/ ty; Expr wh = null; Expr/*!*/ nne; .) + Idents ":" Type + [ "where" Expression (. if (!allowWhereClauses) { + this.SemErr("where clause not allowed on " + context); + } else { + wh = nne; + } + .) + ] + (. foreach(Token/*!*/ id in ids){ + Contract.Assert(id != null); + action(new TypedIdent(id, id.val, ty, wh)); + } + .) + . + +/*------------------------------------------------------------------------*/ +Type += (.Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken/*!*/ tok; ty = dummyType; .) + ( + TypeAtom + | + Ident (. List/*!*/ args = new List (); .) + [ TypeArgs ] (. ty = new UnresolvedTypeIdentifier (tok, tok.val, args); .) + | + MapType + ) + . + +TypeArgs<.List/*!*/ ts.> += (.Contract.Requires(ts != null); IToken/*!*/ tok; Bpl.Type/*!*/ ty; .) + ( + TypeAtom (. ts.Add(ty); .) + [ TypeArgs ] + | + Ident (. List/*!*/ args = new List (); + ts.Add(new UnresolvedTypeIdentifier (tok, tok.val, args)); .) + [ TypeArgs ] + | + MapType (. ts.Add(ty); .) + ) + . + +TypeAtom += (.Contract.Ensures(Contract.ValueAtReturn(out ty) != null); ty = dummyType; .) + ( "int" (. ty = new BasicType(t, SimpleType.Int); .) + | "real" (. ty = new BasicType(t, SimpleType.Real); .) + | "bool" (. ty = new BasicType(t, SimpleType.Bool); .) + /* note: bitvectors are handled in UnresolvedTypeIdentifier */ + | + "(" + Type + ")" + ) + . + +MapType += (.Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken tok = null; + IToken/*!*/ nnTok; + List/*!*/ arguments = new List(); + Bpl.Type/*!*/ result; + List/*!*/ typeParameters = new List(); + .) + [ TypeParams (. tok = nnTok; .) ] + "[" (. if (tok == null) tok = t; .) + [ Types ] + "]" + Type + (. + ty = new MapType(tok, typeParameters, arguments, result); + .) + . + +TypeParams<.out IToken/*!*/ tok, out List/*!*/ typeParams.> += (.Contract.Ensures(Contract.ValueAtReturn(out tok) != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); List/*!*/ typeParamToks; .) + "<" (. tok = t; .) + Idents + ">" + (. + typeParams = new List (); + foreach(Token/*!*/ id in typeParamToks){ + Contract.Assert(id != null); + typeParams.Add(new TypeVariable(id, id.val));} + .) + . + +Types<.List/*!*/ ts.> += (. Contract.Requires(ts != null); Bpl.Type/*!*/ ty; .) + Type (. ts.Add(ty); .) + { "," Type (. ts.Add(ty); .) + } + . + + +/*------------------------------------------------------------------------*/ +Consts<.out List/*!*/ ds.> += (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null); IToken/*!*/ y; List/*!*/ xs; + ds = new List(); + bool u = false; QKeyValue kv = null; + bool ChildrenComplete = false; + List Parents = null; .) + "const" (. y = t; .) + { Attribute } + [ "unique" (. u = true; .) + ] + IdsType + [ OrderSpec ] + (. bool makeClone = false; + foreach(TypedIdent/*!*/ x in xs){ + Contract.Assert(x != null); + + // ensure that no sharing is introduced + List ParentsClone; + if (makeClone && Parents != null) { + ParentsClone = new List (); + foreach (ConstantParent/*!*/ p in Parents){ + Contract.Assert(p != null); + ParentsClone.Add(new ConstantParent ( + new IdentifierExpr (p.Parent.tok, p.Parent.Name), + p.Unique));} + } else { + ParentsClone = Parents; + } + makeClone = true; + + ds.Add(new Constant(y, x, u, ParentsClone, ChildrenComplete, kv)); + } + .) + ";" + . + +OrderSpec<.out bool ChildrenComplete, out List Parents.> += (.Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out Parents),true)); ChildrenComplete = false; + Parents = null; + bool u; + IToken/*!*/ parent; .) + "extends" (. Parents = new List (); + u = false; .) + [ + [ "unique" (. u = true; .) + ] + Ident (. Parents.Add(new ConstantParent ( + new IdentifierExpr(parent, parent.val), u)); .) + { + "," (. u = false; .) + [ "unique" (. u = true; .) + ] + Ident (. Parents.Add(new ConstantParent ( + new IdentifierExpr(parent, parent.val), u)); .) + } + ] + [ "complete" (. ChildrenComplete = true; .) + ] + . + +/*------------------------------------------------------------------------*/ +Function<.out List/*!*/ ds.> += (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null); + ds = new List(); IToken/*!*/ z; + IToken/*!*/ typeParamTok; + var typeParams = new List(); + var arguments = new List(); + TypedIdent/*!*/ tyd; + TypedIdent retTyd = null; + Bpl.Type/*!*/ retTy; + QKeyValue argKv = null; + QKeyValue kv = null; + Expr definition = null; + Expr/*!*/ tmp; + .) + "function" { Attribute } Ident + [ TypeParams ] + "(" + [ VarOrType (. arguments.Add(new Formal(tyd.tok, tyd, true, argKv)); .) + { "," VarOrType (. arguments.Add(new Formal(tyd.tok, tyd, true, argKv)); .) + } ] ")" + (. argKv = null; .) + ( + "returns" "(" VarOrType ")" + | + ":" Type (. retTyd = new TypedIdent(retTy.tok, TypedIdent.NoName, retTy); .) + ) + ( "{" Expression (. definition = tmp; .) "}" | ";" ) + (. + if (retTyd == null) { + // construct a dummy type for the case of syntax error + retTyd = new TypedIdent(t, TypedIdent.NoName, new BasicType(t, SimpleType.Int)); + } + Function/*!*/ func = new Function(z, z.val, typeParams, arguments, + new Formal(retTyd.tok, retTyd, false, argKv), null, kv); + Contract.Assert(func != null); + ds.Add(func); + bool allUnnamed = true; + foreach(Formal/*!*/ f in arguments){ + Contract.Assert(f != null); + if (f.TypedIdent.HasName) { + allUnnamed = false; + break; + } + } + if (!allUnnamed) { + Bpl.Type prevType = null; + for (int i = arguments.Count; 0 <= --i; ) { + TypedIdent/*!*/ curr = cce.NonNull(arguments[i]).TypedIdent; + if (curr.HasName) { + // the argument was given as both an identifier and a type + prevType = curr.Type; + } else { + // the argument was given as just one "thing", which syntactically parsed as a type + if (prevType == null) { + this.errors.SemErr(curr.tok, "the type of the last parameter is unspecified"); + break; + } + Bpl.Type ty = curr.Type; + var uti = ty as UnresolvedTypeIdentifier; + if (uti != null && uti.Arguments.Count == 0) { + // the given "thing" was just an identifier, so let's use it as the name of the parameter + curr.Name = uti.Name; + curr.Type = prevType; + } else { + this.errors.SemErr(curr.tok, "expecting an identifier as parameter name"); + } + } + } + } + if (definition != null) { + // generate either an axiom or a function body + if (QKeyValue.FindBoolAttribute(kv, "inline")) { + func.Body = definition; + } else { + ds.Add(func.CreateDefinitionAxiom(definition, kv)); + } + } + .) + . + +VarOrType += (. + Contract.Ensures(Contract.ValueAtReturn(out tyd) != null); + string/*!*/ varName = TypedIdent.NoName; + Bpl.Type/*!*/ ty; + IToken/*!*/ tok; + kv = null; + .) + { Attribute } + Type (. tok = ty.tok; .) + [ ":" (. var uti = ty as UnresolvedTypeIdentifier; + if (uti != null && uti.Arguments.Count == 0) { + varName = uti.Name; + } else { + this.SemErr("expected identifier before ':'"); + } + .) + Type + ] + (. tyd = new TypedIdent(tok, varName, ty); .) + . + +/*------------------------------------------------------------------------*/ +Axiom += (.Contract.Ensures(Contract.ValueAtReturn(out m) != null); Expr/*!*/ e; QKeyValue kv = null; .) + "axiom" + { Attribute } + (. IToken/*!*/ x = t; .) + Proposition ";" (. m = new Axiom(x,e, null, kv); .) + . + +/*------------------------------------------------------------------------*/ +UserDefinedTypes<.out List/*!*/ ts.> += (. Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out ts))); Declaration/*!*/ decl; QKeyValue kv = null; ts = new List (); .) + "type" + { Attribute } + UserDefinedType (. ts.Add(decl); .) + { "," UserDefinedType (. ts.Add(decl); .) } + ";" + . + +UserDefinedType += (. Contract.Ensures(Contract.ValueAtReturn(out decl) != null); IToken/*!*/ id; List/*!*/ paramTokens = new List (); + Bpl.Type/*!*/ body = dummyType; bool synonym = false; .) + Ident + [ WhiteSpaceIdents ] + [ + "=" Type + (. synonym = true; .) + ] + (. + if (synonym) { + List/*!*/ typeParams = new List(); + foreach(Token/*!*/ t in paramTokens){ + Contract.Assert(t != null); + typeParams.Add(new TypeVariable(t, t.val));} + decl = new TypeSynonymDecl(id, id.val, typeParams, body, kv); + } else { + decl = new TypeCtorDecl(id, id.val, paramTokens.Count, kv); + } + .) + . + + +/*------------------------------------------------------------------------*/ +Procedure += (. Contract.Ensures(Contract.ValueAtReturn(out proc) != null); IToken/*!*/ x; + List/*!*/ typeParams; + List/*!*/ ins, outs; + List/*!*/ pre = new List(); + List/*!*/ mods = new List(); + List/*!*/ post = new List(); + + List/*!*/ locals = new List(); + StmtList/*!*/ stmtList; + QKeyValue kv = null; + impl = null; + .) + + "procedure" + ProcSignature + ( ";" + { Spec } + | { Spec } + ImplBody + (. + impl = new Implementation(x, x.val, typeParams, + Formal.StripWhereClauses(ins), Formal.StripWhereClauses(outs), locals, stmtList, kv == null ? null : (QKeyValue)kv.Clone(), this.errors); + .) + ) + (. proc = new Procedure(x, x.val, typeParams, ins, outs, pre, mods, post, kv); .) + . + + +Implementation += (. Contract.Ensures(Contract.ValueAtReturn(out impl) != null); IToken/*!*/ x; + List/*!*/ typeParams; + List/*!*/ ins, outs; + List/*!*/ locals; + StmtList/*!*/ stmtList; + QKeyValue kv; + .) + + "implementation" + ProcSignature + ImplBody + (. impl = new Implementation(x, x.val, typeParams, ins, outs, locals, stmtList, kv, this.errors); .) + . + + +ProcSignature<.bool allowWhereClausesOnFormals, out IToken/*!*/ name, out List/*!*/ typeParams, + out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv.> += (. Contract.Ensures(Contract.ValueAtReturn(out name) != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); Contract.Ensures(Contract.ValueAtReturn(out ins) != null); Contract.Ensures(Contract.ValueAtReturn(out outs) != null); + IToken/*!*/ typeParamTok; typeParams = new List(); + outs = new List(); kv = null; .) + { Attribute } + Ident + [ TypeParams ] + ProcFormals + [ "returns" ProcFormals ] + . + + +Spec<.List/*!*/ pre, List/*!*/ mods, List/*!*/ post.> += (.Contract.Requires(pre != null); Contract.Requires(mods != null); Contract.Requires(post != null); List/*!*/ ms; .) + ( "modifies" + [ Idents (. foreach(IToken/*!*/ m in ms){ + Contract.Assert(m != null); + mods.Add(new IdentifierExpr(m, m.val)); + } + .) + ] ";" + | "free" SpecPrePost + | SpecPrePost + ) + . + +SpecPrePost<.bool free, List/*!*/ pre, List/*!*/ post.> += (. Contract.Requires(pre != null); Contract.Requires(post != null); Expr/*!*/ e; Token tok = null; QKeyValue kv = null; .) + ( "requires" (. tok = t; .) + { Attribute } + Proposition ";" (. pre.Add(new Requires(tok, free, e, null, kv)); .) + | "ensures" (. tok = t; .) + { Attribute } + Proposition ";" (. post.Add(new Ensures(tok, free, e, null, kv)); .) + ) + . + +/*------------------------------------------------------------------------*/ + +ImplBody<.out List/*!*/ locals, out StmtList/*!*/ stmtList.> += (. Contract.Ensures(Contract.ValueAtReturn(out locals) != null); Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); locals = new List(); .) + "{" + { LocalVars } + StmtList + . + +/* the StmtList also reads the final curly brace */ +StmtList += (. Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); List bigblocks = new List(); + /* built-up state for the current BigBlock: */ + IToken startToken = null; string currentLabel = null; + List cs = null; /* invariant: startToken != null ==> cs != null */ + /* temporary variables: */ + IToken label; Cmd c; BigBlock b; + StructuredCmd ec = null; StructuredCmd/*!*/ ecn; + TransferCmd tc = null; TransferCmd/*!*/ tcn; + .) + + { + ( LabelOrCmd + (. if (c != null) { + // LabelOrCmd read a Cmd + Contract.Assert(label == null); + if (startToken == null) { startToken = c.tok; cs = new List(); } + Contract.Assert(cs != null); + cs.Add(c); + } else { + // LabelOrCmd read a label + Contract.Assert(label != null); + if (startToken != null) { + Contract.Assert(cs != null); + // dump the built-up state into a BigBlock + b = new BigBlock(startToken, currentLabel, cs, null, null); + bigblocks.Add(b); + cs = null; + } + startToken = label; + currentLabel = label.val; + cs = new List(); + } + .) + + | StructuredCmd + (. ec = ecn; + if (startToken == null) { startToken = ec.tok; cs = new List(); } + Contract.Assert(cs != null); + b = new BigBlock(startToken, currentLabel, cs, ec, null); + bigblocks.Add(b); + startToken = null; currentLabel = null; cs = null; + .) + + | TransferCmd + (. tc = tcn; + if (startToken == null) { startToken = tc.tok; cs = new List(); } + Contract.Assert(cs != null); + b = new BigBlock(startToken, currentLabel, cs, null, tc); + bigblocks.Add(b); + startToken = null; currentLabel = null; cs = null; + .) + + ) + } + "}" + (. IToken/*!*/ endCurly = t; + if (startToken == null && bigblocks.Count == 0) { + startToken = t; cs = new List(); + } + if (startToken != null) { + Contract.Assert(cs != null); + b = new BigBlock(startToken, currentLabel, cs, null, null); + bigblocks.Add(b); + } + + stmtList = new StmtList(bigblocks, endCurly); + .) + . + +TransferCmd += (. Contract.Ensures(Contract.ValueAtReturn(out tc) != null); tc = dummyTransferCmd; + Token y; List/*!*/ xs; + List ss = new List(); + .) + ( "goto" (. y = t; .) + Idents (. foreach(IToken/*!*/ s in xs){ + Contract.Assert(s != null); + ss.Add(s.val); } + tc = new GotoCmd(y, ss); + .) + | "return" (. tc = new ReturnCmd(t); .) + ) ";" + . + +StructuredCmd += (. Contract.Ensures(Contract.ValueAtReturn(out ec) != null); ec = dummyStructuredCmd; Contract.Assume(cce.IsPeerConsistent(ec)); + IfCmd/*!*/ ifcmd; WhileCmd/*!*/ wcmd; BreakCmd/*!*/ bcmd; + .) + ( IfCmd (. ec = ifcmd; .) + | WhileCmd (. ec = wcmd; .) + | BreakCmd (. ec = bcmd; .) + ) + . + +IfCmd += (. Contract.Ensures(Contract.ValueAtReturn(out ifcmd) != null); IToken/*!*/ x; + Expr guard; + StmtList/*!*/ thn; + IfCmd/*!*/ elseIf; IfCmd elseIfOption = null; + StmtList/*!*/ els; StmtList elseOption = null; + .) + "if" (. x = t; .) + Guard + "{" StmtList + [ "else" + ( IfCmd (. elseIfOption = elseIf; .) + | "{" + StmtList (. elseOption = els; .) + ) + ] + (. ifcmd = new IfCmd(x, guard, thn, elseIfOption, elseOption); .) + . + +WhileCmd += (. Contract.Ensures(Contract.ValueAtReturn(out wcmd) != null); IToken/*!*/ x; Token z; + Expr guard; Expr/*!*/ e; bool isFree; + List invariants = new List(); + StmtList/*!*/ body; + QKeyValue kv = null; + .) + "while" (. x = t; .) + Guard (. Contract.Assume(guard == null || cce.Owner.None(guard)); .) + { (. isFree = false; z = la/*lookahead token*/; .) + [ "free" (. isFree = true; .) + ] + "invariant" + { Attribute } + Expression (. if (isFree) { + invariants.Add(new AssumeCmd(z, e, kv)); + } else { + invariants.Add(new AssertCmd(z, e, kv)); + } + kv = null; + .) + ";" + } + "{" + StmtList (. wcmd = new WhileCmd(x, guard, invariants, body); .) + . + +Guard += (. Expr/*!*/ ee; e = null; .) + "(" + ( "*" (. e = null; .) + | Expression (. e = ee; .) + ) + ")" + . + +BreakCmd += (.Contract.Ensures(Contract.ValueAtReturn(out bcmd) != null); IToken/*!*/ x; IToken/*!*/ y; + string breakLabel = null; + .) + "break" (. x = t; .) + [ Ident (. breakLabel = y.val; .) + ] ";" (. bcmd = new BreakCmd(x, breakLabel); .) + . + +/*------------------------------------------------------------------------*/ + +LabelOrCmd +/* ensures (c == null) != (label != null) */ += (. IToken/*!*/ x; Expr/*!*/ e; + List/*!*/ xs; + List ids; + c = dummyCmd; label = null; + Cmd/*!*/ cn; + QKeyValue kv = null; + .) + ( LabelOrAssign + | "assert" (. x = t; .) + { Attribute } + Proposition (. c = new AssertCmd(x, e, kv); .) + ";" + | "assume" (. x = t; .) + { Attribute } + Proposition (. c = new AssumeCmd(x, e, kv); .) + ";" + | "havoc" (. x = t; .) + Idents ";" (. ids = new List(); + foreach(IToken/*!*/ y in xs){ + Contract.Assert(y != null); + ids.Add(new IdentifierExpr(y, y.val)); + } + c = new HavocCmd(x,ids); + .) + | CallCmd ";" (. c = cn; .) + | ParCallCmd (. c = cn; .) + | "yield" (. x = t; .) + ";" (. c = new YieldCmd(x); .) + ) + . + +/*------------------------------------------------------------------------*/ + +LabelOrAssign +/* ensures (c == null) != (label != null) */ += (. IToken/*!*/ id; IToken/*!*/ x, y; Expr/*!*/ e0; + c = dummyCmd; label = null; + AssignLhs/*!*/ lhs; + List/*!*/ lhss; + List/*!*/ rhss; + List/*!*/ indexes; + .) + Ident (. x = t; .) + ( ":" (. c = null; label = x; .) + + | (. lhss = new List(); .) + (. lhs = new SimpleAssignLhs(id, new IdentifierExpr(id, id.val)); .) + + { MapAssignIndex (. lhs = new MapAssignLhs(y, lhs, indexes); .) } + (. lhss.Add(lhs); .) + + { "," + Ident + (. lhs = new SimpleAssignLhs(id, new IdentifierExpr(id, id.val)); .) + { MapAssignIndex (. lhs = new MapAssignLhs(y, lhs, indexes); .) } + (. lhss.Add(lhs); .) + } + + ":=" (. x = t; /* use location of := */ .) + Expression (. rhss = new List (); + rhss.Add(e0); .) + { "," + Expression (. rhss.Add(e0); .) + } + ";" (. c = new AssignCmd(x, lhss, rhss); .) + ) + . + +MapAssignIndex<.out IToken/*!*/ x, out List/*!*/ indexes.> += (.Contract.Ensures(Contract.ValueAtReturn(out x) != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out indexes))); indexes = new List (); + Expr/*!*/ e; + .) + "[" (. x = t; .) + [ + Expression (. indexes.Add(e); .) + { "," + Expression (. indexes.Add(e); .) + } + ] + "]" + . + +/*------------------------------------------------------------------------*/ +CallCmd += (. Contract.Ensures(Contract.ValueAtReturn(out c) != null); + IToken x; + bool isAsync = false; + bool isFree = false; + QKeyValue kv = null; + c = null; + .) + [ "async" (. isAsync = true; .) + ] + [ "free" (. isFree = true; .) + ] + "call" (. x = t; .) + { Attribute } + CallParams (. .) + . + +ParCallCmd += (. Contract.Ensures(Contract.ValueAtReturn(out d) != null); + IToken x; + QKeyValue kv = null; + Cmd c = null; + List callCmds = new List(); + .) + "par" (. x = t; .) + { Attribute } + CallParams (. callCmds.Add((CallCmd)c); .) + { "|" CallParams (. callCmds.Add((CallCmd)c); .) + } + ";" (. d = new ParCallCmd(x, callCmds, kv); .) + . + +CallParams += (. + List ids = new List(); + List es = new List(); + Expr en; + IToken first; + IToken p; + c = null; + .) + Ident + ( "(" + [ Expression (. es.Add(en); .) + { "," Expression (. es.Add(en); .) + } + ] + ")" (. c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync; .) + | + (. ids.Add(new IdentifierExpr(first, first.val)); .) + [ "," Ident (. ids.Add(new IdentifierExpr(p, p.val)); .) + { "," Ident (. ids.Add(new IdentifierExpr(p, p.val)); .) + } + ] ":=" + Ident "(" + [ Expression (. es.Add(en); .) + { "," Expression (. es.Add(en); .) + } + ] + ")" (. c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync; .) + ) + . + +/*------------------------------------------------------------------------*/ +Proposition +=(.Contract.Ensures(Contract.ValueAtReturn(out e) != null);.) + Expression + . + +/*------------------------------------------------------------------------*/ +Idents<.out List/*!*/ xs.> += (.Contract.Ensures(Contract.ValueAtReturn(out xs) != null); IToken/*!*/ id; xs = new List(); .) + Ident (. xs.Add(id); .) + { "," Ident (. xs.Add(id); .) + } + . + +/*------------------------------------------------------------------------*/ +WhiteSpaceIdents<.out List/*!*/ xs.> += (. Contract.Ensures(Contract.ValueAtReturn(out xs) != null); IToken/*!*/ id; xs = new List(); .) + Ident (. xs.Add(id); .) + { Ident (. xs.Add(id); .) + } + . + +/*------------------------------------------------------------------------*/ +Expressions<.out List/*!*/ es.> += (. Contract.Ensures(Contract.ValueAtReturn(out es) != null); Expr/*!*/ e; es = new List(); .) + Expression (. es.Add(e); .) + { "," Expression (. es.Add(e); .) + } + . + +/*------------------------------------------------------------------------*/ +Expression<.out Expr/*!*/ e0.> += (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) + ImpliesExpression + { EquivOp (. x = t; .) + ImpliesExpression + (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Iff, e0, e1); .) + } + . + +EquivOp = "<==>" | '\u21d4'. + +/*------------------------------------------------------------------------*/ +ImpliesExpression += (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) + LogicalExpression + [ + ImpliesOp (. x = t; .) + /* recurse because implication is right-associative */ + ImpliesExpression + (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e0, e1); .) + | + ExpliesOp (. if (noExplies) + this.SemErr("illegal mixture of ==> and <==, use parentheses to disambiguate"); + x = t; .) + LogicalExpression + (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e1, e0); .) + /* loop because explies is left-associative */ + { + ExpliesOp (. x = t; .) + LogicalExpression + (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e1, e0); .) + } + ] + . + +ImpliesOp = "==>" | '\u21d2'. +ExpliesOp = "<==" | '\u21d0'. + +/*------------------------------------------------------------------------*/ +LogicalExpression += (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) + RelationalExpression + [ AndOp (. x = t; .) + RelationalExpression + (. e0 = Expr.Binary(x, BinaryOperator.Opcode.And, e0, e1); .) + { AndOp (. x = t; .) + RelationalExpression + (. e0 = Expr.Binary(x, BinaryOperator.Opcode.And, e0, e1); .) + } + | OrOp (. x = t; .) + RelationalExpression + (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Or, e0, e1); .) + { OrOp (. x = t; .) + RelationalExpression + (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Or, e0, e1); .) + } + ] + . + +AndOp = "&&" | '\u2227'. +OrOp = "||" | '\u2228'. + +/*------------------------------------------------------------------------*/ +RelationalExpression += (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .) + BvTerm + [ RelOp + BvTerm (. e0 = Expr.Binary(x, op, e0, e1); .) + ] + . + +RelOp += (.Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/; .) + ( "==" (. x = t; op=BinaryOperator.Opcode.Eq; .) + | "<" (. x = t; op=BinaryOperator.Opcode.Lt; .) + | ">" (. x = t; op=BinaryOperator.Opcode.Gt; .) + | "<=" (. x = t; op=BinaryOperator.Opcode.Le; .) + | ">=" (. x = t; op=BinaryOperator.Opcode.Ge; .) + | "!=" (. x = t; op=BinaryOperator.Opcode.Neq; .) + | "<:" (. x = t; op=BinaryOperator.Opcode.Subtype; .) + | '\u2260' (. x = t; op=BinaryOperator.Opcode.Neq; .) + | '\u2264' (. x = t; op=BinaryOperator.Opcode.Le; .) + | '\u2265' (. x = t; op=BinaryOperator.Opcode.Ge; .) + ) + . + +/*------------------------------------------------------------------------*/ +BvTerm += (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) + Term + { "++" (. x = t; .) + Term (. e0 = new BvConcatExpr(x, e0, e1); .) + } + . + + +/*------------------------------------------------------------------------*/ +Term += (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .) + Factor + { AddOp + Factor (. e0 = Expr.Binary(x, op, e0, e1); .) + } + . + +AddOp += (.Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/; .) + ( "+" (. x = t; op=BinaryOperator.Opcode.Add; .) + | "-" (. x = t; op=BinaryOperator.Opcode.Sub; .) + ) + . + +/*------------------------------------------------------------------------*/ +Factor += (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .) + Power + { MulOp + Power (. e0 = Expr.Binary(x, op, e0, e1); .) + } + . + +MulOp += (. Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/; .) + ( "*" (. x = t; op=BinaryOperator.Opcode.Mul; .) + | "div" (. x = t; op=BinaryOperator.Opcode.Div; .) + | "mod" (. x = t; op=BinaryOperator.Opcode.Mod; .) + | "/" (. x = t; op=BinaryOperator.Opcode.RealDiv; .) + ) + . + +/*------------------------------------------------------------------------*/ +Power += (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) + UnaryExpression + [ + "**" (. x = t; .) + /* recurse because exponentation is right-associative */ + Power (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Pow, e0, e1); .) + ] + . + +/*------------------------------------------------------------------------*/ +UnaryExpression += (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; + e = dummyExpr; + .) + ( "-" (. x = t; .) + UnaryExpression (. e = Expr.Unary(x, UnaryOperator.Opcode.Neg, e); .) + | NegOp (. x = t; .) + UnaryExpression (. e = Expr.Unary(x, UnaryOperator.Opcode.Not, e); .) + | CoercionExpression + ) + . + +NegOp = "!" | '\u00ac'. + +/*------------------------------------------------------------------------*/ + +/* This production creates ambiguities, because types can start with "<" + (polymorphic map types), but can also be followed by "<" (inequalities). + Coco deals with these ambiguities in a reasonable way by preferring to read + further types (type arguments) over relational symbols. E.g., "5 : C < 0" + will cause a parse error because "<" is treated as the beginning of a + map type. */ + +CoercionExpression += (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; + Bpl.Type/*!*/ coercedTo; + BigNum bn; + .) + ArrayExpression + { ":" (. x = t; .) + ( + Type (. e = Expr.CoerceType(x, e, coercedTo); .) + | + Nat /* This means that we really look at a bitvector + expression t[a:b] */ + (. if (!(e is LiteralExpr) || !((LiteralExpr)e).isBigNum) { + this.SemErr("arguments of extract need to be integer literals"); + e = new BvBounds(x, bn, BigNum.ZERO); + } else { + e = new BvBounds(x, bn, ((LiteralExpr)e).asBigNum); + } + .) + ) + } + . + +/*------------------------------------------------------------------------*/ +ArrayExpression += (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; + Expr/*!*/ index0 = dummyExpr; Expr/*!*/ e1; + bool store; bool bvExtract; + List/*!*/ allArgs = dummyExprSeq; + .) + AtomExpression + { "[" (. x = t; allArgs = new List (); + allArgs.Add(e); + store = false; bvExtract = false; .) + [ + Expression + (. if (index0 is BvBounds) + bvExtract = true; + else + allArgs.Add(index0); + .) + { "," Expression + (. if (bvExtract || e1 is BvBounds) + this.SemErr("bitvectors only have one dimension"); + allArgs.Add(e1); + .) + } + [ ":=" Expression + (. if (bvExtract || e1 is BvBounds) + this.SemErr("assignment to bitvectors is not possible"); + allArgs.Add(e1); store = true; + .) + ] + | ":=" Expression (. allArgs.Add(e1); store = true; .) + ] + "]" + (. if (store) + e = new NAryExpr(x, new MapStore(x, allArgs.Count - 2), allArgs); + else if (bvExtract) + e = new BvExtractExpr(x, e, + ((BvBounds)index0).Upper.ToIntSafe, + ((BvBounds)index0).Lower.ToIntSafe); + else + e = new NAryExpr(x, new MapSelect(x, allArgs.Count - 1), allArgs); + .) + } + . + + +/*------------------------------------------------------------------------*/ +AtomExpression += (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; int n; BigNum bn; BigDec bd; + List/*!*/ es; List/*!*/ ds; Trigger trig; + List/*!*/ typeParams; + IdentifierExpr/*!*/ id; + QKeyValue kv; + e = dummyExpr; + List/*!*/ locals; + List/*!*/ blocks; + .) + ( "false" (. e = new LiteralExpr(t, false); .) + | "true" (. e = new LiteralExpr(t, true); .) + | Nat (. e = new LiteralExpr(t, bn); .) + | Dec (. e = new LiteralExpr(t, bd); .) + | BvLit (. e = new LiteralExpr(t, bn, n); .) + + | Ident (. id = new IdentifierExpr(x, x.val); e = id; .) + [ "(" + ( Expressions (. e = new NAryExpr(x, new FunctionCall(id), es); .) + | /* empty */ (. e = new NAryExpr(x, new FunctionCall(id), new List()); .) + ) + ")" + ] + + | "old" (. x = t; .) + "(" + Expression + ")" (. e = new OldExpr(x, e); .) + + | "int" (. x = t; .) + "(" + Expression + ")" (. e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToInt), new List{ e }); .) + + | "real" (. x = t; .) + "(" + Expression + ")" (. e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToReal), new List{ e }); .) + + | "(" ( Expression (. if (e is BvBounds) + this.SemErr("parentheses around bitvector bounds " + + "are not allowed"); .) + | Forall (. x = t; .) + QuantifierBody + (. if (typeParams.Count + ds.Count > 0) + e = new ForallExpr(x, typeParams, ds, kv, trig, e); .) + | Exists (. x = t; .) + QuantifierBody + (. if (typeParams.Count + ds.Count > 0) + e = new ExistsExpr(x, typeParams, ds, kv, trig, e); .) + | Lambda (. x = t; .) + QuantifierBody + (. if (trig != null) + SemErr("triggers not allowed in lambda expressions"); + if (typeParams.Count + ds.Count > 0) + e = new LambdaExpr(x, typeParams, ds, kv, e); .) + ) + ")" + | IfThenElseExpression + | CodeExpression (. e = new CodeExpr(locals, blocks); .) + ) + . + +CodeExpression<.out List/*!*/ locals, out List/*!*/ blocks.> += (. Contract.Ensures(Contract.ValueAtReturn(out locals) != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out blocks))); locals = new List(); Block/*!*/ b; + blocks = new List(); + .) + "|{" + { LocalVars } + SpecBlock (. blocks.Add(b); .) + { SpecBlock (. blocks.Add(b); .) + } + "}|" + . + +SpecBlock += (. Contract.Ensures(Contract.ValueAtReturn(out b) != null); IToken/*!*/ x; IToken/*!*/ y; + Cmd c; IToken label; + List cs = new List(); + List/*!*/ xs; + List ss = new List(); + b = dummyBlock; + Expr/*!*/ e; + .) + Ident ":" + { LabelOrCmd + (. if (c != null) { + Contract.Assert(label == null); + cs.Add(c); + } else { + Contract.Assert(label != null); + SemErr("SpecBlock's can only have one label"); + } + .) + } + ( "goto" (. y = t; .) + Idents (. foreach(IToken/*!*/ s in xs){ + Contract.Assert(s != null); + ss.Add(s.val); } + b = new Block(x,x.val,cs,new GotoCmd(y,ss)); + .) + | "return" Expression + (. b = new Block(x,x.val,cs,new ReturnExprCmd(t,e)); .) + ) + ";" + . + +Attribute += (. Trigger trig = null; .) + AttributeOrTrigger (. if (trig != null) this.SemErr("only attributes, not triggers, allowed here"); .) +. + +AttributeOrTrigger += (. IToken/*!*/ tok; Expr/*!*/ e; List/*!*/ es; + string key; + List parameters; object/*!*/ param; + .) + "{" (. tok = t; .) + ( + ":" ident (. key = t.val; parameters = new List(); .) + [ AttributeParameter (. parameters.Add(param); .) + { "," AttributeParameter (. parameters.Add(param); .) + } + ] + (. if (key == "nopats") { + if (parameters.Count == 1 && parameters[0] is Expr) { + e = (Expr)parameters[0]; + if(trig==null){ + trig = new Trigger(tok, false, new List { e }, null); + } else { + trig.AddLast(new Trigger(tok, false, new List { e }, null)); + } + } else { + this.SemErr("the 'nopats' quantifier attribute expects a string-literal parameter"); + } + } else { + if (kv==null) { + kv = new QKeyValue(tok, key, parameters, null); + } else { + kv.AddLast(new QKeyValue(tok, key, parameters, null)); + } + } + .) + | + Expression (. es = new List { e }; .) + { "," Expression (. es.Add(e); .) + } (. if (trig==null) { + trig = new Trigger(tok, true, es, null); + } else { + trig.AddLast(new Trigger(tok, true, es, null)); + } + .) + ) + "}" + . + +AttributeParameter += (. Contract.Ensures(Contract.ValueAtReturn(out o) != null); + o = "error"; + Expr/*!*/ e; + .) + ( string (. o = t.val.Substring(1, t.val.Length-2); .) + | Expression (. o = e; .) + ) + . + +IfThenElseExpression += (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); + IToken/*!*/ tok; + Expr/*!*/ e0, e1, e2; + e = dummyExpr; .) + "if" (. tok = t; .) Expression "then" Expression "else" Expression + (. e = new NAryExpr(tok, new IfThenElse(tok), new List{ e0, e1, e2 }); .) + . + + +QuantifierBody<.IToken/*!*/ q, out List/*!*/ typeParams, out List/*!*/ ds, + out QKeyValue kv, out Trigger trig, out Expr/*!*/ body.> += (. Contract.Requires(q != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); Contract.Ensures(Contract.ValueAtReturn(out ds) != null); Contract.Ensures(Contract.ValueAtReturn(out body) != null); + trig = null; typeParams = new List (); + IToken/*!*/ tok; + kv = null; + ds = new List (); + .) + ( + TypeParams + [ BoundVars ] + | + BoundVars + ) + QSep + { AttributeOrTrigger } + Expression + . + +Forall = "forall" | '\u2200'. +Exists = "exists" | '\u2203'. +Lambda = "lambda" | '\u03bb'. +QSep = "::" | '\u2022'. + +/*------------------------------------------------------------------------*/ +Ident +=(.Contract.Ensures(Contract.ValueAtReturn(out x) != null);.) + ident (. x = t; + if (x.val.StartsWith("\\")) + x.val = x.val.Substring(1); + .) + . + +/*------------------------------------------------------------------------*/ +Nat += + digits + (. try { + n = BigNum.FromString(t.val); + } catch (FormatException) { + this.SemErr("incorrectly formatted number"); + n = BigNum.ZERO; + } + .) + . + +/*------------------------------------------------------------------------*/ +Dec += (. string s = ""; .) + ( + decimal (. s = t.val; .) + | + float (. s = t.val; .) + ) + (. try { + n = BigDec.FromString(s); + } catch (FormatException) { + this.SemErr("incorrectly formatted number"); + n = BigDec.ZERO; + } + .) + . + +/*------------------------------------------------------------------------*/ +BvLit += + bvlit + (. + int pos = t.val.IndexOf("bv"); + string a = t.val.Substring(0, pos); + string b = t.val.Substring(pos + 2); + try { + n = BigNum.FromString(a); + m = Convert.ToInt32(b); + } catch (FormatException) { + this.SemErr("incorrectly formatted bitvector"); + n = BigNum.ZERO; + m = 0; + } + .) + . +END BoogiePL. diff --git a/Source/Core/CommandLineOptions.cs b/Source/Core/CommandLineOptions.cs index dbbb6fd0..e9aa3ceb 100644 --- a/Source/Core/CommandLineOptions.cs +++ b/Source/Core/CommandLineOptions.cs @@ -1,2143 +1,2185 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.IO; -using System.Linq; -using System.Diagnostics; -using System.Diagnostics.Contracts; - -namespace Microsoft.Boogie { - public class CommandLineOptionEngine - { - public readonly string ToolName; - public readonly string DescriptiveToolName; - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(ToolName != null); - Contract.Invariant(DescriptiveToolName != null); - Contract.Invariant(this._environment != null); - Contract.Invariant(cce.NonNullElements(this._files)); - Contract.Invariant(this._fileTimestamp != null); - } - - private string/*!*/ _environment = ""; - - public string Environment { - get { - Contract.Ensures(Contract.Result() != null); - return this._environment; - } - set { - Contract.Requires(value != null); - this._environment = value; - } - } - - private readonly List/*!*/ _files = new List(); - - public IList/*!*/ Files { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - Contract.Ensures(Contract.Result>().IsReadOnly); - return this._files.AsReadOnly(); - } - } - - public bool HelpRequested = false; - public bool AttrHelpRequested = false; - - public CommandLineOptionEngine(string toolName, string descriptiveName) { - Contract.Requires(toolName != null); - Contract.Requires(descriptiveName != null); - ToolName = toolName; - DescriptiveToolName = descriptiveName; - } - - public virtual string/*!*/ VersionNumber { - get { - Contract.Ensures(Contract.Result() != null); - return cce.NonNull(cce.NonNull(System.Diagnostics.FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetExecutingAssembly().Location)).FileVersion); - } - } - public virtual string/*!*/ VersionSuffix { - get { - Contract.Ensures(Contract.Result() != null); - return " version " + VersionNumber + ", Copyright (c) 2003-2014, Microsoft."; - } - } - public virtual string/*!*/ Version { - get { - Contract.Ensures(Contract.Result() != null); - return DescriptiveToolName + VersionSuffix; - } - } - - private string/*!*/ _fileTimestamp = cce.NonNull(DateTime.Now.ToString("o")).Replace(':', '.'); - - public string FileTimestamp { - get { - Contract.Ensures(Contract.Result() != null); - return this._fileTimestamp; - } - set { - Contract.Requires(value != null); - this._fileTimestamp = value; - } - } - - public void ExpandFilename(ref string pattern, string logPrefix, string fileTimestamp) { - if (pattern != null) { - pattern = pattern.Replace("@PREFIX@", logPrefix).Replace("@TIME@", fileTimestamp); - string fn = Files.Count == 0 ? "" : Files[Files.Count - 1]; - fn = fn.Replace('/', '-').Replace('\\', '-'); - pattern = pattern.Replace("@FILE@", fn); - } - } - - /// - /// Process the option and modify "ps" accordingly. - /// Return true if the option is one that is recognized. - /// - protected virtual bool ParseOption(string name, CommandLineParseState ps) { - Contract.Requires(name != null); - Contract.Requires(ps != null); - - switch (name) { - case "help": - case "?": - if (ps.ConfirmArgumentCount(0)) { - HelpRequested = true; - } - return true; - case "attrHelp": - if (ps.ConfirmArgumentCount(0)) { - AttrHelpRequested = true; - } - return true; - default: - break; - } - return false; // unrecognized option - } - - protected class CommandLineParseState - { - public string s; - public bool hasColonArgument; - public readonly string[]/*!*/ args; - public int i; - public int nextIndex; - public bool EncounteredErrors; - public readonly string ToolName; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(args != null); - Contract.Invariant(0 <= i && i <= args.Length); - Contract.Invariant(0 <= nextIndex && nextIndex <= args.Length); - } - - - public CommandLineParseState(string[] args, string toolName) { - Contract.Requires(args != null); - Contract.Requires(Contract.ForAll(0, args.Length, i => args[i] != null)); - Contract.Requires(toolName != null); - Contract.Ensures(this.args == args); - this.ToolName = toolName; - this.s = null; // set later by client - this.hasColonArgument = false; // set later by client - this.args = args; - this.i = 0; - this.nextIndex = 0; // set later by client - this.EncounteredErrors = false; - } - - public bool CheckBooleanFlag(string flagName, ref bool flag, bool valueWhenPresent) { - Contract.Requires(flagName != null); - //modifies nextIndex, encounteredErrors, Console.Error.*; - bool flagPresent = false; - - if ((s == "/" + flagName || s == "-" + flagName) && ConfirmArgumentCount(0)) { - flag = valueWhenPresent; - flagPresent = true; - } - return flagPresent; - } - - public bool CheckBooleanFlag(string flagName, ref bool flag) { - Contract.Requires(flagName != null); - //modifies nextIndex, encounteredErrors, Console.Error.*; - return CheckBooleanFlag(flagName, ref flag, true); - } - - /// - /// If there is one argument and it is a non-negative integer, then set "arg" to that number and return "true". - /// Otherwise, emit error message, leave "arg" unchanged, and return "false". - /// - public bool GetNumericArgument(ref int arg) { - //modifies nextIndex, encounteredErrors, Console.Error.*; - return GetNumericArgument(ref arg, a => 0 <= a); - } - - /// - /// If there is one argument and the filtering predicate holds, then set "arg" to that number and return "true". - /// Otherwise, emit error message, leave "arg" unchanged, and return "false". - /// - public bool GetNumericArgument(ref int arg, Predicate filter) { - Contract.Requires(filter != null); - - if (this.ConfirmArgumentCount(1)) { - try { - Contract.Assume(args[i] != null); - Contract.Assert(args[i] is string); // needed to prove args[i].IsPeerConsistent - int d = Convert.ToInt32(this.args[this.i]); - if (filter == null || filter(d)) { - arg = d; - return true; - } - } catch (System.FormatException) { - } catch (System.OverflowException) { - } - } else { - return false; - } - Error("Invalid argument \"{0}\" to option {1}", args[this.i], this.s); - return false; - } - - /// - /// If there is one argument and it is a non-negative integer less than "limit", - /// then set "arg" to that number and return "true". - /// Otherwise, emit error message, leave "arg" unchanged, and return "false". - /// - public bool GetNumericArgument(ref int arg, int limit) { - Contract.Requires(this.i < args.Length); - Contract.Ensures(Math.Min(arg, 0) <= Contract.ValueAtReturn(out arg) && Contract.ValueAtReturn(out arg) < limit); - //modifies nextIndex, encounteredErrors, Console.Error.*; - int a = arg; - if (!GetNumericArgument(ref a)) { - return false; - } else if (a < limit) { - arg = a; - return true; - } else { - Error("Invalid argument \"{0}\" to option {1}", args[this.i], this.s); - return false; - } - } - - /// - /// If there is one argument and it is a non-negative real, then set "arg" to that number and return "true". - /// Otherwise, emit an error message, leave "arg" unchanged, and return "false". - /// - public bool GetNumericArgument(ref double arg) { - Contract.Ensures(Contract.ValueAtReturn(out arg) >= 0); - //modifies nextIndex, encounteredErrors, Console.Error.*; - if (this.ConfirmArgumentCount(1)) { - try { - Contract.Assume(args[i] != null); - Contract.Assert(args[i] is string); // needed to prove args[i].IsPeerConsistent - double d = Convert.ToDouble(this.args[this.i]); - if (0 <= d) { - arg = d; - return true; - } - } catch (System.FormatException) { - } catch (System.OverflowException) { - } - } else { - return false; - } - Error("Invalid argument \"{0}\" to option {1}", args[this.i], this.s); - return false; - } - - public bool ConfirmArgumentCount(int argCount) { - Contract.Requires(0 <= argCount); - //modifies nextIndex, encounteredErrors, Console.Error.*; - Contract.Ensures(Contract.Result() == (!(hasColonArgument && argCount != 1) && !(args.Length < i + argCount))); - if (hasColonArgument && argCount != 1) { - Error("\"{0}\" cannot take a colon argument", s); - nextIndex = args.Length; - return false; - } else if (args.Length < i + argCount) { - Error("\"{0}\" expects {1} argument{2}", s, argCount.ToString(), (string)(argCount == 1 ? "" : "s")); - nextIndex = args.Length; - return false; - } else { - nextIndex = i + argCount; - return true; - } - } - - public void Error(string message, params string[] args) { - Contract.Requires(args != null); - Contract.Requires(message != null); - //modifies encounteredErrors, Console.Error.*; - Console.Error.WriteLine("{0}: Error: {1}", ToolName, String.Format(message, args)); - EncounteredErrors = true; - } - } - - public virtual void Usage() { - Console.WriteLine("{0}: usage: {0} [ option ... ] [ filename ... ]", ToolName); - Console.WriteLine(@" where