summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Absy.cs8985
-rw-r--r--Source/Core/AbsyCmd.cs6996
-rw-r--r--Source/Core/AbsyExpr.cs6671
-rw-r--r--Source/Core/AbsyQuant.cs1883
-rw-r--r--Source/Core/AbsyType.cs7812
-rw-r--r--Source/Core/AlphaEquality.cs324
-rw-r--r--Source/Core/BoogiePL.atg3022
-rw-r--r--Source/Core/CommandLineOptions.cs4328
-rw-r--r--Source/Core/Core.csproj470
-rw-r--r--Source/Core/DeadVarElim.cs3513
-rw-r--r--Source/Core/Duplicator.cs1623
-rw-r--r--Source/Core/Graph.as352
-rw-r--r--Source/Core/Inline.cs1538
-rw-r--r--Source/Core/InterProceduralReachabilityGraph.cs612
-rw-r--r--Source/Core/LambdaHelper.cs518
-rw-r--r--Source/Core/LoopUnroll.cs572
-rw-r--r--Source/Core/Makefile40
-rw-r--r--Source/Core/OOLongUtil.cs420
-rw-r--r--Source/Core/Parser.cs4848
-rw-r--r--Source/Core/Readme.txt122
-rw-r--r--Source/Core/ResolutionContext.cs1270
-rw-r--r--Source/Core/Scanner.cs1644
-rw-r--r--Source/Core/StandardVisitor.cs2334
-rw-r--r--Source/Core/TypeAmbiguitySeeker.cs244
-rw-r--r--Source/Core/Util.cs1376
-rw-r--r--Source/Core/VCExp.cs476
-rw-r--r--Source/Core/VariableDependenceAnalyser.cs1292
-rw-r--r--Source/Core/Xml.cs630
-rw-r--r--Source/Core/cce.cs384
29 files changed, 32088 insertions, 32211 deletions
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<CallSite>/*!*/ _returnPoints; // whenever OnExit changes, we start analysis again at all the ReturnPoints
-
- public HashSet<CallSite>/*!*/ ReturnPoints {
- get {
- Contract.Ensures(Contract.Result<HashSet<CallSite>>() != 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<CallSite>();
- }
-
- } // class
-
- public class ProcedureSummary : ArrayList/*<ProcedureSummaryEntry>*/
- {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(
- !IsReadOnly && !IsFixedSize);
- }
-
- public new ProcedureSummaryEntry/*!*/ this[int i] {
- get {
- Contract.Requires(0 <= i && i < Count);
- Contract.Ensures(Contract.Result<ProcedureSummaryEntry>() != 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<object>;
-
- [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<IToken>() != 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);
-
- /// <summary>
- /// Requires the object to have been successfully resolved.
- /// </summary>
- /// <param name="tc"></param>
- [NeedsContracts]
- public abstract void Typecheck(TypecheckingContext/*!*/ tc);
- /// <summary>
- /// Intorduced this so the uniqueId is not the same on a cloned object.
- /// </summary>
- /// <param name="tc"></param>
- public virtual Absy Clone() {
- Contract.Ensures(Contract.Result<Absy>() != 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<Object>(this.InternalNumberedMetadata);
- }
-
- return result;
- }
-
- public virtual Absy StdDispatch(StandardVisitor visitor) {
- Contract.Requires(visitor != null);
- Contract.Ensures(Contract.Result<Absy>() != 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<Object> 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();
-
- /// <summary>
- /// Gets the number of meta data objects associated with this instance
- /// </summary>
- /// <value>The numbered meta data count.</value>
- public int NumberedMetaDataCount
- {
- get { return InternalNumberedMetadata == null? 0: InternalNumberedMetadata.Count; }
- }
-
- /// <summary>
- /// Gets an IEnumerable over the numbered metadata associated
- /// with this instance.
- /// </summary>
- /// <value>
- /// The numbered meta data enumerable that looks like the Enumerable
- /// of a dictionary.
- /// </value>
- public IEnumerable<KeyValuePair<int, Object>> NumberedMetadata
- {
- get {
- if (InternalNumberedMetadata == null)
- return Enumerable.Empty<KeyValuePair<int,Object>>();
- else
- return InternalNumberedMetadata.Select((v, index) => new KeyValuePair<int, Object>(index, v));
- }
- }
-
- /// <summary>
- /// 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.
- /// </summary>
- /// <returns>The stored metadata of type T</returns>
- /// <param name="index">The index of the metadata</param>
- /// <typeparam name="T">The type of the metadata object required</typeparam>
- public T GetMetadata<T>(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<Object>();
- }
- }
- }
-
- /// <summary>
- /// Sets the metadata for this instace at a specified index.
- /// </summary>
- /// <param name="index">The index of the metadata</param>
- /// <param name="value">The value to set</param>
- /// <typeparam name="T">The type of value</typeparam>
- public void SetMetadata<T>(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<out TGet>
- {
- TGet ErrorData
- {
- get;
- }
- }
-
- public interface IPotentialErrorNode<out TGet, in TSet> : IPotentialErrorNode<TGet>
- {
- 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<Declaration>();
- }
-
- public void Emit(TokenTextWriter stream) {
- Contract.Requires(stream != null);
- stream.SetToken(this);
- this.topLevelDeclarations.Emit(stream);
- }
-
- public void ProcessDatatypeConstructors() {
- Dictionary<string, DatatypeConstructor> constructors = new Dictionary<string, DatatypeConstructor>();
- List<Declaration> prunedTopLevelDeclarations = new List<Declaration>();
- 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);
- }
- }
-
- /// <summary>
- /// Returns the number of name resolution errors.
- /// </summary>
- /// <returns></returns>
- 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<Declaration/*!*/>();
- 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<TypeCtorDecl>()) {
- if (!QKeyValue.FindBoolAttribute(d.Attributes, "ignore"))
- d.Resolve(rc);
- }
-
- // collect type synonym declarations
- List<TypeSynonymDecl/*!*/>/*!*/ synonymDecls = new List<TypeSynonymDecl/*!*/>();
- foreach (var d in TopLevelDeclarations.OfType<TypeSynonymDecl>()) {
- 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<Declaration>();
- cloned.AddTopLevelDeclarations(topLevelDeclarations);
- return cloned;
- }
-
- [Rep]
- private List<Declaration/*!*/>/*!*/ topLevelDeclarations;
-
- public IEnumerable<Declaration> TopLevelDeclarations
- {
- get
- {
- Contract.Ensures(cce.NonNullElements(Contract.Result<IEnumerable<Declaration>>()));
- 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<Declaration> 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<Declaration> 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<string, Implementation> implementationsCache;
- public IEnumerable<Implementation> Implementations
- {
- get
- {
- if (implementationsCache != null)
- {
- return implementationsCache.Values;
- }
- var result = TopLevelDeclarations.OfType<Implementation>();
- 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<Axiom> axiomsCache;
- public IEnumerable<Axiom> Axioms
- {
- get
- {
- if (axiomsCache != null)
- {
- return axiomsCache;
- }
- var result = TopLevelDeclarations.OfType<Axiom>();
- if (topLevelDeclarationsAreFrozen)
- {
- axiomsCache = result.ToList();
- }
- return result;
- }
- }
-
- Dictionary<string, Procedure> proceduresCache;
- public IEnumerable<Procedure> Procedures
- {
- get
- {
- if (proceduresCache != null)
- {
- return proceduresCache.Values;
- }
- var result = TopLevelDeclarations.OfType<Procedure>();
- 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<string, Function> functionsCache;
- public IEnumerable<Function> Functions
- {
- get
- {
- if (functionsCache != null)
- {
- return functionsCache.Values;
- }
- var result = TopLevelDeclarations.OfType<Function>();
- 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<Variable> Variables
- {
- get
- {
- return TopLevelDeclarations.OfType<Variable>();
- }
- }
-
- public IEnumerable<Constant> Constants
- {
- get
- {
- return TopLevelDeclarations.OfType<Constant>();
- }
- }
-
- private IEnumerable<GlobalVariable/*!*/> globalVariablesCache = null;
- public List<GlobalVariable/*!*/>/*!*/ GlobalVariables
- {
- get
- {
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<GlobalVariable>>()));
-
- if (globalVariablesCache == null)
- globalVariablesCache = TopLevelDeclarations.OfType<GlobalVariable>();
-
- return new List<GlobalVariable>(globalVariablesCache);
- }
- }
-
- public IEnumerable<Block> Blocks()
- {
- return Implementations.Select(Item => Item.Blocks).SelectMany(Item => Item);
- }
-
- public void ComputeStronglyConnectedComponents() {
- foreach (var d in this.TopLevelDeclarations) {
- d.ComputeStronglyConnectedComponents();
- }
- }
-
- /// <summary>
- /// Reset the abstract stated computed before
- /// </summary>
- 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<Block/*!*/>/*!*/ g,
- List<Implementation/*!*/>/*!*/ loopImpls,
- Dictionary<string, Dictionary<string, Block>> 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<Block/*!*/, List<Variable>/*!*/>/*!*/ loopHeaderToInputs = new Dictionary<Block/*!*/, List<Variable>/*!*/>();
- Dictionary<Block/*!*/, List<Variable>/*!*/>/*!*/ loopHeaderToOutputs = new Dictionary<Block/*!*/, List<Variable>/*!*/>();
- Dictionary<Block/*!*/, Dictionary<Variable, Expr>/*!*/>/*!*/ loopHeaderToSubstMap = new Dictionary<Block/*!*/, Dictionary<Variable, Expr>/*!*/>();
- Dictionary<Block/*!*/, LoopProcedure/*!*/>/*!*/ loopHeaderToLoopProc = new Dictionary<Block/*!*/, LoopProcedure/*!*/>();
- Dictionary<Block/*!*/, CallCmd/*!*/>/*!*/ loopHeaderToCallCmd1 = new Dictionary<Block/*!*/, CallCmd/*!*/>();
- Dictionary<Block, CallCmd> loopHeaderToCallCmd2 = new Dictionary<Block, CallCmd>();
- Dictionary<Block, AssignCmd> loopHeaderToAssignCmd = new Dictionary<Block, AssignCmd>();
-
- foreach (Block/*!*/ header in g.Headers) {
- Contract.Assert(header != null);
- Contract.Assert(header != null);
- List<Variable> inputs = new List<Variable>();
- List<Variable> outputs = new List<Variable>();
- List<Expr> callInputs1 = new List<Expr>();
- List<IdentifierExpr> callOutputs1 = new List<IdentifierExpr>();
- List<Expr> callInputs2 = new List<Expr>();
- List<IdentifierExpr> callOutputs2 = new List<IdentifierExpr>();
- List<AssignLhs> lhss = new List<AssignLhs>();
- List<Expr> rhss = new List<Expr>();
- Dictionary<Variable, Expr> substMap = new Dictionary<Variable, Expr>(); // Variable -> IdentifierExpr
-
- List<Variable>/*!*/ targets = new List<Variable>();
- HashSet<Variable> footprint = new HashSet<Variable>();
-
- 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<IdentifierExpr>/*!*/ globalMods = new List<IdentifierExpr>();
- 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<Block, Block> newBlocksCreated = new Dictionary<Block, Block>();
-
- bool headRecursion = false; // testing an option to put recursive call before loop body
-
- IEnumerable<Block> sortedHeaders = g.SortHeadersByDominance();
- foreach (Block/*!*/ header in sortedHeaders)
- {
- Contract.Assert(header != null);
- LoopProcedure loopProc = loopHeaderToLoopProc[header];
- Dictionary<Block, Block> blockMap = new Dictionary<Block, Block>();
- HashSet<string> dummyBlocks = new HashSet<string>();
-
- CodeCopier codeCopier = new CodeCopier(loopHeaderToSubstMap[header]); // fix me
- List<Variable> inputs = loopHeaderToInputs[header];
- List<Variable> 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<AssignLhs> lhsg = new List<AssignLhs>();
- List<IdentifierExpr>/*!*/ globalsMods = loopHeaderToLoopProc[header].Modifies;
- foreach (IdentifierExpr gl in globalsMods)
- lhsg.Add(new SimpleAssignLhs(Token.NoToken, gl));
- List<Expr> rhsg = new List<Expr>();
- 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<Cmd> cmdSeq;
- if (headRecursion)
- cmdSeq = new List<Cmd>();
- else
- {
- CallCmd callCmd = (CallCmd)(loopHeaderToCallCmd2[header]).Clone();
- addUniqueCallAttr(si_unique_loc, callCmd);
- si_unique_loc++;
- cmdSeq = new List<Cmd> { callCmd };
- }
-
- Block/*!*/ block1 = new Block(Token.NoToken, source.Label + "_dummy",
- new List<Cmd>{ 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<String>/*!*/ newLabels = new List<String>();
- List<Block>/*!*/ newTargets = new List<Block>();
- 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<Block/*!*/>/*!*/ blocks = new List<Block/*!*/>();
- Block exit = new Block(Token.NoToken, "exit", new List<Cmd>(), new ReturnCmd(Token.NoToken));
- GotoCmd cmd = new GotoCmd(Token.NoToken,
- new List<String> { cce.NonNull(blockMap[header]).Label, exit.Label },
- new List<Block> { blockMap[header], exit });
-
- if (detLoopExtract) //cutting the non-determinism
- cmd = new GotoCmd(Token.NoToken,
- new List<String> { cce.NonNull(blockMap[header]).Label },
- new List<Block> { blockMap[header] });
-
- Block entry;
- List<Cmd> initCmds = new List<Cmd>();
- 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<String> newLabels = new List<String>();
- List<Block> newTargets = new List<Block>();
- 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<TypeVariable>(), inputs, outputs, new List<Variable>(), 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<Cmd> { loopHeaderToCallCmd1[header] };
- header.TransferCmd = new GotoCmd(Token.NoToken, new List<String> { lastIterBlockName }, new List<Block> { 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<object>();
- 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<string, Dictionary<string, Block>> fullMap, string procName, string blockName, Block block)
- {
- if (!fullMap.ContainsKey(procName))
- fullMap[procName] = new Dictionary<string, Block>();
- fullMap[procName][blockName] = block;
- }
-
- public static Graph<Implementation> BuildCallGraph(Program program) {
- Graph<Implementation> callGraph = new Graph<Implementation>();
- Dictionary<Procedure, HashSet<Implementation>> procToImpls = new Dictionary<Procedure, HashSet<Implementation>>();
- foreach (var proc in program.Procedures) {
- procToImpls[proc] = new HashSet<Implementation>();
- }
- 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<Block/*!*/>/*!*/ GraphFromImpl(Implementation impl) {
- Contract.Requires(impl != null);
- Contract.Ensures(cce.NonNullElements(Contract.Result<Graph<Block>>().Nodes));
- Contract.Ensures(Contract.Result<Graph<Block>>() != null);
-
- Graph<Block/*!*/> g = new Graph<Block/*!*/>();
- 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<Block> ProcessLoops(Implementation impl) {
- while (true) {
- impl.PruneUnreachableBlocks();
- impl.ComputePredecessorsForBlocks();
- Graph<Block/*!*/>/*!*/ 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<Cmd> newCmdSeq = codeCopier.CopyCmdSeq(splitCandidate.Cmds);
- TransferCmd newTransferCmd;
- GotoCmd splitGotoCmd = splitCandidate.TransferCmd as GotoCmd;
- if (splitGotoCmd == null) {
- newTransferCmd = new ReturnCmd(splitCandidate.tok);
- }
- else {
- List<String> newLabelNames = new List<String>();
- newLabelNames.AddRange(splitGotoCmd.labelNames);
- List<Block> newLabelTargets = new List<Block>();
- 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<string, Dictionary<string, Block>> ExtractLoops()
- {
- HashSet<string> procsWithIrreducibleLoops = null;
- return ExtractLoops(out procsWithIrreducibleLoops);
- }
-
- public Dictionary<string, Dictionary<string, Block>> ExtractLoops(out HashSet<string> procsWithIrreducibleLoops)
- {
- procsWithIrreducibleLoops = new HashSet<string>();
- List<Implementation/*!*/>/*!*/ loopImpls = new List<Implementation/*!*/>();
- Dictionary<string, Dictionary<string, Block>> fullMap = new Dictionary<string, Dictionary<string, Block>>();
- foreach (var impl in this.Implementations)
- {
- if (impl.Blocks != null && impl.Blocks.Count > 0)
- {
- try
- {
- Graph<Block> 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<string, Block>();
- 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<string, Block>();
- 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<Absy>() != 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<object>(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);
- }
- }
-
- /// <summary>
- /// 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.
- /// </summary>
- 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;
- }
-
- /// <summary>
- /// Find and return the last occurrence of an attribute with the name "name", if any. If none, return null.
- /// </summary>
- 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<object/*!*/>(vals), Attributes);
- }
- }
-
- public abstract void Emit(TokenTextWriter/*!*/ stream, int level);
- public abstract void Register(ResolutionContext/*!*/ rc);
-
- /// <summary>
- /// Compute the strongly connected components of the declaration.
- /// By default, it does nothing
- /// </summary>
- public virtual void ComputeStronglyConnectedComponents() { /* Does nothing */
- }
-
- /// <summary>
- /// Reset the abstract stated computed before
- /// </summary>
- 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<Expr>() != 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<Function> functionDependencies;
-
- public ISet<Function> FunctionDependencies
- {
- get { return functionDependencies; }
- }
-
- public void AddFunctionDependency(Function function)
- {
- Contract.Requires(function != null);
-
- if (functionDependencies == null)
- {
- functionDependencies = new HashSet<Function>();
- }
- 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<Absy>() != 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<string>() != 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<string>() != 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<Absy>() != null);
- return visitor.VisitTypeCtorDecl(this);
- }
- }
-
- public class TypeSynonymDecl : NamedDeclaration {
- private List<TypeVariable>/*!*/ typeParameters;
-
- public List<TypeVariable> TypeParameters {
- get {
- Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
- return this.typeParameters;
- }
- set {
- Contract.Requires(value != null);
- this.typeParameters = value;
- }
- }
-
- private Type/*!*/ body;
-
- public Type Body {
- get {
- Contract.Ensures(Contract.Result<Type>() != 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<TypeVariable>/*!*/ 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<TypeVariable>/*!*/ 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<TypeSynonymDecl/*!*/>/*!*/ synonymDecls, ResolutionContext/*!*/ rc) {
- Contract.Requires(cce.NonNullElements(synonymDecls));
- Contract.Requires(rc != null);
- // then discover all dependencies between type synonyms
- IDictionary<TypeSynonymDecl/*!*/, List<TypeSynonymDecl/*!*/>/*!*/>/*!*/ deps =
- new Dictionary<TypeSynonymDecl/*!*/, List<TypeSynonymDecl/*!*/>/*!*/>();
- foreach (TypeSynonymDecl/*!*/ decl in synonymDecls) {
- Contract.Assert(decl != null);
- List<TypeSynonymDecl/*!*/>/*!*/ declDeps = new List<TypeSynonymDecl/*!*/>();
- FindDependencies(decl.Body, declDeps, rc);
- deps.Add(decl, declDeps);
- }
-
- List<TypeSynonymDecl/*!*/>/*!*/ resolved = new List<TypeSynonymDecl/*!*/>();
-
- 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<TypeSynonymDecl/*!*/>/*!*/ 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<Absy>() != null);
- return visitor.VisitTypeSynonymDecl(this);
- }
- }
-
- public abstract class Variable : NamedDeclaration {
- private TypedIdent/*!*/ typedIdent;
-
- public TypedIdent TypedIdent {
- get {
- Contract.Ensures(Contract.Result<TypedIdent>() != 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<ConstantParent/*!*/> 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<ConstantParent/*!*/> 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<ConstantParent>(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<Absy>() != 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<Absy>() != 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);
- }
-
- /// <summary>
- /// 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.
- /// </summary>
- public static List<Variable> StripWhereClauses(List<Variable> w) {
- Contract.Requires(w != null);
- Contract.Ensures(Contract.Result<List<Variable>>() != null);
- List<Variable> s = new List<Variable>();
- 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<Absy>() != 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<Absy>() != 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<Absy>() != null);
- return visitor.VisitBoundVariable(this);
- }
- }
-
- public abstract class DeclWithFormals : NamedDeclaration {
- public List<TypeVariable>/*!*/ TypeParameters;
-
- private /*readonly--except in StandardVisitor*/ List<Variable>/*!*/ inParams, outParams;
-
- public List<Variable>/*!*/ InParams {
- get {
- Contract.Ensures(Contract.Result<List<Variable>>() != null);
- return this.inParams;
- }
- set {
- Contract.Requires(value != null);
- this.inParams = value;
- }
- }
-
- public List<Variable>/*!*/ OutParams
- {
- get {
- Contract.Ensures(Contract.Result<List<Variable>>() != 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<TypeVariable> typeParams,
- List<Variable> inParams, List<Variable> 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<Function>();
- 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<Function>(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<Procedure> procedureDependencies;
-
- public ISet<Procedure> ProcedureDependencies
- {
- get { return procedureDependencies; }
- }
-
- public void AddProcedureDependency(Procedure procedure)
- {
- Contract.Requires(procedure != null);
-
- if (procedureDependencies == null)
- {
- procedureDependencies = new HashSet<Procedure>();
- }
- procedureDependencies.Add(procedure);
- }
-
- ISet<Function> functionDependencies;
-
- public ISet<Function> FunctionDependencies
- {
- get { return functionDependencies; }
- }
-
- public void AddFunctionDependency(Function function)
- {
- Contract.Requires(function != null);
-
- if (functionDependencies == null)
- {
- functionDependencies = new HashSet<Function>();
- }
- 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<Type>/*!*/ allTypes = new List<Type>(InParams.Select(Item => Item.TypedIdent.Type).ToArray());
- Contract.Assert(allTypes != null);
- allTypes.AddRange(new List<Type>(OutParams.Select(Item => Item.TypedIdent.Type).ToArray()));
- TypeParameters = Type.SortTypeParams(TypeParameters, allTypes, null);
- }
-
- /// <summary>
- /// 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.
- /// </summary>
- /// <param name="rc"></param>
- protected void RegisterFormals(List<Variable> 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);
- }
- }
-
- /// <summary>
- /// Resolves the where clauses (and attributes) of the formals.
- /// </summary>
- /// <param name="rc"></param>
- protected void ResolveFormals(List<Variable> 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<DatatypeSelector> 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<DatatypeSelector>();
- }
-
- public override void Resolve(ResolutionContext rc) {
- HashSet<string> selectorNames = new HashSet<string>();
- 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<Variable> { 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<Variable> { 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<Axiom> otherDefinitionAxioms;
- public IEnumerable<Axiom> OtherDefinitionAxioms
- {
- get
- {
- return otherDefinitionAxioms;
- }
- }
-
- public void AddOtherDefinitionAxiom(Axiom axiom)
- {
- Contract.Requires(axiom != null);
-
- if (otherDefinitionAxioms == null)
- {
- otherDefinitionAxioms = new List<Axiom>();
- }
- otherDefinitionAxioms.Add(axiom);
- }
-
- public bool doingExpansion;
-
- private bool neverTrigger;
- private bool neverTriggerComputed;
-
- public Function(IToken tok, string name, List<Variable> args, Variable result)
- : this(tok, name, new List<TypeVariable>(), args, result, null) {
- Contract.Requires(result != null);
- Contract.Requires(args != null);
- Contract.Requires(name != null);
- Contract.Requires(tok != null);
- //:this(tok, name, new List<TypeVariable>(), args, result, null);
- }
- public Function(IToken tok, string name, List<TypeVariable> typeParams, List<Variable> 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<Variable> args, Variable result, string comment)
- : this(tok, name, new List<TypeVariable>(), args, result, comment) {
- Contract.Requires(result != null);
- Contract.Requires(args != null);
- Contract.Requires(name != null);
- Contract.Requires(tok != null);
- //:this(tok, name, new List<TypeVariable>(), args, result, comment);
- }
- public Function(IToken tok, string name, List<TypeVariable> typeParams, List<Variable> args, Variable/*!*/ result, string comment)
- : base(tok, name, typeParams, args, new List<Variable> { 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<TypeVariable> typeParams, List<Variable> 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<Type>(InParams.Select(Item => Item.TypedIdent.Type).ToArray()),
- new List<Type>(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<Absy>() != null);
- return visitor.VisitFunction(this);
- }
-
- public Axiom CreateDefinitionAxiom(Expr definition, QKeyValue kv = null) {
- Contract.Requires(definition != null);
-
- List<Variable> dummies = new List<Variable>();
- List<Expr> callArgs = new List<Expr>();
- 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<TypeVariable>/*!*/ quantifiedTypeVars = new List<TypeVariable>();
- 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<Expr> { call }, null),
- def);
- }
- DefinitionAxiom = new Axiom(tok, def);
- return DefinitionAxiom;
- }
- }
-
- public class Macro : Function {
- public Macro(IToken tok, string name, List<Variable> args, Variable result)
- : base(tok, name, args, result) { }
- }
-
- public class Requires : Absy, IPotentialErrorNode<string, string> {
- public readonly bool Free;
-
- private Expr/*!*/ _condition;
-
- public Expr/*!*/ Condition {
- get {
- Contract.Ensures(Contract.Result<Expr>() != 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<string, string> {
- public readonly bool Free;
-
- private Expr/*!*/ _condition;
-
- public Expr/*!*/ Condition {
- get {
- Contract.Ensures(Contract.Result<Expr>() != 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>/*!*/ Requires;
- public List<IdentifierExpr>/*!*/ Modifies;
- public List<Ensures>/*!*/ 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<TypeVariable>/*!*/ typeParams, List<Variable>/*!*/ inParams, List<Variable>/*!*/ outParams,
- List<Requires>/*!*/ requires, List<IdentifierExpr>/*!*/ modifies, List<Ensures>/*!*/ 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<TypeVariable>/*!*/ typeParams, List<Variable>/*!*/ inParams, List<Variable>/*!*/ outParams,
- List<Requires>/*!*/ @requires, List<IdentifierExpr>/*!*/ @modifies, List<Ensures>/*!*/ @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<Type>(InParams.Select(Item => Item.TypedIdent.Type).ToArray()),
- new List<Type>(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<Absy>() != null);
- return visitor.VisitProcedure(this);
- }
- }
-
- public class LoopProcedure : Procedure
- {
- public Implementation enclosingImpl;
- private Dictionary<Block, Block> blockMap;
- private Dictionary<string, Block> blockLabelMap;
-
- public LoopProcedure(Implementation impl, Block header,
- List<Variable> inputs, List<Variable> outputs, List<IdentifierExpr> globalMods)
- : base(Token.NoToken, impl.Name + "_loop_" + header.ToString(),
- new List<TypeVariable>(), inputs, outputs,
- new List<Requires>(), globalMods, new List<Ensures>())
- {
- enclosingImpl = impl;
- }
-
- public void setBlockMap(Dictionary<Block, Block> bm)
- {
- blockMap = bm;
- blockLabelMap = new Dictionary<string, Block>();
- 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<Variable>/*!*/ LocVars;
- [Rep]
- public StmtList StructuredStmts;
- [Rep]
- public List<Block/*!*/>/*!*/ Blocks;
- public Procedure Proc;
-
- // Blocks before applying passification etc.
- // Both are used only when /inline is set.
- public List<Block/*!*/> OriginalBlocks;
- public List<Variable> OriginalLocVars;
-
- public readonly ISet<byte[]> AssertionChecksums = new HashSet<byte[]>(ChecksumComparer.Default);
-
- public sealed class ChecksumComparer : IEqualityComparer<byte[]>
- {
- static IEqualityComparer<byte[]> defaultComparer;
- public static IEqualityComparer<byte[]> 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<byte[]> AssertionChecksumsInCachedSnapshot { get; set; }
-
- public bool IsAssertionChecksumInCachedSnapshot(byte[] checksum)
- {
- Contract.Requires(AssertionChecksumsInCachedSnapshot != null);
-
- return AssertionChecksumsInCachedSnapshot.Contains(checksum);
- }
-
- public IList<AssertCmd> RecycledFailingAssertions { get; protected set; }
-
- public void AddRecycledFailingAssertion(AssertCmd assertion)
- {
- if (RecycledFailingAssertions == null)
- {
- RecycledFailingAssertions = new List<AssertCmd>();
- }
- RecycledFailingAssertions.Add(assertion);
- }
-
- // Strongly connected components
- private StronglyConnectedComponents<Block/*!*/> 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<byte[], object> ErrorChecksumToCachedError { get; private set; }
-
- public bool IsErrorChecksumInCachedSnapshot(byte[] checksum)
- {
- Contract.Requires(ErrorChecksumToCachedError != null);
-
- return ErrorChecksumToCachedError.ContainsKey(checksum);
- }
-
- public void SetErrorChecksumToCachedError(IEnumerable<Tuple<byte[], byte[], object>> errors)
- {
- Contract.Requires(errors != null);
-
- ErrorChecksumToCachedError = new Dictionary<byte[], object>(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<LocalVariable> injectedAssumptionVariables;
- public IList<LocalVariable> InjectedAssumptionVariables
- {
- get
- {
- return injectedAssumptionVariables != null ? injectedAssumptionVariables : new List<LocalVariable>();
- }
- }
-
- IList<LocalVariable> doomedInjectedAssumptionVariables;
- public IList<LocalVariable> DoomedInjectedAssumptionVariables
- {
- get
- {
- return doomedInjectedAssumptionVariables != null ? doomedInjectedAssumptionVariables : new List<LocalVariable>();
- }
- }
-
- public List<LocalVariable> RelevantInjectedAssumptionVariables(Dictionary<Variable, Expr> 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<LocalVariable> RelevantDoomedInjectedAssumptionVariables(Dictionary<Variable, Expr> 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<Variable, Expr> 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<LocalVariable>();
- }
- doomedInjectedAssumptionVariables.Add(variable);
- }
- else
- {
- if (injectedAssumptionVariables == null)
- {
- injectedAssumptionVariables = new List<LocalVariable>();
- }
- injectedAssumptionVariables.Add(variable);
- }
- }
-
- public Implementation(IToken tok, string name, List<TypeVariable> typeParams, List<Variable> inParams, List<Variable> outParams, List<Variable> 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<TypeVariable> typeParams, List<Variable> inParams, List<Variable> outParams, List<Variable> 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<TypeVariable> typeParams, List<Variable> inParams, List<Variable> outParams, List<Variable> 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<TypeVariable>/*!*/ typeParams,
- List<Variable>/*!*/ inParams,
- List<Variable>/*!*/ outParams,
- List<Variable>/*!*/ 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<TypeVariable> typeParams, List<Variable> inParams, List<Variable> outParams, List<Variable> localVariables, [Captured] List<Block/*!*/> 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<TypeVariable>/*!*/ typeParams,
- List<Variable>/*!*/ inParams,
- List<Variable>/*!*/ outParams,
- List<Variable>/*!*/ localVariables,
- [Captured] List<Block/*!*/>/*!*/ 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<Type>(InParams.Select(Item => Item.TypedIdent.Type).ToArray()),
- new List<Type>(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<IdentifierExpr> 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<Variable>/*!*/ implFormals, List<Variable>/*!*/ 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst1 =
- new Dictionary<TypeVariable/*!*/, Type/*!*/>();
- IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ subst2 =
- new Dictionary<TypeVariable/*!*/, Type/*!*/>();
-
- 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<Variable, Expr>/*?*/ formalMap = null;
- public void ResetImplFormalMap() {
- this.formalMap = null;
- }
- public Dictionary<Variable, Expr>/*!*/ GetImplFormalMap() {
- Contract.Ensures(Contract.Result<Dictionary<Variable, Expr>>() != null);
-
- if (this.formalMap != null)
- return this.formalMap;
- else {
- Dictionary<Variable, Expr>/*!*/ map = new Dictionary<Variable, Expr> (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>", 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;
- }
- }
-
- /// <summary>
- /// Return a collection of blocks that are reachable from the block passed as a parameter.
- /// The block must be defined in the current implementation
- /// </summary>
- public ICollection<Block/*!*/> GetConnectedComponents(Block startingBlock) {
- Contract.Requires(startingBlock != null);
- Contract.Ensures(cce.NonNullElements(Contract.Result<ICollection<Block>>(), 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<Block/*!*/> 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.
- }
-
- /// <summary>
- /// 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
- /// </summary>
- override public void ComputeStronglyConnectedComponents() {
- if (!this.BlockPredecessorsComputed)
- ComputePredecessorsForBlocks();
-
- Adjacency<Block/*!*/> next = new Adjacency<Block/*!*/>(Successors);
- Adjacency<Block/*!*/> prev = new Adjacency<Block/*!*/>(Predecessors);
-
- this.scc = new StronglyConnectedComponents<Block/*!*/>(this.Blocks, next, prev);
- scc.Compute();
-
-
- foreach (Block/*!*/ block in this.Blocks) {
- Contract.Assert(block != null);
- block.Predecessors = new List<Block>();
- }
-
- }
-
- /// <summary>
- /// Reset the abstract stated computed before
- /// </summary>
- override public void ResetAbstractInterpretationState() {
- foreach (Block/*!*/ b in this.Blocks) {
- Contract.Assert(b != null);
- b.ResetAbstractInterpretationState();
- }
- }
-
- /// <summary>
- /// A private method used as delegate for the strongly connected components.
- /// It return, given a node, the set of its successors
- /// </summary>
- private IEnumerable/*<Block!>*//*!*/ Successors(Block node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<IEnumerable>() != 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<Block/*!*/>();
- }
- }
-
- /// <summary>
- /// A private method used as delegate for the strongly connected components.
- /// It return, given a node, the set of its predecessors
- /// </summary>
- private IEnumerable/*<Block!>*//*!*/ Predecessors(Block node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<IEnumerable>() != null);
-
- Contract.Assert(this.BlockPredecessorsComputed);
-
- return node.Predecessors;
- }
-
- /// <summary>
- /// Compute the predecessor informations for the blocks
- /// </summary>
- public void ComputePredecessorsForBlocks() {
- foreach (Block b in this.Blocks) {
- b.Predecessors = new List<Block>();
- }
- 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<Block/*!*/> reachableBlocks = new List<Block/*!*/>();
- HashSet<Block> reachable = new HashSet<Block>(); // 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<Absy>() != 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<Cmd> newCmds = new List<Cmd>();
- 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<object>() { 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<string>() != null);
- return this._name;
- }
- set {
- Contract.Requires(value != null);
- this._name = value;
- }
- }
-
- private Type/*!*/ _type;
-
- public Type/*!*/ Type {
- get {
- Contract.Ensures(Contract.Result<Type>() != 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<Absy>() != null);
- return visitor.VisitTypedIdent(this);
- }
- }
-
- #region Helper methods for generic Sequences
-
- public static class TypeVariableSeqAlgorithms {
- public static void AppendWithoutDups(this List<TypeVariable> tvs, List<TypeVariable> 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<Declaration/*!*/>/*!*/ 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<String> 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<Expr> 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<IdentifierExpr> 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<Variable> 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<Type> 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<TypeVariable> 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<Variable> vars) {
- //Contract.Requires(vars != null);
- throw new NotImplementedException();
- }
- }
- public class AtomicRE : RE {
- private Block/*!*/ _b;
-
- public Block b
- {
- get
- {
- Contract.Ensures(Contract.Result<Block>() != 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<Absy>() != 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<RE>() != null);
- return this._first;
- }
- set {
- Contract.Requires(value != null);
- this._first = value;
- }
- }
-
- private RE/*!*/ _second;
-
- public RE/*!*/ second {
- get {
- Contract.Ensures(Contract.Result<RE>() != 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<Absy>() != null);
- return visitor.VisitSequential(this);
- }
- }
- public class Choice : CompoundRE {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(this._rs != null);
- }
-
- private List<RE>/*!*/ _rs;
-
- public List<RE>/*!*/ rs { //Rename this (and _rs) if possible
- get {
- Contract.Ensures(Contract.Result<List<RE>>() != null);
- return this._rs;
- }
- set {
- Contract.Requires(value != null);
- this._rs = value;
- }
- }
-
- public Choice(List<RE> 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<Absy>() != null);
- return visitor.VisitChoice(this);
- }
- }
- public class DAG2RE {
- public static RE Transform(Block b) {
- Contract.Requires(b != null);
- Contract.Ensures(Contract.Result<RE>() != 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<RE> rs = new List<RE>();
- 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<CallSite>/*!*/ _returnPoints; // whenever OnExit changes, we start analysis again at all the ReturnPoints
+
+ public HashSet<CallSite>/*!*/ ReturnPoints {
+ get {
+ Contract.Ensures(Contract.Result<HashSet<CallSite>>() != 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<CallSite>();
+ }
+
+ } // class
+
+ public class ProcedureSummary : ArrayList/*<ProcedureSummaryEntry>*/
+ {
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(
+ !IsReadOnly && !IsFixedSize);
+ }
+
+ public new ProcedureSummaryEntry/*!*/ this[int i] {
+ get {
+ Contract.Requires(0 <= i && i < Count);
+ Contract.Ensures(Contract.Result<ProcedureSummaryEntry>() != 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<object>;
+
+ [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<IToken>() != 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);
+
+ /// <summary>
+ /// Requires the object to have been successfully resolved.
+ /// </summary>
+ /// <param name="tc"></param>
+ [NeedsContracts]
+ public abstract void Typecheck(TypecheckingContext/*!*/ tc);
+ /// <summary>
+ /// Intorduced this so the uniqueId is not the same on a cloned object.
+ /// </summary>
+ /// <param name="tc"></param>
+ public virtual Absy Clone() {
+ Contract.Ensures(Contract.Result<Absy>() != 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<Object>(this.InternalNumberedMetadata);
+ }
+
+ return result;
+ }
+
+ public virtual Absy StdDispatch(StandardVisitor visitor) {
+ Contract.Requires(visitor != null);
+ Contract.Ensures(Contract.Result<Absy>() != 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<Object> 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();
+
+ /// <summary>
+ /// Gets the number of meta data objects associated with this instance
+ /// </summary>
+ /// <value>The numbered meta data count.</value>
+ public int NumberedMetaDataCount
+ {
+ get { return InternalNumberedMetadata == null? 0: InternalNumberedMetadata.Count; }
+ }
+
+ /// <summary>
+ /// Gets an IEnumerable over the numbered metadata associated
+ /// with this instance.
+ /// </summary>
+ /// <value>
+ /// The numbered meta data enumerable that looks like the Enumerable
+ /// of a dictionary.
+ /// </value>
+ public IEnumerable<KeyValuePair<int, Object>> NumberedMetadata
+ {
+ get {
+ if (InternalNumberedMetadata == null)
+ return Enumerable.Empty<KeyValuePair<int,Object>>();
+ else
+ return InternalNumberedMetadata.Select((v, index) => new KeyValuePair<int, Object>(index, v));
+ }
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ /// <returns>The stored metadata of type T</returns>
+ /// <param name="index">The index of the metadata</param>
+ /// <typeparam name="T">The type of the metadata object required</typeparam>
+ public T GetMetadata<T>(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<Object>();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Sets the metadata for this instace at a specified index.
+ /// </summary>
+ /// <param name="index">The index of the metadata</param>
+ /// <param name="value">The value to set</param>
+ /// <typeparam name="T">The type of value</typeparam>
+ public void SetMetadata<T>(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<out TGet>
+ {
+ TGet ErrorData
+ {
+ get;
+ }
+ }
+
+ public interface IPotentialErrorNode<out TGet, in TSet> : IPotentialErrorNode<TGet>
+ {
+ 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<Declaration>();
+ }
+
+ public void Emit(TokenTextWriter stream) {
+ Contract.Requires(stream != null);
+ stream.SetToken(this);
+ this.topLevelDeclarations.Emit(stream);
+ }
+
+ public void ProcessDatatypeConstructors() {
+ Dictionary<string, DatatypeConstructor> constructors = new Dictionary<string, DatatypeConstructor>();
+ List<Declaration> prunedTopLevelDeclarations = new List<Declaration>();
+ 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);
+ }
+ }
+
+ /// <summary>
+ /// Returns the number of name resolution errors.
+ /// </summary>
+ /// <returns></returns>
+ 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<Declaration/*!*/>();
+ 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<TypeCtorDecl>()) {
+ if (!QKeyValue.FindBoolAttribute(d.Attributes, "ignore"))
+ d.Resolve(rc);
+ }
+
+ // collect type synonym declarations
+ List<TypeSynonymDecl/*!*/>/*!*/ synonymDecls = new List<TypeSynonymDecl/*!*/>();
+ foreach (var d in TopLevelDeclarations.OfType<TypeSynonymDecl>()) {
+ 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<Declaration>();
+ cloned.AddTopLevelDeclarations(topLevelDeclarations);
+ return cloned;
+ }
+
+ [Rep]
+ private List<Declaration/*!*/>/*!*/ topLevelDeclarations;
+
+ public IEnumerable<Declaration> TopLevelDeclarations
+ {
+ get
+ {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<IEnumerable<Declaration>>()));
+ 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<Declaration> 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<Declaration> 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<string, Implementation> implementationsCache;
+ public IEnumerable<Implementation> Implementations
+ {
+ get
+ {
+ if (implementationsCache != null)
+ {
+ return implementationsCache.Values;
+ }
+ var result = TopLevelDeclarations.OfType<Implementation>();
+ 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<Axiom> axiomsCache;
+ public IEnumerable<Axiom> Axioms
+ {
+ get
+ {
+ if (axiomsCache != null)
+ {
+ return axiomsCache;
+ }
+ var result = TopLevelDeclarations.OfType<Axiom>();
+ if (topLevelDeclarationsAreFrozen)
+ {
+ axiomsCache = result.ToList();
+ }
+ return result;
+ }
+ }
+
+ Dictionary<string, Procedure> proceduresCache;
+ public IEnumerable<Procedure> Procedures
+ {
+ get
+ {
+ if (proceduresCache != null)
+ {
+ return proceduresCache.Values;
+ }
+ var result = TopLevelDeclarations.OfType<Procedure>();
+ 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<string, Function> functionsCache;
+ public IEnumerable<Function> Functions
+ {
+ get
+ {
+ if (functionsCache != null)
+ {
+ return functionsCache.Values;
+ }
+ var result = TopLevelDeclarations.OfType<Function>();
+ 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<Variable> Variables
+ {
+ get
+ {
+ return TopLevelDeclarations.OfType<Variable>();
+ }
+ }
+
+ public IEnumerable<Constant> Constants
+ {
+ get
+ {
+ return TopLevelDeclarations.OfType<Constant>();
+ }
+ }
+
+ private IEnumerable<GlobalVariable/*!*/> globalVariablesCache = null;
+ public List<GlobalVariable/*!*/>/*!*/ GlobalVariables
+ {
+ get
+ {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<GlobalVariable>>()));
+
+ if (globalVariablesCache == null)
+ globalVariablesCache = TopLevelDeclarations.OfType<GlobalVariable>();
+
+ return new List<GlobalVariable>(globalVariablesCache);
+ }
+ }
+
+ public readonly ISet<string> NecessaryAssumes = new HashSet<string>();
+
+ public IEnumerable<Block> Blocks()
+ {
+ return Implementations.Select(Item => Item.Blocks).SelectMany(Item => Item);
+ }
+
+ public void ComputeStronglyConnectedComponents() {
+ foreach (var d in this.TopLevelDeclarations) {
+ d.ComputeStronglyConnectedComponents();
+ }
+ }
+
+ /// <summary>
+ /// Reset the abstract stated computed before
+ /// </summary>
+ 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();
+ }
+ }
+ }
+
+
+ /// <summary>
+ /// Finds blocks that break out of a loop in NaturalLoops(header, backEdgeNode)
+ /// </summary>
+ /// <param name="header"></param>
+ /// <param name="backEdgeNode"></param>
+ /// <returns></returns>
+ private HashSet<Block> GetBreakBlocksOfLoop(Block header, Block backEdgeNode, Graph<Block/*!*/>/*!*/ g)
+ {
+ Contract.Assert(CommandLineOptions.Clo.DeterministicExtractLoops, "Can only be called with /deterministicExtractLoops option");
+ var immSuccBlks = new HashSet<Block>();
+ 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<Block> GetBlocksInAllNaturalLoops(Block header, Graph<Block/*!*/>/*!*/ g)
+ {
+ Contract.Assert(CommandLineOptions.Clo.DeterministicExtractLoops, "Can only be called with /deterministicExtractLoops option");
+ var allBlocksInNaturalLoops = new HashSet<Block>();
+ 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<Block/*!*/>/*!*/ g,
+ List<Implementation/*!*/>/*!*/ loopImpls,
+ Dictionary<string, Dictionary<string, Block>> 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<Block/*!*/, List<Variable>/*!*/>/*!*/ loopHeaderToInputs = new Dictionary<Block/*!*/, List<Variable>/*!*/>();
+ Dictionary<Block/*!*/, List<Variable>/*!*/>/*!*/ loopHeaderToOutputs = new Dictionary<Block/*!*/, List<Variable>/*!*/>();
+ Dictionary<Block/*!*/, Dictionary<Variable, Expr>/*!*/>/*!*/ loopHeaderToSubstMap = new Dictionary<Block/*!*/, Dictionary<Variable, Expr>/*!*/>();
+ Dictionary<Block/*!*/, LoopProcedure/*!*/>/*!*/ loopHeaderToLoopProc = new Dictionary<Block/*!*/, LoopProcedure/*!*/>();
+ Dictionary<Block/*!*/, CallCmd/*!*/>/*!*/ loopHeaderToCallCmd1 = new Dictionary<Block/*!*/, CallCmd/*!*/>();
+ Dictionary<Block, CallCmd> loopHeaderToCallCmd2 = new Dictionary<Block, CallCmd>();
+ Dictionary<Block, AssignCmd> loopHeaderToAssignCmd = new Dictionary<Block, AssignCmd>();
+
+ foreach (Block/*!*/ header in g.Headers) {
+ Contract.Assert(header != null);
+ Contract.Assert(header != null);
+ List<Variable> inputs = new List<Variable>();
+ List<Variable> outputs = new List<Variable>();
+ List<Expr> callInputs1 = new List<Expr>();
+ List<IdentifierExpr> callOutputs1 = new List<IdentifierExpr>();
+ List<Expr> callInputs2 = new List<Expr>();
+ List<IdentifierExpr> callOutputs2 = new List<IdentifierExpr>();
+ List<AssignLhs> lhss = new List<AssignLhs>();
+ List<Expr> rhss = new List<Expr>();
+ Dictionary<Variable, Expr> substMap = new Dictionary<Variable, Expr>(); // Variable -> IdentifierExpr
+
+ List<Variable>/*!*/ targets = new List<Variable>();
+ HashSet<Variable> footprint = new HashSet<Variable>();
+
+ foreach (Block/*!*/ b in g.BackEdgeNodes(header))
+ {
+ Contract.Assert(b != null);
+ HashSet<Block> immSuccBlks = new HashSet<Block>();
+ 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<IdentifierExpr>/*!*/ globalMods = new List<IdentifierExpr>();
+ 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<Block, Block> newBlocksCreated = new Dictionary<Block, Block>();
+
+ bool headRecursion = false; // testing an option to put recursive call before loop body
+
+ IEnumerable<Block> sortedHeaders = g.SortHeadersByDominance();
+ foreach (Block/*!*/ header in sortedHeaders)
+ {
+ Contract.Assert(header != null);
+ LoopProcedure loopProc = loopHeaderToLoopProc[header];
+ Dictionary<Block, Block> blockMap = new Dictionary<Block, Block>();
+ HashSet<string> dummyBlocks = new HashSet<string>();
+
+ CodeCopier codeCopier = new CodeCopier(loopHeaderToSubstMap[header]); // fix me
+ List<Variable> inputs = loopHeaderToInputs[header];
+ List<Variable> 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<AssignLhs> lhsg = new List<AssignLhs>();
+ List<IdentifierExpr>/*!*/ globalsMods = loopHeaderToLoopProc[header].Modifies;
+ foreach (IdentifierExpr gl in globalsMods)
+ lhsg.Add(new SimpleAssignLhs(Token.NoToken, gl));
+ List<Expr> rhsg = new List<Expr>();
+ 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<Cmd> cmdSeq;
+ if (headRecursion)
+ cmdSeq = new List<Cmd>();
+ else
+ {
+ CallCmd callCmd = (CallCmd)(loopHeaderToCallCmd2[header]).Clone();
+ addUniqueCallAttr(si_unique_loc, callCmd);
+ si_unique_loc++;
+ cmdSeq = new List<Cmd> { callCmd };
+ }
+
+ Block/*!*/ block1 = new Block(Token.NoToken, source.Label + "_dummy",
+ new List<Cmd>{ 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<String>/*!*/ newLabels = new List<String>();
+ List<Block>/*!*/ newTargets = new List<Block>();
+ 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<Block/*!*/>/*!*/ blocks = new List<Block/*!*/>();
+ Block exit = new Block(Token.NoToken, "exit", new List<Cmd>(), new ReturnCmd(Token.NoToken));
+ GotoCmd cmd = new GotoCmd(Token.NoToken,
+ new List<String> { cce.NonNull(blockMap[header]).Label, exit.Label },
+ new List<Block> { blockMap[header], exit });
+
+ if (detLoopExtract) //cutting the non-determinism
+ cmd = new GotoCmd(Token.NoToken,
+ new List<String> { cce.NonNull(blockMap[header]).Label },
+ new List<Block> { blockMap[header] });
+
+ Block entry;
+ List<Cmd> initCmds = new List<Cmd>();
+ 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<String> newLabels = new List<String>();
+ List<Block> newTargets = new List<Block>();
+ 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<TypeVariable>(), inputs, outputs, new List<Variable>(), 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<Cmd> { loopHeaderToCallCmd1[header] };
+ header.TransferCmd = new GotoCmd(Token.NoToken, new List<String> { lastIterBlockName }, new List<Block> { 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<object>();
+ 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<string, Dictionary<string, Block>> fullMap, string procName, string blockName, Block block)
+ {
+ if (!fullMap.ContainsKey(procName))
+ fullMap[procName] = new Dictionary<string, Block>();
+ fullMap[procName][blockName] = block;
+ }
+
+ public static Graph<Implementation> BuildCallGraph(Program program) {
+ Graph<Implementation> callGraph = new Graph<Implementation>();
+ Dictionary<Procedure, HashSet<Implementation>> procToImpls = new Dictionary<Procedure, HashSet<Implementation>>();
+ foreach (var proc in program.Procedures) {
+ procToImpls[proc] = new HashSet<Implementation>();
+ }
+ 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<Block/*!*/>/*!*/ GraphFromImpl(Implementation impl) {
+ Contract.Requires(impl != null);
+ Contract.Ensures(cce.NonNullElements(Contract.Result<Graph<Block>>().Nodes));
+ Contract.Ensures(Contract.Result<Graph<Block>>() != null);
+
+ Graph<Block/*!*/> g = new Graph<Block/*!*/>();
+ 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<Block> ProcessLoops(Implementation impl) {
+ while (true) {
+ impl.PruneUnreachableBlocks();
+ impl.ComputePredecessorsForBlocks();
+ Graph<Block/*!*/>/*!*/ 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<Cmd> newCmdSeq = codeCopier.CopyCmdSeq(splitCandidate.Cmds);
+ TransferCmd newTransferCmd;
+ GotoCmd splitGotoCmd = splitCandidate.TransferCmd as GotoCmd;
+ if (splitGotoCmd == null) {
+ newTransferCmd = new ReturnCmd(splitCandidate.tok);
+ }
+ else {
+ List<String> newLabelNames = new List<String>();
+ newLabelNames.AddRange(splitGotoCmd.labelNames);
+ List<Block> newLabelTargets = new List<Block>();
+ 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<string, Dictionary<string, Block>> ExtractLoops()
+ {
+ HashSet<string> procsWithIrreducibleLoops = null;
+ return ExtractLoops(out procsWithIrreducibleLoops);
+ }
+
+ public Dictionary<string, Dictionary<string, Block>> ExtractLoops(out HashSet<string> procsWithIrreducibleLoops)
+ {
+ procsWithIrreducibleLoops = new HashSet<string>();
+ List<Implementation/*!*/>/*!*/ loopImpls = new List<Implementation/*!*/>();
+ Dictionary<string, Dictionary<string, Block>> fullMap = new Dictionary<string, Dictionary<string, Block>>();
+ foreach (var impl in this.Implementations)
+ {
+ if (impl.Blocks != null && impl.Blocks.Count > 0)
+ {
+ try
+ {
+ Graph<Block> 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<string, Block>();
+ 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<string, Block>();
+ 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<Absy>() != 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<object>(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);
+ }
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ 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;
+ }
+
+ /// <summary>
+ /// Find and return the last occurrence of an attribute with the name "name", if any. If none, return null.
+ /// </summary>
+ 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<object/*!*/>(vals), Attributes);
+ }
+ }
+
+ public abstract void Emit(TokenTextWriter/*!*/ stream, int level);
+ public abstract void Register(ResolutionContext/*!*/ rc);
+
+ /// <summary>
+ /// Compute the strongly connected components of the declaration.
+ /// By default, it does nothing
+ /// </summary>
+ public virtual void ComputeStronglyConnectedComponents() { /* Does nothing */
+ }
+
+ /// <summary>
+ /// Reset the abstract stated computed before
+ /// </summary>
+ 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<Expr>() != 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<Function> functionDependencies;
+
+ public ISet<Function> FunctionDependencies
+ {
+ get { return functionDependencies; }
+ }
+
+ public void AddFunctionDependency(Function function)
+ {
+ Contract.Requires(function != null);
+
+ if (functionDependencies == null)
+ {
+ functionDependencies = new HashSet<Function>();
+ }
+ 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<Absy>() != 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<string>() != 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<string>() != 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<Absy>() != null);
+ return visitor.VisitTypeCtorDecl(this);
+ }
+ }
+
+ public class TypeSynonymDecl : NamedDeclaration {
+ private List<TypeVariable>/*!*/ typeParameters;
+
+ public List<TypeVariable> TypeParameters {
+ get {
+ Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
+ return this.typeParameters;
+ }
+ set {
+ Contract.Requires(value != null);
+ this.typeParameters = value;
+ }
+ }
+
+ private Type/*!*/ body;
+
+ public Type Body {
+ get {
+ Contract.Ensures(Contract.Result<Type>() != 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<TypeVariable>/*!*/ 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<TypeVariable>/*!*/ 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<TypeSynonymDecl/*!*/>/*!*/ synonymDecls, ResolutionContext/*!*/ rc) {
+ Contract.Requires(cce.NonNullElements(synonymDecls));
+ Contract.Requires(rc != null);
+ // then discover all dependencies between type synonyms
+ IDictionary<TypeSynonymDecl/*!*/, List<TypeSynonymDecl/*!*/>/*!*/>/*!*/ deps =
+ new Dictionary<TypeSynonymDecl/*!*/, List<TypeSynonymDecl/*!*/>/*!*/>();
+ foreach (TypeSynonymDecl/*!*/ decl in synonymDecls) {
+ Contract.Assert(decl != null);
+ List<TypeSynonymDecl/*!*/>/*!*/ declDeps = new List<TypeSynonymDecl/*!*/>();
+ FindDependencies(decl.Body, declDeps, rc);
+ deps.Add(decl, declDeps);
+ }
+
+ List<TypeSynonymDecl/*!*/>/*!*/ resolved = new List<TypeSynonymDecl/*!*/>();
+
+ 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<TypeSynonymDecl/*!*/>/*!*/ 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<Absy>() != null);
+ return visitor.VisitTypeSynonymDecl(this);
+ }
+ }
+
+ public abstract class Variable : NamedDeclaration {
+ private TypedIdent/*!*/ typedIdent;
+
+ public TypedIdent TypedIdent {
+ get {
+ Contract.Ensures(Contract.Result<TypedIdent>() != 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<ConstantParent/*!*/> 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<ConstantParent/*!*/> 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<ConstantParent>(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<Absy>() != 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<Absy>() != 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);
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public static List<Variable> StripWhereClauses(List<Variable> w) {
+ Contract.Requires(w != null);
+ Contract.Ensures(Contract.Result<List<Variable>>() != null);
+ List<Variable> s = new List<Variable>();
+ 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<Absy>() != 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<Absy>() != 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<Absy>() != null);
+ return visitor.VisitBoundVariable(this);
+ }
+ }
+
+ public abstract class DeclWithFormals : NamedDeclaration {
+ public List<TypeVariable>/*!*/ TypeParameters;
+
+ private /*readonly--except in StandardVisitor*/ List<Variable>/*!*/ inParams, outParams;
+
+ public List<Variable>/*!*/ InParams {
+ get {
+ Contract.Ensures(Contract.Result<List<Variable>>() != null);
+ return this.inParams;
+ }
+ set {
+ Contract.Requires(value != null);
+ this.inParams = value;
+ }
+ }
+
+ public List<Variable>/*!*/ OutParams
+ {
+ get {
+ Contract.Ensures(Contract.Result<List<Variable>>() != 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<TypeVariable> typeParams,
+ List<Variable> inParams, List<Variable> 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<Function>();
+ 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<Function>(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<Procedure> procedureDependencies;
+
+ public ISet<Procedure> ProcedureDependencies
+ {
+ get { return procedureDependencies; }
+ }
+
+ public void AddProcedureDependency(Procedure procedure)
+ {
+ Contract.Requires(procedure != null);
+
+ if (procedureDependencies == null)
+ {
+ procedureDependencies = new HashSet<Procedure>();
+ }
+ procedureDependencies.Add(procedure);
+ }
+
+ ISet<Function> functionDependencies;
+
+ public ISet<Function> FunctionDependencies
+ {
+ get { return functionDependencies; }
+ }
+
+ public void AddFunctionDependency(Function function)
+ {
+ Contract.Requires(function != null);
+
+ if (functionDependencies == null)
+ {
+ functionDependencies = new HashSet<Function>();
+ }
+ 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("<no file>", strWr, false, false))
+ {
+ EmitSignature(tokTxtWr, this is Function);
+ sig = strWr.ToString();
+ }
+
+ using (var otherStrWr = new System.IO.StringWriter())
+ using (var otherTokTxtWr = new TokenTextWriter("<no file>", 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<Type>/*!*/ allTypes = new List<Type>(InParams.Select(Item => Item.TypedIdent.Type).ToArray());
+ Contract.Assert(allTypes != null);
+ allTypes.AddRange(new List<Type>(OutParams.Select(Item => Item.TypedIdent.Type).ToArray()));
+ TypeParameters = Type.SortTypeParams(TypeParameters, allTypes, null);
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ /// <param name="rc"></param>
+ protected void RegisterFormals(List<Variable> 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);
+ }
+ }
+
+ /// <summary>
+ /// Resolves the where clauses (and attributes) of the formals.
+ /// </summary>
+ /// <param name="rc"></param>
+ protected void ResolveFormals(List<Variable> 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<DatatypeSelector> 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<DatatypeSelector>();
+ }
+
+ public override void Resolve(ResolutionContext rc) {
+ HashSet<string> selectorNames = new HashSet<string>();
+ 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<Variable> { 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<Variable> { 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<Axiom> otherDefinitionAxioms;
+ public IEnumerable<Axiom> OtherDefinitionAxioms
+ {
+ get
+ {
+ return otherDefinitionAxioms;
+ }
+ }
+
+ public void AddOtherDefinitionAxiom(Axiom axiom)
+ {
+ Contract.Requires(axiom != null);
+
+ if (otherDefinitionAxioms == null)
+ {
+ otherDefinitionAxioms = new List<Axiom>();
+ }
+ otherDefinitionAxioms.Add(axiom);
+ }
+
+ public bool doingExpansion;
+
+ private bool neverTrigger;
+ private bool neverTriggerComputed;
+
+ public string OriginalLambdaExprAsString;
+
+ public Function(IToken tok, string name, List<Variable> args, Variable result)
+ : this(tok, name, new List<TypeVariable>(), args, result, null) {
+ Contract.Requires(result != null);
+ Contract.Requires(args != null);
+ Contract.Requires(name != null);
+ Contract.Requires(tok != null);
+ //:this(tok, name, new List<TypeVariable>(), args, result, null);
+ }
+ public Function(IToken tok, string name, List<TypeVariable> typeParams, List<Variable> 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<Variable> args, Variable result, string comment)
+ : this(tok, name, new List<TypeVariable>(), args, result, comment) {
+ Contract.Requires(result != null);
+ Contract.Requires(args != null);
+ Contract.Requires(name != null);
+ Contract.Requires(tok != null);
+ //:this(tok, name, new List<TypeVariable>(), args, result, comment);
+ }
+ public Function(IToken tok, string name, List<TypeVariable> typeParams, List<Variable> args, Variable/*!*/ result, string comment)
+ : base(tok, name, typeParams, args, new List<Variable> { 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<TypeVariable> typeParams, List<Variable> 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<Type>(InParams.Select(Item => Item.TypedIdent.Type).ToArray()),
+ new List<Type>(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<Absy>() != null);
+ return visitor.VisitFunction(this);
+ }
+
+ public Axiom CreateDefinitionAxiom(Expr definition, QKeyValue kv = null) {
+ Contract.Requires(definition != null);
+
+ List<Variable> dummies = new List<Variable>();
+ List<Expr> callArgs = new List<Expr>();
+ 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<TypeVariable>/*!*/ quantifiedTypeVars = new List<TypeVariable>();
+ 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<Expr> { call }, null),
+ def);
+ }
+ DefinitionAxiom = new Axiom(tok, def);
+ return DefinitionAxiom;
+ }
+ }
+
+ public class Macro : Function {
+ public Macro(IToken tok, string name, List<Variable> args, Variable result)
+ : base(tok, name, args, result) { }
+ }
+
+ public class Requires : Absy, IPotentialErrorNode<string, string> {
+ public readonly bool Free;
+
+ private Expr/*!*/ _condition;
+
+ public Expr/*!*/ Condition {
+ get {
+ Contract.Ensures(Contract.Result<Expr>() != 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<string, string> {
+ public readonly bool Free;
+
+ private Expr/*!*/ _condition;
+
+ public Expr/*!*/ Condition {
+ get {
+ Contract.Ensures(Contract.Result<Expr>() != 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>/*!*/ Requires;
+ public List<IdentifierExpr>/*!*/ Modifies;
+ public List<Ensures>/*!*/ 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<TypeVariable>/*!*/ typeParams, List<Variable>/*!*/ inParams, List<Variable>/*!*/ outParams,
+ List<Requires>/*!*/ requires, List<IdentifierExpr>/*!*/ modifies, List<Ensures>/*!*/ 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<TypeVariable>/*!*/ typeParams, List<Variable>/*!*/ inParams, List<Variable>/*!*/ outParams,
+ List<Requires>/*!*/ @requires, List<IdentifierExpr>/*!*/ @modifies, List<Ensures>/*!*/ @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<Type>(InParams.Select(Item => Item.TypedIdent.Type).ToArray()),
+ new List<Type>(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<Absy>() != null);
+ return visitor.VisitProcedure(this);
+ }
+ }
+
+ public class LoopProcedure : Procedure
+ {
+ public Implementation enclosingImpl;
+ private Dictionary<Block, Block> blockMap;
+ private Dictionary<string, Block> blockLabelMap;
+
+ public LoopProcedure(Implementation impl, Block header,
+ List<Variable> inputs, List<Variable> outputs, List<IdentifierExpr> globalMods)
+ : base(Token.NoToken, impl.Name + "_loop_" + header.ToString(),
+ new List<TypeVariable>(), inputs, outputs,
+ new List<Requires>(), globalMods, new List<Ensures>())
+ {
+ enclosingImpl = impl;
+ }
+
+ public void setBlockMap(Dictionary<Block, Block> bm)
+ {
+ blockMap = bm;
+ blockLabelMap = new Dictionary<string, Block>();
+ 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<Variable>/*!*/ LocVars;
+ [Rep]
+ public StmtList StructuredStmts;
+ [Rep]
+ public List<Block/*!*/>/*!*/ Blocks;
+ public Procedure Proc;
+
+ // Blocks before applying passification etc.
+ // Both are used only when /inline is set.
+ public List<Block/*!*/> OriginalBlocks;
+ public List<Variable> OriginalLocVars;
+
+ public readonly ISet<byte[]> AssertionChecksums = new HashSet<byte[]>(ChecksumComparer.Default);
+
+ public sealed class ChecksumComparer : IEqualityComparer<byte[]>
+ {
+ static IEqualityComparer<byte[]> defaultComparer;
+ public static IEqualityComparer<byte[]> 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<byte[]> AssertionChecksumsInCachedSnapshot { get; set; }
+
+ public bool IsAssertionChecksumInCachedSnapshot(byte[] checksum)
+ {
+ Contract.Requires(AssertionChecksumsInCachedSnapshot != null);
+
+ return AssertionChecksumsInCachedSnapshot.Contains(checksum);
+ }
+
+ public IList<AssertCmd> RecycledFailingAssertions { get; protected set; }
+
+ public void AddRecycledFailingAssertion(AssertCmd assertion)
+ {
+ if (RecycledFailingAssertions == null)
+ {
+ RecycledFailingAssertions = new List<AssertCmd>();
+ }
+ RecycledFailingAssertions.Add(assertion);
+ }
+
+ public Cmd ExplicitAssumptionAboutCachedPrecondition { get; set; }
+
+ // Strongly connected components
+ private StronglyConnectedComponents<Block/*!*/> 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<byte[], object> ErrorChecksumToCachedError { get; private set; }
+
+ public bool IsErrorChecksumInCachedSnapshot(byte[] checksum)
+ {
+ Contract.Requires(ErrorChecksumToCachedError != null);
+
+ return ErrorChecksumToCachedError.ContainsKey(checksum);
+ }
+
+ public void SetErrorChecksumToCachedError(IEnumerable<Tuple<byte[], byte[], object>> errors)
+ {
+ Contract.Requires(errors != null);
+
+ ErrorChecksumToCachedError = new Dictionary<byte[], object>(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<LocalVariable> injectedAssumptionVariables;
+ public IList<LocalVariable> InjectedAssumptionVariables
+ {
+ get
+ {
+ return injectedAssumptionVariables != null ? injectedAssumptionVariables : new List<LocalVariable>();
+ }
+ }
+
+ IList<LocalVariable> doomedInjectedAssumptionVariables;
+ public IList<LocalVariable> DoomedInjectedAssumptionVariables
+ {
+ get
+ {
+ return doomedInjectedAssumptionVariables != null ? doomedInjectedAssumptionVariables : new List<LocalVariable>();
+ }
+ }
+
+ public List<LocalVariable> RelevantInjectedAssumptionVariables(Dictionary<Variable, Expr> 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<LocalVariable> RelevantDoomedInjectedAssumptionVariables(Dictionary<Variable, Expr> 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<Variable, Expr> 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<LocalVariable>();
+ }
+ doomedInjectedAssumptionVariables.Add(variable);
+ }
+ else
+ {
+ if (injectedAssumptionVariables == null)
+ {
+ injectedAssumptionVariables = new List<LocalVariable>();
+ }
+ injectedAssumptionVariables.Add(variable);
+ }
+ }
+
+ public Implementation(IToken tok, string name, List<TypeVariable> typeParams, List<Variable> inParams, List<Variable> outParams, List<Variable> 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<TypeVariable> typeParams, List<Variable> inParams, List<Variable> outParams, List<Variable> 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<TypeVariable> typeParams, List<Variable> inParams, List<Variable> outParams, List<Variable> 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<TypeVariable>/*!*/ typeParams,
+ List<Variable>/*!*/ inParams,
+ List<Variable>/*!*/ outParams,
+ List<Variable>/*!*/ 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<TypeVariable> typeParams, List<Variable> inParams, List<Variable> outParams, List<Variable> localVariables, [Captured] List<Block/*!*/> 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<TypeVariable>/*!*/ typeParams,
+ List<Variable>/*!*/ inParams,
+ List<Variable>/*!*/ outParams,
+ List<Variable>/*!*/ localVariables,
+ [Captured] List<Block/*!*/>/*!*/ 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<Type>(InParams.Select(Item => Item.TypedIdent.Type).ToArray()),
+ new List<Type>(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<IdentifierExpr> 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<Variable>/*!*/ implFormals, List<Variable>/*!*/ 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst1 =
+ new Dictionary<TypeVariable/*!*/, Type/*!*/>();
+ IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ subst2 =
+ new Dictionary<TypeVariable/*!*/, Type/*!*/>();
+
+ 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<Variable, Expr>/*?*/ formalMap = null;
+ public void ResetImplFormalMap() {
+ this.formalMap = null;
+ }
+ public Dictionary<Variable, Expr>/*!*/ GetImplFormalMap() {
+ Contract.Ensures(Contract.Result<Dictionary<Variable, Expr>>() != null);
+
+ if (this.formalMap != null)
+ return this.formalMap;
+ else {
+ Dictionary<Variable, Expr>/*!*/ map = new Dictionary<Variable, Expr> (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>", 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;
+ }
+ }
+
+ /// <summary>
+ /// Return a collection of blocks that are reachable from the block passed as a parameter.
+ /// The block must be defined in the current implementation
+ /// </summary>
+ public ICollection<Block/*!*/> GetConnectedComponents(Block startingBlock) {
+ Contract.Requires(startingBlock != null);
+ Contract.Ensures(cce.NonNullElements(Contract.Result<ICollection<Block>>(), 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<Block/*!*/> 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.
+ }
+
+ /// <summary>
+ /// 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
+ /// </summary>
+ override public void ComputeStronglyConnectedComponents() {
+ if (!this.BlockPredecessorsComputed)
+ ComputePredecessorsForBlocks();
+
+ Adjacency<Block/*!*/> next = new Adjacency<Block/*!*/>(Successors);
+ Adjacency<Block/*!*/> prev = new Adjacency<Block/*!*/>(Predecessors);
+
+ this.scc = new StronglyConnectedComponents<Block/*!*/>(this.Blocks, next, prev);
+ scc.Compute();
+
+
+ foreach (Block/*!*/ block in this.Blocks) {
+ Contract.Assert(block != null);
+ block.Predecessors = new List<Block>();
+ }
+
+ }
+
+ /// <summary>
+ /// Reset the abstract stated computed before
+ /// </summary>
+ override public void ResetAbstractInterpretationState() {
+ foreach (Block/*!*/ b in this.Blocks) {
+ Contract.Assert(b != null);
+ b.ResetAbstractInterpretationState();
+ }
+ }
+
+ /// <summary>
+ /// A private method used as delegate for the strongly connected components.
+ /// It return, given a node, the set of its successors
+ /// </summary>
+ private IEnumerable/*<Block!>*//*!*/ Successors(Block node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<IEnumerable>() != 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<Block/*!*/>();
+ }
+ }
+
+ /// <summary>
+ /// A private method used as delegate for the strongly connected components.
+ /// It return, given a node, the set of its predecessors
+ /// </summary>
+ private IEnumerable/*<Block!>*//*!*/ Predecessors(Block node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<IEnumerable>() != null);
+
+ Contract.Assert(this.BlockPredecessorsComputed);
+
+ return node.Predecessors;
+ }
+
+ /// <summary>
+ /// Compute the predecessor informations for the blocks
+ /// </summary>
+ public void ComputePredecessorsForBlocks() {
+ foreach (Block b in this.Blocks) {
+ b.Predecessors = new List<Block>();
+ }
+ 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<Block/*!*/> reachableBlocks = new List<Block/*!*/>();
+ HashSet<Block> reachable = new HashSet<Block>(); // 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<Absy>() != 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<Cmd> newCmds = new List<Cmd>();
+ 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<object>() { 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<string>() != null);
+ return this._name;
+ }
+ set {
+ Contract.Requires(value != null);
+ this._name = value;
+ }
+ }
+
+ private Type/*!*/ _type;
+
+ public Type/*!*/ Type {
+ get {
+ Contract.Ensures(Contract.Result<Type>() != 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<Absy>() != null);
+ return visitor.VisitTypedIdent(this);
+ }
+ }
+
+ #region Helper methods for generic Sequences
+
+ public static class TypeVariableSeqAlgorithms {
+ public static void AppendWithoutDups(this List<TypeVariable> tvs, List<TypeVariable> 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<Declaration/*!*/>/*!*/ 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<String> 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<Expr> 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<IdentifierExpr> 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<Variable> 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<Type> 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<TypeVariable> 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<Variable> vars) {
+ //Contract.Requires(vars != null);
+ throw new NotImplementedException();
+ }
+ }
+ public class AtomicRE : RE {
+ private Block/*!*/ _b;
+
+ public Block b
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<Block>() != 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<Absy>() != 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<RE>() != null);
+ return this._first;
+ }
+ set {
+ Contract.Requires(value != null);
+ this._first = value;
+ }
+ }
+
+ private RE/*!*/ _second;
+
+ public RE/*!*/ second {
+ get {
+ Contract.Ensures(Contract.Result<RE>() != 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<Absy>() != null);
+ return visitor.VisitSequential(this);
+ }
+ }
+ public class Choice : CompoundRE {
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(this._rs != null);
+ }
+
+ private List<RE>/*!*/ _rs;
+
+ public List<RE>/*!*/ rs { //Rename this (and _rs) if possible
+ get {
+ Contract.Ensures(Contract.Result<List<RE>>() != null);
+ return this._rs;
+ }
+ set {
+ Contract.Requires(value != null);
+ this._rs = value;
+ }
+ }
+
+ public Choice(List<RE> 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<Absy>() != null);
+ return visitor.VisitChoice(this);
+ }
+ }
+ public class DAG2RE {
+ public static RE Transform(Block b) {
+ Contract.Requires(b != null);
+ Contract.Ensures(Contract.Result<RE>() != 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<RE> rs = new List<RE>();
+ 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<object>;
-
-
- //---------------------------------------------------------------------
- // 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<string>() != null);
- return this.labelName;
- }
- set
- {
- Contract.Requires(Anonymous || value != null);
- this.labelName = value;
- }
- }
-
- [Rep]
- private List<Cmd>/*!*/ _simpleCmds;
-
- public List<Cmd>/*!*/ simpleCmds
- {
- get
- {
- Contract.Ensures(Contract.Result<List<Cmd>>() != 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<Cmd> 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<BigBlock/*!*/>/*!*/ bigBlocks;
-
- public IList<BigBlock/*!*/>/*!*/ BigBlocks
- {
- get
- {
- Contract.Ensures(Contract.Result<IList<BigBlock>>() != null);
- Contract.Ensures(Contract.Result<IList<BigBlock>>().IsReadOnly);
- return this.bigBlocks.AsReadOnly();
- }
- }
-
- public List<Cmd> PrefixCommands;
- public readonly IToken/*!*/ EndCurly;
- public StmtList ParentContext;
- public BigBlock ParentBigBlock;
-
- private readonly HashSet<string/*!*/>/*!*/ labels = new HashSet<string/*!*/>();
-
- public void AddLabel(string label)
- {
- labels.Add(label);
- }
-
- public IEnumerable<string/*!*/>/*!*/ Labels
- {
- get
- {
- Contract.Ensures(cce.NonNullElements(Contract.Result<IEnumerable<string/*!*/>/*!*/>()));
- return this.labels.AsEnumerable<string>();
- }
- }
-
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(EndCurly != null);
- Contract.Invariant(cce.NonNullElements(this.bigBlocks));
- Contract.Invariant(cce.NonNullElements(this.labels));
- }
-
- public StmtList(IList<BigBlock/*!*/>/*!*/ bigblocks, IToken endCurly) {
- Contract.Requires(endCurly != null);
- Contract.Requires(cce.NonNullElements(bigblocks));
- Contract.Requires(bigblocks.Count > 0);
- this.bigBlocks = new List<BigBlock>(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;
- }
- }
-
- /// <summary>
- /// 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.
- /// </summary>
- public bool PrefixFirstBlock([Captured] List<Cmd> prefixCmds, ref string suggestedLabel) {
- Contract.Requires(suggestedLabel != null);
- Contract.Requires(prefixCmds != null);
- Contract.Ensures(Contract.Result<bool>() || 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;
- }
- }
- }
- }
-
- /// <summary>
- /// 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.
- /// </summary>
- public class StmtListBuilder {
- List<BigBlock/*!*/>/*!*/ bigBlocks = new List<BigBlock/*!*/>();
- string label;
- List<Cmd> 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<Cmd>();
- }
- bigBlocks.Add(new BigBlock(Token.NoToken, label, simpleCmds, scmd, tcmd));
- label = null;
- simpleCmds = null;
- }
- }
-
- /// <summary>
- /// Collects the StmtList built so far and returns it. The StmtListBuilder should no longer
- /// be used once this method has been invoked.
- /// </summary>
- public StmtList Collect(IToken endCurlyBrace) {
- Contract.Requires(endCurlyBrace != null);
- Contract.Ensures(Contract.Result<StmtList>() != null);
- Dump(null, null);
- if (bigBlocks.Count == 0) {
- simpleCmds = new List<Cmd>(); // 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<Cmd>();
- }
- 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<Block/*!*/> blocks;
- string/*!*/ prefix = "anon";
- int anon = 0;
- int FreshAnon()
- {
- return anon++;
- }
- HashSet<string/*!*/> allLabels = new HashSet<string/*!*/>();
- 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<Block/*!*/>/*!*/ Blocks {
- get {
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<Block>>()));
- if (blocks == null) {
- blocks = new List<Block/*!*/>();
-
- 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<Cmd> cmdPrefixToApply = stmtList.PrefixCommands;
-
- int n = stmtList.BigBlocks.Count;
- foreach (BigBlock b in stmtList.BigBlocks) {
- n--;
- Contract.Assert(b.LabelName != null);
- List<Cmd> theSimpleCmds;
- if (cmdPrefixToApply == null) {
- theSimpleCmds = b.simpleCmds;
- } else {
- theSimpleCmds = new List<Cmd>();
- 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<String> { 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<Cmd> ssBody = new List<Cmd>();
- List<Cmd> ssDone = new List<Cmd>();
- if (wcmd.Guard != null) {
- var ac = new AssumeCmd(wcmd.tok, wcmd.Guard);
- ac.Attributes = new QKeyValue(wcmd.tok, "partition", new List<object>(), null);
- ssBody.Add(ac);
-
- ac = new AssumeCmd(wcmd.tok, Expr.Not(wcmd.Guard));
- ac.Attributes = new QKeyValue(wcmd.tok, "partition", new List<object>(), 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<String> { loopHeadLabel }));
- blocks.Add(block);
-
- // LoopHead: assert/assume loop_invariant; goto LoopDone, LoopBody;
- List<Cmd> ssHead = new List<Cmd>();
- foreach (PredicateCmd inv in wcmd.Invariants) {
- ssHead.Add(inv);
- }
- block = new Block(wcmd.tok, loopHeadLabel, ssHead, new GotoCmd(wcmd.tok, new List<String> { 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<String> { 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<String> { 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<Cmd> 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<Cmd> ssThen = new List<Cmd>();
- List<Cmd> ssElse = new List<Cmd>();
- if (ifcmd.Guard != null) {
- var ac = new AssumeCmd(ifcmd.tok, ifcmd.Guard);
- ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List<object>(), null);
- ssThen.Add(ac);
-
- ac = new AssumeCmd(ifcmd.tok, Expr.Not(ifcmd.Guard));
- ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List<object>(), 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<String> { 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<String> { 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<String> { 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<Cmd>();
- if (ifcmd.Guard != null) {
- var ac = new AssumeCmd(ifcmd.tok, Expr.Not(ifcmd.Guard));
- ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List<object>(), 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<String> { 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<TransferCmd>() != null);
- if (b.successorBigBlock != null) {
- return new GotoCmd(tok, new List<String> { 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<IToken>() != 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<StmtList>() != 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<PredicateCmd/*!*/>/*!*/ Invariants;
- public StmtList/*!*/ Body;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(Body != null);
- Contract.Invariant(cce.NonNullElements(Invariants));
- }
-
-
- public WhileCmd(IToken tok, [Captured] Expr guard, List<PredicateCmd/*!*/>/*!*/ 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<string>() != null);
- return this.label;
- }
- set
- {
- Contract.Requires(value != null);
- this.label = value;
- }
- }
-
- [Rep]
- [ElementsPeer]
- public List<Cmd>/*!*/ cmds;
-
- public List<Cmd>/*!*/ Cmds
- {
- get
- {
- Contract.Ensures(Contract.Result<List<Cmd>>() != 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<Block>/*!*/ Predecessors;
-
- // This field is used during passification to null-out entries in block2Incartion hashtable early
- public int succCount;
-
- private HashSet<Variable/*!*/> _liveVarsBefore;
-
- public IEnumerable<Variable/*!*/> liveVarsBefore
- {
- get
- {
- Contract.Ensures(cce.NonNullElements(Contract.Result<IEnumerable<Variable/*!*/>>(), true));
- if (this._liveVarsBefore == null)
- return null;
- else
- return this._liveVarsBefore.AsEnumerable<Variable>();
- }
- set
- {
- Contract.Requires(cce.NonNullElements(value, true));
- if (value == null)
- this._liveVarsBefore = null;
- else
- this._liveVarsBefore = new HashSet<Variable>(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<Cmd>(), new ReturnCmd(Token.NoToken)) {
-
- }
-
- public Block(IToken tok, string/*!*/ label, List<Cmd>/*!*/ 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<Block>();
- 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);
- }
-
- /// <summary>
- /// 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
- /// </summary>
- public void ResetAbstractInterpretationState() {
- // this.currentlyTraversed = false;
- this.TraversingStatus = VisitState.ToVisit;
- this.iterations = 0;
- }
-
- [Pure]
- public override string ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- return this.Label + (this.widenBlock ? "[w]" : "");
- }
-
- public override Absy StdDispatch(StandardVisitor visitor) {
-
- Contract.Ensures(Contract.Result<Absy>() != 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<Variable> vars) {
- Contract.Requires(vars != null);
- throw new NotImplementedException();
- }
- }
-
- public static class ChecksumHelper
- {
- public static void ComputeChecksums(Cmd cmd, Implementation impl, ISet<Variable> 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("<no file>", 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<Variable>/*!*/ vars);
- public void CheckAssignments(TypecheckingContext tc)
- {
- Contract.Requires(tc != null);
- List<Variable>/*!*/ vars = new List<Variable>();
- 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<AssignCmd>() != null);
- List<AssignLhs/*!*/>/*!*/ lhss = new List<AssignLhs/*!*/>();
- List<Expr/*!*/>/*!*/ rhss = new List<Expr/*!*/>();
-
- 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<Expr>/*!*/ indexes, Expr/*!*/ rhs) {
-
- Contract.Requires(tok != null);
- Contract.Requires(map != null);
- Contract.Requires(indexes != null);
- Contract.Requires(rhs != null);
- Contract.Ensures(Contract.Result<AssignCmd>() != null);
- List<AssignLhs/*!*/>/*!*/ lhss = new List<AssignLhs/*!*/>();
- List<Expr/*!*/>/*!*/ rhss = new List<Expr/*!*/>();
- List<Expr/*!*/>/*!*/ indexesList = new List<Expr/*!*/>();
-
-
-
- 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<AssignCmd>() != null);
-
- List<AssignLhs/*!*/>/*!*/ lhss = new List<AssignLhs/*!*/>();
- List<Expr/*!*/>/*!*/ rhss = new List<Expr/*!*/>();
- List<Expr/*!*/>/*!*/ indexesList = new List<Expr/*!*/>();
-
- 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);
- }
-
- /// <summary>
- /// This is a helper routine for printing a linked list of attributes. Each attribute
- /// is terminated by a space.
- /// </summary>
- 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<string>() != null);
- System.IO.StringWriter buffer = new System.IO.StringWriter();
- using (TokenTextWriter stream = new TokenTextWriter("<buffer>", 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<Variable> vars)
- {
- // nothing to add
- }
- public override Absy StdDispatch(StandardVisitor visitor)
- {
- Contract.Ensures(Contract.Result<Absy>() != 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<Variable> 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<AssignLhs/*!*/>/*!*/ _lhss;
-
- public IList<AssignLhs/*!*/>/*!*/ Lhss {
- get {
- Contract.Ensures(cce.NonNullElements(Contract.Result<IList<AssignLhs>>()));
- Contract.Ensures(Contract.Result<IList<AssignLhs>>().IsReadOnly);
- return this._lhss.AsReadOnly();
- }
- set {
- Contract.Requires(cce.NonNullElements(value));
- this._lhss = new List<AssignLhs>(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<Expr/*!*/>/*!*/ _rhss;
-
- public IList<Expr/*!*/>/*!*/ Rhss {
- get {
- Contract.Ensures(cce.NonNullElements(Contract.Result<IList<Expr>>()));
- Contract.Ensures(Contract.Result<IList<Expr>>().IsReadOnly);
- return this._rhss.AsReadOnly();
- }
- set {
- Contract.Requires(cce.NonNullElements(value));
- this._rhss = new List<Expr>(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<AssignLhs/*!*/>/*!*/ lhss, IList<Expr/*!*/>/*!*/ rhss)
- : base(tok) {
- Contract.Requires(tok != null);
- Contract.Requires(cce.NonNullElements(rhss));
- Contract.Requires(cce.NonNullElements(lhss));
- this._lhss = new List<AssignLhs>(lhss);
- this._rhss = new List<Expr>(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} && <boolean expression>\"", 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<Variable> 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<AssignCmd>() != null);
-
- List<AssignLhs/*!*/>/*!*/ newLhss = new List<AssignLhs/*!*/>();
- List<Expr/*!*/>/*!*/ newRhss = new List<Expr/*!*/>();
-
- 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<IdentifierExpr>() != null);
- throw new NotImplementedException();
- }
- }
- public override Expr AsExpr {
- get {
- Contract.Ensures(Contract.Result<Expr>() != 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<IdentifierExpr>() != 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<Expr>() != 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<Expr/*!*/>/*!*/ 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<IdentifierExpr>() != null);
-
- return Map.DeepAssignedIdentifier;
- }
- }
-
- public override Variable DeepAssignedVariable {
- get {
- return Map.DeepAssignedVariable;
- }
- }
-
- public MapAssignLhs(IToken tok, AssignLhs map, List<Expr/*!*/>/*!*/ 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<Expr>/*!*/ selectArgs = new List<Expr>();
- 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<Expr>() != 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<Absy>() != null);
- return visitor.VisitMapAssignLhs(this);
- }
- }
-
- /// <summary>
- /// 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.
- /// </summary>
- public class StateCmd : Cmd {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(this._locals != null);
- Contract.Invariant(this._cmds != null);
- }
-
- private List<Variable> _locals;
-
- public /*readonly, except for the StandardVisitor*/ List<Variable>/*!*/ Locals {
- get {
- Contract.Ensures(Contract.Result<List<Variable>>() != null);
- return this._locals;
- }
- internal set {
- Contract.Requires(value != null);
- this._locals = value;
- }
- }
-
- private List<Cmd> _cmds;
-
- public /*readonly, except for the StandardVisitor*/ List<Cmd>/*!*/ Cmds {
- get {
- Contract.Ensures(Contract.Result<List<Cmd>>() != null);
- return this._cmds;
- }
- set {
- Contract.Requires(value != null);
- this._cmds = value;
- }
- }
-
- public StateCmd(IToken tok, List<Variable>/*!*/ locals, List<Cmd>/*!*/ 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<Variable> vars) {
- //Contract.Requires(vars != null);
- List<Variable>/*!*/ vs = new List<Variable>();
- 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<Absy>() != 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<Cmd>() != null);
-
- if (desugaring == null) {
- desugaring = ComputeDesugaring();
- }
- return desugaring;
- }
- }
- /// <summary>
- /// 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).
- /// </summary>
- 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<Cmd> before, IEnumerable<Cmd> beforePreconditionCheck, IEnumerable<Cmd> 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<Cmd>(before);
- cmds.Add(desug);
- cmds.AddRange(after);
- desugaring = new StateCmd(Token.NoToken, new List<Variable>(), 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<Cmd>() != 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<Variable> 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<Variable>() != 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<object, object>
- {
- public List<CallCmd> CallCmds;
- public ParCallCmd(IToken tok, List<CallCmd> callCmds)
- : base(tok, null)
- {
- this.CallCmds = callCmds;
- }
- public ParCallCmd(IToken tok, List<CallCmd> 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<Variable> parallelCallLhss = new HashSet<Variable>();
- 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<Variable> vars)
- {
- foreach (CallCmd callCmd in CallCmds)
- {
- callCmd.AddAssignedVariables(vars);
- }
- }
- public override Absy StdDispatch(StandardVisitor visitor)
- {
- //Contract.Requires(visitor != null);
- Contract.Ensures(Contract.Result<Absy>() != null);
- return visitor.VisitParCallCmd(this);
- }
- }
-
- public class CallCmd : CallCommonality, IPotentialErrorNode<object, object>
- {
- 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<Expr>/*!*/ Ins;
- public List<IdentifierExpr>/*!*/ 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<Expr> ins, List<IdentifierExpr> 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<Expr> ins, List<IdentifierExpr> 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<Expr> ins, List<IdentifierExpr> 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<Variable> actualOuts = new HashSet<Variable>();
- 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<Type>/*!*/ formalInTypes = new List<Type>();
- List<Type>/*!*/ formalOutTypes = new List<Type>();
- 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<Variable> 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<Type>/*!*/ formalInTypes = new List<Type>();
- List<Type>/*!*/ formalOutTypes = new List<Type>();
- List<Expr>/*!*/ actualIns = new List<Expr>();
- List<IdentifierExpr>/*!*/ actualOuts = new List<IdentifierExpr>();
- 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<Type/*!*/>/*!*/ 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<TypeVariable/*!*/, Type/*!*/>/*!*/ TypeParamSubstitution() {
- Contract.Ensures(cce.NonNullDictionaryAndValues(Contract.Result<IDictionary<TypeVariable, Type>>()));
- Contract.Assume(TypeParameters != null);
- IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ res = new Dictionary<TypeVariable/*!*/, Type/*!*/>();
- 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<Cmd>() != null);
-
- int uniqueId = 0;
- List<Cmd> newBlockBody = new List<Cmd>();
- Dictionary<Variable, Expr> substMap = new Dictionary<Variable, Expr>();
- Dictionary<Variable, Expr> substMapOld = new Dictionary<Variable, Expr>();
- Dictionary<Variable, Expr> substMapBound = new Dictionary<Variable, Expr>();
- List<Variable>/*!*/ tempVars = new List<Variable>();
-
- // 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<Variable>/*!*/ cins = new List<Variable>();
- List<Variable> wildcardVars = new List<Variable>();
- 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<IdentifierExpr>/*!*/ ies = new List<IdentifierExpr>();
- 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<IdentifierExpr> havocVarExprs = new List<IdentifierExpr>();
-
- 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<Variable>/*!*/ couts = new List<Variable>();
- 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<object>(), 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<IdentifierExpr>
- {
- 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<IdentifierExpr> UnmodifiedBefore(Procedure oldProcedure)
- {
- Contract.Requires(oldProcedure != null);
-
- return Proc.Modifies.Except(oldProcedure.Modifies, comparer).Select(e => new IdentifierExpr(Token.NoToken, e.Decl));
- }
-
- public IEnumerable<IdentifierExpr> 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<Expr> modifies, Dictionary<Variable, Expr> oldSubst, Program program, Func<Expr, Expr> 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<Expr, Expr> 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<Expr> 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<Absy>() != 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<Variable> 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<MiningStrategy>/*!*/ _msList;
-
- public List<MiningStrategy>/*!*/ msList
- {
- get
- {
- Contract.Ensures(Contract.Result<List<MiningStrategy>>() != null);
- return this._msList;
- }
- set
- {
- Contract.Requires(value != null);
- this._msList = value;
- }
- }
-
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(this._msList != null);
- }
-
- public ListOfMiningStrategies(List<MiningStrategy> l) {
- Contract.Requires(l != null);
- this._msList = l;
- }
- }
-
- public class EEDTemplate : MiningStrategy {
- private string/*!*/ _reason;
- public string/*!*/ reason
- {
- get
- {
- Contract.Ensures(Contract.Result<string>() != null);
- return this._reason;
- }
- set
- {
- Contract.Requires(value != null);
- this._reason = value;
- }
- }
-
- private List<Expr/*!*/>/*!*/ exprList;
- public IEnumerable<Expr> Expressions
- {
- get
- {
- Contract.Ensures(cce.NonNullElements(Contract.Result<IEnumerable<Expr>>()));
- return this.exprList.AsReadOnly();
- }
- set
- {
- Contract.Requires(cce.NonNullElements(value));
- this.exprList = new List<Expr>(value);
- }
- }
-
-
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(this._reason != null);
- Contract.Invariant(cce.NonNullElements(this.exprList));
- }
-
- public EEDTemplate(string reason, List<Expr/*!*/>/*!*/ exprList) {
- Contract.Requires(reason != null);
- Contract.Requires(cce.NonNullElements(exprList));
- this._reason = reason;
- this.exprList = exprList;
- }
- }
-
- public class AssertCmd : PredicateCmd, IPotentialErrorNode<object, object>
- {
- public Expr OrigExpr;
- public Dictionary<Variable, Expr> 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<object> { 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<MiningStrategy> l = new List<MiningStrategy>();
- if (expr != null) {
- l = GenerateBoundVarListForMining(expr, l);
- }
- return new ListOfMiningStrategies(l);
- }
-
- public static List<MiningStrategy>/*!*/ GenerateBoundVarListForMining(Expr expr, List<MiningStrategy> l) {
- Contract.Requires(l != null);
- Contract.Requires(expr != null);
- Contract.Ensures(Contract.Result<List<MiningStrategy>>() != 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<Variable> vs = qe.Dummies;
- foreach (Variable/*!*/ x in vs) {
- Contract.Assert(x != null);
- string name = x.Name;
- if (name.StartsWith("^")) {
- name = name.Substring(1);
- List<Expr> exprList = new List<Expr>();
- 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<Absy>() != 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);
- }
- }
-
- /// <summary>
- /// An AssertCmd that is introduced in translation from the requires on a call.
- /// </summary>
- 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<Absy>() != null);
- return visitor.VisitAssertRequiresCmd(this);
- }
- }
-
- /// <summary>
- /// An AssertCmd that is introduced in translation from an ensures
- /// declaration.
- /// </summary>
- 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<Absy>() != 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<Absy>() != 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<Absy>() != null);
- return visitor.VisitReturnExprCmd(this);
- }
- }
-
- public class HavocCmd : Cmd {
- private List<IdentifierExpr>/*!*/ _vars;
-
- public List<IdentifierExpr>/*!*/ Vars {
- get {
- Contract.Ensures(Contract.Result<List<IdentifierExpr>>() != 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<IdentifierExpr>/*!*/ 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<Variable> 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<Absy>() != 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<string>() != null);
- System.IO.StringWriter buffer = new System.IO.StringWriter();
- using (TokenTextWriter stream = new TokenTextWriter("<buffer>", 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<Absy>() != null);
- return visitor.VisitReturnCmd(this);
- }
- }
-
- public class GotoCmd : TransferCmd {
- [Rep]
- public List<String> labelNames;
- [Rep]
- public List<Block> labelTargets;
-
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(labelNames == null || labelTargets == null || labelNames.Count == labelTargets.Count);
- }
-
- [NotDelayed]
- public GotoCmd(IToken/*!*/ tok, List<String>/*!*/ labelSeq)
- : base(tok) {
- Contract.Requires(tok != null);
- Contract.Requires(labelSeq != null);
- this.labelNames = labelSeq;
- }
- public GotoCmd(IToken/*!*/ tok, List<String>/*!*/ labelSeq, List<Block>/*!*/ 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<Block>/*!*/ blockSeq)
- : base(tok) { //requires (blockSeq[i] != null ==> blockSeq[i].Label != null);
- Contract.Requires(tok != null);
- Contract.Requires(blockSeq != null);
- List<String> labelSeq = new List<String>();
- 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<Block>();
- 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<Absy>() != 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<object>;
+
+
+ //---------------------------------------------------------------------
+ // 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<string>() != null);
+ return this.labelName;
+ }
+ set
+ {
+ Contract.Requires(Anonymous || value != null);
+ this.labelName = value;
+ }
+ }
+
+ [Rep]
+ private List<Cmd>/*!*/ _simpleCmds;
+
+ public List<Cmd>/*!*/ simpleCmds
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<List<Cmd>>() != 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<Cmd> 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<BigBlock/*!*/>/*!*/ bigBlocks;
+
+ public IList<BigBlock/*!*/>/*!*/ BigBlocks
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<IList<BigBlock>>() != null);
+ Contract.Ensures(Contract.Result<IList<BigBlock>>().IsReadOnly);
+ return this.bigBlocks.AsReadOnly();
+ }
+ }
+
+ public List<Cmd> PrefixCommands;
+ public readonly IToken/*!*/ EndCurly;
+ public StmtList ParentContext;
+ public BigBlock ParentBigBlock;
+
+ private readonly HashSet<string/*!*/>/*!*/ labels = new HashSet<string/*!*/>();
+
+ public void AddLabel(string label)
+ {
+ labels.Add(label);
+ }
+
+ public IEnumerable<string/*!*/>/*!*/ Labels
+ {
+ get
+ {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<IEnumerable<string/*!*/>/*!*/>()));
+ return this.labels.AsEnumerable<string>();
+ }
+ }
+
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(EndCurly != null);
+ Contract.Invariant(cce.NonNullElements(this.bigBlocks));
+ Contract.Invariant(cce.NonNullElements(this.labels));
+ }
+
+ public StmtList(IList<BigBlock/*!*/>/*!*/ bigblocks, IToken endCurly) {
+ Contract.Requires(endCurly != null);
+ Contract.Requires(cce.NonNullElements(bigblocks));
+ Contract.Requires(bigblocks.Count > 0);
+ this.bigBlocks = new List<BigBlock>(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;
+ }
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public bool PrefixFirstBlock([Captured] List<Cmd> prefixCmds, ref string suggestedLabel) {
+ Contract.Requires(suggestedLabel != null);
+ Contract.Requires(prefixCmds != null);
+ Contract.Ensures(Contract.Result<bool>() || 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;
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public class StmtListBuilder {
+ List<BigBlock/*!*/>/*!*/ bigBlocks = new List<BigBlock/*!*/>();
+ string label;
+ List<Cmd> 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<Cmd>();
+ }
+ bigBlocks.Add(new BigBlock(Token.NoToken, label, simpleCmds, scmd, tcmd));
+ label = null;
+ simpleCmds = null;
+ }
+ }
+
+ /// <summary>
+ /// Collects the StmtList built so far and returns it. The StmtListBuilder should no longer
+ /// be used once this method has been invoked.
+ /// </summary>
+ public StmtList Collect(IToken endCurlyBrace) {
+ Contract.Requires(endCurlyBrace != null);
+ Contract.Ensures(Contract.Result<StmtList>() != null);
+ Dump(null, null);
+ if (bigBlocks.Count == 0) {
+ simpleCmds = new List<Cmd>(); // 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<Cmd>();
+ }
+ 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<Block/*!*/> blocks;
+ string/*!*/ prefix = "anon";
+ int anon = 0;
+ int FreshAnon()
+ {
+ return anon++;
+ }
+ HashSet<string/*!*/> allLabels = new HashSet<string/*!*/>();
+ 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<Block/*!*/>/*!*/ Blocks {
+ get {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<Block>>()));
+ if (blocks == null) {
+ blocks = new List<Block/*!*/>();
+
+ 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<Cmd> cmdPrefixToApply = stmtList.PrefixCommands;
+
+ int n = stmtList.BigBlocks.Count;
+ foreach (BigBlock b in stmtList.BigBlocks) {
+ n--;
+ Contract.Assert(b.LabelName != null);
+ List<Cmd> theSimpleCmds;
+ if (cmdPrefixToApply == null) {
+ theSimpleCmds = b.simpleCmds;
+ } else {
+ theSimpleCmds = new List<Cmd>();
+ 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<String> { 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<Cmd> ssBody = new List<Cmd>();
+ List<Cmd> ssDone = new List<Cmd>();
+ if (wcmd.Guard != null) {
+ var ac = new AssumeCmd(wcmd.tok, wcmd.Guard);
+ ac.Attributes = new QKeyValue(wcmd.tok, "partition", new List<object>(), null);
+ ssBody.Add(ac);
+
+ ac = new AssumeCmd(wcmd.tok, Expr.Not(wcmd.Guard));
+ ac.Attributes = new QKeyValue(wcmd.tok, "partition", new List<object>(), 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<String> { loopHeadLabel }));
+ blocks.Add(block);
+
+ // LoopHead: assert/assume loop_invariant; goto LoopDone, LoopBody;
+ List<Cmd> ssHead = new List<Cmd>();
+ foreach (PredicateCmd inv in wcmd.Invariants) {
+ ssHead.Add(inv);
+ }
+ block = new Block(wcmd.tok, loopHeadLabel, ssHead, new GotoCmd(wcmd.tok, new List<String> { 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<String> { 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<String> { 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<Cmd> 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<Cmd> ssThen = new List<Cmd>();
+ List<Cmd> ssElse = new List<Cmd>();
+ if (ifcmd.Guard != null) {
+ var ac = new AssumeCmd(ifcmd.tok, ifcmd.Guard);
+ ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List<object>(), null);
+ ssThen.Add(ac);
+
+ ac = new AssumeCmd(ifcmd.tok, Expr.Not(ifcmd.Guard));
+ ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List<object>(), 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<String> { 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<String> { 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<String> { 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<Cmd>();
+ if (ifcmd.Guard != null) {
+ var ac = new AssumeCmd(ifcmd.tok, Expr.Not(ifcmd.Guard));
+ ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List<object>(), 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<String> { 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<TransferCmd>() != null);
+ if (b.successorBigBlock != null) {
+ return new GotoCmd(tok, new List<String> { 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<IToken>() != 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<StmtList>() != 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<PredicateCmd/*!*/>/*!*/ Invariants;
+ public StmtList/*!*/ Body;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(Body != null);
+ Contract.Invariant(cce.NonNullElements(Invariants));
+ }
+
+
+ public WhileCmd(IToken tok, [Captured] Expr guard, List<PredicateCmd/*!*/>/*!*/ 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<string>() != null);
+ return this.label;
+ }
+ set
+ {
+ Contract.Requires(value != null);
+ this.label = value;
+ }
+ }
+
+ [Rep]
+ [ElementsPeer]
+ public List<Cmd>/*!*/ cmds;
+
+ public List<Cmd>/*!*/ Cmds
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<List<Cmd>>() != 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<Block>/*!*/ Predecessors;
+
+ // This field is used during passification to null-out entries in block2Incartion hashtable early
+ public int succCount;
+
+ private HashSet<Variable/*!*/> _liveVarsBefore;
+
+ public IEnumerable<Variable/*!*/> liveVarsBefore
+ {
+ get
+ {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<IEnumerable<Variable/*!*/>>(), true));
+ if (this._liveVarsBefore == null)
+ return null;
+ else
+ return this._liveVarsBefore.AsEnumerable<Variable>();
+ }
+ set
+ {
+ Contract.Requires(cce.NonNullElements(value, true));
+ if (value == null)
+ this._liveVarsBefore = null;
+ else
+ this._liveVarsBefore = new HashSet<Variable>(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<Cmd>(), new ReturnCmd(Token.NoToken)) {
+
+ }
+
+ public Block(IToken tok, string/*!*/ label, List<Cmd>/*!*/ 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<Block>();
+ 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);
+ }
+
+ /// <summary>
+ /// 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
+ /// </summary>
+ public void ResetAbstractInterpretationState() {
+ // this.currentlyTraversed = false;
+ this.TraversingStatus = VisitState.ToVisit;
+ this.iterations = 0;
+ }
+
+ [Pure]
+ public override string ToString() {
+ Contract.Ensures(Contract.Result<string>() != null);
+ return this.Label + (this.widenBlock ? "[w]" : "");
+ }
+
+ public override Absy StdDispatch(StandardVisitor visitor) {
+
+ Contract.Ensures(Contract.Result<Absy>() != 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<Variable> vars) {
+ Contract.Requires(vars != null);
+ throw new NotImplementedException();
+ }
+ }
+
+ public static class ChecksumHelper
+ {
+ public static void ComputeChecksums(Cmd cmd, Implementation impl, ISet<Variable> 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("<no file>", 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<Variable>/*!*/ vars);
+ public void CheckAssignments(TypecheckingContext tc)
+ {
+ Contract.Requires(tc != null);
+ List<Variable>/*!*/ vars = new List<Variable>();
+ 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<AssignCmd>() != null);
+ List<AssignLhs/*!*/>/*!*/ lhss = new List<AssignLhs/*!*/>();
+ List<Expr/*!*/>/*!*/ rhss = new List<Expr/*!*/>();
+
+ 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<Expr>/*!*/ indexes, Expr/*!*/ rhs) {
+
+ Contract.Requires(tok != null);
+ Contract.Requires(map != null);
+ Contract.Requires(indexes != null);
+ Contract.Requires(rhs != null);
+ Contract.Ensures(Contract.Result<AssignCmd>() != null);
+ List<AssignLhs/*!*/>/*!*/ lhss = new List<AssignLhs/*!*/>();
+ List<Expr/*!*/>/*!*/ rhss = new List<Expr/*!*/>();
+ List<Expr/*!*/>/*!*/ indexesList = new List<Expr/*!*/>();
+
+
+
+ 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<AssignCmd>() != null);
+
+ List<AssignLhs/*!*/>/*!*/ lhss = new List<AssignLhs/*!*/>();
+ List<Expr/*!*/>/*!*/ rhss = new List<Expr/*!*/>();
+ List<Expr/*!*/>/*!*/ indexesList = new List<Expr/*!*/>();
+
+ 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);
+ }
+
+ /// <summary>
+ /// This is a helper routine for printing a linked list of attributes. Each attribute
+ /// is terminated by a space.
+ /// </summary>
+ 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<string>() != null);
+ System.IO.StringWriter buffer = new System.IO.StringWriter();
+ using (TokenTextWriter stream = new TokenTextWriter("<buffer>", 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<Variable> vars)
+ {
+ // nothing to add
+ }
+ public override Absy StdDispatch(StandardVisitor visitor)
+ {
+ Contract.Ensures(Contract.Result<Absy>() != 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<Variable> 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<AssignLhs/*!*/>/*!*/ _lhss;
+
+ public IList<AssignLhs/*!*/>/*!*/ Lhss {
+ get {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<IList<AssignLhs>>()));
+ Contract.Ensures(Contract.Result<IList<AssignLhs>>().IsReadOnly);
+ return this._lhss.AsReadOnly();
+ }
+ set {
+ Contract.Requires(cce.NonNullElements(value));
+ this._lhss = new List<AssignLhs>(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<Expr/*!*/>/*!*/ _rhss;
+
+ public IList<Expr/*!*/>/*!*/ Rhss {
+ get {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<IList<Expr>>()));
+ Contract.Ensures(Contract.Result<IList<Expr>>().IsReadOnly);
+ return this._rhss.AsReadOnly();
+ }
+ set {
+ Contract.Requires(cce.NonNullElements(value));
+ this._rhss = new List<Expr>(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<AssignLhs/*!*/>/*!*/ lhss, IList<Expr/*!*/>/*!*/ rhss)
+ : base(tok) {
+ Contract.Requires(tok != null);
+ Contract.Requires(cce.NonNullElements(rhss));
+ Contract.Requires(cce.NonNullElements(lhss));
+ this._lhss = new List<AssignLhs>(lhss);
+ this._rhss = new List<Expr>(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} && <boolean expression>\"", 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<Variable> 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<AssignCmd>() != null);
+
+ List<AssignLhs/*!*/>/*!*/ newLhss = new List<AssignLhs/*!*/>();
+ List<Expr/*!*/>/*!*/ newRhss = new List<Expr/*!*/>();
+
+ 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<IdentifierExpr>() != null);
+ throw new NotImplementedException();
+ }
+ }
+ public override Expr AsExpr {
+ get {
+ Contract.Ensures(Contract.Result<Expr>() != 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<IdentifierExpr>() != 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<Expr>() != 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<Expr/*!*/>/*!*/ 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<IdentifierExpr>() != null);
+
+ return Map.DeepAssignedIdentifier;
+ }
+ }
+
+ public override Variable DeepAssignedVariable {
+ get {
+ return Map.DeepAssignedVariable;
+ }
+ }
+
+ public MapAssignLhs(IToken tok, AssignLhs map, List<Expr/*!*/>/*!*/ 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<Expr>/*!*/ selectArgs = new List<Expr>();
+ 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<Expr>() != 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<Absy>() != null);
+ return visitor.VisitMapAssignLhs(this);
+ }
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public class StateCmd : Cmd {
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(this._locals != null);
+ Contract.Invariant(this._cmds != null);
+ }
+
+ private List<Variable> _locals;
+
+ public /*readonly, except for the StandardVisitor*/ List<Variable>/*!*/ Locals {
+ get {
+ Contract.Ensures(Contract.Result<List<Variable>>() != null);
+ return this._locals;
+ }
+ internal set {
+ Contract.Requires(value != null);
+ this._locals = value;
+ }
+ }
+
+ private List<Cmd> _cmds;
+
+ public /*readonly, except for the StandardVisitor*/ List<Cmd>/*!*/ Cmds {
+ get {
+ Contract.Ensures(Contract.Result<List<Cmd>>() != null);
+ return this._cmds;
+ }
+ set {
+ Contract.Requires(value != null);
+ this._cmds = value;
+ }
+ }
+
+ public StateCmd(IToken tok, List<Variable>/*!*/ locals, List<Cmd>/*!*/ 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<Variable> vars) {
+ //Contract.Requires(vars != null);
+ List<Variable>/*!*/ vs = new List<Variable>();
+ 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<Absy>() != 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<Cmd>() != null);
+
+ if (desugaring == null) {
+ desugaring = ComputeDesugaring();
+ }
+ return desugaring;
+ }
+ }
+ /// <summary>
+ /// 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).
+ /// </summary>
+ 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<Cmd> before, IEnumerable<Cmd> beforePreconditionCheck, IEnumerable<Cmd> 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<Cmd>(before);
+ cmds.Add(desug);
+ cmds.AddRange(after);
+ desugaring = new StateCmd(Token.NoToken, new List<Variable>(), 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<Cmd>() != 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<Variable> 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<Variable>() != 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<object, object>
+ {
+ public List<CallCmd> CallCmds;
+ public ParCallCmd(IToken tok, List<CallCmd> callCmds)
+ : base(tok, null)
+ {
+ this.CallCmds = callCmds;
+ }
+ public ParCallCmd(IToken tok, List<CallCmd> 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<Variable> parallelCallLhss = new HashSet<Variable>();
+ 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<Variable> vars)
+ {
+ foreach (CallCmd callCmd in CallCmds)
+ {
+ callCmd.AddAssignedVariables(vars);
+ }
+ }
+ public override Absy StdDispatch(StandardVisitor visitor)
+ {
+ //Contract.Requires(visitor != null);
+ Contract.Ensures(Contract.Result<Absy>() != null);
+ return visitor.VisitParCallCmd(this);
+ }
+ }
+
+ public class CallCmd : CallCommonality, IPotentialErrorNode<object, object>
+ {
+ 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<Expr>/*!*/ Ins;
+ public List<IdentifierExpr>/*!*/ 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<Expr> ins, List<IdentifierExpr> 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<Expr> ins, List<IdentifierExpr> 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<Expr> ins, List<IdentifierExpr> 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<Variable> actualOuts = new HashSet<Variable>();
+ 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<Type>/*!*/ formalInTypes = new List<Type>();
+ List<Type>/*!*/ formalOutTypes = new List<Type>();
+ 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<Variable> 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<Type>/*!*/ formalInTypes = new List<Type>();
+ List<Type>/*!*/ formalOutTypes = new List<Type>();
+ List<Expr>/*!*/ actualIns = new List<Expr>();
+ List<IdentifierExpr>/*!*/ actualOuts = new List<IdentifierExpr>();
+ 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<Type/*!*/>/*!*/ 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<TypeVariable/*!*/, Type/*!*/>/*!*/ TypeParamSubstitution() {
+ Contract.Ensures(cce.NonNullDictionaryAndValues(Contract.Result<IDictionary<TypeVariable, Type>>()));
+ Contract.Assume(TypeParameters != null);
+ IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ res = new Dictionary<TypeVariable/*!*/, Type/*!*/>();
+ 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<Cmd>() != null);
+
+ int uniqueId = 0;
+ List<Cmd> newBlockBody = new List<Cmd>();
+ Dictionary<Variable, Expr> substMap = new Dictionary<Variable, Expr>();
+ Dictionary<Variable, Expr> substMapOld = new Dictionary<Variable, Expr>();
+ Dictionary<Variable, Expr> substMapBound = new Dictionary<Variable, Expr>();
+ List<Variable>/*!*/ tempVars = new List<Variable>();
+
+ // 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<Variable>/*!*/ cins = new List<Variable>();
+ List<Variable> wildcardVars = new List<Variable>();
+ 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<IdentifierExpr>/*!*/ ies = new List<IdentifierExpr>();
+ 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<IdentifierExpr> havocVarExprs = new List<IdentifierExpr>();
+
+ 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<Variable>/*!*/ couts = new List<Variable>();
+ 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<object>(), 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<IdentifierExpr>
+ {
+ 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<IdentifierExpr> UnmodifiedBefore(Procedure oldProcedure)
+ {
+ Contract.Requires(oldProcedure != null);
+
+ return Proc.Modifies.Except(oldProcedure.Modifies, comparer).Select(e => new IdentifierExpr(Token.NoToken, e.Decl));
+ }
+
+ public IEnumerable<IdentifierExpr> 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<Expr> modifies, Dictionary<Variable, Expr> oldSubst, Program program, Func<Expr, Expr> 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<Expr, Expr> 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<Absy>() != 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<Variable> 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<MiningStrategy>/*!*/ _msList;
+
+ public List<MiningStrategy>/*!*/ msList
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<List<MiningStrategy>>() != null);
+ return this._msList;
+ }
+ set
+ {
+ Contract.Requires(value != null);
+ this._msList = value;
+ }
+ }
+
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(this._msList != null);
+ }
+
+ public ListOfMiningStrategies(List<MiningStrategy> l) {
+ Contract.Requires(l != null);
+ this._msList = l;
+ }
+ }
+
+ public class EEDTemplate : MiningStrategy {
+ private string/*!*/ _reason;
+ public string/*!*/ reason
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<string>() != null);
+ return this._reason;
+ }
+ set
+ {
+ Contract.Requires(value != null);
+ this._reason = value;
+ }
+ }
+
+ private List<Expr/*!*/>/*!*/ exprList;
+ public IEnumerable<Expr> Expressions
+ {
+ get
+ {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<IEnumerable<Expr>>()));
+ return this.exprList.AsReadOnly();
+ }
+ set
+ {
+ Contract.Requires(cce.NonNullElements(value));
+ this.exprList = new List<Expr>(value);
+ }
+ }
+
+
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(this._reason != null);
+ Contract.Invariant(cce.NonNullElements(this.exprList));
+ }
+
+ public EEDTemplate(string reason, List<Expr/*!*/>/*!*/ exprList) {
+ Contract.Requires(reason != null);
+ Contract.Requires(cce.NonNullElements(exprList));
+ this._reason = reason;
+ this.exprList = exprList;
+ }
+ }
+
+ public class AssertCmd : PredicateCmd, IPotentialErrorNode<object, object>
+ {
+ public Expr OrigExpr;
+ public Dictionary<Variable, Expr> 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<object> { 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<MiningStrategy> l = new List<MiningStrategy>();
+ if (expr != null) {
+ l = GenerateBoundVarListForMining(expr, l);
+ }
+ return new ListOfMiningStrategies(l);
+ }
+
+ public static List<MiningStrategy>/*!*/ GenerateBoundVarListForMining(Expr expr, List<MiningStrategy> l) {
+ Contract.Requires(l != null);
+ Contract.Requires(expr != null);
+ Contract.Ensures(Contract.Result<List<MiningStrategy>>() != 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<Variable> vs = qe.Dummies;
+ foreach (Variable/*!*/ x in vs) {
+ Contract.Assert(x != null);
+ string name = x.Name;
+ if (name.StartsWith("^")) {
+ name = name.Substring(1);
+ List<Expr> exprList = new List<Expr>();
+ 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<Absy>() != 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);
+ }
+ }
+
+ /// <summary>
+ /// An AssertCmd that is introduced in translation from the requires on a call.
+ /// </summary>
+ 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<Absy>() != null);
+ return visitor.VisitAssertRequiresCmd(this);
+ }
+ }
+
+ /// <summary>
+ /// An AssertCmd that is introduced in translation from an ensures
+ /// declaration.
+ /// </summary>
+ 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<Absy>() != 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<Absy>() != 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<Absy>() != null);
+ return visitor.VisitReturnExprCmd(this);
+ }
+ }
+
+ public class HavocCmd : Cmd {
+ private List<IdentifierExpr>/*!*/ _vars;
+
+ public List<IdentifierExpr>/*!*/ Vars {
+ get {
+ Contract.Ensures(Contract.Result<List<IdentifierExpr>>() != 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<IdentifierExpr>/*!*/ 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<Variable> 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<Absy>() != 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<string>() != null);
+ System.IO.StringWriter buffer = new System.IO.StringWriter();
+ using (TokenTextWriter stream = new TokenTextWriter("<buffer>", 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<Absy>() != null);
+ return visitor.VisitReturnCmd(this);
+ }
+ }
+
+ public class GotoCmd : TransferCmd {
+ [Rep]
+ public List<String> labelNames;
+ [Rep]
+ public List<Block> labelTargets;
+
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(labelNames == null || labelTargets == null || labelNames.Count == labelTargets.Count);
+ }
+
+ [NotDelayed]
+ public GotoCmd(IToken/*!*/ tok, List<String>/*!*/ labelSeq)
+ : base(tok) {
+ Contract.Requires(tok != null);
+ Contract.Requires(labelSeq != null);
+ this.labelNames = labelSeq;
+ }
+ public GotoCmd(IToken/*!*/ tok, List<String>/*!*/ labelSeq, List<Block>/*!*/ 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<Block>/*!*/ blockSeq)
+ : base(tok) { //requires (blockSeq[i] != null ==> blockSeq[i].Label != null);
+ Contract.Requires(tok != null);
+ Contract.Requires(blockSeq != null);
+ List<String> labelSeq = new List<String>();
+ 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<Block>();
+ 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<Absy>() != 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<object>; // 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);
- }
-
- /// <summary>
- /// 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.
- /// </summary>
- /// <value><c>true</c> if immutable; otherwise, <c>false</c>.</value>
- public bool Immutable {
- get;
- private set;
- }
-
- /// <summary>
- /// 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.
- /// </summary>
- /// <returns>The hash code.</returns>
- 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<string>() != null);
- System.IO.StringWriter buffer = new System.IO.StringWriter();
- using (TokenTextWriter stream = new TokenTextWriter("<buffer>", buffer, /*setTokens=*/ false, /*pretty=*/ false)) {
- this.Emit(stream, 0, false);
- }
- return buffer.ToString();
- }
-
- /// <summary>
- /// Add to "freeVars" the free variables in the expression.
- /// </summary>
- public abstract void ComputeFreeVariables(Set /*Variable*//*!*/ freeVars);
-
- /// <summary>
- /// 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).
- /// </summary>
- 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();
- }
- }
-
- /// <summary>
- /// Returns the type of the expression, supposing that all its subexpressions are well typed.
- /// </summary>
- 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<NAryExpr>() != null);
- return new NAryExpr(x, new UnaryOperator(x, op), new List<Expr> { 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<NAryExpr>() != null);
- return new NAryExpr(x, new BinaryOperator(x, op), new List<Expr> { 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<Expr>() != 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<Expr>() != 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<Expr>() != 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<Expr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<IdentifierExpr>() != null);
- return new IdentifierExpr(Token.NoToken, name, type);
- }
-
- public static IdentifierExpr Ident(Variable decl) {
- Contract.Requires(decl != null);
- Contract.Ensures(Contract.Result<IdentifierExpr>() != null);
- IdentifierExpr result = new IdentifierExpr(Token.NoToken, decl);
- return result;
- }
-
- public static LiteralExpr Literal(bool value) {
- Contract.Ensures(Contract.Result<LiteralExpr>() != null);
- return new LiteralExpr(Token.NoToken, value);
- }
- public static LiteralExpr Literal(int value) {
- Contract.Ensures(Contract.Result<LiteralExpr>() != null);
- return new LiteralExpr(Token.NoToken, BigNum.FromInt(value));
- }
- public static LiteralExpr Literal(BigNum value) {
- Contract.Ensures(Contract.Result<LiteralExpr>() != null);
- return new LiteralExpr(Token.NoToken, value);
- }
- public static LiteralExpr Literal(BigDec value) {
- Contract.Ensures(Contract.Result<LiteralExpr>() != null);
- return new LiteralExpr(Token.NoToken, value);
- }
- public static LiteralExpr Literal(BigFloat value)
- {
- Contract.Ensures(Contract.Result<LiteralExpr>() != null);
- return new LiteralExpr(Token.NoToken, value);
- }
-
- private static LiteralExpr/*!*/ true_ = Literal(true);
- public static LiteralExpr/*!*/ True {
- get {
- Contract.Ensures(Contract.Result<LiteralExpr>() != null);
- return true_;
- }
- }
-
- private static LiteralExpr/*!*/ false_ = Literal(false);
- public static LiteralExpr/*!*/ False {
- get {
- Contract.Ensures(Contract.Result<LiteralExpr>() != null);
- return false_;
- }
- }
-
-
- public static NAryExpr Select(Expr map, params Expr[] args) {
- Contract.Requires(args != null);
- Contract.Requires(map != null);
- Contract.Ensures(Contract.Result<NAryExpr>() != null);
- return SelectTok(Token.NoToken, map, args);
- }
-
- public static NAryExpr Select(Expr map, List<Expr/*!*/>/*!*/ args) {
- Contract.Requires(map != null);
- Contract.Requires(cce.NonNullElements(args));
- Contract.Ensures(Contract.Result<NAryExpr>() != 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<NAryExpr>() != null);
- List<Expr>/*!*/ allArgs = new List<Expr>();
- 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<NAryExpr>() != null);
- return StoreTok(Token.NoToken, map, args);
- }
-
- public static NAryExpr Store(Expr map, List<Expr/*!*/>/*!*/ indexes, Expr rhs) {
- Contract.Requires(rhs != null);
- Contract.Requires(map != null);
- Contract.Requires(cce.NonNullElements(indexes));
- Contract.Ensures(Contract.Result<NAryExpr>() != 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<NAryExpr>() != null);
-
- List<Expr>/*!*/ allArgs = new List<Expr>();
- 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<NAryExpr>() != null);
- List<Expr>/*!*/ args = new List<Expr>();
- args.Add(subexpr);
- return new NAryExpr(x, new TypeCoercion(x, type), args);
- }
-
- public static Expr BinaryTreeAnd(List<Expr> terms)
- {
- return BinaryTreeAnd(terms, 0, terms.Count - 1);
- }
-
- private static Expr BinaryTreeAnd(List<Expr> 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<Type>() != 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);
- }
-
- /// <summary>
- /// Creates a literal expression for the boolean value "b".
- /// </summary>
- /// <param name="tok"></param>
- /// <param name="b"></param>
- 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();
- }
-
- /// <summary>
- /// Creates a literal expression for the integer value "v".
- /// </summary>
- /// <param name="tok"></param>
- /// <param name="v"></param>
- 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();
- }
-
- /// <summary>
- /// Creates a literal expression for the real value "v".
- /// </summary>
- /// <param name="tok"></param>
- /// <param name="v"></param>
- 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();
- }
-
- /// <summary>
- /// Creates a literal expression for the floating point value "v".
- /// </summary>
- /// <param name="tok"></param>
- /// <param name="v"></param>
- 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();
- }
-
- /// <summary>
- /// Creates a literal expression for the bitvector value "v".
- /// </summary>
- 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<Type>() != 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<Absy>() != 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<string>() != null);
- return Value + "bv" + Bits;
- }
-
- [Pure]
- public string ToReadableString() {
- Contract.Ensures(Contract.Result<string>() != 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);
- }
-
-
- /// <summary>
- /// 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.
- /// </summary>
- /// <param name="tok"></param>
- /// <param name="name"></param>
- 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();
- }
- /// <summary>
- /// Creates an unresolved identifier expression.
- /// </summary>
- /// <param name="tok"></param>
- /// <param name="name"></param>
- /// <param name="type"></param>
- 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();
- }
-
- /// <summary>
- /// Creates a resolved identifier expression.
- /// </summary>
- /// <param name="tok"></param>
- /// <param name="d"></param>
- 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<Type>() != 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<IList>() != 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<Absy>() != 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<Type>() != null);
-
- return Expr.ShallowType;
- }
- }
-
- public override Absy StdDispatch(StandardVisitor visitor) {
- //Contract.Requires(visitor != null);
- Contract.Ensures(Contract.Result<Absy>() != null);
- return visitor.VisitOldExpr(this);
- }
- }
- [ContractClass(typeof(IAppliableVisitorContracts<>))]
- public interface IAppliableVisitor<T> {
- 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<T> : IAppliableVisitor<T> {
-
- #region IAppliableVisitor<T> 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;
- }
-
- /// <summary>
- /// 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).
- /// </summary>
- /// <param name="args"></param>
- /// <param name="stream"></param>
- /// <param name="contextBindingStrength"></param>
- /// <param name="fragileContext"></param>
- void Emit(IList<Expr>/*!*/ args, TokenTextWriter/*!*/ stream, int contextBindingStrength, bool fragileContext);
-
- void Resolve(ResolutionContext/*!*/ rc, Expr/*!*/ subjectForErrorReporting);
-
- /// <summary>
- /// Requires the object to have been properly resolved.
- /// </summary>
- int ArgumentCount {
- get;
- }
-
- /// <summary>
- /// 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.
- /// </summary>
- /// <param name="args"></param>
- /// <param name="tc"></param>
- Type Typecheck(IList<Expr>/*!*/ args, out TypeParamInstantiation/*!*/ tpInstantiation, TypecheckingContext/*!*/ tc);
-
- // Contract.Requires( Microsoft.SpecSharp.Collections.Reductions.Forall{Expr! arg in args; arg.Type != null});
-
- /// <summary>
- /// Returns the result type of the IAppliable, supposing the argument are of the correct types.
- /// </summary>
- Type/*!*/ ShallowType(IList<Expr>/*!*/ args);
-
- T Dispatch<T>(IAppliableVisitor<T>/*!*/ visitor);
- }
- [ContractClassFor(typeof(IAppliable))]
- abstract class IAppliableContracts : IAppliable {
-
- #region IAppliable Members
-
- public string FunctionName {
- get {
- Contract.Ensures(Contract.Result<string>() != null);
- throw new NotImplementedException();
- }
- }
-
- public void Emit(IList<Expr> 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<Expr> 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<Expr> args) {
- Contract.Requires(args != null);
- Contract.Ensures(Contract.Result<Type>() != null);
-
- throw new NotImplementedException();
- }
-
- public T Dispatch<T>(IAppliableVisitor<T> 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<string>() != 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<Expr> 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<Expr> 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<Expr> args) {
- //Contract.Requires(args != null);
- Contract.Ensures(Contract.Result<Type>() != 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<T>(IAppliableVisitor<T> 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<string>() != 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<Expr> 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<Expr> 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<TypeVariable>/*!*/ unifiable = new List<TypeVariable>();
- unifiable.AddRange(arg0type.FreeVariables);
- unifiable.AddRange(arg1type.FreeVariables);
-
- if (arg0type.Unify(arg1type, unifiable, new Dictionary<TypeVariable/*!*/, Type/*!*/>()))
- 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<Expr> args) {
- //Contract.Requires(args != null);
- Contract.Ensures(Contract.Result<Type>() != 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<Expr> { 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<T>(IAppliableVisitor<T> 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<string>() != 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<string>() != 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<Expr> 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<Expr> 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<Type/*!*/>/*!*/ resultingTypeArgs;
- List<Type> actualResultType =
- Type.CheckArgumentTypes(Func.TypeParameters,
- out resultingTypeArgs,
- new List<Type>(Func.InParams.Select(Item => Item.TypedIdent.Type).ToArray()),
- actuals,
- new List<Type>(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<Expr> args) {
- //Contract.Requires(args != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- Contract.Assume(name.Type != null);
- return name.Type;
- }
-
- public virtual T Dispatch<T>(IAppliableVisitor<T> 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<string>() != null);
-
- return ":";
- }
- }
-
- public void Emit(IList<Expr>/*!*/ 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<Expr>/*!*/ 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<Expr> args) {
- //Contract.Requires(args != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- return this.Type;
- }
-
- public T Dispatch<T>(IAppliableVisitor<T> 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<string>() != 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<Expr> 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<Expr> 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<Expr> args) {
- //Contract.Requires(args != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- return this.type;
- }
-
- public virtual T Dispatch<T>(IAppliableVisitor<T> 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<Expr> _Args;
- public IList<Expr> 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<Expr>;
- }
- }
-
- [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<Expr>/*!*/ 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<Expr>(args);
- CachedHashCode = ComputeHashCode();
- } else {
- if (args is List<Expr>) {
- // Preserve NAryExpr's old behaviour, we take ownership of the List<Expr>.
- // We can only do this if the type matches
- _Args = args as List<Expr>;
- }
- else {
- // Otherwise we must make a copy
- _Args = new List<Expr> (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<Type>() != null);
-
- return Fun.ShallowType(Args);
- }
- }
-
- public override Absy StdDispatch(StandardVisitor visitor) {
- //Contract.Requires(visitor != null);
- Contract.Ensures(Contract.Result<Absy>() != 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<string>() != 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<Expr>/*!*/ 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<Expr>/*!*/ 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<Expr>/*!*/ 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<Expr> 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<Expr> actualArgs = new List<Expr>();
- 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");
- }
-
- /// <summary>
- /// Returns the result type of the IAppliable, supposing the argument are of the correct types.
- /// </summary>
- public Type ShallowType(IList<Expr> args) {
- //Contract.Requires(args != null);
- Contract.Ensures(Contract.Result<Type>() != 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<Type> actualArgTypes = new List<Type>();
- 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<T>(IAppliableVisitor<T> 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<string>() != 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<Expr>/*!*/ 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<Expr>/*!*/ 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<Expr> selectArgs = new List<Expr>();
- 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<Expr>/*!*/ 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");
- }
-
- /// <summary>
- /// Returns the result type of the IAppliable, supposing the argument are of the correct types.
- /// </summary>
- public Type ShallowType(IList<Expr> args) {
- //Contract.Requires(args != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- return cce.NonNull(args[0]).ShallowType;
- }
-
- public T Dispatch<T>(IAppliableVisitor<T> visitor) {
- //Contract.Requires(visitor != null);
- return visitor.Visit(this);
- }
- }
-
-
- public class IfThenElse : IAppliable {
-
- private IToken/*!*/ _tok;
-
- public IToken/*!*/ tok
- {
- get
- {
- Contract.Ensures(Contract.Result<IToken>() != 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<string>() != 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<Expr> 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<Expr> 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;
- }
-
- /// <summary>
- /// Returns the result type of the IAppliable, supposing the argument are of the correct types.
- /// </summary>
- public Type ShallowType(IList<Expr> args) {
- //Contract.Requires(args != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- return cce.NonNull(args[1]).ShallowType;
- }
-
- public T Dispatch<T>(IAppliableVisitor<T> visitor) {
- //Contract.Requires(visitor != null);
- return visitor.Visit(this);
- }
- }
-
-
-
- public class CodeExpr : Expr {
- public List<Variable>/*!*/ LocVars;
- [Rep]
- public List<Block/*!*/>/*!*/ Blocks;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(LocVars != null);
- Contract.Invariant(cce.NonNullElements(Blocks));
- }
-
- public CodeExpr(List<Variable>/*!*/ localVariables, List<Block/*!*/>/*!*/ 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<Type>() != null);
-
- return Type.Bool;
- }
- }
-
- public override Absy StdDispatch(StandardVisitor visitor) {
- //Contract.Requires(visitor != null);
- Contract.Ensures(Contract.Result<Absy>() != 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<Type>() != null);
-
- return Type.GetBvType(End - Start);
- }
- }
-
- public override Absy StdDispatch(StandardVisitor visitor) {
- //Contract.Requires(visitor != null);
- Contract.Ensures(Contract.Result<Absy>() != 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<Type>() != 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<Absy>() != 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<object>; // 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);
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ /// <value><c>true</c> if immutable; otherwise, <c>false</c>.</value>
+ public bool Immutable {
+ get;
+ private set;
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ /// <returns>The hash code.</returns>
+ 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<string>() != null);
+ System.IO.StringWriter buffer = new System.IO.StringWriter();
+ using (TokenTextWriter stream = new TokenTextWriter("<buffer>", buffer, /*setTokens=*/ false, /*pretty=*/ false)) {
+ this.Emit(stream, 0, false);
+ }
+ return buffer.ToString();
+ }
+
+ /// <summary>
+ /// Add to "freeVars" the free variables in the expression.
+ /// </summary>
+ public abstract void ComputeFreeVariables(Set /*Variable*//*!*/ freeVars);
+
+ /// <summary>
+ /// 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).
+ /// </summary>
+ 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();
+ }
+ }
+
+ /// <summary>
+ /// Returns the type of the expression, supposing that all its subexpressions are well typed.
+ /// </summary>
+ 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<NAryExpr>() != null);
+ return new NAryExpr(x, new UnaryOperator(x, op), new List<Expr> { 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<NAryExpr>() != null);
+ return new NAryExpr(x, new BinaryOperator(x, op), new List<Expr> { 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<Expr>() != 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<Expr>() != 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<Expr>() != 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<Expr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<NAryExpr>() != 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<IdentifierExpr>() != null);
+ return new IdentifierExpr(Token.NoToken, name, type);
+ }
+
+ public static IdentifierExpr Ident(Variable decl) {
+ Contract.Requires(decl != null);
+ Contract.Ensures(Contract.Result<IdentifierExpr>() != null);
+ IdentifierExpr result = new IdentifierExpr(Token.NoToken, decl);
+ return result;
+ }
+
+ public static LiteralExpr Literal(bool value) {
+ Contract.Ensures(Contract.Result<LiteralExpr>() != null);
+ return new LiteralExpr(Token.NoToken, value);
+ }
+ public static LiteralExpr Literal(int value) {
+ Contract.Ensures(Contract.Result<LiteralExpr>() != null);
+ return new LiteralExpr(Token.NoToken, BigNum.FromInt(value));
+ }
+ public static LiteralExpr Literal(BigNum value) {
+ Contract.Ensures(Contract.Result<LiteralExpr>() != null);
+ return new LiteralExpr(Token.NoToken, value);
+ }
+ public static LiteralExpr Literal(BigDec value) {
+ Contract.Ensures(Contract.Result<LiteralExpr>() != null);
+ return new LiteralExpr(Token.NoToken, value);
+ }
+ public static LiteralExpr Literal(BigFloat value)
+ {
+ Contract.Ensures(Contract.Result<LiteralExpr>() != null);
+ return new LiteralExpr(Token.NoToken, value);
+ }
+
+ private static LiteralExpr/*!*/ true_ = Literal(true);
+ public static LiteralExpr/*!*/ True {
+ get {
+ Contract.Ensures(Contract.Result<LiteralExpr>() != null);
+ return true_;
+ }
+ }
+
+ private static LiteralExpr/*!*/ false_ = Literal(false);
+ public static LiteralExpr/*!*/ False {
+ get {
+ Contract.Ensures(Contract.Result<LiteralExpr>() != null);
+ return false_;
+ }
+ }
+
+
+ public static NAryExpr Select(Expr map, params Expr[] args) {
+ Contract.Requires(args != null);
+ Contract.Requires(map != null);
+ Contract.Ensures(Contract.Result<NAryExpr>() != null);
+ return SelectTok(Token.NoToken, map, args);
+ }
+
+ public static NAryExpr Select(Expr map, List<Expr/*!*/>/*!*/ args) {
+ Contract.Requires(map != null);
+ Contract.Requires(cce.NonNullElements(args));
+ Contract.Ensures(Contract.Result<NAryExpr>() != 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<NAryExpr>() != null);
+ List<Expr>/*!*/ allArgs = new List<Expr>();
+ 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<NAryExpr>() != null);
+ return StoreTok(Token.NoToken, map, args);
+ }
+
+ public static NAryExpr Store(Expr map, List<Expr/*!*/>/*!*/ indexes, Expr rhs) {
+ Contract.Requires(rhs != null);
+ Contract.Requires(map != null);
+ Contract.Requires(cce.NonNullElements(indexes));
+ Contract.Ensures(Contract.Result<NAryExpr>() != 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<NAryExpr>() != null);
+
+ List<Expr>/*!*/ allArgs = new List<Expr>();
+ 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<NAryExpr>() != null);
+ List<Expr>/*!*/ args = new List<Expr>();
+ args.Add(subexpr);
+ return new NAryExpr(x, new TypeCoercion(x, type), args);
+ }
+
+ public static Expr BinaryTreeAnd(List<Expr> terms)
+ {
+ return BinaryTreeAnd(terms, 0, terms.Count - 1);
+ }
+
+ private static Expr BinaryTreeAnd(List<Expr> 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<Expr> 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<Type>() != 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);
+ }
+
+ /// <summary>
+ /// Creates a literal expression for the boolean value "b".
+ /// </summary>
+ /// <param name="tok"></param>
+ /// <param name="b"></param>
+ 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();
+ }
+
+ /// <summary>
+ /// Creates a literal expression for the integer value "v".
+ /// </summary>
+ /// <param name="tok"></param>
+ /// <param name="v"></param>
+ 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();
+ }
+
+ /// <summary>
+ /// Creates a literal expression for the real value "v".
+ /// </summary>
+ /// <param name="tok"></param>
+ /// <param name="v"></param>
+ 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();
+ }
+
+ /// <summary>
+ /// Creates a literal expression for the floating point value "v".
+ /// </summary>
+ /// <param name="tok"></param>
+ /// <param name="v"></param>
+ 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();
+ }
+
+ /// <summary>
+ /// Creates a literal expression for the bitvector value "v".
+ /// </summary>
+ 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<Type>() != 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<Absy>() != 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<string>() != null);
+ return Value + "bv" + Bits;
+ }
+
+ [Pure]
+ public string ToReadableString() {
+ Contract.Ensures(Contract.Result<string>() != 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);
+ }
+
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ /// <param name="tok"></param>
+ /// <param name="name"></param>
+ 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();
+ }
+ /// <summary>
+ /// Creates an unresolved identifier expression.
+ /// </summary>
+ /// <param name="tok"></param>
+ /// <param name="name"></param>
+ /// <param name="type"></param>
+ 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();
+ }
+
+ /// <summary>
+ /// Creates a resolved identifier expression.
+ /// </summary>
+ /// <param name="tok"></param>
+ /// <param name="d"></param>
+ 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<Type>() != 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<IList>() != 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<Absy>() != 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<Type>() != null);
+
+ return Expr.ShallowType;
+ }
+ }
+
+ public override Absy StdDispatch(StandardVisitor visitor) {
+ //Contract.Requires(visitor != null);
+ Contract.Ensures(Contract.Result<Absy>() != null);
+ return visitor.VisitOldExpr(this);
+ }
+ }
+ [ContractClass(typeof(IAppliableVisitorContracts<>))]
+ public interface IAppliableVisitor<T> {
+ 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<T> : IAppliableVisitor<T> {
+
+ #region IAppliableVisitor<T> 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;
+ }
+
+ /// <summary>
+ /// 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).
+ /// </summary>
+ /// <param name="args"></param>
+ /// <param name="stream"></param>
+ /// <param name="contextBindingStrength"></param>
+ /// <param name="fragileContext"></param>
+ void Emit(IList<Expr>/*!*/ args, TokenTextWriter/*!*/ stream, int contextBindingStrength, bool fragileContext);
+
+ void Resolve(ResolutionContext/*!*/ rc, Expr/*!*/ subjectForErrorReporting);
+
+ /// <summary>
+ /// Requires the object to have been properly resolved.
+ /// </summary>
+ int ArgumentCount {
+ get;
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ /// <param name="args"></param>
+ /// <param name="tc"></param>
+ Type Typecheck(IList<Expr>/*!*/ args, out TypeParamInstantiation/*!*/ tpInstantiation, TypecheckingContext/*!*/ tc);
+
+ // Contract.Requires( Microsoft.SpecSharp.Collections.Reductions.Forall{Expr! arg in args; arg.Type != null});
+
+ /// <summary>
+ /// Returns the result type of the IAppliable, supposing the argument are of the correct types.
+ /// </summary>
+ Type/*!*/ ShallowType(IList<Expr>/*!*/ args);
+
+ T Dispatch<T>(IAppliableVisitor<T>/*!*/ visitor);
+ }
+ [ContractClassFor(typeof(IAppliable))]
+ abstract class IAppliableContracts : IAppliable {
+
+ #region IAppliable Members
+
+ public string FunctionName {
+ get {
+ Contract.Ensures(Contract.Result<string>() != null);
+ throw new NotImplementedException();
+ }
+ }
+
+ public void Emit(IList<Expr> 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<Expr> 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<Expr> args) {
+ Contract.Requires(args != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+
+ throw new NotImplementedException();
+ }
+
+ public T Dispatch<T>(IAppliableVisitor<T> 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<string>() != 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<Expr> 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<Expr> 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<Expr> args) {
+ //Contract.Requires(args != null);
+ Contract.Ensures(Contract.Result<Type>() != 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<T>(IAppliableVisitor<T> 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<string>() != 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<Expr> 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<Expr> 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<TypeVariable>/*!*/ unifiable = new List<TypeVariable>();
+ unifiable.AddRange(arg0type.FreeVariables);
+ unifiable.AddRange(arg1type.FreeVariables);
+
+ if (arg0type.Unify(arg1type, unifiable, new Dictionary<TypeVariable/*!*/, Type/*!*/>()))
+ 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<Expr> args) {
+ //Contract.Requires(args != null);
+ Contract.Ensures(Contract.Result<Type>() != 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<Expr> { 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<T>(IAppliableVisitor<T> 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<string>() != 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<string>() != 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<Expr> 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<Expr> 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<Type/*!*/>/*!*/ resultingTypeArgs;
+ List<Type> actualResultType =
+ Type.CheckArgumentTypes(Func.TypeParameters,
+ out resultingTypeArgs,
+ new List<Type>(Func.InParams.Select(Item => Item.TypedIdent.Type).ToArray()),
+ actuals,
+ new List<Type>(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<Expr> args) {
+ //Contract.Requires(args != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ Contract.Assume(name.Type != null);
+ return name.Type;
+ }
+
+ public virtual T Dispatch<T>(IAppliableVisitor<T> 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<string>() != null);
+
+ return ":";
+ }
+ }
+
+ public void Emit(IList<Expr>/*!*/ 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<Expr>/*!*/ 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<Expr> args) {
+ //Contract.Requires(args != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ return this.Type;
+ }
+
+ public T Dispatch<T>(IAppliableVisitor<T> 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<string>() != 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<Expr> 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<Expr> 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<Expr> args) {
+ //Contract.Requires(args != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ return this.type;
+ }
+
+ public virtual T Dispatch<T>(IAppliableVisitor<T> 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<Expr> _Args;
+ public IList<Expr> 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<Expr>;
+ }
+ }
+
+ [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<Expr>/*!*/ 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<Expr>(args);
+ CachedHashCode = ComputeHashCode();
+ } else {
+ if (args is List<Expr>) {
+ // Preserve NAryExpr's old behaviour, we take ownership of the List<Expr>.
+ // We can only do this if the type matches
+ _Args = args as List<Expr>;
+ }
+ else {
+ // Otherwise we must make a copy
+ _Args = new List<Expr> (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<Type>() != null);
+
+ return Fun.ShallowType(Args);
+ }
+ }
+
+ public override Absy StdDispatch(StandardVisitor visitor) {
+ //Contract.Requires(visitor != null);
+ Contract.Ensures(Contract.Result<Absy>() != 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<string>() != 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<Expr>/*!*/ 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<Expr>/*!*/ 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<Expr>/*!*/ 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<Expr> 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<Expr> actualArgs = new List<Expr>();
+ 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");
+ }
+
+ /// <summary>
+ /// Returns the result type of the IAppliable, supposing the argument are of the correct types.
+ /// </summary>
+ public Type ShallowType(IList<Expr> args) {
+ //Contract.Requires(args != null);
+ Contract.Ensures(Contract.Result<Type>() != 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<Type> actualArgTypes = new List<Type>();
+ 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<T>(IAppliableVisitor<T> 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<string>() != 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<Expr>/*!*/ 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<Expr>/*!*/ 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<Expr> selectArgs = new List<Expr>();
+ 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<Expr>/*!*/ 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");
+ }
+
+ /// <summary>
+ /// Returns the result type of the IAppliable, supposing the argument are of the correct types.
+ /// </summary>
+ public Type ShallowType(IList<Expr> args) {
+ //Contract.Requires(args != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ return cce.NonNull(args[0]).ShallowType;
+ }
+
+ public T Dispatch<T>(IAppliableVisitor<T> visitor) {
+ //Contract.Requires(visitor != null);
+ return visitor.Visit(this);
+ }
+ }
+
+
+ public class IfThenElse : IAppliable {
+
+ private IToken/*!*/ _tok;
+
+ public IToken/*!*/ tok
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<IToken>() != 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<string>() != 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<Expr> 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<Expr> 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;
+ }
+
+ /// <summary>
+ /// Returns the result type of the IAppliable, supposing the argument are of the correct types.
+ /// </summary>
+ public Type ShallowType(IList<Expr> args) {
+ //Contract.Requires(args != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ return cce.NonNull(args[1]).ShallowType;
+ }
+
+ public T Dispatch<T>(IAppliableVisitor<T> visitor) {
+ //Contract.Requires(visitor != null);
+ return visitor.Visit(this);
+ }
+ }
+
+
+
+ public class CodeExpr : Expr {
+ public List<Variable>/*!*/ LocVars;
+ [Rep]
+ public List<Block/*!*/>/*!*/ Blocks;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(LocVars != null);
+ Contract.Invariant(cce.NonNullElements(Blocks));
+ }
+
+ public CodeExpr(List<Variable>/*!*/ localVariables, List<Block/*!*/>/*!*/ 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<Type>() != null);
+
+ return Type.Bool;
+ }
+ }
+
+ public override Absy StdDispatch(StandardVisitor visitor) {
+ //Contract.Requires(visitor != null);
+ Contract.Ensures(Contract.Result<Absy>() != 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<Type>() != null);
+
+ return Type.GetBvType(End - Start);
+ }
+ }
+
+ public override Absy StdDispatch(StandardVisitor visitor) {
+ //Contract.Requires(visitor != null);
+ Contract.Ensures(Contract.Result<Absy>() != 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<Type>() != 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<Absy>() != 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<object>;
-
- //---------------------------------------------------------------------
- // 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<TypeVariable>/*!*/ TypeParameters;
- public List<Variable>/*!*/ 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<TypeVariable>/*!*/ typeParameters,
- List<Variable>/*!*/ 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<Type>(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<TypeVariable> typeParameters, List<Variable> 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<TypeVariable> GetUnmentionedTypeParameters() {
- Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
- List<TypeVariable>/*!*/ dummyParameters = Type.FreeVariablesIn(new List<Type>(Dummies.Select(Item => Item.TypedIdent.Type).ToArray()));
- Contract.Assert(dummyParameters != null);
- List<TypeVariable>/*!*/ unmentionedParameters = new List<TypeVariable>();
- 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<object/*!*/>/*!*/ _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<object> ps)
- {
- Contract.Requires(cce.NonNullElements(ps));
- this._params.AddRange(ps);
- }
-
- public void ClearParams()
- {
- this._params.Clear();
- }
-
- public IList<object> Params
- {
- get
- {
- Contract.Ensures(cce.NonNullElements(Contract.Result<IList<object>>()));
- Contract.Ensures(Contract.Result<IList<object>>().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<object/*!*/>/*!*/ parameters, QKeyValue next)
- : base(tok) {
- Contract.Requires(key != null);
- Contract.Requires(tok != null);
- Contract.Requires(cce.NonNullElements(parameters));
- Key = key;
- this._params = new List<object>(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<object> newParams = new List<object>();
- 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<Expr>/*!*/ tr;
-
- public IList<Expr>/*!*/ Tr
- {
- get
- {
- Contract.Ensures(Contract.Result<IList<Expr>>() != null);
- Contract.Ensures(Contract.Result<IList<Expr>>().Count >= 1);
- Contract.Ensures(this.Pos || Contract.Result<IList<Expr>>().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<Expr>(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<Expr>/*!*/ 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<Expr>(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;
- }
-
- /// <summary>
- /// Add to "freeVars" the free variables in the triggering expressions.
- /// </summary>
- 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<Absy>() != 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<TypeVariable>/*!*/ typeParams,
- List<Variable>/*!*/ 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<Variable> dummies, Trigger triggers, Expr body, bool immutable=false)
- : base(tok, new List<TypeVariable>(), 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<Variable> dummies, Expr body, bool immutable=false)
- : base(tok, new List<TypeVariable>(), 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<TypeVariable> typeParams, List<Variable> 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<Absy>() != null);
- return visitor.VisitForallExpr(this);
- }
-
- public override BinderKind Kind {
- get {
- return BinderKind.Forall;
- }
- }
- }
-
- public class ExistsExpr : QuantifierExpr {
- public ExistsExpr(IToken/*!*/ tok, List<TypeVariable>/*!*/ typeParams, List<Variable>/*!*/ 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<Variable> dummies, Trigger triggers, Expr body, bool immutable=false)
- : base(tok, new List<TypeVariable>(), 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<Variable> dummies, Expr body, bool immutable=false)
- : base(tok, new List<TypeVariable>(), 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<Absy>() != 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<TypeVariable>/*!*/ typeParameters,
- List<Variable>/*!*/ 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<Expr>() != 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<Expr> { 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<TypeVariable>/*!*/ 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<Type>() != 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<TypeVariable>/*!*/ typeParameters,
- List<Variable>/*!*/ 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<Type>/*!*/ argTypes = new List<Type>();
- 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<TypeVariable>/*!*/ 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<Type>() != null);
-
- if (mapType == null) {
- List<Type>/*!*/ argTypes = new List<Type>();
- 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<Absy>() != 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<object>;
+
+ //---------------------------------------------------------------------
+ // 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<TypeVariable>/*!*/ TypeParameters;
+ public List<Variable>/*!*/ 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<TypeVariable>/*!*/ typeParameters,
+ List<Variable>/*!*/ 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<Type>(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<TypeVariable> typeParameters, List<Variable> 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<TypeVariable> GetUnmentionedTypeParameters() {
+ Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
+ List<TypeVariable>/*!*/ dummyParameters = Type.FreeVariablesIn(new List<Type>(Dummies.Select(Item => Item.TypedIdent.Type).ToArray()));
+ Contract.Assert(dummyParameters != null);
+ List<TypeVariable>/*!*/ unmentionedParameters = new List<TypeVariable>();
+ 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<object/*!*/>/*!*/ _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<object> ps)
+ {
+ Contract.Requires(cce.NonNullElements(ps));
+ this._params.AddRange(ps);
+ }
+
+ public void ClearParams()
+ {
+ this._params.Clear();
+ }
+
+ public IList<object> Params
+ {
+ get
+ {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<IList<object>>()));
+ Contract.Ensures(Contract.Result<IList<object>>().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<object/*!*/>/*!*/ parameters, QKeyValue next)
+ : base(tok) {
+ Contract.Requires(key != null);
+ Contract.Requires(tok != null);
+ Contract.Requires(cce.NonNullElements(parameters));
+ Key = key;
+ this._params = new List<object>(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<object> newParams = new List<object>();
+ 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<Expr>/*!*/ tr;
+
+ public IList<Expr>/*!*/ Tr
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<IList<Expr>>() != null);
+ Contract.Ensures(Contract.Result<IList<Expr>>().Count >= 1);
+ Contract.Ensures(this.Pos || Contract.Result<IList<Expr>>().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<Expr>(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<Expr>/*!*/ 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<Expr>(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;
+ }
+
+ /// <summary>
+ /// Add to "freeVars" the free variables in the triggering expressions.
+ /// </summary>
+ 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<Absy>() != 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<TypeVariable>/*!*/ typeParams,
+ List<Variable>/*!*/ 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<Variable> dummies, Trigger triggers, Expr body, bool immutable=false)
+ : base(tok, new List<TypeVariable>(), 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<Variable> dummies, Expr body, bool immutable=false)
+ : base(tok, new List<TypeVariable>(), 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<TypeVariable> typeParams, List<Variable> 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<Absy>() != null);
+ return visitor.VisitForallExpr(this);
+ }
+
+ public override BinderKind Kind {
+ get {
+ return BinderKind.Forall;
+ }
+ }
+ }
+
+ public class ExistsExpr : QuantifierExpr {
+ public ExistsExpr(IToken/*!*/ tok, List<TypeVariable>/*!*/ typeParams, List<Variable>/*!*/ 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<Variable> dummies, Trigger triggers, Expr body, bool immutable=false)
+ : base(tok, new List<TypeVariable>(), 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<Variable> dummies, Expr body, bool immutable=false)
+ : base(tok, new List<TypeVariable>(), 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<Absy>() != 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<TypeVariable>/*!*/ typeParameters,
+ List<Variable>/*!*/ 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<Expr>() != 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<Expr> { 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<TypeVariable>/*!*/ 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<Type>() != 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<TypeVariable>/*!*/ typeParameters,
+ List<Variable>/*!*/ 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<Type>/*!*/ argTypes = new List<Type>();
+ 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<TypeVariable>/*!*/ 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<Type>() != null);
+
+ if (mapType == null) {
+ List<Type>/*!*/ argTypes = new List<Type>();
+ 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<Absy>() != 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<Absy>() != null);
- return this.Clone(new Dictionary<TypeVariable/*!*/, TypeVariable/*!*/>());
- }
-
- public abstract Type/*!*/ Clone(IDictionary<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap);
-
- /// <summary>
- /// 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.
- /// </summary>
- 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<string>() != null);
- System.IO.StringWriter buffer = new System.IO.StringWriter();
- using (TokenTextWriter stream = new TokenTextWriter("<buffer>", 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<TypeVariable>(),
- new List<TypeVariable>());
- }
-
- [Pure]
- public abstract bool Equals(Type/*!*/ that,
- List<TypeVariable>/*!*/ thisBoundVariables,
- List<TypeVariable>/*!*/ 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<Type>() != null);
-
- return this;
- }
- }
-
- //----------- Unification of types -----------
-
- /// <summary>
- /// 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.
- /// </summary>
- public bool Unify(Type that) {
- Contract.Requires(that != null);
- return Unify(that, new List<TypeVariable>(), new Dictionary<TypeVariable/*!*/, Type/*!*/>());
- }
-
- public abstract bool Unify(Type/*!*/ that,
- List<TypeVariable>/*!*/ unifiableVariables,
- // an idempotent substitution that describes the
- // unification result up to a certain point
- IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ unifier);
-
-
- [Pure]
- public static bool IsIdempotent(IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable!, Type!> Unify(Type! that,
- List<TypeVariable>! unifiableVariables) {
- Dictionary<TypeVariable!, Type!>! result = new Dictionary<TypeVariable!, Type!> ();
- try {
- this.Unify(that, unifiableVariables,
- new List<TypeVariable> (), new List<TypeVariable> (), 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<TypeVariable>! unifiableVariables,
- // given mappings that need to be taken into account
- // the old unifier has to be idempotent as well
- IDictionary<TypeVariable!, Type!>! unifier)
- {
- Contract.Requires(Contract.ForAll(unifier.Keys , key=> unifiableVariables.Has(key)));
- Contract.Requires(IsIdempotent(unifier));
- try {
- this.Unify(that, unifiableVariables,
- new List<TypeVariable> (), new List<TypeVariable> (), unifier);
- } catch (UnificationFailedException) {
- return false;
- }
- return true;
- }
-
- public abstract void Unify(Type! that,
- List<TypeVariable>! unifiableVariables,
- List<TypeVariable>! thisBoundVariables,
- List<TypeVariable>! thatBoundVariables,
- // an idempotent substitution that describes the
- // unification result up to a certain point
- IDictionary<TypeVariable!, Type!>! result);
-#endif
-
- //----------- Substitution of free variables with types not containing bound variables -----------------
-
- public abstract Type/*!*/ Substitute(IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable>());
- }
-
- [Pure]
- public abstract int GetHashCode(List<TypeVariable>/*!*/ 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<TypeVariable>/*!*/ FreeVariables {
- get;
- }
-
- // determine the free type proxies in a type, in the order in which they occur
- public abstract List<TypeProxy/*!*/>/*!*/ FreeProxies {
- get;
- }
-
- protected static void AppendWithoutDups<A>(List<A> a, List<A> 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<TypeVariable>() != 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<CtorType>() != 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<MapType>() != 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<UnresolvedTypeIdentifier>() != 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<BvType>() != 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<FloatType>() != 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<TypeVariable!, Type!>!
- MatchArgumentTypes(List<TypeVariable>! typeParams,
- List<Type>! formalArgs,
- List<Expr>! actualArgs,
- List<Type> formalOuts,
- List<IdentifierExpr> 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<TypeVariable>! boundVarSeq0 = new List<TypeVariable> ();
- List<TypeVariable>! boundVarSeq1 = new List<TypeVariable> ();
- Dictionary<TypeVariable!, Type!>! subst = new Dictionary<TypeVariable!, Type!>();
-
- 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<TypeVariable/*!*/, Type/*!*/>/*!*/
- MatchArgumentTypes(List<TypeVariable>/*!*/ typeParams,
- List<Type>/*!*/ formalArgs,
- IList<Expr>/*!*/ actualArgs,
- List<Type> formalOuts,
- List<IdentifierExpr> 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<IDictionary<TypeVariable, Type>>()));
-
- // requires "actualArgs" and "actualOuts" to have been type checked
-
- Dictionary<TypeVariable/*!*/, Type/*!*/> subst = new Dictionary<TypeVariable/*!*/, Type/*!*/>();
- 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<Type> CheckArgumentTypes(List<TypeVariable>/*!*/ typeParams,
- out List<Type/*!*/>/*!*/ actualTypeParams,
- List<Type>/*!*/ formalIns,
- IList<Expr>/*!*/ actualIns,
- List<Type>/*!*/ formalOuts,
- List<IdentifierExpr> 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<Type/*!*/>();
-
- 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<Type>();
- return typeParams.Count == 0 ? formalOuts : null;
- }
-
- int previousErrorCount = tc.ErrorCount;
- IDictionary<TypeVariable/*!*/, Type/*!*/> 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<Type>/*!*/ actualResults = new List<Type>();
- foreach (Type/*!*/ t in formalOuts) {
- Contract.Assert(t != null);
- actualResults.Add(t.Substitute(subst));
- }
- List<TypeVariable> 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<TypeVariable>/*!*/ typeParams,
- List<Type>/*!*/ formalArgs,
- Type/*!*/ formalResult,
- List<Type>/*!*/ actualArgs) {
- Contract.Requires(typeParams != null);
- Contract.Requires(formalArgs != null);
- Contract.Requires(formalResult != null);
- Contract.Requires(actualArgs != null);
- Contract.Ensures(Contract.Result<Type>() != null);
-
- IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable>/*!*/ 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<TypeVariable!, Type!>!
- InferTypeParameters(List<TypeVariable>! typeParams,
- List<Type>! formalArgs,
- List<Type>! actualArgs)
- {
- Contract.Requires(formalArgs.Length == actualArgs.Length);
-
- List<TypeVariable>! boundVarSeq0 = new List<TypeVariable> ();
- List<TypeVariable>! boundVarSeq1 = new List<TypeVariable> ();
- Dictionary<TypeVariable!, Type!>! subst = new Dictionary<TypeVariable!, Type!>();
-
- 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
- /// <summary>
- /// like Type.CheckArgumentTypes, but assumes no errors
- /// (and only does arguments, not results; and takes actuals as List<Type>, not List<Expr>)
- /// </summary>
- public static IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/
- InferTypeParameters(List<TypeVariable>/*!*/ typeParams,
- List<Type>/*!*/ formalArgs,
- List<Type>/*!*/ 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<IDictionary<TypeVariable, Type>>()));
-
-
- List<Type> proxies = new List<Type>();
- Dictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ subst = new Dictionary<TypeVariable/*!*/, Type/*!*/>();
- 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<TypeVariable> 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<TypeVariable>/*!*/ SortTypeParams(List<TypeVariable>/*!*/ typeParams, List<Type>/*!*/ argumentTypes, Type resultType) {
- Contract.Requires(typeParams != null);
- Contract.Requires(argumentTypes != null);
- Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
-
- Contract.Ensures(Contract.Result<List<TypeVariable>>().Count == typeParams.Count);
- if (typeParams.Count == 0) {
- return typeParams;
- }
-
- List<TypeVariable> 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<TypeVariable> sortedTypeParams = new List<TypeVariable>();
- 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<TypeVariable>/*!*/ typeParams,
- List<Type>/*!*/ argumentTypes,
- List<Type> 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<TypeVariable> freeVarsInArgs = FreeVariablesIn(argumentTypes);
- List<TypeVariable> 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<TypeVariable> FreeVariablesIn(List<Type> arguments) {
- Contract.Requires(arguments != null);
- Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
- List<TypeVariable>/*!*/ res = new List<TypeVariable>();
- 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<TypeProxy> FreeProxies {
- get {
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeProxy>>()));
- throw new NotImplementedException();
- }
- }
- public override List<TypeVariable> FreeVariables {
- get {
- Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
- throw new NotImplementedException();
- }
- }
- public override Type Clone(IDictionary<TypeVariable, TypeVariable> varMap) {
- Contract.Requires(cce.NonNullDictionaryAndValues(varMap));
- Contract.Ensures(Contract.Result<Type>() != null);
-
- throw new NotImplementedException();
- }
- public override Type CloneUnresolved() {
- Contract.Ensures(Contract.Result<Type>() != 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<TypeVariable> thisBoundVariables, List<TypeVariable> thatBoundVariables) {
- Contract.Requires(that != null);
- Contract.Requires(thisBoundVariables != null);
- Contract.Requires(thatBoundVariables != null);
- throw new NotImplementedException();
- }
- public override bool Unify(Type that, List<TypeVariable> unifiableVariables, IDictionary<TypeVariable, Type> 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<TypeVariable, Type> subst) {
- Contract.Requires(cce.NonNullDictionaryAndValues(subst));
- Contract.Ensures(Contract.Result<Type>() != null);
-
- throw new NotImplementedException();
- }
- public override Type ResolveType(ResolutionContext rc) {
- Contract.Requires(rc != null);
- Contract.Ensures(Contract.Result<Type>() != null);
-
- throw new NotImplementedException();
- }
- public override int GetHashCode(List<TypeVariable> 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
- //Contract.Requires(cce.NonNullElements(varMap));
- Contract.Ensures(Contract.Result<Type>() != null);
- // BasicTypes are immutable anyway, we do not clone
- return this;
- }
-
- public override Type CloneUnresolved() {
- Contract.Ensures(Contract.Result<Type>() != 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<string>() != 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<TypeVariable> thisBoundVariables, List<TypeVariable> 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<TypeVariable> unifiableVariables, IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable>! unifiableVariables,
- List<TypeVariable>! thisBoundVariables,
- List<TypeVariable>! thatBoundVariables,
- IDictionary<TypeVariable!, Type!>! 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
- //Contract.Requires(cce.NonNullElements(subst));
- Contract.Ensures(Contract.Result<Type>() != null);
- return this;
- }
-
- //----------- Hashcodes ----------------------------------
-
- [Pure]
- public override int GetHashCode(List<TypeVariable> boundVariables) {
- //Contract.Requires(boundVariables != null);
- return this.T.GetHashCode();
- }
-
- //----------- Resolution ----------------------------------
-
- public override Type ResolveType(ResolutionContext rc) {
- //Contract.Requires(rc != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- // nothing to resolve
- return this;
- }
-
- // determine the free variables in a type, in the order in which the variables occur
- public override List<TypeVariable>/*!*/ FreeVariables {
- get {
- Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
-
- return new List<TypeVariable>(); // basic type are closed
- }
- }
-
- public override List<TypeProxy/*!*/>/*!*/ FreeProxies {
- get {
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeProxy>>()));
- return new List<TypeProxy/*!*/>();
- }
- }
-
- //----------- 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<Absy>() != 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap)
- {
- //Contract.Requires(cce.NonNullElements(varMap));
- Contract.Ensures(Contract.Result<Type>() != null);
- // FloatTypes are immutable anyway, we do not clone
- return this;
- }
-
- public override Type CloneUnresolved()
- {
- Contract.Ensures(Contract.Result<Type>() != 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<string>() != null);
- return "float (" + Exponent + " " + Mantissa + ")";
- }
-
- //----------- Equality ----------------------------------
-
- [Pure]
- public override bool Equals(Type/*!*/ that,
- List<TypeVariable>/*!*/ thisBoundVariables,
- List<TypeVariable>/*!*/ 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<TypeVariable>/*!*/ unifiableVariables,
- // an idempotent substitution that describes the
- // unification result up to a certain point
- IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst)
- {
- Contract.Ensures(Contract.Result<Type>() != null);
- return this;
- }
-
- //----------- Hashcodes ----------------------------------
-
- [Pure]
- public override int GetHashCode(List<TypeVariable> boundVariables)
- {
- return this.Mantissa.GetHashCode() + this.Exponent.GetHashCode();
- }
-
- //----------- Resolution ----------------------------------
-
- public override Type ResolveType(ResolutionContext rc)
- {
- //Contract.Requires(rc != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- // nothing to resolve
- return this;
- }
-
- // determine the free variables in a type, in the order in which the variables occur
- public override List<TypeVariable>/*!*/ FreeVariables
- {
- get
- {
- Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
-
- return new List<TypeVariable>(); // bitvector-type are closed
- }
- }
-
- public override List<TypeProxy/*!*/>/*!*/ FreeProxies
- {
- get
- {
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeProxy>>()));
- return new List<TypeProxy/*!*/>();
- }
- }
-
- //----------- 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<Absy>() != 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
- //Contract.Requires(cce.NonNullElements(varMap));
- Contract.Ensures(Contract.Result<Type>() != null);
- // BvTypes are immutable anyway, we do not clone
- return this;
- }
-
- public override Type CloneUnresolved() {
- Contract.Ensures(Contract.Result<Type>() != 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<string>() != null);
- return "bv" + Bits;
- }
-
- //----------- Equality ----------------------------------
-
- [Pure]
- public override bool Equals(Type/*!*/ that,
- List<TypeVariable>/*!*/ thisBoundVariables,
- List<TypeVariable>/*!*/ 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<TypeVariable>/*!*/ unifiableVariables,
- // an idempotent substitution that describes the
- // unification result up to a certain point
- IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable>! unifiableVariables,
- List<TypeVariable>! thisBoundVariables,
- List<TypeVariable>! thatBoundVariables,
- IDictionary<TypeVariable!, Type!> 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
- //Contract.Requires(cce.NonNullElements(subst));
- Contract.Ensures(Contract.Result<Type>() != null);
- return this;
- }
-
- //----------- Hashcodes ----------------------------------
-
- [Pure]
- public override int GetHashCode(List<TypeVariable> boundVariables) {
- //Contract.Requires(boundVariables != null);
- return this.Bits.GetHashCode();
- }
-
- //----------- Resolution ----------------------------------
-
- public override Type ResolveType(ResolutionContext rc) {
- //Contract.Requires(rc != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- // nothing to resolve
- return this;
- }
-
- // determine the free variables in a type, in the order in which the variables occur
- public override List<TypeVariable>/*!*/ FreeVariables {
- get {
- Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
-
- return new List<TypeVariable>(); // bitvector-type are closed
- }
- }
-
- public override List<TypeProxy/*!*/>/*!*/ FreeProxies {
- get {
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeProxy>>()));
- return new List<TypeProxy/*!*/>();
- }
- }
-
- //----------- 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<Absy>() != 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<Type>/*!*/ Arguments;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(Name != null);
- Contract.Invariant(Arguments != null);
- }
-
-
- public UnresolvedTypeIdentifier(IToken token, string name)
- : this(token, name, new List<Type>()) {
- Contract.Requires(name != null);
- Contract.Requires(token != null);
- }
-
- public UnresolvedTypeIdentifier(IToken token, string name, List<Type> 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
- //Contract.Requires(cce.NonNullElements(varMap));
- Contract.Ensures(Contract.Result<Type>() != null);
- List<Type>/*!*/ newArgs = new List<Type>();
- 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<Type>() != null);
- List<Type>/*!*/ newArgs = new List<Type>();
- 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<TypeVariable>/*!*/ thisBoundVariables,
- List<TypeVariable>/*!*/ 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<TypeVariable>/*!*/ unifiableVariables,
- IDictionary<TypeVariable/*!*/, Type/*!*/> 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<TypeVariable>! unifiableVariables,
- List<TypeVariable>! thisBoundVariables,
- List<TypeVariable>! thatBoundVariables,
- IDictionary<TypeVariable!, Type!> 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
- //Contract.Requires(cce.NonNullElements(subst));
- Contract.Ensures(Contract.Result<Type>() != null);
- {
- Contract.Assert(false);
- throw new cce.UnreachableException();
- } // UnresolvedTypeIdentifier.Substitute should never be called
- }
-
- //----------- Hashcodes ----------------------------------
-
- [Pure]
- public override int GetHashCode(List<TypeVariable> 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<Type>() != 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<Type>/*!*/ 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<Type> ResolveArguments(ResolutionContext rc) {
- Contract.Requires(rc != null);
- Contract.Ensures(Contract.Result<List<Type>>() != null);
- List<Type>/*!*/ resolvedArgs = new List<Type>();
- foreach (Type/*!*/ t in Arguments) {
- Contract.Assert(t != null);
- resolvedArgs.Add(t.ResolveType(rc));
- }
- return resolvedArgs;
- }
-
- public override List<TypeVariable>/*!*/ FreeVariables {
- get {
- Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
-
- return new List<TypeVariable>();
- }
- }
-
- public override List<TypeProxy/*!*/>/*!*/ FreeProxies {
- get {
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeProxy>>()));
- return new List<TypeProxy/*!*/>();
- }
- }
-
- //----------- 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<UnresolvedTypeIdentifier>() != null);
- return this;
- }
- }
-
- public override Absy StdDispatch(StandardVisitor visitor) {
- //Contract.Requires(visitor != null);
- Contract.Ensures(Contract.Result<Absy>() != 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
- //Contract.Requires(cce.NonNullElements(varMap));
- Contract.Ensures(Contract.Result<Type>() != 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<Type>() != null);
- return this;
- }
-
- //----------- Equality ----------------------------------
-
- [Pure]
- public override bool Equals(Type that,
- List<TypeVariable>/*!*/ thisBoundVariables,
- List<TypeVariable>/*!*/ 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<TypeVariable>/*!*/ unifiableVariables,
- // an idempotent substitution that describes the
- // unification result up to a certain point
- IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable/*!*/, Type/*!*/>/*!*/ newMapping = new Dictionary<TypeVariable/*!*/, Type/*!*/>();
- // 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<TypeVariable/*!*/>/*!*/ keys = new List<TypeVariable/*!*/>();
- 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<TypeVariable>! unifiableVariables,
- List<TypeVariable>! thisBoundVariables,
- List<TypeVariable>! thatBoundVariables,
- IDictionary<TypeVariable!, Type!> 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<TypeVariable>! 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
- //Contract.Requires(cce.NonNullElements(subst));
- Contract.Ensures(Contract.Result<Type>() != 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<TypeVariable> 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<Type>() != null);
- // nothing to resolve
- return this;
- }
-
- public override List<TypeVariable>/*!*/ FreeVariables {
- get {
- Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
- return new List<TypeVariable> { this };
- }
- }
-
- public override List<TypeProxy/*!*/>/*!*/ FreeProxies {
- get {
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeProxy>>()));
- return new List<TypeProxy/*!*/>();
- }
- }
-
- //----------- Getters/Issers ----------------------------------
-
- public override bool IsVariable {
- get {
- return true;
- }
- }
- public override TypeVariable/*!*/ AsVariable {
- get {
- Contract.Ensures(Contract.Result<TypeVariable>() != null);
- return this;
- }
- }
-
- public override Absy StdDispatch(StandardVisitor visitor) {
- //Contract.Requires(visitor != null);
- //Contract.Ensures(Contract.Result<Absy>() != 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<Type>() != null);
- Contract.Ensures(!(Contract.Result<Type>() is TypeProxy) || ((TypeProxy)Contract.Result<Type>()).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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
- //Contract.Requires(cce.NonNullElements(varMap));
- Contract.Ensures(Contract.Result<Type>() != 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<n>$proxy<m>
- }
- }
-
- public override Type CloneUnresolved() {
- Contract.Ensures(Contract.Result<Type>() != null);
- return new TypeProxy(this.tok, this.Name); // the clone will have a name that ends with $proxy<n>$proxy<m>
- }
-
- //----------- Equality ----------------------------------
-
- [Pure]
- public override bool Equals(Type that,
- List<TypeVariable>/*!*/ thisBoundVariables,
- List<TypeVariable>/*!*/ 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<TypeVariable>/*!*/ unifiableVariables,
- IDictionary<TypeVariable/*!*/, Type/*!*/> 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
- //Contract.Requires(cce.NonNullElements(subst));
- Contract.Ensures(Contract.Result<Type>() != null);
- Type p = ProxyFor;
- if (p != null) {
- return p.Substitute(subst);
- } else {
- return this;
- }
- }
-
- //----------- Hashcodes ----------------------------------
-
- [Pure]
- public override int GetHashCode(List<TypeVariable> 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<Type>() != null);
- Type p = ProxyFor;
- if (p != null) {
- return p.ResolveType(rc);
- } else {
- return this;
- }
- }
-
- public override List<TypeVariable>/*!*/ FreeVariables {
- get {
- Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
-
- Type p = ProxyFor;
- if (p != null) {
- return p.FreeVariables;
- } else {
- return new List<TypeVariable>();
- }
- }
- }
-
- public override List<TypeProxy/*!*/>/*!*/ FreeProxies {
- get {
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeProxy>>()));
- Type p = ProxyFor;
- if (p != null) {
- return p.FreeProxies;
- } else {
- List<TypeProxy/*!*/>/*!*/ res = new List<TypeProxy/*!*/>();
- 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<TypeVariable>() != 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<CtorType>() != 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<MapType>() != 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<UnresolvedTypeIdentifier>() != 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<Absy>() != 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);
- }
- }
-
- /// <summary>
- /// 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.
- /// </summary>
- public class BvTypeProxy : ConstrainedProxy {
- public int MinBits;
- List<BvTypeConstraint/*!*/> 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;
- }
-
- /// <summary>
- /// Requires that any further constraints to be placed on t0 and t1 go via the object to
- /// be constructed.
- /// </summary>
- 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<BvTypeConstraint/*!*/> list = new List<BvTypeConstraint/*!*/>();
- list.Add(new BvTypeConstraint(t0, t1));
- this.constraints = list;
- }
-
- /// <summary>
- /// Construct a BvTypeProxy like p, but with minBits.
- /// </summary>
- 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<BvTypeConstraint/*!*/> 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<int>());
-
- 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
- //Contract.Requires(cce.NonNullElements(varMap));
- Contract.Ensures(Contract.Result<Type>() != 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<n>$bvproxy<m>
- }
- }
-
- public override Type CloneUnresolved() {
- Contract.Ensures(Contract.Result<Type>() != null);
- return new BvTypeProxy(this.tok, this.Name, this.MinBits, this.constraints); // the clone will have a name that ends with $bvproxy<n>$bvproxy<m>
- }
-
- //----------- Unification of types -----------
-
- public override bool Unify(Type that,
- List<TypeVariable> unifiableVariables,
- IDictionary<TypeVariable, Type> 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<BvTypeConstraint/*!*/> list = new List<BvTypeConstraint/*!*/>();
- 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<int>() && Contract.Result<int>() <= 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
- //Contract.Requires(cce.NonNullElements(subst));
- Contract.Ensures(Contract.Result<Type>() != 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<Absy>() != 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<Constraint>/*!*/ constraints = new List<Constraint>();
- [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<Type>/*!*/ Arguments;
- public readonly Type/*!*/ Result;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(Arguments != null);
- Contract.Invariant(Result != null);
- }
-
-
- public Constraint(List<Type> arguments, Type result) {
- Contract.Requires(result != null);
- Contract.Requires(arguments != null);
- Arguments = arguments;
- Result = result;
- }
-
- public Constraint Clone(IDictionary<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
- Contract.Requires(cce.NonNullDictionaryAndValues(varMap));
- List<Type>/*!*/ args = new List<Type>();
- 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<TypeVariable>/*!*/ unifiableVariables,
- IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ result) {
- Contract.Requires(unifiableVariables != null);
- Contract.Requires(cce.NonNullDictionaryAndValues(result));
- Contract.Requires(that != null);
- Contract.Requires(Arguments.Count == that.Arguments.Count);
- Dictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ subst = new Dictionary<TypeVariable/*!*/, Type/*!*/>();
- 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<TypeVariable>(), new Dictionary<TypeVariable/*!*/, Type/*!*/>());
- 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<Expr>/*!*/ 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<Type>/*!*/ arguments = new List<Type>();
- 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<Type>/*!*/ argumentsResult = new List<Type>();
- 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
- //Contract.Requires(cce.NonNullElements(varMap));
- Contract.Ensures(Contract.Result<Type>() != 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<n>$mapproxy<m> (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<TypeVariable>/*!*/ unifiableVariables,
- IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
- //Contract.Requires(cce.NonNullElements(subst));
- Contract.Ensures(Contract.Result<Type>() != 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<MapType>() != 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<Absy>() != 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<Type>/*!*/ 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<Type>/*!*/ 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst =
- new Dictionary<TypeVariable/*!*/, Type/*!*/>();
- 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<Type>/*!*/ 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
- //Contract.Requires(cce.NonNullElements(varMap));
- Contract.Ensures(Contract.Result<Type>() != null);
- List<Type>/*!*/ newArgs = new List<Type>();
- 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<Type>() != null);
- List<Type>/*!*/ newArgs = new List<Type>();
- 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<TypeVariable>/*!*/ thisBoundVariables,
- List<TypeVariable>/*!*/ 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<Type>() != null);
-
- return ExpandedType.Expanded;
- }
- }
-
- //----------- Unification of types -----------
-
- public override bool Unify(Type/*!*/ that,
- List<TypeVariable>/*!*/ unifiableVariables,
- IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable>! unifiableVariables,
- List<TypeVariable>! thisBoundVariables,
- List<TypeVariable>! thatBoundVariables,
- IDictionary<TypeVariable!, Type!>! result) {
- ExpandedType.Unify(that, unifiableVariables,
- thisBoundVariables, thatBoundVariables, result);
- }
-#endif
-
- //----------- Substitution of free variables with types not containing bound variables -----------------
-
- public override Type Substitute(IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
- //Contract.Requires(cce.NonNullElements(subst));
- Contract.Ensures(Contract.Result<Type>() != null);
- if (subst.Count == 0)
- return this;
- List<Type> newArgs = new List<Type>();
- 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<TypeVariable> 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<Type>() != null);
- List<Type> resolvedArgs = new List<Type>();
- foreach (Type/*!*/ t in Arguments) {
- Contract.Assert(t != null);
- resolvedArgs.Add(t.ResolveType(rc));
- }
- return new TypeSynonymAnnotation(tok, Decl, resolvedArgs);
- }
-
- public override List<TypeVariable>/*!*/ FreeVariables {
- get {
- Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
-
- return ExpandedType.FreeVariables;
- }
- }
-
- public override List<TypeProxy/*!*/>/*!*/ FreeProxies {
- get {
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeProxy>>()));
- 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<TypeVariable>() != null);
- return ExpandedType.AsVariable;
- }
- }
- public override bool IsCtor {
- get {
- return ExpandedType.IsCtor;
- }
- }
- public override CtorType/*!*/ AsCtor {
- get {
- Contract.Ensures(Contract.Result<CtorType>() != null);
- return ExpandedType.AsCtor;
- }
- }
- public override bool IsMap {
- get {
- return ExpandedType.IsMap;
- }
- }
- public override MapType/*!*/ AsMap {
- get {
- Contract.Ensures(Contract.Result<MapType>() != null);
- return ExpandedType.AsMap;
- }
- }
- public override bool IsUnresolved {
- get {
- return ExpandedType.IsUnresolved;
- }
- }
- public override UnresolvedTypeIdentifier/*!*/ AsUnresolved {
- get {
- Contract.Ensures(Contract.Result<UnresolvedTypeIdentifier>() != 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<Absy>() != null);
- return visitor.VisitTypeSynonymAnnotation(this);
- }
- }
-
- //=====================================================================
-
- public class CtorType : Type {
- public readonly List<Type>/*!*/ 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<Type>/*!*/ 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
- //Contract.Requires(cce.NonNullElements(varMap));
- Contract.Ensures(Contract.Result<Type>() != null);
- List<Type>/*!*/ newArgs = new List<Type>();
- 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<Type>() != null);
- List<Type>/*!*/ newArgs = new List<Type>();
- 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<TypeVariable>/*!*/ thisBoundVariables,
- List<TypeVariable>/*!*/ 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<TypeVariable>/*!*/ unifiableVariables,
- IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable>! unifiableVariables,
- List<TypeVariable>! thisBoundVariables,
- List<TypeVariable>! thatBoundVariables,
- IDictionary<TypeVariable!, Type!>! 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
- //Contract.Requires(cce.NonNullElements(subst));
- Contract.Ensures(Contract.Result<Type>() != null);
- if (subst.Count == 0)
- return this;
- List<Type> newArgs = new List<Type>();
- 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<TypeVariable> 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<Type> 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<Type>() != null);
- List<Type> resolvedArgs = new List<Type>();
- foreach (Type/*!*/ t in Arguments) {
- Contract.Assert(t != null);
- resolvedArgs.Add(t.ResolveType(rc));
- }
- return new CtorType(tok, Decl, resolvedArgs);
- }
-
- public override List<TypeVariable>/*!*/ FreeVariables {
- get {
- List<TypeVariable>/*!*/ res = new List<TypeVariable>();
- foreach (Type/*!*/ t in Arguments.ToArray()) {
- Contract.Assert(t != null);
- res.AppendWithoutDups(t.FreeVariables);
- }
- return res;
- }
- }
-
- public override List<TypeProxy/*!*/>/*!*/ FreeProxies {
- get {
- List<TypeProxy/*!*/>/*!*/ res = new List<TypeProxy/*!*/>();
- 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<Absy>() != 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<TypeVariable>/*!*/ TypeParameters;
- public readonly List<Type>/*!*/ Arguments;
- public Type/*!*/ Result;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(TypeParameters != null);
- Contract.Invariant(Arguments != null);
- Contract.Invariant(Result != null);
- }
-
-
- public MapType(IToken/*!*/ token, List<TypeVariable>/*!*/ typeParameters, List<Type>/*!*/ 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
- //Contract.Requires(cce.NonNullElements(varMap));
- Contract.Ensures(Contract.Result<Type>() != null);
- IDictionary<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ newVarMap =
- new Dictionary<TypeVariable/*!*/, TypeVariable/*!*/>();
- foreach (KeyValuePair<TypeVariable/*!*/, TypeVariable/*!*/> p in varMap) {
- Contract.Assert(cce.NonNullElements(p));
- if (!TypeParameters.Contains(p.Key))
- newVarMap.Add(p);
- }
-
- List<TypeVariable>/*!*/ newTypeParams = new List<TypeVariable>();
- 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<Type>/*!*/ newArgs = new List<Type>();
- 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<Type>() != null);
- List<TypeVariable>/*!*/ newTypeParams = new List<TypeVariable>();
- 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<Type>/*!*/ newArgs = new List<Type>();
- 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<TypeVariable>/*!*/ thisBoundVariables,
- List<TypeVariable>/*!*/ 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<TypeVariable>/*!*/ unifiableVariables,
- IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst0 =
- new Dictionary<TypeVariable/*!*/, Type/*!*/>();
- Dictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ subst1 =
- new Dictionary<TypeVariable/*!*/, Type/*!*/>();
- List<TypeVariable> freshies = new List<TypeVariable>();
- 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<TypeVariable> 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<TypeVariable/*!*/, Type/*!*/> 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<TypeVariable>! unifiableVariables,
- List<TypeVariable>! thisBoundVariables,
- List<TypeVariable>! thatBoundVariables,
- IDictionary<TypeVariable!, Type!>! 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<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
- //Contract.Requires(cce.NonNullElements(subst));
- Contract.Ensures(Contract.Result<Type>() != 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<Type> newArgs = new List<Type>();
- 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<TypeVariable> 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<Type>() != null);
- int previousState = rc.TypeBinderState;
- try {
- foreach (TypeVariable/*!*/ v in TypeParameters) {
- Contract.Assert(v != null);
- rc.AddTypeBinder(v);
- }
-
- List<Type> resolvedArgs = new List<Type>();
- foreach (Type/*!*/ ty in Arguments) {
- Contract.Assert(ty != null);
- resolvedArgs.Add(ty.ResolveType(rc));
- }
-
- Type resolvedResult = Result.ResolveType(rc);
-
- CheckBoundVariableOccurrences(TypeParameters,
- resolvedArgs, new List<Type> { resolvedResult },
- this.tok, "map arguments",
- rc);
-
- // sort the type parameters so that they are bound in the order of occurrence
- List<TypeVariable>/*!*/ sortedTypeParams = SortTypeParams(TypeParameters, resolvedArgs, resolvedResult);
- Contract.Assert(sortedTypeParams != null);
- return new MapType(tok, sortedTypeParams, resolvedArgs, resolvedResult);
- } finally {
- rc.TypeBinderState = previousState;
- }
- }
-
- public override List<TypeVariable>/*!*/ FreeVariables {
- get {
- List<TypeVariable>/*!*/ 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<TypeProxy/*!*/>/*!*/ FreeProxies {
- get {
- List<TypeProxy/*!*/>/*!*/ res = new List<TypeProxy/*!*//*!*/>();
- 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<Expr>/*!*/ 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<Type/*!*/>/*!*/ actualTypeParams;
- List<Type> actualResult =
- Type.CheckArgumentTypes(TypeParameters, out actualTypeParams, Arguments, actualArgs,
- new List<Type> { 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<Absy>() != 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<TypeVariable/*!*/>/*!*/ 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<TypeVariable> FormalTypeParams {
-
- get {
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeVariable>>()));
- throw new NotImplementedException();
- }
- }
-
- public Type this[TypeVariable var] {
- get {
- Contract.Requires(var != null);
- Contract.Ensures(Contract.Result<Type>() != null);
-
- throw new NotImplementedException();
- }
- }
-
- #endregion
- }
-
-
- public class SimpleTypeParamInstantiation : TypeParamInstantiation {
- private readonly List<TypeVariable/*!*/>/*!*/ TypeParams;
- [ContractInvariantMethod]
- void TypeParamsInvariantMethod() {
- Contract.Invariant(cce.NonNullElements(TypeParams));
- }
- private readonly IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ Instantiations;
- [ContractInvariantMethod]
- void InstantiationsInvariantMethod() {
- Contract.Invariant(cce.NonNullDictionaryAndValues(Instantiations));
- }
-
- public SimpleTypeParamInstantiation(List<TypeVariable/*!*/>/*!*/ typeParams,
- IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ instantiations) {
- Contract.Requires(cce.NonNullElements(typeParams));
- Contract.Requires(cce.NonNullDictionaryAndValues(instantiations));
- this.TypeParams = typeParams;
- this.Instantiations = instantiations;
- }
-
- public static TypeParamInstantiation/*!*/ From(List<TypeVariable> typeParams, List<Type/*!*/>/*!*/ actualTypeParams) {
- Contract.Requires(cce.NonNullElements(actualTypeParams));
- Contract.Requires(typeParams != null);
- Contract.Requires(typeParams.Count == actualTypeParams.Count);
- Contract.Ensures(Contract.Result<TypeParamInstantiation>() != null);
-
- if (typeParams.Count == 0)
- return EMPTY;
-
- List<TypeVariable/*!*/>/*!*/ typeParamList = new List<TypeVariable/*!*/>();
- IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ dict = new Dictionary<TypeVariable/*!*/, Type/*!*/>();
- 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<TypeVariable/*!*/>(),
- new Dictionary<TypeVariable/*!*/, Type/*!*/>());
-
- // return what formal type parameters there are
- public List<TypeVariable/*!*/>/*!*/ FormalTypeParams {
- get {
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeVariable>>()));
- 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<Type>/*!*/ 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<TypeVariable/*!*/, Type/*!*/> 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<Type>/*!*/ argumentsResult) {
- Contract.Requires(proxy != null);
- Contract.Requires(argumentsResult != null);
- this.Proxy = proxy;
- this.ArgumentsResult = argumentsResult;
- }
-
- // return what formal type parameters there are
- public List<TypeVariable/*!*/>/*!*/ 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<TypeVariable/*!*/>();
- 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<Type>/*!*/ formalArgs = new List<Type>();
- 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<Absy>() != null);
+ return this.Clone(new Dictionary<TypeVariable/*!*/, TypeVariable/*!*/>());
+ }
+
+ public abstract Type/*!*/ Clone(IDictionary<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap);
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ 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<string>() != null);
+ System.IO.StringWriter buffer = new System.IO.StringWriter();
+ using (TokenTextWriter stream = new TokenTextWriter("<buffer>", 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<TypeVariable>(),
+ new List<TypeVariable>());
+ }
+
+ [Pure]
+ public abstract bool Equals(Type/*!*/ that,
+ List<TypeVariable>/*!*/ thisBoundVariables,
+ List<TypeVariable>/*!*/ 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<Type>() != null);
+
+ return this;
+ }
+ }
+
+ //----------- Unification of types -----------
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public bool Unify(Type that) {
+ Contract.Requires(that != null);
+ return Unify(that, new List<TypeVariable>(), new Dictionary<TypeVariable/*!*/, Type/*!*/>());
+ }
+
+ public abstract bool Unify(Type/*!*/ that,
+ List<TypeVariable>/*!*/ unifiableVariables,
+ // an idempotent substitution that describes the
+ // unification result up to a certain point
+ IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ unifier);
+
+
+ [Pure]
+ public static bool IsIdempotent(IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable!, Type!> Unify(Type! that,
+ List<TypeVariable>! unifiableVariables) {
+ Dictionary<TypeVariable!, Type!>! result = new Dictionary<TypeVariable!, Type!> ();
+ try {
+ this.Unify(that, unifiableVariables,
+ new List<TypeVariable> (), new List<TypeVariable> (), 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<TypeVariable>! unifiableVariables,
+ // given mappings that need to be taken into account
+ // the old unifier has to be idempotent as well
+ IDictionary<TypeVariable!, Type!>! unifier)
+ {
+ Contract.Requires(Contract.ForAll(unifier.Keys , key=> unifiableVariables.Has(key)));
+ Contract.Requires(IsIdempotent(unifier));
+ try {
+ this.Unify(that, unifiableVariables,
+ new List<TypeVariable> (), new List<TypeVariable> (), unifier);
+ } catch (UnificationFailedException) {
+ return false;
+ }
+ return true;
+ }
+
+ public abstract void Unify(Type! that,
+ List<TypeVariable>! unifiableVariables,
+ List<TypeVariable>! thisBoundVariables,
+ List<TypeVariable>! thatBoundVariables,
+ // an idempotent substitution that describes the
+ // unification result up to a certain point
+ IDictionary<TypeVariable!, Type!>! result);
+#endif
+
+ //----------- Substitution of free variables with types not containing bound variables -----------------
+
+ public abstract Type/*!*/ Substitute(IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable>());
+ }
+
+ [Pure]
+ public abstract int GetHashCode(List<TypeVariable>/*!*/ 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<TypeVariable>/*!*/ FreeVariables {
+ get;
+ }
+
+ // determine the free type proxies in a type, in the order in which they occur
+ public abstract List<TypeProxy/*!*/>/*!*/ FreeProxies {
+ get;
+ }
+
+ protected static void AppendWithoutDups<A>(List<A> a, List<A> 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<TypeVariable>() != 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<CtorType>() != 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<MapType>() != 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<UnresolvedTypeIdentifier>() != 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<BvType>() != 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<FloatType>() != 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<TypeVariable!, Type!>!
+ MatchArgumentTypes(List<TypeVariable>! typeParams,
+ List<Type>! formalArgs,
+ List<Expr>! actualArgs,
+ List<Type> formalOuts,
+ List<IdentifierExpr> 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<TypeVariable>! boundVarSeq0 = new List<TypeVariable> ();
+ List<TypeVariable>! boundVarSeq1 = new List<TypeVariable> ();
+ Dictionary<TypeVariable!, Type!>! subst = new Dictionary<TypeVariable!, Type!>();
+
+ 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<TypeVariable/*!*/, Type/*!*/>/*!*/
+ MatchArgumentTypes(List<TypeVariable>/*!*/ typeParams,
+ List<Type>/*!*/ formalArgs,
+ IList<Expr>/*!*/ actualArgs,
+ List<Type> formalOuts,
+ List<IdentifierExpr> 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<IDictionary<TypeVariable, Type>>()));
+
+ // requires "actualArgs" and "actualOuts" to have been type checked
+
+ Dictionary<TypeVariable/*!*/, Type/*!*/> subst = new Dictionary<TypeVariable/*!*/, Type/*!*/>();
+ 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<Type> CheckArgumentTypes(List<TypeVariable>/*!*/ typeParams,
+ out List<Type/*!*/>/*!*/ actualTypeParams,
+ List<Type>/*!*/ formalIns,
+ IList<Expr>/*!*/ actualIns,
+ List<Type>/*!*/ formalOuts,
+ List<IdentifierExpr> 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<Type/*!*/>();
+
+ 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<Type>();
+ return typeParams.Count == 0 ? formalOuts : null;
+ }
+
+ int previousErrorCount = tc.ErrorCount;
+ IDictionary<TypeVariable/*!*/, Type/*!*/> 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<Type>/*!*/ actualResults = new List<Type>();
+ foreach (Type/*!*/ t in formalOuts) {
+ Contract.Assert(t != null);
+ actualResults.Add(t.Substitute(subst));
+ }
+ List<TypeVariable> 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<TypeVariable>/*!*/ typeParams,
+ List<Type>/*!*/ formalArgs,
+ Type/*!*/ formalResult,
+ List<Type>/*!*/ actualArgs) {
+ Contract.Requires(typeParams != null);
+ Contract.Requires(formalArgs != null);
+ Contract.Requires(formalResult != null);
+ Contract.Requires(actualArgs != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+
+ IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable>/*!*/ 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<TypeVariable!, Type!>!
+ InferTypeParameters(List<TypeVariable>! typeParams,
+ List<Type>! formalArgs,
+ List<Type>! actualArgs)
+ {
+ Contract.Requires(formalArgs.Length == actualArgs.Length);
+
+ List<TypeVariable>! boundVarSeq0 = new List<TypeVariable> ();
+ List<TypeVariable>! boundVarSeq1 = new List<TypeVariable> ();
+ Dictionary<TypeVariable!, Type!>! subst = new Dictionary<TypeVariable!, Type!>();
+
+ 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
+ /// <summary>
+ /// like Type.CheckArgumentTypes, but assumes no errors
+ /// (and only does arguments, not results; and takes actuals as List<Type>, not List<Expr>)
+ /// </summary>
+ public static IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/
+ InferTypeParameters(List<TypeVariable>/*!*/ typeParams,
+ List<Type>/*!*/ formalArgs,
+ List<Type>/*!*/ 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<IDictionary<TypeVariable, Type>>()));
+
+
+ List<Type> proxies = new List<Type>();
+ Dictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ subst = new Dictionary<TypeVariable/*!*/, Type/*!*/>();
+ 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<TypeVariable> 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<TypeVariable>/*!*/ SortTypeParams(List<TypeVariable>/*!*/ typeParams, List<Type>/*!*/ argumentTypes, Type resultType) {
+ Contract.Requires(typeParams != null);
+ Contract.Requires(argumentTypes != null);
+ Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
+
+ Contract.Ensures(Contract.Result<List<TypeVariable>>().Count == typeParams.Count);
+ if (typeParams.Count == 0) {
+ return typeParams;
+ }
+
+ List<TypeVariable> 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<TypeVariable> sortedTypeParams = new List<TypeVariable>();
+ 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<TypeVariable>/*!*/ typeParams,
+ List<Type>/*!*/ argumentTypes,
+ List<Type> 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<TypeVariable> freeVarsInArgs = FreeVariablesIn(argumentTypes);
+ List<TypeVariable> 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<TypeVariable> FreeVariablesIn(List<Type> arguments) {
+ Contract.Requires(arguments != null);
+ Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
+ List<TypeVariable>/*!*/ res = new List<TypeVariable>();
+ 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<TypeProxy> FreeProxies {
+ get {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeProxy>>()));
+ throw new NotImplementedException();
+ }
+ }
+ public override List<TypeVariable> FreeVariables {
+ get {
+ Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
+ throw new NotImplementedException();
+ }
+ }
+ public override Type Clone(IDictionary<TypeVariable, TypeVariable> varMap) {
+ Contract.Requires(cce.NonNullDictionaryAndValues(varMap));
+ Contract.Ensures(Contract.Result<Type>() != null);
+
+ throw new NotImplementedException();
+ }
+ public override Type CloneUnresolved() {
+ Contract.Ensures(Contract.Result<Type>() != 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<TypeVariable> thisBoundVariables, List<TypeVariable> thatBoundVariables) {
+ Contract.Requires(that != null);
+ Contract.Requires(thisBoundVariables != null);
+ Contract.Requires(thatBoundVariables != null);
+ throw new NotImplementedException();
+ }
+ public override bool Unify(Type that, List<TypeVariable> unifiableVariables, IDictionary<TypeVariable, Type> 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<TypeVariable, Type> subst) {
+ Contract.Requires(cce.NonNullDictionaryAndValues(subst));
+ Contract.Ensures(Contract.Result<Type>() != null);
+
+ throw new NotImplementedException();
+ }
+ public override Type ResolveType(ResolutionContext rc) {
+ Contract.Requires(rc != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+
+ throw new NotImplementedException();
+ }
+ public override int GetHashCode(List<TypeVariable> 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
+ //Contract.Requires(cce.NonNullElements(varMap));
+ Contract.Ensures(Contract.Result<Type>() != null);
+ // BasicTypes are immutable anyway, we do not clone
+ return this;
+ }
+
+ public override Type CloneUnresolved() {
+ Contract.Ensures(Contract.Result<Type>() != 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<string>() != 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<TypeVariable> thisBoundVariables, List<TypeVariable> 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<TypeVariable> unifiableVariables, IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable>! unifiableVariables,
+ List<TypeVariable>! thisBoundVariables,
+ List<TypeVariable>! thatBoundVariables,
+ IDictionary<TypeVariable!, Type!>! 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
+ //Contract.Requires(cce.NonNullElements(subst));
+ Contract.Ensures(Contract.Result<Type>() != null);
+ return this;
+ }
+
+ //----------- Hashcodes ----------------------------------
+
+ [Pure]
+ public override int GetHashCode(List<TypeVariable> boundVariables) {
+ //Contract.Requires(boundVariables != null);
+ return this.T.GetHashCode();
+ }
+
+ //----------- Resolution ----------------------------------
+
+ public override Type ResolveType(ResolutionContext rc) {
+ //Contract.Requires(rc != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ // nothing to resolve
+ return this;
+ }
+
+ // determine the free variables in a type, in the order in which the variables occur
+ public override List<TypeVariable>/*!*/ FreeVariables {
+ get {
+ Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
+
+ return new List<TypeVariable>(); // basic type are closed
+ }
+ }
+
+ public override List<TypeProxy/*!*/>/*!*/ FreeProxies {
+ get {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeProxy>>()));
+ return new List<TypeProxy/*!*/>();
+ }
+ }
+
+ //----------- 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<Absy>() != 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap)
+ {
+ //Contract.Requires(cce.NonNullElements(varMap));
+ Contract.Ensures(Contract.Result<Type>() != null);
+ // FloatTypes are immutable anyway, we do not clone
+ return this;
+ }
+
+ public override Type CloneUnresolved()
+ {
+ Contract.Ensures(Contract.Result<Type>() != 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<string>() != null);
+ return "float (" + Exponent + " " + Mantissa + ")";
+ }
+
+ //----------- Equality ----------------------------------
+
+ [Pure]
+ public override bool Equals(Type/*!*/ that,
+ List<TypeVariable>/*!*/ thisBoundVariables,
+ List<TypeVariable>/*!*/ 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<TypeVariable>/*!*/ unifiableVariables,
+ // an idempotent substitution that describes the
+ // unification result up to a certain point
+ IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst)
+ {
+ Contract.Ensures(Contract.Result<Type>() != null);
+ return this;
+ }
+
+ //----------- Hashcodes ----------------------------------
+
+ [Pure]
+ public override int GetHashCode(List<TypeVariable> boundVariables)
+ {
+ return this.Mantissa.GetHashCode() + this.Exponent.GetHashCode();
+ }
+
+ //----------- Resolution ----------------------------------
+
+ public override Type ResolveType(ResolutionContext rc)
+ {
+ //Contract.Requires(rc != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ // nothing to resolve
+ return this;
+ }
+
+ // determine the free variables in a type, in the order in which the variables occur
+ public override List<TypeVariable>/*!*/ FreeVariables
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
+
+ return new List<TypeVariable>(); // bitvector-type are closed
+ }
+ }
+
+ public override List<TypeProxy/*!*/>/*!*/ FreeProxies
+ {
+ get
+ {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeProxy>>()));
+ return new List<TypeProxy/*!*/>();
+ }
+ }
+
+ //----------- 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<Absy>() != 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
+ //Contract.Requires(cce.NonNullElements(varMap));
+ Contract.Ensures(Contract.Result<Type>() != null);
+ // BvTypes are immutable anyway, we do not clone
+ return this;
+ }
+
+ public override Type CloneUnresolved() {
+ Contract.Ensures(Contract.Result<Type>() != 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<string>() != null);
+ return "bv" + Bits;
+ }
+
+ //----------- Equality ----------------------------------
+
+ [Pure]
+ public override bool Equals(Type/*!*/ that,
+ List<TypeVariable>/*!*/ thisBoundVariables,
+ List<TypeVariable>/*!*/ 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<TypeVariable>/*!*/ unifiableVariables,
+ // an idempotent substitution that describes the
+ // unification result up to a certain point
+ IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable>! unifiableVariables,
+ List<TypeVariable>! thisBoundVariables,
+ List<TypeVariable>! thatBoundVariables,
+ IDictionary<TypeVariable!, Type!> 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
+ //Contract.Requires(cce.NonNullElements(subst));
+ Contract.Ensures(Contract.Result<Type>() != null);
+ return this;
+ }
+
+ //----------- Hashcodes ----------------------------------
+
+ [Pure]
+ public override int GetHashCode(List<TypeVariable> boundVariables) {
+ //Contract.Requires(boundVariables != null);
+ return this.Bits.GetHashCode();
+ }
+
+ //----------- Resolution ----------------------------------
+
+ public override Type ResolveType(ResolutionContext rc) {
+ //Contract.Requires(rc != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ // nothing to resolve
+ return this;
+ }
+
+ // determine the free variables in a type, in the order in which the variables occur
+ public override List<TypeVariable>/*!*/ FreeVariables {
+ get {
+ Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
+
+ return new List<TypeVariable>(); // bitvector-type are closed
+ }
+ }
+
+ public override List<TypeProxy/*!*/>/*!*/ FreeProxies {
+ get {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeProxy>>()));
+ return new List<TypeProxy/*!*/>();
+ }
+ }
+
+ //----------- 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<Absy>() != 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<Type>/*!*/ Arguments;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(Name != null);
+ Contract.Invariant(Arguments != null);
+ }
+
+
+ public UnresolvedTypeIdentifier(IToken token, string name)
+ : this(token, name, new List<Type>()) {
+ Contract.Requires(name != null);
+ Contract.Requires(token != null);
+ }
+
+ public UnresolvedTypeIdentifier(IToken token, string name, List<Type> 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
+ //Contract.Requires(cce.NonNullElements(varMap));
+ Contract.Ensures(Contract.Result<Type>() != null);
+ List<Type>/*!*/ newArgs = new List<Type>();
+ 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<Type>() != null);
+ List<Type>/*!*/ newArgs = new List<Type>();
+ 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<TypeVariable>/*!*/ thisBoundVariables,
+ List<TypeVariable>/*!*/ 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<TypeVariable>/*!*/ unifiableVariables,
+ IDictionary<TypeVariable/*!*/, Type/*!*/> 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<TypeVariable>! unifiableVariables,
+ List<TypeVariable>! thisBoundVariables,
+ List<TypeVariable>! thatBoundVariables,
+ IDictionary<TypeVariable!, Type!> 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
+ //Contract.Requires(cce.NonNullElements(subst));
+ Contract.Ensures(Contract.Result<Type>() != null);
+ {
+ Contract.Assert(false);
+ throw new cce.UnreachableException();
+ } // UnresolvedTypeIdentifier.Substitute should never be called
+ }
+
+ //----------- Hashcodes ----------------------------------
+
+ [Pure]
+ public override int GetHashCode(List<TypeVariable> 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<Type>() != 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<Type>/*!*/ 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<Type> ResolveArguments(ResolutionContext rc) {
+ Contract.Requires(rc != null);
+ Contract.Ensures(Contract.Result<List<Type>>() != null);
+ List<Type>/*!*/ resolvedArgs = new List<Type>();
+ foreach (Type/*!*/ t in Arguments) {
+ Contract.Assert(t != null);
+ resolvedArgs.Add(t.ResolveType(rc));
+ }
+ return resolvedArgs;
+ }
+
+ public override List<TypeVariable>/*!*/ FreeVariables {
+ get {
+ Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
+
+ return new List<TypeVariable>();
+ }
+ }
+
+ public override List<TypeProxy/*!*/>/*!*/ FreeProxies {
+ get {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeProxy>>()));
+ return new List<TypeProxy/*!*/>();
+ }
+ }
+
+ //----------- 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<UnresolvedTypeIdentifier>() != null);
+ return this;
+ }
+ }
+
+ public override Absy StdDispatch(StandardVisitor visitor) {
+ //Contract.Requires(visitor != null);
+ Contract.Ensures(Contract.Result<Absy>() != 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
+ //Contract.Requires(cce.NonNullElements(varMap));
+ Contract.Ensures(Contract.Result<Type>() != 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<Type>() != null);
+ return this;
+ }
+
+ //----------- Equality ----------------------------------
+
+ [Pure]
+ public override bool Equals(Type that,
+ List<TypeVariable>/*!*/ thisBoundVariables,
+ List<TypeVariable>/*!*/ 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<TypeVariable>/*!*/ unifiableVariables,
+ // an idempotent substitution that describes the
+ // unification result up to a certain point
+ IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable/*!*/, Type/*!*/>/*!*/ newMapping = new Dictionary<TypeVariable/*!*/, Type/*!*/>();
+ // 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<TypeVariable/*!*/>/*!*/ keys = new List<TypeVariable/*!*/>();
+ 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<TypeVariable>! unifiableVariables,
+ List<TypeVariable>! thisBoundVariables,
+ List<TypeVariable>! thatBoundVariables,
+ IDictionary<TypeVariable!, Type!> 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<TypeVariable>! 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
+ //Contract.Requires(cce.NonNullElements(subst));
+ Contract.Ensures(Contract.Result<Type>() != 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<TypeVariable> 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<Type>() != null);
+ // nothing to resolve
+ return this;
+ }
+
+ public override List<TypeVariable>/*!*/ FreeVariables {
+ get {
+ Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
+ return new List<TypeVariable> { this };
+ }
+ }
+
+ public override List<TypeProxy/*!*/>/*!*/ FreeProxies {
+ get {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeProxy>>()));
+ return new List<TypeProxy/*!*/>();
+ }
+ }
+
+ //----------- Getters/Issers ----------------------------------
+
+ public override bool IsVariable {
+ get {
+ return true;
+ }
+ }
+ public override TypeVariable/*!*/ AsVariable {
+ get {
+ Contract.Ensures(Contract.Result<TypeVariable>() != null);
+ return this;
+ }
+ }
+
+ public override Absy StdDispatch(StandardVisitor visitor) {
+ //Contract.Requires(visitor != null);
+ //Contract.Ensures(Contract.Result<Absy>() != 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<Type>() != null);
+ Contract.Ensures(!(Contract.Result<Type>() is TypeProxy) || ((TypeProxy)Contract.Result<Type>()).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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
+ //Contract.Requires(cce.NonNullElements(varMap));
+ Contract.Ensures(Contract.Result<Type>() != 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<n>$proxy<m>
+ }
+ }
+
+ public override Type CloneUnresolved() {
+ Contract.Ensures(Contract.Result<Type>() != null);
+ return new TypeProxy(this.tok, this.Name); // the clone will have a name that ends with $proxy<n>$proxy<m>
+ }
+
+ //----------- Equality ----------------------------------
+
+ [Pure]
+ public override bool Equals(Type that,
+ List<TypeVariable>/*!*/ thisBoundVariables,
+ List<TypeVariable>/*!*/ 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<TypeVariable>/*!*/ unifiableVariables,
+ IDictionary<TypeVariable/*!*/, Type/*!*/> 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
+ //Contract.Requires(cce.NonNullElements(subst));
+ Contract.Ensures(Contract.Result<Type>() != null);
+ Type p = ProxyFor;
+ if (p != null) {
+ return p.Substitute(subst);
+ } else {
+ return this;
+ }
+ }
+
+ //----------- Hashcodes ----------------------------------
+
+ [Pure]
+ public override int GetHashCode(List<TypeVariable> 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<Type>() != null);
+ Type p = ProxyFor;
+ if (p != null) {
+ return p.ResolveType(rc);
+ } else {
+ return this;
+ }
+ }
+
+ public override List<TypeVariable>/*!*/ FreeVariables {
+ get {
+ Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
+
+ Type p = ProxyFor;
+ if (p != null) {
+ return p.FreeVariables;
+ } else {
+ return new List<TypeVariable>();
+ }
+ }
+ }
+
+ public override List<TypeProxy/*!*/>/*!*/ FreeProxies {
+ get {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeProxy>>()));
+ Type p = ProxyFor;
+ if (p != null) {
+ return p.FreeProxies;
+ } else {
+ List<TypeProxy/*!*/>/*!*/ res = new List<TypeProxy/*!*/>();
+ 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<TypeVariable>() != 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<CtorType>() != 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<MapType>() != 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<UnresolvedTypeIdentifier>() != 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<Absy>() != 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);
+ }
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public class BvTypeProxy : ConstrainedProxy {
+ public int MinBits;
+ List<BvTypeConstraint/*!*/> 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;
+ }
+
+ /// <summary>
+ /// Requires that any further constraints to be placed on t0 and t1 go via the object to
+ /// be constructed.
+ /// </summary>
+ 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<BvTypeConstraint/*!*/> list = new List<BvTypeConstraint/*!*/>();
+ list.Add(new BvTypeConstraint(t0, t1));
+ this.constraints = list;
+ }
+
+ /// <summary>
+ /// Construct a BvTypeProxy like p, but with minBits.
+ /// </summary>
+ 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<BvTypeConstraint/*!*/> 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<int>());
+
+ 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
+ //Contract.Requires(cce.NonNullElements(varMap));
+ Contract.Ensures(Contract.Result<Type>() != 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<n>$bvproxy<m>
+ }
+ }
+
+ public override Type CloneUnresolved() {
+ Contract.Ensures(Contract.Result<Type>() != null);
+ return new BvTypeProxy(this.tok, this.Name, this.MinBits, this.constraints); // the clone will have a name that ends with $bvproxy<n>$bvproxy<m>
+ }
+
+ //----------- Unification of types -----------
+
+ public override bool Unify(Type that,
+ List<TypeVariable> unifiableVariables,
+ IDictionary<TypeVariable, Type> 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<BvTypeConstraint/*!*/> list = new List<BvTypeConstraint/*!*/>();
+ 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<int>() && Contract.Result<int>() <= 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
+ //Contract.Requires(cce.NonNullElements(subst));
+ Contract.Ensures(Contract.Result<Type>() != 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<Absy>() != 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<Constraint>/*!*/ constraints = new List<Constraint>();
+ [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<Type>/*!*/ Arguments;
+ public readonly Type/*!*/ Result;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(Arguments != null);
+ Contract.Invariant(Result != null);
+ }
+
+
+ public Constraint(List<Type> arguments, Type result) {
+ Contract.Requires(result != null);
+ Contract.Requires(arguments != null);
+ Arguments = arguments;
+ Result = result;
+ }
+
+ public Constraint Clone(IDictionary<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
+ Contract.Requires(cce.NonNullDictionaryAndValues(varMap));
+ List<Type>/*!*/ args = new List<Type>();
+ 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<TypeVariable>/*!*/ unifiableVariables,
+ IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ result) {
+ Contract.Requires(unifiableVariables != null);
+ Contract.Requires(cce.NonNullDictionaryAndValues(result));
+ Contract.Requires(that != null);
+ Contract.Requires(Arguments.Count == that.Arguments.Count);
+ Dictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ subst = new Dictionary<TypeVariable/*!*/, Type/*!*/>();
+ 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<TypeVariable>(), new Dictionary<TypeVariable/*!*/, Type/*!*/>());
+ 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<Expr>/*!*/ 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<Type>/*!*/ arguments = new List<Type>();
+ 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<Type>/*!*/ argumentsResult = new List<Type>();
+ 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
+ //Contract.Requires(cce.NonNullElements(varMap));
+ Contract.Ensures(Contract.Result<Type>() != 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<n>$mapproxy<m> (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<TypeVariable>/*!*/ unifiableVariables,
+ IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
+ //Contract.Requires(cce.NonNullElements(subst));
+ Contract.Ensures(Contract.Result<Type>() != 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<MapType>() != 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<Absy>() != 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<Type>/*!*/ 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<Type>/*!*/ 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst =
+ new Dictionary<TypeVariable/*!*/, Type/*!*/>();
+ 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<Type>/*!*/ 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
+ //Contract.Requires(cce.NonNullElements(varMap));
+ Contract.Ensures(Contract.Result<Type>() != null);
+ List<Type>/*!*/ newArgs = new List<Type>();
+ 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<Type>() != null);
+ List<Type>/*!*/ newArgs = new List<Type>();
+ 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<TypeVariable>/*!*/ thisBoundVariables,
+ List<TypeVariable>/*!*/ 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<Type>() != null);
+
+ return ExpandedType.Expanded;
+ }
+ }
+
+ //----------- Unification of types -----------
+
+ public override bool Unify(Type/*!*/ that,
+ List<TypeVariable>/*!*/ unifiableVariables,
+ IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable>! unifiableVariables,
+ List<TypeVariable>! thisBoundVariables,
+ List<TypeVariable>! thatBoundVariables,
+ IDictionary<TypeVariable!, Type!>! result) {
+ ExpandedType.Unify(that, unifiableVariables,
+ thisBoundVariables, thatBoundVariables, result);
+ }
+#endif
+
+ //----------- Substitution of free variables with types not containing bound variables -----------------
+
+ public override Type Substitute(IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
+ //Contract.Requires(cce.NonNullElements(subst));
+ Contract.Ensures(Contract.Result<Type>() != null);
+ if (subst.Count == 0)
+ return this;
+ List<Type> newArgs = new List<Type>();
+ 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<TypeVariable> 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<Type>() != null);
+ List<Type> resolvedArgs = new List<Type>();
+ foreach (Type/*!*/ t in Arguments) {
+ Contract.Assert(t != null);
+ resolvedArgs.Add(t.ResolveType(rc));
+ }
+ return new TypeSynonymAnnotation(tok, Decl, resolvedArgs);
+ }
+
+ public override List<TypeVariable>/*!*/ FreeVariables {
+ get {
+ Contract.Ensures(Contract.Result<List<TypeVariable>>() != null);
+
+ return ExpandedType.FreeVariables;
+ }
+ }
+
+ public override List<TypeProxy/*!*/>/*!*/ FreeProxies {
+ get {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeProxy>>()));
+ 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<TypeVariable>() != null);
+ return ExpandedType.AsVariable;
+ }
+ }
+ public override bool IsCtor {
+ get {
+ return ExpandedType.IsCtor;
+ }
+ }
+ public override CtorType/*!*/ AsCtor {
+ get {
+ Contract.Ensures(Contract.Result<CtorType>() != null);
+ return ExpandedType.AsCtor;
+ }
+ }
+ public override bool IsMap {
+ get {
+ return ExpandedType.IsMap;
+ }
+ }
+ public override MapType/*!*/ AsMap {
+ get {
+ Contract.Ensures(Contract.Result<MapType>() != null);
+ return ExpandedType.AsMap;
+ }
+ }
+ public override bool IsUnresolved {
+ get {
+ return ExpandedType.IsUnresolved;
+ }
+ }
+ public override UnresolvedTypeIdentifier/*!*/ AsUnresolved {
+ get {
+ Contract.Ensures(Contract.Result<UnresolvedTypeIdentifier>() != 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<Absy>() != null);
+ return visitor.VisitTypeSynonymAnnotation(this);
+ }
+ }
+
+ //=====================================================================
+
+ public class CtorType : Type {
+ public readonly List<Type>/*!*/ 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<Type>/*!*/ 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
+ //Contract.Requires(cce.NonNullElements(varMap));
+ Contract.Ensures(Contract.Result<Type>() != null);
+ List<Type>/*!*/ newArgs = new List<Type>();
+ 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<Type>() != null);
+ List<Type>/*!*/ newArgs = new List<Type>();
+ 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<TypeVariable>/*!*/ thisBoundVariables,
+ List<TypeVariable>/*!*/ 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<TypeVariable>/*!*/ unifiableVariables,
+ IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable>! unifiableVariables,
+ List<TypeVariable>! thisBoundVariables,
+ List<TypeVariable>! thatBoundVariables,
+ IDictionary<TypeVariable!, Type!>! 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
+ //Contract.Requires(cce.NonNullElements(subst));
+ Contract.Ensures(Contract.Result<Type>() != null);
+ if (subst.Count == 0)
+ return this;
+ List<Type> newArgs = new List<Type>();
+ 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<TypeVariable> 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<Type> 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<Type>() != null);
+ List<Type> resolvedArgs = new List<Type>();
+ foreach (Type/*!*/ t in Arguments) {
+ Contract.Assert(t != null);
+ resolvedArgs.Add(t.ResolveType(rc));
+ }
+ return new CtorType(tok, Decl, resolvedArgs);
+ }
+
+ public override List<TypeVariable>/*!*/ FreeVariables {
+ get {
+ List<TypeVariable>/*!*/ res = new List<TypeVariable>();
+ foreach (Type/*!*/ t in Arguments.ToArray()) {
+ Contract.Assert(t != null);
+ res.AppendWithoutDups(t.FreeVariables);
+ }
+ return res;
+ }
+ }
+
+ public override List<TypeProxy/*!*/>/*!*/ FreeProxies {
+ get {
+ List<TypeProxy/*!*/>/*!*/ res = new List<TypeProxy/*!*/>();
+ 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<Absy>() != 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<TypeVariable>/*!*/ TypeParameters;
+ public readonly List<Type>/*!*/ Arguments;
+ public Type/*!*/ Result;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(TypeParameters != null);
+ Contract.Invariant(Arguments != null);
+ Contract.Invariant(Result != null);
+ }
+
+
+ public MapType(IToken/*!*/ token, List<TypeVariable>/*!*/ typeParameters, List<Type>/*!*/ 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<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ varMap) {
+ //Contract.Requires(cce.NonNullElements(varMap));
+ Contract.Ensures(Contract.Result<Type>() != null);
+ IDictionary<TypeVariable/*!*/, TypeVariable/*!*/>/*!*/ newVarMap =
+ new Dictionary<TypeVariable/*!*/, TypeVariable/*!*/>();
+ foreach (KeyValuePair<TypeVariable/*!*/, TypeVariable/*!*/> p in varMap) {
+ Contract.Assert(cce.NonNullElements(p));
+ if (!TypeParameters.Contains(p.Key))
+ newVarMap.Add(p);
+ }
+
+ List<TypeVariable>/*!*/ newTypeParams = new List<TypeVariable>();
+ 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<Type>/*!*/ newArgs = new List<Type>();
+ 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<Type>() != null);
+ List<TypeVariable>/*!*/ newTypeParams = new List<TypeVariable>();
+ 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<Type>/*!*/ newArgs = new List<Type>();
+ 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<TypeVariable>/*!*/ thisBoundVariables,
+ List<TypeVariable>/*!*/ 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<TypeVariable>/*!*/ unifiableVariables,
+ IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst0 =
+ new Dictionary<TypeVariable/*!*/, Type/*!*/>();
+ Dictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ subst1 =
+ new Dictionary<TypeVariable/*!*/, Type/*!*/>();
+ List<TypeVariable> freshies = new List<TypeVariable>();
+ 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<TypeVariable> 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<TypeVariable/*!*/, Type/*!*/> 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<TypeVariable>! unifiableVariables,
+ List<TypeVariable>! thisBoundVariables,
+ List<TypeVariable>! thatBoundVariables,
+ IDictionary<TypeVariable!, Type!>! 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<TypeVariable/*!*/, Type/*!*/>/*!*/ 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<TypeVariable/*!*/, Type/*!*/>/*!*/ subst) {
+ //Contract.Requires(cce.NonNullElements(subst));
+ Contract.Ensures(Contract.Result<Type>() != 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<Type> newArgs = new List<Type>();
+ 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<TypeVariable> 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<Type>() != null);
+ int previousState = rc.TypeBinderState;
+ try {
+ foreach (TypeVariable/*!*/ v in TypeParameters) {
+ Contract.Assert(v != null);
+ rc.AddTypeBinder(v);
+ }
+
+ List<Type> resolvedArgs = new List<Type>();
+ foreach (Type/*!*/ ty in Arguments) {
+ Contract.Assert(ty != null);
+ resolvedArgs.Add(ty.ResolveType(rc));
+ }
+
+ Type resolvedResult = Result.ResolveType(rc);
+
+ CheckBoundVariableOccurrences(TypeParameters,
+ resolvedArgs, new List<Type> { resolvedResult },
+ this.tok, "map arguments",
+ rc);
+
+ // sort the type parameters so that they are bound in the order of occurrence
+ List<TypeVariable>/*!*/ sortedTypeParams = SortTypeParams(TypeParameters, resolvedArgs, resolvedResult);
+ Contract.Assert(sortedTypeParams != null);
+ return new MapType(tok, sortedTypeParams, resolvedArgs, resolvedResult);
+ } finally {
+ rc.TypeBinderState = previousState;
+ }
+ }
+
+ public override List<TypeVariable>/*!*/ FreeVariables {
+ get {
+ List<TypeVariable>/*!*/ 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<TypeProxy/*!*/>/*!*/ FreeProxies {
+ get {
+ List<TypeProxy/*!*/>/*!*/ res = new List<TypeProxy/*!*//*!*/>();
+ 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<Expr>/*!*/ 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<Type/*!*/>/*!*/ actualTypeParams;
+ List<Type> actualResult =
+ Type.CheckArgumentTypes(TypeParameters, out actualTypeParams, Arguments, actualArgs,
+ new List<Type> { 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<Absy>() != 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<TypeVariable/*!*/>/*!*/ 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<TypeVariable> FormalTypeParams {
+
+ get {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeVariable>>()));
+ throw new NotImplementedException();
+ }
+ }
+
+ public Type this[TypeVariable var] {
+ get {
+ Contract.Requires(var != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+
+ throw new NotImplementedException();
+ }
+ }
+
+ #endregion
+ }
+
+
+ public class SimpleTypeParamInstantiation : TypeParamInstantiation {
+ private readonly List<TypeVariable/*!*/>/*!*/ TypeParams;
+ [ContractInvariantMethod]
+ void TypeParamsInvariantMethod() {
+ Contract.Invariant(cce.NonNullElements(TypeParams));
+ }
+ private readonly IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ Instantiations;
+ [ContractInvariantMethod]
+ void InstantiationsInvariantMethod() {
+ Contract.Invariant(cce.NonNullDictionaryAndValues(Instantiations));
+ }
+
+ public SimpleTypeParamInstantiation(List<TypeVariable/*!*/>/*!*/ typeParams,
+ IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ instantiations) {
+ Contract.Requires(cce.NonNullElements(typeParams));
+ Contract.Requires(cce.NonNullDictionaryAndValues(instantiations));
+ this.TypeParams = typeParams;
+ this.Instantiations = instantiations;
+ }
+
+ public static TypeParamInstantiation/*!*/ From(List<TypeVariable> typeParams, List<Type/*!*/>/*!*/ actualTypeParams) {
+ Contract.Requires(cce.NonNullElements(actualTypeParams));
+ Contract.Requires(typeParams != null);
+ Contract.Requires(typeParams.Count == actualTypeParams.Count);
+ Contract.Ensures(Contract.Result<TypeParamInstantiation>() != null);
+
+ if (typeParams.Count == 0)
+ return EMPTY;
+
+ List<TypeVariable/*!*/>/*!*/ typeParamList = new List<TypeVariable/*!*/>();
+ IDictionary<TypeVariable/*!*/, Type/*!*/>/*!*/ dict = new Dictionary<TypeVariable/*!*/, Type/*!*/>();
+ 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<TypeVariable/*!*/>(),
+ new Dictionary<TypeVariable/*!*/, Type/*!*/>());
+
+ // return what formal type parameters there are
+ public List<TypeVariable/*!*/>/*!*/ FormalTypeParams {
+ get {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<TypeVariable>>()));
+ 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<Type>/*!*/ 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<TypeVariable/*!*/, Type/*!*/> 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<Type>/*!*/ argumentsResult) {
+ Contract.Requires(proxy != null);
+ Contract.Requires(argumentsResult != null);
+ this.Proxy = proxy;
+ this.ArgumentsResult = argumentsResult;
+ }
+
+ // return what formal type parameters there are
+ public List<TypeVariable/*!*/>/*!*/ 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<TypeVariable/*!*/>();
+ 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<Type>/*!*/ formalArgs = new List<Type>();
+ 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<Expr>
- {
- private readonly DeBruijnRenamer deBruijn = new DeBruijnRenamer();
-
- bool IEqualityComparer<Expr>.Equals(Expr x, Expr y) {
- var nx = deBruijn.Rename(x);
- var ny = deBruijn.Rename(y);
- return BinderExpr.EqualWithAttributesAndTriggers(nx, ny);
- }
-
- int IEqualityComparer<Expr>.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<BoundVariable> boundVars =
- new TypeDict<BoundVariable>("bv", ti => new BoundVariable(Token.NoToken, ti));
-
- private readonly TypeDict<FreeVariable> freeVars =
- new TypeDict<FreeVariable>("fv", ti => new FreeVariable(ti));
-
- // These three variables are reset at the beginning of every renaming
- private int boundVarCount, freeVarCount;
- private Dictionary<Variable, FreeVariable> freeVarMap;
-
- // Cached, previous results
- private readonly Dictionary<Expr, Expr> cache = new Dictionary<Expr, Expr>();
-
- public Expr Rename(Expr e) {
- Expr ne;
- if (!cache.TryGetValue(e, out ne)) {
- boundVarCount = 0;
- freeVarCount = 0;
- freeVarMap = new Dictionary<Variable, FreeVariable>();
-
- ne = VisitExpr(e);
- cache[e] = ne;
-#if DEBUG_ALPHA_RENAMING
- var wr = new TokenTextWriter("<console>", 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<Variable, Expr>();
- var newBound = new List<Variable>();
- 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<A>
- {
- private readonly Dictionary<Tuple<int, Type>, A> vars = new Dictionary<Tuple<int, Type>, A>();
-
- private readonly string Prefix; // either "bv" or "fv"
- private readonly Func<TypedIdent, A> Mk; // either new BoundVar or new FreeVar
-
- public TypeDict(string prefix, Func<TypedIdent, A> 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<Expr>
+ {
+ private readonly DeBruijnRenamer deBruijn = new DeBruijnRenamer();
+
+ bool IEqualityComparer<Expr>.Equals(Expr x, Expr y) {
+ var nx = deBruijn.Rename(x);
+ var ny = deBruijn.Rename(y);
+ return BinderExpr.EqualWithAttributesAndTriggers(nx, ny);
+ }
+
+ int IEqualityComparer<Expr>.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<BoundVariable> boundVars =
+ new TypeDict<BoundVariable>("bv", ti => new BoundVariable(Token.NoToken, ti));
+
+ private readonly TypeDict<FreeVariable> freeVars =
+ new TypeDict<FreeVariable>("fv", ti => new FreeVariable(ti));
+
+ // These three variables are reset at the beginning of every renaming
+ private int boundVarCount, freeVarCount;
+ private Dictionary<Variable, FreeVariable> freeVarMap;
+
+ // Cached, previous results
+ private readonly Dictionary<Expr, Expr> cache = new Dictionary<Expr, Expr>();
+
+ public Expr Rename(Expr e) {
+ Expr ne;
+ if (!cache.TryGetValue(e, out ne)) {
+ boundVarCount = 0;
+ freeVarCount = 0;
+ freeVarMap = new Dictionary<Variable, FreeVariable>();
+
+ ne = VisitExpr(e);
+ cache[e] = ne;
+#if DEBUG_ALPHA_RENAMING
+ var wr = new TokenTextWriter("<console>", 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<Variable, Expr>();
+ var newBound = new List<Variable>();
+ 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<A>
+ {
+ private readonly Dictionary<Tuple<int, Type>, A> vars = new Dictionary<Tuple<int, Type>, A>();
+
+ private readonly string Prefix; // either "bv" or "fv"
+ private readonly Func<TypedIdent, A> Mk; // either new BoundVar or new FreeVar
+
+ public TypeDict(string prefix, Func<TypedIdent, A> 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<Expr>/*!*/ dummyExprSeq;
-readonly TransferCmd/*!*/ dummyTransferCmd;
-readonly StructuredCmd/*!*/ dummyStructuredCmd;
-
-///<summary>
-///Returns the number of parsing errors encountered. If 0, "program" returns as
-///the parsed program.
-///</summary>
-public static int Parse (string/*!*/ filename, /*maybe null*/ List<string/*!*/> 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<string/*!*/>();
- }
-
- 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<Cmd>(), new ReturnCmd(Token.NoToken));
- dummyType = new BasicType(Token.NoToken, SimpleType.Bool);
- dummyExprSeq = new List<Expr> ();
- 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<Bpl.Type>() != 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<object>/*!*/ 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<Variable>/*!*/ vs;
- List<Declaration>/*!*/ ds;
- Axiom/*!*/ ax;
- List<Declaration/*!*/>/*!*/ ts;
- Procedure/*!*/ pr;
- Implementation im;
- Implementation/*!*/ nnim;
- .)
- { Consts<out vs> (. foreach(Bpl.Variable/*!*/ v in vs){
- Contract.Assert(v != null);
- Pgm.AddTopLevelDeclaration(v);
- }
- .)
- | Function<out ds> (. foreach(Bpl.Declaration/*!*/ d in ds){
- Contract.Assert(d != null);
- Pgm.AddTopLevelDeclaration(d);
- }
- .)
- | Axiom<out ax> (. Pgm.AddTopLevelDeclaration(ax); .)
- | UserDefinedTypes<out ts> (. foreach(Declaration/*!*/ td in ts){
- Contract.Assert(td != null);
- Pgm.AddTopLevelDeclaration(td);
- }
- .)
- | GlobalVars<out vs> (. foreach(Bpl.Variable/*!*/ v in vs){
- Contract.Assert(v != null);
- Pgm.AddTopLevelDeclaration(v);
- }
- .)
- | Procedure<out pr, out im> (. Pgm.AddTopLevelDeclaration(pr);
- if (im != null) {
- Pgm.AddTopLevelDeclaration(im);
- }
- .)
- | Implementation<out nnim> (. Pgm.AddTopLevelDeclaration(nnim); .)
- }
- EOF
- .
-
-/*------------------------------------------------------------------------*/
-GlobalVars<.out List<Variable>/*!*/ ds.>
-= (.
- Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
- QKeyValue kv = null;
- ds = new List<Variable>();
- var dsx = ds;
- .)
- "var"
- { Attribute<ref kv> }
- IdsTypeWheres<true, "global variables", delegate(TypedIdent tyd) { dsx.Add(new GlobalVariable(tyd.tok, tyd, kv)); } > ";"
- .
-
-LocalVars<.List<Variable>/*!*/ ds.>
-= (.
- Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
- QKeyValue kv = null;
- .)
- "var"
- { Attribute<ref kv> }
- IdsTypeWheres<true, "local variables", delegate(TypedIdent tyd) { ds.Add(new LocalVariable(tyd.tok, tyd, kv)); } > ";"
- .
-
-ProcFormals<.bool incoming, bool allowWhereClauses, out List<Variable>/*!*/ ds.>
-= (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
- ds = new List<Variable>();
- var dsx = ds;
- var context = allowWhereClauses ? "procedure formals" : "the 'implementation' copies of formals";
- .)
- "("
- [ AttrsIdsTypeWheres<allowWhereClauses, allowWhereClauses, context, delegate(TypedIdent tyd, QKeyValue kv) { dsx.Add(new Formal(tyd.tok, tyd, incoming, kv)); }>
- ]
- ")"
- .
-
-BoundVars<.IToken/*!*/ x, out List<Variable>/*!*/ ds.>
-= (.
- Contract.Requires(x != null);
- Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
- List<TypedIdent>/*!*/ tyds = new List<TypedIdent>();
- ds = new List<Variable>();
- var dsx = ds;
- .)
- AttrsIdsTypeWheres<true, false, "bound variables", delegate(TypedIdent tyd, QKeyValue kv) { dsx.Add(new BoundVariable(tyd.tok, tyd, kv)); } >
- .
-
-/*------------------------------------------------------------------------*/
-/* IdsType is used with const declarations */
-IdsType<.out List<TypedIdent>/*!*/ tyds.>
-= (. Contract.Ensures(Contract.ValueAtReturn(out tyds) != null); List<IToken>/*!*/ ids; Bpl.Type/*!*/ ty; .)
- Idents<out ids> ":" Type<out ty>
- (. tyds = new List<TypedIdent>();
- 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<TypedIdent, QKeyValue> action .>
-=
- AttributesIdsTypeWhere<allowAttributes, allowWhereClauses, context, action>
- { "," AttributesIdsTypeWhere<allowAttributes, allowWhereClauses, context, action> }
- .
-
-IdsTypeWheres<. bool allowWhereClauses, string context, System.Action<TypedIdent> action .>
-=
- IdsTypeWhere<allowWhereClauses, context, action>
- { "," IdsTypeWhere<allowWhereClauses, context, action> }
- .
-
-AttributesIdsTypeWhere<. bool allowAttributes, bool allowWhereClauses, string context, System.Action<TypedIdent, QKeyValue> action .>
-= (. QKeyValue kv = null; .)
- { Attribute<ref kv> (. if (!allowAttributes) {
- kv = null;
- this.SemErr("attributes are not allowed on " + context);
- }
- .)
- }
- IdsTypeWhere<allowWhereClauses, context, delegate(TypedIdent tyd) { action(tyd, kv); }>
- .
-
-/* context is allowed to be null if allowWhereClauses is true */
-IdsTypeWhere<. bool allowWhereClauses, string context, System.Action<TypedIdent> action .>
-= (. List<IToken>/*!*/ ids; Bpl.Type/*!*/ ty; Expr wh = null; Expr/*!*/ nne; .)
- Idents<out ids> ":" Type<out ty>
- [ "where" Expression<out nne> (. 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<out Bpl.Type/*!*/ ty>
-= (.Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken/*!*/ tok; ty = dummyType; .)
- (
- TypeAtom<out ty>
- |
- Ident<out tok> (. List<Bpl.Type>/*!*/ args = new List<Bpl.Type> (); .)
- [ TypeArgs<args> ] (. ty = new UnresolvedTypeIdentifier (tok, tok.val, args); .)
- |
- MapType<out ty>
- )
- .
-
-TypeArgs<.List<Bpl.Type>/*!*/ ts.>
-= (.Contract.Requires(ts != null); IToken/*!*/ tok; Bpl.Type/*!*/ ty; .)
- (
- TypeAtom<out ty> (. ts.Add(ty); .)
- [ TypeArgs<ts> ]
- |
- Ident<out tok> (. List<Bpl.Type>/*!*/ args = new List<Bpl.Type> ();
- ts.Add(new UnresolvedTypeIdentifier (tok, tok.val, args)); .)
- [ TypeArgs<ts> ]
- |
- MapType<out ty> (. ts.Add(ty); .)
- )
- .
-
-TypeAtom<out Bpl.Type/*!*/ ty>
-= (.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<out ty>
- ")"
- )
- .
-
-MapType<out Bpl.Type/*!*/ ty>
-= (.Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken tok = null;
- IToken/*!*/ nnTok;
- List<Bpl.Type>/*!*/ arguments = new List<Bpl.Type>();
- Bpl.Type/*!*/ result;
- List<TypeVariable>/*!*/ typeParameters = new List<TypeVariable>();
- .)
- [ TypeParams<out nnTok, out typeParameters> (. tok = nnTok; .) ]
- "[" (. if (tok == null) tok = t; .)
- [ Types<arguments> ]
- "]"
- Type<out result>
- (.
- ty = new MapType(tok, typeParameters, arguments, result);
- .)
- .
-
-TypeParams<.out IToken/*!*/ tok, out List<TypeVariable>/*!*/ typeParams.>
-= (.Contract.Ensures(Contract.ValueAtReturn(out tok) != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); List<IToken>/*!*/ typeParamToks; .)
- "<" (. tok = t; .)
- Idents<out typeParamToks>
- ">"
- (.
- typeParams = new List<TypeVariable> ();
- foreach(Token/*!*/ id in typeParamToks){
- Contract.Assert(id != null);
- typeParams.Add(new TypeVariable(id, id.val));}
- .)
- .
-
-Types<.List<Bpl.Type>/*!*/ ts.>
-= (. Contract.Requires(ts != null); Bpl.Type/*!*/ ty; .)
- Type<out ty> (. ts.Add(ty); .)
- { "," Type<out ty> (. ts.Add(ty); .)
- }
- .
-
-
-/*------------------------------------------------------------------------*/
-Consts<.out List<Variable>/*!*/ ds.>
-= (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null); IToken/*!*/ y; List<TypedIdent>/*!*/ xs;
- ds = new List<Variable>();
- bool u = false; QKeyValue kv = null;
- bool ChildrenComplete = false;
- List<ConstantParent/*!*/> Parents = null; .)
- "const" (. y = t; .)
- { Attribute<ref kv> }
- [ "unique" (. u = true; .)
- ]
- IdsType<out xs>
- [ OrderSpec<out ChildrenComplete, out Parents> ]
- (. bool makeClone = false;
- foreach(TypedIdent/*!*/ x in xs){
- Contract.Assert(x != null);
-
- // ensure that no sharing is introduced
- List<ConstantParent/*!*/> ParentsClone;
- if (makeClone && Parents != null) {
- ParentsClone = new List<ConstantParent/*!*/> ();
- 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<ConstantParent/*!*/> Parents.>
-= (.Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out Parents),true)); ChildrenComplete = false;
- Parents = null;
- bool u;
- IToken/*!*/ parent; .)
- "extends" (. Parents = new List<ConstantParent/*!*/> ();
- u = false; .)
- [
- [ "unique" (. u = true; .)
- ]
- Ident<out parent> (. Parents.Add(new ConstantParent (
- new IdentifierExpr(parent, parent.val), u)); .)
- {
- "," (. u = false; .)
- [ "unique" (. u = true; .)
- ]
- Ident<out parent> (. Parents.Add(new ConstantParent (
- new IdentifierExpr(parent, parent.val), u)); .)
- }
- ]
- [ "complete" (. ChildrenComplete = true; .)
- ]
- .
-
-/*------------------------------------------------------------------------*/
-Function<.out List<Declaration>/*!*/ ds.>
-= (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
- ds = new List<Declaration>(); IToken/*!*/ z;
- IToken/*!*/ typeParamTok;
- var typeParams = new List<TypeVariable>();
- var arguments = new List<Variable>();
- TypedIdent/*!*/ tyd;
- TypedIdent retTyd = null;
- Bpl.Type/*!*/ retTy;
- QKeyValue argKv = null;
- QKeyValue kv = null;
- Expr definition = null;
- Expr/*!*/ tmp;
- .)
- "function" { Attribute<ref kv> } Ident<out z>
- [ TypeParams<out typeParamTok, out typeParams> ]
- "("
- [ VarOrType<out tyd, out argKv> (. arguments.Add(new Formal(tyd.tok, tyd, true, argKv)); .)
- { "," VarOrType<out tyd, out argKv> (. arguments.Add(new Formal(tyd.tok, tyd, true, argKv)); .)
- } ] ")"
- (. argKv = null; .)
- (
- "returns" "(" VarOrType<out retTyd, out argKv> ")"
- |
- ":" Type<out retTy> (. retTyd = new TypedIdent(retTy.tok, TypedIdent.NoName, retTy); .)
- )
- ( "{" Expression<out tmp> (. 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<out TypedIdent/*!*/ tyd, out QKeyValue kv>
-= (.
- Contract.Ensures(Contract.ValueAtReturn(out tyd) != null);
- string/*!*/ varName = TypedIdent.NoName;
- Bpl.Type/*!*/ ty;
- IToken/*!*/ tok;
- kv = null;
- .)
- { Attribute<ref kv> }
- Type<out ty> (. 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<out ty>
- ]
- (. tyd = new TypedIdent(tok, varName, ty); .)
- .
-
-/*------------------------------------------------------------------------*/
-Axiom<out Axiom/*!*/ m>
-= (.Contract.Ensures(Contract.ValueAtReturn(out m) != null); Expr/*!*/ e; QKeyValue kv = null; .)
- "axiom"
- { Attribute<ref kv> }
- (. IToken/*!*/ x = t; .)
- Proposition<out e> ";" (. m = new Axiom(x,e, null, kv); .)
- .
-
-/*------------------------------------------------------------------------*/
-UserDefinedTypes<.out List<Declaration/*!*/>/*!*/ ts.>
-= (. Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out ts))); Declaration/*!*/ decl; QKeyValue kv = null; ts = new List<Declaration/*!*/> (); .)
- "type"
- { Attribute<ref kv> }
- UserDefinedType<out decl, kv> (. ts.Add(decl); .)
- { "," UserDefinedType<out decl, kv> (. ts.Add(decl); .) }
- ";"
- .
-
-UserDefinedType<out Declaration/*!*/ decl, QKeyValue kv>
-= (. Contract.Ensures(Contract.ValueAtReturn(out decl) != null); IToken/*!*/ id; List<IToken>/*!*/ paramTokens = new List<IToken> ();
- Bpl.Type/*!*/ body = dummyType; bool synonym = false; .)
- Ident<out id>
- [ WhiteSpaceIdents<out paramTokens> ]
- [
- "=" Type<out body>
- (. synonym = true; .)
- ]
- (.
- if (synonym) {
- List<TypeVariable>/*!*/ typeParams = new List<TypeVariable>();
- 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<out Procedure/*!*/ proc, out /*maybe null*/ Implementation impl>
-= (. Contract.Ensures(Contract.ValueAtReturn(out proc) != null); IToken/*!*/ x;
- List<TypeVariable>/*!*/ typeParams;
- List<Variable>/*!*/ ins, outs;
- List<Requires>/*!*/ pre = new List<Requires>();
- List<IdentifierExpr>/*!*/ mods = new List<IdentifierExpr>();
- List<Ensures>/*!*/ post = new List<Ensures>();
-
- List<Variable>/*!*/ locals = new List<Variable>();
- StmtList/*!*/ stmtList;
- QKeyValue kv = null;
- impl = null;
- .)
-
- "procedure"
- ProcSignature<true, out x, out typeParams, out ins, out outs, out kv>
- ( ";"
- { Spec<pre, mods, post> }
- | { Spec<pre, mods, post> }
- ImplBody<out locals, out stmtList>
- (.
- 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<out Implementation/*!*/ impl>
-= (. Contract.Ensures(Contract.ValueAtReturn(out impl) != null); IToken/*!*/ x;
- List<TypeVariable>/*!*/ typeParams;
- List<Variable>/*!*/ ins, outs;
- List<Variable>/*!*/ locals;
- StmtList/*!*/ stmtList;
- QKeyValue kv;
- .)
-
- "implementation"
- ProcSignature<false, out x, out typeParams, out ins, out outs, out kv>
- ImplBody<out locals, out stmtList>
- (. impl = new Implementation(x, x.val, typeParams, ins, outs, locals, stmtList, kv, this.errors); .)
- .
-
-
-ProcSignature<.bool allowWhereClausesOnFormals, out IToken/*!*/ name, out List<TypeVariable>/*!*/ typeParams,
- out List<Variable>/*!*/ ins, out List<Variable>/*!*/ 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<TypeVariable>();
- outs = new List<Variable>(); kv = null; .)
- { Attribute<ref kv> }
- Ident<out name>
- [ TypeParams<out typeParamTok, out typeParams> ]
- ProcFormals<true, allowWhereClausesOnFormals, out ins>
- [ "returns" ProcFormals<false, allowWhereClausesOnFormals, out outs> ]
- .
-
-
-Spec<.List<Requires>/*!*/ pre, List<IdentifierExpr>/*!*/ mods, List<Ensures>/*!*/ post.>
-= (.Contract.Requires(pre != null); Contract.Requires(mods != null); Contract.Requires(post != null); List<IToken>/*!*/ ms; .)
- ( "modifies"
- [ Idents<out ms> (. foreach(IToken/*!*/ m in ms){
- Contract.Assert(m != null);
- mods.Add(new IdentifierExpr(m, m.val));
- }
- .)
- ] ";"
- | "free" SpecPrePost<true, pre, post>
- | SpecPrePost<false, pre, post>
- )
- .
-
-SpecPrePost<.bool free, List<Requires>/*!*/ pre, List<Ensures>/*!*/ post.>
-= (. Contract.Requires(pre != null); Contract.Requires(post != null); Expr/*!*/ e; Token tok = null; QKeyValue kv = null; .)
- ( "requires" (. tok = t; .)
- { Attribute<ref kv> }
- Proposition<out e> ";" (. pre.Add(new Requires(tok, free, e, null, kv)); .)
- | "ensures" (. tok = t; .)
- { Attribute<ref kv> }
- Proposition<out e> ";" (. post.Add(new Ensures(tok, free, e, null, kv)); .)
- )
- .
-
-/*------------------------------------------------------------------------*/
-
-ImplBody<.out List<Variable>/*!*/ locals, out StmtList/*!*/ stmtList.>
-= (. Contract.Ensures(Contract.ValueAtReturn(out locals) != null); Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); locals = new List<Variable>(); .)
- "{"
- { LocalVars<locals> }
- StmtList<out stmtList>
- .
-
-/* the StmtList also reads the final curly brace */
-StmtList<out StmtList/*!*/ stmtList>
-= (. Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); List<BigBlock/*!*/> bigblocks = new List<BigBlock/*!*/>();
- /* built-up state for the current BigBlock: */
- IToken startToken = null; string currentLabel = null;
- List<Cmd> 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<out c, out label>
- (. if (c != null) {
- // LabelOrCmd read a Cmd
- Contract.Assert(label == null);
- if (startToken == null) { startToken = c.tok; cs = new List<Cmd>(); }
- 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<Cmd>();
- }
- .)
-
- | StructuredCmd<out ecn>
- (. ec = ecn;
- if (startToken == null) { startToken = ec.tok; cs = new List<Cmd>(); }
- Contract.Assert(cs != null);
- b = new BigBlock(startToken, currentLabel, cs, ec, null);
- bigblocks.Add(b);
- startToken = null; currentLabel = null; cs = null;
- .)
-
- | TransferCmd<out tcn>
- (. tc = tcn;
- if (startToken == null) { startToken = tc.tok; cs = new List<Cmd>(); }
- 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<Cmd>();
- }
- if (startToken != null) {
- Contract.Assert(cs != null);
- b = new BigBlock(startToken, currentLabel, cs, null, null);
- bigblocks.Add(b);
- }
-
- stmtList = new StmtList(bigblocks, endCurly);
- .)
- .
-
-TransferCmd<out TransferCmd/*!*/ tc>
-= (. Contract.Ensures(Contract.ValueAtReturn(out tc) != null); tc = dummyTransferCmd;
- Token y; List<IToken>/*!*/ xs;
- List<String> ss = new List<String>();
- .)
- ( "goto" (. y = t; .)
- Idents<out xs> (. foreach(IToken/*!*/ s in xs){
- Contract.Assert(s != null);
- ss.Add(s.val); }
- tc = new GotoCmd(y, ss);
- .)
- | "return" (. tc = new ReturnCmd(t); .)
- ) ";"
- .
-
-StructuredCmd<out StructuredCmd/*!*/ ec>
-= (. Contract.Ensures(Contract.ValueAtReturn(out ec) != null); ec = dummyStructuredCmd; Contract.Assume(cce.IsPeerConsistent(ec));
- IfCmd/*!*/ ifcmd; WhileCmd/*!*/ wcmd; BreakCmd/*!*/ bcmd;
- .)
- ( IfCmd<out ifcmd> (. ec = ifcmd; .)
- | WhileCmd<out wcmd> (. ec = wcmd; .)
- | BreakCmd<out bcmd> (. ec = bcmd; .)
- )
- .
-
-IfCmd<out IfCmd/*!*/ 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<out guard>
- "{" StmtList<out thn>
- [ "else"
- ( IfCmd<out elseIf> (. elseIfOption = elseIf; .)
- | "{"
- StmtList<out els> (. elseOption = els; .)
- )
- ]
- (. ifcmd = new IfCmd(x, guard, thn, elseIfOption, elseOption); .)
- .
-
-WhileCmd<out WhileCmd/*!*/ wcmd>
-= (. Contract.Ensures(Contract.ValueAtReturn(out wcmd) != null); IToken/*!*/ x; Token z;
- Expr guard; Expr/*!*/ e; bool isFree;
- List<PredicateCmd/*!*/> invariants = new List<PredicateCmd/*!*/>();
- StmtList/*!*/ body;
- QKeyValue kv = null;
- .)
- "while" (. x = t; .)
- Guard<out guard> (. Contract.Assume(guard == null || cce.Owner.None(guard)); .)
- { (. isFree = false; z = la/*lookahead token*/; .)
- [ "free" (. isFree = true; .)
- ]
- "invariant"
- { Attribute<ref kv> }
- Expression<out e> (. if (isFree) {
- invariants.Add(new AssumeCmd(z, e, kv));
- } else {
- invariants.Add(new AssertCmd(z, e, kv));
- }
- kv = null;
- .)
- ";"
- }
- "{"
- StmtList<out body> (. wcmd = new WhileCmd(x, guard, invariants, body); .)
- .
-
-Guard<out Expr e>
-= (. Expr/*!*/ ee; e = null; .)
- "("
- ( "*" (. e = null; .)
- | Expression<out ee> (. e = ee; .)
- )
- ")"
- .
-
-BreakCmd<out BreakCmd/*!*/ bcmd>
-= (.Contract.Ensures(Contract.ValueAtReturn(out bcmd) != null); IToken/*!*/ x; IToken/*!*/ y;
- string breakLabel = null;
- .)
- "break" (. x = t; .)
- [ Ident<out y> (. breakLabel = y.val; .)
- ] ";" (. bcmd = new BreakCmd(x, breakLabel); .)
- .
-
-/*------------------------------------------------------------------------*/
-
-LabelOrCmd<out Cmd c, out IToken label>
-/* ensures (c == null) != (label != null) */
-= (. IToken/*!*/ x; Expr/*!*/ e;
- List<IToken>/*!*/ xs;
- List<IdentifierExpr> ids;
- c = dummyCmd; label = null;
- Cmd/*!*/ cn;
- QKeyValue kv = null;
- .)
- ( LabelOrAssign<out c, out label>
- | "assert" (. x = t; .)
- { Attribute<ref kv> }
- Proposition<out e> (. c = new AssertCmd(x, e, kv); .)
- ";"
- | "assume" (. x = t; .)
- { Attribute<ref kv> }
- Proposition<out e> (. c = new AssumeCmd(x, e, kv); .)
- ";"
- | "havoc" (. x = t; .)
- Idents<out xs> ";" (. ids = new List<IdentifierExpr>();
- foreach(IToken/*!*/ y in xs){
- Contract.Assert(y != null);
- ids.Add(new IdentifierExpr(y, y.val));
- }
- c = new HavocCmd(x,ids);
- .)
- | CallCmd<out cn> ";" (. c = cn; .)
- | ParCallCmd<out cn> (. c = cn; .)
- | "yield" (. x = t; .)
- ";" (. c = new YieldCmd(x); .)
- )
- .
-
-/*------------------------------------------------------------------------*/
-
-LabelOrAssign<out Cmd c, out IToken label>
-/* ensures (c == null) != (label != null) */
-= (. IToken/*!*/ id; IToken/*!*/ x, y; Expr/*!*/ e0;
- c = dummyCmd; label = null;
- AssignLhs/*!*/ lhs;
- List<AssignLhs/*!*/>/*!*/ lhss;
- List<Expr/*!*/>/*!*/ rhss;
- List<Expr/*!*/>/*!*/ indexes;
- .)
- Ident<out id> (. x = t; .)
- ( ":" (. c = null; label = x; .)
-
- | (. lhss = new List<AssignLhs/*!*/>(); .)
- (. lhs = new SimpleAssignLhs(id, new IdentifierExpr(id, id.val)); .)
-
- { MapAssignIndex<out y, out indexes> (. lhs = new MapAssignLhs(y, lhs, indexes); .) }
- (. lhss.Add(lhs); .)
-
- { ","
- Ident<out id>
- (. lhs = new SimpleAssignLhs(id, new IdentifierExpr(id, id.val)); .)
- { MapAssignIndex<out y, out indexes> (. lhs = new MapAssignLhs(y, lhs, indexes); .) }
- (. lhss.Add(lhs); .)
- }
-
- ":=" (. x = t; /* use location of := */ .)
- Expression<out e0> (. rhss = new List<Expr/*!*/> ();
- rhss.Add(e0); .)
- { ","
- Expression<out e0> (. rhss.Add(e0); .)
- }
- ";" (. c = new AssignCmd(x, lhss, rhss); .)
- )
- .
-
-MapAssignIndex<.out IToken/*!*/ x, out List<Expr/*!*/>/*!*/ indexes.>
-= (.Contract.Ensures(Contract.ValueAtReturn(out x) != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out indexes))); indexes = new List<Expr/*!*/> ();
- Expr/*!*/ e;
- .)
- "[" (. x = t; .)
- [
- Expression<out e> (. indexes.Add(e); .)
- { ","
- Expression<out e> (. indexes.Add(e); .)
- }
- ]
- "]"
- .
-
-/*------------------------------------------------------------------------*/
-CallCmd<out Cmd c>
-= (. 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<ref kv> }
- CallParams<isAsync, isFree, kv, x, out c> (. .)
- .
-
-ParCallCmd<out Cmd d>
-= (. Contract.Ensures(Contract.ValueAtReturn(out d) != null);
- IToken x;
- QKeyValue kv = null;
- Cmd c = null;
- List<CallCmd> callCmds = new List<CallCmd>();
- .)
- "par" (. x = t; .)
- { Attribute<ref kv> }
- CallParams<false, false, kv, x, out c> (. callCmds.Add((CallCmd)c); .)
- { "|" CallParams<false, false, kv, x, out c> (. callCmds.Add((CallCmd)c); .)
- }
- ";" (. d = new ParCallCmd(x, callCmds, kv); .)
- .
-
-CallParams<bool isAsync, bool isFree, QKeyValue kv, IToken x, out Cmd c>
-= (.
- List<IdentifierExpr> ids = new List<IdentifierExpr>();
- List<Expr> es = new List<Expr>();
- Expr en;
- IToken first;
- IToken p;
- c = null;
- .)
- Ident<out first>
- ( "("
- [ Expression<out en> (. es.Add(en); .)
- { "," Expression<out en> (. 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<out p> (. ids.Add(new IdentifierExpr(p, p.val)); .)
- { "," Ident<out p> (. ids.Add(new IdentifierExpr(p, p.val)); .)
- }
- ] ":="
- Ident<out first> "("
- [ Expression<out en> (. es.Add(en); .)
- { "," Expression<out en> (. es.Add(en); .)
- }
- ]
- ")" (. c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync; .)
- )
- .
-
-/*------------------------------------------------------------------------*/
-Proposition<out Expr/*!*/ e>
-=(.Contract.Ensures(Contract.ValueAtReturn(out e) != null);.)
- Expression<out e>
- .
-
-/*------------------------------------------------------------------------*/
-Idents<.out List<IToken>/*!*/ xs.>
-= (.Contract.Ensures(Contract.ValueAtReturn(out xs) != null); IToken/*!*/ id; xs = new List<IToken>(); .)
- Ident<out id> (. xs.Add(id); .)
- { "," Ident<out id> (. xs.Add(id); .)
- }
- .
-
-/*------------------------------------------------------------------------*/
-WhiteSpaceIdents<.out List<IToken>/*!*/ xs.>
-= (. Contract.Ensures(Contract.ValueAtReturn(out xs) != null); IToken/*!*/ id; xs = new List<IToken>(); .)
- Ident<out id> (. xs.Add(id); .)
- { Ident<out id> (. xs.Add(id); .)
- }
- .
-
-/*------------------------------------------------------------------------*/
-Expressions<.out List<Expr>/*!*/ es.>
-= (. Contract.Ensures(Contract.ValueAtReturn(out es) != null); Expr/*!*/ e; es = new List<Expr>(); .)
- Expression<out e> (. es.Add(e); .)
- { "," Expression<out e> (. es.Add(e); .)
- }
- .
-
-/*------------------------------------------------------------------------*/
-Expression<.out Expr/*!*/ e0.>
-= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .)
- ImpliesExpression<false, out e0>
- { EquivOp (. x = t; .)
- ImpliesExpression<false, out e1>
- (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Iff, e0, e1); .)
- }
- .
-
-EquivOp = "<==>" | '\u21d4'.
-
-/*------------------------------------------------------------------------*/
-ImpliesExpression<bool noExplies, out Expr/*!*/ e0>
-= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .)
- LogicalExpression<out e0>
- [
- ImpliesOp (. x = t; .)
- /* recurse because implication is right-associative */
- ImpliesExpression<true, out e1>
- (. 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<out e1>
- (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e1, e0); .)
- /* loop because explies is left-associative */
- {
- ExpliesOp (. x = t; .)
- LogicalExpression<out e1>
- (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e1, e0); .)
- }
- ]
- .
-
-ImpliesOp = "==>" | '\u21d2'.
-ExpliesOp = "<==" | '\u21d0'.
-
-/*------------------------------------------------------------------------*/
-LogicalExpression<out Expr/*!*/ e0>
-= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .)
- RelationalExpression<out e0>
- [ AndOp (. x = t; .)
- RelationalExpression<out e1>
- (. e0 = Expr.Binary(x, BinaryOperator.Opcode.And, e0, e1); .)
- { AndOp (. x = t; .)
- RelationalExpression<out e1>
- (. e0 = Expr.Binary(x, BinaryOperator.Opcode.And, e0, e1); .)
- }
- | OrOp (. x = t; .)
- RelationalExpression<out e1>
- (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Or, e0, e1); .)
- { OrOp (. x = t; .)
- RelationalExpression<out e1>
- (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Or, e0, e1); .)
- }
- ]
- .
-
-AndOp = "&&" | '\u2227'.
-OrOp = "||" | '\u2228'.
-
-/*------------------------------------------------------------------------*/
-RelationalExpression<out Expr/*!*/ e0>
-= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .)
- BvTerm<out e0>
- [ RelOp<out x, out op>
- BvTerm<out e1> (. e0 = Expr.Binary(x, op, e0, e1); .)
- ]
- .
-
-RelOp<out IToken/*!*/ x, out BinaryOperator.Opcode op>
-= (.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<out Expr/*!*/ e0>
-= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .)
- Term<out e0>
- { "++" (. x = t; .)
- Term<out e1> (. e0 = new BvConcatExpr(x, e0, e1); .)
- }
- .
-
-
-/*------------------------------------------------------------------------*/
-Term<out Expr/*!*/ e0>
-= (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .)
- Factor<out e0>
- { AddOp<out x, out op>
- Factor<out e1> (. e0 = Expr.Binary(x, op, e0, e1); .)
- }
- .
-
-AddOp<out IToken/*!*/ x, out BinaryOperator.Opcode op>
-= (.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<out Expr/*!*/ e0>
-= (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .)
- Power<out e0>
- { MulOp<out x, out op>
- Power<out e1> (. e0 = Expr.Binary(x, op, e0, e1); .)
- }
- .
-
-MulOp<out IToken/*!*/ x, out BinaryOperator.Opcode op>
-= (. 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<out Expr/*!*/ e0>
-= (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .)
- UnaryExpression<out e0>
- [
- "**" (. x = t; .)
- /* recurse because exponentation is right-associative */
- Power<out e1> (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Pow, e0, e1); .)
- ]
- .
-
-/*------------------------------------------------------------------------*/
-UnaryExpression<out Expr/*!*/ e>
-= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x;
- e = dummyExpr;
- .)
- ( "-" (. x = t; .)
- UnaryExpression<out e> (. e = Expr.Unary(x, UnaryOperator.Opcode.Neg, e); .)
- | NegOp (. x = t; .)
- UnaryExpression<out e> (. e = Expr.Unary(x, UnaryOperator.Opcode.Not, e); .)
- | CoercionExpression<out e>
- )
- .
-
-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<out Expr/*!*/ e>
-= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x;
- Bpl.Type/*!*/ coercedTo;
- BigNum bn;
- .)
- ArrayExpression<out e>
- { ":" (. x = t; .)
- (
- Type<out coercedTo> (. e = Expr.CoerceType(x, e, coercedTo); .)
- |
- Nat<out bn> /* 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<out Expr/*!*/ e>
-= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x;
- Expr/*!*/ index0 = dummyExpr; Expr/*!*/ e1;
- bool store; bool bvExtract;
- List<Expr>/*!*/ allArgs = dummyExprSeq;
- .)
- AtomExpression<out e>
- { "[" (. x = t; allArgs = new List<Expr> ();
- allArgs.Add(e);
- store = false; bvExtract = false; .)
- [
- Expression<out index0>
- (. if (index0 is BvBounds)
- bvExtract = true;
- else
- allArgs.Add(index0);
- .)
- { "," Expression<out e1>
- (. if (bvExtract || e1 is BvBounds)
- this.SemErr("bitvectors only have one dimension");
- allArgs.Add(e1);
- .)
- }
- [ ":=" Expression<out e1>
- (. if (bvExtract || e1 is BvBounds)
- this.SemErr("assignment to bitvectors is not possible");
- allArgs.Add(e1); store = true;
- .)
- ]
- | ":=" Expression<out e1> (. 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<out Expr/*!*/ e>
-= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; int n; BigNum bn; BigDec bd;
- List<Expr>/*!*/ es; List<Variable>/*!*/ ds; Trigger trig;
- List<TypeVariable>/*!*/ typeParams;
- IdentifierExpr/*!*/ id;
- QKeyValue kv;
- e = dummyExpr;
- List<Variable>/*!*/ locals;
- List<Block/*!*/>/*!*/ blocks;
- .)
- ( "false" (. e = new LiteralExpr(t, false); .)
- | "true" (. e = new LiteralExpr(t, true); .)
- | Nat<out bn> (. e = new LiteralExpr(t, bn); .)
- | Dec<out bd> (. e = new LiteralExpr(t, bd); .)
- | BvLit<out bn, out n> (. e = new LiteralExpr(t, bn, n); .)
-
- | Ident<out x> (. id = new IdentifierExpr(x, x.val); e = id; .)
- [ "("
- ( Expressions<out es> (. e = new NAryExpr(x, new FunctionCall(id), es); .)
- | /* empty */ (. e = new NAryExpr(x, new FunctionCall(id), new List<Expr>()); .)
- )
- ")"
- ]
-
- | "old" (. x = t; .)
- "("
- Expression<out e>
- ")" (. e = new OldExpr(x, e); .)
-
- | "int" (. x = t; .)
- "("
- Expression<out e>
- ")" (. e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToInt), new List<Expr>{ e }); .)
-
- | "real" (. x = t; .)
- "("
- Expression<out e>
- ")" (. e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToReal), new List<Expr>{ e }); .)
-
- | "(" ( Expression<out e> (. if (e is BvBounds)
- this.SemErr("parentheses around bitvector bounds " +
- "are not allowed"); .)
- | Forall (. x = t; .)
- QuantifierBody<x, out typeParams, out ds, out kv, out trig, out e>
- (. if (typeParams.Count + ds.Count > 0)
- e = new ForallExpr(x, typeParams, ds, kv, trig, e); .)
- | Exists (. x = t; .)
- QuantifierBody<x, out typeParams, out ds, out kv, out trig, out e>
- (. if (typeParams.Count + ds.Count > 0)
- e = new ExistsExpr(x, typeParams, ds, kv, trig, e); .)
- | Lambda (. x = t; .)
- QuantifierBody<x, out typeParams, out ds, out kv, out trig, out e>
- (. 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<out e>
- | CodeExpression<out locals, out blocks> (. e = new CodeExpr(locals, blocks); .)
- )
- .
-
-CodeExpression<.out List<Variable>/*!*/ locals, out List<Block/*!*/>/*!*/ blocks.>
-= (. Contract.Ensures(Contract.ValueAtReturn(out locals) != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out blocks))); locals = new List<Variable>(); Block/*!*/ b;
- blocks = new List<Block/*!*/>();
- .)
- "|{"
- { LocalVars<locals> }
- SpecBlock<out b> (. blocks.Add(b); .)
- { SpecBlock<out b> (. blocks.Add(b); .)
- }
- "}|"
- .
-
-SpecBlock<out Block/*!*/ b>
-= (. Contract.Ensures(Contract.ValueAtReturn(out b) != null); IToken/*!*/ x; IToken/*!*/ y;
- Cmd c; IToken label;
- List<Cmd> cs = new List<Cmd>();
- List<IToken>/*!*/ xs;
- List<String> ss = new List<String>();
- b = dummyBlock;
- Expr/*!*/ e;
- .)
- Ident<out x> ":"
- { LabelOrCmd<out c, out label>
- (. 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<out xs> (. 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<out e>
- (. b = new Block(x,x.val,cs,new ReturnExprCmd(t,e)); .)
- )
- ";"
- .
-
-Attribute<ref QKeyValue kv>
-= (. Trigger trig = null; .)
- AttributeOrTrigger<ref kv, ref trig> (. if (trig != null) this.SemErr("only attributes, not triggers, allowed here"); .)
-.
-
-AttributeOrTrigger<ref QKeyValue kv, ref Trigger trig>
-= (. IToken/*!*/ tok; Expr/*!*/ e; List<Expr>/*!*/ es;
- string key;
- List<object/*!*/> parameters; object/*!*/ param;
- .)
- "{" (. tok = t; .)
- (
- ":" ident (. key = t.val; parameters = new List<object/*!*/>(); .)
- [ AttributeParameter<out param> (. parameters.Add(param); .)
- { "," AttributeParameter<out param> (. 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<Expr> { e }, null);
- } else {
- trig.AddLast(new Trigger(tok, false, new List<Expr> { 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<out e> (. es = new List<Expr> { e }; .)
- { "," Expression<out e> (. es.Add(e); .)
- } (. if (trig==null) {
- trig = new Trigger(tok, true, es, null);
- } else {
- trig.AddLast(new Trigger(tok, true, es, null));
- }
- .)
- )
- "}"
- .
-
-AttributeParameter<out object/*!*/ o>
-= (. Contract.Ensures(Contract.ValueAtReturn(out o) != null);
- o = "error";
- Expr/*!*/ e;
- .)
- ( string (. o = t.val.Substring(1, t.val.Length-2); .)
- | Expression<out e> (. o = e; .)
- )
- .
-
-IfThenElseExpression<out Expr/*!*/ e>
-= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null);
- IToken/*!*/ tok;
- Expr/*!*/ e0, e1, e2;
- e = dummyExpr; .)
- "if" (. tok = t; .) Expression<out e0> "then" Expression<out e1> "else" Expression<out e2>
- (. e = new NAryExpr(tok, new IfThenElse(tok), new List<Expr>{ e0, e1, e2 }); .)
- .
-
-
-QuantifierBody<.IToken/*!*/ q, out List<TypeVariable>/*!*/ typeParams, out List<Variable>/*!*/ 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<TypeVariable> ();
- IToken/*!*/ tok;
- kv = null;
- ds = new List<Variable> ();
- .)
- (
- TypeParams<out tok, out typeParams>
- [ BoundVars<q, out ds> ]
- |
- BoundVars<q, out ds>
- )
- QSep
- { AttributeOrTrigger<ref kv, ref trig> }
- Expression<out body>
- .
-
-Forall = "forall" | '\u2200'.
-Exists = "exists" | '\u2203'.
-Lambda = "lambda" | '\u03bb'.
-QSep = "::" | '\u2022'.
-
-/*------------------------------------------------------------------------*/
-Ident<out IToken/*!*/ x>
-=(.Contract.Ensures(Contract.ValueAtReturn(out x) != null);.)
- ident (. x = t;
- if (x.val.StartsWith("\\"))
- x.val = x.val.Substring(1);
- .)
- .
-
-/*------------------------------------------------------------------------*/
-Nat<out BigNum n>
-=
- digits
- (. try {
- n = BigNum.FromString(t.val);
- } catch (FormatException) {
- this.SemErr("incorrectly formatted number");
- n = BigNum.ZERO;
- }
- .)
- .
-
-/*------------------------------------------------------------------------*/
-Dec<out BigDec n>
-= (. 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<out BigNum n, out int m>
-=
- 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<Expr>/*!*/ dummyExprSeq;
+readonly TransferCmd/*!*/ dummyTransferCmd;
+readonly StructuredCmd/*!*/ dummyStructuredCmd;
+
+///<summary>
+///Returns the number of parsing errors encountered. If 0, "program" returns as
+///the parsed program.
+///</summary>
+public static int Parse (string/*!*/ filename, /*maybe null*/ List<string/*!*/> 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<string/*!*/>();
+ }
+
+ 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<Cmd>(), new ReturnCmd(Token.NoToken));
+ dummyType = new BasicType(Token.NoToken, SimpleType.Bool);
+ dummyExprSeq = new List<Expr> ();
+ 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<Bpl.Type>() != 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<object>/*!*/ 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<Variable>/*!*/ vs;
+ List<Declaration>/*!*/ ds;
+ Axiom/*!*/ ax;
+ List<Declaration/*!*/>/*!*/ ts;
+ Procedure/*!*/ pr;
+ Implementation im;
+ Implementation/*!*/ nnim;
+ .)
+ { Consts<out vs> (. foreach(Bpl.Variable/*!*/ v in vs){
+ Contract.Assert(v != null);
+ Pgm.AddTopLevelDeclaration(v);
+ }
+ .)
+ | Function<out ds> (. foreach(Bpl.Declaration/*!*/ d in ds){
+ Contract.Assert(d != null);
+ Pgm.AddTopLevelDeclaration(d);
+ }
+ .)
+ | Axiom<out ax> (. Pgm.AddTopLevelDeclaration(ax); .)
+ | UserDefinedTypes<out ts> (. foreach(Declaration/*!*/ td in ts){
+ Contract.Assert(td != null);
+ Pgm.AddTopLevelDeclaration(td);
+ }
+ .)
+ | GlobalVars<out vs> (. foreach(Bpl.Variable/*!*/ v in vs){
+ Contract.Assert(v != null);
+ Pgm.AddTopLevelDeclaration(v);
+ }
+ .)
+ | Procedure<out pr, out im> (. Pgm.AddTopLevelDeclaration(pr);
+ if (im != null) {
+ Pgm.AddTopLevelDeclaration(im);
+ }
+ .)
+ | Implementation<out nnim> (. Pgm.AddTopLevelDeclaration(nnim); .)
+ }
+ EOF
+ .
+
+/*------------------------------------------------------------------------*/
+GlobalVars<.out List<Variable>/*!*/ ds.>
+= (.
+ Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
+ QKeyValue kv = null;
+ ds = new List<Variable>();
+ var dsx = ds;
+ .)
+ "var"
+ { Attribute<ref kv> }
+ IdsTypeWheres<true, "global variables", delegate(TypedIdent tyd) { dsx.Add(new GlobalVariable(tyd.tok, tyd, kv)); } > ";"
+ .
+
+LocalVars<.List<Variable>/*!*/ ds.>
+= (.
+ Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
+ QKeyValue kv = null;
+ .)
+ "var"
+ { Attribute<ref kv> }
+ IdsTypeWheres<true, "local variables", delegate(TypedIdent tyd) { ds.Add(new LocalVariable(tyd.tok, tyd, kv)); } > ";"
+ .
+
+ProcFormals<.bool incoming, bool allowWhereClauses, out List<Variable>/*!*/ ds.>
+= (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
+ ds = new List<Variable>();
+ var dsx = ds;
+ var context = allowWhereClauses ? "procedure formals" : "the 'implementation' copies of formals";
+ .)
+ "("
+ [ AttrsIdsTypeWheres<allowWhereClauses, allowWhereClauses, context, delegate(TypedIdent tyd, QKeyValue kv) { dsx.Add(new Formal(tyd.tok, tyd, incoming, kv)); }>
+ ]
+ ")"
+ .
+
+BoundVars<.IToken/*!*/ x, out List<Variable>/*!*/ ds.>
+= (.
+ Contract.Requires(x != null);
+ Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
+ List<TypedIdent>/*!*/ tyds = new List<TypedIdent>();
+ ds = new List<Variable>();
+ var dsx = ds;
+ .)
+ AttrsIdsTypeWheres<true, false, "bound variables", delegate(TypedIdent tyd, QKeyValue kv) { dsx.Add(new BoundVariable(tyd.tok, tyd, kv)); } >
+ .
+
+/*------------------------------------------------------------------------*/
+/* IdsType is used with const declarations */
+IdsType<.out List<TypedIdent>/*!*/ tyds.>
+= (. Contract.Ensures(Contract.ValueAtReturn(out tyds) != null); List<IToken>/*!*/ ids; Bpl.Type/*!*/ ty; .)
+ Idents<out ids> ":" Type<out ty>
+ (. tyds = new List<TypedIdent>();
+ 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<TypedIdent, QKeyValue> action .>
+=
+ AttributesIdsTypeWhere<allowAttributes, allowWhereClauses, context, action>
+ { "," AttributesIdsTypeWhere<allowAttributes, allowWhereClauses, context, action> }
+ .
+
+IdsTypeWheres<. bool allowWhereClauses, string context, System.Action<TypedIdent> action .>
+=
+ IdsTypeWhere<allowWhereClauses, context, action>
+ { "," IdsTypeWhere<allowWhereClauses, context, action> }
+ .
+
+AttributesIdsTypeWhere<. bool allowAttributes, bool allowWhereClauses, string context, System.Action<TypedIdent, QKeyValue> action .>
+= (. QKeyValue kv = null; .)
+ { Attribute<ref kv> (. if (!allowAttributes) {
+ kv = null;
+ this.SemErr("attributes are not allowed on " + context);
+ }
+ .)
+ }
+ IdsTypeWhere<allowWhereClauses, context, delegate(TypedIdent tyd) { action(tyd, kv); }>
+ .
+
+/* context is allowed to be null if allowWhereClauses is true */
+IdsTypeWhere<. bool allowWhereClauses, string context, System.Action<TypedIdent> action .>
+= (. List<IToken>/*!*/ ids; Bpl.Type/*!*/ ty; Expr wh = null; Expr/*!*/ nne; .)
+ Idents<out ids> ":" Type<out ty>
+ [ "where" Expression<out nne> (. 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<out Bpl.Type/*!*/ ty>
+= (.Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken/*!*/ tok; ty = dummyType; .)
+ (
+ TypeAtom<out ty>
+ |
+ Ident<out tok> (. List<Bpl.Type>/*!*/ args = new List<Bpl.Type> (); .)
+ [ TypeArgs<args> ] (. ty = new UnresolvedTypeIdentifier (tok, tok.val, args); .)
+ |
+ MapType<out ty>
+ )
+ .
+
+TypeArgs<.List<Bpl.Type>/*!*/ ts.>
+= (.Contract.Requires(ts != null); IToken/*!*/ tok; Bpl.Type/*!*/ ty; .)
+ (
+ TypeAtom<out ty> (. ts.Add(ty); .)
+ [ TypeArgs<ts> ]
+ |
+ Ident<out tok> (. List<Bpl.Type>/*!*/ args = new List<Bpl.Type> ();
+ ts.Add(new UnresolvedTypeIdentifier (tok, tok.val, args)); .)
+ [ TypeArgs<ts> ]
+ |
+ MapType<out ty> (. ts.Add(ty); .)
+ )
+ .
+
+TypeAtom<out Bpl.Type/*!*/ ty>
+= (.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<out ty>
+ ")"
+ )
+ .
+
+MapType<out Bpl.Type/*!*/ ty>
+= (.Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken tok = null;
+ IToken/*!*/ nnTok;
+ List<Bpl.Type>/*!*/ arguments = new List<Bpl.Type>();
+ Bpl.Type/*!*/ result;
+ List<TypeVariable>/*!*/ typeParameters = new List<TypeVariable>();
+ .)
+ [ TypeParams<out nnTok, out typeParameters> (. tok = nnTok; .) ]
+ "[" (. if (tok == null) tok = t; .)
+ [ Types<arguments> ]
+ "]"
+ Type<out result>
+ (.
+ ty = new MapType(tok, typeParameters, arguments, result);
+ .)
+ .
+
+TypeParams<.out IToken/*!*/ tok, out List<TypeVariable>/*!*/ typeParams.>
+= (.Contract.Ensures(Contract.ValueAtReturn(out tok) != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); List<IToken>/*!*/ typeParamToks; .)
+ "<" (. tok = t; .)
+ Idents<out typeParamToks>
+ ">"
+ (.
+ typeParams = new List<TypeVariable> ();
+ foreach(Token/*!*/ id in typeParamToks){
+ Contract.Assert(id != null);
+ typeParams.Add(new TypeVariable(id, id.val));}
+ .)
+ .
+
+Types<.List<Bpl.Type>/*!*/ ts.>
+= (. Contract.Requires(ts != null); Bpl.Type/*!*/ ty; .)
+ Type<out ty> (. ts.Add(ty); .)
+ { "," Type<out ty> (. ts.Add(ty); .)
+ }
+ .
+
+
+/*------------------------------------------------------------------------*/
+Consts<.out List<Variable>/*!*/ ds.>
+= (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null); IToken/*!*/ y; List<TypedIdent>/*!*/ xs;
+ ds = new List<Variable>();
+ bool u = false; QKeyValue kv = null;
+ bool ChildrenComplete = false;
+ List<ConstantParent/*!*/> Parents = null; .)
+ "const" (. y = t; .)
+ { Attribute<ref kv> }
+ [ "unique" (. u = true; .)
+ ]
+ IdsType<out xs>
+ [ OrderSpec<out ChildrenComplete, out Parents> ]
+ (. bool makeClone = false;
+ foreach(TypedIdent/*!*/ x in xs){
+ Contract.Assert(x != null);
+
+ // ensure that no sharing is introduced
+ List<ConstantParent/*!*/> ParentsClone;
+ if (makeClone && Parents != null) {
+ ParentsClone = new List<ConstantParent/*!*/> ();
+ 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<ConstantParent/*!*/> Parents.>
+= (.Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out Parents),true)); ChildrenComplete = false;
+ Parents = null;
+ bool u;
+ IToken/*!*/ parent; .)
+ "extends" (. Parents = new List<ConstantParent/*!*/> ();
+ u = false; .)
+ [
+ [ "unique" (. u = true; .)
+ ]
+ Ident<out parent> (. Parents.Add(new ConstantParent (
+ new IdentifierExpr(parent, parent.val), u)); .)
+ {
+ "," (. u = false; .)
+ [ "unique" (. u = true; .)
+ ]
+ Ident<out parent> (. Parents.Add(new ConstantParent (
+ new IdentifierExpr(parent, parent.val), u)); .)
+ }
+ ]
+ [ "complete" (. ChildrenComplete = true; .)
+ ]
+ .
+
+/*------------------------------------------------------------------------*/
+Function<.out List<Declaration>/*!*/ ds.>
+= (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
+ ds = new List<Declaration>(); IToken/*!*/ z;
+ IToken/*!*/ typeParamTok;
+ var typeParams = new List<TypeVariable>();
+ var arguments = new List<Variable>();
+ TypedIdent/*!*/ tyd;
+ TypedIdent retTyd = null;
+ Bpl.Type/*!*/ retTy;
+ QKeyValue argKv = null;
+ QKeyValue kv = null;
+ Expr definition = null;
+ Expr/*!*/ tmp;
+ .)
+ "function" { Attribute<ref kv> } Ident<out z>
+ [ TypeParams<out typeParamTok, out typeParams> ]
+ "("
+ [ VarOrType<out tyd, out argKv> (. arguments.Add(new Formal(tyd.tok, tyd, true, argKv)); .)
+ { "," VarOrType<out tyd, out argKv> (. arguments.Add(new Formal(tyd.tok, tyd, true, argKv)); .)
+ } ] ")"
+ (. argKv = null; .)
+ (
+ "returns" "(" VarOrType<out retTyd, out argKv> ")"
+ |
+ ":" Type<out retTy> (. retTyd = new TypedIdent(retTy.tok, TypedIdent.NoName, retTy); .)
+ )
+ ( "{" Expression<out tmp> (. 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<out TypedIdent/*!*/ tyd, out QKeyValue kv>
+= (.
+ Contract.Ensures(Contract.ValueAtReturn(out tyd) != null);
+ string/*!*/ varName = TypedIdent.NoName;
+ Bpl.Type/*!*/ ty;
+ IToken/*!*/ tok;
+ kv = null;
+ .)
+ { Attribute<ref kv> }
+ Type<out ty> (. 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<out ty>
+ ]
+ (. tyd = new TypedIdent(tok, varName, ty); .)
+ .
+
+/*------------------------------------------------------------------------*/
+Axiom<out Axiom/*!*/ m>
+= (.Contract.Ensures(Contract.ValueAtReturn(out m) != null); Expr/*!*/ e; QKeyValue kv = null; .)
+ "axiom"
+ { Attribute<ref kv> }
+ (. IToken/*!*/ x = t; .)
+ Proposition<out e> ";" (. m = new Axiom(x,e, null, kv); .)
+ .
+
+/*------------------------------------------------------------------------*/
+UserDefinedTypes<.out List<Declaration/*!*/>/*!*/ ts.>
+= (. Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out ts))); Declaration/*!*/ decl; QKeyValue kv = null; ts = new List<Declaration/*!*/> (); .)
+ "type"
+ { Attribute<ref kv> }
+ UserDefinedType<out decl, kv> (. ts.Add(decl); .)
+ { "," UserDefinedType<out decl, kv> (. ts.Add(decl); .) }
+ ";"
+ .
+
+UserDefinedType<out Declaration/*!*/ decl, QKeyValue kv>
+= (. Contract.Ensures(Contract.ValueAtReturn(out decl) != null); IToken/*!*/ id; List<IToken>/*!*/ paramTokens = new List<IToken> ();
+ Bpl.Type/*!*/ body = dummyType; bool synonym = false; .)
+ Ident<out id>
+ [ WhiteSpaceIdents<out paramTokens> ]
+ [
+ "=" Type<out body>
+ (. synonym = true; .)
+ ]
+ (.
+ if (synonym) {
+ List<TypeVariable>/*!*/ typeParams = new List<TypeVariable>();
+ 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<out Procedure/*!*/ proc, out /*maybe null*/ Implementation impl>
+= (. Contract.Ensures(Contract.ValueAtReturn(out proc) != null); IToken/*!*/ x;
+ List<TypeVariable>/*!*/ typeParams;
+ List<Variable>/*!*/ ins, outs;
+ List<Requires>/*!*/ pre = new List<Requires>();
+ List<IdentifierExpr>/*!*/ mods = new List<IdentifierExpr>();
+ List<Ensures>/*!*/ post = new List<Ensures>();
+
+ List<Variable>/*!*/ locals = new List<Variable>();
+ StmtList/*!*/ stmtList;
+ QKeyValue kv = null;
+ impl = null;
+ .)
+
+ "procedure"
+ ProcSignature<true, out x, out typeParams, out ins, out outs, out kv>
+ ( ";"
+ { Spec<pre, mods, post> }
+ | { Spec<pre, mods, post> }
+ ImplBody<out locals, out stmtList>
+ (.
+ 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<out Implementation/*!*/ impl>
+= (. Contract.Ensures(Contract.ValueAtReturn(out impl) != null); IToken/*!*/ x;
+ List<TypeVariable>/*!*/ typeParams;
+ List<Variable>/*!*/ ins, outs;
+ List<Variable>/*!*/ locals;
+ StmtList/*!*/ stmtList;
+ QKeyValue kv;
+ .)
+
+ "implementation"
+ ProcSignature<false, out x, out typeParams, out ins, out outs, out kv>
+ ImplBody<out locals, out stmtList>
+ (. impl = new Implementation(x, x.val, typeParams, ins, outs, locals, stmtList, kv, this.errors); .)
+ .
+
+
+ProcSignature<.bool allowWhereClausesOnFormals, out IToken/*!*/ name, out List<TypeVariable>/*!*/ typeParams,
+ out List<Variable>/*!*/ ins, out List<Variable>/*!*/ 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<TypeVariable>();
+ outs = new List<Variable>(); kv = null; .)
+ { Attribute<ref kv> }
+ Ident<out name>
+ [ TypeParams<out typeParamTok, out typeParams> ]
+ ProcFormals<true, allowWhereClausesOnFormals, out ins>
+ [ "returns" ProcFormals<false, allowWhereClausesOnFormals, out outs> ]
+ .
+
+
+Spec<.List<Requires>/*!*/ pre, List<IdentifierExpr>/*!*/ mods, List<Ensures>/*!*/ post.>
+= (.Contract.Requires(pre != null); Contract.Requires(mods != null); Contract.Requires(post != null); List<IToken>/*!*/ ms; .)
+ ( "modifies"
+ [ Idents<out ms> (. foreach(IToken/*!*/ m in ms){
+ Contract.Assert(m != null);
+ mods.Add(new IdentifierExpr(m, m.val));
+ }
+ .)
+ ] ";"
+ | "free" SpecPrePost<true, pre, post>
+ | SpecPrePost<false, pre, post>
+ )
+ .
+
+SpecPrePost<.bool free, List<Requires>/*!*/ pre, List<Ensures>/*!*/ post.>
+= (. Contract.Requires(pre != null); Contract.Requires(post != null); Expr/*!*/ e; Token tok = null; QKeyValue kv = null; .)
+ ( "requires" (. tok = t; .)
+ { Attribute<ref kv> }
+ Proposition<out e> ";" (. pre.Add(new Requires(tok, free, e, null, kv)); .)
+ | "ensures" (. tok = t; .)
+ { Attribute<ref kv> }
+ Proposition<out e> ";" (. post.Add(new Ensures(tok, free, e, null, kv)); .)
+ )
+ .
+
+/*------------------------------------------------------------------------*/
+
+ImplBody<.out List<Variable>/*!*/ locals, out StmtList/*!*/ stmtList.>
+= (. Contract.Ensures(Contract.ValueAtReturn(out locals) != null); Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); locals = new List<Variable>(); .)
+ "{"
+ { LocalVars<locals> }
+ StmtList<out stmtList>
+ .
+
+/* the StmtList also reads the final curly brace */
+StmtList<out StmtList/*!*/ stmtList>
+= (. Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); List<BigBlock/*!*/> bigblocks = new List<BigBlock/*!*/>();
+ /* built-up state for the current BigBlock: */
+ IToken startToken = null; string currentLabel = null;
+ List<Cmd> 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<out c, out label>
+ (. if (c != null) {
+ // LabelOrCmd read a Cmd
+ Contract.Assert(label == null);
+ if (startToken == null) { startToken = c.tok; cs = new List<Cmd>(); }
+ 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<Cmd>();
+ }
+ .)
+
+ | StructuredCmd<out ecn>
+ (. ec = ecn;
+ if (startToken == null) { startToken = ec.tok; cs = new List<Cmd>(); }
+ Contract.Assert(cs != null);
+ b = new BigBlock(startToken, currentLabel, cs, ec, null);
+ bigblocks.Add(b);
+ startToken = null; currentLabel = null; cs = null;
+ .)
+
+ | TransferCmd<out tcn>
+ (. tc = tcn;
+ if (startToken == null) { startToken = tc.tok; cs = new List<Cmd>(); }
+ 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<Cmd>();
+ }
+ if (startToken != null) {
+ Contract.Assert(cs != null);
+ b = new BigBlock(startToken, currentLabel, cs, null, null);
+ bigblocks.Add(b);
+ }
+
+ stmtList = new StmtList(bigblocks, endCurly);
+ .)
+ .
+
+TransferCmd<out TransferCmd/*!*/ tc>
+= (. Contract.Ensures(Contract.ValueAtReturn(out tc) != null); tc = dummyTransferCmd;
+ Token y; List<IToken>/*!*/ xs;
+ List<String> ss = new List<String>();
+ .)
+ ( "goto" (. y = t; .)
+ Idents<out xs> (. foreach(IToken/*!*/ s in xs){
+ Contract.Assert(s != null);
+ ss.Add(s.val); }
+ tc = new GotoCmd(y, ss);
+ .)
+ | "return" (. tc = new ReturnCmd(t); .)
+ ) ";"
+ .
+
+StructuredCmd<out StructuredCmd/*!*/ ec>
+= (. Contract.Ensures(Contract.ValueAtReturn(out ec) != null); ec = dummyStructuredCmd; Contract.Assume(cce.IsPeerConsistent(ec));
+ IfCmd/*!*/ ifcmd; WhileCmd/*!*/ wcmd; BreakCmd/*!*/ bcmd;
+ .)
+ ( IfCmd<out ifcmd> (. ec = ifcmd; .)
+ | WhileCmd<out wcmd> (. ec = wcmd; .)
+ | BreakCmd<out bcmd> (. ec = bcmd; .)
+ )
+ .
+
+IfCmd<out IfCmd/*!*/ 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<out guard>
+ "{" StmtList<out thn>
+ [ "else"
+ ( IfCmd<out elseIf> (. elseIfOption = elseIf; .)
+ | "{"
+ StmtList<out els> (. elseOption = els; .)
+ )
+ ]
+ (. ifcmd = new IfCmd(x, guard, thn, elseIfOption, elseOption); .)
+ .
+
+WhileCmd<out WhileCmd/*!*/ wcmd>
+= (. Contract.Ensures(Contract.ValueAtReturn(out wcmd) != null); IToken/*!*/ x; Token z;
+ Expr guard; Expr/*!*/ e; bool isFree;
+ List<PredicateCmd/*!*/> invariants = new List<PredicateCmd/*!*/>();
+ StmtList/*!*/ body;
+ QKeyValue kv = null;
+ .)
+ "while" (. x = t; .)
+ Guard<out guard> (. Contract.Assume(guard == null || cce.Owner.None(guard)); .)
+ { (. isFree = false; z = la/*lookahead token*/; .)
+ [ "free" (. isFree = true; .)
+ ]
+ "invariant"
+ { Attribute<ref kv> }
+ Expression<out e> (. if (isFree) {
+ invariants.Add(new AssumeCmd(z, e, kv));
+ } else {
+ invariants.Add(new AssertCmd(z, e, kv));
+ }
+ kv = null;
+ .)
+ ";"
+ }
+ "{"
+ StmtList<out body> (. wcmd = new WhileCmd(x, guard, invariants, body); .)
+ .
+
+Guard<out Expr e>
+= (. Expr/*!*/ ee; e = null; .)
+ "("
+ ( "*" (. e = null; .)
+ | Expression<out ee> (. e = ee; .)
+ )
+ ")"
+ .
+
+BreakCmd<out BreakCmd/*!*/ bcmd>
+= (.Contract.Ensures(Contract.ValueAtReturn(out bcmd) != null); IToken/*!*/ x; IToken/*!*/ y;
+ string breakLabel = null;
+ .)
+ "break" (. x = t; .)
+ [ Ident<out y> (. breakLabel = y.val; .)
+ ] ";" (. bcmd = new BreakCmd(x, breakLabel); .)
+ .
+
+/*------------------------------------------------------------------------*/
+
+LabelOrCmd<out Cmd c, out IToken label>
+/* ensures (c == null) != (label != null) */
+= (. IToken/*!*/ x; Expr/*!*/ e;
+ List<IToken>/*!*/ xs;
+ List<IdentifierExpr> ids;
+ c = dummyCmd; label = null;
+ Cmd/*!*/ cn;
+ QKeyValue kv = null;
+ .)
+ ( LabelOrAssign<out c, out label>
+ | "assert" (. x = t; .)
+ { Attribute<ref kv> }
+ Proposition<out e> (. c = new AssertCmd(x, e, kv); .)
+ ";"
+ | "assume" (. x = t; .)
+ { Attribute<ref kv> }
+ Proposition<out e> (. c = new AssumeCmd(x, e, kv); .)
+ ";"
+ | "havoc" (. x = t; .)
+ Idents<out xs> ";" (. ids = new List<IdentifierExpr>();
+ foreach(IToken/*!*/ y in xs){
+ Contract.Assert(y != null);
+ ids.Add(new IdentifierExpr(y, y.val));
+ }
+ c = new HavocCmd(x,ids);
+ .)
+ | CallCmd<out cn> ";" (. c = cn; .)
+ | ParCallCmd<out cn> (. c = cn; .)
+ | "yield" (. x = t; .)
+ ";" (. c = new YieldCmd(x); .)
+ )
+ .
+
+/*------------------------------------------------------------------------*/
+
+LabelOrAssign<out Cmd c, out IToken label>
+/* ensures (c == null) != (label != null) */
+= (. IToken/*!*/ id; IToken/*!*/ x, y; Expr/*!*/ e0;
+ c = dummyCmd; label = null;
+ AssignLhs/*!*/ lhs;
+ List<AssignLhs/*!*/>/*!*/ lhss;
+ List<Expr/*!*/>/*!*/ rhss;
+ List<Expr/*!*/>/*!*/ indexes;
+ .)
+ Ident<out id> (. x = t; .)
+ ( ":" (. c = null; label = x; .)
+
+ | (. lhss = new List<AssignLhs/*!*/>(); .)
+ (. lhs = new SimpleAssignLhs(id, new IdentifierExpr(id, id.val)); .)
+
+ { MapAssignIndex<out y, out indexes> (. lhs = new MapAssignLhs(y, lhs, indexes); .) }
+ (. lhss.Add(lhs); .)
+
+ { ","
+ Ident<out id>
+ (. lhs = new SimpleAssignLhs(id, new IdentifierExpr(id, id.val)); .)
+ { MapAssignIndex<out y, out indexes> (. lhs = new MapAssignLhs(y, lhs, indexes); .) }
+ (. lhss.Add(lhs); .)
+ }
+
+ ":=" (. x = t; /* use location of := */ .)
+ Expression<out e0> (. rhss = new List<Expr/*!*/> ();
+ rhss.Add(e0); .)
+ { ","
+ Expression<out e0> (. rhss.Add(e0); .)
+ }
+ ";" (. c = new AssignCmd(x, lhss, rhss); .)
+ )
+ .
+
+MapAssignIndex<.out IToken/*!*/ x, out List<Expr/*!*/>/*!*/ indexes.>
+= (.Contract.Ensures(Contract.ValueAtReturn(out x) != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out indexes))); indexes = new List<Expr/*!*/> ();
+ Expr/*!*/ e;
+ .)
+ "[" (. x = t; .)
+ [
+ Expression<out e> (. indexes.Add(e); .)
+ { ","
+ Expression<out e> (. indexes.Add(e); .)
+ }
+ ]
+ "]"
+ .
+
+/*------------------------------------------------------------------------*/
+CallCmd<out Cmd c>
+= (. 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<ref kv> }
+ CallParams<isAsync, isFree, kv, x, out c> (. .)
+ .
+
+ParCallCmd<out Cmd d>
+= (. Contract.Ensures(Contract.ValueAtReturn(out d) != null);
+ IToken x;
+ QKeyValue kv = null;
+ Cmd c = null;
+ List<CallCmd> callCmds = new List<CallCmd>();
+ .)
+ "par" (. x = t; .)
+ { Attribute<ref kv> }
+ CallParams<false, false, kv, x, out c> (. callCmds.Add((CallCmd)c); .)
+ { "|" CallParams<false, false, kv, x, out c> (. callCmds.Add((CallCmd)c); .)
+ }
+ ";" (. d = new ParCallCmd(x, callCmds, kv); .)
+ .
+
+CallParams<bool isAsync, bool isFree, QKeyValue kv, IToken x, out Cmd c>
+= (.
+ List<IdentifierExpr> ids = new List<IdentifierExpr>();
+ List<Expr> es = new List<Expr>();
+ Expr en;
+ IToken first;
+ IToken p;
+ c = null;
+ .)
+ Ident<out first>
+ ( "("
+ [ Expression<out en> (. es.Add(en); .)
+ { "," Expression<out en> (. 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<out p> (. ids.Add(new IdentifierExpr(p, p.val)); .)
+ { "," Ident<out p> (. ids.Add(new IdentifierExpr(p, p.val)); .)
+ }
+ ] ":="
+ Ident<out first> "("
+ [ Expression<out en> (. es.Add(en); .)
+ { "," Expression<out en> (. es.Add(en); .)
+ }
+ ]
+ ")" (. c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync; .)
+ )
+ .
+
+/*------------------------------------------------------------------------*/
+Proposition<out Expr/*!*/ e>
+=(.Contract.Ensures(Contract.ValueAtReturn(out e) != null);.)
+ Expression<out e>
+ .
+
+/*------------------------------------------------------------------------*/
+Idents<.out List<IToken>/*!*/ xs.>
+= (.Contract.Ensures(Contract.ValueAtReturn(out xs) != null); IToken/*!*/ id; xs = new List<IToken>(); .)
+ Ident<out id> (. xs.Add(id); .)
+ { "," Ident<out id> (. xs.Add(id); .)
+ }
+ .
+
+/*------------------------------------------------------------------------*/
+WhiteSpaceIdents<.out List<IToken>/*!*/ xs.>
+= (. Contract.Ensures(Contract.ValueAtReturn(out xs) != null); IToken/*!*/ id; xs = new List<IToken>(); .)
+ Ident<out id> (. xs.Add(id); .)
+ { Ident<out id> (. xs.Add(id); .)
+ }
+ .
+
+/*------------------------------------------------------------------------*/
+Expressions<.out List<Expr>/*!*/ es.>
+= (. Contract.Ensures(Contract.ValueAtReturn(out es) != null); Expr/*!*/ e; es = new List<Expr>(); .)
+ Expression<out e> (. es.Add(e); .)
+ { "," Expression<out e> (. es.Add(e); .)
+ }
+ .
+
+/*------------------------------------------------------------------------*/
+Expression<.out Expr/*!*/ e0.>
+= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .)
+ ImpliesExpression<false, out e0>
+ { EquivOp (. x = t; .)
+ ImpliesExpression<false, out e1>
+ (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Iff, e0, e1); .)
+ }
+ .
+
+EquivOp = "<==>" | '\u21d4'.
+
+/*------------------------------------------------------------------------*/
+ImpliesExpression<bool noExplies, out Expr/*!*/ e0>
+= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .)
+ LogicalExpression<out e0>
+ [
+ ImpliesOp (. x = t; .)
+ /* recurse because implication is right-associative */
+ ImpliesExpression<true, out e1>
+ (. 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<out e1>
+ (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e1, e0); .)
+ /* loop because explies is left-associative */
+ {
+ ExpliesOp (. x = t; .)
+ LogicalExpression<out e1>
+ (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e1, e0); .)
+ }
+ ]
+ .
+
+ImpliesOp = "==>" | '\u21d2'.
+ExpliesOp = "<==" | '\u21d0'.
+
+/*------------------------------------------------------------------------*/
+LogicalExpression<out Expr/*!*/ e0>
+= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .)
+ RelationalExpression<out e0>
+ [ AndOp (. x = t; .)
+ RelationalExpression<out e1>
+ (. e0 = Expr.Binary(x, BinaryOperator.Opcode.And, e0, e1); .)
+ { AndOp (. x = t; .)
+ RelationalExpression<out e1>
+ (. e0 = Expr.Binary(x, BinaryOperator.Opcode.And, e0, e1); .)
+ }
+ | OrOp (. x = t; .)
+ RelationalExpression<out e1>
+ (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Or, e0, e1); .)
+ { OrOp (. x = t; .)
+ RelationalExpression<out e1>
+ (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Or, e0, e1); .)
+ }
+ ]
+ .
+
+AndOp = "&&" | '\u2227'.
+OrOp = "||" | '\u2228'.
+
+/*------------------------------------------------------------------------*/
+RelationalExpression<out Expr/*!*/ e0>
+= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .)
+ BvTerm<out e0>
+ [ RelOp<out x, out op>
+ BvTerm<out e1> (. e0 = Expr.Binary(x, op, e0, e1); .)
+ ]
+ .
+
+RelOp<out IToken/*!*/ x, out BinaryOperator.Opcode op>
+= (.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<out Expr/*!*/ e0>
+= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .)
+ Term<out e0>
+ { "++" (. x = t; .)
+ Term<out e1> (. e0 = new BvConcatExpr(x, e0, e1); .)
+ }
+ .
+
+
+/*------------------------------------------------------------------------*/
+Term<out Expr/*!*/ e0>
+= (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .)
+ Factor<out e0>
+ { AddOp<out x, out op>
+ Factor<out e1> (. e0 = Expr.Binary(x, op, e0, e1); .)
+ }
+ .
+
+AddOp<out IToken/*!*/ x, out BinaryOperator.Opcode op>
+= (.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<out Expr/*!*/ e0>
+= (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .)
+ Power<out e0>
+ { MulOp<out x, out op>
+ Power<out e1> (. e0 = Expr.Binary(x, op, e0, e1); .)
+ }
+ .
+
+MulOp<out IToken/*!*/ x, out BinaryOperator.Opcode op>
+= (. 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<out Expr/*!*/ e0>
+= (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .)
+ UnaryExpression<out e0>
+ [
+ "**" (. x = t; .)
+ /* recurse because exponentation is right-associative */
+ Power<out e1> (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Pow, e0, e1); .)
+ ]
+ .
+
+/*------------------------------------------------------------------------*/
+UnaryExpression<out Expr/*!*/ e>
+= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x;
+ e = dummyExpr;
+ .)
+ ( "-" (. x = t; .)
+ UnaryExpression<out e> (. e = Expr.Unary(x, UnaryOperator.Opcode.Neg, e); .)
+ | NegOp (. x = t; .)
+ UnaryExpression<out e> (. e = Expr.Unary(x, UnaryOperator.Opcode.Not, e); .)
+ | CoercionExpression<out e>
+ )
+ .
+
+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<out Expr/*!*/ e>
+= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x;
+ Bpl.Type/*!*/ coercedTo;
+ BigNum bn;
+ .)
+ ArrayExpression<out e>
+ { ":" (. x = t; .)
+ (
+ Type<out coercedTo> (. e = Expr.CoerceType(x, e, coercedTo); .)
+ |
+ Nat<out bn> /* 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<out Expr/*!*/ e>
+= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x;
+ Expr/*!*/ index0 = dummyExpr; Expr/*!*/ e1;
+ bool store; bool bvExtract;
+ List<Expr>/*!*/ allArgs = dummyExprSeq;
+ .)
+ AtomExpression<out e>
+ { "[" (. x = t; allArgs = new List<Expr> ();
+ allArgs.Add(e);
+ store = false; bvExtract = false; .)
+ [
+ Expression<out index0>
+ (. if (index0 is BvBounds)
+ bvExtract = true;
+ else
+ allArgs.Add(index0);
+ .)
+ { "," Expression<out e1>
+ (. if (bvExtract || e1 is BvBounds)
+ this.SemErr("bitvectors only have one dimension");
+ allArgs.Add(e1);
+ .)
+ }
+ [ ":=" Expression<out e1>
+ (. if (bvExtract || e1 is BvBounds)
+ this.SemErr("assignment to bitvectors is not possible");
+ allArgs.Add(e1); store = true;
+ .)
+ ]
+ | ":=" Expression<out e1> (. 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<out Expr/*!*/ e>
+= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; int n; BigNum bn; BigDec bd;
+ List<Expr>/*!*/ es; List<Variable>/*!*/ ds; Trigger trig;
+ List<TypeVariable>/*!*/ typeParams;
+ IdentifierExpr/*!*/ id;
+ QKeyValue kv;
+ e = dummyExpr;
+ List<Variable>/*!*/ locals;
+ List<Block/*!*/>/*!*/ blocks;
+ .)
+ ( "false" (. e = new LiteralExpr(t, false); .)
+ | "true" (. e = new LiteralExpr(t, true); .)
+ | Nat<out bn> (. e = new LiteralExpr(t, bn); .)
+ | Dec<out bd> (. e = new LiteralExpr(t, bd); .)
+ | BvLit<out bn, out n> (. e = new LiteralExpr(t, bn, n); .)
+
+ | Ident<out x> (. id = new IdentifierExpr(x, x.val); e = id; .)
+ [ "("
+ ( Expressions<out es> (. e = new NAryExpr(x, new FunctionCall(id), es); .)
+ | /* empty */ (. e = new NAryExpr(x, new FunctionCall(id), new List<Expr>()); .)
+ )
+ ")"
+ ]
+
+ | "old" (. x = t; .)
+ "("
+ Expression<out e>
+ ")" (. e = new OldExpr(x, e); .)
+
+ | "int" (. x = t; .)
+ "("
+ Expression<out e>
+ ")" (. e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToInt), new List<Expr>{ e }); .)
+
+ | "real" (. x = t; .)
+ "("
+ Expression<out e>
+ ")" (. e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToReal), new List<Expr>{ e }); .)
+
+ | "(" ( Expression<out e> (. if (e is BvBounds)
+ this.SemErr("parentheses around bitvector bounds " +
+ "are not allowed"); .)
+ | Forall (. x = t; .)
+ QuantifierBody<x, out typeParams, out ds, out kv, out trig, out e>
+ (. if (typeParams.Count + ds.Count > 0)
+ e = new ForallExpr(x, typeParams, ds, kv, trig, e); .)
+ | Exists (. x = t; .)
+ QuantifierBody<x, out typeParams, out ds, out kv, out trig, out e>
+ (. if (typeParams.Count + ds.Count > 0)
+ e = new ExistsExpr(x, typeParams, ds, kv, trig, e); .)
+ | Lambda (. x = t; .)
+ QuantifierBody<x, out typeParams, out ds, out kv, out trig, out e>
+ (. 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<out e>
+ | CodeExpression<out locals, out blocks> (. e = new CodeExpr(locals, blocks); .)
+ )
+ .
+
+CodeExpression<.out List<Variable>/*!*/ locals, out List<Block/*!*/>/*!*/ blocks.>
+= (. Contract.Ensures(Contract.ValueAtReturn(out locals) != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out blocks))); locals = new List<Variable>(); Block/*!*/ b;
+ blocks = new List<Block/*!*/>();
+ .)
+ "|{"
+ { LocalVars<locals> }
+ SpecBlock<out b> (. blocks.Add(b); .)
+ { SpecBlock<out b> (. blocks.Add(b); .)
+ }
+ "}|"
+ .
+
+SpecBlock<out Block/*!*/ b>
+= (. Contract.Ensures(Contract.ValueAtReturn(out b) != null); IToken/*!*/ x; IToken/*!*/ y;
+ Cmd c; IToken label;
+ List<Cmd> cs = new List<Cmd>();
+ List<IToken>/*!*/ xs;
+ List<String> ss = new List<String>();
+ b = dummyBlock;
+ Expr/*!*/ e;
+ .)
+ Ident<out x> ":"
+ { LabelOrCmd<out c, out label>
+ (. 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<out xs> (. 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<out e>
+ (. b = new Block(x,x.val,cs,new ReturnExprCmd(t,e)); .)
+ )
+ ";"
+ .
+
+Attribute<ref QKeyValue kv>
+= (. Trigger trig = null; .)
+ AttributeOrTrigger<ref kv, ref trig> (. if (trig != null) this.SemErr("only attributes, not triggers, allowed here"); .)
+.
+
+AttributeOrTrigger<ref QKeyValue kv, ref Trigger trig>
+= (. IToken/*!*/ tok; Expr/*!*/ e; List<Expr>/*!*/ es;
+ string key;
+ List<object/*!*/> parameters; object/*!*/ param;
+ .)
+ "{" (. tok = t; .)
+ (
+ ":" ident (. key = t.val; parameters = new List<object/*!*/>(); .)
+ [ AttributeParameter<out param> (. parameters.Add(param); .)
+ { "," AttributeParameter<out param> (. 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<Expr> { e }, null);
+ } else {
+ trig.AddLast(new Trigger(tok, false, new List<Expr> { 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<out e> (. es = new List<Expr> { e }; .)
+ { "," Expression<out e> (. es.Add(e); .)
+ } (. if (trig==null) {
+ trig = new Trigger(tok, true, es, null);
+ } else {
+ trig.AddLast(new Trigger(tok, true, es, null));
+ }
+ .)
+ )
+ "}"
+ .
+
+AttributeParameter<out object/*!*/ o>
+= (. Contract.Ensures(Contract.ValueAtReturn(out o) != null);
+ o = "error";
+ Expr/*!*/ e;
+ .)
+ ( string (. o = t.val.Substring(1, t.val.Length-2); .)
+ | Expression<out e> (. o = e; .)
+ )
+ .
+
+IfThenElseExpression<out Expr/*!*/ e>
+= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null);
+ IToken/*!*/ tok;
+ Expr/*!*/ e0, e1, e2;
+ e = dummyExpr; .)
+ "if" (. tok = t; .) Expression<out e0> "then" Expression<out e1> "else" Expression<out e2>
+ (. e = new NAryExpr(tok, new IfThenElse(tok), new List<Expr>{ e0, e1, e2 }); .)
+ .
+
+
+QuantifierBody<.IToken/*!*/ q, out List<TypeVariable>/*!*/ typeParams, out List<Variable>/*!*/ 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<TypeVariable> ();
+ IToken/*!*/ tok;
+ kv = null;
+ ds = new List<Variable> ();
+ .)
+ (
+ TypeParams<out tok, out typeParams>
+ [ BoundVars<q, out ds> ]
+ |
+ BoundVars<q, out ds>
+ )
+ QSep
+ { AttributeOrTrigger<ref kv, ref trig> }
+ Expression<out body>
+ .
+
+Forall = "forall" | '\u2200'.
+Exists = "exists" | '\u2203'.
+Lambda = "lambda" | '\u03bb'.
+QSep = "::" | '\u2022'.
+
+/*------------------------------------------------------------------------*/
+Ident<out IToken/*!*/ x>
+=(.Contract.Ensures(Contract.ValueAtReturn(out x) != null);.)
+ ident (. x = t;
+ if (x.val.StartsWith("\\"))
+ x.val = x.val.Substring(1);
+ .)
+ .
+
+/*------------------------------------------------------------------------*/
+Nat<out BigNum n>
+=
+ digits
+ (. try {
+ n = BigNum.FromString(t.val);
+ } catch (FormatException) {
+ this.SemErr("incorrectly formatted number");
+ n = BigNum.ZERO;
+ }
+ .)
+ .
+
+/*------------------------------------------------------------------------*/
+Dec<out BigDec n>
+= (. 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<out BigNum n, out int m>
+=
+ 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<string>() != null);
- return this._environment;
- }
- set {
- Contract.Requires(value != null);
- this._environment = value;
- }
- }
-
- private readonly List<string/*!*/>/*!*/ _files = new List<string/*!*/>();
-
- public IList<string/*!*/>/*!*/ Files {
- get {
- Contract.Ensures(cce.NonNullElements(Contract.Result<IList<string>>()));
- Contract.Ensures(Contract.Result<IList<string>>().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<string>() != 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<string>() != null);
- return " version " + VersionNumber + ", Copyright (c) 2003-2014, Microsoft.";
- }
- }
- public virtual string/*!*/ Version {
- get {
- Contract.Ensures(Contract.Result<string>() != null);
- return DescriptiveToolName + VersionSuffix;
- }
- }
-
- private string/*!*/ _fileTimestamp = cce.NonNull(DateTime.Now.ToString("o")).Replace(':', '.');
-
- public string FileTimestamp {
- get {
- Contract.Ensures(Contract.Result<string>() != 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);
- }
- }
-
- /// <summary>
- /// Process the option and modify "ps" accordingly.
- /// Return true if the option is one that is recognized.
- /// </summary>
- 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);
- }
-
- /// <summary>
- /// 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".
- /// </summary>
- public bool GetNumericArgument(ref int arg) {
- //modifies nextIndex, encounteredErrors, Console.Error.*;
- return GetNumericArgument(ref arg, a => 0 <= a);
- }
-
- /// <summary>
- /// 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".
- /// </summary>
- public bool GetNumericArgument(ref int arg, Predicate<int> 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;
- }
-
- /// <summary>
- /// 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".
- /// </summary>
- 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;
- }
- }
-
- /// <summary>
- /// 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".
- /// </summary>
- 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<bool>() == (!(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 <option> is one of
-
- ---- General options -------------------------------------------------------
-
- /help this message
- /attrHelp print a message about declaration attributes supported by
- this implementation");
- }
-
- public virtual void AttributeUsage() {
- }
-
- /// <summary>
- /// This method is called after all parsing is done, if no parse errors were encountered.
- /// </summary>
- public virtual void ApplyDefaultOptions() {
- }
-
- /// <summary>
- /// Parses the command-line arguments "args" into the global flag variables. Returns true
- /// if there were no errors.
- /// </summary>
- /// <param name="args">Consumed ("captured" and possibly modified) by the method.</param>
- public bool Parse([Captured] string[]/*!*/ args) {
- Contract.Requires(cce.NonNullElements(args));
-
- // save the command line options for the log files
- Environment += "Command Line Options: " + args.Concat(" ");
- args = cce.NonNull((string[])args.Clone()); // the operations performed may mutate the array, so make a copy
- var ps = new CommandLineParseState(args, ToolName);
-
- while (ps.i < args.Length) {
- cce.LoopInvariant(ps.args == args);
- string arg = args[ps.i];
- Contract.Assert(arg != null);
- ps.s = arg.Trim();
-
- bool isOption = ps.s.StartsWith("-") || ps.s.StartsWith("/");
- int colonIndex = ps.s.IndexOf(':');
- if (0 <= colonIndex && isOption) {
- ps.hasColonArgument = true;
- args[ps.i] = ps.s.Substring(colonIndex + 1);
- ps.s = ps.s.Substring(0, colonIndex);
- } else {
- ps.i++;
- ps.hasColonArgument = false;
- }
- ps.nextIndex = ps.i;
-
- if (isOption) {
- if (!ParseOption(ps.s.Substring(1), ps)) {
- if (Path.DirectorySeparatorChar == '/' && ps.s.StartsWith("/"))
- this._files.Add(arg);
- else
- ps.Error("unknown switch: {0}", ps.s);
- }
- } else {
- this._files.Add(arg);
- }
-
- ps.i = ps.nextIndex;
- }
-
- if (HelpRequested) {
- Usage();
- } else if (AttrHelpRequested) {
- AttributeUsage();
- } else if (ps.EncounteredErrors) {
- Console.WriteLine("Use /help for available options");
- }
-
- if (ps.EncounteredErrors) {
- return false;
- } else {
- this.ApplyDefaultOptions();
- return true;
- }
- }
-
- }
-
- /// <summary>
- /// Boogie command-line options (other tools can subclass this class in order to support a
- /// superset of Boogie's options.
- /// </summary>
- public class CommandLineOptions : CommandLineOptionEngine {
-
- public CommandLineOptions()
- : base("Boogie", "Boogie program verifier") {
- }
-
- protected CommandLineOptions(string toolName, string descriptiveName)
- : base(toolName, descriptiveName) {
- Contract.Requires(toolName != null);
- Contract.Requires(descriptiveName != null);
- }
-
- private static CommandLineOptions clo;
- public static CommandLineOptions/*!*/ Clo
- {
- get { return clo; }
- }
-
- public static void Install(CommandLineOptions options) {
- Contract.Requires(options != null);
- clo = options;
- }
-
- public const long Megabyte = 1048576;
-
- // Flags and arguments
-
- public bool RunningBoogieFromCommandLine = false; // "false" means running Boogie from the plug-in
-
- [ContractInvariantMethod]
- void ObjectInvariant2() {
- Contract.Invariant(LogPrefix != null);
- Contract.Invariant(0 <= PrintUnstructured && PrintUnstructured < 3); // 0 = print only structured, 1 = both structured and unstructured, 2 = only unstructured
- }
-
- public int VerifySnapshots = -1;
- public bool VerifySeparately = false;
- public string PrintFile = null;
- public int PrintUnstructured = 0;
- public bool UseBaseNameForFileName = false;
- public int DoomStrategy = -1;
- public bool DoomRestartTP = false;
- public bool PrintDesugarings = false;
- public string SimplifyLogFilePath = null;
- public bool PrintInstrumented = false;
- public bool InstrumentWithAsserts = false;
- public enum InstrumentationPlaces {
- LoopHeaders,
- Everywhere
- }
- public InstrumentationPlaces InstrumentInfer = InstrumentationPlaces.LoopHeaders;
- public bool PrintWithUniqueASTIds = false;
- private string XmlSinkFilename = null;
- [Peer]
- public XmlSink XmlSink = null;
- public bool Wait = false;
- public bool Trace = false;
- public bool TraceTimes = false;
- public bool TraceProofObligations = false;
- public bool TraceCachingForTesting
- {
- get
- {
- return TraceCaching == 1 || TraceCaching == 3;
- }
- }
- public bool TraceCachingForBenchmarking
- {
- get
- {
- return TraceCaching == 2 || TraceCaching == 3;
- }
- }
- public bool TraceCachingForDebugging
- {
- get
- {
- return TraceCaching == 3;
- }
- }
- internal int TraceCaching = 0;
- public bool NoResolve = false;
- public bool NoTypecheck = false;
- public bool OverlookBoogieTypeErrors = false;
- public bool Verify = true;
- public bool TraceVerify = false;
- public int /*(0:3)*/ ErrorTrace = 1;
- public bool IntraproceduralInfer = true;
- public bool ContractInfer = false;
- public bool ExplainHoudini = false;
- public bool ReverseHoudiniWorklist = false;
- public bool ConcurrentHoudini = false;
- public bool ModifyTopologicalSorting = false;
- public bool DebugConcurrentHoudini = false;
- public bool HoudiniUseCrossDependencies = false;
- public string StagedHoudini = null;
- public bool DebugStagedHoudini = false;
- public bool StagedHoudiniReachabilityAnalysis = false;
- public bool StagedHoudiniMergeIgnoredAnnotations = false;
- public int StagedHoudiniThreads = 1;
- public string VariableDependenceIgnore = null;
- public string AbstractHoudini = null;
- public bool UseUnsatCoreForContractInfer = false;
- public bool PrintAssignment = false;
- public int InlineDepth = -1;
- public bool UseProverEvaluate = false; // Use ProverInterface's Evaluate method, instead of model to get variable values
- public bool UseUncheckedContracts = false;
- public bool SimplifyLogFileAppend = false;
- public bool SoundnessSmokeTest = false;
- public string Z3ExecutablePath = null;
- public string CVC4ExecutablePath = null;
- public int KInductionDepth = -1;
-
- private string/*!*/ _logPrefix = "";
-
- public string LogPrefix {
- get {
- Contract.Ensures(Contract.Result<string>() != null);
- return this._logPrefix;
- }
- set {
- Contract.Requires(value != null);
- this._logPrefix = value;
- }
- }
-
- public bool PrettyPrint = true;
-
- public enum ProverWarnings {
- None,
- Stdout,
- Stderr
- }
- public ProverWarnings PrintProverWarnings = ProverWarnings.None;
- public int ProverShutdownLimit = 0;
-
- public enum SubsumptionOption {
- Never,
- NotForQuantifiers,
- Always
- }
- public SubsumptionOption UseSubsumption = SubsumptionOption.Always;
-
- public bool AlwaysAssumeFreeLoopInvariants = false;
-
- public enum ShowEnvironment {
- Never,
- DuringPrint,
- Always
- }
- public ShowEnvironment ShowEnv = ShowEnvironment.DuringPrint;
- public bool DontShowLogo = false;
- [ContractInvariantMethod]
- void ObjectInvariant3() {
- Contract.Invariant(-1 <= LoopFrameConditions && LoopFrameConditions < 3);
- Contract.Invariant(0 <= ModifiesDefault && ModifiesDefault < 7);
- Contract.Invariant((0 <= PrintErrorModel && PrintErrorModel <= 2) || PrintErrorModel == 4);
- Contract.Invariant(0 <= EnhancedErrorMessages && EnhancedErrorMessages < 2);
- Contract.Invariant(0 <= StepsBeforeWidening && StepsBeforeWidening <= 9);
- Contract.Invariant(-1 <= this.bracketIdsInVC && this.bracketIdsInVC <= 1);
- Contract.Invariant(cce.NonNullElements(this.proverOptions));
- }
-
- public int LoopUnrollCount = -1; // -1 means don't unroll loops
- public bool SoundLoopUnrolling = false;
- public int LoopFrameConditions = -1; // -1 means not specified -- this will be replaced by the "implications" section below
- public int ModifiesDefault = 5;
- public bool LocalModifiesChecks = true;
- public bool NoVerifyByDefault = false;
- public enum OwnershipModelOption {
- Standard,
- Experimental,
- Trivial
- }
- public OwnershipModelOption OwnershipModelEncoding = OwnershipModelOption.Standard;
- public int PrintErrorModel = 0;
- public string PrintErrorModelFile = null;
- public string/*?*/ ModelViewFile = null;
- public int EnhancedErrorMessages = 0;
- public string PrintCFGPrefix = null;
- public bool ForceBplErrors = false; // if true, boogie error is shown even if "msg" attribute is present
- public bool UseArrayTheory = false;
- public bool UseSmtOutputFormat = false;
- public bool WeakArrayTheory = false;
- public bool UseLabels = true;
- public bool SIBoolControlVC = false;
- public bool MonomorphicArrays {
- get {
- return UseArrayTheory || TypeEncodingMethod == TypeEncoding.Monomorphic;
- }
- }
- public bool ExpandLambdas = true; // not useful from command line, only to be set to false programatically
- public bool DoModSetAnalysis = false;
- public bool UseAbstractInterpretation = true; // true iff the user want to use abstract interpretation
- private int /*0..9*/stepsBeforeWidening = 0; // The number of steps that must be done before applying a widen operator
-
- public int StepsBeforeWidening
- {
- get
- {
- Contract.Ensures(0 <= Contract.Result<int>() && Contract.Result<int>() <= 9);
- return this.stepsBeforeWidening;
- }
- set
- {
- Contract.Requires(0 <= value && value <= 9);
- this.stepsBeforeWidening = value;
- }
- }
-
- public string OwickiGriesDesugaredOutputFile = null;
- public bool TrustAtomicityTypes = false;
- public bool TrustNonInterference = false;
- public int TrustLayersUpto = -1;
- public int TrustLayersDownto = int.MaxValue;
-
- public enum VCVariety {
- Structured,
- Block,
- Local,
- BlockNested,
- BlockReach,
- BlockNestedReach,
- Dag,
- DagIterative,
- Doomed,
- Unspecified
- }
- public VCVariety vcVariety = VCVariety.Unspecified; // will not be Unspecified after command line has been parsed
-
- public bool RemoveEmptyBlocks = true;
- public bool CoalesceBlocks = true;
- public bool PruneInfeasibleEdges = true;
-
- [Rep]
- public ProverFactory TheProverFactory;
- public string ProverName;
- [Peer]
- private List<string> proverOptions = new List<string>();
-
- public IEnumerable<string> ProverOptions
- {
- set
- {
- Contract.Requires(cce.NonNullElements(value));
-
- this.proverOptions = new List<string>(value);
- }
- get
- {
- Contract.Ensures(cce.NonNullElements(Contract.Result<IEnumerable<string>>()));
-
- foreach (string s in this.proverOptions)
- yield return s;
- }
- }
-
- [Obsolete("use the setter for 'ProverOptions' directly")]
- public void AddProverOption(string option)
- {
- Contract.Requires(option != null);
-
- this.ProverOptions = this.ProverOptions.Concat1(option);
- }
-
- [Obsolete("use the setter for 'ProverOptions' directly")]
- public void RemoveAllProverOptions(Predicate<string> match)
- {
- this.ProverOptions = this.ProverOptions.Where(s => !match(s));
- }
-
- private int bracketIdsInVC = -1; // -1 - not specified, 0 - no, 1 - yes
-
- public int BracketIdsInVC {
- get {
- Contract.Ensures(-1 <= Contract.Result<int>() && Contract.Result<int>() <= 1);
- return this.bracketIdsInVC;
- }
- set {
- Contract.Requires(-1 <= value && value <= 1);
- this.bracketIdsInVC = value;
- }
- }
-
- public bool CausalImplies = false;
-
- public int SimplifyProverMatchDepth = -1; // -1 means not specified
- public int ProverKillTime = -1; // -1 means not specified
- public int SmokeTimeout = 10; // default to 10s
- public int ProverCCLimit = 5;
- public bool z3AtFlag = true;
- public bool RestartProverPerVC = false;
-
- public double VcsMaxCost = 1.0;
- public double VcsPathJoinMult = 0.8;
- public double VcsPathCostMult = 1.0;
- public double VcsAssumeMult = 0.01;
- public double VcsPathSplitMult = 0.5; // 0.5-always, 2-rarely do path splitting
- public int VcsMaxSplits = 1;
- public int VcsMaxKeepGoingSplits = 1;
- public int VcsFinalAssertTimeout = 30;
- public int VcsKeepGoingTimeout = 1;
- public int VcsCores = 1;
- public bool VcsDumpSplits = false;
-
- public bool DebugRefuted = false;
-
- public XmlSink XmlRefuted {
- get {
- if (DebugRefuted)
- return XmlSink;
- else
- return null;
- }
- }
- [ContractInvariantMethod]
- void ObjectInvariant4() {
- Contract.Invariant(cce.NonNullElements(this.z3Options));
- Contract.Invariant(0 <= Z3lets && Z3lets < 4);
- }
-
- [Peer]
- private List<string> z3Options = new List<string>();
-
- public IEnumerable<string> Z3Options
- {
- get
- {
- Contract.Ensures(Contract.Result<IEnumerable<string>>() != null);
- foreach (string s in z3Options)
- yield return s;
- }
- }
-
- public void AddZ3Option(string option)
- {
- Contract.Requires(option != null);
- this.z3Options.Add(option);
- }
-
- public bool Z3types = false;
- public int Z3lets = 3; // 0 - none, 1 - only LET TERM, 2 - only LET FORMULA, 3 - (default) any
-
-
- // Maximum amount of virtual memory (in bytes) for the prover to use
- //
- // Non-positive number indicates unbounded.
- public long MaxProverMemory = 100 * Megabyte;
-
- // Minimum number of prover calls before restart
- public int MinNumOfProverCalls = 5;
-
- public enum PlatformType {
- notSpecified,
- v1,
- v11,
- v2,
- cli1
- }
- public PlatformType TargetPlatform;
- public string TargetPlatformLocation;
- public string StandardLibraryLocation;
-
- // whether procedure inlining is enabled at call sites.
- public enum Inlining {
- None,
- Assert,
- Assume,
- Spec
- };
- public Inlining ProcedureInlining = Inlining.Assume;
- public bool PrintInlined = false;
- public bool ExtractLoops = false;
- public bool DeterministicExtractLoops = false;
- public string SecureVcGen = null;
- public int StratifiedInlining = 0;
- public string FixedPointEngine = null;
- public int StratifiedInliningOption = 0;
- public bool StratifiedInliningWithoutModels = false; // disable model generation for SI
- public int StratifiedInliningVerbose = 0; // verbosity level
- public int RecursionBound = 500;
- public bool NonUniformUnfolding = false;
- public int StackDepthBound = 0;
- public string inferLeastForUnsat = null;
-
- // Inference mode for fixed point engine
- public enum FixedPointInferenceMode {
- Corral,
- OldCorral,
- Flat,
- Procedure,
- Call
- };
- public FixedPointInferenceMode FixedPointMode = FixedPointInferenceMode.Procedure;
-
- public string PrintFixedPoint = null;
-
- public string PrintConjectures = null;
-
- public bool ExtractLoopsUnrollIrreducible = true; // unroll irreducible loops? (set programmatically)
-
- public enum TypeEncoding {
- None,
- Predicates,
- Arguments,
- Monomorphic
- };
- public TypeEncoding TypeEncodingMethod = TypeEncoding.Predicates;
-
- public bool Monomorphize = false;
-
- public bool ReflectAdd = false;
-
- public int LiveVariableAnalysis = 1;
-
- // Static constructor
- static CommandLineOptions() {
- if (System.Type.GetType("Mono.Runtime") == null) { // MONO
- TraceListenerCollection/*!*/ dbl = Debug.Listeners;
- Contract.Assert(dbl != null);
- Contract.Assume(cce.IsPeerConsistent(dbl)); // hangs off static field
- dbl.Add(new DefaultTraceListener());
- }
- }
-
- public IEnumerable<string/*!*/> ProcsToCheck {
- get {
- Contract.Ensures(cce.NonNullElements(Contract.Result<IEnumerable<string/*!*/>>(), true));
- return this.procsToCheck != null ? this.procsToCheck.AsEnumerable() : null;
- }
- }
-
- private List<string/*!*/> procsToCheck = null; // null means "no restriction"
-
- [ContractInvariantMethod]
- void ObjectInvariant5() {
- Contract.Invariant(cce.NonNullElements(this.procsToCheck, true));
- Contract.Invariant(Ai != null);
- }
-
- public class AiFlags {
- public bool J_Trivial = false;
- public bool J_Intervals = false;
- public bool DebugStatistics = false;
- }
- public readonly AiFlags/*!*/ Ai = new AiFlags();
-
- public class ConcurrentHoudiniOptions
- {
- public List<string> ProverOptions = new List<string>();
- public int ProverCCLimit = 5;
- public bool DisableLoopInvEntryAssert = false;
- public bool DisableLoopInvMaintainedAssert = false;
- public bool ModifyTopologicalSorting = false;
- }
- public List<ConcurrentHoudiniOptions> Cho = new List<ConcurrentHoudiniOptions>();
-
- protected override bool ParseOption(string name, CommandLineOptionEngine.CommandLineParseState ps) {
- var args = ps.args; // convenient synonym
- switch (name) {
- case "infer":
- if (ps.ConfirmArgumentCount(1)) {
- foreach (char c in cce.NonNull(args[ps.i])) {
- switch (c) {
- case 't':
- Ai.J_Trivial = true;
- UseAbstractInterpretation = true;
- break;
- case 'j':
- Ai.J_Intervals = true;
- UseAbstractInterpretation = true;
- break;
- case 's':
- Ai.DebugStatistics = true;
- UseAbstractInterpretation = true;
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- StepsBeforeWidening = (int)char.GetNumericValue(c);
- break;
- default:
- ps.Error("Invalid argument '{0}' to option {1}", c.ToString(), ps.s);
- break;
- }
- }
- }
- return true;
-
- case "noinfer":
- if (ps.ConfirmArgumentCount(0)) {
- UseAbstractInterpretation = false;
- }
- return true;
-
- case "break":
- case "launch":
- if (ps.ConfirmArgumentCount(0)) {
- System.Diagnostics.Debugger.Launch();
- }
- return true;
-
- case "proc":
- if (this.procsToCheck == null) {
- this.procsToCheck = new List<string/*!*/>();
- }
- if (ps.ConfirmArgumentCount(1)) {
- this.procsToCheck.Add(cce.NonNull(args[ps.i]));
- }
- return true;
-
- case "xml":
- if (ps.ConfirmArgumentCount(1)) {
- XmlSinkFilename = args[ps.i];
- }
- return true;
-
- case "print":
- if (ps.ConfirmArgumentCount(1)) {
- PrintFile = args[ps.i];
- }
- return true;
-
- case "pretty":
- int val = 1;
- if (ps.GetNumericArgument(ref val, 2)) {
- PrettyPrint = val == 1;
- }
- return true;
-
- case "OwickiGries":
- if (ps.ConfirmArgumentCount(1)) {
- OwickiGriesDesugaredOutputFile = args[ps.i];
- }
- return true;
-
- case "trustLayersUpto":
- if (ps.ConfirmArgumentCount(1))
- {
- ps.GetNumericArgument(ref TrustLayersUpto);
- }
- return true;
-
- case "trustLayersDownto":
- if (ps.ConfirmArgumentCount(1))
- {
- ps.GetNumericArgument(ref TrustLayersDownto);
- }
- return true;
-
- case "proverLog":
- if (ps.ConfirmArgumentCount(1)) {
- SimplifyLogFilePath = args[ps.i];
- }
- return true;
-
- case "logPrefix":
- if (ps.ConfirmArgumentCount(1)) {
- string s = cce.NonNull(args[ps.i]);
- LogPrefix += s.Replace('/', '-').Replace('\\', '-');
- }
- return true;
-
- case "proverShutdownLimit":
- ps.GetNumericArgument(ref ProverShutdownLimit);
- return true;
-
- case "errorTrace":
- ps.GetNumericArgument(ref ErrorTrace, 3);
- return true;
-
- case "proverWarnings": {
- int pw = 0;
- if (ps.GetNumericArgument(ref pw, 3)) {
- switch (pw) {
- case 0:
- PrintProverWarnings = ProverWarnings.None;
- break;
- case 1:
- PrintProverWarnings = ProverWarnings.Stdout;
- break;
- case 2:
- PrintProverWarnings = ProverWarnings.Stderr;
- break;
- default: {
- Contract.Assert(false);
- throw new cce.UnreachableException();
- } // postcondition of GetNumericArgument guarantees that we don't get here
- }
- }
- return true;
- }
-
- case "env": {
- int e = 0;
- if (ps.GetNumericArgument(ref e, 3)) {
- switch (e) {
- case 0:
- ShowEnv = ShowEnvironment.Never;
- break;
- case 1:
- ShowEnv = ShowEnvironment.DuringPrint;
- break;
- case 2:
- ShowEnv = ShowEnvironment.Always;
- break;
- default: {
- Contract.Assert(false);
- throw new cce.UnreachableException();
- } // postcondition of GetNumericArgument guarantees that we don't get here
- }
- }
- return true;
- }
-
- case "loopUnroll":
- ps.GetNumericArgument(ref LoopUnrollCount);
- return true;
-
- case "printModel":
- if (ps.ConfirmArgumentCount(1)) {
- switch (args[ps.i]) {
- case "0":
- PrintErrorModel = 0;
- break;
- case "1":
- PrintErrorModel = 1;
- break;
- case "2":
- PrintErrorModel = 2;
- break;
- case "4":
- PrintErrorModel = 4;
- break;
- default:
- ps.Error("Invalid argument \"{0}\" to option {1}", args[ps.i], ps.s);
- break;
- }
- }
- return true;
-
- case "mv":
- if (ps.ConfirmArgumentCount(1)) {
- ModelViewFile = args[ps.i];
- }
- return true;
-
- case "printModelToFile":
- if (ps.ConfirmArgumentCount(1)) {
- PrintErrorModelFile = args[ps.i];
- }
- return true;
-
- case "enhancedErrorMessages":
- ps.GetNumericArgument(ref EnhancedErrorMessages, 2);
- return true;
-
- case "printCFG":
- if (ps.ConfirmArgumentCount(1)) {
- PrintCFGPrefix = args[ps.i];
- }
- return true;
-
- case "inlineDepth":
- ps.GetNumericArgument(ref InlineDepth);
- return true;
-
- case "subsumption": {
- int s = 0;
- if (ps.GetNumericArgument(ref s, 3)) {
- switch (s) {
- case 0:
- UseSubsumption = SubsumptionOption.Never;
- break;
- case 1:
- UseSubsumption = SubsumptionOption.NotForQuantifiers;
- break;
- case 2:
- UseSubsumption = SubsumptionOption.Always;
- break;
- default: {
- Contract.Assert(false);
- throw new cce.UnreachableException();
- } // postcondition of GetNumericArgument guarantees that we don't get here
- }
- }
- return true;
- }
-
- case "liveVariableAnalysis": {
- int lva = 0;
- if (ps.GetNumericArgument(ref lva, 3)) {
- LiveVariableAnalysis = lva;
- }
- return true;
- }
-
- case "removeEmptyBlocks": {
- int reb = 0;
- if (ps.GetNumericArgument(ref reb, 2)) {
- RemoveEmptyBlocks = reb == 1;
- }
- return true;
- }
-
- case "coalesceBlocks": {
- int cb = 0;
- if (ps.GetNumericArgument(ref cb, 2)) {
- CoalesceBlocks = cb == 1;
- }
- return true;
- }
-
- case "noPruneInfeasibleEdges": {
- if (ps.ConfirmArgumentCount(0)) {
- PruneInfeasibleEdges = false;
- }
- return true;
- }
-
- case "stagedHoudini": {
- if (ps.ConfirmArgumentCount(1)) {
- if(args[ps.i] == "COARSE" ||
- args[ps.i] == "FINE" ||
- args[ps.i] == "BALANCED") {
- StagedHoudini = args[ps.i];
- } else {
- ps.Error("Invalid argument \"{0}\" to option {1}", args[ps.i], ps.s);
- }
- }
- return true;
- }
-
- case "stagedHoudiniThreads": {
- ps.GetNumericArgument(ref StagedHoudiniThreads);
- return true;
- }
-
- case "stagedHoudiniReachabilityAnalysis": {
- if (ps.ConfirmArgumentCount(0)) {
- StagedHoudiniReachabilityAnalysis = true;
- }
- return true;
- }
-
- case "stagedHoudiniMergeIgnoredAnnotations": {
- if (ps.ConfirmArgumentCount(0)) {
- StagedHoudiniMergeIgnoredAnnotations = true;
- }
- return true;
- }
-
- case "debugStagedHoudini": {
- if (ps.ConfirmArgumentCount(0)) {
- DebugStagedHoudini = true;
- }
- return true;
- }
-
- case "variableDependenceIgnore": {
- if (ps.ConfirmArgumentCount(1)) {
- VariableDependenceIgnore = args[ps.i];
- }
- return true;
- }
-
- case "abstractHoudini":
- {
- if (ps.ConfirmArgumentCount(1))
- {
- AbstractHoudini = args[ps.i];
- }
- return true;
- }
- case "vc":
- if (ps.ConfirmArgumentCount(1)) {
- switch (args[ps.i]) {
- case "s":
- case "structured":
- vcVariety = VCVariety.Structured;
- break;
- case "b":
- case "block":
- vcVariety = VCVariety.Block;
- break;
- case "l":
- case "local":
- vcVariety = VCVariety.Local;
- break;
- case "n":
- case "nested":
- vcVariety = VCVariety.BlockNested;
- break;
- case "m":
- vcVariety = VCVariety.BlockNestedReach;
- break;
- case "r":
- vcVariety = VCVariety.BlockReach;
- break;
- case "d":
- case "dag":
- vcVariety = VCVariety.Dag;
- break;
- case "i":
- vcVariety = VCVariety.DagIterative;
- break;
- case "doomed":
- vcVariety = VCVariety.Doomed;
- break;
- default:
- ps.Error("Invalid argument \"{0}\" to option {1}", args[ps.i], ps.s);
- break;
- }
- }
- return true;
-
- case "prover":
- if (ps.ConfirmArgumentCount(1)) {
- TheProverFactory = ProverFactory.Load(cce.NonNull(args[ps.i]));
- ProverName = cce.NonNull(args[ps.i]).ToUpper();
- }
- return true;
-
- case "p":
- case "proverOpt":
- if (ps.ConfirmArgumentCount(1)) {
- ProverOptions = ProverOptions.Concat1(cce.NonNull(args[ps.i]));
- }
- return true;
-
- case "DoomStrategy":
- ps.GetNumericArgument(ref DoomStrategy);
- return true;
-
- case "DoomRestartTP":
- if (ps.ConfirmArgumentCount(0)) {
- DoomRestartTP = true;
- }
- return true;
-
- case "extractLoops":
- if (ps.ConfirmArgumentCount(0)) {
- ExtractLoops = true;
- }
- return true;
-
- case "deterministicExtractLoops":
- if (ps.ConfirmArgumentCount(0)) {
- DeterministicExtractLoops = true;
- }
- return true;
-
- case "inline":
- if (ps.ConfirmArgumentCount(1)) {
- switch (args[ps.i]) {
- case "none":
- ProcedureInlining = Inlining.None;
- break;
- case "assert":
- ProcedureInlining = Inlining.Assert;
- break;
- case "assume":
- ProcedureInlining = Inlining.Assume;
- break;
- case "spec":
- ProcedureInlining = Inlining.Spec;
- break;
- default:
- ps.Error("Invalid argument \"{0}\" to option {1}", args[ps.i], ps.s);
- break;
- }
- }
- return true;
- case "secure":
- if (ps.ConfirmArgumentCount(1))
- SecureVcGen = args[ps.i];
- return true;
- case "stratifiedInline":
- if (ps.ConfirmArgumentCount(1)) {
- switch (args[ps.i]) {
- case "0":
- StratifiedInlining = 0;
- break;
- case "1":
- StratifiedInlining = 1;
- break;
- default:
- StratifiedInlining = Int32.Parse(cce.NonNull(args[ps.i]));
- //ps.Error("Invalid argument \"{0}\" to option {1}", args[ps.i], ps.s);
- break;
- }
- }
- return true;
- case "fixedPointEngine":
- if (ps.ConfirmArgumentCount(1))
- {
- FixedPointEngine = args[ps.i];
- }
- return true;
- case "fixedPointInfer":
- if (ps.ConfirmArgumentCount(1))
- {
- switch (args[ps.i])
- {
- case "corral":
- FixedPointMode = FixedPointInferenceMode.Corral;
- break;
- case "oldCorral":
- FixedPointMode = FixedPointInferenceMode.OldCorral;
- break;
- case "flat":
- FixedPointMode = FixedPointInferenceMode.Flat;
- break;
- case "procedure":
- FixedPointMode = FixedPointInferenceMode.Procedure;
- break;
- case "call":
- FixedPointMode = FixedPointInferenceMode.Call;
- break;
- default:
- ps.Error("Invalid argument \"{0}\" to option {1}", args[ps.i], ps.s);
- break;
- }
- }
- return true;
- case "printFixedPoint":
- if (ps.ConfirmArgumentCount(1))
- {
- PrintFixedPoint = args[ps.i];
- }
- return true;
- case "printConjectures":
- if (ps.ConfirmArgumentCount(1))
- {
- PrintConjectures = args[ps.i];
- }
- return true;
- case "siVerbose":
- if (ps.ConfirmArgumentCount(1)) {
- StratifiedInliningVerbose = Int32.Parse(cce.NonNull(args[ps.i]));
- }
- return true;
- case "recursionBound":
- if (ps.ConfirmArgumentCount(1)) {
- RecursionBound = Int32.Parse(cce.NonNull(args[ps.i]));
- }
- return true;
- case "stackDepthBound":
- if (ps.ConfirmArgumentCount(1))
- {
- StackDepthBound = Int32.Parse(cce.NonNull(args[ps.i]));
- }
- return true;
- case "stratifiedInlineOption":
- if (ps.ConfirmArgumentCount(1)) {
- StratifiedInliningOption = Int32.Parse(cce.NonNull(args[ps.i]));
- }
- return true;
-
- case "inferLeastForUnsat":
- if (ps.ConfirmArgumentCount(1)) {
- inferLeastForUnsat = args[ps.i];
- }
- return true;
-
- case "typeEncoding":
- if (ps.ConfirmArgumentCount(1)) {
- switch (args[ps.i]) {
- case "n":
- case "none":
- TypeEncodingMethod = TypeEncoding.None;
- break;
- case "p":
- case "predicates":
- TypeEncodingMethod = TypeEncoding.Predicates;
- break;
- case "a":
- case "arguments":
- TypeEncodingMethod = TypeEncoding.Arguments;
- break;
- case "m":
- case "monomorphic":
- TypeEncodingMethod = TypeEncoding.Monomorphic;
- break;
- default:
- ps.Error("Invalid argument \"{0}\" to option {1}", args[ps.i], ps.s);
- break;
- }
- }
- return true;
-
- case "instrumentInfer":
- if (ps.ConfirmArgumentCount(1)) {
- switch (args[ps.i]) {
- case "e":
- InstrumentInfer = InstrumentationPlaces.Everywhere;
- break;
- case "h":
- InstrumentInfer = InstrumentationPlaces.LoopHeaders;
- break;
- default:
- ps.Error("Invalid argument \"{0}\" to option {1}", args[ps.i], ps.s);
- break;
- }
- }
- return true;
-
- case "concurrentHoudini":
- if (ps.ConfirmArgumentCount(0)) {
- ConcurrentHoudini = true;
- }
- return true;
-
- case "modifyTopologicalSorting":
- if (ps.ConfirmArgumentCount(0)) {
- ModifyTopologicalSorting = true;
- }
- return true;
-
- case "debugConcurrentHoudini":
- if (ps.ConfirmArgumentCount(0)) {
- DebugConcurrentHoudini = true;
- }
- return true;
-
- case "vcBrackets":
- ps.GetNumericArgument(ref bracketIdsInVC, 2);
- return true;
-
- case "proverMemoryLimit": {
- int d = 0;
- if (ps.GetNumericArgument(ref d)) {
- MaxProverMemory = d * Megabyte;
- }
- return true;
- }
-
- case "vcsMaxCost":
- ps.GetNumericArgument(ref VcsMaxCost);
- return true;
-
- case "vcsPathJoinMult":
- ps.GetNumericArgument(ref VcsPathJoinMult);
- return true;
-
- case "vcsPathCostMult":
- ps.GetNumericArgument(ref VcsPathCostMult);
- return true;
-
- case "vcsAssumeMult":
- ps.GetNumericArgument(ref VcsAssumeMult);
- return true;
-
- case "vcsPathSplitMult":
- ps.GetNumericArgument(ref VcsPathSplitMult);
- return true;
-
- case "vcsMaxSplits":
- ps.GetNumericArgument(ref VcsMaxSplits);
- return true;
-
- case "vcsMaxKeepGoingSplits":
- ps.GetNumericArgument(ref VcsMaxKeepGoingSplits);
- return true;
-
- case "vcsFinalAssertTimeout":
- ps.GetNumericArgument(ref VcsFinalAssertTimeout);
- return true;
-
- case "vcsKeepGoingTimeout":
- ps.GetNumericArgument(ref VcsKeepGoingTimeout);
- return true;
-
- case "vcsCores":
- ps.GetNumericArgument(ref VcsCores, a => 1 <= a);
- return true;
-
- case "vcsLoad":
- double load = 0.0;
- if (ps.GetNumericArgument(ref load)) {
- if (3.0 <= load) {
- ps.Error("surprisingly high load specified; got {0}, expected nothing above 3.0", load.ToString());
- load = 3.0;
- }
- int p = (int)Math.Round(System.Environment.ProcessorCount * load);
- VcsCores = p < 1 ? 1 : p;
- }
- return true;
-
- case "simplifyMatchDepth":
- ps.GetNumericArgument(ref SimplifyProverMatchDepth);
- return true;
-
- case "timeLimit":
- ps.GetNumericArgument(ref ProverKillTime);
- return true;
-
- case "smokeTimeout":
- ps.GetNumericArgument(ref SmokeTimeout);
- return true;
-
- case "errorLimit":
- ps.GetNumericArgument(ref ProverCCLimit);
- return true;
-
- case "verifySnapshots":
- ps.GetNumericArgument(ref VerifySnapshots, 3);
- return true;
-
- case "traceCaching":
- ps.GetNumericArgument(ref TraceCaching, 4);
- return true;
-
- case "useSmtOutputFormat": {
- if (ps.ConfirmArgumentCount(0)) {
- UseSmtOutputFormat = true;
- }
- return true;
- }
-
- case "z3opt":
- if (ps.ConfirmArgumentCount(1)) {
- AddZ3Option(cce.NonNull(args[ps.i]));
- }
- return true;
-
- case "z3lets":
- ps.GetNumericArgument(ref Z3lets, 4);
- return true;
-
- case "platform":
- if (ps.ConfirmArgumentCount(1)) {
- StringCollection platformOptions = this.ParseNamedArgumentList(args[ps.i]);
- if (platformOptions != null && platformOptions.Count > 0) {
- try {
- this.TargetPlatform = (PlatformType)cce.NonNull(Enum.Parse(typeof(PlatformType), cce.NonNull(platformOptions[0])));
- } catch {
- ps.Error("Bad /platform type '{0}'", platformOptions[0]);
- break;
- }
- if (platformOptions.Count > 1) {
- this.TargetPlatformLocation = platformOptions[1];
- if (!Directory.Exists(platformOptions[1])) {
- ps.Error("/platform directory '{0}' does not exist", platformOptions[1]);
- break;
- }
- }
- }
- }
- return true;
-
- case "z3exe":
- if (ps.ConfirmArgumentCount(1)) {
- Z3ExecutablePath = args[ps.i];
- }
- return true;
-
- case "cvc4exe":
- if (ps.ConfirmArgumentCount(1)) {
- CVC4ExecutablePath = args[ps.i];
- }
- return true;
-
- case "kInductionDepth":
- ps.GetNumericArgument(ref KInductionDepth);
- return true;
-
- default:
- bool optionValue = false;
- if (ps.CheckBooleanFlag("printUnstructured", ref optionValue)) {
- PrintUnstructured = optionValue ? 1 : 0;
- return true;
- }
-
- if (ps.CheckBooleanFlag("printDesugared", ref PrintDesugarings) ||
- ps.CheckBooleanFlag("printInstrumented", ref PrintInstrumented) ||
- ps.CheckBooleanFlag("printWithUniqueIds", ref PrintWithUniqueASTIds) ||
- ps.CheckBooleanFlag("wait", ref Wait) ||
- ps.CheckBooleanFlag("trace", ref Trace) ||
- ps.CheckBooleanFlag("traceTimes", ref TraceTimes) ||
- ps.CheckBooleanFlag("tracePOs", ref TraceProofObligations) ||
- ps.CheckBooleanFlag("noResolve", ref NoResolve) ||
- ps.CheckBooleanFlag("noTypecheck", ref NoTypecheck) ||
- ps.CheckBooleanFlag("overlookTypeErrors", ref OverlookBoogieTypeErrors) ||
- ps.CheckBooleanFlag("noVerify", ref Verify, false) ||
- ps.CheckBooleanFlag("traceverify", ref TraceVerify) ||
- ps.CheckBooleanFlag("alwaysAssumeFreeLoopInvariants", ref AlwaysAssumeFreeLoopInvariants, true) ||
- ps.CheckBooleanFlag("nologo", ref DontShowLogo) ||
- ps.CheckBooleanFlag("proverLogAppend", ref SimplifyLogFileAppend) ||
- ps.CheckBooleanFlag("soundLoopUnrolling", ref SoundLoopUnrolling) ||
- ps.CheckBooleanFlag("checkInfer", ref InstrumentWithAsserts) ||
- ps.CheckBooleanFlag("interprocInfer", ref IntraproceduralInfer, false) ||
- ps.CheckBooleanFlag("restartProver", ref RestartProverPerVC) ||
- ps.CheckBooleanFlag("printInlined", ref PrintInlined) ||
- ps.CheckBooleanFlag("smoke", ref SoundnessSmokeTest) ||
- ps.CheckBooleanFlag("vcsDumpSplits", ref VcsDumpSplits) ||
- ps.CheckBooleanFlag("dbgRefuted", ref DebugRefuted) ||
- ps.CheckBooleanFlag("causalImplies", ref CausalImplies) ||
- ps.CheckBooleanFlag("reflectAdd", ref ReflectAdd) ||
- ps.CheckBooleanFlag("z3types", ref Z3types) ||
- ps.CheckBooleanFlag("z3multipleErrors", ref z3AtFlag, false) ||
- ps.CheckBooleanFlag("monomorphize", ref Monomorphize) ||
- ps.CheckBooleanFlag("useArrayTheory", ref UseArrayTheory) ||
- ps.CheckBooleanFlag("weakArrayTheory", ref WeakArrayTheory) ||
- ps.CheckBooleanFlag("doModSetAnalysis", ref DoModSetAnalysis) ||
- ps.CheckBooleanFlag("doNotUseLabels", ref UseLabels, false) ||
- ps.CheckBooleanFlag("boolControlVC", ref SIBoolControlVC, true) ||
- ps.CheckBooleanFlag("contractInfer", ref ContractInfer) ||
- ps.CheckBooleanFlag("explainHoudini", ref ExplainHoudini) ||
- ps.CheckBooleanFlag("reverseHoudiniWorklist", ref ReverseHoudiniWorklist) ||
- ps.CheckBooleanFlag("crossDependencies", ref HoudiniUseCrossDependencies) ||
- ps.CheckBooleanFlag("useUnsatCoreForContractInfer", ref UseUnsatCoreForContractInfer) ||
- ps.CheckBooleanFlag("printAssignment", ref PrintAssignment) ||
- ps.CheckBooleanFlag("useProverEvaluate", ref UseProverEvaluate) ||
- ps.CheckBooleanFlag("nonUniformUnfolding", ref NonUniformUnfolding) ||
- ps.CheckBooleanFlag("deterministicExtractLoops", ref DeterministicExtractLoops) ||
- ps.CheckBooleanFlag("verifySeparately", ref VerifySeparately) ||
- ps.CheckBooleanFlag("trustAtomicityTypes", ref TrustAtomicityTypes) ||
- ps.CheckBooleanFlag("trustNonInterference", ref TrustNonInterference) ||
- ps.CheckBooleanFlag("useBaseNameForFileName", ref UseBaseNameForFileName)
- ) {
- // one of the boolean flags matched
- return true;
- }
- break;
- }
-
- return base.ParseOption(name, ps); // defer to superclass
- }
-
- public override void ApplyDefaultOptions() {
- Contract.Ensures(TheProverFactory != null);
- Contract.Ensures(vcVariety != VCVariety.Unspecified);
-
- base.ApplyDefaultOptions();
-
- // expand macros in filenames, now that LogPrefix is fully determined
- ExpandFilename(ref XmlSinkFilename, LogPrefix, FileTimestamp);
- ExpandFilename(ref PrintFile, LogPrefix, FileTimestamp);
- ExpandFilename(ref SimplifyLogFilePath, LogPrefix, FileTimestamp);
- ExpandFilename(ref PrintErrorModelFile, LogPrefix, FileTimestamp);
-
- Contract.Assume(XmlSink == null); // XmlSink is to be set here
- if (XmlSinkFilename != null) {
- XmlSink = new XmlSink(XmlSinkFilename);
- }
-
- if (TheProverFactory == null) {
- TheProverFactory = ProverFactory.Load("SMTLib");
- ProverName = "SMTLib".ToUpper();
- }
-
- var proverOpts = TheProverFactory.BlankProverOptions();
- proverOpts.Parse(ProverOptions);
- if (!TheProverFactory.SupportsLabels(proverOpts)) {
- UseLabels = false;
- }
-
- if (vcVariety == VCVariety.Unspecified) {
- vcVariety = TheProverFactory.DefaultVCVariety;
- }
-
- if (UseArrayTheory) {
- Monomorphize = true;
- }
-
- if (inferLeastForUnsat != null) {
- StratifiedInlining = 1;
- }
-
- if (StratifiedInlining > 0) {
- TypeEncodingMethod = TypeEncoding.Monomorphic;
- UseArrayTheory = true;
- UseAbstractInterpretation = false;
- MaxProverMemory = 0; // no max: avoids restarts
- if (ProverName == "Z3API" || ProverName == "SMTLIB") {
- ProverCCLimit = 1;
- }
- if (UseProverEvaluate)
- StratifiedInliningWithoutModels = true;
- }
-
- if (Trace) {
- BoogieDebug.DoPrinting = true; // reuse the -trace option for debug printing
- }
- }
-
-
-
- public bool UserWantsToCheckRoutine(string methodFullname) {
- Contract.Requires(methodFullname != null);
- if (ProcsToCheck == null) {
- // no preference
- return true;
- }
- return ProcsToCheck.Any(s => 0 <= methodFullname.IndexOf(s));
- }
-
- public virtual StringCollection ParseNamedArgumentList(string argList) {
- if (argList == null || argList.Length == 0)
- return null;
- StringCollection result = new StringCollection();
- int i = 0;
- for (int n = argList.Length; i < n; ) {
- cce.LoopInvariant(0 <= i);
- int separatorIndex = this.GetArgumentSeparatorIndex(argList, i);
- if (separatorIndex > i) {
- result.Add(argList.Substring(i, separatorIndex - i));
- i = separatorIndex + 1;
- continue;
- }
- result.Add(argList.Substring(i));
- break;
- }
- return result;
- }
- public int GetArgumentSeparatorIndex(string argList, int startIndex) {
- Contract.Requires(argList != null);
- Contract.Requires(0 <= startIndex && startIndex <= argList.Length);
- Contract.Ensures(Contract.Result<int>() < argList.Length);
- int commaIndex = argList.IndexOf(",", startIndex);
- int semicolonIndex = argList.IndexOf(";", startIndex);
- if (commaIndex == -1)
- return semicolonIndex;
- if (semicolonIndex == -1)
- return commaIndex;
- if (commaIndex < semicolonIndex)
- return commaIndex;
- return semicolonIndex;
- }
-
- public override void AttributeUsage() {
- Console.WriteLine(
-@"Boogie: The following attributes are supported by this implementation.
-
- ---- On top-level declarations ---------------------------------------------
-
- {:ignore}
- Ignore the declaration (after checking for duplicate names).
-
- {:extern}
- If two top-level declarations introduce the same name (for example, two
- constants with the same name or two procedures with the same name), then
- Boogie usually produces an error message. However, if at least one of
- the declarations is declared with :extern, one of the declarations is
- ignored. If both declarations are :extern, Boogie arbitrarily chooses
- one of them to keep; otherwise, Boogie ignore the :extern declaration
- and keeps the other.
-
- {:checksum <string>}
- Attach a checksum to be used for verification result caching.
-
- ---- On implementations and procedures -------------------------------------
-
- {:inline N}
- Inline given procedure (can be also used on implementation).
- N should be a non-negative number and represents the inlining depth.
- With /inline:assume call is replaced with ""assume false"" once inlining depth is reached.
- With /inline:assert call is replaced with ""assert false"" once inlining depth is reached.
- With /inline:spec call is left as is once inlining depth is reached.
- With the above three options, methods with the attribute {:inline N} are not verified.
- With /inline:none the entire attribute is ignored.
-
- {:verify false}
- Skip verification of an implementation.
-
- {:vcs_max_cost N}
- {:vcs_max_splits N}
- {:vcs_max_keep_going_splits N}
- Per-implementation versions of
- /vcsMaxCost, /vcsMaxSplits and /vcsMaxKeepGoingSplits.
-
- {:selective_checking true}
- Turn all asserts into assumes except for the ones reachable from
- assumptions marked with the attribute {:start_checking_here}.
- Thus, ""assume {:start_checking_here} something;"" becomes an inverse
- of ""assume false;"": the first one disables all verification before
- it, and the second one disables all verification after.
-
- {:priority N}
- Assign a positive priority 'N' to an implementation to control the order
- in which implementations are verified (default: N = 1).
-
- {:id <string>}
- Assign a unique ID to an implementation to be used for verification
- result caching (default: ""<impl. name>:0"").
-
- {:timeLimit N}
- Set the time limit for a given implementation.
-
- ---- On functions ----------------------------------------------------------
-
- {:builtin ""spec""}
- {:bvbuiltin ""spec""}
- Rewrite the function to built-in prover function symbol 'fn'.
-
- {:inline}
- {:inline true}
- Expand function according to its definition before going to the prover.
-
- {:never_pattern true}
- Terms starting with this function symbol will never be
- automatically selected as patterns. It does not prevent them
- from being used inside the triggers, and does not affect explicit
- trigger annotations. Internally it works by adding {:nopats ...}
- annotations to quantifiers.
-
- {:identity}
- {:identity true}
- If the function has 1 argument and the use of it has type X->X for
- some X, then the abstract interpreter will treat the function as an
- identity function. Note, the abstract interpreter trusts the
- attribute--it does not try to verify that the function really is an
- identity function.
-
- ---- On variables ----------------------------------------------------------
-
- {:existential true}
- Marks a global Boolean variable as existentially quantified. If
- used in combination with option /contractInfer Boogie will check
- whether there exists a Boolean assignment to the existentials
- that makes all verification conditions valid. Without option
- /contractInfer the attribute is ignored.
-
- ---- On assert statements --------------------------------------------------
-
- {:subsumption n}
- Overrides the /subsumption command-line setting for this assertion.
-
- {:split_here}
- Verifies code leading to this point and code leading from this point
- to the next split_here as separate pieces. May help with timeouts.
- May also occasionally double-report errors.
-
- ---- The end ---------------------------------------------------------------
-");
- }
-
- public override void Usage() {
- Console.WriteLine(@"
- /nologo suppress printing of version number, copyright message
- /env:<n> print command line arguments
- 0 - never, 1 (default) - during BPL print and prover log,
- 2 - like 1 and also to standard output
- /wait await Enter from keyboard before terminating program
- /xml:<file> also produce output in XML format to <file>
-
- ---- Boogie options --------------------------------------------------------
-
- Multiple .bpl files supplied on the command line are concatenated into one
- Boogie program.
-
- /proc:<p> : limits which procedures to check
- /noResolve : parse only
- /noTypecheck : parse and resolve only
-
- /print:<file> : print Boogie program after parsing it
- (use - as <file> to print to console)
- /pretty:<n>
- 0 - print each Boogie statement on one line (faster).
- 1 (default) - pretty-print with some line breaks.
- /printWithUniqueIds : print augmented information that uniquely
- identifies variables
- /printUnstructured : with /print option, desugars all structured statements
- /printDesugared : with /print option, desugars calls
-
- /overlookTypeErrors : skip any implementation with resolution or type
- checking errors
-
- /loopUnroll:<n>
- unroll loops, following up to n back edges (and then some)
- /soundLoopUnrolling
- sound loop unrolling
- /printModel:<n>
- 0 (default) - do not print Z3's error model
- 1 - print Z3's error model
- 2 - print Z3's error model plus reverse mappings
- 4 - print Z3's error model in a more human readable way
- /printModelToFile:<file>
- print model to <file> instead of console
- /mv:<file> Specify file where to save the model in BVD format
- /enhancedErrorMessages:<n>
- 0 (default) - no enhanced error messages
- 1 - Z3 error model enhanced error messages
-
- /printCFG:<prefix> : print control flow graph of each implementation in
- Graphviz format to files named:
- <prefix>.<procedure name>.dot
-
- /useBaseNameForFileName : When parsing use basename of file for tokens instead
- of the path supplied on the command line
-
- ---- Inference options -----------------------------------------------------
-
- /infer:<flags>
- use abstract interpretation to infer invariants
- The default is /infer:i"
- // This is not 100% true, as the /infer ALWAYS creates
- // a multilattice, whereas if nothing is specified then
- // intervals are isntantiated WITHOUT being embedded in
- // a multilattice
- + @"
- <flags> are as follows (missing <flags> means all)
- i = intervals
- c = constant propagation
- d = dynamic type
- n = nullness
- p = polyhedra for linear inequalities
- t = trivial bottom/top lattice (cannot be combined with
- other domains)
- j = stronger intervals (cannot be combined with other
- domains)
- or the following (which denote options, not domains):
- s = debug statistics
- 0..9 = number of iterations before applying a widen (default=0)
- /noinfer turn off the default inference, and overrides the /infer
- switch on its left
- /checkInfer instrument inferred invariants as asserts to be checked by
- theorem prover
- /interprocInfer
- perform interprocedural inference (deprecated, not supported)
- /contractInfer
- perform procedure contract inference
- /instrumentInfer
- h - instrument inferred invariants only at beginning of
- loop headers (default)
- e - instrument inferred invariants at beginning and end
- of every block (this mode is intended for use in
- debugging of abstract domains)
- /printInstrumented
- print Boogie program after it has been instrumented with
- invariants
-
- ---- Debugging and general tracing options ---------------------------------
-
- /trace blurt out various debug trace information
- /traceTimes output timing information at certain points in the pipeline
- /tracePOs output information about the number of proof obligations
- (also included in the /trace output)
- /log[:method] Print debug output during translation
-
- /break launch and break into debugger
-
- ---- Verification-condition generation options -----------------------------
-
- /liveVariableAnalysis:<c>
- 0 = do not perform live variable analysis
- 1 = perform live variable analysis (default)
- 2 = perform interprocedural live variable analysis
- /noVerify skip VC generation and invocation of the theorem prover
- /verifySnapshots:<n>
- verify several program snapshots (named <filename>.v0.bpl
- to <filename>.vN.bpl) using verification result caching:
- 0 - do not use any verification result caching (default)
- 1 - use the basic verification result caching
- 2 - use the more advanced verification result caching
- /verifySeparately
- verify each input program separately
- /removeEmptyBlocks:<c>
- 0 - do not remove empty blocks during VC generation
- 1 - remove empty blocks (default)
- /coalesceBlocks:<c>
- 0 = do not coalesce blocks
- 1 = coalesce blocks (default)
- /vc:<variety> n = nested block (default for /prover:Simplify),
- m = nested block reach,
- b = flat block, r = flat block reach,
- s = structured, l = local,
- d = dag (default, except with /prover:Simplify)
- doomed = doomed
- /traceverify print debug output during verification condition generation
- /subsumption:<c>
- apply subsumption to asserted conditions:
- 0 - never, 1 - not for quantifiers, 2 (default) - always
- /alwaysAssumeFreeLoopInvariants
- usually, a free loop invariant (or assume
- statement in that position) is ignored in checking contexts
- (like other free things); this option includes these free
- loop invariants as assumes in both contexts
- /inline:<i> use inlining strategy <i> for procedures with the :inline
- attribute, see /attrHelp for details:
- none
- assume (default)
- assert
- spec
- /printInlined
- print the implementation after inlining calls to
- procedures with the :inline attribute (works with /inline)
- /lazyInline:1
- Use the lazy inlining algorithm
- /stratifiedInline:1
- Use the stratified inlining algorithm
- /fixedPointEngine:<engine>
- Use the specified fixed point engine for inference
- /recursionBound:<n>
- Set the recursion bound for stratified inlining to
- be n (default 500)
- /inferLeastForUnsat:<str>
- Infer the least number of constants (whose names
- are prefixed by <str>) that need to be set to
- true for the program to be correct. This turns
- on stratified inlining.
- /smoke Soundness Smoke Test: try to stick assert false; in some
- places in the BPL and see if we can still prove it
- /smokeTimeout:<n>
- Timeout, in seconds, for a single theorem prover
- invocation during smoke test, defaults to 10.
- /causalImplies
- Translate Boogie's A ==> B into prover's A ==> A && B.
- /typeEncoding:<m>
- how to encode types when sending VC to theorem prover
- n = none (unsound)
- p = predicates (default)
- a = arguments
- m = monomorphic
- /monomorphize
- Do not abstract map types in the encoding (this is an
- experimental feature that will not do the right thing if
- the program uses polymorphism)
- /reflectAdd In the VC, generate an auxiliary symbol, elsewhere defined
- to be +, instead of +.
-
- ---- Verification-condition splitting --------------------------------------
-
- /vcsMaxCost:<f>
- VC will not be split unless the cost of a VC exceeds this
- number, defaults to 2000.0. This does NOT apply in the
- keep-going mode after first round of splitting.
- /vcsMaxSplits:<n>
- Maximal number of VC generated per method. In keep
- going mode only applies to the first round.
- Defaults to 1.
- /vcsMaxKeepGoingSplits:<n>
- If set to more than 1, activates the keep
- going mode, where after the first round of splitting,
- VCs that timed out are split into <n> pieces and retried
- until we succeed proving them, or there is only one
- assertion on a single path and it timeouts (in which
- case error is reported for that assertion).
- Defaults to 1.
- /vcsKeepGoingTimeout:<n>
- Timeout in seconds for a single theorem prover
- invocation in keep going mode, except for the final
- single-assertion case. Defaults to 1s.
- /vcsFinalAssertTimeout:<n>
- Timeout in seconds for the single last
- assertion in the keep going mode. Defaults to 30s.
- /vcsPathJoinMult:<f>
- If more than one path join at a block, by how much
- multiply the number of paths in that block, to accomodate
- for the fact that the prover will learn something on one
- paths, before proceeding to another. Defaults to 0.8.
- /vcsPathCostMult:<f1>
- /vcsAssumeMult:<f2>
- The cost of a block is
- (<assert-cost> + <f2>*<assume-cost>) *
- (1.0 + <f1>*<entering-paths>)
- <f1> defaults to 1.0, <f2> defaults to 0.01.
- The cost of a single assertion or assumption is
- currently always 1.0.
- /vcsPathSplitMult:<f>
- If the best path split of a VC of cost A is into
- VCs of cost B and C, then the split is applied if
- A >= <f>*(B+C), otherwise assertion splitting will be
- applied. Defaults to 0.5 (always do path splitting if
- possible), set to more to do less path splitting
- and more assertion splitting.
- /vcsDumpSplits
- For split #n dump split.n.dot and split.n.bpl.
- Warning: Affects error reporting.
- /vcsCores:<n>
- Try to verify <n> VCs at once. Defaults to 1.
- /vcsLoad:<f> Sets vcsCores to the machine's ProcessorCount * f,
- rounded to the nearest integer (where 0.0 <= f <= 3.0),
- but never to less than 1.
-
- ---- Prover options --------------------------------------------------------
-
- /errorLimit:<num>
- Limit the number of errors produced for each procedure
- (default is 5, some provers may support only 1)
- /timeLimit:<num>
- Limit the number of seconds spent trying to verify
- each procedure
- /errorTrace:<n>
- 0 - no Trace labels in the error output,
- 1 (default) - include useful Trace labels in error output,
- 2 - include all Trace labels in the error output
- /vcBrackets:<b>
- bracket odd-charactered identifier names with |'s. <b> is:
- 0 - no (default with non-/prover:Simplify),
- 1 - yes (default with /prover:Simplify)
- /prover:<tp> use theorem prover <tp>, where <tp> is either the name of
- a DLL containing the prover interface located in the
- Boogie directory, or a full path to a DLL containing such
- an interface. The standard interfaces shipped include:
- SMTLib (default, uses the SMTLib2 format and calls Z3)
- Z3 (uses Z3 with the Simplify format)
- Simplify
- ContractInference (uses Z3)
- Z3api (Z3 using Managed .NET API)
- /proverOpt:KEY[=VALUE]
- Provide a prover-specific option (short form /p).
- /proverLog:<file>
- Log input for the theorem prover. Like filenames
- supplied as arguments to other options, <file> can use the
- following macros:
- @TIME@ expands to the current time
- @PREFIX@ expands to the concatenation of strings given
- by /logPrefix options
- @FILE@ expands to the last filename specified on the
- command line
- In addition, /proverLog can also use the macro '@PROC@',
- which causes there to be one prover log file per
- verification condition, and the macro then expands to the
- name of the procedure that the verification condition is for.
- /logPrefix:<str>
- Defines the expansion of the macro '@PREFIX@', which can
- be used in various filenames specified by other options.
- /proverLogAppend
- Append (not overwrite) the specified prover log file
- /proverWarnings
- 0 (default) - don't print, 1 - print to stdout,
- 2 - print to stderr
- /proverMemoryLimit:<num>
- Limit on the virtual memory for prover before
- restart in MB (default:100MB)
- /restartProver
- Restart the prover after each query
- /proverShutdownLimit<num>
- Time between closing the stream to the prover and
- killing the prover process (default: 0s)
- /platform:<ptype>,<location>
- ptype = v11,v2,cli1
- location = platform libraries directory
-
- Simplify specific options:
- /simplifyMatchDepth:<num>
- Set Simplify prover's matching depth limit
-
- Z3 specific options:
- /z3opt:<arg> specify additional Z3 options
- /z3multipleErrors
- report multiple counterexamples for each error
- /useArrayTheory
- use Z3's native theory (as opposed to axioms). Currently
- implies /monomorphize.
- /useSmtOutputFormat
- Z3 outputs a model in the SMTLIB2 format.
- /z3types generate multi-sorted VC that make use of Z3 types
- /z3lets:<n> 0 - no LETs, 1 - only LET TERM, 2 - only LET FORMULA,
- 3 - (default) any
- /z3exe:<path>
- path to Z3 executable
-
- CVC4 specific options:
- /cvc4exe:<path>
- path to CVC4 executable
-");
- }
- }
-}
+//-----------------------------------------------------------------------------
+//
+// 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;
+using System.Text.RegularExpressions;
+
+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<string>() != null);
+ return this._environment;
+ }
+ set {
+ Contract.Requires(value != null);
+ this._environment = value;
+ }
+ }
+
+ private readonly List<string/*!*/>/*!*/ _files = new List<string/*!*/>();
+
+ public IList<string/*!*/>/*!*/ Files {
+ get {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<IList<string>>()));
+ Contract.Ensures(Contract.Result<IList<string>>().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<string>() != 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<string>() != null);
+ return " version " + VersionNumber + ", Copyright (c) 2003-2014, Microsoft.";
+ }
+ }
+ public virtual string/*!*/ Version {
+ get {
+ Contract.Ensures(Contract.Result<string>() != null);
+ return DescriptiveToolName + VersionSuffix;
+ }
+ }
+
+ private string/*!*/ _fileTimestamp = cce.NonNull(DateTime.Now.ToString("o")).Replace(':', '.');
+
+ public string FileTimestamp {
+ get {
+ Contract.Ensures(Contract.Result<string>() != 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);
+ }
+ }
+
+ /// <summary>
+ /// Process the option and modify "ps" accordingly.
+ /// Return true if the option is one that is recognized.
+ /// </summary>
+ 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);
+ }
+
+ /// <summary>
+ /// 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".
+ /// </summary>
+ public bool GetNumericArgument(ref int arg) {
+ //modifies nextIndex, encounteredErrors, Console.Error.*;
+ return GetNumericArgument(ref arg, a => 0 <= a);
+ }
+
+ /// <summary>
+ /// 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".
+ /// </summary>
+ public bool GetNumericArgument(ref int arg, Predicate<int> 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;
+ }
+
+ /// <summary>
+ /// 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".
+ /// </summary>
+ 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;
+ }
+ }
+
+ /// <summary>
+ /// 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".
+ /// </summary>
+ 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<bool>() == (!(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 <option> is one of
+
+ ---- General options -------------------------------------------------------
+
+ /help this message
+ /attrHelp print a message about declaration attributes supported by
+ this implementation");
+ }
+
+ public virtual void AttributeUsage() {
+ }
+
+ /// <summary>
+ /// This method is called after all parsing is done, if no parse errors were encountered.
+ /// </summary>
+ public virtual void ApplyDefaultOptions() {
+ }
+
+ /// <summary>
+ /// Parses the command-line arguments "args" into the global flag variables. Returns true
+ /// if there were no errors.
+ /// </summary>
+ /// <param name="args">Consumed ("captured" and possibly modified) by the method.</param>
+ public bool Parse([Captured] string[]/*!*/ args) {
+ Contract.Requires(cce.NonNullElements(args));
+
+ // save the command line options for the log files
+ Environment += "Command Line Options: " + args.Concat(" ");
+ args = cce.NonNull((string[])args.Clone()); // the operations performed may mutate the array, so make a copy
+ var ps = new CommandLineParseState(args, ToolName);
+
+ while (ps.i < args.Length) {
+ cce.LoopInvariant(ps.args == args);
+ string arg = args[ps.i];
+ Contract.Assert(arg != null);
+ ps.s = arg.Trim();
+
+ bool isOption = ps.s.StartsWith("-") || ps.s.StartsWith("/");
+ int colonIndex = ps.s.IndexOf(':');
+ if (0 <= colonIndex && isOption) {
+ ps.hasColonArgument = true;
+ args[ps.i] = ps.s.Substring(colonIndex + 1);
+ ps.s = ps.s.Substring(0, colonIndex);
+ } else {
+ ps.i++;
+ ps.hasColonArgument = false;
+ }
+ ps.nextIndex = ps.i;
+
+ if (isOption) {
+ if (!ParseOption(ps.s.Substring(1), ps)) {
+ if (Path.DirectorySeparatorChar == '/' && ps.s.StartsWith("/"))
+ this._files.Add(arg);
+ else
+ ps.Error("unknown switch: {0}", ps.s);
+ }
+ } else {
+ this._files.Add(arg);
+ }
+
+ ps.i = ps.nextIndex;
+ }
+
+ if (HelpRequested) {
+ Usage();
+ } else if (AttrHelpRequested) {
+ AttributeUsage();
+ } else if (ps.EncounteredErrors) {
+ Console.WriteLine("Use /help for available options");
+ }
+
+ if (ps.EncounteredErrors) {
+ return false;
+ } else {
+ this.ApplyDefaultOptions();
+ return true;
+ }
+ }
+
+ }
+
+ /// <summary>
+ /// Boogie command-line options (other tools can subclass this class in order to support a
+ /// superset of Boogie's options.
+ /// </summary>
+ public class CommandLineOptions : CommandLineOptionEngine {
+
+ public CommandLineOptions()
+ : base("Boogie", "Boogie program verifier") {
+ }
+
+ protected CommandLineOptions(string toolName, string descriptiveName)
+ : base(toolName, descriptiveName) {
+ Contract.Requires(toolName != null);
+ Contract.Requires(descriptiveName != null);
+ }
+
+ private static CommandLineOptions clo;
+ public static CommandLineOptions/*!*/ Clo
+ {
+ get { return clo; }
+ }
+
+ public static void Install(CommandLineOptions options) {
+ Contract.Requires(options != null);
+ clo = options;
+ }
+
+ public const long Megabyte = 1048576;
+
+ // Flags and arguments
+
+ public bool RunningBoogieFromCommandLine = false; // "false" means running Boogie from the plug-in
+
+ [ContractInvariantMethod]
+ void ObjectInvariant2() {
+ Contract.Invariant(LogPrefix != null);
+ Contract.Invariant(0 <= PrintUnstructured && PrintUnstructured < 3); // 0 = print only structured, 1 = both structured and unstructured, 2 = only unstructured
+ }
+
+ public int VerifySnapshots = -1;
+ public bool VerifySeparately = false;
+ public string PrintFile = null;
+ public int PrintUnstructured = 0;
+ public bool UseBaseNameForFileName = false;
+ public int DoomStrategy = -1;
+ public bool DoomRestartTP = false;
+ public bool PrintDesugarings = false;
+ public string SimplifyLogFilePath = null;
+ public bool PrintInstrumented = false;
+ public bool InstrumentWithAsserts = false;
+ public string ProverPreamble = null;
+
+ public enum InstrumentationPlaces {
+ LoopHeaders,
+ Everywhere
+ }
+ public InstrumentationPlaces InstrumentInfer = InstrumentationPlaces.LoopHeaders;
+ public bool PrintWithUniqueASTIds = false;
+ private string XmlSinkFilename = null;
+ [Peer]
+ public XmlSink XmlSink = null;
+ public bool Wait = false;
+ public bool Trace = false;
+ public bool TraceTimes = false;
+ public bool TraceProofObligations = false;
+ public bool TraceCachingForTesting
+ {
+ get
+ {
+ return TraceCaching == 1 || TraceCaching == 3;
+ }
+ }
+ public bool TraceCachingForBenchmarking
+ {
+ get
+ {
+ return TraceCaching == 2 || TraceCaching == 3;
+ }
+ }
+ public bool TraceCachingForDebugging
+ {
+ get
+ {
+ return TraceCaching == 3;
+ }
+ }
+ internal int TraceCaching = 0;
+ public bool NoResolve = false;
+ public bool NoTypecheck = false;
+ public bool OverlookBoogieTypeErrors = false;
+ public bool Verify = true;
+ public bool TraceVerify = false;
+ public int /*(0:3)*/ ErrorTrace = 1;
+ public bool IntraproceduralInfer = true;
+ public bool ContractInfer = false;
+ public bool ExplainHoudini = false;
+ public bool ReverseHoudiniWorklist = false;
+ public bool ConcurrentHoudini = false;
+ public bool ModifyTopologicalSorting = false;
+ public bool DebugConcurrentHoudini = false;
+ public bool HoudiniUseCrossDependencies = false;
+ public string StagedHoudini = null;
+ public bool DebugStagedHoudini = false;
+ public bool StagedHoudiniReachabilityAnalysis = false;
+ public bool StagedHoudiniMergeIgnoredAnnotations = false;
+ public int StagedHoudiniThreads = 1;
+ public string VariableDependenceIgnore = null;
+ public string AbstractHoudini = null;
+ public bool UseUnsatCoreForContractInfer = false;
+ public bool PrintAssignment = false;
+ // TODO(wuestholz): Add documentation for this flag.
+ public bool PrintNecessaryAssumes = false;
+ public int InlineDepth = -1;
+ public bool UseProverEvaluate = false; // Use ProverInterface's Evaluate method, instead of model to get variable values
+ public bool UseUncheckedContracts = false;
+ public bool SimplifyLogFileAppend = false;
+ public bool SoundnessSmokeTest = false;
+ public string Z3ExecutablePath = null;
+ public string Z3ExecutableName = null;
+ public string CVC4ExecutablePath = null;
+ public int KInductionDepth = -1;
+
+ private string/*!*/ _logPrefix = "";
+
+ public string LogPrefix {
+ get {
+ Contract.Ensures(Contract.Result<string>() != null);
+ return this._logPrefix;
+ }
+ set {
+ Contract.Requires(value != null);
+ this._logPrefix = value;
+ }
+ }
+
+ public bool PrettyPrint = true;
+
+ public enum ProverWarnings {
+ None,
+ Stdout,
+ Stderr
+ }
+ public ProverWarnings PrintProverWarnings = ProverWarnings.None;
+ public int ProverShutdownLimit = 0;
+
+ public enum SubsumptionOption {
+ Never,
+ NotForQuantifiers,
+ Always
+ }
+ public SubsumptionOption UseSubsumption = SubsumptionOption.Always;
+
+ public bool AlwaysAssumeFreeLoopInvariants = false;
+
+ public enum ShowEnvironment {
+ Never,
+ DuringPrint,
+ Always
+ }
+ public ShowEnvironment ShowEnv = ShowEnvironment.DuringPrint;
+ public bool DontShowLogo = false;
+ [ContractInvariantMethod]
+ void ObjectInvariant3() {
+ Contract.Invariant(-1 <= LoopFrameConditions && LoopFrameConditions < 3);
+ Contract.Invariant(0 <= ModifiesDefault && ModifiesDefault < 7);
+ Contract.Invariant((0 <= PrintErrorModel && PrintErrorModel <= 2) || PrintErrorModel == 4);
+ Contract.Invariant(0 <= EnhancedErrorMessages && EnhancedErrorMessages < 2);
+ Contract.Invariant(0 <= StepsBeforeWidening && StepsBeforeWidening <= 9);
+ Contract.Invariant(-1 <= this.bracketIdsInVC && this.bracketIdsInVC <= 1);
+ Contract.Invariant(cce.NonNullElements(this.proverOptions));
+ }
+
+ public int LoopUnrollCount = -1; // -1 means don't unroll loops
+ public bool SoundLoopUnrolling = false;
+ public int LoopFrameConditions = -1; // -1 means not specified -- this will be replaced by the "implications" section below
+ public int ModifiesDefault = 5;
+ public bool LocalModifiesChecks = true;
+ public bool NoVerifyByDefault = false;
+ public enum OwnershipModelOption {
+ Standard,
+ Experimental,
+ Trivial
+ }
+ public OwnershipModelOption OwnershipModelEncoding = OwnershipModelOption.Standard;
+ public int PrintErrorModel = 0;
+ public string PrintErrorModelFile = null;
+ public string/*?*/ ModelViewFile = null;
+ public int EnhancedErrorMessages = 0;
+ public string PrintCFGPrefix = null;
+ public bool ForceBplErrors = false; // if true, boogie error is shown even if "msg" attribute is present
+ public bool UseArrayTheory = false;
+ public bool UseSmtOutputFormat = false;
+ public bool WeakArrayTheory = false;
+ public bool UseLabels = true;
+ public bool RunDiagnosticsOnTimeout = false;
+ public bool TraceDiagnosticsOnTimeout = false;
+ public int TimeLimitPerAssertionInPercent = 10;
+ public bool SIBoolControlVC = false;
+ public bool MonomorphicArrays {
+ get {
+ return UseArrayTheory || TypeEncodingMethod == TypeEncoding.Monomorphic;
+ }
+ }
+ public bool ExpandLambdas = true; // not useful from command line, only to be set to false programatically
+ public bool DoModSetAnalysis = false;
+ public bool UseAbstractInterpretation = true; // true iff the user want to use abstract interpretation
+ private int /*0..9*/stepsBeforeWidening = 0; // The number of steps that must be done before applying a widen operator
+
+ public int StepsBeforeWidening
+ {
+ get
+ {
+ Contract.Ensures(0 <= Contract.Result<int>() && Contract.Result<int>() <= 9);
+ return this.stepsBeforeWidening;
+ }
+ set
+ {
+ Contract.Requires(0 <= value && value <= 9);
+ this.stepsBeforeWidening = value;
+ }
+ }
+
+ public string CivlDesugaredFile = null;
+ public bool TrustAtomicityTypes = false;
+ public bool TrustNonInterference = false;
+ public int TrustLayersUpto = -1;
+ public int TrustLayersDownto = int.MaxValue;
+
+ public enum VCVariety {
+ Structured,
+ Block,
+ Local,
+ BlockNested,
+ BlockReach,
+ BlockNestedReach,
+ Dag,
+ DagIterative,
+ Doomed,
+ Unspecified
+ }
+ public VCVariety vcVariety = VCVariety.Unspecified; // will not be Unspecified after command line has been parsed
+
+ public bool RemoveEmptyBlocks = true;
+ public bool CoalesceBlocks = true;
+ public bool PruneInfeasibleEdges = true;
+
+ [Rep]
+ public ProverFactory TheProverFactory;
+ public string ProverName;
+ [Peer]
+ private List<string> proverOptions = new List<string>();
+
+ public IEnumerable<string> ProverOptions
+ {
+ set
+ {
+ Contract.Requires(cce.NonNullElements(value));
+
+ this.proverOptions = new List<string>(value);
+ }
+ get
+ {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<IEnumerable<string>>()));
+
+ foreach (string s in this.proverOptions)
+ yield return s;
+ }
+ }
+
+ [Obsolete("use the setter for 'ProverOptions' directly")]
+ public void AddProverOption(string option)
+ {
+ Contract.Requires(option != null);
+
+ this.ProverOptions = this.ProverOptions.Concat1(option);
+ }
+
+ [Obsolete("use the setter for 'ProverOptions' directly")]
+ public void RemoveAllProverOptions(Predicate<string> match)
+ {
+ this.ProverOptions = this.ProverOptions.Where(s => !match(s));
+ }
+
+ private int bracketIdsInVC = -1; // -1 - not specified, 0 - no, 1 - yes
+
+ public int BracketIdsInVC {
+ get {
+ Contract.Ensures(-1 <= Contract.Result<int>() && Contract.Result<int>() <= 1);
+ return this.bracketIdsInVC;
+ }
+ set {
+ Contract.Requires(-1 <= value && value <= 1);
+ this.bracketIdsInVC = value;
+ }
+ }
+
+ public bool CausalImplies = false;
+
+ public int SimplifyProverMatchDepth = -1; // -1 means not specified
+ public int ProverKillTime = -1; // -1 means not specified
+ public int SmokeTimeout = 10; // default to 10s
+ public int ProverCCLimit = 5;
+ public bool z3AtFlag = true;
+ public bool RestartProverPerVC = false;
+
+ public double VcsMaxCost = 1.0;
+ public double VcsPathJoinMult = 0.8;
+ public double VcsPathCostMult = 1.0;
+ public double VcsAssumeMult = 0.01;
+ public double VcsPathSplitMult = 0.5; // 0.5-always, 2-rarely do path splitting
+ public int VcsMaxSplits = 1;
+ public int VcsMaxKeepGoingSplits = 1;
+ public int VcsFinalAssertTimeout = 30;
+ public int VcsKeepGoingTimeout = 1;
+ public int VcsCores = 1;
+ public bool VcsDumpSplits = false;
+
+ public bool DebugRefuted = false;
+
+ public XmlSink XmlRefuted {
+ get {
+ if (DebugRefuted)
+ return XmlSink;
+ else
+ return null;
+ }
+ }
+ [ContractInvariantMethod]
+ void ObjectInvariant4() {
+ Contract.Invariant(cce.NonNullElements(this.z3Options));
+ Contract.Invariant(0 <= Z3lets && Z3lets < 4);
+ }
+
+ [Peer]
+ private List<string> z3Options = new List<string>();
+
+ public IEnumerable<string> Z3Options
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<IEnumerable<string>>() != null);
+ foreach (string s in z3Options)
+ yield return s;
+ }
+ }
+
+ public void AddZ3Option(string option)
+ {
+ Contract.Requires(option != null);
+ this.z3Options.Add(option);
+ }
+
+ public bool Z3types = false;
+ public int Z3lets = 3; // 0 - none, 1 - only LET TERM, 2 - only LET FORMULA, 3 - (default) any
+
+
+ // Maximum amount of virtual memory (in bytes) for the prover to use
+ //
+ // Non-positive number indicates unbounded.
+ public long MaxProverMemory = 100 * Megabyte;
+
+ // Minimum number of prover calls before restart
+ public int MinNumOfProverCalls = 5;
+
+ public enum PlatformType {
+ notSpecified,
+ v1,
+ v11,
+ v2,
+ cli1
+ }
+ public PlatformType TargetPlatform;
+ public string TargetPlatformLocation;
+ public string StandardLibraryLocation;
+
+ // whether procedure inlining is enabled at call sites.
+ public enum Inlining {
+ None,
+ Assert,
+ Assume,
+ Spec
+ };
+ public Inlining ProcedureInlining = Inlining.Assume;
+ public bool PrintInlined = false;
+ public bool ExtractLoops = false;
+ public bool DeterministicExtractLoops = false;
+ public string SecureVcGen = null;
+ public int StratifiedInlining = 0;
+ public string FixedPointEngine = null;
+ public int StratifiedInliningOption = 0;
+ public bool StratifiedInliningWithoutModels = false; // disable model generation for SI
+ public int StratifiedInliningVerbose = 0; // verbosity level
+ public int RecursionBound = 500;
+ public bool NonUniformUnfolding = false;
+ public int StackDepthBound = 0;
+ public string inferLeastForUnsat = null;
+
+ // Inference mode for fixed point engine
+ public enum FixedPointInferenceMode {
+ Corral,
+ OldCorral,
+ Flat,
+ Procedure,
+ Call
+ };
+ public FixedPointInferenceMode FixedPointMode = FixedPointInferenceMode.Procedure;
+
+ public string PrintFixedPoint = null;
+
+ public string PrintConjectures = null;
+
+ public bool ExtractLoopsUnrollIrreducible = true; // unroll irreducible loops? (set programmatically)
+
+ public enum TypeEncoding {
+ None,
+ Predicates,
+ Arguments,
+ Monomorphic
+ };
+ public TypeEncoding TypeEncodingMethod = TypeEncoding.Predicates;
+
+ public bool Monomorphize = false;
+
+ public bool ReflectAdd = false;
+
+ public int LiveVariableAnalysis = 1;
+
+ // Static constructor
+ static CommandLineOptions() {
+ if (System.Type.GetType("Mono.Runtime") == null) { // MONO
+ TraceListenerCollection/*!*/ dbl = Debug.Listeners;
+ Contract.Assert(dbl != null);
+ Contract.Assume(cce.IsPeerConsistent(dbl)); // hangs off static field
+ dbl.Add(new DefaultTraceListener());
+ }
+ }
+
+ public IEnumerable<string/*!*/> ProcsToCheck {
+ get {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<IEnumerable<string/*!*/>>(), true));
+ return this.procsToCheck != null ? this.procsToCheck.AsEnumerable() : null;
+ }
+ }
+
+ private List<string/*!*/> procsToCheck = null; // null means "no restriction"
+
+ [ContractInvariantMethod]
+ void ObjectInvariant5() {
+ Contract.Invariant(cce.NonNullElements(this.procsToCheck, true));
+ Contract.Invariant(Ai != null);
+ }
+
+ public class AiFlags {
+ public bool J_Trivial = false;
+ public bool J_Intervals = false;
+ public bool DebugStatistics = false;
+ }
+ public readonly AiFlags/*!*/ Ai = new AiFlags();
+
+ public class ConcurrentHoudiniOptions
+ {
+ public List<string> ProverOptions = new List<string>();
+ public int ProverCCLimit = 5;
+ public bool DisableLoopInvEntryAssert = false;
+ public bool DisableLoopInvMaintainedAssert = false;
+ public bool ModifyTopologicalSorting = false;
+ }
+ public List<ConcurrentHoudiniOptions> Cho = new List<ConcurrentHoudiniOptions>();
+
+ protected override bool ParseOption(string name, CommandLineOptionEngine.CommandLineParseState ps) {
+ var args = ps.args; // convenient synonym
+ switch (name) {
+ case "infer":
+ if (ps.ConfirmArgumentCount(1)) {
+ foreach (char c in cce.NonNull(args[ps.i])) {
+ switch (c) {
+ case 't':
+ Ai.J_Trivial = true;
+ UseAbstractInterpretation = true;
+ break;
+ case 'j':
+ Ai.J_Intervals = true;
+ UseAbstractInterpretation = true;
+ break;
+ case 's':
+ Ai.DebugStatistics = true;
+ UseAbstractInterpretation = true;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ StepsBeforeWidening = (int)char.GetNumericValue(c);
+ break;
+ default:
+ ps.Error("Invalid argument '{0}' to option {1}", c.ToString(), ps.s);
+ break;
+ }
+ }
+ }
+ return true;
+
+ case "noinfer":
+ if (ps.ConfirmArgumentCount(0)) {
+ UseAbstractInterpretation = false;
+ }
+ return true;
+
+ case "break":
+ case "launch":
+ if (ps.ConfirmArgumentCount(0)) {
+ System.Diagnostics.Debugger.Launch();
+ }
+ return true;
+
+ case "proc":
+ if (this.procsToCheck == null) {
+ this.procsToCheck = new List<string/*!*/>();
+ }
+ if (ps.ConfirmArgumentCount(1)) {
+ this.procsToCheck.Add(cce.NonNull(args[ps.i]));
+ }
+ return true;
+
+ case "xml":
+ if (ps.ConfirmArgumentCount(1)) {
+ XmlSinkFilename = args[ps.i];
+ }
+ return true;
+
+ case "print":
+ if (ps.ConfirmArgumentCount(1)) {
+ PrintFile = args[ps.i];
+ }
+ return true;
+
+ case "pretty":
+ int val = 1;
+ if (ps.GetNumericArgument(ref val, 2)) {
+ PrettyPrint = val == 1;
+ }
+ return true;
+
+ case "CivlDesugaredFile":
+ if (ps.ConfirmArgumentCount(1)) {
+ CivlDesugaredFile = args[ps.i];
+ }
+ return true;
+
+ case "trustLayersUpto":
+ if (ps.ConfirmArgumentCount(1))
+ {
+ ps.GetNumericArgument(ref TrustLayersUpto);
+ }
+ return true;
+
+ case "trustLayersDownto":
+ if (ps.ConfirmArgumentCount(1))
+ {
+ ps.GetNumericArgument(ref TrustLayersDownto);
+ }
+ return true;
+
+ case "proverLog":
+ if (ps.ConfirmArgumentCount(1)) {
+ SimplifyLogFilePath = args[ps.i];
+ }
+ return true;
+
+ case "proverPreamble":
+ if (ps.ConfirmArgumentCount(1))
+ {
+ ProverPreamble = args[ps.i];
+ }
+ return true;
+
+ case "logPrefix":
+ if (ps.ConfirmArgumentCount(1)) {
+ string s = cce.NonNull(args[ps.i]);
+ LogPrefix += s.Replace('/', '-').Replace('\\', '-');
+ }
+ return true;
+
+ case "proverShutdownLimit":
+ ps.GetNumericArgument(ref ProverShutdownLimit);
+ return true;
+
+ case "errorTrace":
+ ps.GetNumericArgument(ref ErrorTrace, 3);
+ return true;
+
+ case "proverWarnings": {
+ int pw = 0;
+ if (ps.GetNumericArgument(ref pw, 3)) {
+ switch (pw) {
+ case 0:
+ PrintProverWarnings = ProverWarnings.None;
+ break;
+ case 1:
+ PrintProverWarnings = ProverWarnings.Stdout;
+ break;
+ case 2:
+ PrintProverWarnings = ProverWarnings.Stderr;
+ break;
+ default: {
+ Contract.Assert(false);
+ throw new cce.UnreachableException();
+ } // postcondition of GetNumericArgument guarantees that we don't get here
+ }
+ }
+ return true;
+ }
+
+ case "env": {
+ int e = 0;
+ if (ps.GetNumericArgument(ref e, 3)) {
+ switch (e) {
+ case 0:
+ ShowEnv = ShowEnvironment.Never;
+ break;
+ case 1:
+ ShowEnv = ShowEnvironment.DuringPrint;
+ break;
+ case 2:
+ ShowEnv = ShowEnvironment.Always;
+ break;
+ default: {
+ Contract.Assert(false);
+ throw new cce.UnreachableException();
+ } // postcondition of GetNumericArgument guarantees that we don't get here
+ }
+ }
+ return true;
+ }
+
+ case "loopUnroll":
+ ps.GetNumericArgument(ref LoopUnrollCount);
+ return true;
+
+ case "printModel":
+ if (ps.ConfirmArgumentCount(1)) {
+ switch (args[ps.i]) {
+ case "0":
+ PrintErrorModel = 0;
+ break;
+ case "1":
+ PrintErrorModel = 1;
+ break;
+ case "2":
+ PrintErrorModel = 2;
+ break;
+ case "4":
+ PrintErrorModel = 4;
+ break;
+ default:
+ ps.Error("Invalid argument \"{0}\" to option {1}", args[ps.i], ps.s);
+ break;
+ }
+ }
+ return true;
+
+ case "mv":
+ if (ps.ConfirmArgumentCount(1)) {
+ ModelViewFile = args[ps.i];
+ }
+ return true;
+
+ case "printModelToFile":
+ if (ps.ConfirmArgumentCount(1)) {
+ PrintErrorModelFile = args[ps.i];
+ }
+ return true;
+
+ case "enhancedErrorMessages":
+ ps.GetNumericArgument(ref EnhancedErrorMessages, 2);
+ return true;
+
+ case "printCFG":
+ if (ps.ConfirmArgumentCount(1)) {
+ PrintCFGPrefix = args[ps.i];
+ }
+ return true;
+
+ case "inlineDepth":
+ ps.GetNumericArgument(ref InlineDepth);
+ return true;
+
+ case "subsumption": {
+ int s = 0;
+ if (ps.GetNumericArgument(ref s, 3)) {
+ switch (s) {
+ case 0:
+ UseSubsumption = SubsumptionOption.Never;
+ break;
+ case 1:
+ UseSubsumption = SubsumptionOption.NotForQuantifiers;
+ break;
+ case 2:
+ UseSubsumption = SubsumptionOption.Always;
+ break;
+ default: {
+ Contract.Assert(false);
+ throw new cce.UnreachableException();
+ } // postcondition of GetNumericArgument guarantees that we don't get here
+ }
+ }
+ return true;
+ }
+
+ case "liveVariableAnalysis": {
+ int lva = 0;
+ if (ps.GetNumericArgument(ref lva, 3)) {
+ LiveVariableAnalysis = lva;
+ }
+ return true;
+ }
+
+ case "removeEmptyBlocks": {
+ int reb = 0;
+ if (ps.GetNumericArgument(ref reb, 2)) {
+ RemoveEmptyBlocks = reb == 1;
+ }
+ return true;
+ }
+
+ case "coalesceBlocks": {
+ int cb = 0;
+ if (ps.GetNumericArgument(ref cb, 2)) {
+ CoalesceBlocks = cb == 1;
+ }
+ return true;
+ }
+
+ case "noPruneInfeasibleEdges": {
+ if (ps.ConfirmArgumentCount(0)) {
+ PruneInfeasibleEdges = false;
+ }
+ return true;
+ }
+
+ case "stagedHoudini": {
+ if (ps.ConfirmArgumentCount(1)) {
+ if(args[ps.i] == "COARSE" ||
+ args[ps.i] == "FINE" ||
+ args[ps.i] == "BALANCED") {
+ StagedHoudini = args[ps.i];
+ } else {
+ ps.Error("Invalid argument \"{0}\" to option {1}", args[ps.i], ps.s);
+ }
+ }
+ return true;
+ }
+
+ case "stagedHoudiniThreads": {
+ ps.GetNumericArgument(ref StagedHoudiniThreads);
+ return true;
+ }
+
+ case "stagedHoudiniReachabilityAnalysis": {
+ if (ps.ConfirmArgumentCount(0)) {
+ StagedHoudiniReachabilityAnalysis = true;
+ }
+ return true;
+ }
+
+ case "stagedHoudiniMergeIgnoredAnnotations": {
+ if (ps.ConfirmArgumentCount(0)) {
+ StagedHoudiniMergeIgnoredAnnotations = true;
+ }
+ return true;
+ }
+
+ case "debugStagedHoudini": {
+ if (ps.ConfirmArgumentCount(0)) {
+ DebugStagedHoudini = true;
+ }
+ return true;
+ }
+
+ case "variableDependenceIgnore": {
+ if (ps.ConfirmArgumentCount(1)) {
+ VariableDependenceIgnore = args[ps.i];
+ }
+ return true;
+ }
+
+ case "abstractHoudini":
+ {
+ if (ps.ConfirmArgumentCount(1))
+ {
+ AbstractHoudini = args[ps.i];
+ }
+ return true;
+ }
+ case "vc":
+ if (ps.ConfirmArgumentCount(1)) {
+ switch (args[ps.i]) {
+ case "s":
+ case "structured":
+ vcVariety = VCVariety.Structured;
+ break;
+ case "b":
+ case "block":
+ vcVariety = VCVariety.Block;
+ break;
+ case "l":
+ case "local":
+ vcVariety = VCVariety.Local;
+ break;
+ case "n":
+ case "nested":
+ vcVariety = VCVariety.BlockNested;
+ break;
+ case "m":
+ vcVariety = VCVariety.BlockNestedReach;
+ break;
+ case "r":
+ vcVariety = VCVariety.BlockReach;
+ break;
+ case "d":
+ case "dag":
+ vcVariety = VCVariety.Dag;
+ break;
+ case "i":
+ vcVariety = VCVariety.DagIterative;
+ break;
+ case "doomed":
+ vcVariety = VCVariety.Doomed;
+ break;
+ default:
+ ps.Error("Invalid argument \"{0}\" to option {1}", args[ps.i], ps.s);
+ break;
+ }
+ }
+ return true;
+
+ case "prover":
+ if (ps.ConfirmArgumentCount(1)) {
+ TheProverFactory = ProverFactory.Load(cce.NonNull(args[ps.i]));
+ ProverName = cce.NonNull(args[ps.i]).ToUpper();
+ }
+ return true;
+
+ case "p":
+ case "proverOpt":
+ if (ps.ConfirmArgumentCount(1)) {
+ ProverOptions = ProverOptions.Concat1(cce.NonNull(args[ps.i]));
+ }
+ return true;
+
+ case "DoomStrategy":
+ ps.GetNumericArgument(ref DoomStrategy);
+ return true;
+
+ case "DoomRestartTP":
+ if (ps.ConfirmArgumentCount(0)) {
+ DoomRestartTP = true;
+ }
+ return true;
+
+ case "extractLoops":
+ if (ps.ConfirmArgumentCount(0)) {
+ ExtractLoops = true;
+ }
+ return true;
+
+ case "deterministicExtractLoops":
+ if (ps.ConfirmArgumentCount(0)) {
+ DeterministicExtractLoops = true;
+ }
+ return true;
+
+ case "inline":
+ if (ps.ConfirmArgumentCount(1)) {
+ switch (args[ps.i]) {
+ case "none":
+ ProcedureInlining = Inlining.None;
+ break;
+ case "assert":
+ ProcedureInlining = Inlining.Assert;
+ break;
+ case "assume":
+ ProcedureInlining = Inlining.Assume;
+ break;
+ case "spec":
+ ProcedureInlining = Inlining.Spec;
+ break;
+ default:
+ ps.Error("Invalid argument \"{0}\" to option {1}", args[ps.i], ps.s);
+ break;
+ }
+ }
+ return true;
+ case "secure":
+ if (ps.ConfirmArgumentCount(1))
+ SecureVcGen = args[ps.i];
+ return true;
+ case "stratifiedInline":
+ if (ps.ConfirmArgumentCount(1)) {
+ switch (args[ps.i]) {
+ case "0":
+ StratifiedInlining = 0;
+ break;
+ case "1":
+ StratifiedInlining = 1;
+ break;
+ default:
+ StratifiedInlining = Int32.Parse(cce.NonNull(args[ps.i]));
+ //ps.Error("Invalid argument \"{0}\" to option {1}", args[ps.i], ps.s);
+ break;
+ }
+ }
+ return true;
+ case "fixedPointEngine":
+ if (ps.ConfirmArgumentCount(1))
+ {
+ FixedPointEngine = args[ps.i];
+ }
+ return true;
+ case "fixedPointInfer":
+ if (ps.ConfirmArgumentCount(1))
+ {
+ switch (args[ps.i])
+ {
+ case "corral":
+ FixedPointMode = FixedPointInferenceMode.Corral;
+ break;
+ case "oldCorral":
+ FixedPointMode = FixedPointInferenceMode.OldCorral;
+ break;
+ case "flat":
+ FixedPointMode = FixedPointInferenceMode.Flat;
+ break;
+ case "procedure":
+ FixedPointMode = FixedPointInferenceMode.Procedure;
+ break;
+ case "call":
+ FixedPointMode = FixedPointInferenceMode.Call;
+ break;
+ default:
+ ps.Error("Invalid argument \"{0}\" to option {1}", args[ps.i], ps.s);
+ break;
+ }
+ }
+ return true;
+ case "printFixedPoint":
+ if (ps.ConfirmArgumentCount(1))
+ {
+ PrintFixedPoint = args[ps.i];
+ }
+ return true;
+ case "printConjectures":
+ if (ps.ConfirmArgumentCount(1))
+ {
+ PrintConjectures = args[ps.i];
+ }
+ return true;
+ case "siVerbose":
+ if (ps.ConfirmArgumentCount(1)) {
+ StratifiedInliningVerbose = Int32.Parse(cce.NonNull(args[ps.i]));
+ }
+ return true;
+ case "recursionBound":
+ if (ps.ConfirmArgumentCount(1)) {
+ RecursionBound = Int32.Parse(cce.NonNull(args[ps.i]));
+ }
+ return true;
+ case "stackDepthBound":
+ if (ps.ConfirmArgumentCount(1))
+ {
+ StackDepthBound = Int32.Parse(cce.NonNull(args[ps.i]));
+ }
+ return true;
+ case "stratifiedInlineOption":
+ if (ps.ConfirmArgumentCount(1)) {
+ StratifiedInliningOption = Int32.Parse(cce.NonNull(args[ps.i]));
+ }
+ return true;
+
+ case "inferLeastForUnsat":
+ if (ps.ConfirmArgumentCount(1)) {
+ inferLeastForUnsat = args[ps.i];
+ }
+ return true;
+
+ case "typeEncoding":
+ if (ps.ConfirmArgumentCount(1)) {
+ switch (args[ps.i]) {
+ case "n":
+ case "none":
+ TypeEncodingMethod = TypeEncoding.None;
+ break;
+ case "p":
+ case "predicates":
+ TypeEncodingMethod = TypeEncoding.Predicates;
+ break;
+ case "a":
+ case "arguments":
+ TypeEncodingMethod = TypeEncoding.Arguments;
+ break;
+ case "m":
+ case "monomorphic":
+ TypeEncodingMethod = TypeEncoding.Monomorphic;
+ break;
+ default:
+ ps.Error("Invalid argument \"{0}\" to option {1}", args[ps.i], ps.s);
+ break;
+ }
+ }
+ return true;
+
+ case "instrumentInfer":
+ if (ps.ConfirmArgumentCount(1)) {
+ switch (args[ps.i]) {
+ case "e":
+ InstrumentInfer = InstrumentationPlaces.Everywhere;
+ break;
+ case "h":
+ InstrumentInfer = InstrumentationPlaces.LoopHeaders;
+ break;
+ default:
+ ps.Error("Invalid argument \"{0}\" to option {1}", args[ps.i], ps.s);
+ break;
+ }
+ }
+ return true;
+
+ case "concurrentHoudini":
+ if (ps.ConfirmArgumentCount(0)) {
+ ConcurrentHoudini = true;
+ }
+ return true;
+
+ case "modifyTopologicalSorting":
+ if (ps.ConfirmArgumentCount(0)) {
+ ModifyTopologicalSorting = true;
+ }
+ return true;
+
+ case "debugConcurrentHoudini":
+ if (ps.ConfirmArgumentCount(0)) {
+ DebugConcurrentHoudini = true;
+ }
+ return true;
+
+ case "vcBrackets":
+ ps.GetNumericArgument(ref bracketIdsInVC, 2);
+ return true;
+
+ case "proverMemoryLimit": {
+ int d = 0;
+ if (ps.GetNumericArgument(ref d)) {
+ MaxProverMemory = d * Megabyte;
+ }
+ return true;
+ }
+
+ case "vcsMaxCost":
+ ps.GetNumericArgument(ref VcsMaxCost);
+ return true;
+
+ case "vcsPathJoinMult":
+ ps.GetNumericArgument(ref VcsPathJoinMult);
+ return true;
+
+ case "vcsPathCostMult":
+ ps.GetNumericArgument(ref VcsPathCostMult);
+ return true;
+
+ case "vcsAssumeMult":
+ ps.GetNumericArgument(ref VcsAssumeMult);
+ return true;
+
+ case "vcsPathSplitMult":
+ ps.GetNumericArgument(ref VcsPathSplitMult);
+ return true;
+
+ case "vcsMaxSplits":
+ ps.GetNumericArgument(ref VcsMaxSplits);
+ return true;
+
+ case "vcsMaxKeepGoingSplits":
+ ps.GetNumericArgument(ref VcsMaxKeepGoingSplits);
+ return true;
+
+ case "vcsFinalAssertTimeout":
+ ps.GetNumericArgument(ref VcsFinalAssertTimeout);
+ return true;
+
+ case "vcsKeepGoingTimeout":
+ ps.GetNumericArgument(ref VcsKeepGoingTimeout);
+ return true;
+
+ case "vcsCores":
+ ps.GetNumericArgument(ref VcsCores, a => 1 <= a);
+ return true;
+
+ case "vcsLoad":
+ double load = 0.0;
+ if (ps.GetNumericArgument(ref load)) {
+ if (3.0 <= load) {
+ ps.Error("surprisingly high load specified; got {0}, expected nothing above 3.0", load.ToString());
+ load = 3.0;
+ }
+ int p = (int)Math.Round(System.Environment.ProcessorCount * load);
+ VcsCores = p < 1 ? 1 : p;
+ }
+ return true;
+
+ case "simplifyMatchDepth":
+ ps.GetNumericArgument(ref SimplifyProverMatchDepth);
+ return true;
+
+ case "timeLimit":
+ ps.GetNumericArgument(ref ProverKillTime);
+ return true;
+
+ case "timeLimitPerAssertionInPercent":
+ ps.GetNumericArgument(ref TimeLimitPerAssertionInPercent, a => 0 < a);
+ return true;
+
+ case "smokeTimeout":
+ ps.GetNumericArgument(ref SmokeTimeout);
+ return true;
+
+ case "errorLimit":
+ ps.GetNumericArgument(ref ProverCCLimit);
+ return true;
+
+ case "verifySnapshots":
+ ps.GetNumericArgument(ref VerifySnapshots, 4);
+ return true;
+
+ case "traceCaching":
+ ps.GetNumericArgument(ref TraceCaching, 4);
+ return true;
+
+ case "useSmtOutputFormat": {
+ if (ps.ConfirmArgumentCount(0)) {
+ UseSmtOutputFormat = true;
+ }
+ return true;
+ }
+
+ case "z3opt":
+ if (ps.ConfirmArgumentCount(1)) {
+ AddZ3Option(cce.NonNull(args[ps.i]));
+ }
+ return true;
+
+ case "z3lets":
+ ps.GetNumericArgument(ref Z3lets, 4);
+ return true;
+
+ case "platform":
+ if (ps.ConfirmArgumentCount(1)) {
+ StringCollection platformOptions = this.ParseNamedArgumentList(args[ps.i]);
+ if (platformOptions != null && platformOptions.Count > 0) {
+ try {
+ this.TargetPlatform = (PlatformType)cce.NonNull(Enum.Parse(typeof(PlatformType), cce.NonNull(platformOptions[0])));
+ } catch {
+ ps.Error("Bad /platform type '{0}'", platformOptions[0]);
+ break;
+ }
+ if (platformOptions.Count > 1) {
+ this.TargetPlatformLocation = platformOptions[1];
+ if (!Directory.Exists(platformOptions[1])) {
+ ps.Error("/platform directory '{0}' does not exist", platformOptions[1]);
+ break;
+ }
+ }
+ }
+ }
+ return true;
+
+ case "z3exe":
+ if (ps.ConfirmArgumentCount(1)) {
+ Z3ExecutablePath = args[ps.i];
+ }
+ return true;
+ // This sets name of z3 binary boogie binary directory, not path
+ case "z3name":
+ if (ps.ConfirmArgumentCount(1))
+ {
+ Z3ExecutableName = args[ps.i];
+ }
+ return true;
+
+ case "cvc4exe":
+ if (ps.ConfirmArgumentCount(1)) {
+ CVC4ExecutablePath = args[ps.i];
+ }
+ return true;
+
+ case "kInductionDepth":
+ ps.GetNumericArgument(ref KInductionDepth);
+ return true;
+
+ default:
+ bool optionValue = false;
+ if (ps.CheckBooleanFlag("printUnstructured", ref optionValue)) {
+ PrintUnstructured = optionValue ? 1 : 0;
+ return true;
+ }
+
+ if (ps.CheckBooleanFlag("printDesugared", ref PrintDesugarings) ||
+ ps.CheckBooleanFlag("printInstrumented", ref PrintInstrumented) ||
+ ps.CheckBooleanFlag("printWithUniqueIds", ref PrintWithUniqueASTIds) ||
+ ps.CheckBooleanFlag("wait", ref Wait) ||
+ ps.CheckBooleanFlag("trace", ref Trace) ||
+ ps.CheckBooleanFlag("traceTimes", ref TraceTimes) ||
+ ps.CheckBooleanFlag("tracePOs", ref TraceProofObligations) ||
+ ps.CheckBooleanFlag("noResolve", ref NoResolve) ||
+ ps.CheckBooleanFlag("noTypecheck", ref NoTypecheck) ||
+ ps.CheckBooleanFlag("overlookTypeErrors", ref OverlookBoogieTypeErrors) ||
+ ps.CheckBooleanFlag("noVerify", ref Verify, false) ||
+ ps.CheckBooleanFlag("traceverify", ref TraceVerify) ||
+ ps.CheckBooleanFlag("alwaysAssumeFreeLoopInvariants", ref AlwaysAssumeFreeLoopInvariants, true) ||
+ ps.CheckBooleanFlag("nologo", ref DontShowLogo) ||
+ ps.CheckBooleanFlag("proverLogAppend", ref SimplifyLogFileAppend) ||
+ ps.CheckBooleanFlag("soundLoopUnrolling", ref SoundLoopUnrolling) ||
+ ps.CheckBooleanFlag("checkInfer", ref InstrumentWithAsserts) ||
+ ps.CheckBooleanFlag("interprocInfer", ref IntraproceduralInfer, false) ||
+ ps.CheckBooleanFlag("restartProver", ref RestartProverPerVC) ||
+ ps.CheckBooleanFlag("printInlined", ref PrintInlined) ||
+ ps.CheckBooleanFlag("smoke", ref SoundnessSmokeTest) ||
+ ps.CheckBooleanFlag("vcsDumpSplits", ref VcsDumpSplits) ||
+ ps.CheckBooleanFlag("dbgRefuted", ref DebugRefuted) ||
+ ps.CheckBooleanFlag("causalImplies", ref CausalImplies) ||
+ ps.CheckBooleanFlag("reflectAdd", ref ReflectAdd) ||
+ ps.CheckBooleanFlag("z3types", ref Z3types) ||
+ ps.CheckBooleanFlag("z3multipleErrors", ref z3AtFlag, false) ||
+ ps.CheckBooleanFlag("monomorphize", ref Monomorphize) ||
+ ps.CheckBooleanFlag("useArrayTheory", ref UseArrayTheory) ||
+ ps.CheckBooleanFlag("weakArrayTheory", ref WeakArrayTheory) ||
+ ps.CheckBooleanFlag("doModSetAnalysis", ref DoModSetAnalysis) ||
+ ps.CheckBooleanFlag("doNotUseLabels", ref UseLabels, false) ||
+ ps.CheckBooleanFlag("runDiagnosticsOnTimeout", ref RunDiagnosticsOnTimeout) ||
+ ps.CheckBooleanFlag("traceDiagnosticsOnTimeout", ref TraceDiagnosticsOnTimeout) ||
+ ps.CheckBooleanFlag("boolControlVC", ref SIBoolControlVC, true) ||
+ ps.CheckBooleanFlag("contractInfer", ref ContractInfer) ||
+ ps.CheckBooleanFlag("explainHoudini", ref ExplainHoudini) ||
+ ps.CheckBooleanFlag("reverseHoudiniWorklist", ref ReverseHoudiniWorklist) ||
+ ps.CheckBooleanFlag("crossDependencies", ref HoudiniUseCrossDependencies) ||
+ ps.CheckBooleanFlag("useUnsatCoreForContractInfer", ref UseUnsatCoreForContractInfer) ||
+ ps.CheckBooleanFlag("printAssignment", ref PrintAssignment) ||
+ ps.CheckBooleanFlag("printNecessaryAssumes", ref PrintNecessaryAssumes) ||
+ ps.CheckBooleanFlag("useProverEvaluate", ref UseProverEvaluate) ||
+ ps.CheckBooleanFlag("nonUniformUnfolding", ref NonUniformUnfolding) ||
+ ps.CheckBooleanFlag("deterministicExtractLoops", ref DeterministicExtractLoops) ||
+ ps.CheckBooleanFlag("verifySeparately", ref VerifySeparately) ||
+ ps.CheckBooleanFlag("trustAtomicityTypes", ref TrustAtomicityTypes) ||
+ ps.CheckBooleanFlag("trustNonInterference", ref TrustNonInterference) ||
+ ps.CheckBooleanFlag("useBaseNameForFileName", ref UseBaseNameForFileName)
+ ) {
+ // one of the boolean flags matched
+ return true;
+ }
+ break;
+ }
+
+ return base.ParseOption(name, ps); // defer to superclass
+ }
+
+ public override void ApplyDefaultOptions() {
+ Contract.Ensures(TheProverFactory != null);
+ Contract.Ensures(vcVariety != VCVariety.Unspecified);
+
+ base.ApplyDefaultOptions();
+
+ // expand macros in filenames, now that LogPrefix is fully determined
+ ExpandFilename(ref XmlSinkFilename, LogPrefix, FileTimestamp);
+ ExpandFilename(ref PrintFile, LogPrefix, FileTimestamp);
+ ExpandFilename(ref SimplifyLogFilePath, LogPrefix, FileTimestamp);
+ ExpandFilename(ref PrintErrorModelFile, LogPrefix, FileTimestamp);
+
+ Contract.Assume(XmlSink == null); // XmlSink is to be set here
+ if (XmlSinkFilename != null) {
+ XmlSink = new XmlSink(XmlSinkFilename);
+ }
+
+ if (TheProverFactory == null) {
+ TheProverFactory = ProverFactory.Load("SMTLib");
+ ProverName = "SMTLib".ToUpper();
+ }
+
+ var proverOpts = TheProverFactory.BlankProverOptions();
+ proverOpts.Parse(ProverOptions);
+ if (!TheProverFactory.SupportsLabels(proverOpts)) {
+ UseLabels = false;
+ }
+
+ if (vcVariety == VCVariety.Unspecified) {
+ vcVariety = TheProverFactory.DefaultVCVariety;
+ }
+
+ if (UseArrayTheory) {
+ Monomorphize = true;
+ }
+
+ if (inferLeastForUnsat != null) {
+ StratifiedInlining = 1;
+ }
+
+ if (StratifiedInlining > 0) {
+ TypeEncodingMethod = TypeEncoding.Monomorphic;
+ UseArrayTheory = true;
+ UseAbstractInterpretation = false;
+ MaxProverMemory = 0; // no max: avoids restarts
+ if (ProverName == "Z3API" || ProverName == "SMTLIB") {
+ ProverCCLimit = 1;
+ }
+ if (UseProverEvaluate)
+ StratifiedInliningWithoutModels = true;
+ }
+
+ if (Trace) {
+ BoogieDebug.DoPrinting = true; // reuse the -trace option for debug printing
+ }
+ }
+
+
+
+ public bool UserWantsToCheckRoutine(string methodFullname) {
+ Contract.Requires(methodFullname != null);
+ if (ProcsToCheck == null) {
+ // no preference
+ return true;
+ }
+ return ProcsToCheck.Any(s => Regex.IsMatch(methodFullname, "^" + Regex.Escape(s).Replace(@"\*", ".*") + "$"));
+ }
+
+ public virtual StringCollection ParseNamedArgumentList(string argList) {
+ if (argList == null || argList.Length == 0)
+ return null;
+ StringCollection result = new StringCollection();
+ int i = 0;
+ for (int n = argList.Length; i < n; ) {
+ cce.LoopInvariant(0 <= i);
+ int separatorIndex = this.GetArgumentSeparatorIndex(argList, i);
+ if (separatorIndex > i) {
+ result.Add(argList.Substring(i, separatorIndex - i));
+ i = separatorIndex + 1;
+ continue;
+ }
+ result.Add(argList.Substring(i));
+ break;
+ }
+ return result;
+ }
+ public int GetArgumentSeparatorIndex(string argList, int startIndex) {
+ Contract.Requires(argList != null);
+ Contract.Requires(0 <= startIndex && startIndex <= argList.Length);
+ Contract.Ensures(Contract.Result<int>() < argList.Length);
+ int commaIndex = argList.IndexOf(",", startIndex);
+ int semicolonIndex = argList.IndexOf(";", startIndex);
+ if (commaIndex == -1)
+ return semicolonIndex;
+ if (semicolonIndex == -1)
+ return commaIndex;
+ if (commaIndex < semicolonIndex)
+ return commaIndex;
+ return semicolonIndex;
+ }
+
+ public override void AttributeUsage() {
+ Console.WriteLine(
+@"Boogie: The following attributes are supported by this implementation.
+
+ ---- On top-level declarations ---------------------------------------------
+
+ {:ignore}
+ Ignore the declaration (after checking for duplicate names).
+
+ {:extern}
+ If two top-level declarations introduce the same name (for example, two
+ constants with the same name or two procedures with the same name), then
+ Boogie usually produces an error message. However, if at least one of
+ the declarations is declared with :extern, one of the declarations is
+ ignored. If both declarations are :extern, Boogie arbitrarily chooses
+ one of them to keep; otherwise, Boogie ignore the :extern declaration
+ and keeps the other.
+
+ {:checksum <string>}
+ Attach a checksum to be used for verification result caching.
+
+ ---- On implementations and procedures -------------------------------------
+
+ {:inline N}
+ Inline given procedure (can be also used on implementation).
+ N should be a non-negative number and represents the inlining depth.
+ With /inline:assume call is replaced with ""assume false"" once inlining depth is reached.
+ With /inline:assert call is replaced with ""assert false"" once inlining depth is reached.
+ With /inline:spec call is left as is once inlining depth is reached.
+ With the above three options, methods with the attribute {:inline N} are not verified.
+ With /inline:none the entire attribute is ignored.
+
+ {:verify false}
+ Skip verification of an implementation.
+
+ {:vcs_max_cost N}
+ {:vcs_max_splits N}
+ {:vcs_max_keep_going_splits N}
+ Per-implementation versions of
+ /vcsMaxCost, /vcsMaxSplits and /vcsMaxKeepGoingSplits.
+
+ {:selective_checking true}
+ Turn all asserts into assumes except for the ones reachable from
+ assumptions marked with the attribute {:start_checking_here}.
+ Thus, ""assume {:start_checking_here} something;"" becomes an inverse
+ of ""assume false;"": the first one disables all verification before
+ it, and the second one disables all verification after.
+
+ {:priority N}
+ Assign a positive priority 'N' to an implementation to control the order
+ in which implementations are verified (default: N = 1).
+
+ {:id <string>}
+ Assign a unique ID to an implementation to be used for verification
+ result caching (default: ""<impl. name>:0"").
+
+ {:timeLimit N}
+ Set the time limit for a given implementation.
+
+ ---- On functions ----------------------------------------------------------
+
+ {:builtin ""spec""}
+ {:bvbuiltin ""spec""}
+ Rewrite the function to built-in prover function symbol 'fn'.
+
+ {:inline}
+ {:inline true}
+ Expand function according to its definition before going to the prover.
+
+ {:never_pattern true}
+ Terms starting with this function symbol will never be
+ automatically selected as patterns. It does not prevent them
+ from being used inside the triggers, and does not affect explicit
+ trigger annotations. Internally it works by adding {:nopats ...}
+ annotations to quantifiers.
+
+ {:identity}
+ {:identity true}
+ If the function has 1 argument and the use of it has type X->X for
+ some X, then the abstract interpreter will treat the function as an
+ identity function. Note, the abstract interpreter trusts the
+ attribute--it does not try to verify that the function really is an
+ identity function.
+
+ ---- On variables ----------------------------------------------------------
+
+ {:existential true}
+ Marks a global Boolean variable as existentially quantified. If
+ used in combination with option /contractInfer Boogie will check
+ whether there exists a Boolean assignment to the existentials
+ that makes all verification conditions valid. Without option
+ /contractInfer the attribute is ignored.
+
+ ---- On assert statements --------------------------------------------------
+
+ {:subsumption n}
+ Overrides the /subsumption command-line setting for this assertion.
+
+ {:split_here}
+ Verifies code leading to this point and code leading from this point
+ to the next split_here as separate pieces. May help with timeouts.
+ May also occasionally double-report errors.
+
+ ---- The end ---------------------------------------------------------------
+");
+ }
+
+ public override void Usage() {
+ Console.WriteLine(@"
+ /nologo suppress printing of version number, copyright message
+ /env:<n> print command line arguments
+ 0 - never, 1 (default) - during BPL print and prover log,
+ 2 - like 1 and also to standard output
+ /wait await Enter from keyboard before terminating program
+ /xml:<file> also produce output in XML format to <file>
+
+ ---- Boogie options --------------------------------------------------------
+
+ Multiple .bpl files supplied on the command line are concatenated into one
+ Boogie program.
+
+ /proc:<p> : Only check procedures matched by pattern <p>. This option
+ may be specified multiple times to match multiple patterns.
+ The pattern <p> matches the whole procedure name (i.e.
+ pattern ""foo"" will only match a procedure called foo and
+ not fooBar). The pattern <p> may contain * wildcards which
+ match any character zero or more times. For example the
+ pattern ""ab*d"" would match abd, abcd and abccd but not
+ Aabd nor abdD. The pattern ""*ab*d*"" would match abd,
+ abcd, abccd, Abd and abdD.
+ /noResolve : parse only
+ /noTypecheck : parse and resolve only
+
+ /print:<file> : print Boogie program after parsing it
+ (use - as <file> to print to console)
+ /pretty:<n>
+ 0 - print each Boogie statement on one line (faster).
+ 1 (default) - pretty-print with some line breaks.
+ /printWithUniqueIds : print augmented information that uniquely
+ identifies variables
+ /printUnstructured : with /print option, desugars all structured statements
+ /printDesugared : with /print option, desugars calls
+
+ /overlookTypeErrors : skip any implementation with resolution or type
+ checking errors
+
+ /loopUnroll:<n>
+ unroll loops, following up to n back edges (and then some)
+ /soundLoopUnrolling
+ sound loop unrolling
+ /printModel:<n>
+ 0 (default) - do not print Z3's error model
+ 1 - print Z3's error model
+ 2 - print Z3's error model plus reverse mappings
+ 4 - print Z3's error model in a more human readable way
+ /printModelToFile:<file>
+ print model to <file> instead of console
+ /mv:<file> Specify file where to save the model in BVD format
+ /enhancedErrorMessages:<n>
+ 0 (default) - no enhanced error messages
+ 1 - Z3 error model enhanced error messages
+
+ /printCFG:<prefix> : print control flow graph of each implementation in
+ Graphviz format to files named:
+ <prefix>.<procedure name>.dot
+
+ /useBaseNameForFileName : When parsing use basename of file for tokens instead
+ of the path supplied on the command line
+
+ ---- Inference options -----------------------------------------------------
+
+ /infer:<flags>
+ use abstract interpretation to infer invariants
+ The default is /infer:i"
+ // This is not 100% true, as the /infer ALWAYS creates
+ // a multilattice, whereas if nothing is specified then
+ // intervals are isntantiated WITHOUT being embedded in
+ // a multilattice
+ + @"
+ <flags> are as follows (missing <flags> means all)
+ i = intervals
+ c = constant propagation
+ d = dynamic type
+ n = nullness
+ p = polyhedra for linear inequalities
+ t = trivial bottom/top lattice (cannot be combined with
+ other domains)
+ j = stronger intervals (cannot be combined with other
+ domains)
+ or the following (which denote options, not domains):
+ s = debug statistics
+ 0..9 = number of iterations before applying a widen (default=0)
+ /noinfer turn off the default inference, and overrides the /infer
+ switch on its left
+ /checkInfer instrument inferred invariants as asserts to be checked by
+ theorem prover
+ /interprocInfer
+ perform interprocedural inference (deprecated, not supported)
+ /contractInfer
+ perform procedure contract inference
+ /instrumentInfer
+ h - instrument inferred invariants only at beginning of
+ loop headers (default)
+ e - instrument inferred invariants at beginning and end
+ of every block (this mode is intended for use in
+ debugging of abstract domains)
+ /printInstrumented
+ print Boogie program after it has been instrumented with
+ invariants
+
+ ---- Debugging and general tracing options ---------------------------------
+
+ /trace blurt out various debug trace information
+ /traceTimes output timing information at certain points in the pipeline
+ /tracePOs output information about the number of proof obligations
+ (also included in the /trace output)
+ /log[:method] Print debug output during translation
+
+ /break launch and break into debugger
+
+ ---- Verification-condition generation options -----------------------------
+
+ /liveVariableAnalysis:<c>
+ 0 = do not perform live variable analysis
+ 1 = perform live variable analysis (default)
+ 2 = perform interprocedural live variable analysis
+ /noVerify skip VC generation and invocation of the theorem prover
+ /verifySnapshots:<n>
+ verify several program snapshots (named <filename>.v0.bpl
+ to <filename>.vN.bpl) using verification result caching:
+ 0 - do not use any verification result caching (default)
+ 1 - use the basic verification result caching
+ 2 - use the more advanced verification result caching
+ 3 - use the more advanced caching and report errors according
+ to the new source locations for errors and their
+ related locations (but not /errorTrace and CaptureState
+ locations)
+ /verifySeparately
+ verify each input program separately
+ /removeEmptyBlocks:<c>
+ 0 - do not remove empty blocks during VC generation
+ 1 - remove empty blocks (default)
+ /coalesceBlocks:<c>
+ 0 = do not coalesce blocks
+ 1 = coalesce blocks (default)
+ /vc:<variety> n = nested block (default for /prover:Simplify),
+ m = nested block reach,
+ b = flat block, r = flat block reach,
+ s = structured, l = local,
+ d = dag (default, except with /prover:Simplify)
+ doomed = doomed
+ /traceverify print debug output during verification condition generation
+ /subsumption:<c>
+ apply subsumption to asserted conditions:
+ 0 - never, 1 - not for quantifiers, 2 (default) - always
+ /alwaysAssumeFreeLoopInvariants
+ usually, a free loop invariant (or assume
+ statement in that position) is ignored in checking contexts
+ (like other free things); this option includes these free
+ loop invariants as assumes in both contexts
+ /inline:<i> use inlining strategy <i> for procedures with the :inline
+ attribute, see /attrHelp for details:
+ none
+ assume (default)
+ assert
+ spec
+ /printInlined
+ print the implementation after inlining calls to
+ procedures with the :inline attribute (works with /inline)
+ /lazyInline:1
+ Use the lazy inlining algorithm
+ /stratifiedInline:1
+ Use the stratified inlining algorithm
+ /fixedPointEngine:<engine>
+ Use the specified fixed point engine for inference
+ /recursionBound:<n>
+ Set the recursion bound for stratified inlining to
+ be n (default 500)
+ /inferLeastForUnsat:<str>
+ Infer the least number of constants (whose names
+ are prefixed by <str>) that need to be set to
+ true for the program to be correct. This turns
+ on stratified inlining.
+ /smoke Soundness Smoke Test: try to stick assert false; in some
+ places in the BPL and see if we can still prove it
+ /smokeTimeout:<n>
+ Timeout, in seconds, for a single theorem prover
+ invocation during smoke test, defaults to 10.
+ /causalImplies
+ Translate Boogie's A ==> B into prover's A ==> A && B.
+ /typeEncoding:<m>
+ how to encode types when sending VC to theorem prover
+ n = none (unsound)
+ p = predicates (default)
+ a = arguments
+ m = monomorphic
+ /monomorphize
+ Do not abstract map types in the encoding (this is an
+ experimental feature that will not do the right thing if
+ the program uses polymorphism)
+ /reflectAdd In the VC, generate an auxiliary symbol, elsewhere defined
+ to be +, instead of +.
+
+ ---- Verification-condition splitting --------------------------------------
+
+ /vcsMaxCost:<f>
+ VC will not be split unless the cost of a VC exceeds this
+ number, defaults to 2000.0. This does NOT apply in the
+ keep-going mode after first round of splitting.
+ /vcsMaxSplits:<n>
+ Maximal number of VC generated per method. In keep
+ going mode only applies to the first round.
+ Defaults to 1.
+ /vcsMaxKeepGoingSplits:<n>
+ If set to more than 1, activates the keep
+ going mode, where after the first round of splitting,
+ VCs that timed out are split into <n> pieces and retried
+ until we succeed proving them, or there is only one
+ assertion on a single path and it timeouts (in which
+ case error is reported for that assertion).
+ Defaults to 1.
+ /vcsKeepGoingTimeout:<n>
+ Timeout in seconds for a single theorem prover
+ invocation in keep going mode, except for the final
+ single-assertion case. Defaults to 1s.
+ /vcsFinalAssertTimeout:<n>
+ Timeout in seconds for the single last
+ assertion in the keep going mode. Defaults to 30s.
+ /vcsPathJoinMult:<f>
+ If more than one path join at a block, by how much
+ multiply the number of paths in that block, to accomodate
+ for the fact that the prover will learn something on one
+ paths, before proceeding to another. Defaults to 0.8.
+ /vcsPathCostMult:<f1>
+ /vcsAssumeMult:<f2>
+ The cost of a block is
+ (<assert-cost> + <f2>*<assume-cost>) *
+ (1.0 + <f1>*<entering-paths>)
+ <f1> defaults to 1.0, <f2> defaults to 0.01.
+ The cost of a single assertion or assumption is
+ currently always 1.0.
+ /vcsPathSplitMult:<f>
+ If the best path split of a VC of cost A is into
+ VCs of cost B and C, then the split is applied if
+ A >= <f>*(B+C), otherwise assertion splitting will be
+ applied. Defaults to 0.5 (always do path splitting if
+ possible), set to more to do less path splitting
+ and more assertion splitting.
+ /vcsDumpSplits
+ For split #n dump split.n.dot and split.n.bpl.
+ Warning: Affects error reporting.
+ /vcsCores:<n>
+ Try to verify <n> VCs at once. Defaults to 1.
+ /vcsLoad:<f> Sets vcsCores to the machine's ProcessorCount * f,
+ rounded to the nearest integer (where 0.0 <= f <= 3.0),
+ but never to less than 1.
+
+ ---- Prover options --------------------------------------------------------
+
+ /errorLimit:<num>
+ Limit the number of errors produced for each procedure
+ (default is 5, some provers may support only 1)
+ /timeLimit:<num>
+ Limit the number of seconds spent trying to verify
+ each procedure
+ /errorTrace:<n>
+ 0 - no Trace labels in the error output,
+ 1 (default) - include useful Trace labels in error output,
+ 2 - include all Trace labels in the error output
+ /vcBrackets:<b>
+ bracket odd-charactered identifier names with |'s. <b> is:
+ 0 - no (default with non-/prover:Simplify),
+ 1 - yes (default with /prover:Simplify)
+ /prover:<tp> use theorem prover <tp>, where <tp> is either the name of
+ a DLL containing the prover interface located in the
+ Boogie directory, or a full path to a DLL containing such
+ an interface. The standard interfaces shipped include:
+ SMTLib (default, uses the SMTLib2 format and calls Z3)
+ Z3 (uses Z3 with the Simplify format)
+ Simplify
+ ContractInference (uses Z3)
+ Z3api (Z3 using Managed .NET API)
+ /proverOpt:KEY[=VALUE]
+ Provide a prover-specific option (short form /p).
+ /proverLog:<file>
+ Log input for the theorem prover. Like filenames
+ supplied as arguments to other options, <file> can use the
+ following macros:
+ @TIME@ expands to the current time
+ @PREFIX@ expands to the concatenation of strings given
+ by /logPrefix options
+ @FILE@ expands to the last filename specified on the
+ command line
+ In addition, /proverLog can also use the macro '@PROC@',
+ which causes there to be one prover log file per
+ verification condition, and the macro then expands to the
+ name of the procedure that the verification condition is for.
+ /logPrefix:<str>
+ Defines the expansion of the macro '@PREFIX@', which can
+ be used in various filenames specified by other options.
+ /proverLogAppend
+ Append (not overwrite) the specified prover log file
+ /proverWarnings
+ 0 (default) - don't print, 1 - print to stdout,
+ 2 - print to stderr
+ /proverMemoryLimit:<num>
+ Limit on the virtual memory for prover before
+ restart in MB (default:100MB)
+ /restartProver
+ Restart the prover after each query
+ /proverShutdownLimit<num>
+ Time between closing the stream to the prover and
+ killing the prover process (default: 0s)
+ /platform:<ptype>,<location>
+ ptype = v11,v2,cli1
+ location = platform libraries directory
+
+ Simplify specific options:
+ /simplifyMatchDepth:<num>
+ Set Simplify prover's matching depth limit
+
+ Z3 specific options:
+ /z3opt:<arg> specify additional Z3 options
+ /z3multipleErrors
+ report multiple counterexamples for each error
+ /useArrayTheory
+ use Z3's native theory (as opposed to axioms). Currently
+ implies /monomorphize.
+ /useSmtOutputFormat
+ Z3 outputs a model in the SMTLIB2 format.
+ /z3types generate multi-sorted VC that make use of Z3 types
+ /z3lets:<n> 0 - no LETs, 1 - only LET TERM, 2 - only LET FORMULA,
+ 3 - (default) any
+ /z3exe:<path>
+ path to Z3 executable
+
+ CVC4 specific options:
+ /cvc4exe:<path>
+ path to CVC4 executable
+");
+ }
+ }
+}
diff --git a/Source/Core/Core.csproj b/Source/Core/Core.csproj
index fbb23cfe..7c4cb7ae 100644
--- a/Source/Core/Core.csproj
+++ b/Source/Core/Core.csproj
@@ -1,236 +1,236 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProductVersion>9.0.21022</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
- <ProjectGuid>{B230A69C-C466-4065-B9C1-84D80E76D802}</ProjectGuid>
- <OutputType>Library</OutputType>
- <AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>Core</RootNamespace>
- <AssemblyName>Core</AssemblyName>
- <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
- <FileAlignment>512</FileAlignment>
- <CodeContractsAssemblyMode>1</CodeContractsAssemblyMode>
- <SignAssembly>true</SignAssembly>
- <AssemblyOriginatorKeyFile>..\InterimKey.snk</AssemblyOriginatorKeyFile>
- <FileUpgradeFlags>
- </FileUpgradeFlags>
- <OldToolsVersion>3.5</OldToolsVersion>
- <UpgradeBackupLocation />
- <PublishUrl>publish\</PublishUrl>
- <Install>true</Install>
- <InstallFrom>Disk</InstallFrom>
- <UpdateEnabled>false</UpdateEnabled>
- <UpdateMode>Foreground</UpdateMode>
- <UpdateInterval>7</UpdateInterval>
- <UpdateIntervalUnits>Days</UpdateIntervalUnits>
- <UpdatePeriodically>false</UpdatePeriodically>
- <UpdateRequired>false</UpdateRequired>
- <MapFileExtensions>true</MapFileExtensions>
- <ApplicationRevision>0</ApplicationRevision>
- <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
- <IsWebBootstrapper>false</IsWebBootstrapper>
- <UseApplicationTrust>false</UseApplicationTrust>
- <BootstrapperEnabled>true</BootstrapperEnabled>
- <TargetFrameworkProfile Condition=" '$(OS)' == 'Windows_NT'">Client</TargetFrameworkProfile>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>bin\Debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- <CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
- <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
- <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
- <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
- <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
- <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
- <CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
- <CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
- <CodeContractsPointerObligations>False</CodeContractsPointerObligations>
- <CodeContractsContainerAnalysis>False</CodeContractsContainerAnalysis>
- <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
- <CodeContractsRunInBackground>True</CodeContractsRunInBackground>
- <CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
- <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
- <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
- <CodeContractsCustomRewriterAssembly>
- </CodeContractsCustomRewriterAssembly>
- <CodeContractsCustomRewriterClass>
- </CodeContractsCustomRewriterClass>
- <CodeContractsLibPaths>
- </CodeContractsLibPaths>
- <CodeContractsExtraRewriteOptions>
- </CodeContractsExtraRewriteOptions>
- <CodeContractsExtraAnalysisOptions>
- </CodeContractsExtraAnalysisOptions>
- <CodeContractsBaseLineFile>
- </CodeContractsBaseLineFile>
- <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
- <CodeContractsReferenceAssembly>%28none%29</CodeContractsReferenceAssembly>
- <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>pdbonly</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>bin\Release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'z3apidebug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <OutputPath>bin\z3apidebug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <DebugType>full</DebugType>
- <PlatformTarget>AnyCPU</PlatformTarget>
- <CodeAnalysisRuleAssemblies>
- </CodeAnalysisRuleAssemblies>
- <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
- <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
- <ErrorReport>prompt</ErrorReport>
- <CodeAnalysisRuleSet>Migrated rules for Core.ruleset</CodeAnalysisRuleSet>
- <CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
- <WarningLevel>4</WarningLevel>
- <Optimize>false</Optimize>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Checked|AnyCPU'">
- <DebugSymbols>true</DebugSymbols>
- <OutputPath>bin\Checked\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <DebugType>full</DebugType>
- <PlatformTarget>AnyCPU</PlatformTarget>
- <CodeAnalysisLogFile>bin\Debug\Core.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
- <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
- <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
- <ErrorReport>prompt</ErrorReport>
- <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
- <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
- <CodeAnalysisIgnoreBuiltInRuleSets>true</CodeAnalysisIgnoreBuiltInRuleSets>
- <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
- <CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
- <CodeContractsEnableRuntimeChecking>True</CodeContractsEnableRuntimeChecking>
- <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
- <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
- <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
- <CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
- <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
- <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
- <CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
- <CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
- <CodeContractsEnumObligations>False</CodeContractsEnumObligations>
- <CodeContractsPointerObligations>False</CodeContractsPointerObligations>
- <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
- <CodeContractsRunInBackground>True</CodeContractsRunInBackground>
- <CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
- <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
- <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
- <CodeContractsCustomRewriterAssembly />
- <CodeContractsCustomRewriterClass />
- <CodeContractsLibPaths />
- <CodeContractsExtraRewriteOptions />
- <CodeContractsExtraAnalysisOptions />
- <CodeContractsBaseLineFile />
- <CodeContractsCacheAnalysisResults>False</CodeContractsCacheAnalysisResults>
- <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
- <CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
- <CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
- <WarningLevel>4</WarningLevel>
- <Optimize>false</Optimize>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'QED|AnyCPU'">
- <DebugSymbols>true</DebugSymbols>
- <OutputPath>bin\QED\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <DebugType>full</DebugType>
- <PlatformTarget>AnyCPU</PlatformTarget>
- <ErrorReport>prompt</ErrorReport>
- <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="System" />
- <Reference Include="System.Numerics" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="Absy.cs" />
- <Compile Include="AbsyCmd.cs" />
- <Compile Include="AbsyExpr.cs" />
- <Compile Include="AbsyQuant.cs" />
- <Compile Include="AbsyType.cs" />
- <Compile Include="AlphaEquality.cs" />
- <Compile Include="InterProceduralReachabilityGraph.cs" />
- <Compile Include="CommandLineOptions.cs" />
- <Compile Include="DeadVarElim.cs" />
- <Compile Include="Duplicator.cs" />
- <Compile Include="Inline.cs" />
- <Compile Include="LambdaHelper.cs" />
- <Compile Include="LoopUnroll.cs" />
- <Compile Include="OOLongUtil.cs" />
- <Compile Include="Parser.cs" />
- <Compile Include="ResolutionContext.cs" />
- <Compile Include="Scanner.cs" />
- <Compile Include="StandardVisitor.cs" />
- <Compile Include="TypeAmbiguitySeeker.cs" />
- <Compile Include="Util.cs" />
- <Compile Include="VariableDependenceAnalyser.cs" />
- <Compile Include="VCExp.cs" />
- <Compile Include="..\version.cs" />
- <Compile Include="Xml.cs" />
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\Basetypes\Basetypes.csproj">
- <Project>{43dfad18-3e35-4558-9be2-caff6b5ba8a0}</Project>
- <Name>Basetypes</Name>
- </ProjectReference>
- <ProjectReference Include="..\CodeContractsExtender\CodeContractsExtender.csproj">
- <Project>{ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}</Project>
- <Name>CodeContractsExtender</Name>
- </ProjectReference>
- <ProjectReference Include="..\Graph\Graph.csproj">
- <Project>{69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}</Project>
- <Name>Graph</Name>
- </ProjectReference>
- <ProjectReference Include="..\ParserHelper\ParserHelper.csproj">
- <Project>{FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}</Project>
- <Name>ParserHelper</Name>
- </ProjectReference>
- </ItemGroup>
- <ItemGroup>
- <Folder Include="Properties\" />
- </ItemGroup>
- <ItemGroup>
- <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
- <Visible>False</Visible>
- <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
- <Install>false</Install>
- </BootstrapperPackage>
- <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
- <Visible>False</Visible>
- <ProductName>.NET Framework 3.5 SP1</ProductName>
- <Install>true</Install>
- </BootstrapperPackage>
- <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
- <Visible>False</Visible>
- <ProductName>Windows Installer 3.1</ProductName>
- <Install>true</Install>
- </BootstrapperPackage>
- </ItemGroup>
- <ItemGroup>
- <None Include="BoogiePL.atg" />
- </ItemGroup>
- <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
- <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
- Other similar extension points exist, see Microsoft.Common.targets.
- <Target Name="BeforeBuild">
- </Target>
- <Target Name="AfterBuild">
- </Target>
- -->
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{B230A69C-C466-4065-B9C1-84D80E76D802}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Core</RootNamespace>
+ <AssemblyName>BoogieCore</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <CodeContractsAssemblyMode>1</CodeContractsAssemblyMode>
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>..\InterimKey.snk</AssemblyOriginatorKeyFile>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>3.5</OldToolsVersion>
+ <UpgradeBackupLocation />
+ <PublishUrl>publish\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Disk</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ <TargetFrameworkProfile Condition=" '$(OS)' == 'Windows_NT'">Client</TargetFrameworkProfile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
+ <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
+ <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
+ <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
+ <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
+ <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
+ <CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
+ <CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
+ <CodeContractsPointerObligations>False</CodeContractsPointerObligations>
+ <CodeContractsContainerAnalysis>False</CodeContractsContainerAnalysis>
+ <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
+ <CodeContractsRunInBackground>True</CodeContractsRunInBackground>
+ <CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
+ <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
+ <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
+ <CodeContractsCustomRewriterAssembly>
+ </CodeContractsCustomRewriterAssembly>
+ <CodeContractsCustomRewriterClass>
+ </CodeContractsCustomRewriterClass>
+ <CodeContractsLibPaths>
+ </CodeContractsLibPaths>
+ <CodeContractsExtraRewriteOptions>
+ </CodeContractsExtraRewriteOptions>
+ <CodeContractsExtraAnalysisOptions>
+ </CodeContractsExtraAnalysisOptions>
+ <CodeContractsBaseLineFile>
+ </CodeContractsBaseLineFile>
+ <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
+ <CodeContractsReferenceAssembly>%28none%29</CodeContractsReferenceAssembly>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'z3apidebug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\z3apidebug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DebugType>full</DebugType>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <CodeAnalysisRuleAssemblies>
+ </CodeAnalysisRuleAssemblies>
+ <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+ <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>Migrated rules for Core.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
+ <WarningLevel>4</WarningLevel>
+ <Optimize>false</Optimize>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Checked|AnyCPU'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\Checked\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DebugType>full</DebugType>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <CodeAnalysisLogFile>bin\Debug\Core.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+ <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+ <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+ <CodeAnalysisIgnoreBuiltInRuleSets>true</CodeAnalysisIgnoreBuiltInRuleSets>
+ <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+ <CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
+ <CodeContractsEnableRuntimeChecking>True</CodeContractsEnableRuntimeChecking>
+ <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
+ <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
+ <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
+ <CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
+ <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
+ <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
+ <CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
+ <CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
+ <CodeContractsEnumObligations>False</CodeContractsEnumObligations>
+ <CodeContractsPointerObligations>False</CodeContractsPointerObligations>
+ <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
+ <CodeContractsRunInBackground>True</CodeContractsRunInBackground>
+ <CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
+ <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
+ <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
+ <CodeContractsCustomRewriterAssembly />
+ <CodeContractsCustomRewriterClass />
+ <CodeContractsLibPaths />
+ <CodeContractsExtraRewriteOptions />
+ <CodeContractsExtraAnalysisOptions />
+ <CodeContractsBaseLineFile />
+ <CodeContractsCacheAnalysisResults>False</CodeContractsCacheAnalysisResults>
+ <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
+ <CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
+ <CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
+ <WarningLevel>4</WarningLevel>
+ <Optimize>false</Optimize>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'QED|AnyCPU'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\QED\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DebugType>full</DebugType>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Numerics" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Absy.cs" />
+ <Compile Include="AbsyCmd.cs" />
+ <Compile Include="AbsyExpr.cs" />
+ <Compile Include="AbsyQuant.cs" />
+ <Compile Include="AbsyType.cs" />
+ <Compile Include="AlphaEquality.cs" />
+ <Compile Include="InterProceduralReachabilityGraph.cs" />
+ <Compile Include="CommandLineOptions.cs" />
+ <Compile Include="DeadVarElim.cs" />
+ <Compile Include="Duplicator.cs" />
+ <Compile Include="Inline.cs" />
+ <Compile Include="LambdaHelper.cs" />
+ <Compile Include="LoopUnroll.cs" />
+ <Compile Include="OOLongUtil.cs" />
+ <Compile Include="Parser.cs" />
+ <Compile Include="ResolutionContext.cs" />
+ <Compile Include="Scanner.cs" />
+ <Compile Include="StandardVisitor.cs" />
+ <Compile Include="TypeAmbiguitySeeker.cs" />
+ <Compile Include="Util.cs" />
+ <Compile Include="VariableDependenceAnalyser.cs" />
+ <Compile Include="VCExp.cs" />
+ <Compile Include="..\version.cs" />
+ <Compile Include="Xml.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Basetypes\Basetypes.csproj">
+ <Project>{43dfad18-3e35-4558-9be2-caff6b5ba8a0}</Project>
+ <Name>Basetypes</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\CodeContractsExtender\CodeContractsExtender.csproj">
+ <Project>{ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}</Project>
+ <Name>CodeContractsExtender</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Graph\Graph.csproj">
+ <Project>{69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}</Project>
+ <Name>Graph</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\ParserHelper\ParserHelper.csproj">
+ <Project>{FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}</Project>
+ <Name>ParserHelper</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Folder Include="Properties\" />
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+ <Visible>False</Visible>
+ <ProductName>Windows Installer 3.1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="BoogiePL.atg" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
</Project> \ No newline at end of file
diff --git a/Source/Core/DeadVarElim.cs b/Source/Core/DeadVarElim.cs
index 77086f0f..fc39debb 100644
--- a/Source/Core/DeadVarElim.cs
+++ b/Source/Core/DeadVarElim.cs
@@ -1,1753 +1,1762 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Microsoft.Boogie.GraphUtil;
-using System.Diagnostics.Contracts;
-
-
-namespace Microsoft.Boogie {
- public class UnusedVarEliminator : VariableCollector {
- public static void Eliminate(Program program) {
- Contract.Requires(program != null);
- UnusedVarEliminator elim = new UnusedVarEliminator();
- elim.Visit(program);
- }
-
- private UnusedVarEliminator()
- : base() {
-
- }
-
- public override Implementation VisitImplementation(Implementation node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Implementation>() != null);
- //Console.WriteLine("Procedure {0}", node.Name);
- Implementation/*!*/ impl = base.VisitImplementation(node);
- Contract.Assert(impl != null);
- //Console.WriteLine("Old number of local variables = {0}", impl.LocVars.Length);
- List<Variable>/*!*/ vars = new List<Variable>();
- foreach (Variable/*!*/ var in impl.LocVars) {
- Contract.Assert(var != null);
- if (_usedVars.Contains(var))
- vars.Add(var);
- }
- impl.LocVars = vars;
- //Console.WriteLine("New number of local variables = {0}", impl.LocVars.Length);
- //Console.WriteLine("---------------------------------");
- _usedVars.Clear();
- return impl;
- }
- }
-
- public class ModSetCollector : ReadOnlyVisitor {
- private Procedure enclosingProc;
- private Dictionary<Procedure/*!*/, HashSet<Variable/*!*/>/*!*/>/*!*/ modSets;
- private HashSet<Procedure> yieldingProcs;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cce.NonNullDictionaryAndValues(modSets));
- Contract.Invariant(Contract.ForAll(modSets.Values, v => cce.NonNullElements(v)));
- }
-
- public ModSetCollector() {
- modSets = new Dictionary<Procedure/*!*/, HashSet<Variable/*!*/>/*!*/>();
- yieldingProcs = new HashSet<Procedure>();
- }
-
- private bool moreProcessingRequired;
-
- public void DoModSetAnalysis(Program program) {
- Contract.Requires(program != null);
-
- if (CommandLineOptions.Clo.Trace)
- {
-// Console.WriteLine();
-// Console.WriteLine("Running modset analysis ...");
-// int procCount = 0;
-// foreach (Declaration/*!*/ decl in program.TopLevelDeclarations)
-// {
-// Contract.Assert(decl != null);
-// if (decl is Procedure)
-// procCount++;
-// }
-// Console.WriteLine("Number of procedures = {0}", procCount);*/
- }
-
- HashSet<Procedure/*!*/> implementedProcs = new HashSet<Procedure/*!*/>();
- foreach (var impl in program.Implementations) {
- if (impl.Proc != null)
- implementedProcs.Add(impl.Proc);
- }
- foreach (var proc in program.Procedures) {
- if (!implementedProcs.Contains(proc))
- {
- enclosingProc = proc;
- foreach (var expr in proc.Modifies)
- {
- Contract.Assert(expr != null);
- ProcessVariable(expr.Decl);
- }
- enclosingProc = null;
- }
- else
- {
- modSets.Add(proc, new HashSet<Variable>());
- }
- }
-
- moreProcessingRequired = true;
- while (moreProcessingRequired) {
- moreProcessingRequired = false;
- this.Visit(program);
- }
-
- foreach (Procedure x in modSets.Keys)
- {
- x.Modifies = new List<IdentifierExpr>();
- foreach (Variable v in modSets[x])
- {
- x.Modifies.Add(new IdentifierExpr(v.tok, v));
- }
- }
- foreach (Procedure x in yieldingProcs)
- {
- if (!QKeyValue.FindBoolAttribute(x.Attributes, "yields"))
- {
- x.AddAttribute("yields");
- }
- }
-
-#if DEBUG_PRINT
- Console.WriteLine("Number of procedures with nonempty modsets = {0}", modSets.Keys.Count);
- foreach (Procedure/*!*/ x in modSets.Keys) {
- Contract.Assert(x != null);
- Console.Write("{0} : ", x.Name);
- bool first = true;
- foreach (Variable/*!*/ y in modSets[x]) {
- Contract.Assert(y != null);
- if (first)
- first = false;
- else
- Console.Write(", ");
- Console.Write("{0}", y.Name);
- }
- Console.WriteLine("");
- }
-#endif
- }
-
- public override Implementation VisitImplementation(Implementation node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Implementation>() != null);
- enclosingProc = node.Proc;
- Implementation/*!*/ ret = base.VisitImplementation(node);
- Contract.Assert(ret != null);
- enclosingProc = null;
-
- return ret;
- }
- public override YieldCmd VisitYieldCmd(YieldCmd node)
- {
- if (!yieldingProcs.Contains(enclosingProc))
- {
- yieldingProcs.Add(enclosingProc);
- moreProcessingRequired = true;
- }
- return base.VisitYieldCmd(node);
- }
- public override Cmd VisitAssignCmd(AssignCmd assignCmd) {
- //Contract.Requires(assignCmd != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- Cmd ret = base.VisitAssignCmd(assignCmd);
- foreach (AssignLhs/*!*/ lhs in assignCmd.Lhss) {
- Contract.Assert(lhs != null);
- ProcessVariable(lhs.DeepAssignedVariable);
- }
- return ret;
- }
- public override Cmd VisitHavocCmd(HavocCmd havocCmd) {
- //Contract.Requires(havocCmd != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- Cmd ret = base.VisitHavocCmd(havocCmd);
- foreach (IdentifierExpr/*!*/ expr in havocCmd.Vars) {
- Contract.Assert(expr != null);
- ProcessVariable(expr.Decl);
- }
- return ret;
- }
- public override Cmd VisitCallCmd(CallCmd callCmd) {
- //Contract.Requires(callCmd != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- Cmd ret = base.VisitCallCmd(callCmd);
- foreach (IdentifierExpr ie in callCmd.Outs)
- {
- if (ie != null) ProcessVariable(ie.Decl);
- }
- Procedure callee = callCmd.Proc;
- if (callee == null)
- return ret;
- if (modSets.ContainsKey(callee)) {
- foreach (Variable var in modSets[callee]) {
- ProcessVariable(var);
- }
- }
- if (!yieldingProcs.Contains(enclosingProc) && (yieldingProcs.Contains(callCmd.Proc) || callCmd.IsAsync))
- {
- yieldingProcs.Add(enclosingProc);
- moreProcessingRequired = true;
- }
- if (callCmd.IsAsync)
- {
- if (!yieldingProcs.Contains(callCmd.Proc))
- {
- yieldingProcs.Add(callCmd.Proc);
- moreProcessingRequired = true;
- }
- }
- return ret;
- }
- public override Cmd VisitParCallCmd(ParCallCmd node)
- {
- //Contract.Requires(callCmd != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- Cmd ret = base.VisitParCallCmd(node);
- if (!yieldingProcs.Contains(enclosingProc))
- {
- yieldingProcs.Add(enclosingProc);
- moreProcessingRequired = true;
- }
- foreach (CallCmd callCmd in node.CallCmds)
- {
- if (!yieldingProcs.Contains(callCmd.Proc))
- {
- yieldingProcs.Add(callCmd.Proc);
- moreProcessingRequired = true;
- }
- }
- return ret;
- }
- private void ProcessVariable(Variable var) {
- Procedure/*!*/ localProc = cce.NonNull(enclosingProc);
- if (var == null)
- return;
- if (!(var is GlobalVariable))
- return;
- if (!modSets.ContainsKey(localProc)) {
- modSets[localProc] = new HashSet<Variable/*!*/>();
- }
- if (modSets[localProc].Contains(var))
- return;
- moreProcessingRequired = true;
- modSets[localProc].Add(var);
- }
- public override Expr VisitCodeExpr(CodeExpr node) {
- // don't go into the code expression, since it can only modify variables local to the code expression,
- // and the mod-set analysis is interested in global variables
- return node;
- }
- }
-
- public class MutableVariableCollector : ReadOnlyVisitor
- {
- public HashSet<Variable> UsedVariables = new HashSet<Variable>();
-
- public void AddUsedVariables(HashSet<Variable> usedVariables)
- {
- Contract.Requires(usedVariables != null);
-
- foreach (var v in usedVariables)
- {
- UsedVariables.Add(v);
- }
- }
-
- public override Expr VisitIdentifierExpr(IdentifierExpr node)
- {
- Contract.Ensures(Contract.Result<Expr>() != null);
-
- if (node.Decl != null && node.Decl.IsMutable)
- {
- UsedVariables.Add(node.Decl);
- }
- return base.VisitIdentifierExpr(node);
- }
- }
-
- public class VariableCollector : ReadOnlyVisitor {
- protected HashSet<Variable/*!*/>/*!*/ _usedVars;
- public IEnumerable<Variable /*!*/>/*!*/ usedVars
- {
- get
- {
- return _usedVars.AsEnumerable();
- }
- }
-
- protected HashSet<Variable/*!*/>/*!*/ _oldVarsUsed;
- public IEnumerable<Variable /*!*/>/*!*/ oldVarsUsed
- {
- get
- {
- return _oldVarsUsed.AsEnumerable();
- }
- }
-
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cce.NonNullElements(_usedVars));
- Contract.Invariant(cce.NonNullElements(_oldVarsUsed));
- }
-
- int insideOldExpr;
-
- public VariableCollector() {
- _usedVars = new System.Collections.Generic.HashSet<Variable/*!*/>();
- _oldVarsUsed = new System.Collections.Generic.HashSet<Variable/*!*/>();
- insideOldExpr = 0;
- }
-
- public override Expr VisitOldExpr(OldExpr node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- insideOldExpr++;
- node.Expr = this.VisitExpr(node.Expr);
- insideOldExpr--;
- return node;
- }
-
- public override Expr VisitIdentifierExpr(IdentifierExpr node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- if (node.Decl != null) {
- _usedVars.Add(node.Decl);
- if (insideOldExpr > 0) {
- _oldVarsUsed.Add(node.Decl);
- }
- }
- return node;
- }
- }
-
- public class BlockCoalescer : ReadOnlyVisitor {
- public static void CoalesceBlocks(Program program) {
- Contract.Requires(program != null);
- BlockCoalescer blockCoalescer = new BlockCoalescer();
- blockCoalescer.Visit(program);
- }
-
- private static HashSet<Block/*!*/>/*!*/ ComputeMultiPredecessorBlocks(Implementation/*!*/ impl) {
- Contract.Requires(impl != null);
- Contract.Ensures(cce.NonNullElements(Contract.Result<HashSet<Block>>()));
- HashSet<Block/*!*/> visitedBlocks = new HashSet<Block/*!*/>();
- HashSet<Block/*!*/> multiPredBlocks = new HashSet<Block/*!*/>();
- Stack<Block/*!*/> dfsStack = new Stack<Block/*!*/>();
- dfsStack.Push(impl.Blocks[0]);
- while (dfsStack.Count > 0) {
- Block/*!*/ b = dfsStack.Pop();
- Contract.Assert(b != null);
- if (visitedBlocks.Contains(b)) {
- multiPredBlocks.Add(b);
- continue;
- }
- visitedBlocks.Add(b);
- if (b.TransferCmd == null)
- continue;
- if (b.TransferCmd is ReturnCmd)
- continue;
- Contract.Assert(b.TransferCmd is GotoCmd);
- GotoCmd gotoCmd = (GotoCmd)b.TransferCmd;
- if (gotoCmd.labelTargets == null)
- continue;
- foreach (Block/*!*/ succ in gotoCmd.labelTargets) {
- Contract.Assert(succ != null);
- dfsStack.Push(succ);
- }
- }
- return multiPredBlocks;
- }
-
- public override Implementation VisitImplementation(Implementation impl) {
- //Contract.Requires(impl != null);
- Contract.Ensures(Contract.Result<Implementation>() != null);
- //Console.WriteLine("Procedure {0}", impl.Name);
- //Console.WriteLine("Initial number of blocks = {0}", impl.Blocks.Count);
-
- HashSet<Block/*!*/> multiPredBlocks = ComputeMultiPredecessorBlocks(impl);
- Contract.Assert(cce.NonNullElements(multiPredBlocks));
- HashSet<Block/*!*/> visitedBlocks = new HashSet<Block/*!*/>();
- HashSet<Block/*!*/> removedBlocks = new HashSet<Block/*!*/>();
- Stack<Block/*!*/> dfsStack = new Stack<Block/*!*/>();
- dfsStack.Push(impl.Blocks[0]);
- while (dfsStack.Count > 0) {
- Block/*!*/ b = dfsStack.Pop();
- Contract.Assert(b != null);
- if (visitedBlocks.Contains(b))
- continue;
- visitedBlocks.Add(b);
- if (b.TransferCmd == null)
- continue;
- if (b.TransferCmd is ReturnCmd)
- continue;
- Contract.Assert(b.TransferCmd is GotoCmd);
- GotoCmd gotoCmd = (GotoCmd)b.TransferCmd;
- if (gotoCmd.labelTargets == null)
- continue;
- if (gotoCmd.labelTargets.Count == 1) {
- Block/*!*/ succ = cce.NonNull(gotoCmd.labelTargets[0]);
- if (!multiPredBlocks.Contains(succ)) {
- foreach (Cmd/*!*/ cmd in succ.Cmds) {
- Contract.Assert(cmd != null);
- b.Cmds.Add(cmd);
- }
- b.TransferCmd = succ.TransferCmd;
- if (!b.tok.IsValid && succ.tok.IsValid) {
- b.tok = succ.tok;
- b.Label = succ.Label;
- }
- removedBlocks.Add(succ);
- dfsStack.Push(b);
- visitedBlocks.Remove(b);
- continue;
- }
- }
- foreach (Block/*!*/ succ in gotoCmd.labelTargets) {
- Contract.Assert(succ != null);
- dfsStack.Push(succ);
- }
- }
-
- List<Block/*!*/> newBlocks = new List<Block/*!*/>();
- foreach (Block/*!*/ b in impl.Blocks) {
- Contract.Assert(b != null);
- if (visitedBlocks.Contains(b) && !removedBlocks.Contains(b)) {
- newBlocks.Add(b);
- }
- }
- impl.Blocks = newBlocks;
-
- // Console.WriteLine("Final number of blocks = {0}", impl.Blocks.Count);
- return impl;
- }
- }
-
- public class LiveVariableAnalysis {
- public static void ClearLiveVariables(Implementation impl) {
- Contract.Requires(impl != null);
- foreach (Block/*!*/ block in impl.Blocks) {
- Contract.Assert(block != null);
- block.liveVarsBefore = null;
- }
- }
-
- public static void ComputeLiveVariables(Implementation impl) {
- Contract.Requires(impl != null);
- Microsoft.Boogie.Helpers.ExtraTraceInformation("Starting live variable analysis");
- Graph<Block> dag = new Graph<Block>();
- dag.AddSource(cce.NonNull(impl.Blocks[0])); // there is always at least one node in the graph
- foreach (Block b in impl.Blocks) {
- GotoCmd gtc = b.TransferCmd as GotoCmd;
- if (gtc != null) {
- Contract.Assume(gtc.labelTargets != null);
- foreach (Block/*!*/ dest in gtc.labelTargets) {
- Contract.Assert(dest != null);
- dag.AddEdge(dest, b);
- }
- }
- }
-
- IEnumerable<Block> sortedNodes;
- if (CommandLineOptions.Clo.ModifyTopologicalSorting) {
- sortedNodes = dag.TopologicalSort(true);
- } else {
- sortedNodes = dag.TopologicalSort();
- }
- foreach (Block/*!*/ block in sortedNodes) {
- Contract.Assert(block != null);
- HashSet<Variable/*!*/>/*!*/ liveVarsAfter = new HashSet<Variable/*!*/>();
-
- // The injected assumption variables should always be considered to be live.
- foreach (var v in impl.InjectedAssumptionVariables.Concat(impl.DoomedInjectedAssumptionVariables))
- {
- liveVarsAfter.Add(v);
- }
-
- if (block.TransferCmd is GotoCmd) {
- GotoCmd gotoCmd = (GotoCmd)block.TransferCmd;
- if (gotoCmd.labelTargets != null) {
- foreach (Block/*!*/ succ in gotoCmd.labelTargets) {
- Contract.Assert(succ != null);
- Contract.Assert(succ.liveVarsBefore != null);
- liveVarsAfter.UnionWith(succ.liveVarsBefore);
- }
- }
- }
-
- List<Cmd> cmds = block.Cmds;
- int len = cmds.Count;
- for (int i = len - 1; i >= 0; i--) {
- if (cmds[i] is CallCmd) {
- Procedure/*!*/ proc = cce.NonNull(cce.NonNull((CallCmd/*!*/)cmds[i]).Proc);
- if (InterProcGenKill.HasSummary(proc.Name)) {
- liveVarsAfter =
- InterProcGenKill.PropagateLiveVarsAcrossCall(cce.NonNull((CallCmd/*!*/)cmds[i]), liveVarsAfter);
- continue;
- }
- }
- Propagate(cmds[i], liveVarsAfter);
- }
-
- block.liveVarsBefore = liveVarsAfter;
-
- }
- }
-
- // perform in place update of liveSet
- public static void Propagate(Cmd cmd, HashSet<Variable/*!*/>/*!*/ liveSet) {
- Contract.Requires(cmd != null);
- Contract.Requires(cce.NonNullElements(liveSet));
- if (cmd is AssignCmd) {
- AssignCmd/*!*/ assignCmd = (AssignCmd)cce.NonNull(cmd);
- // I must first iterate over all the targets and remove the live ones.
- // After the removals are done, I must add the variables referred on
- // the right side of the removed targets
-
- AssignCmd simpleAssignCmd = assignCmd.AsSimpleAssignCmd;
- HashSet<int> indexSet = new HashSet<int>();
- int index = 0;
- foreach (AssignLhs/*!*/ lhs in simpleAssignCmd.Lhss) {
- Contract.Assert(lhs != null);
- SimpleAssignLhs salhs = lhs as SimpleAssignLhs;
- Contract.Assert(salhs != null);
- Variable var = salhs.DeepAssignedVariable;
- if (var != null && liveSet.Contains(var)) {
- indexSet.Add(index);
- liveSet.Remove(var);
- }
- index++;
- }
- index = 0;
- foreach (Expr/*!*/ expr in simpleAssignCmd.Rhss) {
- Contract.Assert(expr != null);
- if (indexSet.Contains(index)) {
- VariableCollector/*!*/ collector = new VariableCollector();
- collector.Visit(expr);
- liveSet.UnionWith(collector.usedVars);
- }
- index++;
- }
- } else if (cmd is HavocCmd) {
- HavocCmd/*!*/ havocCmd = (HavocCmd)cmd;
- foreach (IdentifierExpr/*!*/ expr in havocCmd.Vars) {
- Contract.Assert(expr != null);
- if (expr.Decl != null && !(QKeyValue.FindBoolAttribute(expr.Decl.Attributes, "assumption") && expr.Decl.Name.StartsWith("a##post##"))) {
- liveSet.Remove(expr.Decl);
- }
- }
- } else if (cmd is PredicateCmd) {
- Contract.Assert((cmd is AssertCmd || cmd is AssumeCmd));
- PredicateCmd/*!*/ predicateCmd = (PredicateCmd)cce.NonNull(cmd);
- if (predicateCmd.Expr is LiteralExpr) {
- LiteralExpr le = (LiteralExpr)predicateCmd.Expr;
- if (le.IsFalse) {
- liveSet.Clear();
- }
- } else {
- VariableCollector/*!*/ collector = new VariableCollector();
- collector.Visit(predicateCmd.Expr);
- liveSet.UnionWith(collector.usedVars);
- }
- } else if (cmd is CommentCmd) {
- // comments are just for debugging and don't affect verification
- } else if (cmd is SugaredCmd) {
- SugaredCmd/*!*/ sugCmd = (SugaredCmd)cce.NonNull(cmd);
- Propagate(sugCmd.Desugaring, liveSet);
- } else if (cmd is StateCmd) {
- StateCmd/*!*/ stCmd = (StateCmd)cce.NonNull(cmd);
- List<Cmd>/*!*/ cmds = cce.NonNull(stCmd.Cmds);
- int len = cmds.Count;
- for (int i = len - 1; i >= 0; i--) {
- Propagate(cmds[i], liveSet);
- }
- foreach (Variable/*!*/ v in stCmd.Locals) {
- Contract.Assert(v != null);
- liveSet.Remove(v);
- }
- } else {
- {
- Contract.Assert(false);
- throw new cce.UnreachableException();
- }
- }
- }
- }
-
- /*
- // An idempotent semiring interface
- abstract public class Weight {
- abstract public Weight! one();
- abstract public Weight! zero();
- abstract public Weight! extend(Weight! w1, Weight! w2);
- abstract public Weight! combine(Weight! w1, Weight! w2);
- abstract public Weight! isEqual(Weight! w);
- abstract public Weight! projectLocals()
- }
- */
-
- // Weight domain for LiveVariableAnalysis (Gen/Kill)
-
- public class GenKillWeight {
- // lambda S. (S - kill) union gen
- HashSet<Variable/*!*/>/*!*/ gen;
- HashSet<Variable/*!*/>/*!*/ kill;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cce.NonNullElements(gen));
- Contract.Invariant(cce.NonNullElements(kill));
- Contract.Invariant(oneWeight != null);
- Contract.Invariant(zeroWeight != null);
- }
-
- bool isZero;
-
- public static GenKillWeight/*!*/ oneWeight = new GenKillWeight(new HashSet<Variable/*!*/>(), new HashSet<Variable/*!*/>());
- public static GenKillWeight/*!*/ zeroWeight = new GenKillWeight();
-
- // initializes to zero
- public GenKillWeight() {
- this.isZero = true;
- this.gen = new HashSet<Variable/*!*/>();
- this.kill = new HashSet<Variable/*!*/>();
- }
-
- public GenKillWeight(HashSet<Variable/*!*/> gen, HashSet<Variable/*!*/> kill) {
- Contract.Requires(cce.NonNullElements(gen));
- Contract.Requires(cce.NonNullElements(kill));
- Contract.Assert(gen != null);
- Contract.Assert(kill != null);
- this.gen = gen;
- this.kill = kill;
- this.isZero = false;
- }
-
- public static GenKillWeight one() {
- Contract.Ensures(Contract.Result<GenKillWeight>() != null);
- return oneWeight;
- }
-
- public static GenKillWeight zero() {
- Contract.Ensures(Contract.Result<GenKillWeight>() != null);
- return zeroWeight;
- }
-
- public static GenKillWeight extend(GenKillWeight w1, GenKillWeight w2) {
- Contract.Requires(w2 != null);
- Contract.Requires(w1 != null);
- Contract.Ensures(Contract.Result<GenKillWeight>() != null);
- if (w1.isZero || w2.isZero)
- return zero();
-
- HashSet<Variable> t = new HashSet<Variable>(w2.gen);
- t.ExceptWith(w1.kill);
- HashSet<Variable> g = new HashSet<Variable>(w1.gen);
- g.UnionWith(t);
- HashSet<Variable> k = new HashSet<Variable>(w1.kill);
- k.UnionWith(w2.kill);
- return new GenKillWeight(g, k);
- //return new GenKillWeight(w1.gen.Union(w2.gen.Difference(w1.kill)), w1.kill.Union(w2.kill));
- }
-
- public static GenKillWeight combine(GenKillWeight w1, GenKillWeight w2) {
- Contract.Requires(w2 != null);
- Contract.Requires(w1 != null);
- Contract.Ensures(Contract.Result<GenKillWeight>() != null);
- if (w1.isZero)
- return w2;
- if (w2.isZero)
- return w1;
-
- HashSet<Variable> g = new HashSet<Variable>(w1.gen);
- g.UnionWith(w2.gen);
- HashSet<Variable> k = new HashSet<Variable>(w1.kill);
- k.IntersectWith(w2.kill);
- return new GenKillWeight(g, k);
- //return new GenKillWeight(w1.gen.Union(w2.gen), w1.kill.Intersection(w2.kill));
- }
-
- public static GenKillWeight projectLocals(GenKillWeight w) {
- Contract.Requires(w != null);
- Contract.Ensures(Contract.Result<GenKillWeight>() != null);
- HashSet<Variable/*!*/> gen = new HashSet<Variable>();
- foreach (Variable v in w.gen)
- {
- if (isGlobal(v))
- gen.Add(v);
- }
- HashSet<Variable/*!*/> kill = new HashSet<Variable>();
- foreach (Variable v in w.kill)
- {
- if (isGlobal(v))
- kill.Add(v);
- }
-
- return new GenKillWeight(gen, kill);
- }
-
- public static bool isEqual(GenKillWeight w1, GenKillWeight w2) {
- Contract.Requires(w2 != null);
- Contract.Requires(w1 != null);
- if (w1.isZero)
- return w2.isZero;
- if (w2.isZero)
- return w1.isZero;
-
- return (w1.gen.Equals(w2.gen) && w1.kill.Equals(w2.kill));
- }
-
- private static bool isGlobal(Variable v) {
- Contract.Requires(v != null);
- return (v is GlobalVariable);
- }
-
- [Pure]
- public override string ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- return string.Format("({0},{1})", gen.ToString(), kill.ToString());
- }
-
- public HashSet<Variable/*!*/>/*!*/ getLiveVars() {
- Contract.Ensures(cce.NonNullElements(Contract.Result<HashSet<Variable>>()));
- return gen;
- }
-
- public HashSet<Variable/*!*/>/*!*/ getLiveVars(HashSet<Variable/*!*/>/*!*/ lv) {
- Contract.Requires(cce.NonNullElements(lv));
- Contract.Ensures(cce.NonNullElements(Contract.Result<HashSet<Variable>>()));
- HashSet<Variable> temp = new HashSet<Variable>(lv);
- temp.ExceptWith(kill);
- temp.UnionWith(gen);
- return temp;
- }
-
- }
-
- public class ICFG {
- public Graph<Block/*!*/>/*!*/ graph;
- // Map from procedure to the list of blocks that call that procedure
- public Dictionary<string/*!*/, List<Block/*!*/>/*!*/>/*!*/ procsCalled;
- public HashSet<Block/*!*/>/*!*/ nodes;
- public Dictionary<Block/*!*/, HashSet<Block/*!*/>/*!*/>/*!*/ succEdges;
- public Dictionary<Block/*!*/, HashSet<Block/*!*/>/*!*/>/*!*/ predEdges;
- private Dictionary<Block/*!*/, int>/*!*/ priority;
-
- public HashSet<Block/*!*/>/*!*/ srcNodes;
- public HashSet<Block/*!*/>/*!*/ exitNodes;
-
- public Dictionary<Block/*!*/, GenKillWeight/*!*/>/*!*/ weightBefore;
- public Dictionary<Block/*!*/, GenKillWeight/*!*/>/*!*/ weightAfter;
- public Dictionary<Block/*!*/, HashSet<Variable/*!*/>/*!*/>/*!*/ liveVarsAfter;
- public Dictionary<Block/*!*/, HashSet<Variable/*!*/>/*!*/>/*!*/ liveVarsBefore;
-
- public GenKillWeight/*!*/ summary;
- public Implementation/*!*/ impl;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cce.NonNullElements(graph.Nodes));
- Contract.Invariant(cce.NonNullDictionaryAndValues(procsCalled));
- Contract.Invariant(cce.NonNullElements(nodes));
- Contract.Invariant(cce.NonNullDictionaryAndValues(succEdges));
- Contract.Invariant(cce.NonNullDictionaryAndValues(predEdges));
- Contract.Invariant(priority != null);
- Contract.Invariant(cce.NonNullElements(srcNodes));
- Contract.Invariant(cce.NonNullElements(exitNodes));
- Contract.Invariant(cce.NonNullDictionaryAndValues(weightBefore));
- Contract.Invariant(cce.NonNullDictionaryAndValues(weightAfter));
- Contract.Invariant(cce.NonNullDictionaryAndValues(liveVarsAfter));
- Contract.Invariant(cce.NonNullDictionaryAndValues(liveVarsBefore));
- Contract.Invariant(summary != null);
- Contract.Invariant(impl != null);
- }
-
-
- [NotDelayed]
- public ICFG(Implementation impl) {
- Contract.Requires(impl != null);
- this.graph = new Graph<Block/*!*/>();
- this.procsCalled = new Dictionary<string/*!*/, List<Block/*!*/>/*!*/>();
- this.nodes = new HashSet<Block/*!*/>();
- this.succEdges = new Dictionary<Block/*!*/, HashSet<Block/*!*/>/*!*/>();
- this.predEdges = new Dictionary<Block/*!*/, HashSet<Block/*!*/>/*!*/>();
-
- this.priority = new Dictionary<Block/*!*/, int>();
-
- this.srcNodes = new HashSet<Block/*!*/>();
- this.exitNodes = new HashSet<Block/*!*/>();
-
- this.weightBefore = new Dictionary<Block/*!*/, GenKillWeight/*!*/>();
- this.weightAfter = new Dictionary<Block/*!*/, GenKillWeight/*!*/>();
- this.liveVarsAfter = new Dictionary<Block/*!*/, HashSet<Variable/*!*/>/*!*/>();
- this.liveVarsBefore = new Dictionary<Block/*!*/, HashSet<Variable/*!*/>/*!*/>();
-
- summary = GenKillWeight.zero();
- this.impl = impl;
-
- Initialize(impl);
-
- }
-
- private void Initialize(Implementation impl) {
- Contract.Requires(impl != null);
- addSource(impl.Blocks[0]);
- graph.AddSource(impl.Blocks[0]);
-
- foreach (Block/*!*/ b in impl.Blocks) {
- Contract.Assert(b != null);
- if (b.TransferCmd is ReturnCmd) {
- exitNodes.Add(b);
- } else {
- GotoCmd gc = b.TransferCmd as GotoCmd;
- Contract.Assert(gc != null);
- Contract.Assert(gc.labelTargets != null);
- foreach (Block/*!*/ t in gc.labelTargets) {
- Contract.Assert(t != null);
- addEdge(b, t);
- graph.AddEdge(b, t);
- }
- }
-
- weightBefore[b] = GenKillWeight.zero();
- weightAfter[b] = GenKillWeight.zero();
-
- foreach (Cmd/*!*/ c in b.Cmds) {
- Contract.Assert(c != null);
- if (c is CallCmd) {
- CallCmd/*!*/ cc = cce.NonNull((CallCmd/*!*/)c);
- Contract.Assert(cc.Proc != null);
- string/*!*/ procName = cc.Proc.Name;
- Contract.Assert(procName != null);
- if (!procsCalled.ContainsKey(procName)) {
- procsCalled.Add(procName, new List<Block/*!*/>());
- }
- procsCalled[procName].Add(b);
- }
- }
- }
-
- List<Block>/*!*/ sortedNodes;
- bool acyclic;
-
- graph.TarjanTopSort(out acyclic, out sortedNodes);
-
- if (!acyclic) {
- Console.WriteLine("Warning: graph is not a dag");
- }
-
- int num = sortedNodes.Count;
- foreach (Block/*!*/ b in sortedNodes) {
- Contract.Assert(b != null);
- priority.Add(b, num);
- num--;
- }
-
- }
-
- public int getPriority(Block b) {
- Contract.Requires(b != null);
- if (priority.ContainsKey(b))
- return priority[b];
- return Int32.MaxValue;
- }
-
- private void addSource(Block b) {
- Contract.Requires(b != null);
- registerNode(b);
- this.srcNodes.Add(b);
- }
-
- private void addExit(Block b) {
- Contract.Requires(b != null);
- registerNode(b);
- this.exitNodes.Add(b);
- }
-
- private void registerNode(Block b) {
- Contract.Requires(b != null);
- if (!succEdges.ContainsKey(b)) {
- succEdges.Add(b, new HashSet<Block/*!*/>());
- }
-
- if (!predEdges.ContainsKey(b)) {
- predEdges.Add(b, new HashSet<Block/*!*/>());
- }
-
- nodes.Add(b);
- }
-
- private void addEdge(Block src, Block tgt) {
- Contract.Requires(tgt != null);
- Contract.Requires(src != null);
- registerNode(src);
- registerNode(tgt);
-
- succEdges[src].Add(tgt);
- predEdges[tgt].Add(src);
- }
-
-
- }
-
- // Interprocedural Gen/Kill Analysis
- public class InterProcGenKill {
- Program/*!*/ program;
- Dictionary<string/*!*/, ICFG/*!*/>/*!*/ procICFG;
- Dictionary<string/*!*/, Procedure/*!*/>/*!*/ name2Proc;
- Dictionary<string/*!*/, List<WorkItem/*!*/>/*!*/>/*!*/ callers;
- Graph<string/*!*/>/*!*/ callGraph;
- Dictionary<string/*!*/, int>/*!*/ procPriority;
- int maxBlocksInProc;
-
- WorkList/*!*/ workList;
-
- Implementation/*!*/ mainImpl;
-
- static Dictionary<string/*!*/, HashSet<Variable/*!*/>/*!*/>/*!*/ varsLiveAtExit = new Dictionary<string/*!*/, HashSet<Variable/*!*/>/*!*/>();
- static Dictionary<string/*!*/, HashSet<Variable/*!*/>/*!*/>/*!*/ varsLiveAtEntry = new Dictionary<string/*!*/, HashSet<Variable/*!*/>/*!*/>();
- static Dictionary<string/*!*/, GenKillWeight/*!*/>/*!*/ varsLiveSummary = new Dictionary<string/*!*/, GenKillWeight/*!*/>();
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(workList != null);
- Contract.Invariant(mainImpl != null);
- Contract.Invariant(program != null);
- Contract.Invariant(cce.NonNullDictionaryAndValues(procICFG));
- Contract.Invariant(cce.NonNullDictionaryAndValues(name2Proc));
- Contract.Invariant(cce.NonNullDictionaryAndValues(callers) &&
- Contract.ForAll(callers.Values, v => cce.NonNullElements(v)));
- Contract.Invariant(cce.NonNullElements(callGraph.Nodes));
- Contract.Invariant(procPriority != null);
- Contract.Invariant(cce.NonNullDictionaryAndValues(varsLiveAtEntry));
- Contract.Invariant(cce.NonNullDictionaryAndValues(varsLiveAtExit) &&
- Contract.ForAll(varsLiveAtExit.Values, v => cce.NonNullElements(v)));
- Contract.Invariant(cce.NonNullDictionaryAndValues(varsLiveSummary));
- Contract.Invariant(cce.NonNullDictionaryAndValues(weightCacheAfterCall));
- Contract.Invariant(cce.NonNullDictionaryAndValues(weightCacheBeforeCall));
- }
-
-
- [NotDelayed]
- public InterProcGenKill(Implementation impl, Program program) {
- Contract.Requires(program != null);
- Contract.Requires(impl != null);
- this.program = program;
- procICFG = new Dictionary<string/*!*/, ICFG/*!*/>();
- name2Proc = new Dictionary<string/*!*/, Procedure/*!*/>();
- workList = new WorkList();
- this.callers = new Dictionary<string/*!*/, List<WorkItem/*!*/>/*!*/>();
- this.callGraph = new Graph<string/*!*/>();
- this.procPriority = new Dictionary<string/*!*/, int>();
- this.maxBlocksInProc = 0;
- this.mainImpl = impl;
-
- Dictionary<string/*!*/, Implementation/*!*/>/*!*/ name2Impl = new Dictionary<string/*!*/, Implementation/*!*/>();
- varsLiveAtExit.Clear();
- varsLiveAtEntry.Clear();
- varsLiveSummary.Clear();
-
- foreach (var decl in program.TopLevelDeclarations) {
- Contract.Assert(decl != null);
- if (decl is Implementation) {
- Implementation/*!*/ imp = (Implementation/*!*/)cce.NonNull(decl);
- name2Impl[imp.Name] = imp;
- } else if (decl is Procedure) {
- Procedure/*!*/ proc = cce.NonNull(decl as Procedure);
- name2Proc[proc.Name] = proc;
- }
- }
-
- ICFG/*!*/ mainICFG = new ICFG(mainImpl);
- Contract.Assert(mainICFG != null);
- procICFG.Add(mainICFG.impl.Name, mainICFG);
- callGraph.AddSource(mainICFG.impl.Name);
-
- List<ICFG/*!*/>/*!*/ procsToConsider = new List<ICFG/*!*/>();
- procsToConsider.Add(mainICFG);
-
- while (procsToConsider.Count != 0) {
- ICFG/*!*/ p = procsToConsider[0];
- Contract.Assert(p != null);
- procsToConsider.RemoveAt(0);
-
- foreach (string/*!*/ callee in p.procsCalled.Keys) {
- Contract.Assert(callee != null);
- if (!name2Impl.ContainsKey(callee))
- continue;
-
- callGraph.AddEdge(p.impl.Name, callee);
-
- if (maxBlocksInProc < p.nodes.Count) {
- maxBlocksInProc = p.nodes.Count;
- }
-
- if (!callers.ContainsKey(callee)) {
- callers.Add(callee, new List<WorkItem/*!*/>());
- }
- foreach (Block/*!*/ b in p.procsCalled[callee]) {
- Contract.Assert(b != null);
- callers[callee].Add(new WorkItem(p, b));
- }
-
- if (procICFG.ContainsKey(callee))
- continue;
- ICFG/*!*/ ncfg = new ICFG(name2Impl[callee]);
- Contract.Assert(ncfg != null);
- procICFG.Add(callee, ncfg);
- procsToConsider.Add(ncfg);
- }
- }
-
- bool acyclic;
- List<string>/*!*/ sortedNodes;
- callGraph.TarjanTopSort(out acyclic, out sortedNodes);
-
- Contract.Assert(acyclic);
-
- int cnt = 0;
- for (int i = sortedNodes.Count - 1; i >= 0; i--) {
- string s = sortedNodes[i];
- if (s == null)
- continue;
- procPriority.Add(s, cnt);
- cnt++;
- }
-
- }
-
- public static HashSet<Variable/*!*/>/*!*/ GetVarsLiveAtExit(Implementation impl, Program prog) {
- Contract.Requires(prog != null);
- Contract.Requires(impl != null);
- Contract.Ensures(cce.NonNullElements(Contract.Result<HashSet<Variable>>()));
- if (varsLiveAtExit.ContainsKey(impl.Name)) {
- return varsLiveAtExit[impl.Name];
- }
- // Return default: all globals and out params
- HashSet<Variable/*!*/>/*!*/ lv = new HashSet<Variable/*!*/>();
- foreach (Variable/*!*/ v in prog.GlobalVariables) {
- Contract.Assert(v != null);
- lv.Add(v);
- }
- foreach (Variable/*!*/ v in impl.OutParams) {
- Contract.Assert(v != null);
- lv.Add(v);
- }
- return lv;
- }
-
- public static HashSet<Variable/*!*/>/*!*/ GetVarsLiveAtEntry(Implementation impl, Program prog) {
- Contract.Requires(prog != null);
- Contract.Requires(impl != null);
- Contract.Ensures(cce.NonNullElements(Contract.Result<HashSet<Variable>>()));
- if (varsLiveAtEntry.ContainsKey(impl.Name)) {
- return varsLiveAtEntry[impl.Name];
- }
- // Return default: all globals and in params
- HashSet<Variable/*!*/>/*!*/ lv = new HashSet<Variable/*!*/>();
- foreach (Variable/*!*/ v in prog.GlobalVariables) {
- Contract.Assert(v != null);
- lv.Add(v);
- }
- foreach (Variable/*!*/ v in impl.InParams) {
- Contract.Assert(v != null);
- lv.Add(v);
- }
- return lv;
- }
-
- public static bool HasSummary(string name) {
- Contract.Requires(name != null);
- return varsLiveSummary.ContainsKey(name);
- }
-
- public static HashSet<Variable/*!*/>/*!*/ PropagateLiveVarsAcrossCall(CallCmd cmd, HashSet<Variable/*!*/>/*!*/ lvAfter) {
- Contract.Requires(cmd != null);
- Contract.Requires(cce.NonNullElements(lvAfter));
- Contract.Ensures(cce.NonNullElements(Contract.Result<HashSet<Variable>>()));
- Procedure/*!*/ proc = cce.NonNull(cmd.Proc);
- if (varsLiveSummary.ContainsKey(proc.Name)) {
- GenKillWeight/*!*/ w1 = getWeightBeforeCall(cmd);
- Contract.Assert(w1 != null);
- GenKillWeight/*!*/ w2 = varsLiveSummary[proc.Name];
- Contract.Assert(w2 != null);
- GenKillWeight/*!*/ w3 = getWeightAfterCall(cmd);
- Contract.Assert(w3 != null);
- GenKillWeight/*!*/ w = GenKillWeight.extend(w1, GenKillWeight.extend(w2, w3));
- Contract.Assert(w != null);
- return w.getLiveVars(lvAfter);
- }
- HashSet<Variable/*!*/>/*!*/ ret = new HashSet<Variable/*!*/>();
- ret.UnionWith(lvAfter);
- LiveVariableAnalysis.Propagate(cmd, ret);
- return ret;
- }
-
- class WorkItem {
- public ICFG/*!*/ cfg;
- public Block/*!*/ block;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cfg != null);
- Contract.Invariant(block != null);
- }
-
-
- public WorkItem(ICFG cfg, Block block) {
- Contract.Requires(block != null);
- Contract.Requires(cfg != null);
- this.cfg = cfg;
- this.block = block;
- }
-
- public GenKillWeight getWeightAfter() {
- Contract.Ensures(Contract.Result<GenKillWeight>() != null);
- return cfg.weightAfter[block];
- }
-
- public bool setWeightBefore(GenKillWeight w) {
- Contract.Requires(w != null);
- GenKillWeight/*!*/ prev = cfg.weightBefore[block];
- Contract.Assert(prev != null);
- GenKillWeight/*!*/ curr = GenKillWeight.combine(w, prev);
- Contract.Assert(curr != null);
- if (GenKillWeight.isEqual(prev, curr))
- return false;
- cfg.weightBefore[block] = curr;
- return true;
- }
-
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public override bool Equals(object other) {
- WorkItem/*!*/ wi = (WorkItem/*!*/)cce.NonNull(other);
- return (wi.cfg == cfg && wi.block == block);
- }
-
- [Pure]
- public override int GetHashCode() {
- return 0;
- }
-
- public string getLabel() {
- Contract.Ensures(Contract.Result<string>() != null);
- return cfg.impl.Name + "::" + block.Label;
- }
-
- }
-
- private void AddToWorkList(WorkItem wi) {
- Contract.Requires(wi != null);
- int i = procPriority[wi.cfg.impl.Name];
- int j = wi.cfg.getPriority(wi.block);
- int priority = (i * maxBlocksInProc) + j;
-
- workList.Add(wi, priority);
- }
-
- private void AddToWorkListReverse(WorkItem wi) {
- Contract.Requires(wi != null);
- int i = procPriority[wi.cfg.impl.Name];
- int j = wi.cfg.getPriority(wi.block);
- int priority = (procPriority.Count - i) * maxBlocksInProc + j;
- workList.Add(wi, priority);
- }
-
- class WorkList {
- SortedList<int, int>/*!*/ priorities;
- HashSet<string/*!*/>/*!*/ labels;
-
- Dictionary<int, List<WorkItem/*!*/>/*!*/>/*!*/ workList;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(priorities != null);
- Contract.Invariant(cce.NonNullElements(labels));
- Contract.Invariant(cce.NonNullDictionaryAndValues(workList) &&
- Contract.ForAll(workList.Values, v => cce.NonNullElements(v)));
- }
-
-
- public WorkList() {
- labels = new HashSet<string/*!*/>();
- priorities = new SortedList<int, int>();
- workList = new Dictionary<int, List<WorkItem/*!*/>/*!*/>();
- }
-
- public void Add(WorkItem wi, int priority) {
- Contract.Requires(wi != null);
- string/*!*/ lab = wi.getLabel();
- Contract.Assert(lab != null);
- if (labels.Contains(lab)) {
- // Already on worklist
- return;
- }
- labels.Add(lab);
- if (!workList.ContainsKey(priority)) {
- workList.Add(priority, new List<WorkItem/*!*/>());
- }
- workList[priority].Add(wi);
- if (!priorities.ContainsKey(priority)) {
- priorities.Add(priority, 0);
- }
-
- priorities[priority] = priorities[priority] + 1;
- }
-
- public WorkItem Get() {
- Contract.Ensures(Contract.Result<WorkItem>() != null);
- // Get minimum priority
- int p = cce.NonNull(priorities.Keys)[0];
- priorities[p] = priorities[p] - 1;
- if (priorities[p] == 0) {
- priorities.Remove(p);
- }
-
- // Get a WI with this priority
- WorkItem/*!*/ wi = workList[p][0];
- Contract.Assert(wi != null);
- workList[p].RemoveAt(0);
-
- // update labels
- labels.Remove(wi.getLabel());
- return wi;
- }
-
- public int Count {
- get {
- return labels.Count;
- }
- }
- }
-
- private GenKillWeight getSummary(CallCmd cmd) {
- Contract.Requires(cmd != null);
- Contract.Ensures(Contract.Result<GenKillWeight>() != null);
- Contract.Assert(cmd.Proc != null);
- string/*!*/ procName = cmd.Proc.Name;
- Contract.Assert(procName != null);
- if (procICFG.ContainsKey(procName)) {
- ICFG/*!*/ cfg = procICFG[procName];
- Contract.Assert(cfg != null);
- return GenKillWeight.projectLocals(cfg.summary);
- }
- {
- Contract.Assert(false);
- throw new cce.UnreachableException();
- }
- }
-
- public static void ComputeLiveVars(Implementation impl, Program/*!*/ prog) {
- Contract.Requires(prog != null);
- Contract.Requires(impl != null);
- InterProcGenKill/*!*/ ipgk = new InterProcGenKill(impl, prog);
- Contract.Assert(ipgk != null);
- ipgk.Compute();
- }
-
- public void Compute() {
- // Put all exit nodes in the worklist
- foreach (ICFG/*!*/ cfg in procICFG.Values) {
- Contract.Assert(cfg != null);
- foreach (Block/*!*/ eb in cfg.exitNodes) {
- Contract.Assert(eb != null);
- WorkItem/*!*/ wi = new WorkItem(cfg, eb);
- Contract.Assert(wi != null);
- cfg.weightAfter[eb] = GenKillWeight.one();
- AddToWorkList(wi);
- }
- }
-
- while (workList.Count != 0) {
- WorkItem/*!*/ wi = workList.Get();
- Contract.Assert(wi != null);
- process(wi);
- }
-
- // Propagate LV to all procedures
- foreach (ICFG/*!*/ cfg in procICFG.Values) {
- Contract.Assert(cfg != null);
- foreach (Block/*!*/ b in cfg.nodes) {
- Contract.Assert(b != null);
- cfg.liveVarsAfter.Add(b, new HashSet<Variable/*!*/>());
- cfg.liveVarsBefore.Add(b, new HashSet<Variable/*!*/>());
- }
- }
-
- ICFG/*!*/ mainCfg = procICFG[mainImpl.Name];
- Contract.Assert(mainCfg != null);
- foreach (Block/*!*/ eb in mainCfg.exitNodes) {
- Contract.Assert(eb != null);
- WorkItem/*!*/ wi = new WorkItem(mainCfg, eb);
- Contract.Assert(wi != null);
- AddToWorkListReverse(wi);
- }
-
- while (workList.Count != 0) {
- WorkItem/*!*/ wi = workList.Get();
- Contract.Assert(wi != null);
- processLV(wi);
- }
-
- // Set live variable info
- foreach (ICFG/*!*/ cfg in procICFG.Values) {
- Contract.Assert(cfg != null);
- HashSet<Variable/*!*/>/*!*/ lv = new HashSet<Variable/*!*/>();
- foreach (Block/*!*/ eb in cfg.exitNodes) {
- Contract.Assert(eb != null);
- lv.UnionWith(cfg.liveVarsAfter[eb]);
- }
- varsLiveAtExit.Add(cfg.impl.Name, lv);
- lv = new HashSet<Variable/*!*/>();
- foreach (Block/*!*/ eb in cfg.srcNodes) {
- Contract.Assert(eb != null);
- lv.UnionWith(cfg.liveVarsBefore[eb]);
- }
- varsLiveAtEntry.Add(cfg.impl.Name, lv);
- varsLiveSummary.Add(cfg.impl.Name, cfg.summary);
- }
-
- /*
- foreach(Block/*!*/
- /* b in mainImpl.Blocks){
-Contract.Assert(b != null);
-//Set<Variable!> lv = cfg.weightBefore[b].getLiveVars();
-b.liveVarsBefore = procICFG[mainImpl.Name].liveVarsAfter[b];
-//foreach(GlobalVariable/*!*/
- /* v in program.GlobalVariables){Contract.Assert(v != null);
-// b.liveVarsBefore.Add(v);
-//}
-}
-*/
- }
-
- // Called when summaries have already been computed
- private void processLV(WorkItem wi) {
- Contract.Requires(wi != null);
- ICFG/*!*/ cfg = wi.cfg;
- Contract.Assert(cfg != null);
- Block/*!*/ block = wi.block;
- Contract.Assert(block != null);
- HashSet<Variable/*!*/>/*!*/ lv = cfg.liveVarsAfter[block];
- Contract.Assert(cce.NonNullElements(lv));
- // Propagate backwards in the block
- HashSet<Variable/*!*/>/*!*/ prop = new HashSet<Variable/*!*/>();
- prop.UnionWith(lv);
- for (int i = block.Cmds.Count - 1; i >= 0; i--) {
- Cmd/*!*/ cmd = block.Cmds[i];
- Contract.Assert(cmd != null);
- if (cmd is CallCmd) {
- string/*!*/ procName = cce.NonNull(cce.NonNull((CallCmd)cmd).Proc).Name;
- Contract.Assert(procName != null);
- if (procICFG.ContainsKey(procName)) {
- ICFG/*!*/ callee = procICFG[procName];
- Contract.Assert(callee != null);
- // Inter propagation
- // Remove local variables; add return variables
- HashSet<Variable/*!*/>/*!*/ elv = new HashSet<Variable/*!*/>();
- foreach (Variable/*!*/ v in prop) {
- Contract.Assert(v != null);
- if (v is GlobalVariable)
- elv.Add(v);
- }
- foreach (Variable/*!*/ v in callee.impl.OutParams) {
- Contract.Assert(v != null);
- elv.Add(v);
- }
-
- foreach (Block/*!*/ eb in callee.exitNodes) {
- Contract.Assert(eb != null);
- callee.liveVarsAfter[eb].UnionWith(elv);
- // TODO: check if modified before inserting
- AddToWorkListReverse(new WorkItem(callee, eb));
- }
-
- // Continue with intra propagation
- GenKillWeight/*!*/ summary = getWeightCall(cce.NonNull((CallCmd/*!*/)cmd));
- prop = summary.getLiveVars(prop);
- } else {
- LiveVariableAnalysis.Propagate(cmd, prop);
- }
- } else {
- LiveVariableAnalysis.Propagate(cmd, prop);
- }
- }
-
- cfg.liveVarsBefore[block].UnionWith(prop);
-
- foreach (Block/*!*/ b in cfg.predEdges[block]) {
- Contract.Assert(b != null);
- HashSet<Variable/*!*/>/*!*/ prev = cfg.liveVarsAfter[b];
- Contract.Assert(cce.NonNullElements(prev));
- HashSet<Variable/*!*/>/*!*/ curr = new HashSet<Variable>(prev);
- curr.UnionWith(cfg.liveVarsBefore[block]);
- Contract.Assert(cce.NonNullElements(curr));
- if (curr.Count != prev.Count) {
- cfg.liveVarsAfter[b] = curr;
- AddToWorkListReverse(new WorkItem(cfg, b));
- }
- }
- }
-
- private void process(WorkItem wi) {
- Contract.Requires(wi != null);
- GenKillWeight/*!*/ w = wi.getWeightAfter();
- Contract.Assert(w != null);
-
- for (int i = wi.block.Cmds.Count - 1; i >= 0; i--) {
- Cmd/*!*/ c = wi.block.Cmds[i];
- Contract.Assert(c != null);
- if (c is CallCmd && procICFG.ContainsKey(cce.NonNull(cce.NonNull((CallCmd)c).Proc).Name)) {
- w = GenKillWeight.extend(getWeightCall(cce.NonNull((CallCmd)c)), w);
- } else {
- GenKillWeight/*!*/ cweight = getWeight(c, wi.cfg.impl, program);
- Contract.Assert(cweight != null);
- w = GenKillWeight.extend(cweight, w);
- }
- }
-
- bool change = wi.setWeightBefore(w);
-
- if (change && wi.cfg.srcNodes.Contains(wi.block)) {
- GenKillWeight/*!*/ prev = wi.cfg.summary;
- Contract.Assert(prev != null);
- GenKillWeight/*!*/ curr = GenKillWeight.combine(prev, wi.cfg.weightBefore[wi.block]);
- Contract.Assert(curr != null);
- if (!GenKillWeight.isEqual(prev, curr)) {
- wi.cfg.summary = curr;
- // push callers onto the worklist
- if (callers.ContainsKey(wi.cfg.impl.Name)) {
- foreach (WorkItem/*!*/ caller in callers[wi.cfg.impl.Name]) {
- Contract.Assert(caller != null);
- AddToWorkList(caller);
- }
- }
- }
- }
-
- foreach (Block/*!*/ b in wi.cfg.predEdges[wi.block]) {
- Contract.Assert(b != null);
- GenKillWeight/*!*/ prev = wi.cfg.weightAfter[b];
- Contract.Assert(prev != null);
- GenKillWeight/*!*/ curr = GenKillWeight.combine(prev, w);
- Contract.Assert(curr != null);
- if (!GenKillWeight.isEqual(prev, curr)) {
- wi.cfg.weightAfter[b] = curr;
- AddToWorkList(new WorkItem(wi.cfg, b));
- }
- }
-
- }
-
- static Dictionary<Cmd/*!*/, GenKillWeight/*!*/>/*!*/ weightCache = new Dictionary<Cmd/*!*/, GenKillWeight/*!*/>();
-
- private static GenKillWeight getWeight(Cmd cmd) {
- Contract.Requires(cmd != null);
- Contract.Ensures(Contract.Result<GenKillWeight>() != null);
- return getWeight(cmd, null, null);
- }
-
- private GenKillWeight getWeightCall(CallCmd cmd) {
- Contract.Requires(cmd != null);
- Contract.Ensures(Contract.Result<GenKillWeight>() != null);
- GenKillWeight/*!*/ w1 = getWeightBeforeCall(cmd);
- GenKillWeight/*!*/ w2 = getSummary(cmd);
- GenKillWeight/*!*/ w3 = getWeightAfterCall(cmd);
- Contract.Assert(w1 != null);
- Contract.Assert(w2 != null);
- Contract.Assert(w3 != null);
- return GenKillWeight.extend(w1, GenKillWeight.extend(w2, w3));
- }
-
- private static GenKillWeight getWeight(Cmd cmd, Implementation impl, Program prog) {
- Contract.Requires(cmd != null);
- Contract.Ensures(Contract.Result<GenKillWeight>() != null);
-
- if (weightCache.ContainsKey(cmd))
- return weightCache[cmd];
-
- HashSet<Variable/*!*/>/*!*/ gen = new HashSet<Variable/*!*/>();
- HashSet<Variable/*!*/>/*!*/ kill = new HashSet<Variable/*!*/>();
- GenKillWeight/*!*/ ret;
-
- if (cmd is AssignCmd) {
- AssignCmd/*!*/ assignCmd = (AssignCmd)cmd;
- Contract.Assert(cmd != null);
- // I must first iterate over all the targets and remove the live ones.
- // After the removals are done, I must add the variables referred on
- // the right side of the removed targets
- foreach (AssignLhs/*!*/ lhs in assignCmd.Lhss) {
- Contract.Assert(lhs != null);
- Variable var = lhs.DeepAssignedVariable;
- if (var != null) {
- if (lhs is SimpleAssignLhs) {
- // we should only remove non-map target variables because there is an implicit
- // read of a map variable in an assignment to it
- kill.Add(var);
- }
- }
- }
- int index = 0;
- foreach (Expr/*!*/ expr in assignCmd.Rhss) {
- Contract.Assert(expr != null);
- VariableCollector/*!*/ collector = new VariableCollector();
- collector.Visit(expr);
- gen.UnionWith(collector.usedVars);
- AssignLhs lhs = assignCmd.Lhss[index];
- if (lhs is MapAssignLhs) {
- // If the target is a map, then all indices are also read
- MapAssignLhs malhs = (MapAssignLhs)lhs;
- foreach (Expr e in malhs.Indexes) {
- VariableCollector/*!*/ c = new VariableCollector();
- c.Visit(e);
- gen.UnionWith(c.usedVars);
- }
- }
- index++;
- }
- ret = new GenKillWeight(gen, kill);
- } else if (cmd is HavocCmd) {
- HavocCmd/*!*/ havocCmd = (HavocCmd)cce.NonNull(cmd);
- foreach (IdentifierExpr/*!*/ expr in havocCmd.Vars) {
- Contract.Assert(expr != null);
- if (expr.Decl != null) {
- kill.Add(expr.Decl);
- }
- }
- ret = new GenKillWeight(gen, kill);
- } else if (cmd is PredicateCmd) {
- Contract.Assert((cmd is AssertCmd || cmd is AssumeCmd));
- PredicateCmd/*!*/ predicateCmd = (PredicateCmd)cce.NonNull(cmd);
- if (predicateCmd.Expr is LiteralExpr && prog != null && impl != null) {
- LiteralExpr le = (LiteralExpr)predicateCmd.Expr;
- if (le.IsFalse) {
- var globals = prog.GlobalVariables;
- Contract.Assert(cce.NonNullElements(globals));
- foreach (Variable/*!*/ v in globals) {
- Contract.Assert(v != null);
- kill.Add(v);
- }
- foreach (Variable/*!*/ v in impl.LocVars) {
- Contract.Assert(v != null);
- kill.Add(v);
- }
- foreach (Variable/*!*/ v in impl.OutParams) {
- Contract.Assert(v != null);
- kill.Add(v);
- }
- }
- } else {
- VariableCollector/*!*/ collector = new VariableCollector();
- collector.Visit(predicateCmd.Expr);
- gen.UnionWith(collector.usedVars);
- }
- ret = new GenKillWeight(gen, kill);
- } else if (cmd is CommentCmd) {
- ret = new GenKillWeight(gen, kill);
- // comments are just for debugging and don't affect verification
- } else if (cmd is SugaredCmd) {
- SugaredCmd/*!*/ sugCmd = (SugaredCmd)cmd;
- Contract.Assert(sugCmd != null);
- ret = getWeight(sugCmd.Desugaring, impl, prog);
- } else if (cmd is StateCmd) {
- StateCmd/*!*/ stCmd = (StateCmd)cmd;
- Contract.Assert(stCmd != null);
- List<Cmd>/*!*/ cmds = stCmd.Cmds;
- Contract.Assert(cmds != null);
- int len = cmds.Count;
- ret = GenKillWeight.one();
- for (int i = len - 1; i >= 0; i--) {
- GenKillWeight/*!*/ w = getWeight(cmds[i], impl, prog);
- Contract.Assert(w != null);
- ret = GenKillWeight.extend(w, ret);
- }
- foreach (Variable/*!*/ v in stCmd.Locals) {
- Contract.Assert(v != null);
- kill.Add(v);
- }
- ret = GenKillWeight.extend(new GenKillWeight(gen, kill), ret);
- } else {
- {
- Contract.Assert(false);
- throw new cce.UnreachableException();
- }
- }
-
- weightCache[cmd] = ret;
- return ret;
- }
-
- static Dictionary<Cmd/*!*/, GenKillWeight/*!*/>/*!*/ weightCacheAfterCall = new Dictionary<Cmd/*!*/, GenKillWeight/*!*/>();
- static Dictionary<Cmd/*!*/, GenKillWeight/*!*/>/*!*/ weightCacheBeforeCall = new Dictionary<Cmd/*!*/, GenKillWeight/*!*/>();
-
- private static GenKillWeight getWeightAfterCall(Cmd cmd) {
- Contract.Requires(cmd != null);
- Contract.Ensures(Contract.Result<GenKillWeight>() != null);
-
- if (weightCacheAfterCall.ContainsKey(cmd))
- return weightCacheAfterCall[cmd];
-
- HashSet<Variable/*!*/>/*!*/ gen = new HashSet<Variable/*!*/>();
- HashSet<Variable/*!*/>/*!*/ kill = new HashSet<Variable/*!*/>();
-
- Contract.Assert(cmd is CallCmd);
- CallCmd/*!*/ ccmd = cce.NonNull((CallCmd)cmd);
-
- foreach (IdentifierExpr/*!*/ ie in ccmd.Outs) {
- Contract.Assert(ie != null);
- if (ie.Decl != null)
- kill.Add(ie.Decl);
- }
-
- // Variables in ensures are considered as "read"
- foreach (Ensures/*!*/ re in cce.NonNull(ccmd.Proc).Ensures) {
- Contract.Assert(re != null);
- VariableCollector/*!*/ collector = new VariableCollector();
- collector.Visit(re.Condition);
- foreach (Variable/*!*/ v in collector.usedVars) {
- Contract.Assert(v != null);
- if (v is GlobalVariable) {
- gen.Add(v);
- }
- }
- }
-
- GenKillWeight/*!*/ ret = new GenKillWeight(gen, kill);
- Contract.Assert(ret != null);
- weightCacheAfterCall[cmd] = ret;
- return ret;
- }
-
- private static GenKillWeight getWeightBeforeCall(Cmd cmd) {
- Contract.Requires(cmd != null);
- Contract.Ensures(Contract.Result<GenKillWeight>() != null);
- Contract.Assert((cmd is CallCmd));
- if (weightCacheBeforeCall.ContainsKey(cmd))
- return weightCacheBeforeCall[cmd];
-
- HashSet<Variable/*!*/>/*!*/ gen = new HashSet<Variable/*!*/>();
- HashSet<Variable/*!*/>/*!*/ kill = new HashSet<Variable/*!*/>();
- CallCmd/*!*/ ccmd = cce.NonNull((CallCmd/*!*/)cmd);
-
- foreach (Expr/*!*/ expr in ccmd.Ins) {
- Contract.Assert(expr != null);
- VariableCollector/*!*/ collector = new VariableCollector();
- collector.Visit(expr);
- gen.UnionWith(collector.usedVars);
- }
-
- Contract.Assert(ccmd.Proc != null);
-
- // Variables in requires are considered as "read"
- foreach (Requires/*!*/ re in ccmd.Proc.Requires) {
- Contract.Assert(re != null);
- VariableCollector/*!*/ collector = new VariableCollector();
- collector.Visit(re.Condition);
- foreach (Variable/*!*/ v in collector.usedVars) {
- Contract.Assert(v != null);
- if (v is GlobalVariable) {
- gen.Add(v);
- }
- }
- }
-
- // Old variables in ensures are considered as "read"
- foreach (Ensures/*!*/ re in ccmd.Proc.Ensures) {
- Contract.Assert(re != null);
- VariableCollector/*!*/ collector = new VariableCollector();
- collector.Visit(re.Condition);
- foreach (Variable/*!*/ v in collector.oldVarsUsed) {
- Contract.Assert(v != null);
- if (v is GlobalVariable) {
- gen.Add(v);
- }
- }
- }
-
- GenKillWeight/*!*/ ret = new GenKillWeight(gen, kill);
- Contract.Assert(ret != null);
- weightCacheAfterCall[cmd] = ret;
- return ret;
- }
- }
-
- public class TokenEliminator : ReadOnlyVisitor
- {
- public int TokenCount = 0;
- public override Expr VisitExpr(Expr node)
- {
- node.tok = Token.NoToken;
- TokenCount++;
- return base.VisitExpr(node);
- }
- public override Variable VisitVariable(Variable node)
- {
- node.tok = Token.NoToken;
- TokenCount++;
- return base.VisitVariable(node);
- }
- public override Function VisitFunction(Function node)
- {
- node.tok = Token.NoToken;
- TokenCount++;
- return base.VisitFunction(node);
- }
- public override Implementation VisitImplementation(Implementation node)
- {
- node.tok = Token.NoToken;
- TokenCount++;
- return base.VisitImplementation(node);
- }
- public override Procedure VisitProcedure(Procedure node)
- {
- node.tok = Token.NoToken;
- TokenCount++;
- return base.VisitProcedure(node);
- }
- public override Axiom VisitAxiom(Axiom node)
- {
- node.tok = Token.NoToken;
- TokenCount++;
- return base.VisitAxiom(node);
- }
- public override Cmd VisitAssignCmd(AssignCmd node)
- {
- node.tok = Token.NoToken;
- TokenCount++;
- return base.VisitAssignCmd(node);
- }
- public override Cmd VisitAssumeCmd(AssumeCmd node)
- {
- node.tok = Token.NoToken;
- TokenCount++;
- return base.VisitAssumeCmd(node);
- }
- public override Cmd VisitHavocCmd(HavocCmd node)
- {
- node.tok = Token.NoToken;
- TokenCount++;
- return base.VisitHavocCmd(node);
- }
- public override Constant VisitConstant(Constant node)
- {
- node.tok = Token.NoToken;
- TokenCount++;
- return base.VisitConstant(node);
- }
- public override TransferCmd VisitTransferCmd(TransferCmd node)
- {
- node.tok = Token.NoToken;
- TokenCount++;
- return base.VisitTransferCmd(node);
- }
- public override Block VisitBlock(Block node)
- {
- node.tok = Token.NoToken;
- TokenCount++;
- return base.VisitBlock(node);
- }
- }
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Boogie.GraphUtil;
+using System.Diagnostics.Contracts;
+
+
+namespace Microsoft.Boogie {
+ public class UnusedVarEliminator : VariableCollector {
+ public static void Eliminate(Program program) {
+ Contract.Requires(program != null);
+ UnusedVarEliminator elim = new UnusedVarEliminator();
+ elim.Visit(program);
+ }
+
+ private UnusedVarEliminator()
+ : base() {
+
+ }
+
+ public override Implementation VisitImplementation(Implementation node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Implementation>() != null);
+ //Console.WriteLine("Procedure {0}", node.Name);
+ Implementation/*!*/ impl = base.VisitImplementation(node);
+ Contract.Assert(impl != null);
+ //Console.WriteLine("Old number of local variables = {0}", impl.LocVars.Length);
+ List<Variable>/*!*/ vars = new List<Variable>();
+ foreach (Variable/*!*/ var in impl.LocVars) {
+ Contract.Assert(var != null);
+ if (_usedVars.Contains(var))
+ vars.Add(var);
+ }
+ impl.LocVars = vars;
+ //Console.WriteLine("New number of local variables = {0}", impl.LocVars.Length);
+ //Console.WriteLine("---------------------------------");
+ _usedVars.Clear();
+ return impl;
+ }
+ }
+
+ public class ModSetCollector : ReadOnlyVisitor {
+ private Procedure enclosingProc;
+ private Dictionary<Procedure/*!*/, HashSet<Variable/*!*/>/*!*/>/*!*/ modSets;
+ private HashSet<Procedure> yieldingProcs;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(cce.NonNullDictionaryAndValues(modSets));
+ Contract.Invariant(Contract.ForAll(modSets.Values, v => cce.NonNullElements(v)));
+ }
+
+ public ModSetCollector() {
+ modSets = new Dictionary<Procedure/*!*/, HashSet<Variable/*!*/>/*!*/>();
+ yieldingProcs = new HashSet<Procedure>();
+ }
+
+ private bool moreProcessingRequired;
+
+ public void DoModSetAnalysis(Program program) {
+ Contract.Requires(program != null);
+
+ if (CommandLineOptions.Clo.Trace)
+ {
+// Console.WriteLine();
+// Console.WriteLine("Running modset analysis ...");
+// int procCount = 0;
+// foreach (Declaration/*!*/ decl in program.TopLevelDeclarations)
+// {
+// Contract.Assert(decl != null);
+// if (decl is Procedure)
+// procCount++;
+// }
+// Console.WriteLine("Number of procedures = {0}", procCount);*/
+ }
+
+ HashSet<Procedure/*!*/> implementedProcs = new HashSet<Procedure/*!*/>();
+ foreach (var impl in program.Implementations) {
+ if (impl.Proc != null)
+ implementedProcs.Add(impl.Proc);
+ }
+ foreach (var proc in program.Procedures) {
+ if (!implementedProcs.Contains(proc))
+ {
+ enclosingProc = proc;
+ foreach (var expr in proc.Modifies)
+ {
+ Contract.Assert(expr != null);
+ ProcessVariable(expr.Decl);
+ }
+ enclosingProc = null;
+ }
+ else
+ {
+ modSets.Add(proc, new HashSet<Variable>());
+ }
+ }
+
+ moreProcessingRequired = true;
+ while (moreProcessingRequired) {
+ moreProcessingRequired = false;
+ this.Visit(program);
+ }
+
+ foreach (Procedure x in modSets.Keys)
+ {
+ x.Modifies = new List<IdentifierExpr>();
+ foreach (Variable v in modSets[x])
+ {
+ x.Modifies.Add(new IdentifierExpr(v.tok, v));
+ }
+ }
+ foreach (Procedure x in yieldingProcs)
+ {
+ if (!QKeyValue.FindBoolAttribute(x.Attributes, "yields"))
+ {
+ x.AddAttribute("yields");
+ }
+ }
+
+#if DEBUG_PRINT
+ Console.WriteLine("Number of procedures with nonempty modsets = {0}", modSets.Keys.Count);
+ foreach (Procedure/*!*/ x in modSets.Keys) {
+ Contract.Assert(x != null);
+ Console.Write("{0} : ", x.Name);
+ bool first = true;
+ foreach (Variable/*!*/ y in modSets[x]) {
+ Contract.Assert(y != null);
+ if (first)
+ first = false;
+ else
+ Console.Write(", ");
+ Console.Write("{0}", y.Name);
+ }
+ Console.WriteLine("");
+ }
+#endif
+ }
+
+ public override Implementation VisitImplementation(Implementation node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Implementation>() != null);
+ enclosingProc = node.Proc;
+ Implementation/*!*/ ret = base.VisitImplementation(node);
+ Contract.Assert(ret != null);
+ enclosingProc = null;
+
+ return ret;
+ }
+ public override YieldCmd VisitYieldCmd(YieldCmd node)
+ {
+ if (!yieldingProcs.Contains(enclosingProc))
+ {
+ yieldingProcs.Add(enclosingProc);
+ moreProcessingRequired = true;
+ }
+ return base.VisitYieldCmd(node);
+ }
+ public override Cmd VisitAssignCmd(AssignCmd assignCmd) {
+ //Contract.Requires(assignCmd != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ Cmd ret = base.VisitAssignCmd(assignCmd);
+ foreach (AssignLhs/*!*/ lhs in assignCmd.Lhss) {
+ Contract.Assert(lhs != null);
+ ProcessVariable(lhs.DeepAssignedVariable);
+ }
+ return ret;
+ }
+ public override Cmd VisitHavocCmd(HavocCmd havocCmd) {
+ //Contract.Requires(havocCmd != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ Cmd ret = base.VisitHavocCmd(havocCmd);
+ foreach (IdentifierExpr/*!*/ expr in havocCmd.Vars) {
+ Contract.Assert(expr != null);
+ ProcessVariable(expr.Decl);
+ }
+ return ret;
+ }
+ public override Cmd VisitCallCmd(CallCmd callCmd) {
+ //Contract.Requires(callCmd != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ Cmd ret = base.VisitCallCmd(callCmd);
+ foreach (IdentifierExpr ie in callCmd.Outs)
+ {
+ if (ie != null) ProcessVariable(ie.Decl);
+ }
+ Procedure callee = callCmd.Proc;
+ if (callee == null)
+ return ret;
+ if (modSets.ContainsKey(callee)) {
+ foreach (Variable var in modSets[callee]) {
+ ProcessVariable(var);
+ }
+ }
+ if (!yieldingProcs.Contains(enclosingProc) && (yieldingProcs.Contains(callCmd.Proc) || callCmd.IsAsync))
+ {
+ yieldingProcs.Add(enclosingProc);
+ moreProcessingRequired = true;
+ }
+ if (callCmd.IsAsync)
+ {
+ if (!yieldingProcs.Contains(callCmd.Proc))
+ {
+ yieldingProcs.Add(callCmd.Proc);
+ moreProcessingRequired = true;
+ }
+ }
+ return ret;
+ }
+ public override Cmd VisitParCallCmd(ParCallCmd node)
+ {
+ //Contract.Requires(callCmd != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ Cmd ret = base.VisitParCallCmd(node);
+ if (!yieldingProcs.Contains(enclosingProc))
+ {
+ yieldingProcs.Add(enclosingProc);
+ moreProcessingRequired = true;
+ }
+ foreach (CallCmd callCmd in node.CallCmds)
+ {
+ if (!yieldingProcs.Contains(callCmd.Proc))
+ {
+ yieldingProcs.Add(callCmd.Proc);
+ moreProcessingRequired = true;
+ }
+ }
+ return ret;
+ }
+ private void ProcessVariable(Variable var) {
+ Procedure/*!*/ localProc = cce.NonNull(enclosingProc);
+ if (var == null)
+ return;
+ if (!(var is GlobalVariable))
+ return;
+ if (!modSets.ContainsKey(localProc)) {
+ modSets[localProc] = new HashSet<Variable/*!*/>();
+ }
+ if (modSets[localProc].Contains(var))
+ return;
+ moreProcessingRequired = true;
+ modSets[localProc].Add(var);
+ }
+ public override Expr VisitCodeExpr(CodeExpr node) {
+ // don't go into the code expression, since it can only modify variables local to the code expression,
+ // and the mod-set analysis is interested in global variables
+ return node;
+ }
+ }
+
+ public class MutableVariableCollector : ReadOnlyVisitor
+ {
+ public HashSet<Variable> UsedVariables = new HashSet<Variable>();
+
+ public void AddUsedVariables(HashSet<Variable> usedVariables)
+ {
+ Contract.Requires(usedVariables != null);
+
+ foreach (var v in usedVariables)
+ {
+ UsedVariables.Add(v);
+ }
+ }
+
+ public override Expr VisitIdentifierExpr(IdentifierExpr node)
+ {
+ Contract.Ensures(Contract.Result<Expr>() != null);
+
+ if (node.Decl != null && node.Decl.IsMutable)
+ {
+ UsedVariables.Add(node.Decl);
+ }
+ return base.VisitIdentifierExpr(node);
+ }
+ }
+
+ public class VariableCollector : ReadOnlyVisitor {
+ protected HashSet<Variable/*!*/>/*!*/ _usedVars;
+ public IEnumerable<Variable /*!*/>/*!*/ usedVars
+ {
+ get
+ {
+ return _usedVars.AsEnumerable();
+ }
+ }
+
+ protected HashSet<Variable/*!*/>/*!*/ _oldVarsUsed;
+ public IEnumerable<Variable /*!*/>/*!*/ oldVarsUsed
+ {
+ get
+ {
+ return _oldVarsUsed.AsEnumerable();
+ }
+ }
+
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(cce.NonNullElements(_usedVars));
+ Contract.Invariant(cce.NonNullElements(_oldVarsUsed));
+ }
+
+ int insideOldExpr;
+
+ public VariableCollector() {
+ _usedVars = new System.Collections.Generic.HashSet<Variable/*!*/>();
+ _oldVarsUsed = new System.Collections.Generic.HashSet<Variable/*!*/>();
+ insideOldExpr = 0;
+ }
+
+ public override Expr VisitOldExpr(OldExpr node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ insideOldExpr++;
+ node.Expr = this.VisitExpr(node.Expr);
+ insideOldExpr--;
+ return node;
+ }
+
+ public override Expr VisitIdentifierExpr(IdentifierExpr node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ if (node.Decl != null) {
+ _usedVars.Add(node.Decl);
+ if (insideOldExpr > 0) {
+ _oldVarsUsed.Add(node.Decl);
+ }
+ }
+ return node;
+ }
+ }
+
+ public class BlockCoalescer : ReadOnlyVisitor {
+ public static void CoalesceBlocks(Program program) {
+ Contract.Requires(program != null);
+ BlockCoalescer blockCoalescer = new BlockCoalescer();
+ blockCoalescer.Visit(program);
+ }
+
+ private static HashSet<Block/*!*/>/*!*/ ComputeMultiPredecessorBlocks(Implementation/*!*/ impl) {
+ Contract.Requires(impl != null);
+ Contract.Ensures(cce.NonNullElements(Contract.Result<HashSet<Block>>()));
+ HashSet<Block/*!*/> visitedBlocks = new HashSet<Block/*!*/>();
+ HashSet<Block/*!*/> multiPredBlocks = new HashSet<Block/*!*/>();
+ Stack<Block/*!*/> dfsStack = new Stack<Block/*!*/>();
+ dfsStack.Push(impl.Blocks[0]);
+ while (dfsStack.Count > 0) {
+ Block/*!*/ b = dfsStack.Pop();
+ Contract.Assert(b != null);
+ if (visitedBlocks.Contains(b)) {
+ multiPredBlocks.Add(b);
+ continue;
+ }
+ visitedBlocks.Add(b);
+ if (b.TransferCmd == null)
+ continue;
+ if (b.TransferCmd is ReturnCmd)
+ continue;
+ Contract.Assert(b.TransferCmd is GotoCmd);
+ GotoCmd gotoCmd = (GotoCmd)b.TransferCmd;
+ if (gotoCmd.labelTargets == null)
+ continue;
+ foreach (Block/*!*/ succ in gotoCmd.labelTargets) {
+ Contract.Assert(succ != null);
+ dfsStack.Push(succ);
+ }
+ }
+ return multiPredBlocks;
+ }
+
+ public override Implementation VisitImplementation(Implementation impl) {
+ //Contract.Requires(impl != null);
+ Contract.Ensures(Contract.Result<Implementation>() != null);
+ //Console.WriteLine("Procedure {0}", impl.Name);
+ //Console.WriteLine("Initial number of blocks = {0}", impl.Blocks.Count);
+
+ HashSet<Block/*!*/> multiPredBlocks = ComputeMultiPredecessorBlocks(impl);
+ Contract.Assert(cce.NonNullElements(multiPredBlocks));
+ HashSet<Block/*!*/> visitedBlocks = new HashSet<Block/*!*/>();
+ HashSet<Block/*!*/> removedBlocks = new HashSet<Block/*!*/>();
+ Stack<Block/*!*/> dfsStack = new Stack<Block/*!*/>();
+ dfsStack.Push(impl.Blocks[0]);
+ while (dfsStack.Count > 0) {
+ Block/*!*/ b = dfsStack.Pop();
+ Contract.Assert(b != null);
+ if (visitedBlocks.Contains(b))
+ continue;
+ visitedBlocks.Add(b);
+ if (b.TransferCmd == null)
+ continue;
+ if (b.TransferCmd is ReturnCmd)
+ continue;
+ Contract.Assert(b.TransferCmd is GotoCmd);
+ GotoCmd gotoCmd = (GotoCmd)b.TransferCmd;
+ if (gotoCmd.labelTargets == null)
+ continue;
+ if (gotoCmd.labelTargets.Count == 1) {
+ Block/*!*/ succ = cce.NonNull(gotoCmd.labelTargets[0]);
+ if (!multiPredBlocks.Contains(succ)) {
+ foreach (Cmd/*!*/ cmd in succ.Cmds) {
+ Contract.Assert(cmd != null);
+ b.Cmds.Add(cmd);
+ }
+ b.TransferCmd = succ.TransferCmd;
+ if (!b.tok.IsValid && succ.tok.IsValid) {
+ b.tok = succ.tok;
+ b.Label = succ.Label;
+ }
+ removedBlocks.Add(succ);
+ dfsStack.Push(b);
+ visitedBlocks.Remove(b);
+ continue;
+ }
+ }
+ foreach (Block/*!*/ succ in gotoCmd.labelTargets) {
+ Contract.Assert(succ != null);
+ dfsStack.Push(succ);
+ }
+ }
+
+ List<Block/*!*/> newBlocks = new List<Block/*!*/>();
+ foreach (Block/*!*/ b in impl.Blocks) {
+ Contract.Assert(b != null);
+ if (visitedBlocks.Contains(b) && !removedBlocks.Contains(b)) {
+ newBlocks.Add(b);
+ }
+ }
+ impl.Blocks = newBlocks;
+ foreach (Block b in impl.Blocks)
+ {
+ if (b.TransferCmd is ReturnCmd) continue;
+ GotoCmd gotoCmd = b.TransferCmd as GotoCmd;
+ gotoCmd.labelNames = new List<string>();
+ foreach (Block succ in gotoCmd.labelTargets)
+ {
+ gotoCmd.labelNames.Add(succ.Label);
+ }
+ }
+ // Console.WriteLine("Final number of blocks = {0}", impl.Blocks.Count);
+ return impl;
+ }
+ }
+
+ public class LiveVariableAnalysis {
+ public static void ClearLiveVariables(Implementation impl) {
+ Contract.Requires(impl != null);
+ foreach (Block/*!*/ block in impl.Blocks) {
+ Contract.Assert(block != null);
+ block.liveVarsBefore = null;
+ }
+ }
+
+ public static void ComputeLiveVariables(Implementation impl) {
+ Contract.Requires(impl != null);
+ Microsoft.Boogie.Helpers.ExtraTraceInformation("Starting live variable analysis");
+ Graph<Block> dag = new Graph<Block>();
+ dag.AddSource(cce.NonNull(impl.Blocks[0])); // there is always at least one node in the graph
+ foreach (Block b in impl.Blocks) {
+ GotoCmd gtc = b.TransferCmd as GotoCmd;
+ if (gtc != null) {
+ Contract.Assume(gtc.labelTargets != null);
+ foreach (Block/*!*/ dest in gtc.labelTargets) {
+ Contract.Assert(dest != null);
+ dag.AddEdge(dest, b);
+ }
+ }
+ }
+
+ IEnumerable<Block> sortedNodes;
+ if (CommandLineOptions.Clo.ModifyTopologicalSorting) {
+ sortedNodes = dag.TopologicalSort(true);
+ } else {
+ sortedNodes = dag.TopologicalSort();
+ }
+ foreach (Block/*!*/ block in sortedNodes) {
+ Contract.Assert(block != null);
+ HashSet<Variable/*!*/>/*!*/ liveVarsAfter = new HashSet<Variable/*!*/>();
+
+ // The injected assumption variables should always be considered to be live.
+ foreach (var v in impl.InjectedAssumptionVariables.Concat(impl.DoomedInjectedAssumptionVariables))
+ {
+ liveVarsAfter.Add(v);
+ }
+
+ if (block.TransferCmd is GotoCmd) {
+ GotoCmd gotoCmd = (GotoCmd)block.TransferCmd;
+ if (gotoCmd.labelTargets != null) {
+ foreach (Block/*!*/ succ in gotoCmd.labelTargets) {
+ Contract.Assert(succ != null);
+ Contract.Assert(succ.liveVarsBefore != null);
+ liveVarsAfter.UnionWith(succ.liveVarsBefore);
+ }
+ }
+ }
+
+ List<Cmd> cmds = block.Cmds;
+ int len = cmds.Count;
+ for (int i = len - 1; i >= 0; i--) {
+ if (cmds[i] is CallCmd) {
+ Procedure/*!*/ proc = cce.NonNull(cce.NonNull((CallCmd/*!*/)cmds[i]).Proc);
+ if (InterProcGenKill.HasSummary(proc.Name)) {
+ liveVarsAfter =
+ InterProcGenKill.PropagateLiveVarsAcrossCall(cce.NonNull((CallCmd/*!*/)cmds[i]), liveVarsAfter);
+ continue;
+ }
+ }
+ Propagate(cmds[i], liveVarsAfter);
+ }
+
+ block.liveVarsBefore = liveVarsAfter;
+
+ }
+ }
+
+ // perform in place update of liveSet
+ public static void Propagate(Cmd cmd, HashSet<Variable/*!*/>/*!*/ liveSet) {
+ Contract.Requires(cmd != null);
+ Contract.Requires(cce.NonNullElements(liveSet));
+ if (cmd is AssignCmd) {
+ AssignCmd/*!*/ assignCmd = (AssignCmd)cce.NonNull(cmd);
+ // I must first iterate over all the targets and remove the live ones.
+ // After the removals are done, I must add the variables referred on
+ // the right side of the removed targets
+
+ AssignCmd simpleAssignCmd = assignCmd.AsSimpleAssignCmd;
+ HashSet<int> indexSet = new HashSet<int>();
+ int index = 0;
+ foreach (AssignLhs/*!*/ lhs in simpleAssignCmd.Lhss) {
+ Contract.Assert(lhs != null);
+ SimpleAssignLhs salhs = lhs as SimpleAssignLhs;
+ Contract.Assert(salhs != null);
+ Variable var = salhs.DeepAssignedVariable;
+ if (var != null && liveSet.Contains(var)) {
+ indexSet.Add(index);
+ liveSet.Remove(var);
+ }
+ index++;
+ }
+ index = 0;
+ foreach (Expr/*!*/ expr in simpleAssignCmd.Rhss) {
+ Contract.Assert(expr != null);
+ if (indexSet.Contains(index)) {
+ VariableCollector/*!*/ collector = new VariableCollector();
+ collector.Visit(expr);
+ liveSet.UnionWith(collector.usedVars);
+ }
+ index++;
+ }
+ } else if (cmd is HavocCmd) {
+ HavocCmd/*!*/ havocCmd = (HavocCmd)cmd;
+ foreach (IdentifierExpr/*!*/ expr in havocCmd.Vars) {
+ Contract.Assert(expr != null);
+ if (expr.Decl != null && !(QKeyValue.FindBoolAttribute(expr.Decl.Attributes, "assumption") && expr.Decl.Name.StartsWith("a##cached##"))) {
+ liveSet.Remove(expr.Decl);
+ }
+ }
+ } else if (cmd is PredicateCmd) {
+ Contract.Assert((cmd is AssertCmd || cmd is AssumeCmd));
+ PredicateCmd/*!*/ predicateCmd = (PredicateCmd)cce.NonNull(cmd);
+ if (predicateCmd.Expr is LiteralExpr) {
+ LiteralExpr le = (LiteralExpr)predicateCmd.Expr;
+ if (le.IsFalse) {
+ liveSet.Clear();
+ }
+ } else {
+ VariableCollector/*!*/ collector = new VariableCollector();
+ collector.Visit(predicateCmd.Expr);
+ liveSet.UnionWith(collector.usedVars);
+ }
+ } else if (cmd is CommentCmd) {
+ // comments are just for debugging and don't affect verification
+ } else if (cmd is SugaredCmd) {
+ SugaredCmd/*!*/ sugCmd = (SugaredCmd)cce.NonNull(cmd);
+ Propagate(sugCmd.Desugaring, liveSet);
+ } else if (cmd is StateCmd) {
+ StateCmd/*!*/ stCmd = (StateCmd)cce.NonNull(cmd);
+ List<Cmd>/*!*/ cmds = cce.NonNull(stCmd.Cmds);
+ int len = cmds.Count;
+ for (int i = len - 1; i >= 0; i--) {
+ Propagate(cmds[i], liveSet);
+ }
+ foreach (Variable/*!*/ v in stCmd.Locals) {
+ Contract.Assert(v != null);
+ liveSet.Remove(v);
+ }
+ } else {
+ {
+ Contract.Assert(false);
+ throw new cce.UnreachableException();
+ }
+ }
+ }
+ }
+
+ /*
+ // An idempotent semiring interface
+ abstract public class Weight {
+ abstract public Weight! one();
+ abstract public Weight! zero();
+ abstract public Weight! extend(Weight! w1, Weight! w2);
+ abstract public Weight! combine(Weight! w1, Weight! w2);
+ abstract public Weight! isEqual(Weight! w);
+ abstract public Weight! projectLocals()
+ }
+ */
+
+ // Weight domain for LiveVariableAnalysis (Gen/Kill)
+
+ public class GenKillWeight {
+ // lambda S. (S - kill) union gen
+ HashSet<Variable/*!*/>/*!*/ gen;
+ HashSet<Variable/*!*/>/*!*/ kill;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(cce.NonNullElements(gen));
+ Contract.Invariant(cce.NonNullElements(kill));
+ Contract.Invariant(oneWeight != null);
+ Contract.Invariant(zeroWeight != null);
+ }
+
+ bool isZero;
+
+ public static GenKillWeight/*!*/ oneWeight = new GenKillWeight(new HashSet<Variable/*!*/>(), new HashSet<Variable/*!*/>());
+ public static GenKillWeight/*!*/ zeroWeight = new GenKillWeight();
+
+ // initializes to zero
+ public GenKillWeight() {
+ this.isZero = true;
+ this.gen = new HashSet<Variable/*!*/>();
+ this.kill = new HashSet<Variable/*!*/>();
+ }
+
+ public GenKillWeight(HashSet<Variable/*!*/> gen, HashSet<Variable/*!*/> kill) {
+ Contract.Requires(cce.NonNullElements(gen));
+ Contract.Requires(cce.NonNullElements(kill));
+ Contract.Assert(gen != null);
+ Contract.Assert(kill != null);
+ this.gen = gen;
+ this.kill = kill;
+ this.isZero = false;
+ }
+
+ public static GenKillWeight one() {
+ Contract.Ensures(Contract.Result<GenKillWeight>() != null);
+ return oneWeight;
+ }
+
+ public static GenKillWeight zero() {
+ Contract.Ensures(Contract.Result<GenKillWeight>() != null);
+ return zeroWeight;
+ }
+
+ public static GenKillWeight extend(GenKillWeight w1, GenKillWeight w2) {
+ Contract.Requires(w2 != null);
+ Contract.Requires(w1 != null);
+ Contract.Ensures(Contract.Result<GenKillWeight>() != null);
+ if (w1.isZero || w2.isZero)
+ return zero();
+
+ HashSet<Variable> t = new HashSet<Variable>(w2.gen);
+ t.ExceptWith(w1.kill);
+ HashSet<Variable> g = new HashSet<Variable>(w1.gen);
+ g.UnionWith(t);
+ HashSet<Variable> k = new HashSet<Variable>(w1.kill);
+ k.UnionWith(w2.kill);
+ return new GenKillWeight(g, k);
+ //return new GenKillWeight(w1.gen.Union(w2.gen.Difference(w1.kill)), w1.kill.Union(w2.kill));
+ }
+
+ public static GenKillWeight combine(GenKillWeight w1, GenKillWeight w2) {
+ Contract.Requires(w2 != null);
+ Contract.Requires(w1 != null);
+ Contract.Ensures(Contract.Result<GenKillWeight>() != null);
+ if (w1.isZero)
+ return w2;
+ if (w2.isZero)
+ return w1;
+
+ HashSet<Variable> g = new HashSet<Variable>(w1.gen);
+ g.UnionWith(w2.gen);
+ HashSet<Variable> k = new HashSet<Variable>(w1.kill);
+ k.IntersectWith(w2.kill);
+ return new GenKillWeight(g, k);
+ //return new GenKillWeight(w1.gen.Union(w2.gen), w1.kill.Intersection(w2.kill));
+ }
+
+ public static GenKillWeight projectLocals(GenKillWeight w) {
+ Contract.Requires(w != null);
+ Contract.Ensures(Contract.Result<GenKillWeight>() != null);
+ HashSet<Variable/*!*/> gen = new HashSet<Variable>();
+ foreach (Variable v in w.gen)
+ {
+ if (isGlobal(v))
+ gen.Add(v);
+ }
+ HashSet<Variable/*!*/> kill = new HashSet<Variable>();
+ foreach (Variable v in w.kill)
+ {
+ if (isGlobal(v))
+ kill.Add(v);
+ }
+
+ return new GenKillWeight(gen, kill);
+ }
+
+ public static bool isEqual(GenKillWeight w1, GenKillWeight w2) {
+ Contract.Requires(w2 != null);
+ Contract.Requires(w1 != null);
+ if (w1.isZero)
+ return w2.isZero;
+ if (w2.isZero)
+ return w1.isZero;
+
+ return (w1.gen.Equals(w2.gen) && w1.kill.Equals(w2.kill));
+ }
+
+ private static bool isGlobal(Variable v) {
+ Contract.Requires(v != null);
+ return (v is GlobalVariable);
+ }
+
+ [Pure]
+ public override string ToString() {
+ Contract.Ensures(Contract.Result<string>() != null);
+ return string.Format("({0},{1})", gen.ToString(), kill.ToString());
+ }
+
+ public HashSet<Variable/*!*/>/*!*/ getLiveVars() {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<HashSet<Variable>>()));
+ return gen;
+ }
+
+ public HashSet<Variable/*!*/>/*!*/ getLiveVars(HashSet<Variable/*!*/>/*!*/ lv) {
+ Contract.Requires(cce.NonNullElements(lv));
+ Contract.Ensures(cce.NonNullElements(Contract.Result<HashSet<Variable>>()));
+ HashSet<Variable> temp = new HashSet<Variable>(lv);
+ temp.ExceptWith(kill);
+ temp.UnionWith(gen);
+ return temp;
+ }
+
+ }
+
+ public class ICFG {
+ public Graph<Block/*!*/>/*!*/ graph;
+ // Map from procedure to the list of blocks that call that procedure
+ public Dictionary<string/*!*/, List<Block/*!*/>/*!*/>/*!*/ procsCalled;
+ public HashSet<Block/*!*/>/*!*/ nodes;
+ public Dictionary<Block/*!*/, HashSet<Block/*!*/>/*!*/>/*!*/ succEdges;
+ public Dictionary<Block/*!*/, HashSet<Block/*!*/>/*!*/>/*!*/ predEdges;
+ private Dictionary<Block/*!*/, int>/*!*/ priority;
+
+ public HashSet<Block/*!*/>/*!*/ srcNodes;
+ public HashSet<Block/*!*/>/*!*/ exitNodes;
+
+ public Dictionary<Block/*!*/, GenKillWeight/*!*/>/*!*/ weightBefore;
+ public Dictionary<Block/*!*/, GenKillWeight/*!*/>/*!*/ weightAfter;
+ public Dictionary<Block/*!*/, HashSet<Variable/*!*/>/*!*/>/*!*/ liveVarsAfter;
+ public Dictionary<Block/*!*/, HashSet<Variable/*!*/>/*!*/>/*!*/ liveVarsBefore;
+
+ public GenKillWeight/*!*/ summary;
+ public Implementation/*!*/ impl;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(cce.NonNullElements(graph.Nodes));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(procsCalled));
+ Contract.Invariant(cce.NonNullElements(nodes));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(succEdges));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(predEdges));
+ Contract.Invariant(priority != null);
+ Contract.Invariant(cce.NonNullElements(srcNodes));
+ Contract.Invariant(cce.NonNullElements(exitNodes));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(weightBefore));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(weightAfter));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(liveVarsAfter));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(liveVarsBefore));
+ Contract.Invariant(summary != null);
+ Contract.Invariant(impl != null);
+ }
+
+
+ [NotDelayed]
+ public ICFG(Implementation impl) {
+ Contract.Requires(impl != null);
+ this.graph = new Graph<Block/*!*/>();
+ this.procsCalled = new Dictionary<string/*!*/, List<Block/*!*/>/*!*/>();
+ this.nodes = new HashSet<Block/*!*/>();
+ this.succEdges = new Dictionary<Block/*!*/, HashSet<Block/*!*/>/*!*/>();
+ this.predEdges = new Dictionary<Block/*!*/, HashSet<Block/*!*/>/*!*/>();
+
+ this.priority = new Dictionary<Block/*!*/, int>();
+
+ this.srcNodes = new HashSet<Block/*!*/>();
+ this.exitNodes = new HashSet<Block/*!*/>();
+
+ this.weightBefore = new Dictionary<Block/*!*/, GenKillWeight/*!*/>();
+ this.weightAfter = new Dictionary<Block/*!*/, GenKillWeight/*!*/>();
+ this.liveVarsAfter = new Dictionary<Block/*!*/, HashSet<Variable/*!*/>/*!*/>();
+ this.liveVarsBefore = new Dictionary<Block/*!*/, HashSet<Variable/*!*/>/*!*/>();
+
+ summary = GenKillWeight.zero();
+ this.impl = impl;
+
+ Initialize(impl);
+
+ }
+
+ private void Initialize(Implementation impl) {
+ Contract.Requires(impl != null);
+ addSource(impl.Blocks[0]);
+ graph.AddSource(impl.Blocks[0]);
+
+ foreach (Block/*!*/ b in impl.Blocks) {
+ Contract.Assert(b != null);
+ if (b.TransferCmd is ReturnCmd) {
+ exitNodes.Add(b);
+ } else {
+ GotoCmd gc = b.TransferCmd as GotoCmd;
+ Contract.Assert(gc != null);
+ Contract.Assert(gc.labelTargets != null);
+ foreach (Block/*!*/ t in gc.labelTargets) {
+ Contract.Assert(t != null);
+ addEdge(b, t);
+ graph.AddEdge(b, t);
+ }
+ }
+
+ weightBefore[b] = GenKillWeight.zero();
+ weightAfter[b] = GenKillWeight.zero();
+
+ foreach (Cmd/*!*/ c in b.Cmds) {
+ Contract.Assert(c != null);
+ if (c is CallCmd) {
+ CallCmd/*!*/ cc = cce.NonNull((CallCmd/*!*/)c);
+ Contract.Assert(cc.Proc != null);
+ string/*!*/ procName = cc.Proc.Name;
+ Contract.Assert(procName != null);
+ if (!procsCalled.ContainsKey(procName)) {
+ procsCalled.Add(procName, new List<Block/*!*/>());
+ }
+ procsCalled[procName].Add(b);
+ }
+ }
+ }
+
+ List<Block>/*!*/ sortedNodes;
+ bool acyclic;
+
+ graph.TarjanTopSort(out acyclic, out sortedNodes);
+
+ if (!acyclic) {
+ Console.WriteLine("Warning: graph is not a dag");
+ }
+
+ int num = sortedNodes.Count;
+ foreach (Block/*!*/ b in sortedNodes) {
+ Contract.Assert(b != null);
+ priority.Add(b, num);
+ num--;
+ }
+
+ }
+
+ public int getPriority(Block b) {
+ Contract.Requires(b != null);
+ if (priority.ContainsKey(b))
+ return priority[b];
+ return Int32.MaxValue;
+ }
+
+ private void addSource(Block b) {
+ Contract.Requires(b != null);
+ registerNode(b);
+ this.srcNodes.Add(b);
+ }
+
+ private void addExit(Block b) {
+ Contract.Requires(b != null);
+ registerNode(b);
+ this.exitNodes.Add(b);
+ }
+
+ private void registerNode(Block b) {
+ Contract.Requires(b != null);
+ if (!succEdges.ContainsKey(b)) {
+ succEdges.Add(b, new HashSet<Block/*!*/>());
+ }
+
+ if (!predEdges.ContainsKey(b)) {
+ predEdges.Add(b, new HashSet<Block/*!*/>());
+ }
+
+ nodes.Add(b);
+ }
+
+ private void addEdge(Block src, Block tgt) {
+ Contract.Requires(tgt != null);
+ Contract.Requires(src != null);
+ registerNode(src);
+ registerNode(tgt);
+
+ succEdges[src].Add(tgt);
+ predEdges[tgt].Add(src);
+ }
+
+
+ }
+
+ // Interprocedural Gen/Kill Analysis
+ public class InterProcGenKill {
+ Program/*!*/ program;
+ Dictionary<string/*!*/, ICFG/*!*/>/*!*/ procICFG;
+ Dictionary<string/*!*/, Procedure/*!*/>/*!*/ name2Proc;
+ Dictionary<string/*!*/, List<WorkItem/*!*/>/*!*/>/*!*/ callers;
+ Graph<string/*!*/>/*!*/ callGraph;
+ Dictionary<string/*!*/, int>/*!*/ procPriority;
+ int maxBlocksInProc;
+
+ WorkList/*!*/ workList;
+
+ Implementation/*!*/ mainImpl;
+
+ static Dictionary<string/*!*/, HashSet<Variable/*!*/>/*!*/>/*!*/ varsLiveAtExit = new Dictionary<string/*!*/, HashSet<Variable/*!*/>/*!*/>();
+ static Dictionary<string/*!*/, HashSet<Variable/*!*/>/*!*/>/*!*/ varsLiveAtEntry = new Dictionary<string/*!*/, HashSet<Variable/*!*/>/*!*/>();
+ static Dictionary<string/*!*/, GenKillWeight/*!*/>/*!*/ varsLiveSummary = new Dictionary<string/*!*/, GenKillWeight/*!*/>();
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(workList != null);
+ Contract.Invariant(mainImpl != null);
+ Contract.Invariant(program != null);
+ Contract.Invariant(cce.NonNullDictionaryAndValues(procICFG));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(name2Proc));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(callers) &&
+ Contract.ForAll(callers.Values, v => cce.NonNullElements(v)));
+ Contract.Invariant(cce.NonNullElements(callGraph.Nodes));
+ Contract.Invariant(procPriority != null);
+ Contract.Invariant(cce.NonNullDictionaryAndValues(varsLiveAtEntry));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(varsLiveAtExit) &&
+ Contract.ForAll(varsLiveAtExit.Values, v => cce.NonNullElements(v)));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(varsLiveSummary));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(weightCacheAfterCall));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(weightCacheBeforeCall));
+ }
+
+
+ [NotDelayed]
+ public InterProcGenKill(Implementation impl, Program program) {
+ Contract.Requires(program != null);
+ Contract.Requires(impl != null);
+ this.program = program;
+ procICFG = new Dictionary<string/*!*/, ICFG/*!*/>();
+ name2Proc = new Dictionary<string/*!*/, Procedure/*!*/>();
+ workList = new WorkList();
+ this.callers = new Dictionary<string/*!*/, List<WorkItem/*!*/>/*!*/>();
+ this.callGraph = new Graph<string/*!*/>();
+ this.procPriority = new Dictionary<string/*!*/, int>();
+ this.maxBlocksInProc = 0;
+ this.mainImpl = impl;
+
+ Dictionary<string/*!*/, Implementation/*!*/>/*!*/ name2Impl = new Dictionary<string/*!*/, Implementation/*!*/>();
+ varsLiveAtExit.Clear();
+ varsLiveAtEntry.Clear();
+ varsLiveSummary.Clear();
+
+ foreach (var decl in program.TopLevelDeclarations) {
+ Contract.Assert(decl != null);
+ if (decl is Implementation) {
+ Implementation/*!*/ imp = (Implementation/*!*/)cce.NonNull(decl);
+ name2Impl[imp.Name] = imp;
+ } else if (decl is Procedure) {
+ Procedure/*!*/ proc = cce.NonNull(decl as Procedure);
+ name2Proc[proc.Name] = proc;
+ }
+ }
+
+ ICFG/*!*/ mainICFG = new ICFG(mainImpl);
+ Contract.Assert(mainICFG != null);
+ procICFG.Add(mainICFG.impl.Name, mainICFG);
+ callGraph.AddSource(mainICFG.impl.Name);
+
+ List<ICFG/*!*/>/*!*/ procsToConsider = new List<ICFG/*!*/>();
+ procsToConsider.Add(mainICFG);
+
+ while (procsToConsider.Count != 0) {
+ ICFG/*!*/ p = procsToConsider[0];
+ Contract.Assert(p != null);
+ procsToConsider.RemoveAt(0);
+
+ foreach (string/*!*/ callee in p.procsCalled.Keys) {
+ Contract.Assert(callee != null);
+ if (!name2Impl.ContainsKey(callee))
+ continue;
+
+ callGraph.AddEdge(p.impl.Name, callee);
+
+ if (maxBlocksInProc < p.nodes.Count) {
+ maxBlocksInProc = p.nodes.Count;
+ }
+
+ if (!callers.ContainsKey(callee)) {
+ callers.Add(callee, new List<WorkItem/*!*/>());
+ }
+ foreach (Block/*!*/ b in p.procsCalled[callee]) {
+ Contract.Assert(b != null);
+ callers[callee].Add(new WorkItem(p, b));
+ }
+
+ if (procICFG.ContainsKey(callee))
+ continue;
+ ICFG/*!*/ ncfg = new ICFG(name2Impl[callee]);
+ Contract.Assert(ncfg != null);
+ procICFG.Add(callee, ncfg);
+ procsToConsider.Add(ncfg);
+ }
+ }
+
+ bool acyclic;
+ List<string>/*!*/ sortedNodes;
+ callGraph.TarjanTopSort(out acyclic, out sortedNodes);
+
+ Contract.Assert(acyclic);
+
+ int cnt = 0;
+ for (int i = sortedNodes.Count - 1; i >= 0; i--) {
+ string s = sortedNodes[i];
+ if (s == null)
+ continue;
+ procPriority.Add(s, cnt);
+ cnt++;
+ }
+
+ }
+
+ public static HashSet<Variable/*!*/>/*!*/ GetVarsLiveAtExit(Implementation impl, Program prog) {
+ Contract.Requires(prog != null);
+ Contract.Requires(impl != null);
+ Contract.Ensures(cce.NonNullElements(Contract.Result<HashSet<Variable>>()));
+ if (varsLiveAtExit.ContainsKey(impl.Name)) {
+ return varsLiveAtExit[impl.Name];
+ }
+ // Return default: all globals and out params
+ HashSet<Variable/*!*/>/*!*/ lv = new HashSet<Variable/*!*/>();
+ foreach (Variable/*!*/ v in prog.GlobalVariables) {
+ Contract.Assert(v != null);
+ lv.Add(v);
+ }
+ foreach (Variable/*!*/ v in impl.OutParams) {
+ Contract.Assert(v != null);
+ lv.Add(v);
+ }
+ return lv;
+ }
+
+ public static HashSet<Variable/*!*/>/*!*/ GetVarsLiveAtEntry(Implementation impl, Program prog) {
+ Contract.Requires(prog != null);
+ Contract.Requires(impl != null);
+ Contract.Ensures(cce.NonNullElements(Contract.Result<HashSet<Variable>>()));
+ if (varsLiveAtEntry.ContainsKey(impl.Name)) {
+ return varsLiveAtEntry[impl.Name];
+ }
+ // Return default: all globals and in params
+ HashSet<Variable/*!*/>/*!*/ lv = new HashSet<Variable/*!*/>();
+ foreach (Variable/*!*/ v in prog.GlobalVariables) {
+ Contract.Assert(v != null);
+ lv.Add(v);
+ }
+ foreach (Variable/*!*/ v in impl.InParams) {
+ Contract.Assert(v != null);
+ lv.Add(v);
+ }
+ return lv;
+ }
+
+ public static bool HasSummary(string name) {
+ Contract.Requires(name != null);
+ return varsLiveSummary.ContainsKey(name);
+ }
+
+ public static HashSet<Variable/*!*/>/*!*/ PropagateLiveVarsAcrossCall(CallCmd cmd, HashSet<Variable/*!*/>/*!*/ lvAfter) {
+ Contract.Requires(cmd != null);
+ Contract.Requires(cce.NonNullElements(lvAfter));
+ Contract.Ensures(cce.NonNullElements(Contract.Result<HashSet<Variable>>()));
+ Procedure/*!*/ proc = cce.NonNull(cmd.Proc);
+ if (varsLiveSummary.ContainsKey(proc.Name)) {
+ GenKillWeight/*!*/ w1 = getWeightBeforeCall(cmd);
+ Contract.Assert(w1 != null);
+ GenKillWeight/*!*/ w2 = varsLiveSummary[proc.Name];
+ Contract.Assert(w2 != null);
+ GenKillWeight/*!*/ w3 = getWeightAfterCall(cmd);
+ Contract.Assert(w3 != null);
+ GenKillWeight/*!*/ w = GenKillWeight.extend(w1, GenKillWeight.extend(w2, w3));
+ Contract.Assert(w != null);
+ return w.getLiveVars(lvAfter);
+ }
+ HashSet<Variable/*!*/>/*!*/ ret = new HashSet<Variable/*!*/>();
+ ret.UnionWith(lvAfter);
+ LiveVariableAnalysis.Propagate(cmd, ret);
+ return ret;
+ }
+
+ class WorkItem {
+ public ICFG/*!*/ cfg;
+ public Block/*!*/ block;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(cfg != null);
+ Contract.Invariant(block != null);
+ }
+
+
+ public WorkItem(ICFG cfg, Block block) {
+ Contract.Requires(block != null);
+ Contract.Requires(cfg != null);
+ this.cfg = cfg;
+ this.block = block;
+ }
+
+ public GenKillWeight getWeightAfter() {
+ Contract.Ensures(Contract.Result<GenKillWeight>() != null);
+ return cfg.weightAfter[block];
+ }
+
+ public bool setWeightBefore(GenKillWeight w) {
+ Contract.Requires(w != null);
+ GenKillWeight/*!*/ prev = cfg.weightBefore[block];
+ Contract.Assert(prev != null);
+ GenKillWeight/*!*/ curr = GenKillWeight.combine(w, prev);
+ Contract.Assert(curr != null);
+ if (GenKillWeight.isEqual(prev, curr))
+ return false;
+ cfg.weightBefore[block] = curr;
+ return true;
+ }
+
+ [Pure]
+ [Reads(ReadsAttribute.Reads.Nothing)]
+ public override bool Equals(object other) {
+ WorkItem/*!*/ wi = (WorkItem/*!*/)cce.NonNull(other);
+ return (wi.cfg == cfg && wi.block == block);
+ }
+
+ [Pure]
+ public override int GetHashCode() {
+ return 0;
+ }
+
+ public string getLabel() {
+ Contract.Ensures(Contract.Result<string>() != null);
+ return cfg.impl.Name + "::" + block.Label;
+ }
+
+ }
+
+ private void AddToWorkList(WorkItem wi) {
+ Contract.Requires(wi != null);
+ int i = procPriority[wi.cfg.impl.Name];
+ int j = wi.cfg.getPriority(wi.block);
+ int priority = (i * maxBlocksInProc) + j;
+
+ workList.Add(wi, priority);
+ }
+
+ private void AddToWorkListReverse(WorkItem wi) {
+ Contract.Requires(wi != null);
+ int i = procPriority[wi.cfg.impl.Name];
+ int j = wi.cfg.getPriority(wi.block);
+ int priority = (procPriority.Count - i) * maxBlocksInProc + j;
+ workList.Add(wi, priority);
+ }
+
+ class WorkList {
+ SortedList<int, int>/*!*/ priorities;
+ HashSet<string/*!*/>/*!*/ labels;
+
+ Dictionary<int, List<WorkItem/*!*/>/*!*/>/*!*/ workList;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(priorities != null);
+ Contract.Invariant(cce.NonNullElements(labels));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(workList) &&
+ Contract.ForAll(workList.Values, v => cce.NonNullElements(v)));
+ }
+
+
+ public WorkList() {
+ labels = new HashSet<string/*!*/>();
+ priorities = new SortedList<int, int>();
+ workList = new Dictionary<int, List<WorkItem/*!*/>/*!*/>();
+ }
+
+ public void Add(WorkItem wi, int priority) {
+ Contract.Requires(wi != null);
+ string/*!*/ lab = wi.getLabel();
+ Contract.Assert(lab != null);
+ if (labels.Contains(lab)) {
+ // Already on worklist
+ return;
+ }
+ labels.Add(lab);
+ if (!workList.ContainsKey(priority)) {
+ workList.Add(priority, new List<WorkItem/*!*/>());
+ }
+ workList[priority].Add(wi);
+ if (!priorities.ContainsKey(priority)) {
+ priorities.Add(priority, 0);
+ }
+
+ priorities[priority] = priorities[priority] + 1;
+ }
+
+ public WorkItem Get() {
+ Contract.Ensures(Contract.Result<WorkItem>() != null);
+ // Get minimum priority
+ int p = cce.NonNull(priorities.Keys)[0];
+ priorities[p] = priorities[p] - 1;
+ if (priorities[p] == 0) {
+ priorities.Remove(p);
+ }
+
+ // Get a WI with this priority
+ WorkItem/*!*/ wi = workList[p][0];
+ Contract.Assert(wi != null);
+ workList[p].RemoveAt(0);
+
+ // update labels
+ labels.Remove(wi.getLabel());
+ return wi;
+ }
+
+ public int Count {
+ get {
+ return labels.Count;
+ }
+ }
+ }
+
+ private GenKillWeight getSummary(CallCmd cmd) {
+ Contract.Requires(cmd != null);
+ Contract.Ensures(Contract.Result<GenKillWeight>() != null);
+ Contract.Assert(cmd.Proc != null);
+ string/*!*/ procName = cmd.Proc.Name;
+ Contract.Assert(procName != null);
+ if (procICFG.ContainsKey(procName)) {
+ ICFG/*!*/ cfg = procICFG[procName];
+ Contract.Assert(cfg != null);
+ return GenKillWeight.projectLocals(cfg.summary);
+ }
+ {
+ Contract.Assert(false);
+ throw new cce.UnreachableException();
+ }
+ }
+
+ public static void ComputeLiveVars(Implementation impl, Program/*!*/ prog) {
+ Contract.Requires(prog != null);
+ Contract.Requires(impl != null);
+ InterProcGenKill/*!*/ ipgk = new InterProcGenKill(impl, prog);
+ Contract.Assert(ipgk != null);
+ ipgk.Compute();
+ }
+
+ public void Compute() {
+ // Put all exit nodes in the worklist
+ foreach (ICFG/*!*/ cfg in procICFG.Values) {
+ Contract.Assert(cfg != null);
+ foreach (Block/*!*/ eb in cfg.exitNodes) {
+ Contract.Assert(eb != null);
+ WorkItem/*!*/ wi = new WorkItem(cfg, eb);
+ Contract.Assert(wi != null);
+ cfg.weightAfter[eb] = GenKillWeight.one();
+ AddToWorkList(wi);
+ }
+ }
+
+ while (workList.Count != 0) {
+ WorkItem/*!*/ wi = workList.Get();
+ Contract.Assert(wi != null);
+ process(wi);
+ }
+
+ // Propagate LV to all procedures
+ foreach (ICFG/*!*/ cfg in procICFG.Values) {
+ Contract.Assert(cfg != null);
+ foreach (Block/*!*/ b in cfg.nodes) {
+ Contract.Assert(b != null);
+ cfg.liveVarsAfter.Add(b, new HashSet<Variable/*!*/>());
+ cfg.liveVarsBefore.Add(b, new HashSet<Variable/*!*/>());
+ }
+ }
+
+ ICFG/*!*/ mainCfg = procICFG[mainImpl.Name];
+ Contract.Assert(mainCfg != null);
+ foreach (Block/*!*/ eb in mainCfg.exitNodes) {
+ Contract.Assert(eb != null);
+ WorkItem/*!*/ wi = new WorkItem(mainCfg, eb);
+ Contract.Assert(wi != null);
+ AddToWorkListReverse(wi);
+ }
+
+ while (workList.Count != 0) {
+ WorkItem/*!*/ wi = workList.Get();
+ Contract.Assert(wi != null);
+ processLV(wi);
+ }
+
+ // Set live variable info
+ foreach (ICFG/*!*/ cfg in procICFG.Values) {
+ Contract.Assert(cfg != null);
+ HashSet<Variable/*!*/>/*!*/ lv = new HashSet<Variable/*!*/>();
+ foreach (Block/*!*/ eb in cfg.exitNodes) {
+ Contract.Assert(eb != null);
+ lv.UnionWith(cfg.liveVarsAfter[eb]);
+ }
+ varsLiveAtExit.Add(cfg.impl.Name, lv);
+ lv = new HashSet<Variable/*!*/>();
+ foreach (Block/*!*/ eb in cfg.srcNodes) {
+ Contract.Assert(eb != null);
+ lv.UnionWith(cfg.liveVarsBefore[eb]);
+ }
+ varsLiveAtEntry.Add(cfg.impl.Name, lv);
+ varsLiveSummary.Add(cfg.impl.Name, cfg.summary);
+ }
+
+ /*
+ foreach(Block/*!*/
+ /* b in mainImpl.Blocks){
+Contract.Assert(b != null);
+//Set<Variable!> lv = cfg.weightBefore[b].getLiveVars();
+b.liveVarsBefore = procICFG[mainImpl.Name].liveVarsAfter[b];
+//foreach(GlobalVariable/*!*/
+ /* v in program.GlobalVariables){Contract.Assert(v != null);
+// b.liveVarsBefore.Add(v);
+//}
+}
+*/
+ }
+
+ // Called when summaries have already been computed
+ private void processLV(WorkItem wi) {
+ Contract.Requires(wi != null);
+ ICFG/*!*/ cfg = wi.cfg;
+ Contract.Assert(cfg != null);
+ Block/*!*/ block = wi.block;
+ Contract.Assert(block != null);
+ HashSet<Variable/*!*/>/*!*/ lv = cfg.liveVarsAfter[block];
+ Contract.Assert(cce.NonNullElements(lv));
+ // Propagate backwards in the block
+ HashSet<Variable/*!*/>/*!*/ prop = new HashSet<Variable/*!*/>();
+ prop.UnionWith(lv);
+ for (int i = block.Cmds.Count - 1; i >= 0; i--) {
+ Cmd/*!*/ cmd = block.Cmds[i];
+ Contract.Assert(cmd != null);
+ if (cmd is CallCmd) {
+ string/*!*/ procName = cce.NonNull(cce.NonNull((CallCmd)cmd).Proc).Name;
+ Contract.Assert(procName != null);
+ if (procICFG.ContainsKey(procName)) {
+ ICFG/*!*/ callee = procICFG[procName];
+ Contract.Assert(callee != null);
+ // Inter propagation
+ // Remove local variables; add return variables
+ HashSet<Variable/*!*/>/*!*/ elv = new HashSet<Variable/*!*/>();
+ foreach (Variable/*!*/ v in prop) {
+ Contract.Assert(v != null);
+ if (v is GlobalVariable)
+ elv.Add(v);
+ }
+ foreach (Variable/*!*/ v in callee.impl.OutParams) {
+ Contract.Assert(v != null);
+ elv.Add(v);
+ }
+
+ foreach (Block/*!*/ eb in callee.exitNodes) {
+ Contract.Assert(eb != null);
+ callee.liveVarsAfter[eb].UnionWith(elv);
+ // TODO: check if modified before inserting
+ AddToWorkListReverse(new WorkItem(callee, eb));
+ }
+
+ // Continue with intra propagation
+ GenKillWeight/*!*/ summary = getWeightCall(cce.NonNull((CallCmd/*!*/)cmd));
+ prop = summary.getLiveVars(prop);
+ } else {
+ LiveVariableAnalysis.Propagate(cmd, prop);
+ }
+ } else {
+ LiveVariableAnalysis.Propagate(cmd, prop);
+ }
+ }
+
+ cfg.liveVarsBefore[block].UnionWith(prop);
+
+ foreach (Block/*!*/ b in cfg.predEdges[block]) {
+ Contract.Assert(b != null);
+ HashSet<Variable/*!*/>/*!*/ prev = cfg.liveVarsAfter[b];
+ Contract.Assert(cce.NonNullElements(prev));
+ HashSet<Variable/*!*/>/*!*/ curr = new HashSet<Variable>(prev);
+ curr.UnionWith(cfg.liveVarsBefore[block]);
+ Contract.Assert(cce.NonNullElements(curr));
+ if (curr.Count != prev.Count) {
+ cfg.liveVarsAfter[b] = curr;
+ AddToWorkListReverse(new WorkItem(cfg, b));
+ }
+ }
+ }
+
+ private void process(WorkItem wi) {
+ Contract.Requires(wi != null);
+ GenKillWeight/*!*/ w = wi.getWeightAfter();
+ Contract.Assert(w != null);
+
+ for (int i = wi.block.Cmds.Count - 1; i >= 0; i--) {
+ Cmd/*!*/ c = wi.block.Cmds[i];
+ Contract.Assert(c != null);
+ if (c is CallCmd && procICFG.ContainsKey(cce.NonNull(cce.NonNull((CallCmd)c).Proc).Name)) {
+ w = GenKillWeight.extend(getWeightCall(cce.NonNull((CallCmd)c)), w);
+ } else {
+ GenKillWeight/*!*/ cweight = getWeight(c, wi.cfg.impl, program);
+ Contract.Assert(cweight != null);
+ w = GenKillWeight.extend(cweight, w);
+ }
+ }
+
+ bool change = wi.setWeightBefore(w);
+
+ if (change && wi.cfg.srcNodes.Contains(wi.block)) {
+ GenKillWeight/*!*/ prev = wi.cfg.summary;
+ Contract.Assert(prev != null);
+ GenKillWeight/*!*/ curr = GenKillWeight.combine(prev, wi.cfg.weightBefore[wi.block]);
+ Contract.Assert(curr != null);
+ if (!GenKillWeight.isEqual(prev, curr)) {
+ wi.cfg.summary = curr;
+ // push callers onto the worklist
+ if (callers.ContainsKey(wi.cfg.impl.Name)) {
+ foreach (WorkItem/*!*/ caller in callers[wi.cfg.impl.Name]) {
+ Contract.Assert(caller != null);
+ AddToWorkList(caller);
+ }
+ }
+ }
+ }
+
+ foreach (Block/*!*/ b in wi.cfg.predEdges[wi.block]) {
+ Contract.Assert(b != null);
+ GenKillWeight/*!*/ prev = wi.cfg.weightAfter[b];
+ Contract.Assert(prev != null);
+ GenKillWeight/*!*/ curr = GenKillWeight.combine(prev, w);
+ Contract.Assert(curr != null);
+ if (!GenKillWeight.isEqual(prev, curr)) {
+ wi.cfg.weightAfter[b] = curr;
+ AddToWorkList(new WorkItem(wi.cfg, b));
+ }
+ }
+
+ }
+
+ static Dictionary<Cmd/*!*/, GenKillWeight/*!*/>/*!*/ weightCache = new Dictionary<Cmd/*!*/, GenKillWeight/*!*/>();
+
+ private static GenKillWeight getWeight(Cmd cmd) {
+ Contract.Requires(cmd != null);
+ Contract.Ensures(Contract.Result<GenKillWeight>() != null);
+ return getWeight(cmd, null, null);
+ }
+
+ private GenKillWeight getWeightCall(CallCmd cmd) {
+ Contract.Requires(cmd != null);
+ Contract.Ensures(Contract.Result<GenKillWeight>() != null);
+ GenKillWeight/*!*/ w1 = getWeightBeforeCall(cmd);
+ GenKillWeight/*!*/ w2 = getSummary(cmd);
+ GenKillWeight/*!*/ w3 = getWeightAfterCall(cmd);
+ Contract.Assert(w1 != null);
+ Contract.Assert(w2 != null);
+ Contract.Assert(w3 != null);
+ return GenKillWeight.extend(w1, GenKillWeight.extend(w2, w3));
+ }
+
+ private static GenKillWeight getWeight(Cmd cmd, Implementation impl, Program prog) {
+ Contract.Requires(cmd != null);
+ Contract.Ensures(Contract.Result<GenKillWeight>() != null);
+
+ if (weightCache.ContainsKey(cmd))
+ return weightCache[cmd];
+
+ HashSet<Variable/*!*/>/*!*/ gen = new HashSet<Variable/*!*/>();
+ HashSet<Variable/*!*/>/*!*/ kill = new HashSet<Variable/*!*/>();
+ GenKillWeight/*!*/ ret;
+
+ if (cmd is AssignCmd) {
+ AssignCmd/*!*/ assignCmd = (AssignCmd)cmd;
+ Contract.Assert(cmd != null);
+ // I must first iterate over all the targets and remove the live ones.
+ // After the removals are done, I must add the variables referred on
+ // the right side of the removed targets
+ foreach (AssignLhs/*!*/ lhs in assignCmd.Lhss) {
+ Contract.Assert(lhs != null);
+ Variable var = lhs.DeepAssignedVariable;
+ if (var != null) {
+ if (lhs is SimpleAssignLhs) {
+ // we should only remove non-map target variables because there is an implicit
+ // read of a map variable in an assignment to it
+ kill.Add(var);
+ }
+ }
+ }
+ int index = 0;
+ foreach (Expr/*!*/ expr in assignCmd.Rhss) {
+ Contract.Assert(expr != null);
+ VariableCollector/*!*/ collector = new VariableCollector();
+ collector.Visit(expr);
+ gen.UnionWith(collector.usedVars);
+ AssignLhs lhs = assignCmd.Lhss[index];
+ if (lhs is MapAssignLhs) {
+ // If the target is a map, then all indices are also read
+ MapAssignLhs malhs = (MapAssignLhs)lhs;
+ foreach (Expr e in malhs.Indexes) {
+ VariableCollector/*!*/ c = new VariableCollector();
+ c.Visit(e);
+ gen.UnionWith(c.usedVars);
+ }
+ }
+ index++;
+ }
+ ret = new GenKillWeight(gen, kill);
+ } else if (cmd is HavocCmd) {
+ HavocCmd/*!*/ havocCmd = (HavocCmd)cce.NonNull(cmd);
+ foreach (IdentifierExpr/*!*/ expr in havocCmd.Vars) {
+ Contract.Assert(expr != null);
+ if (expr.Decl != null) {
+ kill.Add(expr.Decl);
+ }
+ }
+ ret = new GenKillWeight(gen, kill);
+ } else if (cmd is PredicateCmd) {
+ Contract.Assert((cmd is AssertCmd || cmd is AssumeCmd));
+ PredicateCmd/*!*/ predicateCmd = (PredicateCmd)cce.NonNull(cmd);
+ if (predicateCmd.Expr is LiteralExpr && prog != null && impl != null) {
+ LiteralExpr le = (LiteralExpr)predicateCmd.Expr;
+ if (le.IsFalse) {
+ var globals = prog.GlobalVariables;
+ Contract.Assert(cce.NonNullElements(globals));
+ foreach (Variable/*!*/ v in globals) {
+ Contract.Assert(v != null);
+ kill.Add(v);
+ }
+ foreach (Variable/*!*/ v in impl.LocVars) {
+ Contract.Assert(v != null);
+ kill.Add(v);
+ }
+ foreach (Variable/*!*/ v in impl.OutParams) {
+ Contract.Assert(v != null);
+ kill.Add(v);
+ }
+ }
+ } else {
+ VariableCollector/*!*/ collector = new VariableCollector();
+ collector.Visit(predicateCmd.Expr);
+ gen.UnionWith(collector.usedVars);
+ }
+ ret = new GenKillWeight(gen, kill);
+ } else if (cmd is CommentCmd) {
+ ret = new GenKillWeight(gen, kill);
+ // comments are just for debugging and don't affect verification
+ } else if (cmd is SugaredCmd) {
+ SugaredCmd/*!*/ sugCmd = (SugaredCmd)cmd;
+ Contract.Assert(sugCmd != null);
+ ret = getWeight(sugCmd.Desugaring, impl, prog);
+ } else if (cmd is StateCmd) {
+ StateCmd/*!*/ stCmd = (StateCmd)cmd;
+ Contract.Assert(stCmd != null);
+ List<Cmd>/*!*/ cmds = stCmd.Cmds;
+ Contract.Assert(cmds != null);
+ int len = cmds.Count;
+ ret = GenKillWeight.one();
+ for (int i = len - 1; i >= 0; i--) {
+ GenKillWeight/*!*/ w = getWeight(cmds[i], impl, prog);
+ Contract.Assert(w != null);
+ ret = GenKillWeight.extend(w, ret);
+ }
+ foreach (Variable/*!*/ v in stCmd.Locals) {
+ Contract.Assert(v != null);
+ kill.Add(v);
+ }
+ ret = GenKillWeight.extend(new GenKillWeight(gen, kill), ret);
+ } else {
+ {
+ Contract.Assert(false);
+ throw new cce.UnreachableException();
+ }
+ }
+
+ weightCache[cmd] = ret;
+ return ret;
+ }
+
+ static Dictionary<Cmd/*!*/, GenKillWeight/*!*/>/*!*/ weightCacheAfterCall = new Dictionary<Cmd/*!*/, GenKillWeight/*!*/>();
+ static Dictionary<Cmd/*!*/, GenKillWeight/*!*/>/*!*/ weightCacheBeforeCall = new Dictionary<Cmd/*!*/, GenKillWeight/*!*/>();
+
+ private static GenKillWeight getWeightAfterCall(Cmd cmd) {
+ Contract.Requires(cmd != null);
+ Contract.Ensures(Contract.Result<GenKillWeight>() != null);
+
+ if (weightCacheAfterCall.ContainsKey(cmd))
+ return weightCacheAfterCall[cmd];
+
+ HashSet<Variable/*!*/>/*!*/ gen = new HashSet<Variable/*!*/>();
+ HashSet<Variable/*!*/>/*!*/ kill = new HashSet<Variable/*!*/>();
+
+ Contract.Assert(cmd is CallCmd);
+ CallCmd/*!*/ ccmd = cce.NonNull((CallCmd)cmd);
+
+ foreach (IdentifierExpr/*!*/ ie in ccmd.Outs) {
+ Contract.Assert(ie != null);
+ if (ie.Decl != null)
+ kill.Add(ie.Decl);
+ }
+
+ // Variables in ensures are considered as "read"
+ foreach (Ensures/*!*/ re in cce.NonNull(ccmd.Proc).Ensures) {
+ Contract.Assert(re != null);
+ VariableCollector/*!*/ collector = new VariableCollector();
+ collector.Visit(re.Condition);
+ foreach (Variable/*!*/ v in collector.usedVars) {
+ Contract.Assert(v != null);
+ if (v is GlobalVariable) {
+ gen.Add(v);
+ }
+ }
+ }
+
+ GenKillWeight/*!*/ ret = new GenKillWeight(gen, kill);
+ Contract.Assert(ret != null);
+ weightCacheAfterCall[cmd] = ret;
+ return ret;
+ }
+
+ private static GenKillWeight getWeightBeforeCall(Cmd cmd) {
+ Contract.Requires(cmd != null);
+ Contract.Ensures(Contract.Result<GenKillWeight>() != null);
+ Contract.Assert((cmd is CallCmd));
+ if (weightCacheBeforeCall.ContainsKey(cmd))
+ return weightCacheBeforeCall[cmd];
+
+ HashSet<Variable/*!*/>/*!*/ gen = new HashSet<Variable/*!*/>();
+ HashSet<Variable/*!*/>/*!*/ kill = new HashSet<Variable/*!*/>();
+ CallCmd/*!*/ ccmd = cce.NonNull((CallCmd/*!*/)cmd);
+
+ foreach (Expr/*!*/ expr in ccmd.Ins) {
+ Contract.Assert(expr != null);
+ VariableCollector/*!*/ collector = new VariableCollector();
+ collector.Visit(expr);
+ gen.UnionWith(collector.usedVars);
+ }
+
+ Contract.Assert(ccmd.Proc != null);
+
+ // Variables in requires are considered as "read"
+ foreach (Requires/*!*/ re in ccmd.Proc.Requires) {
+ Contract.Assert(re != null);
+ VariableCollector/*!*/ collector = new VariableCollector();
+ collector.Visit(re.Condition);
+ foreach (Variable/*!*/ v in collector.usedVars) {
+ Contract.Assert(v != null);
+ if (v is GlobalVariable) {
+ gen.Add(v);
+ }
+ }
+ }
+
+ // Old variables in ensures are considered as "read"
+ foreach (Ensures/*!*/ re in ccmd.Proc.Ensures) {
+ Contract.Assert(re != null);
+ VariableCollector/*!*/ collector = new VariableCollector();
+ collector.Visit(re.Condition);
+ foreach (Variable/*!*/ v in collector.oldVarsUsed) {
+ Contract.Assert(v != null);
+ if (v is GlobalVariable) {
+ gen.Add(v);
+ }
+ }
+ }
+
+ GenKillWeight/*!*/ ret = new GenKillWeight(gen, kill);
+ Contract.Assert(ret != null);
+ weightCacheAfterCall[cmd] = ret;
+ return ret;
+ }
+ }
+
+ public class TokenEliminator : ReadOnlyVisitor
+ {
+ public int TokenCount = 0;
+ public override Expr VisitExpr(Expr node)
+ {
+ node.tok = Token.NoToken;
+ TokenCount++;
+ return base.VisitExpr(node);
+ }
+ public override Variable VisitVariable(Variable node)
+ {
+ node.tok = Token.NoToken;
+ TokenCount++;
+ return base.VisitVariable(node);
+ }
+ public override Function VisitFunction(Function node)
+ {
+ node.tok = Token.NoToken;
+ TokenCount++;
+ return base.VisitFunction(node);
+ }
+ public override Implementation VisitImplementation(Implementation node)
+ {
+ node.tok = Token.NoToken;
+ TokenCount++;
+ return base.VisitImplementation(node);
+ }
+ public override Procedure VisitProcedure(Procedure node)
+ {
+ node.tok = Token.NoToken;
+ TokenCount++;
+ return base.VisitProcedure(node);
+ }
+ public override Axiom VisitAxiom(Axiom node)
+ {
+ node.tok = Token.NoToken;
+ TokenCount++;
+ return base.VisitAxiom(node);
+ }
+ public override Cmd VisitAssignCmd(AssignCmd node)
+ {
+ node.tok = Token.NoToken;
+ TokenCount++;
+ return base.VisitAssignCmd(node);
+ }
+ public override Cmd VisitAssumeCmd(AssumeCmd node)
+ {
+ node.tok = Token.NoToken;
+ TokenCount++;
+ return base.VisitAssumeCmd(node);
+ }
+ public override Cmd VisitHavocCmd(HavocCmd node)
+ {
+ node.tok = Token.NoToken;
+ TokenCount++;
+ return base.VisitHavocCmd(node);
+ }
+ public override Constant VisitConstant(Constant node)
+ {
+ node.tok = Token.NoToken;
+ TokenCount++;
+ return base.VisitConstant(node);
+ }
+ public override TransferCmd VisitTransferCmd(TransferCmd node)
+ {
+ node.tok = Token.NoToken;
+ TokenCount++;
+ return base.VisitTransferCmd(node);
+ }
+ public override Block VisitBlock(Block node)
+ {
+ node.tok = Token.NoToken;
+ TokenCount++;
+ return base.VisitBlock(node);
+ }
+ }
} \ No newline at end of file
diff --git a/Source/Core/Duplicator.cs b/Source/Core/Duplicator.cs
index 181b80a1..bbc7e0ad 100644
--- a/Source/Core/Duplicator.cs
+++ b/Source/Core/Duplicator.cs
@@ -1,794 +1,829 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-//---------------------------------------------------------------------------------------------
-// BoogiePL - Duplicator.cs
-//---------------------------------------------------------------------------------------------
-
-using System.Collections;
-using System.Collections.Generic;
-using System.Diagnostics.Contracts;
-using System.Linq;
-
-namespace Microsoft.Boogie {
- public class Duplicator : StandardVisitor {
- // This is used to ensure that Procedures get duplicated only once
- // and that Implementation.Proc is resolved to the correct duplicated
- // Procedure.
- private Dictionary<Procedure,Procedure> OldToNewProcedureMap = null;
-
- public override Absy Visit(Absy node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Absy>() != null);
- node = base.Visit(node);
- return node;
- }
-
- public override Cmd VisitAssertCmd(AssertCmd node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- return base.VisitAssertCmd((AssertCmd)node.Clone());
- }
- public override Cmd VisitAssertEnsuresCmd(AssertEnsuresCmd node)
- {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- return base.VisitAssertEnsuresCmd((AssertEnsuresCmd)node.Clone());
- }
- public override Cmd VisitAssertRequiresCmd(AssertRequiresCmd node)
- {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- return base.VisitAssertRequiresCmd((AssertRequiresCmd)node.Clone());
- }
- public override Cmd VisitAssignCmd(AssignCmd node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- AssignCmd clone = (AssignCmd)node.Clone();
- clone.Lhss = new List<AssignLhs/*!*/>(clone.Lhss);
- clone.Rhss = new List<Expr/*!*/>(clone.Rhss);
- return base.VisitAssignCmd(clone);
- }
- public override Cmd VisitAssumeCmd(AssumeCmd node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- return base.VisitAssumeCmd((AssumeCmd)node.Clone());
- }
- public override AtomicRE VisitAtomicRE(AtomicRE node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<AtomicRE>() != null);
- return base.VisitAtomicRE((AtomicRE)node.Clone());
- }
- public override Axiom VisitAxiom(Axiom node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Axiom>() != null);
- return base.VisitAxiom((Axiom)node.Clone());
- }
- public override Type VisitBasicType(BasicType node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- // do /not/ clone the type recursively
- return (BasicType)node.Clone();
- }
- public override Block VisitBlock(Block node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Block>() != null);
- return base.VisitBlock((Block) node.Clone());
- }
- public override Expr VisitBvConcatExpr (BvConcatExpr node) {
- Contract.Ensures(Contract.Result<Expr>() != null);
- return base.VisitBvConcatExpr((BvConcatExpr) node.Clone());
- }
- public override Expr VisitBvExtractExpr(BvExtractExpr node) {
- Contract.Ensures(Contract.Result<Expr>() != null);
- return base.VisitBvExtractExpr((BvExtractExpr) node.Clone());
- }
- public override Expr VisitCodeExpr(CodeExpr node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- CodeExpr clone = (CodeExpr)base.VisitCodeExpr((CodeExpr)node.Clone());
- // Before returning, fix up the resolved goto targets
- Contract.Assert(node.Blocks.Count == clone.Blocks.Count);
- Dictionary<Block, Block> subst = new Dictionary<Block, Block>();
- for (int i = 0; i < node.Blocks.Count; i++) {
- subst.Add(node.Blocks[i], clone.Blocks[i]);
- }
- foreach (Block/*!*/ b in clone.Blocks) {
- Contract.Assert(b != null);
- GotoCmd g = b.TransferCmd as GotoCmd;
- if (g != null) {
- List<Block> targets = new List<Block>();
- foreach (Block t in cce.NonNull(g.labelTargets)) {
- Block nt = subst[t];
- targets.Add(nt);
- }
- g.labelTargets = targets;
- }
- }
- return clone;
- }
- public override List<Block> VisitBlockSeq(List<Block> blockSeq) {
- //Contract.Requires(blockSeq != null);
- Contract.Ensures(Contract.Result<List<Block>>() != null);
- return base.VisitBlockSeq(new List<Block>(blockSeq));
- }
- public override List<Block/*!*/>/*!*/ VisitBlockList(List<Block/*!*/>/*!*/ blocks) {
- //Contract.Requires(cce.NonNullElements(blocks));
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<Block>>()));
- return base.VisitBlockList(new List<Block/*!*/>(blocks));
- }
- public override BoundVariable VisitBoundVariable(BoundVariable node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<BoundVariable>() != null);
- return base.VisitBoundVariable((BoundVariable)node.Clone());
- }
- public override Type VisitBvType(BvType node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- // do /not/ clone the type recursively
- return (BvType)node.Clone();
- }
- public override Cmd VisitCallCmd(CallCmd node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- CallCmd clone = (CallCmd)node.Clone();
- Contract.Assert(clone != null);
- clone.Ins = new List<Expr>(clone.Ins);
- clone.Outs = new List<IdentifierExpr>(clone.Outs);
- return base.VisitCallCmd(clone);
- }
- public override Choice VisitChoice(Choice node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Choice>() != null);
- return base.VisitChoice((Choice)node.Clone());
- }
- public override List<Cmd> VisitCmdSeq(List<Cmd> cmdSeq) {
- //Contract.Requires(cmdSeq != null);
- Contract.Ensures(Contract.Result<List<Cmd>>() != null);
- return base.VisitCmdSeq(new List<Cmd>(cmdSeq));
- }
- public override Constant VisitConstant(Constant node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Constant>() != null);
- return base.VisitConstant((Constant)node.Clone());
- }
- public override CtorType VisitCtorType(CtorType node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<CtorType>() != null);
- // do /not/ clone the type recursively
- return (CtorType)node.Clone();
- }
- public override Declaration VisitDeclaration(Declaration node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Declaration>() != null);
- return base.VisitDeclaration((Declaration)node.Clone());
- }
- public override List<Declaration/*!*/>/*!*/ VisitDeclarationList(List<Declaration/*!*/>/*!*/ declarationList) {
- //Contract.Requires(cce.NonNullElements(declarationList));
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<Declaration>>()));
-
- // For Implementation.Proc to resolve correctly to duplicated Procedures
- // we need to visit the procedures first
- for (int i = 0, n = declarationList.Count; i < n; i++) {
- if (!( declarationList[i] is Procedure ))
- continue;
-
- declarationList[i] = cce.NonNull((Declaration) this.Visit(declarationList[i]));
- }
-
- // Now visit everything else
- for (int i = 0, n = declarationList.Count; i < n; i++) {
- if (declarationList[i] is Procedure)
- continue;
-
- declarationList[i] = cce.NonNull((Declaration) this.Visit(declarationList[i]));
- }
- return declarationList;
- }
- public override DeclWithFormals VisitDeclWithFormals(DeclWithFormals node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<DeclWithFormals>() != null);
- return base.VisitDeclWithFormals((DeclWithFormals)node.Clone());
- }
- public override Ensures VisitEnsures(Ensures node)
- {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Ensures>() != null);
- return base.VisitEnsures((Ensures)node.Clone());
- }
- public override List<Ensures> VisitEnsuresSeq(List<Ensures> ensuresSeq)
- {
- //Contract.Requires(ensuresSeq != null);
- Contract.Ensures(Contract.Result<List<Ensures>>() != null);
- return base.VisitEnsuresSeq(new List<Ensures>(ensuresSeq));
- }
- public override Expr VisitExistsExpr(ExistsExpr node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- return base.VisitExistsExpr((ExistsExpr)node.Clone());
- }
- public override Expr VisitExpr(Expr node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- return base.VisitExpr((Expr)node.Clone());
- }
- public override IList<Expr> VisitExprSeq(IList<Expr> list) {
- //Contract.Requires(list != null);
- Contract.Ensures(Contract.Result<IList<Expr>>() != null);
- return base.VisitExprSeq(new List<Expr>(list));
- }
- public override Expr VisitForallExpr(ForallExpr node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- return base.VisitForallExpr((ForallExpr)node.Clone());
- }
- public override Formal VisitFormal(Formal node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Formal>() != null);
- return base.VisitFormal((Formal)node.Clone());
- }
- public override Function VisitFunction(Function node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Function>() != null);
- return base.VisitFunction((Function)node.Clone());
- }
- public override GlobalVariable VisitGlobalVariable(GlobalVariable node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<GlobalVariable>() != null);
- return base.VisitGlobalVariable((GlobalVariable)node.Clone());
- }
- public override GotoCmd VisitGotoCmd(GotoCmd node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<GotoCmd>() != null);
- // NOTE: This doesn't duplicate the labelTarget basic blocks
- // or resolve them to the new blocks
- // VisitImplementation() and VisitBlock() handle this
- return base.VisitGotoCmd( (GotoCmd)node.Clone());
- }
- public override Cmd VisitHavocCmd(HavocCmd node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- return base.VisitHavocCmd((HavocCmd)node.Clone());
- }
- public override Expr VisitIdentifierExpr(IdentifierExpr node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- return base.VisitIdentifierExpr((IdentifierExpr)node.Clone());
- }
- public override List<IdentifierExpr> VisitIdentifierExprSeq(List<IdentifierExpr> identifierExprSeq) {
- //Contract.Requires(identifierExprSeq != null);
- Contract.Ensures(Contract.Result<List<IdentifierExpr>>() != null);
- return base.VisitIdentifierExprSeq(new List<IdentifierExpr>(identifierExprSeq));
- }
- public override Implementation VisitImplementation(Implementation node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Implementation>() != null);
- var impl = base.VisitImplementation((Implementation)node.Clone());
- var blockDuplicationMapping = new Dictionary<Block, Block>();
-
- // Compute the mapping between the blocks of the old implementation (node)
- // and the new implementation (impl).
- foreach (var blockPair in node.Blocks.Zip(impl.Blocks)) {
- blockDuplicationMapping.Add(blockPair.Item1, blockPair.Item2);
- }
-
- // The GotoCmds and blocks have now been duplicated.
- // Resolve GotoCmd targets to the duplicated blocks
- foreach (GotoCmd gotoCmd in impl.Blocks.Select( bb => bb.TransferCmd).OfType<GotoCmd>()) {
- var newLabelTargets = new List<Block>();
- var newLabelNames = new List<string>();
- for (int index = 0; index < gotoCmd.labelTargets.Count; ++index) {
- var newBlock = blockDuplicationMapping[gotoCmd.labelTargets[index]];
- newLabelTargets.Add(newBlock);
- newLabelNames.Add(newBlock.Label);
- }
- gotoCmd.labelTargets = newLabelTargets;
- gotoCmd.labelNames = newLabelNames;
- }
-
- return impl;
- }
- public override Expr VisitLiteralExpr(LiteralExpr node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- return base.VisitLiteralExpr((LiteralExpr)node.Clone());
- }
- public override LocalVariable VisitLocalVariable(LocalVariable node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<LocalVariable>() != null);
- return base.VisitLocalVariable((LocalVariable)node.Clone());
- }
- public override AssignLhs VisitMapAssignLhs(MapAssignLhs node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<AssignLhs>() != null);
- MapAssignLhs clone = (MapAssignLhs)node.Clone();
- clone.Indexes = new List<Expr/*!*/>(clone.Indexes);
- return base.VisitMapAssignLhs(clone);
- }
- public override MapType VisitMapType(MapType node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<MapType>() != null);
- // do /not/ clone the type recursively
- return (MapType)node.Clone();
- }
- public override Expr VisitNAryExpr(NAryExpr node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- return base.VisitNAryExpr((NAryExpr)node.Clone());
- }
- public override Expr VisitOldExpr(OldExpr node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- return base.VisitOldExpr((OldExpr)node.Clone());
- }
- public override Cmd VisitParCallCmd(ParCallCmd node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- ParCallCmd clone = (ParCallCmd)node.Clone();
- Contract.Assert(clone != null);
- clone.CallCmds = new List<CallCmd>(node.CallCmds);
- return base.VisitParCallCmd(clone);
- }
- public override Procedure VisitProcedure(Procedure node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Procedure>() != null);
- Procedure newProcedure = null;
- if (OldToNewProcedureMap != null && OldToNewProcedureMap.ContainsKey(node)) {
- newProcedure = OldToNewProcedureMap[node];
- } else {
- newProcedure = base.VisitProcedure((Procedure) node.Clone());
- if (OldToNewProcedureMap != null)
- OldToNewProcedureMap[node] = newProcedure;
- }
- return newProcedure;
- }
- public override Program VisitProgram(Program node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Program>() != null);
-
- // If cloning an entire program we need to ensure that
- // Implementation.Proc gets resolved to the right Procedure
- // (i.e. we don't duplicate Procedure twice) and CallCmds
- // call the right Procedure.
- // The map below is used to achieve this.
- OldToNewProcedureMap = new Dictionary<Procedure, Procedure>();
- var newProgram = base.VisitProgram((Program)node.Clone());
-
- // We need to make sure that CallCmds get resolved to call Procedures we duplicated
- // instead of pointing to procedures in the old program
- var callCmds = newProgram.Blocks().SelectMany(b => b.Cmds).OfType<CallCmd>();
- foreach (var callCmd in callCmds) {
- callCmd.Proc = OldToNewProcedureMap[callCmd.Proc];
- }
-
- OldToNewProcedureMap = null; // This Visitor could be used for other things later so remove the map.
- return newProgram;
- }
- public override QKeyValue VisitQKeyValue(QKeyValue node) {
- //Contract.Requires(node != null);
- var newParams = new List<object>();
- foreach (var o in node.Params) {
- var e = o as Expr;
- if (e == null) {
- newParams.Add(o);
- } else {
- newParams.Add((Expr)this.Visit(e));
- }
- }
- QKeyValue next = node.Next == null ? null : (QKeyValue)this.Visit(node.Next);
- return new QKeyValue(node.tok, node.Key, newParams, next);
- }
- public override BinderExpr VisitBinderExpr(BinderExpr node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<BinderExpr>() != null);
- return base.VisitBinderExpr((BinderExpr)node.Clone());
- }
- public override Requires VisitRequires(Requires node)
- {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Requires>() != null);
- return base.VisitRequires((Requires)node.Clone());
- }
- public override List<Requires> VisitRequiresSeq(List<Requires> requiresSeq)
- {
- //Contract.Requires(requiresSeq != null);
- Contract.Ensures(Contract.Result<List<Requires>>() != null);
- return base.VisitRequiresSeq(new List<Requires>(requiresSeq));
- }
- public override Cmd VisitRE(RE node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- return base.VisitRE((RE)node.Clone());
- }
- public override List<RE> VisitRESeq(List<RE> reSeq) {
- //Contract.Requires(reSeq != null);
- Contract.Ensures(Contract.Result<List<RE>>() != null);
- return base.VisitRESeq(new List<RE>(reSeq));
- }
- public override ReturnCmd VisitReturnCmd(ReturnCmd node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<ReturnCmd>() != null);
- return base.VisitReturnCmd((ReturnCmd)node.Clone());
- }
- public override ReturnExprCmd VisitReturnExprCmd(ReturnExprCmd node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<ReturnExprCmd>() != null);
- return base.VisitReturnExprCmd((ReturnExprCmd)node.Clone());
- }
- public override Sequential VisitSequential(Sequential node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Sequential>() != null);
- return base.VisitSequential((Sequential)node.Clone());
- }
- public override AssignLhs VisitSimpleAssignLhs(SimpleAssignLhs node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<AssignLhs>() != null);
- return base.VisitSimpleAssignLhs((SimpleAssignLhs)node.Clone());
- }
- public override Cmd VisitStateCmd(StateCmd node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- return base.VisitStateCmd((StateCmd)node.Clone());
- }
- public override TransferCmd VisitTransferCmd(TransferCmd node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<TransferCmd>() != null);
- return base.VisitTransferCmd((TransferCmd)node.Clone());
- }
- public override Trigger VisitTrigger(Trigger node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Trigger>() != null);
- return base.VisitTrigger((Trigger)node.Clone());
- }
- public override Type VisitType(Type node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- // do /not/ clone the type recursively
- return (Type)node.Clone();
- }
- public override TypedIdent VisitTypedIdent(TypedIdent node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<TypedIdent>() != null);
- return base.VisitTypedIdent((TypedIdent)node.Clone());
- }
- public override Variable VisitVariable(Variable node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Variable>() != null);
- return node;
- }
- public override List<Variable> VisitVariableSeq(List<Variable> variableSeq) {
- //Contract.Requires(variableSeq != null);
- Contract.Ensures(Contract.Result<List<Variable>>() != null);
- return base.VisitVariableSeq(new List<Variable>(variableSeq));
- }
- public override YieldCmd VisitYieldCmd(YieldCmd node)
- {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<YieldCmd>() != null);
- return base.VisitYieldCmd((YieldCmd)node.Clone());
- }
- }
-
-
- #region A duplicator that also does substitutions for a set of variables
- /// <summary>
- /// A substitution is a partial mapping from Variables to Exprs.
- /// </summary>
- public delegate Expr/*?*/ Substitution(Variable/*!*/ v);
-
- public static class Substituter {
- public static Substitution SubstitutionFromHashtable(Dictionary<Variable, Expr> map, bool fallBackOnName = false, Procedure proc = null)
- {
- Contract.Requires(map != null);
- Contract.Ensures(Contract.Result<Substitution>() != null);
- // TODO: With Whidbey, could use anonymous functions.
- return new Substitution(new CreateSubstitutionClosure(map, fallBackOnName, proc).Method);
- }
- private sealed class CreateSubstitutionClosure {
- Dictionary<Variable /*!*/, Expr /*!*/>/*!*/ map;
- Dictionary<string /*!*/, Expr /*!*/>/*!*/ nameMap;
- Procedure proc;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(map != null);
- }
-
- static string UniqueName(Variable variable, Procedure proc)
- {
- // TODO(wuestholz): Maybe we should define structural equality for variables instead.
- var scope = "#global_scope#";
- if (proc != null && !(variable is GlobalVariable || variable is Constant))
- {
- scope = proc.Name;
- }
- return string.Format("{0}.{1}", scope, variable.Name);
- }
-
- public CreateSubstitutionClosure(Dictionary<Variable, Expr> map, bool fallBackOnName = false, Procedure proc = null)
- : base() {
- Contract.Requires(map != null);
- this.map = map;
- this.proc = proc;
- if (fallBackOnName && proc != null)
- {
- this.nameMap = map.ToDictionary(kv => UniqueName(kv.Key, proc), kv => kv.Value);
- }
- }
- public Expr/*?*/ Method(Variable v) {
- Contract.Requires(v != null);
- if(map.ContainsKey(v)) {
- return map[v];
- }
- Expr e;
- if (nameMap != null && proc != null && nameMap.TryGetValue(UniqueName(v, proc), out e))
- {
- return e;
- }
- return null;
- }
- }
-
- // ----------------------------- Substitutions for Expr -------------------------------
-
- /// <summary>
- /// Apply a substitution to an expression. Any variables not in domain(subst)
- /// is not changed. The substitutions apply within the "old", but the "old"
- /// expression remains.
- /// </summary>
- public static Expr Apply(Substitution subst, Expr expr) {
- Contract.Requires(subst != null);
- Contract.Requires(expr != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- return (Expr)new NormalSubstituter(subst).Visit(expr);
- }
-
- /// <summary>
- /// Apply a substitution to an expression.
- /// Outside "old" expressions, the substitution "always" is applied; any variable not in
- /// domain(always) is not changed. Inside "old" expressions, apply map "forOld" to
- /// variables in domain(forOld), apply map "always" to variables in
- /// domain(always)-domain(forOld), and leave variable unchanged otherwise.
- /// </summary>
- public static Expr Apply(Substitution always, Substitution forold, Expr expr) {
- Contract.Requires(always != null);
- Contract.Requires(forold != null);
- Contract.Requires(expr != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- return (Expr)new NormalSubstituter(always, forold).Visit(expr);
- }
-
- /// <summary>
- /// Apply a substitution to an expression replacing "old" expressions.
- /// Outside "old" expressions, the substitution "always" is applied; any variable not in
- /// domain(always) is not changed. Inside "old" expressions, apply map "forOld" to
- /// variables in domain(forOld), apply map "always" to variables in
- /// domain(always)-domain(forOld), and leave variable unchanged otherwise.
- /// </summary>
- public static Expr ApplyReplacingOldExprs(Substitution always, Substitution forOld, Expr expr) {
- Contract.Requires(always != null);
- Contract.Requires(forOld != null);
- Contract.Requires(expr != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- return (Expr)new ReplacingOldSubstituter(always, forOld).Visit(expr);
- }
-
- public static Expr FunctionCallReresolvingApplyReplacingOldExprs(Substitution always, Substitution forOld, Expr expr, Program program)
- {
- Contract.Requires(always != null);
- Contract.Requires(forOld != null);
- Contract.Requires(expr != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- return (Expr)new FunctionCallReresolvingReplacingOldSubstituter(program, always, forOld).Visit(expr);
- }
-
- // ----------------------------- Substitutions for Cmd -------------------------------
-
- /// <summary>
- /// Apply a substitution to a command. Any variables not in domain(subst)
- /// is not changed. The substitutions apply within the "old", but the "old"
- /// expression remains.
- /// </summary>
- public static Cmd Apply(Substitution subst, Cmd cmd) {
- Contract.Requires(subst != null);
- Contract.Requires(cmd != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- return (Cmd)new NormalSubstituter(subst).Visit(cmd);
- }
-
- /// <summary>
- /// Apply a substitution to a command.
- /// Outside "old" expressions, the substitution "always" is applied; any variable not in
- /// domain(always) is not changed. Inside "old" expressions, apply map "forOld" to
- /// variables in domain(forOld), apply map "always" to variables in
- /// domain(always)-domain(forOld), and leave variable unchanged otherwise.
- /// </summary>
- public static Cmd Apply(Substitution always, Substitution forOld, Cmd cmd)
- {
- Contract.Requires(always != null);
- Contract.Requires(forOld != null);
- Contract.Requires(cmd != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- return (Cmd)new NormalSubstituter(always, forOld).Visit(cmd);
- }
-
- /// <summary>
- /// Apply a substitution to a command replacing "old" expressions.
- /// Outside "old" expressions, the substitution "always" is applied; any variable not in
- /// domain(always) is not changed. Inside "old" expressions, apply map "forOld" to
- /// variables in domain(forOld), apply map "always" to variables in
- /// domain(always)-domain(forOld), and leave variable unchanged otherwise.
- /// </summary>
- public static Cmd ApplyReplacingOldExprs(Substitution always, Substitution forOld, Cmd cmd) {
- Contract.Requires(always != null);
- Contract.Requires(forOld != null);
- Contract.Requires(cmd != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- return (Cmd)new ReplacingOldSubstituter(always, forOld).Visit(cmd);
- }
-
- // ----------------------------- Substitutions for QKeyValue -------------------------------
-
- /// <summary>
- /// Apply a substitution to a list of attributes. Any variables not in domain(subst)
- /// is not changed. The substitutions apply within the "old", but the "old"
- /// expression remains.
- /// </summary>
- public static QKeyValue Apply(Substitution subst, QKeyValue kv) {
- Contract.Requires(subst != null);
- if (kv == null) {
- return null;
- } else {
- return (QKeyValue)new NormalSubstituter(subst).Visit(kv);
- }
- }
-
- /// <summary>
- /// Apply a substitution to a list of attributes replacing "old" expressions.
- /// For a further description, see "ApplyReplacingOldExprs" above for Expr.
- /// </summary>
- public static QKeyValue ApplyReplacingOldExprs(Substitution always, Substitution forOld, QKeyValue kv) {
- Contract.Requires(always != null);
- Contract.Requires(forOld != null);
- if (kv == null) {
- return null;
- } else {
- return (QKeyValue)new ReplacingOldSubstituter(always, forOld).Visit(kv);
- }
- }
-
- // ------------------------------------------------------------
-
- private sealed class NormalSubstituter : Duplicator
- {
- private readonly Substitution/*!*/ always;
- private readonly Substitution/*!*/ forold;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(always != null);
- Contract.Invariant(forold != null);
- }
-
- public NormalSubstituter(Substitution subst)
- : base() {
- Contract.Requires(subst != null);
- this.always = subst;
- this.forold = Substituter.SubstitutionFromHashtable(new Dictionary<Variable, Expr>());
- }
-
- public NormalSubstituter(Substitution subst, Substitution forold)
- : base()
- {
- Contract.Requires(subst != null);
- this.always = subst;
- this.forold = forold;
- }
-
- private bool insideOldExpr = false;
-
- public override Expr VisitIdentifierExpr(IdentifierExpr node)
- {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- Expr/*?*/ e = null;
-
- if (insideOldExpr)
- {
- e = forold(cce.NonNull(node.Decl));
- }
-
- if (e == null)
- {
- e = always(cce.NonNull(node.Decl));
- }
-
- return e == null ? base.VisitIdentifierExpr(node) : e;
- }
-
- public override Expr VisitOldExpr(OldExpr node)
- {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- bool previouslyInOld = insideOldExpr;
- insideOldExpr = true;
- Expr/*!*/ e = (Expr/*!*/)cce.NonNull(this.Visit(node.Expr));
- insideOldExpr = previouslyInOld;
- return new OldExpr(node.tok, e);
- }
- }
-
- private sealed class FunctionCallReresolvingReplacingOldSubstituter : ReplacingOldSubstituter
- {
- readonly Program Program;
-
- public FunctionCallReresolvingReplacingOldSubstituter(Program program, Substitution always, Substitution forold)
- : base(always, forold)
- {
- Program = program;
- }
-
- public override Expr VisitNAryExpr(NAryExpr node)
- {
- var result = base.VisitNAryExpr(node);
- var nAryExpr = result as NAryExpr;
- if (nAryExpr != null)
- {
- var funCall = nAryExpr.Fun as FunctionCall;
- if (funCall != null)
- {
- funCall.Func = Program.FindFunction(funCall.FunctionName);
- }
- }
- return result;
- }
- }
-
- private class ReplacingOldSubstituter : Duplicator {
- private readonly Substitution/*!*/ always;
- private readonly Substitution/*!*/ forold;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(always != null);
- Contract.Invariant(forold != null);
- }
-
- public ReplacingOldSubstituter(Substitution always, Substitution forold)
- : base() {
- Contract.Requires(forold != null);
- Contract.Requires(always != null);
- this.always = always;
- this.forold = forold;
- }
-
- private bool insideOldExpr = false;
-
- public override Expr VisitIdentifierExpr(IdentifierExpr node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- Expr/*?*/ e = null;
-
- if (insideOldExpr) {
- e = forold(cce.NonNull(node.Decl));
- }
-
- if (e == null) {
- e = always(cce.NonNull(node.Decl));
- }
-
- return e == null ? base.VisitIdentifierExpr(node) : e;
- }
-
- public override Expr VisitOldExpr(OldExpr node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- bool previouslyInOld = insideOldExpr;
- insideOldExpr = true;
- Expr/*!*/ e = (Expr/*!*/)cce.NonNull(this.Visit(node.Expr));
- insideOldExpr = previouslyInOld;
- return e;
- }
- }
- }
- #endregion
-}
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------------
+// BoogiePL - Duplicator.cs
+//---------------------------------------------------------------------------------------------
+
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Linq;
+
+namespace Microsoft.Boogie {
+ public class Duplicator : StandardVisitor {
+ // This is used to ensure that Procedures get duplicated only once
+ // and that Implementation.Proc is resolved to the correct duplicated
+ // Procedure.
+ private Dictionary<Procedure,Procedure> OldToNewProcedureMap = null;
+
+ public override Absy Visit(Absy node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Absy>() != null);
+ node = base.Visit(node);
+ return node;
+ }
+
+ public override Cmd VisitAssertCmd(AssertCmd node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ return base.VisitAssertCmd((AssertCmd)node.Clone());
+ }
+ public override Cmd VisitAssertEnsuresCmd(AssertEnsuresCmd node)
+ {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ return base.VisitAssertEnsuresCmd((AssertEnsuresCmd)node.Clone());
+ }
+ public override Cmd VisitAssertRequiresCmd(AssertRequiresCmd node)
+ {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ return base.VisitAssertRequiresCmd((AssertRequiresCmd)node.Clone());
+ }
+ public override Cmd VisitAssignCmd(AssignCmd node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ AssignCmd clone = (AssignCmd)node.Clone();
+ clone.Lhss = new List<AssignLhs/*!*/>(clone.Lhss);
+ clone.Rhss = new List<Expr/*!*/>(clone.Rhss);
+ return base.VisitAssignCmd(clone);
+ }
+ public override Cmd VisitAssumeCmd(AssumeCmd node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ return base.VisitAssumeCmd((AssumeCmd)node.Clone());
+ }
+ public override AtomicRE VisitAtomicRE(AtomicRE node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<AtomicRE>() != null);
+ return base.VisitAtomicRE((AtomicRE)node.Clone());
+ }
+ public override Axiom VisitAxiom(Axiom node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Axiom>() != null);
+ return base.VisitAxiom((Axiom)node.Clone());
+ }
+ public override Type VisitBasicType(BasicType node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ // do /not/ clone the type recursively
+ return (BasicType)node.Clone();
+ }
+ public override Block VisitBlock(Block node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Block>() != null);
+ return base.VisitBlock((Block) node.Clone());
+ }
+ public override Expr VisitBvConcatExpr (BvConcatExpr node) {
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ return base.VisitBvConcatExpr((BvConcatExpr) node.Clone());
+ }
+ public override Expr VisitBvExtractExpr(BvExtractExpr node) {
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ return base.VisitBvExtractExpr((BvExtractExpr) node.Clone());
+ }
+ public override Expr VisitCodeExpr(CodeExpr node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ CodeExpr clone = (CodeExpr)base.VisitCodeExpr((CodeExpr)node.Clone());
+ // Before returning, fix up the resolved goto targets
+ Contract.Assert(node.Blocks.Count == clone.Blocks.Count);
+ Dictionary<Block, Block> subst = new Dictionary<Block, Block>();
+ for (int i = 0; i < node.Blocks.Count; i++) {
+ subst.Add(node.Blocks[i], clone.Blocks[i]);
+ }
+ foreach (Block/*!*/ b in clone.Blocks) {
+ Contract.Assert(b != null);
+ GotoCmd g = b.TransferCmd as GotoCmd;
+ if (g != null) {
+ List<Block> targets = new List<Block>();
+ foreach (Block t in cce.NonNull(g.labelTargets)) {
+ Block nt = subst[t];
+ targets.Add(nt);
+ }
+ g.labelTargets = targets;
+ }
+ }
+ return clone;
+ }
+ public override List<Block> VisitBlockSeq(List<Block> blockSeq) {
+ //Contract.Requires(blockSeq != null);
+ Contract.Ensures(Contract.Result<List<Block>>() != null);
+ return base.VisitBlockSeq(new List<Block>(blockSeq));
+ }
+ public override List<Block/*!*/>/*!*/ VisitBlockList(List<Block/*!*/>/*!*/ blocks) {
+ //Contract.Requires(cce.NonNullElements(blocks));
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<Block>>()));
+ return base.VisitBlockList(new List<Block/*!*/>(blocks));
+ }
+ public override BoundVariable VisitBoundVariable(BoundVariable node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<BoundVariable>() != null);
+ return base.VisitBoundVariable((BoundVariable)node.Clone());
+ }
+ public override Type VisitBvType(BvType node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ // do /not/ clone the type recursively
+ return (BvType)node.Clone();
+ }
+ public override Cmd VisitCallCmd(CallCmd node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ CallCmd clone = (CallCmd)node.Clone();
+ Contract.Assert(clone != null);
+ clone.Ins = new List<Expr>(clone.Ins);
+ clone.Outs = new List<IdentifierExpr>(clone.Outs);
+ return base.VisitCallCmd(clone);
+ }
+ public override Choice VisitChoice(Choice node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Choice>() != null);
+ return base.VisitChoice((Choice)node.Clone());
+ }
+ public override List<Cmd> VisitCmdSeq(List<Cmd> cmdSeq) {
+ //Contract.Requires(cmdSeq != null);
+ Contract.Ensures(Contract.Result<List<Cmd>>() != null);
+ return base.VisitCmdSeq(new List<Cmd>(cmdSeq));
+ }
+ public override Constant VisitConstant(Constant node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Constant>() != null);
+ return base.VisitConstant((Constant)node.Clone());
+ }
+ public override CtorType VisitCtorType(CtorType node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<CtorType>() != null);
+ // do /not/ clone the type recursively
+ return (CtorType)node.Clone();
+ }
+ public override Declaration VisitDeclaration(Declaration node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Declaration>() != null);
+ return base.VisitDeclaration((Declaration)node.Clone());
+ }
+ public override List<Declaration/*!*/>/*!*/ VisitDeclarationList(List<Declaration/*!*/>/*!*/ declarationList) {
+ //Contract.Requires(cce.NonNullElements(declarationList));
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<Declaration>>()));
+
+ // For Implementation.Proc to resolve correctly to duplicated Procedures
+ // we need to visit the procedures first
+ for (int i = 0, n = declarationList.Count; i < n; i++) {
+ if (!( declarationList[i] is Procedure ))
+ continue;
+
+ declarationList[i] = cce.NonNull((Declaration) this.Visit(declarationList[i]));
+ }
+
+ // Now visit everything else
+ for (int i = 0, n = declarationList.Count; i < n; i++) {
+ if (declarationList[i] is Procedure)
+ continue;
+
+ declarationList[i] = cce.NonNull((Declaration) this.Visit(declarationList[i]));
+ }
+ return declarationList;
+ }
+ public override DeclWithFormals VisitDeclWithFormals(DeclWithFormals node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<DeclWithFormals>() != null);
+ return base.VisitDeclWithFormals((DeclWithFormals)node.Clone());
+ }
+ public override Ensures VisitEnsures(Ensures node)
+ {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Ensures>() != null);
+ return base.VisitEnsures((Ensures)node.Clone());
+ }
+ public override List<Ensures> VisitEnsuresSeq(List<Ensures> ensuresSeq)
+ {
+ //Contract.Requires(ensuresSeq != null);
+ Contract.Ensures(Contract.Result<List<Ensures>>() != null);
+ return base.VisitEnsuresSeq(new List<Ensures>(ensuresSeq));
+ }
+ public override Expr VisitExistsExpr(ExistsExpr node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ return base.VisitExistsExpr((ExistsExpr)node.Clone());
+ }
+ public override Expr VisitExpr(Expr node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ return base.VisitExpr((Expr)node.Clone());
+ }
+ public override IList<Expr> VisitExprSeq(IList<Expr> list) {
+ //Contract.Requires(list != null);
+ Contract.Ensures(Contract.Result<IList<Expr>>() != null);
+ return base.VisitExprSeq(new List<Expr>(list));
+ }
+ public override Expr VisitForallExpr(ForallExpr node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ return base.VisitForallExpr((ForallExpr)node.Clone());
+ }
+ public override Formal VisitFormal(Formal node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Formal>() != null);
+ return base.VisitFormal((Formal)node.Clone());
+ }
+ public override Function VisitFunction(Function node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Function>() != null);
+ return base.VisitFunction((Function)node.Clone());
+ }
+ public override GlobalVariable VisitGlobalVariable(GlobalVariable node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<GlobalVariable>() != null);
+ return base.VisitGlobalVariable((GlobalVariable)node.Clone());
+ }
+ public override GotoCmd VisitGotoCmd(GotoCmd node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<GotoCmd>() != null);
+ // NOTE: This doesn't duplicate the labelTarget basic blocks
+ // or resolve them to the new blocks
+ // VisitImplementation() and VisitBlock() handle this
+ return base.VisitGotoCmd( (GotoCmd)node.Clone());
+ }
+ public override Cmd VisitHavocCmd(HavocCmd node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ return base.VisitHavocCmd((HavocCmd)node.Clone());
+ }
+ public override Expr VisitIdentifierExpr(IdentifierExpr node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ return base.VisitIdentifierExpr((IdentifierExpr)node.Clone());
+ }
+ public override List<IdentifierExpr> VisitIdentifierExprSeq(List<IdentifierExpr> identifierExprSeq) {
+ //Contract.Requires(identifierExprSeq != null);
+ Contract.Ensures(Contract.Result<List<IdentifierExpr>>() != null);
+ return base.VisitIdentifierExprSeq(new List<IdentifierExpr>(identifierExprSeq));
+ }
+ public override Implementation VisitImplementation(Implementation node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Implementation>() != null);
+ var impl = base.VisitImplementation((Implementation)node.Clone());
+ var blockDuplicationMapping = new Dictionary<Block, Block>();
+
+ // Compute the mapping between the blocks of the old implementation (node)
+ // and the new implementation (impl).
+ foreach (var blockPair in node.Blocks.Zip(impl.Blocks)) {
+ blockDuplicationMapping.Add(blockPair.Item1, blockPair.Item2);
+ }
+
+ // The GotoCmds and blocks have now been duplicated.
+ // Resolve GotoCmd targets to the duplicated blocks
+ foreach (GotoCmd gotoCmd in impl.Blocks.Select( bb => bb.TransferCmd).OfType<GotoCmd>()) {
+ var newLabelTargets = new List<Block>();
+ var newLabelNames = new List<string>();
+ for (int index = 0; index < gotoCmd.labelTargets.Count; ++index) {
+ var newBlock = blockDuplicationMapping[gotoCmd.labelTargets[index]];
+ newLabelTargets.Add(newBlock);
+ newLabelNames.Add(newBlock.Label);
+ }
+ gotoCmd.labelTargets = newLabelTargets;
+ gotoCmd.labelNames = newLabelNames;
+ }
+
+ return impl;
+ }
+ public override Expr VisitLiteralExpr(LiteralExpr node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ return base.VisitLiteralExpr((LiteralExpr)node.Clone());
+ }
+ public override LocalVariable VisitLocalVariable(LocalVariable node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<LocalVariable>() != null);
+ return base.VisitLocalVariable((LocalVariable)node.Clone());
+ }
+ public override AssignLhs VisitMapAssignLhs(MapAssignLhs node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<AssignLhs>() != null);
+ MapAssignLhs clone = (MapAssignLhs)node.Clone();
+ clone.Indexes = new List<Expr/*!*/>(clone.Indexes);
+ return base.VisitMapAssignLhs(clone);
+ }
+ public override MapType VisitMapType(MapType node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<MapType>() != null);
+ // do /not/ clone the type recursively
+ return (MapType)node.Clone();
+ }
+ public override Expr VisitNAryExpr(NAryExpr node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ return base.VisitNAryExpr((NAryExpr)node.Clone());
+ }
+ public override Expr VisitOldExpr(OldExpr node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ return base.VisitOldExpr((OldExpr)node.Clone());
+ }
+ public override Cmd VisitParCallCmd(ParCallCmd node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ ParCallCmd clone = (ParCallCmd)node.Clone();
+ Contract.Assert(clone != null);
+ clone.CallCmds = new List<CallCmd>(node.CallCmds);
+ return base.VisitParCallCmd(clone);
+ }
+ public override Procedure VisitProcedure(Procedure node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Procedure>() != null);
+ Procedure newProcedure = null;
+ if (OldToNewProcedureMap != null && OldToNewProcedureMap.ContainsKey(node)) {
+ newProcedure = OldToNewProcedureMap[node];
+ } else {
+ newProcedure = base.VisitProcedure((Procedure) node.Clone());
+ if (OldToNewProcedureMap != null)
+ OldToNewProcedureMap[node] = newProcedure;
+ }
+ return newProcedure;
+ }
+ public override Program VisitProgram(Program node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Program>() != null);
+
+ // If cloning an entire program we need to ensure that
+ // Implementation.Proc gets resolved to the right Procedure
+ // (i.e. we don't duplicate Procedure twice) and CallCmds
+ // call the right Procedure.
+ // The map below is used to achieve this.
+ OldToNewProcedureMap = new Dictionary<Procedure, Procedure>();
+ var newProgram = base.VisitProgram((Program)node.Clone());
+
+ // We need to make sure that CallCmds get resolved to call Procedures we duplicated
+ // instead of pointing to procedures in the old program
+ var callCmds = newProgram.Blocks().SelectMany(b => b.Cmds).OfType<CallCmd>();
+ foreach (var callCmd in callCmds) {
+ callCmd.Proc = OldToNewProcedureMap[callCmd.Proc];
+ }
+
+ OldToNewProcedureMap = null; // This Visitor could be used for other things later so remove the map.
+ return newProgram;
+ }
+ public override QKeyValue VisitQKeyValue(QKeyValue node) {
+ //Contract.Requires(node != null);
+ var newParams = new List<object>();
+ foreach (var o in node.Params) {
+ var e = o as Expr;
+ if (e == null) {
+ newParams.Add(o);
+ } else {
+ newParams.Add((Expr)this.Visit(e));
+ }
+ }
+ QKeyValue next = node.Next == null ? null : (QKeyValue)this.Visit(node.Next);
+ return new QKeyValue(node.tok, node.Key, newParams, next);
+ }
+ public override BinderExpr VisitBinderExpr(BinderExpr node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<BinderExpr>() != null);
+ return base.VisitBinderExpr((BinderExpr)node.Clone());
+ }
+ public override Requires VisitRequires(Requires node)
+ {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Requires>() != null);
+ return base.VisitRequires((Requires)node.Clone());
+ }
+ public override List<Requires> VisitRequiresSeq(List<Requires> requiresSeq)
+ {
+ //Contract.Requires(requiresSeq != null);
+ Contract.Ensures(Contract.Result<List<Requires>>() != null);
+ return base.VisitRequiresSeq(new List<Requires>(requiresSeq));
+ }
+ public override Cmd VisitRE(RE node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ return base.VisitRE((RE)node.Clone());
+ }
+ public override List<RE> VisitRESeq(List<RE> reSeq) {
+ //Contract.Requires(reSeq != null);
+ Contract.Ensures(Contract.Result<List<RE>>() != null);
+ return base.VisitRESeq(new List<RE>(reSeq));
+ }
+ public override ReturnCmd VisitReturnCmd(ReturnCmd node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<ReturnCmd>() != null);
+ return base.VisitReturnCmd((ReturnCmd)node.Clone());
+ }
+ public override ReturnExprCmd VisitReturnExprCmd(ReturnExprCmd node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<ReturnExprCmd>() != null);
+ return base.VisitReturnExprCmd((ReturnExprCmd)node.Clone());
+ }
+ public override Sequential VisitSequential(Sequential node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Sequential>() != null);
+ return base.VisitSequential((Sequential)node.Clone());
+ }
+ public override AssignLhs VisitSimpleAssignLhs(SimpleAssignLhs node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<AssignLhs>() != null);
+ return base.VisitSimpleAssignLhs((SimpleAssignLhs)node.Clone());
+ }
+ public override Cmd VisitStateCmd(StateCmd node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ return base.VisitStateCmd((StateCmd)node.Clone());
+ }
+ public override TransferCmd VisitTransferCmd(TransferCmd node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<TransferCmd>() != null);
+ return base.VisitTransferCmd((TransferCmd)node.Clone());
+ }
+ public override Trigger VisitTrigger(Trigger node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Trigger>() != null);
+ return base.VisitTrigger((Trigger)node.Clone());
+ }
+ public override Type VisitType(Type node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ // do /not/ clone the type recursively
+ return (Type)node.Clone();
+ }
+ public override TypedIdent VisitTypedIdent(TypedIdent node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<TypedIdent>() != null);
+ return base.VisitTypedIdent((TypedIdent)node.Clone());
+ }
+ public override Variable VisitVariable(Variable node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Variable>() != null);
+ return node;
+ }
+ public override List<Variable> VisitVariableSeq(List<Variable> variableSeq) {
+ //Contract.Requires(variableSeq != null);
+ Contract.Ensures(Contract.Result<List<Variable>>() != null);
+ return base.VisitVariableSeq(new List<Variable>(variableSeq));
+ }
+ public override YieldCmd VisitYieldCmd(YieldCmd node)
+ {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<YieldCmd>() != null);
+ return base.VisitYieldCmd((YieldCmd)node.Clone());
+ }
+ }
+
+
+ #region A duplicator that also does substitutions for a set of variables
+ /// <summary>
+ /// A substitution is a partial mapping from Variables to Exprs.
+ /// </summary>
+ public delegate Expr/*?*/ Substitution(Variable/*!*/ v);
+
+ public static class Substituter {
+ public static Substitution SubstitutionFromHashtable(Dictionary<Variable, Expr> map, bool fallBackOnName = false, Procedure proc = null)
+ {
+ Contract.Requires(map != null);
+ Contract.Ensures(Contract.Result<Substitution>() != null);
+ // TODO: With Whidbey, could use anonymous functions.
+ return new Substitution(new CreateSubstitutionClosure(map, fallBackOnName, proc).Method);
+ }
+ private sealed class CreateSubstitutionClosure {
+ Dictionary<Variable /*!*/, Expr /*!*/>/*!*/ map;
+ Dictionary<string /*!*/, Expr /*!*/>/*!*/ nameMap;
+ Procedure proc;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(map != null);
+ }
+
+ static string UniqueName(Variable variable, Procedure proc)
+ {
+ // TODO(wuestholz): Maybe we should define structural equality for variables instead.
+ var scope = "#global_scope#";
+ if (proc != null && !(variable is GlobalVariable || variable is Constant))
+ {
+ scope = proc.Name;
+ }
+ return string.Format("{0}.{1}", scope, variable.Name);
+ }
+
+ public CreateSubstitutionClosure(Dictionary<Variable, Expr> map, bool fallBackOnName = false, Procedure proc = null)
+ : base() {
+ Contract.Requires(map != null);
+ this.map = map;
+ this.proc = proc;
+ if (fallBackOnName && proc != null)
+ {
+ this.nameMap = map.ToDictionary(kv => UniqueName(kv.Key, proc), kv => kv.Value);
+ }
+ }
+ public Expr/*?*/ Method(Variable v) {
+ Contract.Requires(v != null);
+ if(map.ContainsKey(v)) {
+ return map[v];
+ }
+ Expr e;
+ if (nameMap != null && proc != null && nameMap.TryGetValue(UniqueName(v, proc), out e))
+ {
+ return e;
+ }
+ return null;
+ }
+ }
+
+ // ----------------------------- Substitutions for Expr -------------------------------
+
+ /// <summary>
+ /// Apply a substitution to an expression. Any variables not in domain(subst)
+ /// is not changed. The substitutions apply within the "old", but the "old"
+ /// expression remains.
+ /// </summary>
+ public static Expr Apply(Substitution subst, Expr expr) {
+ Contract.Requires(subst != null);
+ Contract.Requires(expr != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ return (Expr)new NormalSubstituter(subst).Visit(expr);
+ }
+
+ /// <summary>
+ /// Apply a substitution to an expression.
+ /// Outside "old" expressions, the substitution "always" is applied; any variable not in
+ /// domain(always) is not changed. Inside "old" expressions, apply map "forOld" to
+ /// variables in domain(forOld), apply map "always" to variables in
+ /// domain(always)-domain(forOld), and leave variable unchanged otherwise.
+ /// </summary>
+ public static Expr Apply(Substitution always, Substitution forold, Expr expr) {
+ Contract.Requires(always != null);
+ Contract.Requires(forold != null);
+ Contract.Requires(expr != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ return (Expr)new NormalSubstituter(always, forold).Visit(expr);
+ }
+
+ /// <summary>
+ /// Apply a substitution to an expression replacing "old" expressions.
+ /// Outside "old" expressions, the substitution "always" is applied; any variable not in
+ /// domain(always) is not changed. Inside "old" expressions, apply map "forOld" to
+ /// variables in domain(forOld), apply map "always" to variables in
+ /// domain(always)-domain(forOld), and leave variable unchanged otherwise.
+ /// </summary>
+ public static Expr ApplyReplacingOldExprs(Substitution always, Substitution forOld, Expr expr) {
+ Contract.Requires(always != null);
+ Contract.Requires(forOld != null);
+ Contract.Requires(expr != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ return (Expr)new ReplacingOldSubstituter(always, forOld).Visit(expr);
+ }
+
+ public static Expr FunctionCallReresolvingApplyReplacingOldExprs(Substitution always, Substitution forOld, Expr expr, Program program)
+ {
+ Contract.Requires(always != null);
+ Contract.Requires(forOld != null);
+ Contract.Requires(expr != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ return (Expr)new FunctionCallReresolvingReplacingOldSubstituter(program, always, forOld).Visit(expr);
+ }
+
+ public static Expr FunctionCallReresolvingApply(Substitution always, Substitution forOld, Expr expr, Program program)
+ {
+ Contract.Requires(always != null);
+ Contract.Requires(forOld != null);
+ Contract.Requires(expr != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ return (Expr)new FunctionCallReresolvingNormalSubstituter(program, always, forOld).Visit(expr);
+ }
+
+ // ----------------------------- Substitutions for Cmd -------------------------------
+
+ /// <summary>
+ /// Apply a substitution to a command. Any variables not in domain(subst)
+ /// is not changed. The substitutions apply within the "old", but the "old"
+ /// expression remains.
+ /// </summary>
+ public static Cmd Apply(Substitution subst, Cmd cmd) {
+ Contract.Requires(subst != null);
+ Contract.Requires(cmd != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ return (Cmd)new NormalSubstituter(subst).Visit(cmd);
+ }
+
+ /// <summary>
+ /// Apply a substitution to a command.
+ /// Outside "old" expressions, the substitution "always" is applied; any variable not in
+ /// domain(always) is not changed. Inside "old" expressions, apply map "forOld" to
+ /// variables in domain(forOld), apply map "always" to variables in
+ /// domain(always)-domain(forOld), and leave variable unchanged otherwise.
+ /// </summary>
+ public static Cmd Apply(Substitution always, Substitution forOld, Cmd cmd)
+ {
+ Contract.Requires(always != null);
+ Contract.Requires(forOld != null);
+ Contract.Requires(cmd != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ return (Cmd)new NormalSubstituter(always, forOld).Visit(cmd);
+ }
+
+ /// <summary>
+ /// Apply a substitution to a command replacing "old" expressions.
+ /// Outside "old" expressions, the substitution "always" is applied; any variable not in
+ /// domain(always) is not changed. Inside "old" expressions, apply map "forOld" to
+ /// variables in domain(forOld), apply map "always" to variables in
+ /// domain(always)-domain(forOld), and leave variable unchanged otherwise.
+ /// </summary>
+ public static Cmd ApplyReplacingOldExprs(Substitution always, Substitution forOld, Cmd cmd) {
+ Contract.Requires(always != null);
+ Contract.Requires(forOld != null);
+ Contract.Requires(cmd != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ return (Cmd)new ReplacingOldSubstituter(always, forOld).Visit(cmd);
+ }
+
+ // ----------------------------- Substitutions for QKeyValue -------------------------------
+
+ /// <summary>
+ /// Apply a substitution to a list of attributes. Any variables not in domain(subst)
+ /// is not changed. The substitutions apply within the "old", but the "old"
+ /// expression remains.
+ /// </summary>
+ public static QKeyValue Apply(Substitution subst, QKeyValue kv) {
+ Contract.Requires(subst != null);
+ if (kv == null) {
+ return null;
+ } else {
+ return (QKeyValue)new NormalSubstituter(subst).Visit(kv);
+ }
+ }
+
+ /// <summary>
+ /// Apply a substitution to a list of attributes replacing "old" expressions.
+ /// For a further description, see "ApplyReplacingOldExprs" above for Expr.
+ /// </summary>
+ public static QKeyValue ApplyReplacingOldExprs(Substitution always, Substitution forOld, QKeyValue kv) {
+ Contract.Requires(always != null);
+ Contract.Requires(forOld != null);
+ if (kv == null) {
+ return null;
+ } else {
+ return (QKeyValue)new ReplacingOldSubstituter(always, forOld).Visit(kv);
+ }
+ }
+
+ // ------------------------------------------------------------
+
+ private class NormalSubstituter : Duplicator
+ {
+ private readonly Substitution/*!*/ always;
+ private readonly Substitution/*!*/ forold;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(always != null);
+ Contract.Invariant(forold != null);
+ }
+
+ public NormalSubstituter(Substitution subst)
+ : base() {
+ Contract.Requires(subst != null);
+ this.always = subst;
+ this.forold = Substituter.SubstitutionFromHashtable(new Dictionary<Variable, Expr>());
+ }
+
+ public NormalSubstituter(Substitution subst, Substitution forold)
+ : base()
+ {
+ Contract.Requires(subst != null);
+ this.always = subst;
+ this.forold = forold;
+ }
+
+ private bool insideOldExpr = false;
+
+ public override Expr VisitIdentifierExpr(IdentifierExpr node)
+ {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ Expr/*?*/ e = null;
+
+ if (insideOldExpr)
+ {
+ e = forold(cce.NonNull(node.Decl));
+ }
+
+ if (e == null)
+ {
+ e = always(cce.NonNull(node.Decl));
+ }
+
+ return e == null ? base.VisitIdentifierExpr(node) : e;
+ }
+
+ public override Expr VisitOldExpr(OldExpr node)
+ {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ bool previouslyInOld = insideOldExpr;
+ insideOldExpr = true;
+ Expr/*!*/ e = (Expr/*!*/)cce.NonNull(this.Visit(node.Expr));
+ insideOldExpr = previouslyInOld;
+ return new OldExpr(node.tok, e);
+ }
+ }
+
+ private sealed class FunctionCallReresolvingReplacingOldSubstituter : ReplacingOldSubstituter
+ {
+ readonly Program Program;
+
+ public FunctionCallReresolvingReplacingOldSubstituter(Program program, Substitution always, Substitution forold)
+ : base(always, forold)
+ {
+ Program = program;
+ }
+
+ public override Expr VisitNAryExpr(NAryExpr node)
+ {
+ var result = base.VisitNAryExpr(node);
+ var nAryExpr = result as NAryExpr;
+ if (nAryExpr != null)
+ {
+ var funCall = nAryExpr.Fun as FunctionCall;
+ if (funCall != null)
+ {
+ funCall.Func = Program.FindFunction(funCall.FunctionName);
+ }
+ }
+ return result;
+ }
+ }
+
+ private sealed class FunctionCallReresolvingNormalSubstituter : NormalSubstituter
+ {
+ readonly Program Program;
+
+ public FunctionCallReresolvingNormalSubstituter(Program program, Substitution always, Substitution forold)
+ : base(always, forold)
+ {
+ Program = program;
+ }
+
+ public override Expr VisitNAryExpr(NAryExpr node)
+ {
+ var result = base.VisitNAryExpr(node);
+ var nAryExpr = result as NAryExpr;
+ if (nAryExpr != null)
+ {
+ var funCall = nAryExpr.Fun as FunctionCall;
+ if (funCall != null)
+ {
+ funCall.Func = Program.FindFunction(funCall.FunctionName);
+ }
+ }
+ return result;
+ }
+ }
+
+ private class ReplacingOldSubstituter : Duplicator {
+ private readonly Substitution/*!*/ always;
+ private readonly Substitution/*!*/ forold;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(always != null);
+ Contract.Invariant(forold != null);
+ }
+
+ public ReplacingOldSubstituter(Substitution always, Substitution forold)
+ : base() {
+ Contract.Requires(forold != null);
+ Contract.Requires(always != null);
+ this.always = always;
+ this.forold = forold;
+ }
+
+ private bool insideOldExpr = false;
+
+ public override Expr VisitIdentifierExpr(IdentifierExpr node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ Expr/*?*/ e = null;
+
+ if (insideOldExpr) {
+ e = forold(cce.NonNull(node.Decl));
+ }
+
+ if (e == null) {
+ e = always(cce.NonNull(node.Decl));
+ }
+
+ return e == null ? base.VisitIdentifierExpr(node) : e;
+ }
+
+ public override Expr VisitOldExpr(OldExpr node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ bool previouslyInOld = insideOldExpr;
+ insideOldExpr = true;
+ Expr/*!*/ e = (Expr/*!*/)cce.NonNull(this.Visit(node.Expr));
+ insideOldExpr = previouslyInOld;
+ return e;
+ }
+ }
+ }
+ #endregion
+}
diff --git a/Source/Core/Graph.as b/Source/Core/Graph.as
deleted file mode 100644
index 1466c341..00000000
--- a/Source/Core/Graph.as
+++ /dev/null
@@ -1,352 +0,0 @@
-using System.Collections;
-namespace Graphing;
-
-type Node = object;
-type Edge = <Node,Node>;
-
-class PreHeader {
- Node myHeader;
- PreHeader(Node h) { myHeader = h; }
-
- public override string ToString() { return "#" + myHeader.ToString(); }
-}
-
-public class Graph {
- private Set<Edge> es;
- private Set<Node> ns;
- private Node source;
- private bool reducible;
- private Set<Node> headers;
- private Map<Node,Set<Node>> backEdgeNodes;
- private Map<Edge,Set<Node>> naturalLoops;
- private Map<Node,Set<Node>> dominatorMap;
- private Map<Node,Set<Node>> immediateDominatorMap;
-
- public Graph(Set<Edge> edges)
- {
- es = edges;
- ns = Set<Node>{ x : <x,y> in es } + Set<Node>{ y : <x,y> in es };
- }
- public Graph()
- { es = Set<Edge>{}; ns = Set<Node>{}; }
-
- public void AddSource(Node x)
- {
- ns += Set<Node>{x};
- source = x;
- }
- public void AddEdge(Node source, Node dest)
- {
- es += Set<Edge>{<source,dest>};
- ns += Set<Node>{source, dest};
- }
-
- public Set<Node> Nodes { get { return ns; } }
- public Set<Edge> Edges { get { return es; } }
-
- public bool Edge(Node x, Node y) { return <x,y> in es; }
- Set<Node> predecessors(Node n)
- {
- Set<Node> result = Set{ x : x in Nodes, Edge(x,n) };
- return result;
- }
- public override string ToString() { return es.ToString(); }
-
- public IEnumerable TopologicalSort()
- {
- <bool,Seq<Node>> <res,ns> = TopSort(this);
- return res ? ns : null;
- }
- public void ComputeLoops()
- {
- <bool, Set<Node>, Map<Node,Set<Node>>, Map<Edge,Set<Node>>>
- <reducible,headers,backEdgeNodes,naturalLoops> = Reducible(this,this.source);
- this.reducible = reducible;
- this.headers = headers;
- this.backEdgeNodes = backEdgeNodes;
- this.naturalLoops = naturalLoops;
- return;
- }
- public bool Reducible { get { return reducible; } }
- public IEnumerable Headers { get { return headers; } }
- public IEnumerable BackEdgeNodes(Node h) { return h in backEdgeNodes ? backEdgeNodes[h] : null; }
- public IEnumerable NaturalLoops(Node header, Node backEdgeNode)
- { Edge e = <backEdgeNode,header>; return e in naturalLoops ? naturalLoops[e] : null; }
- public bool Acyclic { get { return Acyclic(this,this.source); } }
- public Map<Node,Set<Node>> DominatorMap
- {
- get {
- if (dominatorMap == null) dominatorMap = ComputeDominators(this, source);
- return dominatorMap;
- }
- }
- public Map<Node,Set<Node>> ImmediateDominatorMap
- {
- get {
- if (immediateDominatorMap == null)
- {
- immediateDominatorMap = Map{};
- foreach(Node y in Nodes)
- {
- Set<Node> nodesThatYDominates = Set{ x : x in Nodes, x != y && (y in DominatorMap[x]) };
- Set<Node> immediateDominatees = Set{ x : x in nodesThatYDominates,
- !(Exists{ v != y && v != x && (v in DominatorMap[x]) : v in nodesThatYDominates })
- };
- immediateDominatorMap[y] = immediateDominatees;
- }
- }
- return immediateDominatorMap;
- }
- }
- public Set<Node> ImmediatelyDominatedBy(Node n) { return ImmediateDominatorMap[n]; }
-
-}
-
-// From AsmL distribution example: TopologicalSort
-<bool,Seq<Node>> TopSort(Graph g)
-{
- Seq<Node> S = Seq{};
- Set<Node> V = g.Nodes;
- bool change = true;
- while ( change )
- {
- change = false;
- Set<Node> X = V - ((Set<Node>) S);
- if ( X != Set{} )
- {
- Node temp = Choose{ v : v in X, !(Exists{ g.Edge(u,v) : u in X }) ifnone null };
- if ( temp == null )
- {
- return <false,Seq<Node>{}>;
- }
- else if ( temp != Seq<Node>{} )
- {
- S += Seq{temp};
- change = true;
- }
- }
- }
- return <true,S>;
-}
-
-bool Acyclic(Graph g, Node source)
-{
- <bool,Seq<Node>> <acyc,xs> = TopSort(g);
- return acyc;
-}
-
-//
-// [Dragon, pp. 670--671]
-// returns map D s.t. d in D(n) iff d dom n
-//
-Map<Node,Set<Node>> ComputeDominators(Graph g, Node source) {
- Set<Node> N = g.Nodes;
- Set<Node> nonSourceNodes = N - Set{source};
- Map<Node,Set<Node>> D = Map{};
- D[source] = Set<Node>{ source };
- foreach (Node n in nonSourceNodes)
- {
- D[n] = N;
- }
- bool change = true;
- while ( change )
- {
- change = false;
- foreach (Node n in nonSourceNodes)
- {
- Set<Set<Node>> allPreds = Set{ D[p] : p in g.predecessors(n) };
- Set<Node> temp = Set<Node>{ n } + BigIntersect(allPreds);
- if ( temp != D[n] )
- {
- change = true;
- D[n] = temp;
- }
- }
- }
- return D;
-}
-
-// [Dragon, Fig. 10.15, p. 604. Algorithm for constructing the natural loop.]
-Set<Node> NaturalLoop(Graph g, Edge backEdge)
-{
- <Node,Node> <n,d> = backEdge;
- Seq<Node> stack = Seq{};
- Set<Node> loop = Set{ d };
- if ( n != d ) // then n is not in loop
- {
- loop += Set{ n };
- stack = Seq{ n } + stack; // push n onto stack
- }
- while ( stack != Seq{} ) // not empty
- {
- Node m = Head(stack);
- stack = Tail(stack); // pop stack
- foreach (Node p in g.predecessors(m))
- {
- if ( !(p in loop) )
- {
- loop += Set{ p };
- stack = Seq{ p } + stack; // push p onto stack
- }
- }
- }
- return loop;
-}
-
-// [Dragon, p. 606]
-<bool, Set<Node>, Map<Node,Set<Node>>, Map<Edge,Set<Node>>>
- Reducible(Graph g, Node source) {
- // first, compute the dom relation
- Map<Node,Set<Node>> D = g.DominatorMap;
- return Reducible(g,source,D);
-}
-
-// [Dragon, p. 606]
-<bool, Set<Node>, Map<Node,Set<Node>>, Map<Edge,Set<Node>>>
- Reducible(Graph g, Node source, Map<Node,Set<Node>> DomRelation) {
-
- Set<Edge> edges = g.Edges;
- Set<Edge> backEdges = Set{};
- Set<Edge> nonBackEdges = Set{};
- foreach (Edge e in edges)
- {
- <Node,Node> <x,y> = e; // so there is an edge from x to y
- if ( y in DomRelation[x] ) // y dom x: which means y dominates x
- {
- backEdges += Set{ e };
- }
- else
- {
- nonBackEdges += Set{ e };
- }
- }
- if ( !Acyclic(new Graph(nonBackEdges), source) )
- {
- return <false,Set<Node>{},Map<Node,Set<Node>>{},Map<Edge,Set<Node>>{}>;
- }
- else
- {
- Set<Node> headers = Set{ d : <n,d> in backEdges };
- Map<Node,Set<Node>> backEdgeNodes = Map{ h -> bs : h in headers, bs = Set<Node>{ b : <b,x> in backEdges, x == h } };
- Map<Edge,Set<Node>> naturalLoops = Map{ e -> NaturalLoop(g,e) : e in backEdges };
-
- return <true, headers, backEdgeNodes, naturalLoops>;
- }
-}
-
-// [Dragon, p. 606]
-bool OldReducible(Graph g, Node source) {
- // first, compute the dom relation
- Map<Node,Set<Node>> D = ComputeDominators(g, source);
- return OldReducible(g,source,D);
-}
-
-// [Dragon, p. 606]
-bool OldReducible(Graph g, Node source, Map<Node,Set<Node>> DomRelation) {
-
- Set<Edge> edges = g.Edges;
- Set<Edge> backEdges = Set{};
- Set<Edge> nonBackEdges = Set{};
- foreach (Edge e in edges)
- {
- <Node,Node> <x,y> = e;
- if ( y in DomRelation[x] ) // y dom x
- {
- backEdges += Set{ e };
- }
- else
- {
- nonBackEdges += Set{ e };
- }
- }
- WriteLine("backEdges: " + backEdges);
- WriteLine("nonBackEdges: " + nonBackEdges);
- if ( Acyclic(new Graph(nonBackEdges), source) )
- {
- foreach(Edge e in backEdges)
- {
- Set<Node> naturalLoop = NaturalLoop(g,e);
- WriteLine("Natural loop for back edge '" + e + "' is: " + naturalLoop);
- }
- Set<Node> headers = Set{ d : <n,d> in backEdges };
- WriteLine("Loop headers = " + headers);
-
- edges -= backEdges; // this cuts all of the back edges
- foreach (Node h in headers)
- {
- Set<Edge> bs = Set{ <n,d> : <n,d> in backEdges, d == h };
- Set<Node> preds = Set<Node>{ p : <p,y> in edges, y == h };
- Node preheader = new PreHeader(h);
- edges += Set{ <preheader,h> };
- foreach (Node p in preds)
- {
- edges -= Set{ <p,h> };
- edges += Set{ <p,preheader> };
- }
- }
- Graph newGraph = new Graph(edges);
- WriteLine("transformed graph = " + newGraph);
- return true;
- }
- else
- {
- return false;
- }
-}
-
-void Main()
-{
- Graph g;
- Map<Node,Set<Node>> D;
-/*
- g = new Graph(Set<Edge>{ <1,2>, <1,3>, <2,3> });
- g.AddSource(1);
- Map<Node,Set<Node>> doms = ComputeDominators(g,1);
- WriteLine(doms);
-*/
- g = new Graph(Set<Edge>{
- <1,2>, <1,3>,
- <2,3>,
- <3,4>,
- <4,3>, <4,5>, <4,6>,
- <5,7>,
- <6,7>,
- <7,4>, <7,8>,
- <8,3>, <8,9>, <8,10>,
- <9,1>,
- <10,7>
- });
- g.AddSource(1);
- WriteLine("G = " + g);
- D = ComputeDominators(g,1);
- WriteLine("Dom relation: " + D);
- WriteLine("G's Dominator Map = " + g.DominatorMap);
- WriteLine("G's Immediate Dominator Map = " + g.ImmediateDominatorMap);
- WriteLine("G is reducible: " + OldReducible(g,1,D));
- g.ComputeLoops();
-
- WriteLine("");
-
- g = new Graph(Set<Edge>{ <1,2>, <1,3>, <2,3>, <3,2> });
- g.AddSource(1);
- WriteLine("G = " + g);
- D = ComputeDominators(g,1);
- WriteLine("Dom relation: " + D);
- WriteLine("G's Dominator Map = " + g.DominatorMap);
- WriteLine("G's Immediate Dominator Map = " + g.ImmediateDominatorMap);
- WriteLine("G is reducible: " + OldReducible(g,1,D));
- g.ComputeLoops();
-
- WriteLine("");
-
- g = new Graph(Set<Edge>{ <1,2>, <2,3>, <2,4>, <3,2> });
- g.AddSource(1);
- WriteLine("G = " + g);
- WriteLine("G's Dominator Map = " + g.DominatorMap);
- WriteLine("G's Immediate Dominator Map = " + g.ImmediateDominatorMap);
-// D = ComputeDominators(g,1);
-// WriteLine("Dom relation: " + D);
-// WriteLine("G is reducible: " + OldReducible(g,1,D));
- g.ComputeLoops();
-
-} \ No newline at end of file
diff --git a/Source/Core/Inline.cs b/Source/Core/Inline.cs
index cfeaeb8a..958051d5 100644
--- a/Source/Core/Inline.cs
+++ b/Source/Core/Inline.cs
@@ -1,770 +1,770 @@
-//-----------------------------------------------------------------------------
-//
-// 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;
- using BoogiePL=Microsoft.Boogie;
- using System.Diagnostics;
- using System.Text.RegularExpressions; // for procedure inlining
-
- public delegate void InlineCallback(Implementation/*!*/ impl);
-
- public class Inliner : Duplicator {
- protected bool inlinedSomething;
-
- protected Program program;
-
- private InlineCallback inlineCallback;
-
- protected CodeCopier/*!*/ codeCopier;
-
- protected Dictionary<string/*!*/, int>/*!*/ /* Procedure.Name -> int */ recursiveProcUnrollMap;
-
- protected Dictionary<string/*!*/, int>/*!*/ /* Procedure.Name -> int */ inlinedProcLblMap;
-
- protected int inlineDepth;
-
- protected List<Variable>/*!*/ newLocalVars;
-
- protected List<IdentifierExpr>/*!*/ newModifies;
-
- protected string prefix;
-
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(program != null);
- Contract.Invariant(newLocalVars != null);
- Contract.Invariant(newModifies != null);
- Contract.Invariant(codeCopier != null);
- Contract.Invariant(recursiveProcUnrollMap != null);
- Contract.Invariant(inlinedProcLblMap != null);
- }
-
- public override Expr VisitCodeExpr(CodeExpr node)
- {
- Inliner codeExprInliner = new Inliner(program, inlineCallback, CommandLineOptions.Clo.InlineDepth);
- codeExprInliner.newLocalVars.AddRange(node.LocVars);
- codeExprInliner.inlinedProcLblMap = this.inlinedProcLblMap;
- List<Block> newCodeExprBlocks = codeExprInliner.DoInlineBlocks(node.Blocks, ref inlinedSomething);
- return new CodeExpr(codeExprInliner.newLocalVars, newCodeExprBlocks);
- }
-
- protected void NextInlinedProcLabel(string procName) {
- Contract.Requires(procName != null);
- int currentId;
- if (inlinedProcLblMap.TryGetValue(procName, out currentId)) {
- inlinedProcLblMap[procName] = currentId + 1;
- } else {
- inlinedProcLblMap.Add(procName, 0);
- }
- }
-
- protected string GetInlinedProcLabel(string procName) {
- Contract.Requires(procName != null);
- Contract.Ensures(Contract.Result<string>() != null);
- return prefix + procName + "$" + inlinedProcLblMap[procName];
- }
-
- protected string GetProcVarName(string procName, string formalName) {
- Contract.Requires(formalName != null);
- Contract.Requires(procName != null);
- Contract.Ensures(Contract.Result<string>() != null);
- return GetInlinedProcLabel(procName) + "$" + formalName;
- }
-
- public Inliner(Program program, InlineCallback cb, int inlineDepth) {
- this.program = program;
- this.inlinedProcLblMap = new Dictionary<string/*!*/, int>();
- this.recursiveProcUnrollMap = new Dictionary<string/*!*/, int>();
- this.inlineDepth = inlineDepth;
- this.codeCopier = new CodeCopier();
- this.inlineCallback = cb;
- this.newLocalVars = new List<Variable>();
- this.newModifies = new List<IdentifierExpr>();
- this.prefix = null;
- }
-
- // This method calculates a prefix (storing it in the prefix field) so that prepending it to any string
- // is guaranteed not to create a conflict with the names of variables and blocks in scope inside impl.
- protected void ComputePrefix(Program program, Implementation impl)
- {
- this.prefix = "inline$";
- foreach (var v in impl.InParams)
- {
- DistinguishPrefix(v.Name);
- }
- foreach (var v in impl.OutParams)
- {
- DistinguishPrefix(v.Name);
- }
- foreach (var v in impl.LocVars)
- {
- DistinguishPrefix(v.Name);
- }
- foreach (var v in program.GlobalVariables)
- {
- DistinguishPrefix(v.Name);
- }
- foreach (Block b in impl.Blocks)
- {
- DistinguishPrefix(b.Label);
- }
- }
-
- private void DistinguishPrefix(string s)
- {
- if (!s.StartsWith(prefix)) return;
- for (int i = prefix.Length; i < s.Length; i++)
- {
- prefix = prefix + "$";
- if (s[i] != '$') break;
- }
- if (prefix == s)
- {
- prefix = prefix + "$";
- }
- }
-
- protected static void ProcessImplementation(Program program, Implementation impl, Inliner inliner) {
- Contract.Requires(impl != null);
- Contract.Requires(impl.Proc != null);
-
- inliner.ComputePrefix(program, impl);
-
- inliner.newLocalVars.AddRange(impl.LocVars);
- inliner.newModifies.AddRange(impl.Proc.Modifies);
-
- bool inlined = false;
- List<Block> newBlocks = inliner.DoInlineBlocks(impl.Blocks, ref inlined);
- Contract.Assert(cce.NonNullElements(newBlocks));
-
- if (!inlined)
- return;
-
- impl.InParams = new List<Variable>(impl.InParams);
- impl.OutParams = new List<Variable>(impl.OutParams);
- impl.LocVars = inliner.newLocalVars;
- impl.Proc.Modifies = inliner.newModifies;
- impl.Blocks = newBlocks;
-
- impl.ResetImplFormalMap();
-
- // we need to resolve the new code
- inliner.ResolveImpl(impl);
-
- if (CommandLineOptions.Clo.PrintInlined) {
- inliner.EmitImpl(impl);
- }
- }
-
- public static void ProcessImplementationForHoudini(Program program, Implementation impl) {
- Contract.Requires(impl != null);
- Contract.Requires(program != null);
- Contract.Requires(impl.Proc != null);
- ProcessImplementation(program, impl, new Inliner(program, null, CommandLineOptions.Clo.InlineDepth));
- }
-
- public static void ProcessImplementation(Program program, Implementation impl) {
- Contract.Requires(impl != null);
- Contract.Requires(program != null);
- Contract.Requires(impl.Proc != null);
- ProcessImplementation(program, impl, new Inliner(program, null, -1));
- }
-
- protected void EmitImpl(Implementation impl) {
- Contract.Requires(impl != null);
- Contract.Requires(impl.Proc != null);
- Console.WriteLine("after inlining procedure calls");
- impl.Proc.Emit(new TokenTextWriter("<console>", Console.Out, /*pretty=*/ false), 0);
- impl.Emit(new TokenTextWriter("<console>", Console.Out, /*pretty=*/ false), 0);
- }
-
- private sealed class DummyErrorSink : IErrorSink {
- public void Error(IToken tok, string msg) {
- //Contract.Requires(msg != null);
- //Contract.Requires(tok != null);
- // FIXME
- // noop.
- // This is required because during the resolution, some resolution errors happen
- // (such as the ones caused addion of loop invariants J_(block.Label) by the AI package
- }
- }
-
- protected void ResolveImpl(Implementation impl) {
- Contract.Requires(impl != null);
- Contract.Ensures(impl.Proc != null);
- ResolutionContext rc = new ResolutionContext(new DummyErrorSink());
-
- foreach (var decl in program.TopLevelDeclarations) {
- decl.Register(rc);
- }
-
- impl.Proc = null; // to force Resolve() redo the operation
- impl.Resolve(rc);
-
- TypecheckingContext tc = new TypecheckingContext(new DummyErrorSink());
-
- impl.Typecheck(tc);
- }
-
- // Redundant for this class; but gives a chance for other classes to
- // override this and implement their own inlining policy
- protected virtual int GetInlineCount(CallCmd callCmd, Implementation impl)
- {
- return GetInlineCount(impl);
- }
-
- // returns true if it is ok to further unroll the procedure
- // otherwise, the procedure is not inlined at the call site
- protected int GetInlineCount(Implementation impl) {
- Contract.Requires(impl != null);
- Contract.Requires(impl.Proc != null);
-
- string/*!*/ procName = impl.Name;
- Contract.Assert(procName != null);
- int c;
- if (recursiveProcUnrollMap.TryGetValue(procName, out c)) {
- return c;
- }
-
- c = -1; // TryGetValue above always overwrites c
- impl.CheckIntAttribute("inline", ref c);
- // procedure attribute overrides implementation
- impl.Proc.CheckIntAttribute("inline", ref c);
-
- recursiveProcUnrollMap[procName] = c;
- return c;
- }
-
- void CheckRecursion(Implementation impl, Stack<Procedure/*!*/>/*!*/ callStack) {
- Contract.Requires(impl != null);
- Contract.Requires(cce.NonNullElements(callStack));
- foreach (Procedure/*!*/ p in callStack) {
- Contract.Assert(p != null);
- if (p == impl.Proc) {
- string msg = "";
- foreach (Procedure/*!*/ q in callStack) {
- Contract.Assert(q != null);
- msg = q.Name + " -> " + msg;
- }
- msg += p.Name;
- //checkingCtx.Error(impl, "inlined procedure is recursive, call stack: {0}", msg);
- }
- }
- }
-
- private int InlineCallCmd(Block block, CallCmd callCmd, Implementation impl, List<Cmd> newCmds, List<Block> newBlocks, int lblCount)
- {
- Contract.Assume(impl != null);
- Contract.Assert(cce.NonNull(impl.OriginalBlocks).Count > 0);
-
- // do inline now
- int nextlblCount = lblCount + 1;
- string nextBlockLabel = block.Label + "$" + nextlblCount;
-
- // run the callback before each inline
- if (inlineCallback != null)
- {
- inlineCallback(impl);
- }
-
- // increment the counter for the procedure to be used in constructing the locals and formals
- NextInlinedProcLabel(impl.Proc.Name);
-
- BeginInline(impl);
-
- List<Block/*!*/>/*!*/ inlinedBlocks = CreateInlinedBlocks(callCmd, impl, nextBlockLabel);
- Contract.Assert(cce.NonNullElements(inlinedBlocks));
-
- EndInline();
-
- if (inlineDepth >= 0)
- {
- Debug.Assert(inlineDepth > 0);
- inlineDepth = inlineDepth - 1;
- }
- else
- {
- recursiveProcUnrollMap[impl.Name] = recursiveProcUnrollMap[impl.Name] - 1;
- }
-
- bool inlinedSomething = true;
- inlinedBlocks = DoInlineBlocks(inlinedBlocks, ref inlinedSomething);
-
- if (inlineDepth >= 0)
- {
- inlineDepth = inlineDepth + 1;
- }
- else
- {
- recursiveProcUnrollMap[impl.Name] = recursiveProcUnrollMap[impl.Name] + 1;
- }
-
- Block/*!*/ startBlock = inlinedBlocks[0];
- Contract.Assert(startBlock != null);
-
- GotoCmd gotoCmd = new GotoCmd(Token.NoToken, new List<String> { startBlock.Label });
- Block newBlock = new Block(block.tok, ((lblCount == 0) ? (block.Label) : (block.Label + "$" + lblCount)), newCmds, gotoCmd);
-
- newBlocks.Add(newBlock);
- newBlocks.AddRange(inlinedBlocks);
-
- return nextlblCount;
- }
-
- public virtual List<Block/*!*/>/*!*/ DoInlineBlocks(List<Block/*!*/>/*!*/ blocks, ref bool inlinedSomething) {
- Contract.Requires(cce.NonNullElements(blocks));
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<Block>>()));
- List<Block/*!*/>/*!*/ newBlocks = new List<Block/*!*/>();
-
- foreach (Block block in blocks) {
- TransferCmd/*!*/ transferCmd = cce.NonNull(block.TransferCmd);
- List<Cmd> cmds = block.Cmds;
- List<Cmd> newCmds = new List<Cmd>();
- int lblCount = 0;
-
- for (int i = 0; i < cmds.Count; ++i)
- {
- Cmd cmd = cmds[i];
-
- if (cmd is CallCmd)
- {
- CallCmd callCmd = (CallCmd)cmd;
- Implementation impl = FindProcImpl(program, callCmd.Proc);
- if (impl == null)
- {
- newCmds.Add(codeCopier.CopyCmd(callCmd));
- continue;
- }
- int inline = inlineDepth >= 0 ? inlineDepth : GetInlineCount(callCmd, impl);
- if (inline > 0)
- {
- inlinedSomething = true;
- lblCount = InlineCallCmd(block, callCmd, impl, newCmds, newBlocks, lblCount);
- newCmds = new List<Cmd>();
- }
- else if (inline == 0)
- {
- inlinedSomething = true;
- if (CommandLineOptions.Clo.ProcedureInlining == CommandLineOptions.Inlining.Assert)
- {
- // add assert
- newCmds.Add(new AssertCmd(callCmd.tok, Expr.False));
- }
- else if (CommandLineOptions.Clo.ProcedureInlining == CommandLineOptions.Inlining.Assume)
- {
- // add assume
- newCmds.Add(new AssumeCmd(callCmd.tok, Expr.False));
- }
- else
- {
- // add call
- newCmds.Add(codeCopier.CopyCmd(callCmd));
- }
- }
- else
- {
- newCmds.Add(codeCopier.CopyCmd(callCmd));
- }
- }
- else if (cmd is PredicateCmd)
- {
- PredicateCmd predCmd = (PredicateCmd)cmd;
- this.inlinedSomething = false;
- Expr newExpr = this.VisitExpr(predCmd.Expr);
- if (this.inlinedSomething)
- {
- inlinedSomething = true;
- PredicateCmd newPredCmd = (PredicateCmd)codeCopier.CopyCmd(predCmd);
- newPredCmd.Expr = newExpr;
- newCmds.Add(newPredCmd);
- }
- else
- {
- newCmds.Add(codeCopier.CopyCmd(predCmd));
- }
- }
- else if (cmd is AssignCmd)
- {
- AssignCmd assignCmd = (AssignCmd)cmd;
- this.inlinedSomething = false;
- List<Expr> newRhss = new List<Expr>();
- foreach (Expr rhsExpr in assignCmd.Rhss)
- {
- newRhss.Add(this.VisitExpr(rhsExpr));
- }
- if (this.inlinedSomething)
- {
- inlinedSomething = true;
- AssignCmd newAssignCmd = (AssignCmd)codeCopier.CopyCmd(assignCmd);
- newAssignCmd.Rhss = newRhss;
- newCmds.Add(newAssignCmd);
- }
- else
- {
- newCmds.Add(codeCopier.CopyCmd(assignCmd));
- }
- }
- else
- {
- newCmds.Add(codeCopier.CopyCmd(cmd));
- }
- }
-
- Block newBlock = new Block(block.tok, ((lblCount == 0) ? (block.Label) : (block.Label + "$" + lblCount)), newCmds, codeCopier.CopyTransferCmd(transferCmd));
- newBlocks.Add(newBlock);
- }
-
- return newBlocks;
- }
-
- protected void BeginInline(Implementation impl) {
- Contract.Requires(impl != null);
- Contract.Requires(impl.Proc != null);
- Contract.Requires(newModifies != null);
- Contract.Requires(newLocalVars != null);
-
- Dictionary<Variable, Expr> substMap = new Dictionary<Variable, Expr>();
- Procedure proc = impl.Proc;
-
- foreach (Variable/*!*/ locVar in cce.NonNull(impl.OriginalLocVars)) {
- Contract.Assert(locVar != null);
- LocalVariable localVar = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, GetProcVarName(proc.Name, locVar.Name), locVar.TypedIdent.Type, locVar.TypedIdent.WhereExpr));
- localVar.Attributes = locVar.Attributes; // copy attributes
- newLocalVars.Add(localVar);
- IdentifierExpr ie = new IdentifierExpr(Token.NoToken, localVar);
- substMap.Add(locVar, ie);
- }
-
- for (int i = 0; i < impl.InParams.Count; i++) {
- Variable inVar = cce.NonNull(impl.InParams[i]);
- LocalVariable localVar = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, GetProcVarName(proc.Name, inVar.Name), inVar.TypedIdent.Type, inVar.TypedIdent.WhereExpr));
- newLocalVars.Add(localVar);
- if (impl.Proc != null) localVar.Attributes = impl.Proc.InParams[i].Attributes; // copy attributes
- IdentifierExpr ie = new IdentifierExpr(Token.NoToken, localVar);
- substMap.Add(inVar, ie);
- // also add a substitution from the corresponding formal occurring in the PROCEDURE declaration
- Variable procInVar = cce.NonNull(proc.InParams[i]);
- if (procInVar != inVar) {
- substMap.Add(procInVar, ie);
- }
- }
-
- for (int i = 0; i < impl.OutParams.Count; i++) {
- Variable outVar = cce.NonNull(impl.OutParams[i]);
- LocalVariable localVar = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, GetProcVarName(proc.Name, outVar.Name), outVar.TypedIdent.Type, outVar.TypedIdent.WhereExpr));
- if (impl.Proc != null) localVar.Attributes = impl.Proc.OutParams[i].Attributes; // copy attributes
- newLocalVars.Add(localVar);
- IdentifierExpr ie = new IdentifierExpr(Token.NoToken, localVar);
- substMap.Add(outVar, ie);
- // also add a substitution from the corresponding formal occurring in the PROCEDURE declaration
- Variable procOutVar = cce.NonNull(proc.OutParams[i]);
- if (procOutVar != outVar) {
- substMap.Add(procOutVar, ie);
- }
- }
-
- Dictionary<Variable, Expr> substMapOld = new Dictionary<Variable, Expr>();
-
- foreach (IdentifierExpr/*!*/ mie in proc.Modifies) {
- Contract.Assert(mie != null);
- Variable/*!*/ mVar = cce.NonNull(mie.Decl);
- LocalVariable localVar = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, GetProcVarName(proc.Name, mVar.Name), mVar.TypedIdent.Type));
- newLocalVars.Add(localVar);
- IdentifierExpr ie = new IdentifierExpr(Token.NoToken, localVar);
- substMapOld.Add(mVar, ie);
- // FIXME why are we doing this? the modifies list should already include them.
- // add the modified variable to the modifies list of the procedure
- if (!newModifies.Contains(mie)) {
- newModifies.Add(mie);
- }
- }
-
- codeCopier.Subst = Substituter.SubstitutionFromHashtable(substMap);
- codeCopier.OldSubst = Substituter.SubstitutionFromHashtable(substMapOld);
- }
-
- protected void EndInline() {
- codeCopier.Subst = null;
- codeCopier.OldSubst = null;
- }
-
- private Cmd InlinedRequires(CallCmd callCmd, Requires req) {
- Requires/*!*/ reqCopy = (Requires/*!*/)cce.NonNull(req.Clone());
- if (req.Free)
- reqCopy.Condition = Expr.True;
- else
- reqCopy.Condition = codeCopier.CopyExpr(req.Condition);
- AssertCmd/*!*/ a = new AssertRequiresCmd(callCmd, reqCopy);
- a.ErrorDataEnhanced = reqCopy.ErrorDataEnhanced;
- return a;
- }
-
- private Cmd InlinedEnsures(CallCmd callCmd, Ensures ens) {
- if (QKeyValue.FindBoolAttribute(ens.Attributes, "InlineAssume")) {
- return new AssumeCmd(ens.tok, codeCopier.CopyExpr(ens.Condition));
- } else if (ens.Free) {
- return new AssumeCmd(ens.tok, Expr.True);
- } else {
- Ensures/*!*/ ensCopy = (Ensures/*!*/)cce.NonNull(ens.Clone());
- ensCopy.Condition = codeCopier.CopyExpr(ens.Condition);
- return new AssertEnsuresCmd(ensCopy);
- }
- }
-
- private List<Cmd> RemoveAsserts(List<Cmd> cmds) {
- List<Cmd> newCmdSeq = new List<Cmd>();
- for (int i = 0; i < cmds.Count; i++) {
- Cmd cmd = cmds[i];
- if (cmd is AssertCmd) continue;
- newCmdSeq.Add(cmd);
- }
- return newCmdSeq;
- }
-
- // result[0] is the entry block
- protected List<Block/*!*/>/*!*/ CreateInlinedBlocks(CallCmd callCmd, Implementation impl, string nextBlockLabel) {
- Contract.Requires(nextBlockLabel != null);
- Contract.Requires(impl != null);
- Contract.Requires(impl.Proc != null);
- Contract.Requires(callCmd != null);
- Contract.Requires(codeCopier.Subst != null);
-
- Contract.Requires(codeCopier.OldSubst != null);
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<Block>>()));
- List<Block/*!*/>/*!*/ implBlocks = cce.NonNull(impl.OriginalBlocks);
- Contract.Assert(implBlocks.Count > 0);
-
- Procedure proc = impl.Proc;
- string startLabel = implBlocks[0].Label;
-
- List<Block/*!*/>/*!*/ inlinedBlocks = new List<Block/*!*/>();
-
- // create in block
- List<Cmd> inCmds = new List<Cmd>();
-
- // assign in parameters
- for (int i = 0; i < impl.InParams.Count; ++i) {
- Cmd cmd = Cmd.SimpleAssign(impl.tok,
- (IdentifierExpr)cce.NonNull(codeCopier.Subst)(cce.NonNull(impl.InParams[i])),
- cce.NonNull(callCmd.Ins[i]));
- inCmds.Add(cmd);
- }
-
- // inject requires
- for (int i = 0; i < proc.Requires.Count; i++) {
- Requires/*!*/ req = cce.NonNull(proc.Requires[i]);
- inCmds.Add(InlinedRequires(callCmd, req));
- }
-
- List<Variable> locVars = cce.NonNull(impl.OriginalLocVars);
-
- // havoc locals and out parameters in case procedure is invoked in a loop
- List<IdentifierExpr> havocVars = new List<IdentifierExpr>();
- foreach (Variable v in locVars)
- {
- havocVars.Add((IdentifierExpr)codeCopier.Subst(v));
- }
- foreach (Variable v in impl.OutParams)
- {
- havocVars.Add((IdentifierExpr)codeCopier.Subst(v));
- }
- if (havocVars.Count > 0)
- {
- inCmds.Add(new HavocCmd(Token.NoToken, havocVars));
- }
-
- // add where clauses of local vars as assume
- for (int i = 0; i < locVars.Count; ++i) {
- Expr whereExpr = (cce.NonNull(locVars[i])).TypedIdent.WhereExpr;
- if (whereExpr != null) {
- whereExpr = Substituter.Apply(codeCopier.Subst, whereExpr);
- // FIXME we cannot overwrite it, can we?!
- (cce.NonNull(locVars[i])).TypedIdent.WhereExpr = whereExpr;
- AssumeCmd/*!*/ a = new AssumeCmd(Token.NoToken, whereExpr);
- Contract.Assert(a != null);
- inCmds.Add(a);
- }
- }
-
- // add where clauses of output params as assume
- for (int i = 0; i < impl.OutParams.Count; ++i) {
- Expr whereExpr = (cce.NonNull(impl.OutParams[i])).TypedIdent.WhereExpr;
- if (whereExpr != null) {
- whereExpr = Substituter.Apply(codeCopier.Subst, whereExpr);
- // FIXME likewise
- (cce.NonNull(impl.OutParams[i])).TypedIdent.WhereExpr = whereExpr;
- AssumeCmd/*!*/ a = new AssumeCmd(Token.NoToken, whereExpr);
- Contract.Assert(a != null);
- inCmds.Add(a);
- }
- }
-
- // assign modifies old values
- foreach (IdentifierExpr/*!*/ mie in proc.Modifies) {
- Contract.Assert(mie != null);
- Variable/*!*/ mvar = cce.NonNull(mie.Decl);
- AssignCmd assign = Cmd.SimpleAssign(impl.tok, (IdentifierExpr)cce.NonNull(codeCopier.OldSubst(mvar)), mie);
- inCmds.Add(assign);
- }
-
- GotoCmd inGotoCmd = new GotoCmd(callCmd.tok, new List<String> { GetInlinedProcLabel(proc.Name) + "$" + startLabel });
- Block inBlock = new Block(impl.tok, GetInlinedProcLabel(proc.Name) + "$Entry", inCmds, inGotoCmd);
- inlinedBlocks.Add(inBlock);
-
- // inject the blocks of the implementation
- Block intBlock;
- foreach (Block block in implBlocks) {
- List<Cmd> copyCmds = codeCopier.CopyCmdSeq(block.Cmds);
- if (0 <= inlineDepth) {
- copyCmds = RemoveAsserts(copyCmds);
- }
- TransferCmd transferCmd = CreateInlinedTransferCmd(cce.NonNull(block.TransferCmd), GetInlinedProcLabel(proc.Name));
- intBlock = new Block(block.tok, GetInlinedProcLabel(proc.Name) + "$" + block.Label, copyCmds, transferCmd);
- inlinedBlocks.Add(intBlock);
- }
-
- // create out block
- List<Cmd> outCmds = new List<Cmd>();
-
- // inject ensures
- for (int i = 0; i < proc.Ensures.Count; i++) {
- Ensures/*!*/ ens = cce.NonNull(proc.Ensures[i]);
- outCmds.Add(InlinedEnsures(callCmd, ens));
- }
-
- // assign out params
- for (int i = 0; i < impl.OutParams.Count; ++i) {
- Expr/*!*/ cout_exp = (IdentifierExpr)cce.NonNull(codeCopier.Subst(cce.NonNull(impl.OutParams[i])));
- Cmd cmd = Cmd.SimpleAssign(impl.tok, cce.NonNull(callCmd.Outs[i]), cout_exp);
- outCmds.Add(cmd);
- }
-
- // create out block
- GotoCmd outGotoCmd = new GotoCmd(Token.NoToken, new List<String> { nextBlockLabel });
- Block outBlock = new Block(impl.tok, GetInlinedProcLabel(proc.Name) + "$Return", outCmds, outGotoCmd);
- inlinedBlocks.Add(outBlock);
-
- return inlinedBlocks;
- }
-
- protected TransferCmd CreateInlinedTransferCmd(TransferCmd transferCmd, string procLabel) {
- Contract.Requires(procLabel != null);
- Contract.Requires(transferCmd != null);
- TransferCmd newTransferCmd;
-
- GotoCmd gotoCmd = transferCmd as GotoCmd;
- if (gotoCmd != null) {
- List<String> gotoSeq = gotoCmd.labelNames;
- List<String> newGotoSeq = new List<String>();
- foreach (string/*!*/ blockLabel in cce.NonNull(gotoSeq)) {
- Contract.Assert(blockLabel != null);
- newGotoSeq.Add(procLabel + "$" + blockLabel);
- }
- newTransferCmd = new GotoCmd(transferCmd.tok, newGotoSeq);
- } else {
- newTransferCmd = new GotoCmd(transferCmd.tok, new List<String> { procLabel + "$Return" });
- }
-
- return newTransferCmd;
- }
-
- protected static Implementation FindProcImpl(Program program, Procedure proc) {
- Contract.Requires(program != null);
- foreach (var impl in program.Implementations) {
- if (impl.Proc == proc) {
- return impl;
- }
- }
- return null;
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- public class CodeCopier {
- public Substitution Subst;
- public Substitution OldSubst;
-
- public CodeCopier(Dictionary<Variable, Expr> substMap) {
- Contract.Requires(substMap != null);
- Subst = Substituter.SubstitutionFromHashtable(substMap);
- }
-
- public CodeCopier(Dictionary<Variable, Expr> substMap, Dictionary<Variable, Expr> oldSubstMap) {
- Contract.Requires(oldSubstMap != null);
- Contract.Requires(substMap != null);
- Subst = Substituter.SubstitutionFromHashtable(substMap);
- OldSubst = Substituter.SubstitutionFromHashtable(oldSubstMap);
- }
-
- public CodeCopier() {
- }
-
- public List<Cmd> CopyCmdSeq(List<Cmd> cmds) {
- Contract.Requires(cmds != null);
- Contract.Ensures(Contract.Result<List<Cmd>>() != null);
- List<Cmd> newCmds = new List<Cmd>();
- foreach (Cmd/*!*/ cmd in cmds) {
- Contract.Assert(cmd != null);
- newCmds.Add(CopyCmd(cmd));
- }
- return newCmds;
- }
-
- public TransferCmd CopyTransferCmd(TransferCmd cmd) {
- Contract.Requires(cmd != null);
- Contract.Ensures(Contract.Result<TransferCmd>() != null);
- TransferCmd transferCmd;
- GotoCmd gotocmd = cmd as GotoCmd;
- if (gotocmd != null) {
- Contract.Assert(gotocmd.labelNames != null);
- List<String> labels = new List<String>();
- labels.AddRange(gotocmd.labelNames);
- transferCmd = new GotoCmd(cmd.tok, labels);
- } else {
- ReturnExprCmd returnExprCmd = cmd as ReturnExprCmd;
- if (returnExprCmd != null)
- {
- transferCmd = new ReturnExprCmd(cmd.tok, CopyExpr(returnExprCmd.Expr));
- }
- else
- {
- transferCmd = new ReturnCmd(cmd.tok);
- }
- }
- return transferCmd;
- }
-
- public Cmd CopyCmd(Cmd cmd) {
- Contract.Requires(cmd != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- if (Subst == null) {
- return cmd;
- } else if (OldSubst == null) {
- return Substituter.Apply(Subst, cmd);
- } else {
- return Substituter.ApplyReplacingOldExprs(Subst, OldSubst, cmd);
- }
- }
-
- public Expr CopyExpr(Expr expr) {
- Contract.Requires(expr != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- if (Subst == null) {
- return expr;
- } else if (OldSubst == null) {
- return Substituter.Apply(Subst, expr);
- } else {
- return Substituter.ApplyReplacingOldExprs(Subst, OldSubst, expr);
- }
- }
- } // end class CodeCopier
+//-----------------------------------------------------------------------------
+//
+// 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;
+ using BoogiePL=Microsoft.Boogie;
+ using System.Diagnostics;
+ using System.Text.RegularExpressions; // for procedure inlining
+
+ public delegate void InlineCallback(Implementation/*!*/ impl);
+
+ public class Inliner : Duplicator {
+ protected bool inlinedSomething;
+
+ protected Program program;
+
+ private InlineCallback inlineCallback;
+
+ protected CodeCopier/*!*/ codeCopier;
+
+ protected Dictionary<string/*!*/, int>/*!*/ /* Procedure.Name -> int */ recursiveProcUnrollMap;
+
+ protected Dictionary<string/*!*/, int>/*!*/ /* Procedure.Name -> int */ inlinedProcLblMap;
+
+ protected int inlineDepth;
+
+ protected List<Variable>/*!*/ newLocalVars;
+
+ protected List<IdentifierExpr>/*!*/ newModifies;
+
+ protected string prefix;
+
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(program != null);
+ Contract.Invariant(newLocalVars != null);
+ Contract.Invariant(newModifies != null);
+ Contract.Invariant(codeCopier != null);
+ Contract.Invariant(recursiveProcUnrollMap != null);
+ Contract.Invariant(inlinedProcLblMap != null);
+ }
+
+ public override Expr VisitCodeExpr(CodeExpr node)
+ {
+ Inliner codeExprInliner = new Inliner(program, inlineCallback, CommandLineOptions.Clo.InlineDepth);
+ codeExprInliner.newLocalVars.AddRange(node.LocVars);
+ codeExprInliner.inlinedProcLblMap = this.inlinedProcLblMap;
+ List<Block> newCodeExprBlocks = codeExprInliner.DoInlineBlocks(node.Blocks, ref inlinedSomething);
+ return new CodeExpr(codeExprInliner.newLocalVars, newCodeExprBlocks);
+ }
+
+ protected void NextInlinedProcLabel(string procName) {
+ Contract.Requires(procName != null);
+ int currentId;
+ if (inlinedProcLblMap.TryGetValue(procName, out currentId)) {
+ inlinedProcLblMap[procName] = currentId + 1;
+ } else {
+ inlinedProcLblMap.Add(procName, 0);
+ }
+ }
+
+ protected string GetInlinedProcLabel(string procName) {
+ Contract.Requires(procName != null);
+ Contract.Ensures(Contract.Result<string>() != null);
+ return prefix + procName + "$" + inlinedProcLblMap[procName];
+ }
+
+ protected string GetProcVarName(string procName, string formalName) {
+ Contract.Requires(formalName != null);
+ Contract.Requires(procName != null);
+ Contract.Ensures(Contract.Result<string>() != null);
+ return GetInlinedProcLabel(procName) + "$" + formalName;
+ }
+
+ public Inliner(Program program, InlineCallback cb, int inlineDepth) {
+ this.program = program;
+ this.inlinedProcLblMap = new Dictionary<string/*!*/, int>();
+ this.recursiveProcUnrollMap = new Dictionary<string/*!*/, int>();
+ this.inlineDepth = inlineDepth;
+ this.codeCopier = new CodeCopier();
+ this.inlineCallback = cb;
+ this.newLocalVars = new List<Variable>();
+ this.newModifies = new List<IdentifierExpr>();
+ this.prefix = null;
+ }
+
+ // This method calculates a prefix (storing it in the prefix field) so that prepending it to any string
+ // is guaranteed not to create a conflict with the names of variables and blocks in scope inside impl.
+ protected void ComputePrefix(Program program, Implementation impl)
+ {
+ this.prefix = "inline$";
+ foreach (var v in impl.InParams)
+ {
+ DistinguishPrefix(v.Name);
+ }
+ foreach (var v in impl.OutParams)
+ {
+ DistinguishPrefix(v.Name);
+ }
+ foreach (var v in impl.LocVars)
+ {
+ DistinguishPrefix(v.Name);
+ }
+ foreach (var v in program.GlobalVariables)
+ {
+ DistinguishPrefix(v.Name);
+ }
+ foreach (Block b in impl.Blocks)
+ {
+ DistinguishPrefix(b.Label);
+ }
+ }
+
+ private void DistinguishPrefix(string s)
+ {
+ if (!s.StartsWith(prefix)) return;
+ for (int i = prefix.Length; i < s.Length; i++)
+ {
+ prefix = prefix + "$";
+ if (s[i] != '$') break;
+ }
+ if (prefix == s)
+ {
+ prefix = prefix + "$";
+ }
+ }
+
+ protected static void ProcessImplementation(Program program, Implementation impl, Inliner inliner) {
+ Contract.Requires(impl != null);
+ Contract.Requires(impl.Proc != null);
+
+ inliner.ComputePrefix(program, impl);
+
+ inliner.newLocalVars.AddRange(impl.LocVars);
+ inliner.newModifies.AddRange(impl.Proc.Modifies);
+
+ bool inlined = false;
+ List<Block> newBlocks = inliner.DoInlineBlocks(impl.Blocks, ref inlined);
+ Contract.Assert(cce.NonNullElements(newBlocks));
+
+ if (!inlined)
+ return;
+
+ impl.InParams = new List<Variable>(impl.InParams);
+ impl.OutParams = new List<Variable>(impl.OutParams);
+ impl.LocVars = inliner.newLocalVars;
+ impl.Proc.Modifies = inliner.newModifies;
+ impl.Blocks = newBlocks;
+
+ impl.ResetImplFormalMap();
+
+ // we need to resolve the new code
+ inliner.ResolveImpl(impl);
+
+ if (CommandLineOptions.Clo.PrintInlined) {
+ inliner.EmitImpl(impl);
+ }
+ }
+
+ public static void ProcessImplementationForHoudini(Program program, Implementation impl) {
+ Contract.Requires(impl != null);
+ Contract.Requires(program != null);
+ Contract.Requires(impl.Proc != null);
+ ProcessImplementation(program, impl, new Inliner(program, null, CommandLineOptions.Clo.InlineDepth));
+ }
+
+ public static void ProcessImplementation(Program program, Implementation impl) {
+ Contract.Requires(impl != null);
+ Contract.Requires(program != null);
+ Contract.Requires(impl.Proc != null);
+ ProcessImplementation(program, impl, new Inliner(program, null, -1));
+ }
+
+ protected void EmitImpl(Implementation impl) {
+ Contract.Requires(impl != null);
+ Contract.Requires(impl.Proc != null);
+ Console.WriteLine("after inlining procedure calls");
+ impl.Proc.Emit(new TokenTextWriter("<console>", Console.Out, /*pretty=*/ false), 0);
+ impl.Emit(new TokenTextWriter("<console>", Console.Out, /*pretty=*/ false), 0);
+ }
+
+ private sealed class DummyErrorSink : IErrorSink {
+ public void Error(IToken tok, string msg) {
+ //Contract.Requires(msg != null);
+ //Contract.Requires(tok != null);
+ // FIXME
+ // noop.
+ // This is required because during the resolution, some resolution errors happen
+ // (such as the ones caused addion of loop invariants J_(block.Label) by the AI package
+ }
+ }
+
+ protected void ResolveImpl(Implementation impl) {
+ Contract.Requires(impl != null);
+ Contract.Ensures(impl.Proc != null);
+ ResolutionContext rc = new ResolutionContext(new DummyErrorSink());
+
+ foreach (var decl in program.TopLevelDeclarations) {
+ decl.Register(rc);
+ }
+
+ impl.Proc = null; // to force Resolve() redo the operation
+ impl.Resolve(rc);
+
+ TypecheckingContext tc = new TypecheckingContext(new DummyErrorSink());
+
+ impl.Typecheck(tc);
+ }
+
+ // Redundant for this class; but gives a chance for other classes to
+ // override this and implement their own inlining policy
+ protected virtual int GetInlineCount(CallCmd callCmd, Implementation impl)
+ {
+ return GetInlineCount(impl);
+ }
+
+ // returns true if it is ok to further unroll the procedure
+ // otherwise, the procedure is not inlined at the call site
+ protected int GetInlineCount(Implementation impl) {
+ Contract.Requires(impl != null);
+ Contract.Requires(impl.Proc != null);
+
+ string/*!*/ procName = impl.Name;
+ Contract.Assert(procName != null);
+ int c;
+ if (recursiveProcUnrollMap.TryGetValue(procName, out c)) {
+ return c;
+ }
+
+ c = -1; // TryGetValue above always overwrites c
+ impl.CheckIntAttribute("inline", ref c);
+ // procedure attribute overrides implementation
+ impl.Proc.CheckIntAttribute("inline", ref c);
+
+ recursiveProcUnrollMap[procName] = c;
+ return c;
+ }
+
+ void CheckRecursion(Implementation impl, Stack<Procedure/*!*/>/*!*/ callStack) {
+ Contract.Requires(impl != null);
+ Contract.Requires(cce.NonNullElements(callStack));
+ foreach (Procedure/*!*/ p in callStack) {
+ Contract.Assert(p != null);
+ if (p == impl.Proc) {
+ string msg = "";
+ foreach (Procedure/*!*/ q in callStack) {
+ Contract.Assert(q != null);
+ msg = q.Name + " -> " + msg;
+ }
+ msg += p.Name;
+ //checkingCtx.Error(impl, "inlined procedure is recursive, call stack: {0}", msg);
+ }
+ }
+ }
+
+ private int InlineCallCmd(Block block, CallCmd callCmd, Implementation impl, List<Cmd> newCmds, List<Block> newBlocks, int lblCount)
+ {
+ Contract.Assume(impl != null);
+ Contract.Assert(cce.NonNull(impl.OriginalBlocks).Count > 0);
+
+ // do inline now
+ int nextlblCount = lblCount + 1;
+ string nextBlockLabel = block.Label + "$" + nextlblCount;
+
+ // run the callback before each inline
+ if (inlineCallback != null)
+ {
+ inlineCallback(impl);
+ }
+
+ // increment the counter for the procedure to be used in constructing the locals and formals
+ NextInlinedProcLabel(impl.Proc.Name);
+
+ BeginInline(impl);
+
+ List<Block/*!*/>/*!*/ inlinedBlocks = CreateInlinedBlocks(callCmd, impl, nextBlockLabel);
+ Contract.Assert(cce.NonNullElements(inlinedBlocks));
+
+ EndInline();
+
+ if (inlineDepth >= 0)
+ {
+ Debug.Assert(inlineDepth > 0);
+ inlineDepth = inlineDepth - 1;
+ }
+ else
+ {
+ recursiveProcUnrollMap[impl.Name] = recursiveProcUnrollMap[impl.Name] - 1;
+ }
+
+ bool inlinedSomething = true;
+ inlinedBlocks = DoInlineBlocks(inlinedBlocks, ref inlinedSomething);
+
+ if (inlineDepth >= 0)
+ {
+ inlineDepth = inlineDepth + 1;
+ }
+ else
+ {
+ recursiveProcUnrollMap[impl.Name] = recursiveProcUnrollMap[impl.Name] + 1;
+ }
+
+ Block/*!*/ startBlock = inlinedBlocks[0];
+ Contract.Assert(startBlock != null);
+
+ GotoCmd gotoCmd = new GotoCmd(Token.NoToken, new List<String> { startBlock.Label });
+ Block newBlock = new Block(block.tok, ((lblCount == 0) ? (block.Label) : (block.Label + "$" + lblCount)), newCmds, gotoCmd);
+
+ newBlocks.Add(newBlock);
+ newBlocks.AddRange(inlinedBlocks);
+
+ return nextlblCount;
+ }
+
+ public virtual List<Block/*!*/>/*!*/ DoInlineBlocks(List<Block/*!*/>/*!*/ blocks, ref bool inlinedSomething) {
+ Contract.Requires(cce.NonNullElements(blocks));
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<Block>>()));
+ List<Block/*!*/>/*!*/ newBlocks = new List<Block/*!*/>();
+
+ foreach (Block block in blocks) {
+ TransferCmd/*!*/ transferCmd = cce.NonNull(block.TransferCmd);
+ List<Cmd> cmds = block.Cmds;
+ List<Cmd> newCmds = new List<Cmd>();
+ int lblCount = 0;
+
+ for (int i = 0; i < cmds.Count; ++i)
+ {
+ Cmd cmd = cmds[i];
+
+ if (cmd is CallCmd)
+ {
+ CallCmd callCmd = (CallCmd)cmd;
+ Implementation impl = FindProcImpl(program, callCmd.Proc);
+ if (impl == null)
+ {
+ newCmds.Add(codeCopier.CopyCmd(callCmd));
+ continue;
+ }
+ int inline = inlineDepth >= 0 ? inlineDepth : GetInlineCount(callCmd, impl);
+ if (inline > 0)
+ {
+ inlinedSomething = true;
+ lblCount = InlineCallCmd(block, callCmd, impl, newCmds, newBlocks, lblCount);
+ newCmds = new List<Cmd>();
+ }
+ else if (inline == 0)
+ {
+ inlinedSomething = true;
+ if (CommandLineOptions.Clo.ProcedureInlining == CommandLineOptions.Inlining.Assert)
+ {
+ // add assert
+ newCmds.Add(new AssertCmd(callCmd.tok, Expr.False));
+ }
+ else if (CommandLineOptions.Clo.ProcedureInlining == CommandLineOptions.Inlining.Assume)
+ {
+ // add assume
+ newCmds.Add(new AssumeCmd(callCmd.tok, Expr.False));
+ }
+ else
+ {
+ // add call
+ newCmds.Add(codeCopier.CopyCmd(callCmd));
+ }
+ }
+ else
+ {
+ newCmds.Add(codeCopier.CopyCmd(callCmd));
+ }
+ }
+ else if (cmd is PredicateCmd)
+ {
+ PredicateCmd predCmd = (PredicateCmd)cmd;
+ this.inlinedSomething = false;
+ Expr newExpr = this.VisitExpr(predCmd.Expr);
+ if (this.inlinedSomething)
+ {
+ inlinedSomething = true;
+ PredicateCmd newPredCmd = (PredicateCmd)codeCopier.CopyCmd(predCmd);
+ newPredCmd.Expr = newExpr;
+ newCmds.Add(newPredCmd);
+ }
+ else
+ {
+ newCmds.Add(codeCopier.CopyCmd(predCmd));
+ }
+ }
+ else if (cmd is AssignCmd)
+ {
+ AssignCmd assignCmd = (AssignCmd)cmd;
+ this.inlinedSomething = false;
+ List<Expr> newRhss = new List<Expr>();
+ foreach (Expr rhsExpr in assignCmd.Rhss)
+ {
+ newRhss.Add(this.VisitExpr(rhsExpr));
+ }
+ if (this.inlinedSomething)
+ {
+ inlinedSomething = true;
+ AssignCmd newAssignCmd = (AssignCmd)codeCopier.CopyCmd(assignCmd);
+ newAssignCmd.Rhss = newRhss;
+ newCmds.Add(newAssignCmd);
+ }
+ else
+ {
+ newCmds.Add(codeCopier.CopyCmd(assignCmd));
+ }
+ }
+ else
+ {
+ newCmds.Add(codeCopier.CopyCmd(cmd));
+ }
+ }
+
+ Block newBlock = new Block(block.tok, ((lblCount == 0) ? (block.Label) : (block.Label + "$" + lblCount)), newCmds, codeCopier.CopyTransferCmd(transferCmd));
+ newBlocks.Add(newBlock);
+ }
+
+ return newBlocks;
+ }
+
+ protected void BeginInline(Implementation impl) {
+ Contract.Requires(impl != null);
+ Contract.Requires(impl.Proc != null);
+ Contract.Requires(newModifies != null);
+ Contract.Requires(newLocalVars != null);
+
+ Dictionary<Variable, Expr> substMap = new Dictionary<Variable, Expr>();
+ Procedure proc = impl.Proc;
+
+ foreach (Variable/*!*/ locVar in cce.NonNull(impl.OriginalLocVars)) {
+ Contract.Assert(locVar != null);
+ LocalVariable localVar = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, GetProcVarName(proc.Name, locVar.Name), locVar.TypedIdent.Type, locVar.TypedIdent.WhereExpr));
+ localVar.Attributes = locVar.Attributes; // copy attributes
+ newLocalVars.Add(localVar);
+ IdentifierExpr ie = new IdentifierExpr(Token.NoToken, localVar);
+ substMap.Add(locVar, ie);
+ }
+
+ for (int i = 0; i < impl.InParams.Count; i++) {
+ Variable inVar = cce.NonNull(impl.InParams[i]);
+ LocalVariable localVar = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, GetProcVarName(proc.Name, inVar.Name), inVar.TypedIdent.Type, inVar.TypedIdent.WhereExpr));
+ newLocalVars.Add(localVar);
+ if (impl.Proc != null) localVar.Attributes = impl.Proc.InParams[i].Attributes; // copy attributes
+ IdentifierExpr ie = new IdentifierExpr(Token.NoToken, localVar);
+ substMap.Add(inVar, ie);
+ // also add a substitution from the corresponding formal occurring in the PROCEDURE declaration
+ Variable procInVar = cce.NonNull(proc.InParams[i]);
+ if (procInVar != inVar) {
+ substMap.Add(procInVar, ie);
+ }
+ }
+
+ for (int i = 0; i < impl.OutParams.Count; i++) {
+ Variable outVar = cce.NonNull(impl.OutParams[i]);
+ LocalVariable localVar = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, GetProcVarName(proc.Name, outVar.Name), outVar.TypedIdent.Type, outVar.TypedIdent.WhereExpr));
+ if (impl.Proc != null) localVar.Attributes = impl.Proc.OutParams[i].Attributes; // copy attributes
+ newLocalVars.Add(localVar);
+ IdentifierExpr ie = new IdentifierExpr(Token.NoToken, localVar);
+ substMap.Add(outVar, ie);
+ // also add a substitution from the corresponding formal occurring in the PROCEDURE declaration
+ Variable procOutVar = cce.NonNull(proc.OutParams[i]);
+ if (procOutVar != outVar) {
+ substMap.Add(procOutVar, ie);
+ }
+ }
+
+ Dictionary<Variable, Expr> substMapOld = new Dictionary<Variable, Expr>();
+
+ foreach (IdentifierExpr/*!*/ mie in proc.Modifies) {
+ Contract.Assert(mie != null);
+ Variable/*!*/ mVar = cce.NonNull(mie.Decl);
+ LocalVariable localVar = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, GetProcVarName(proc.Name, mVar.Name), mVar.TypedIdent.Type));
+ newLocalVars.Add(localVar);
+ IdentifierExpr ie = new IdentifierExpr(Token.NoToken, localVar);
+ substMapOld.Add(mVar, ie);
+ // FIXME why are we doing this? the modifies list should already include them.
+ // add the modified variable to the modifies list of the procedure
+ if (!newModifies.Contains(mie)) {
+ newModifies.Add(mie);
+ }
+ }
+
+ codeCopier.Subst = Substituter.SubstitutionFromHashtable(substMap);
+ codeCopier.OldSubst = Substituter.SubstitutionFromHashtable(substMapOld);
+ }
+
+ protected void EndInline() {
+ codeCopier.Subst = null;
+ codeCopier.OldSubst = null;
+ }
+
+ private Cmd InlinedRequires(CallCmd callCmd, Requires req) {
+ Requires/*!*/ reqCopy = (Requires/*!*/)cce.NonNull(req.Clone());
+ if (req.Free)
+ reqCopy.Condition = Expr.True;
+ else
+ reqCopy.Condition = codeCopier.CopyExpr(req.Condition);
+ AssertCmd/*!*/ a = new AssertRequiresCmd(callCmd, reqCopy);
+ a.ErrorDataEnhanced = reqCopy.ErrorDataEnhanced;
+ return a;
+ }
+
+ private Cmd InlinedEnsures(CallCmd callCmd, Ensures ens) {
+ if (QKeyValue.FindBoolAttribute(ens.Attributes, "InlineAssume")) {
+ return new AssumeCmd(ens.tok, codeCopier.CopyExpr(ens.Condition));
+ } else if (ens.Free) {
+ return new AssumeCmd(ens.tok, Expr.True);
+ } else {
+ Ensures/*!*/ ensCopy = (Ensures/*!*/)cce.NonNull(ens.Clone());
+ ensCopy.Condition = codeCopier.CopyExpr(ens.Condition);
+ return new AssertEnsuresCmd(ensCopy);
+ }
+ }
+
+ private List<Cmd> RemoveAsserts(List<Cmd> cmds) {
+ List<Cmd> newCmdSeq = new List<Cmd>();
+ for (int i = 0; i < cmds.Count; i++) {
+ Cmd cmd = cmds[i];
+ if (cmd is AssertCmd) continue;
+ newCmdSeq.Add(cmd);
+ }
+ return newCmdSeq;
+ }
+
+ // result[0] is the entry block
+ protected List<Block/*!*/>/*!*/ CreateInlinedBlocks(CallCmd callCmd, Implementation impl, string nextBlockLabel) {
+ Contract.Requires(nextBlockLabel != null);
+ Contract.Requires(impl != null);
+ Contract.Requires(impl.Proc != null);
+ Contract.Requires(callCmd != null);
+ Contract.Requires(codeCopier.Subst != null);
+
+ Contract.Requires(codeCopier.OldSubst != null);
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<Block>>()));
+ List<Block/*!*/>/*!*/ implBlocks = cce.NonNull(impl.OriginalBlocks);
+ Contract.Assert(implBlocks.Count > 0);
+
+ Procedure proc = impl.Proc;
+ string startLabel = implBlocks[0].Label;
+
+ List<Block/*!*/>/*!*/ inlinedBlocks = new List<Block/*!*/>();
+
+ // create in block
+ List<Cmd> inCmds = new List<Cmd>();
+
+ // assign in parameters
+ for (int i = 0; i < impl.InParams.Count; ++i) {
+ Cmd cmd = Cmd.SimpleAssign(impl.tok,
+ (IdentifierExpr)cce.NonNull(codeCopier.Subst)(cce.NonNull(impl.InParams[i])),
+ cce.NonNull(callCmd.Ins[i]));
+ inCmds.Add(cmd);
+ }
+
+ // inject requires
+ for (int i = 0; i < proc.Requires.Count; i++) {
+ Requires/*!*/ req = cce.NonNull(proc.Requires[i]);
+ inCmds.Add(InlinedRequires(callCmd, req));
+ }
+
+ List<Variable> locVars = cce.NonNull(impl.OriginalLocVars);
+
+ // havoc locals and out parameters in case procedure is invoked in a loop
+ List<IdentifierExpr> havocVars = new List<IdentifierExpr>();
+ foreach (Variable v in locVars)
+ {
+ havocVars.Add((IdentifierExpr)codeCopier.Subst(v));
+ }
+ foreach (Variable v in impl.OutParams)
+ {
+ havocVars.Add((IdentifierExpr)codeCopier.Subst(v));
+ }
+ if (havocVars.Count > 0)
+ {
+ inCmds.Add(new HavocCmd(Token.NoToken, havocVars));
+ }
+
+ // add where clauses of local vars as assume
+ for (int i = 0; i < locVars.Count; ++i) {
+ Expr whereExpr = (cce.NonNull(locVars[i])).TypedIdent.WhereExpr;
+ if (whereExpr != null) {
+ whereExpr = Substituter.Apply(codeCopier.Subst, whereExpr);
+ // FIXME we cannot overwrite it, can we?!
+ (cce.NonNull(locVars[i])).TypedIdent.WhereExpr = whereExpr;
+ AssumeCmd/*!*/ a = new AssumeCmd(Token.NoToken, whereExpr);
+ Contract.Assert(a != null);
+ inCmds.Add(a);
+ }
+ }
+
+ // add where clauses of output params as assume
+ for (int i = 0; i < impl.OutParams.Count; ++i) {
+ Expr whereExpr = (cce.NonNull(impl.OutParams[i])).TypedIdent.WhereExpr;
+ if (whereExpr != null) {
+ whereExpr = Substituter.Apply(codeCopier.Subst, whereExpr);
+ // FIXME likewise
+ (cce.NonNull(impl.OutParams[i])).TypedIdent.WhereExpr = whereExpr;
+ AssumeCmd/*!*/ a = new AssumeCmd(Token.NoToken, whereExpr);
+ Contract.Assert(a != null);
+ inCmds.Add(a);
+ }
+ }
+
+ // assign modifies old values
+ foreach (IdentifierExpr/*!*/ mie in proc.Modifies) {
+ Contract.Assert(mie != null);
+ Variable/*!*/ mvar = cce.NonNull(mie.Decl);
+ AssignCmd assign = Cmd.SimpleAssign(impl.tok, (IdentifierExpr)cce.NonNull(codeCopier.OldSubst(mvar)), mie);
+ inCmds.Add(assign);
+ }
+
+ GotoCmd inGotoCmd = new GotoCmd(callCmd.tok, new List<String> { GetInlinedProcLabel(proc.Name) + "$" + startLabel });
+ Block inBlock = new Block(impl.tok, GetInlinedProcLabel(proc.Name) + "$Entry", inCmds, inGotoCmd);
+ inlinedBlocks.Add(inBlock);
+
+ // inject the blocks of the implementation
+ Block intBlock;
+ foreach (Block block in implBlocks) {
+ List<Cmd> copyCmds = codeCopier.CopyCmdSeq(block.Cmds);
+ if (0 <= inlineDepth) {
+ copyCmds = RemoveAsserts(copyCmds);
+ }
+ TransferCmd transferCmd = CreateInlinedTransferCmd(cce.NonNull(block.TransferCmd), GetInlinedProcLabel(proc.Name));
+ intBlock = new Block(block.tok, GetInlinedProcLabel(proc.Name) + "$" + block.Label, copyCmds, transferCmd);
+ inlinedBlocks.Add(intBlock);
+ }
+
+ // create out block
+ List<Cmd> outCmds = new List<Cmd>();
+
+ // inject ensures
+ for (int i = 0; i < proc.Ensures.Count; i++) {
+ Ensures/*!*/ ens = cce.NonNull(proc.Ensures[i]);
+ outCmds.Add(InlinedEnsures(callCmd, ens));
+ }
+
+ // assign out params
+ for (int i = 0; i < impl.OutParams.Count; ++i) {
+ Expr/*!*/ cout_exp = (IdentifierExpr)cce.NonNull(codeCopier.Subst(cce.NonNull(impl.OutParams[i])));
+ Cmd cmd = Cmd.SimpleAssign(impl.tok, cce.NonNull(callCmd.Outs[i]), cout_exp);
+ outCmds.Add(cmd);
+ }
+
+ // create out block
+ GotoCmd outGotoCmd = new GotoCmd(Token.NoToken, new List<String> { nextBlockLabel });
+ Block outBlock = new Block(impl.tok, GetInlinedProcLabel(proc.Name) + "$Return", outCmds, outGotoCmd);
+ inlinedBlocks.Add(outBlock);
+
+ return inlinedBlocks;
+ }
+
+ protected TransferCmd CreateInlinedTransferCmd(TransferCmd transferCmd, string procLabel) {
+ Contract.Requires(procLabel != null);
+ Contract.Requires(transferCmd != null);
+ TransferCmd newTransferCmd;
+
+ GotoCmd gotoCmd = transferCmd as GotoCmd;
+ if (gotoCmd != null) {
+ List<String> gotoSeq = gotoCmd.labelNames;
+ List<String> newGotoSeq = new List<String>();
+ foreach (string/*!*/ blockLabel in cce.NonNull(gotoSeq)) {
+ Contract.Assert(blockLabel != null);
+ newGotoSeq.Add(procLabel + "$" + blockLabel);
+ }
+ newTransferCmd = new GotoCmd(transferCmd.tok, newGotoSeq);
+ } else {
+ newTransferCmd = new GotoCmd(transferCmd.tok, new List<String> { procLabel + "$Return" });
+ }
+
+ return newTransferCmd;
+ }
+
+ protected static Implementation FindProcImpl(Program program, Procedure proc) {
+ Contract.Requires(program != null);
+ foreach (var impl in program.Implementations) {
+ if (impl.Proc == proc) {
+ return impl;
+ }
+ }
+ return null;
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ public class CodeCopier {
+ public Substitution Subst;
+ public Substitution OldSubst;
+
+ public CodeCopier(Dictionary<Variable, Expr> substMap) {
+ Contract.Requires(substMap != null);
+ Subst = Substituter.SubstitutionFromHashtable(substMap);
+ }
+
+ public CodeCopier(Dictionary<Variable, Expr> substMap, Dictionary<Variable, Expr> oldSubstMap) {
+ Contract.Requires(oldSubstMap != null);
+ Contract.Requires(substMap != null);
+ Subst = Substituter.SubstitutionFromHashtable(substMap);
+ OldSubst = Substituter.SubstitutionFromHashtable(oldSubstMap);
+ }
+
+ public CodeCopier() {
+ }
+
+ public List<Cmd> CopyCmdSeq(List<Cmd> cmds) {
+ Contract.Requires(cmds != null);
+ Contract.Ensures(Contract.Result<List<Cmd>>() != null);
+ List<Cmd> newCmds = new List<Cmd>();
+ foreach (Cmd/*!*/ cmd in cmds) {
+ Contract.Assert(cmd != null);
+ newCmds.Add(CopyCmd(cmd));
+ }
+ return newCmds;
+ }
+
+ public TransferCmd CopyTransferCmd(TransferCmd cmd) {
+ Contract.Requires(cmd != null);
+ Contract.Ensures(Contract.Result<TransferCmd>() != null);
+ TransferCmd transferCmd;
+ GotoCmd gotocmd = cmd as GotoCmd;
+ if (gotocmd != null) {
+ Contract.Assert(gotocmd.labelNames != null);
+ List<String> labels = new List<String>();
+ labels.AddRange(gotocmd.labelNames);
+ transferCmd = new GotoCmd(cmd.tok, labels);
+ } else {
+ ReturnExprCmd returnExprCmd = cmd as ReturnExprCmd;
+ if (returnExprCmd != null)
+ {
+ transferCmd = new ReturnExprCmd(cmd.tok, CopyExpr(returnExprCmd.Expr));
+ }
+ else
+ {
+ transferCmd = new ReturnCmd(cmd.tok);
+ }
+ }
+ return transferCmd;
+ }
+
+ public Cmd CopyCmd(Cmd cmd) {
+ Contract.Requires(cmd != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ if (Subst == null) {
+ return cmd;
+ } else if (OldSubst == null) {
+ return Substituter.Apply(Subst, cmd);
+ } else {
+ return Substituter.ApplyReplacingOldExprs(Subst, OldSubst, cmd);
+ }
+ }
+
+ public Expr CopyExpr(Expr expr) {
+ Contract.Requires(expr != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ if (Subst == null) {
+ return expr;
+ } else if (OldSubst == null) {
+ return Substituter.Apply(Subst, expr);
+ } else {
+ return Substituter.ApplyReplacingOldExprs(Subst, OldSubst, expr);
+ }
+ }
+ } // end class CodeCopier
} // end namespace \ No newline at end of file
diff --git a/Source/Core/InterProceduralReachabilityGraph.cs b/Source/Core/InterProceduralReachabilityGraph.cs
index d75a4b7d..73c88bca 100644
--- a/Source/Core/InterProceduralReachabilityGraph.cs
+++ b/Source/Core/InterProceduralReachabilityGraph.cs
@@ -1,306 +1,306 @@
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Diagnostics;
-using Microsoft.Boogie.GraphUtil;
-
-namespace Microsoft.Boogie
-{
-
- public interface IInterproceduralReachabilityGraph {
-
- bool MayReach(Block src, Block dst);
-
- void dump();
-
- Block GetNewEntryBlock(string p);
-
- Block GetNewExitBlock(string p);
-
- Block GetNewBlock(Block block);
- }
-
- public class InterproceduralReachabilityGraph : IInterproceduralReachabilityGraph
- {
-
- private Program prog;
- private HashSet<Block> nodes;
- private Dictionary<Block, Block> originalToNew;
- private Dictionary<string, Block> newProcedureEntryNodes;
- private Dictionary<string, Block> newProcedureExitNodes;
-
- private Graph<Block> reachabilityGraph;
-
- public InterproceduralReachabilityGraph(Program prog) {
- this.prog = prog;
- originalToNew = new Dictionary<Block,Block>();
- newProcedureEntryNodes = new Dictionary<string,Block>();
- newProcedureExitNodes = new Dictionary<string,Block>();
- nodes = new HashSet<Block>();
-
- ProcessImplementations();
-
- ProcessBodilessProcedures();
-
- PatchUpGotoTargets();
-
- AddCallAndReturnEdges();
-
- reachabilityGraph = new Graph<Block>();
-
- foreach(var n in nodes) {
- GotoCmd gotoCmd = n.TransferCmd as GotoCmd;
- if(gotoCmd != null) {
- foreach(Block b in gotoCmd.labelTargets) {
- reachabilityGraph.AddEdge(n, b);
- }
- }
- }
-
- foreach(var n in nodes) {
- // If there are disconnected nodes, put them into the
- // graph as self-loops so that every node is represented in
- // the graph
- if(!reachabilityGraph.Nodes.Contains(n)) {
- reachabilityGraph.AddEdge(n, n);
- }
- }
- }
-
- private IEnumerable<Block> OriginalProgramBlocks()
- {
- return prog.Implementations.Select(Item => Item.Blocks).SelectMany(Item => Item);
- }
-
- private void AddCallAndReturnEdges()
- {
- #region Add call and return edges
- foreach (var n in nodes)
- {
- if (n.Cmds.Count == 1 && n.Cmds[0] is CallCmd)
- {
- string proc = ((CallCmd)n.Cmds[0]).callee;
- GotoCmd gotoCmd = n.TransferCmd as GotoCmd;
- Debug.Assert(gotoCmd != null);
-
- for (int i = 0; i < gotoCmd.labelTargets.Count; i++)
- {
- (newProcedureExitNodes[proc].TransferCmd as GotoCmd).labelTargets.Add(gotoCmd.labelTargets[i]);
- (newProcedureExitNodes[proc].TransferCmd as GotoCmd).labelNames.Add(gotoCmd.labelNames[i]);
- }
- gotoCmd.labelTargets = new List<Block> { newProcedureEntryNodes[proc] };
- gotoCmd.labelNames = new List<String> { newProcedureEntryNodes[proc].Label };
- }
- }
- #endregion
- }
-
- private void PatchUpGotoTargets()
- {
- #region Patch up goto targets
- foreach (var n in nodes)
- {
- var gotoCmd = n.TransferCmd as GotoCmd;
- if (gotoCmd != null)
- {
- List<Block> newTargets = new List<Block>();
- foreach (Block t in gotoCmd.labelTargets)
- {
- if (originalToNew.ContainsKey(t))
- {
- newTargets.Add(originalToNew[t]);
- }
- else
- {
- newTargets.Add(t);
- }
- }
- gotoCmd.labelTargets = newTargets;
- }
- }
- #endregion
- }
-
- private void ProcessBodilessProcedures()
- {
- #region Add single node CFG for procedures with no body
- foreach (var proc in prog.Procedures)
- {
- if (!newProcedureEntryNodes.ContainsKey(proc.Name))
- {
- Block newBlock = new Block(Token.NoToken, proc + "__dummy_node", new List<Cmd>(), new GotoCmd(Token.NoToken, new List<Block>()));
- nodes.Add(newBlock);
- newProcedureEntryNodes[proc.Name] = newBlock;
- newProcedureExitNodes[proc.Name] = newBlock;
- }
- }
- #endregion
- }
-
- private void ProcessImplementations()
- {
- #region Transform implementation CFGs so that every call is in its own basic block
- foreach (var impl in prog.Implementations)
- {
- string exitLabel = "__" + impl.Name + "_newExit";
- Block newExit = new Block(Token.NoToken, exitLabel, new List<Cmd>(), new GotoCmd(Token.NoToken, new List<Block>()));
- nodes.Add(newExit);
- newProcedureExitNodes[impl.Name] = newExit;
- foreach (Block b in impl.Blocks)
- {
- Block prev = null;
- int i = 0;
- foreach (List<Cmd> cmds in SeparateCallCmds(b.Cmds))
- {
- Block newBlock;
- if (prev == null)
- {
- newBlock = new Block(b.tok, "__" + impl.Name + "_" + b.Label, new List<Cmd>(cmds.ToArray()), null);
- nodes.Add(newBlock);
- originalToNew[b] = newBlock;
- if (impl.Blocks[0] == b)
- {
- newProcedureEntryNodes[impl.Name] = newBlock;
- }
- }
- else
- {
- string label = "__" + impl.Name + "_" + b.Label + "_call_" + i;
- newBlock = new Block(b.tok, label, new List<Cmd>(cmds.ToArray()), null);
- nodes.Add(newBlock);
- originalToNew[newBlock] = newBlock;
- prev.TransferCmd = new GotoCmd(Token.NoToken, new List<String> { label }, new List<Block> { newBlock });
- }
- prev = newBlock;
- i++;
- }
- Debug.Assert(prev != null);
- if (b.TransferCmd is ReturnCmd || (b.TransferCmd is GotoCmd &&
- ((GotoCmd)b.TransferCmd).labelTargets.Count == 0))
- {
- prev.TransferCmd = new GotoCmd(Token.NoToken, new List<String> { exitLabel }, new List<Block> { newExit });
- }
- else
- {
- if(b.TransferCmd is ReturnCmd) {
- prev.TransferCmd = new ReturnCmd(b.TransferCmd.tok);
- } else {
- var gotoCmd = b.TransferCmd as GotoCmd;
- Debug.Assert(gotoCmd != null);
- prev.TransferCmd = new GotoCmd(gotoCmd.tok, gotoCmd.labelNames, gotoCmd.labelTargets);
- }
- }
- }
- }
- #endregion
- }
-
- private static List<List<Cmd>> SeparateCallCmds(List<Cmd> Cmds) {
- List<List<Cmd>> result = new List<List<Cmd>>();
- int currentIndex = 0;
- while(currentIndex < Cmds.Count) {
- if(Cmds[currentIndex] is CallCmd) {
- result.Add(new List<Cmd> { Cmds[currentIndex] });
- currentIndex++;
- } else {
- List<Cmd> nonCallCmds = new List<Cmd>();
- while(currentIndex < Cmds.Count && !(Cmds[currentIndex] is CallCmd)) {
- nonCallCmds.Add(Cmds[currentIndex]);
- currentIndex++;
- }
- result.Add(nonCallCmds);
- }
- }
- if(result.Count == 0) {
- result.Add(new List<Cmd>());
- }
- return result;
- }
-
- private Graph<SCC<Block>> ReachabilityGraphSCCsDAG;
- private Dictionary<Block, SCC<Block>> BlockToSCC;
-
- private Dictionary<SCC<Block>, HashSet<Block>> MayReachCache = new Dictionary<SCC<Block>, HashSet<Block>>();
-
- public bool MayReach(Block src, Block dst) {
- if (ReachabilityGraphSCCsDAG == null) {
- if (CommandLineOptions.Clo.Trace) {
- Console.WriteLine("Interprocedural reachability: computing SCCs");
- }
- Adjacency<Block> next = new Adjacency<Block>(reachabilityGraph.Successors);
- Adjacency<Block> prev = new Adjacency<Block>(reachabilityGraph.Predecessors);
- StronglyConnectedComponents<Block> ReachabilitySCCs = new StronglyConnectedComponents<Block>(
- reachabilityGraph.Nodes, next, prev);
- ReachabilitySCCs.Compute();
-
- BlockToSCC = new Dictionary<Block, SCC<Block>>();
- foreach (var scc in ReachabilitySCCs) {
- foreach (var s in scc) {
- BlockToSCC[s] = scc;
- }
- }
-
- ReachabilityGraphSCCsDAG = new Graph<SCC<Block>>();
- foreach (var edge in reachabilityGraph.Edges) {
- if (BlockToSCC[edge.Item1] != BlockToSCC[edge.Item2]) {
- ReachabilityGraphSCCsDAG.AddEdge(BlockToSCC[edge.Item1], BlockToSCC[edge.Item2]);
- }
- }
-
- SCC<Block> dummy = new SCC<Block>();
- foreach (var n in reachabilityGraph.Nodes) {
- ReachabilityGraphSCCsDAG.AddEdge(BlockToSCC[n], dummy);
- }
-
- if (CommandLineOptions.Clo.Trace) {
- Console.WriteLine("Interprocedural reachability: SCCs computed!");
- }
- }
- return ReachableFrom(BlockToSCC[src]).Contains(dst);
- }
-
- private HashSet<Block> ReachableFrom(SCC<Block> scc) {
- if (!MayReachCache.ContainsKey(scc)) {
- HashSet<Block> result = new HashSet<Block>();
- if (scc.Count() > 0) {
- result.UnionWith(scc);
- foreach (var nextSCC in ReachabilityGraphSCCsDAG.Successors(scc)) {
- result.UnionWith(ReachableFrom(nextSCC));
- }
- }
- MayReachCache[scc] = result;
- }
- return MayReachCache[scc];
- }
-
- public void dump() {
- foreach(var n in nodes) {
- Console.WriteLine(n.Label + " -> {");
- GotoCmd gotoCmd = n.TransferCmd as GotoCmd;
- if(n != null) {
- foreach(Block m in gotoCmd.labelTargets) {
- Console.WriteLine(" " + m.Label);
- }
- }
- Console.WriteLine("}");
- }
- }
-
- public Block GetNewEntryBlock(string proc) {
- return newProcedureEntryNodes[proc];
- }
-
- public Block GetNewExitBlock(string proc) {
- return newProcedureExitNodes[proc];
- }
-
- public Block GetNewBlock(Block b) {
- return originalToNew[b];
- }
-
- }
-
-
-}
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Diagnostics;
+using Microsoft.Boogie.GraphUtil;
+
+namespace Microsoft.Boogie
+{
+
+ public interface IInterproceduralReachabilityGraph {
+
+ bool MayReach(Block src, Block dst);
+
+ void dump();
+
+ Block GetNewEntryBlock(string p);
+
+ Block GetNewExitBlock(string p);
+
+ Block GetNewBlock(Block block);
+ }
+
+ public class InterproceduralReachabilityGraph : IInterproceduralReachabilityGraph
+ {
+
+ private Program prog;
+ private HashSet<Block> nodes;
+ private Dictionary<Block, Block> originalToNew;
+ private Dictionary<string, Block> newProcedureEntryNodes;
+ private Dictionary<string, Block> newProcedureExitNodes;
+
+ private Graph<Block> reachabilityGraph;
+
+ public InterproceduralReachabilityGraph(Program prog) {
+ this.prog = prog;
+ originalToNew = new Dictionary<Block,Block>();
+ newProcedureEntryNodes = new Dictionary<string,Block>();
+ newProcedureExitNodes = new Dictionary<string,Block>();
+ nodes = new HashSet<Block>();
+
+ ProcessImplementations();
+
+ ProcessBodilessProcedures();
+
+ PatchUpGotoTargets();
+
+ AddCallAndReturnEdges();
+
+ reachabilityGraph = new Graph<Block>();
+
+ foreach(var n in nodes) {
+ GotoCmd gotoCmd = n.TransferCmd as GotoCmd;
+ if(gotoCmd != null) {
+ foreach(Block b in gotoCmd.labelTargets) {
+ reachabilityGraph.AddEdge(n, b);
+ }
+ }
+ }
+
+ foreach(var n in nodes) {
+ // If there are disconnected nodes, put them into the
+ // graph as self-loops so that every node is represented in
+ // the graph
+ if(!reachabilityGraph.Nodes.Contains(n)) {
+ reachabilityGraph.AddEdge(n, n);
+ }
+ }
+ }
+
+ private IEnumerable<Block> OriginalProgramBlocks()
+ {
+ return prog.Implementations.Select(Item => Item.Blocks).SelectMany(Item => Item);
+ }
+
+ private void AddCallAndReturnEdges()
+ {
+ #region Add call and return edges
+ foreach (var n in nodes)
+ {
+ if (n.Cmds.Count == 1 && n.Cmds[0] is CallCmd)
+ {
+ string proc = ((CallCmd)n.Cmds[0]).callee;
+ GotoCmd gotoCmd = n.TransferCmd as GotoCmd;
+ Debug.Assert(gotoCmd != null);
+
+ for (int i = 0; i < gotoCmd.labelTargets.Count; i++)
+ {
+ (newProcedureExitNodes[proc].TransferCmd as GotoCmd).labelTargets.Add(gotoCmd.labelTargets[i]);
+ (newProcedureExitNodes[proc].TransferCmd as GotoCmd).labelNames.Add(gotoCmd.labelNames[i]);
+ }
+ gotoCmd.labelTargets = new List<Block> { newProcedureEntryNodes[proc] };
+ gotoCmd.labelNames = new List<String> { newProcedureEntryNodes[proc].Label };
+ }
+ }
+ #endregion
+ }
+
+ private void PatchUpGotoTargets()
+ {
+ #region Patch up goto targets
+ foreach (var n in nodes)
+ {
+ var gotoCmd = n.TransferCmd as GotoCmd;
+ if (gotoCmd != null)
+ {
+ List<Block> newTargets = new List<Block>();
+ foreach (Block t in gotoCmd.labelTargets)
+ {
+ if (originalToNew.ContainsKey(t))
+ {
+ newTargets.Add(originalToNew[t]);
+ }
+ else
+ {
+ newTargets.Add(t);
+ }
+ }
+ gotoCmd.labelTargets = newTargets;
+ }
+ }
+ #endregion
+ }
+
+ private void ProcessBodilessProcedures()
+ {
+ #region Add single node CFG for procedures with no body
+ foreach (var proc in prog.Procedures)
+ {
+ if (!newProcedureEntryNodes.ContainsKey(proc.Name))
+ {
+ Block newBlock = new Block(Token.NoToken, proc + "__dummy_node", new List<Cmd>(), new GotoCmd(Token.NoToken, new List<Block>()));
+ nodes.Add(newBlock);
+ newProcedureEntryNodes[proc.Name] = newBlock;
+ newProcedureExitNodes[proc.Name] = newBlock;
+ }
+ }
+ #endregion
+ }
+
+ private void ProcessImplementations()
+ {
+ #region Transform implementation CFGs so that every call is in its own basic block
+ foreach (var impl in prog.Implementations)
+ {
+ string exitLabel = "__" + impl.Name + "_newExit";
+ Block newExit = new Block(Token.NoToken, exitLabel, new List<Cmd>(), new GotoCmd(Token.NoToken, new List<Block>()));
+ nodes.Add(newExit);
+ newProcedureExitNodes[impl.Name] = newExit;
+ foreach (Block b in impl.Blocks)
+ {
+ Block prev = null;
+ int i = 0;
+ foreach (List<Cmd> cmds in SeparateCallCmds(b.Cmds))
+ {
+ Block newBlock;
+ if (prev == null)
+ {
+ newBlock = new Block(b.tok, "__" + impl.Name + "_" + b.Label, new List<Cmd>(cmds.ToArray()), null);
+ nodes.Add(newBlock);
+ originalToNew[b] = newBlock;
+ if (impl.Blocks[0] == b)
+ {
+ newProcedureEntryNodes[impl.Name] = newBlock;
+ }
+ }
+ else
+ {
+ string label = "__" + impl.Name + "_" + b.Label + "_call_" + i;
+ newBlock = new Block(b.tok, label, new List<Cmd>(cmds.ToArray()), null);
+ nodes.Add(newBlock);
+ originalToNew[newBlock] = newBlock;
+ prev.TransferCmd = new GotoCmd(Token.NoToken, new List<String> { label }, new List<Block> { newBlock });
+ }
+ prev = newBlock;
+ i++;
+ }
+ Debug.Assert(prev != null);
+ if (b.TransferCmd is ReturnCmd || (b.TransferCmd is GotoCmd &&
+ ((GotoCmd)b.TransferCmd).labelTargets.Count == 0))
+ {
+ prev.TransferCmd = new GotoCmd(Token.NoToken, new List<String> { exitLabel }, new List<Block> { newExit });
+ }
+ else
+ {
+ if(b.TransferCmd is ReturnCmd) {
+ prev.TransferCmd = new ReturnCmd(b.TransferCmd.tok);
+ } else {
+ var gotoCmd = b.TransferCmd as GotoCmd;
+ Debug.Assert(gotoCmd != null);
+ prev.TransferCmd = new GotoCmd(gotoCmd.tok, gotoCmd.labelNames, gotoCmd.labelTargets);
+ }
+ }
+ }
+ }
+ #endregion
+ }
+
+ private static List<List<Cmd>> SeparateCallCmds(List<Cmd> Cmds) {
+ List<List<Cmd>> result = new List<List<Cmd>>();
+ int currentIndex = 0;
+ while(currentIndex < Cmds.Count) {
+ if(Cmds[currentIndex] is CallCmd) {
+ result.Add(new List<Cmd> { Cmds[currentIndex] });
+ currentIndex++;
+ } else {
+ List<Cmd> nonCallCmds = new List<Cmd>();
+ while(currentIndex < Cmds.Count && !(Cmds[currentIndex] is CallCmd)) {
+ nonCallCmds.Add(Cmds[currentIndex]);
+ currentIndex++;
+ }
+ result.Add(nonCallCmds);
+ }
+ }
+ if(result.Count == 0) {
+ result.Add(new List<Cmd>());
+ }
+ return result;
+ }
+
+ private Graph<SCC<Block>> ReachabilityGraphSCCsDAG;
+ private Dictionary<Block, SCC<Block>> BlockToSCC;
+
+ private Dictionary<SCC<Block>, HashSet<Block>> MayReachCache = new Dictionary<SCC<Block>, HashSet<Block>>();
+
+ public bool MayReach(Block src, Block dst) {
+ if (ReachabilityGraphSCCsDAG == null) {
+ if (CommandLineOptions.Clo.Trace) {
+ Console.WriteLine("Interprocedural reachability: computing SCCs");
+ }
+ Adjacency<Block> next = new Adjacency<Block>(reachabilityGraph.Successors);
+ Adjacency<Block> prev = new Adjacency<Block>(reachabilityGraph.Predecessors);
+ StronglyConnectedComponents<Block> ReachabilitySCCs = new StronglyConnectedComponents<Block>(
+ reachabilityGraph.Nodes, next, prev);
+ ReachabilitySCCs.Compute();
+
+ BlockToSCC = new Dictionary<Block, SCC<Block>>();
+ foreach (var scc in ReachabilitySCCs) {
+ foreach (var s in scc) {
+ BlockToSCC[s] = scc;
+ }
+ }
+
+ ReachabilityGraphSCCsDAG = new Graph<SCC<Block>>();
+ foreach (var edge in reachabilityGraph.Edges) {
+ if (BlockToSCC[edge.Item1] != BlockToSCC[edge.Item2]) {
+ ReachabilityGraphSCCsDAG.AddEdge(BlockToSCC[edge.Item1], BlockToSCC[edge.Item2]);
+ }
+ }
+
+ SCC<Block> dummy = new SCC<Block>();
+ foreach (var n in reachabilityGraph.Nodes) {
+ ReachabilityGraphSCCsDAG.AddEdge(BlockToSCC[n], dummy);
+ }
+
+ if (CommandLineOptions.Clo.Trace) {
+ Console.WriteLine("Interprocedural reachability: SCCs computed!");
+ }
+ }
+ return ReachableFrom(BlockToSCC[src]).Contains(dst);
+ }
+
+ private HashSet<Block> ReachableFrom(SCC<Block> scc) {
+ if (!MayReachCache.ContainsKey(scc)) {
+ HashSet<Block> result = new HashSet<Block>();
+ if (scc.Count() > 0) {
+ result.UnionWith(scc);
+ foreach (var nextSCC in ReachabilityGraphSCCsDAG.Successors(scc)) {
+ result.UnionWith(ReachableFrom(nextSCC));
+ }
+ }
+ MayReachCache[scc] = result;
+ }
+ return MayReachCache[scc];
+ }
+
+ public void dump() {
+ foreach(var n in nodes) {
+ Console.WriteLine(n.Label + " -> {");
+ GotoCmd gotoCmd = n.TransferCmd as GotoCmd;
+ if(n != null) {
+ foreach(Block m in gotoCmd.labelTargets) {
+ Console.WriteLine(" " + m.Label);
+ }
+ }
+ Console.WriteLine("}");
+ }
+ }
+
+ public Block GetNewEntryBlock(string proc) {
+ return newProcedureEntryNodes[proc];
+ }
+
+ public Block GetNewExitBlock(string proc) {
+ return newProcedureExitNodes[proc];
+ }
+
+ public Block GetNewBlock(Block b) {
+ return originalToNew[b];
+ }
+
+ }
+
+
+}
diff --git a/Source/Core/LambdaHelper.cs b/Source/Core/LambdaHelper.cs
index d07eaac6..a566daaf 100644
--- a/Source/Core/LambdaHelper.cs
+++ b/Source/Core/LambdaHelper.cs
@@ -1,259 +1,259 @@
-//-----------------------------------------------------------------------------
-//
-// 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;
- using System.Diagnostics.Contracts;
- using Set = GSet<object>; // for the purposes here, "object" really means "either Variable or TypeVariable"
-
- public static class LambdaHelper {
- public static Program Desugar(Program program, out List<Expr/*!*/>/*!*/ axioms, out List<Function/*!*/>/*!*/ functions) {
- Contract.Requires(program != null);
- Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out functions)));
- Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out axioms)));
- Contract.Ensures(Contract.Result<Program>() != null);
- LambdaVisitor v = new LambdaVisitor();
- program = v.VisitProgram(program);
- axioms = v.lambdaAxioms;
- functions = v.lambdaFunctions;
- if (CommandLineOptions.Clo.TraceVerify) {
- Console.WriteLine("Desugaring of lambda expressions produced {0} functions and {1} axioms:", functions.Count, axioms.Count);
- TokenTextWriter wr = new TokenTextWriter("<console>", Console.Out, /*pretty=*/ false);
- foreach (Function f in functions) {
- f.Emit(wr, 0);
- }
- foreach (Expr ax in axioms) {
- ax.Emit(wr);
- Console.WriteLine();
- }
- }
- return program;
- }
-
- public static void ExpandLambdas(Program prog) {
- Contract.Requires(prog != null);
- List<Expr/*!*/>/*!*/ axioms;
- List<Function/*!*/>/*!*/ functions;
-
- Desugar(prog, out axioms, out functions);
- foreach (var f in functions) {
- prog.AddTopLevelDeclaration(f);
- }
- foreach (var a in axioms) {
- prog.AddTopLevelDeclaration(new Axiom(a.tok, a));
- }
- }
-
- private class LambdaVisitor : StandardVisitor {
- private readonly Dictionary<Expr, FunctionCall> liftedLambdas =
- new Dictionary<Expr, FunctionCall>(new AlphaEquality());
-
- internal List<Expr/*!*/>/*!*/ lambdaAxioms = new List<Expr/*!*/>();
- internal List<Function/*!*/>/*!*/ lambdaFunctions = new List<Function/*!*/>();
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cce.NonNullElements(lambdaAxioms));
- Contract.Invariant(cce.NonNullElements(lambdaFunctions));
- }
-
- int lambdaid = 0;
-
- string FreshLambdaFunctionName()
- {
- // TODO(wuestholz): Should we use a counter per top-level declaration?
- return string.Format("lambda#{0}", lambdaid++);
- }
-
- public override Expr VisitLambdaExpr(LambdaExpr lambda) {
- var baseResult = base.VisitLambdaExpr(lambda);
- lambda = baseResult as LambdaExpr;
- if (lambda == null) {
- return baseResult; // apparently, the base visitor already turned the lambda into something else
- }
-
- // We start by getting rid of any use of "old" inside the lambda. This is done as follows.
- // For each variable "g" occurring inside lambda as "old(... g ...)", create a new name "og".
- // Replace each old occurrence of "g" with "og", removing the enclosing "old" wrappers.
- var oldFinder = new OldFinder();
- oldFinder.Visit(lambda);
- var oldSubst = new Dictionary<Variable, Expr>(); // g -> g0
- var callOldMapping = new Dictionary<Variable, Expr>(); // g0 -> old(g)
- foreach (var v in oldFinder.FreeOldVars) {
- var g = v as GlobalVariable;
- if (g != null) {
- var g0 = new GlobalVariable(g.tok, new TypedIdent(g.tok, g.TypedIdent.Name + "@old", g.TypedIdent.Type));
- oldSubst.Add(g, new IdentifierExpr(g0.tok, g0));
- callOldMapping.Add(g0, new OldExpr(g0.tok, new IdentifierExpr(g.tok, g)));
- }
- }
- var lambdaBody = Substituter.ApplyReplacingOldExprs(
- Substituter.SubstitutionFromHashtable(new Dictionary<Variable,Expr>()),
- Substituter.SubstitutionFromHashtable(oldSubst),
- lambda.Body);
- var lambdaAttrs = Substituter.ApplyReplacingOldExprs(
- Substituter.SubstitutionFromHashtable(new Dictionary<Variable, Expr>()),
- Substituter.SubstitutionFromHashtable(oldSubst),
- lambda.Attributes);
-
- if (0 < CommandLineOptions.Clo.VerifySnapshots && QKeyValue.FindStringAttribute(lambdaAttrs, "checksum") == null)
- {
- // Attach a dummy checksum to avoid issues in the dependency analysis.
- var checksumAttr = new QKeyValue(lambda.tok, "checksum", new List<object> { "stable" }, null);
- if (lambdaAttrs == null)
- {
- lambdaAttrs = checksumAttr;
- }
- else
- {
- lambdaAttrs.AddLast(checksumAttr);
- }
- }
-
- // this is ugly, the output will depend on hashing order
- var subst = new Dictionary<Variable, Expr>();
- var substFnAttrs = new Dictionary<Variable, Expr>();
- var formals = new List<Variable>();
- var callArgs = new List<Expr>();
- var axCallArgs = new List<Expr>();
- var dummies = new List<Variable>(lambda.Dummies);
- var freeTypeVars = new List<TypeVariable>();
- var fnTypeVarActuals = new List<Type/*!*/>();
- var freshTypeVars = new List<TypeVariable>(); // these are only used in the lambda@n function's definition
-
- // compute the free variables of the lambda expression, but with lambdaBody instead of lambda.Body
- Set freeVars = new Set();
- BinderExpr.ComputeBinderFreeVariables(lambda.TypeParameters, lambda.Dummies, lambdaBody, lambdaAttrs, freeVars);
-
- foreach (object o in freeVars) {
- // 'o' is either a Variable or a TypeVariable.
- if (o is Variable) {
- var v = o as Variable;
- var ti = new TypedIdent(v.TypedIdent.tok, v.TypedIdent.Name, v.TypedIdent.Type);
- var f = new Formal(v.tok, ti, true);
- formals.Add(f);
- substFnAttrs.Add(v, new IdentifierExpr(f.tok, f));
- var b = new BoundVariable(v.tok, ti);
- dummies.Add(b);
- if (callOldMapping.ContainsKey(v)) {
- callArgs.Add(callOldMapping[v]);
- } else {
- callArgs.Add(new IdentifierExpr(v.tok, v));
- }
- Expr id = new IdentifierExpr(b.tok, b);
- subst.Add(v, id);
- axCallArgs.Add(id);
- } else {
- var tv = (TypeVariable)o;
- freeTypeVars.Add(tv);
- fnTypeVarActuals.Add(tv);
- freshTypeVars.Add(new TypeVariable(tv.tok, tv.Name));
- }
- }
-
- var sw = new System.IO.StringWriter();
- var wr = new TokenTextWriter(sw, true);
- lambda.Emit(wr);
- string lam_str = sw.ToString();
-
- FunctionCall fcall;
- IToken tok = lambda.tok;
- Formal res = new Formal(tok, new TypedIdent(tok, TypedIdent.NoName, cce.NonNull(lambda.Type)), false);
-
- if (liftedLambdas.TryGetValue(lambda, out fcall)) {
- if (CommandLineOptions.Clo.TraceVerify) {
- Console.WriteLine("Old lambda: {0}", lam_str);
- }
- } else {
- if (CommandLineOptions.Clo.TraceVerify) {
- Console.WriteLine("New lambda: {0}", lam_str);
- }
- Function fn = new Function(tok, FreshLambdaFunctionName(), freshTypeVars, formals, res, "auto-generated lambda function",
- Substituter.Apply(Substituter.SubstitutionFromHashtable(substFnAttrs), lambdaAttrs));
-
- fcall = new FunctionCall(new IdentifierExpr(tok, fn.Name));
- fcall.Func = fn; // resolve here
- liftedLambdas[lambda] = fcall;
-
- List<Expr/*!*/> selectArgs = new List<Expr/*!*/>();
- foreach (Variable/*!*/ v in lambda.Dummies) {
- Contract.Assert(v != null);
- selectArgs.Add(new IdentifierExpr(v.tok, v));
- }
- NAryExpr axcall = new NAryExpr(tok, fcall, axCallArgs);
- axcall.Type = res.TypedIdent.Type;
- axcall.TypeParameters = SimpleTypeParamInstantiation.From(freeTypeVars, fnTypeVarActuals);
- NAryExpr select = Expr.Select(axcall, selectArgs);
- select.Type = lambdaBody.Type;
- List<Type/*!*/> selectTypeParamActuals = new List<Type/*!*/>();
- List<TypeVariable> forallTypeVariables = new List<TypeVariable>();
- foreach (TypeVariable/*!*/ tp in lambda.TypeParameters) {
- Contract.Assert(tp != null);
- selectTypeParamActuals.Add(tp);
- forallTypeVariables.Add(tp);
- }
- forallTypeVariables.AddRange(freeTypeVars);
- select.TypeParameters = SimpleTypeParamInstantiation.From(lambda.TypeParameters, selectTypeParamActuals);
-
- Expr bb = Substituter.Apply(Substituter.SubstitutionFromHashtable(subst), lambdaBody);
- NAryExpr body = Expr.Eq(select, bb);
- body.Type = Type.Bool;
- body.TypeParameters = SimpleTypeParamInstantiation.EMPTY;
- Trigger trig = new Trigger(select.tok, true, new List<Expr> { select });
-
- lambdaFunctions.Add(fn);
- lambdaAxioms.Add(new ForallExpr(tok, forallTypeVariables, dummies,
- Substituter.Apply(Substituter.SubstitutionFromHashtable(subst), lambdaAttrs),
- trig, body));
- }
-
- NAryExpr call = new NAryExpr(tok, fcall, callArgs);
- call.Type = res.TypedIdent.Type;
- call.TypeParameters = SimpleTypeParamInstantiation.From(freeTypeVars, fnTypeVarActuals);
-
- return call;
- }
- public override Cmd VisitCallCmd(CallCmd node) {
- var baseResult = base.VisitCallCmd(node);
- node = baseResult as CallCmd;
- if (node == null) {
- return baseResult; // apparently, the base visitor already turned the lambda into something else
- }
- // also visit the desugaring (which the StandardVisitor does not do)
- node.VisitDesugaring(this);
- return node;
- }
- }
- }
-
- class OldFinder : ReadOnlyVisitor
- {
- public readonly GSet<Variable> FreeOldVars = new GSet<Variable>();
- public override Expr VisitOldExpr(OldExpr node) {
- Set freeVars = new Set();
- node.Expr.ComputeFreeVariables(freeVars);
- foreach (var v in freeVars) {
- // Note, "v" is either a Variable or a TypeVariable
- if (v is Variable) {
- FreeOldVars.Add((Variable)v);
- }
- }
- return node; // don't visit subexpressions, since ComputeFreeVariables has already gone through those
- }
- public override BinderExpr VisitBinderExpr(BinderExpr node) {
- base.VisitBinderExpr(node);
- // visit attributes, even though StandardVisitor does not do that (but maybe it should?)
- if (node.Attributes != null) {
- this.Visit(node.Attributes);
- }
- return node;
- }
- }
-
-} // end namespace \ No newline at end of file
+//-----------------------------------------------------------------------------
+//
+// 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;
+ using System.Diagnostics.Contracts;
+ using Set = GSet<object>; // for the purposes here, "object" really means "either Variable or TypeVariable"
+
+ public static class LambdaHelper {
+ public static Program Desugar(Program program, out List<Expr/*!*/>/*!*/ axioms, out List<Function/*!*/>/*!*/ functions) {
+ Contract.Requires(program != null);
+ Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out functions)));
+ Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out axioms)));
+ Contract.Ensures(Contract.Result<Program>() != null);
+ LambdaVisitor v = new LambdaVisitor();
+ program = v.VisitProgram(program);
+ axioms = v.lambdaAxioms;
+ functions = v.lambdaFunctions;
+ if (CommandLineOptions.Clo.TraceVerify) {
+ Console.WriteLine("Desugaring of lambda expressions produced {0} functions and {1} axioms:", functions.Count, axioms.Count);
+ TokenTextWriter wr = new TokenTextWriter("<console>", Console.Out, /*pretty=*/ false);
+ foreach (Function f in functions) {
+ f.Emit(wr, 0);
+ }
+ foreach (Expr ax in axioms) {
+ ax.Emit(wr);
+ Console.WriteLine();
+ }
+ }
+ return program;
+ }
+
+ public static void ExpandLambdas(Program prog) {
+ Contract.Requires(prog != null);
+ List<Expr/*!*/>/*!*/ axioms;
+ List<Function/*!*/>/*!*/ functions;
+
+ Desugar(prog, out axioms, out functions);
+ foreach (var f in functions) {
+ prog.AddTopLevelDeclaration(f);
+ }
+ foreach (var a in axioms) {
+ prog.AddTopLevelDeclaration(new Axiom(a.tok, a));
+ }
+ }
+
+ private class LambdaVisitor : StandardVisitor {
+ private readonly Dictionary<Expr, FunctionCall> liftedLambdas =
+ new Dictionary<Expr, FunctionCall>(new AlphaEquality());
+
+ internal List<Expr/*!*/>/*!*/ lambdaAxioms = new List<Expr/*!*/>();
+ internal List<Function/*!*/>/*!*/ lambdaFunctions = new List<Function/*!*/>();
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(cce.NonNullElements(lambdaAxioms));
+ Contract.Invariant(cce.NonNullElements(lambdaFunctions));
+ }
+
+ int lambdaid = 0;
+
+ string FreshLambdaFunctionName()
+ {
+ return string.Format("lambda#{0}", lambdaid++);
+ }
+
+ public override Expr VisitLambdaExpr(LambdaExpr lambda) {
+ var baseResult = base.VisitLambdaExpr(lambda);
+ lambda = baseResult as LambdaExpr;
+ if (lambda == null) {
+ return baseResult; // apparently, the base visitor already turned the lambda into something else
+ }
+
+ // We start by getting rid of any use of "old" inside the lambda. This is done as follows.
+ // For each variable "g" occurring inside lambda as "old(... g ...)", create a new name "og".
+ // Replace each old occurrence of "g" with "og", removing the enclosing "old" wrappers.
+ var oldFinder = new OldFinder();
+ oldFinder.Visit(lambda);
+ var oldSubst = new Dictionary<Variable, Expr>(); // g -> g0
+ var callOldMapping = new Dictionary<Variable, Expr>(); // g0 -> old(g)
+ foreach (var v in oldFinder.FreeOldVars) {
+ var g = v as GlobalVariable;
+ if (g != null) {
+ var g0 = new GlobalVariable(g.tok, new TypedIdent(g.tok, g.TypedIdent.Name + "@old", g.TypedIdent.Type));
+ oldSubst.Add(g, new IdentifierExpr(g0.tok, g0));
+ callOldMapping.Add(g0, new OldExpr(g0.tok, new IdentifierExpr(g.tok, g)));
+ }
+ }
+ var lambdaBody = Substituter.ApplyReplacingOldExprs(
+ Substituter.SubstitutionFromHashtable(new Dictionary<Variable,Expr>()),
+ Substituter.SubstitutionFromHashtable(oldSubst),
+ lambda.Body);
+ var lambdaAttrs = Substituter.ApplyReplacingOldExprs(
+ Substituter.SubstitutionFromHashtable(new Dictionary<Variable, Expr>()),
+ Substituter.SubstitutionFromHashtable(oldSubst),
+ lambda.Attributes);
+
+ if (0 < CommandLineOptions.Clo.VerifySnapshots && QKeyValue.FindStringAttribute(lambdaAttrs, "checksum") == null)
+ {
+ // Attach a dummy checksum to avoid issues in the dependency analysis.
+ var checksumAttr = new QKeyValue(lambda.tok, "checksum", new List<object> { "lambda expression" }, null);
+ if (lambdaAttrs == null)
+ {
+ lambdaAttrs = checksumAttr;
+ }
+ else
+ {
+ lambdaAttrs.AddLast(checksumAttr);
+ }
+ }
+
+ // this is ugly, the output will depend on hashing order
+ var subst = new Dictionary<Variable, Expr>();
+ var substFnAttrs = new Dictionary<Variable, Expr>();
+ var formals = new List<Variable>();
+ var callArgs = new List<Expr>();
+ var axCallArgs = new List<Expr>();
+ var dummies = new List<Variable>(lambda.Dummies);
+ var freeTypeVars = new List<TypeVariable>();
+ var fnTypeVarActuals = new List<Type/*!*/>();
+ var freshTypeVars = new List<TypeVariable>(); // these are only used in the lambda@n function's definition
+
+ // compute the free variables of the lambda expression, but with lambdaBody instead of lambda.Body
+ Set freeVars = new Set();
+ BinderExpr.ComputeBinderFreeVariables(lambda.TypeParameters, lambda.Dummies, lambdaBody, lambdaAttrs, freeVars);
+
+ foreach (object o in freeVars) {
+ // 'o' is either a Variable or a TypeVariable.
+ if (o is Variable) {
+ var v = o as Variable;
+ var ti = new TypedIdent(v.TypedIdent.tok, v.TypedIdent.Name, v.TypedIdent.Type);
+ var f = new Formal(v.tok, ti, true);
+ formals.Add(f);
+ substFnAttrs.Add(v, new IdentifierExpr(f.tok, f));
+ var b = new BoundVariable(v.tok, ti);
+ dummies.Add(b);
+ if (callOldMapping.ContainsKey(v)) {
+ callArgs.Add(callOldMapping[v]);
+ } else {
+ callArgs.Add(new IdentifierExpr(v.tok, v));
+ }
+ Expr id = new IdentifierExpr(b.tok, b);
+ subst.Add(v, id);
+ axCallArgs.Add(id);
+ } else {
+ var tv = (TypeVariable)o;
+ freeTypeVars.Add(tv);
+ fnTypeVarActuals.Add(tv);
+ freshTypeVars.Add(new TypeVariable(tv.tok, tv.Name));
+ }
+ }
+
+ var sw = new System.IO.StringWriter();
+ var wr = new TokenTextWriter(sw, true);
+ lambda.Emit(wr);
+ string lam_str = sw.ToString();
+
+ FunctionCall fcall;
+ IToken tok = lambda.tok;
+ Formal res = new Formal(tok, new TypedIdent(tok, TypedIdent.NoName, cce.NonNull(lambda.Type)), false);
+
+ if (liftedLambdas.TryGetValue(lambda, out fcall)) {
+ if (CommandLineOptions.Clo.TraceVerify) {
+ Console.WriteLine("Old lambda: {0}", lam_str);
+ }
+ } else {
+ if (CommandLineOptions.Clo.TraceVerify) {
+ Console.WriteLine("New lambda: {0}", lam_str);
+ }
+ Function fn = new Function(tok, FreshLambdaFunctionName(), freshTypeVars, formals, res, "auto-generated lambda function",
+ Substituter.Apply(Substituter.SubstitutionFromHashtable(substFnAttrs), lambdaAttrs));
+ fn.OriginalLambdaExprAsString = lam_str;
+
+ fcall = new FunctionCall(new IdentifierExpr(tok, fn.Name));
+ fcall.Func = fn; // resolve here
+ liftedLambdas[lambda] = fcall;
+
+ List<Expr/*!*/> selectArgs = new List<Expr/*!*/>();
+ foreach (Variable/*!*/ v in lambda.Dummies) {
+ Contract.Assert(v != null);
+ selectArgs.Add(new IdentifierExpr(v.tok, v));
+ }
+ NAryExpr axcall = new NAryExpr(tok, fcall, axCallArgs);
+ axcall.Type = res.TypedIdent.Type;
+ axcall.TypeParameters = SimpleTypeParamInstantiation.From(freeTypeVars, fnTypeVarActuals);
+ NAryExpr select = Expr.Select(axcall, selectArgs);
+ select.Type = lambdaBody.Type;
+ List<Type/*!*/> selectTypeParamActuals = new List<Type/*!*/>();
+ List<TypeVariable> forallTypeVariables = new List<TypeVariable>();
+ foreach (TypeVariable/*!*/ tp in lambda.TypeParameters) {
+ Contract.Assert(tp != null);
+ selectTypeParamActuals.Add(tp);
+ forallTypeVariables.Add(tp);
+ }
+ forallTypeVariables.AddRange(freeTypeVars);
+ select.TypeParameters = SimpleTypeParamInstantiation.From(lambda.TypeParameters, selectTypeParamActuals);
+
+ Expr bb = Substituter.Apply(Substituter.SubstitutionFromHashtable(subst), lambdaBody);
+ NAryExpr body = Expr.Eq(select, bb);
+ body.Type = Type.Bool;
+ body.TypeParameters = SimpleTypeParamInstantiation.EMPTY;
+ Trigger trig = new Trigger(select.tok, true, new List<Expr> { select });
+
+ lambdaFunctions.Add(fn);
+ lambdaAxioms.Add(new ForallExpr(tok, forallTypeVariables, dummies,
+ Substituter.Apply(Substituter.SubstitutionFromHashtable(subst), lambdaAttrs),
+ trig, body));
+ }
+
+ NAryExpr call = new NAryExpr(tok, fcall, callArgs);
+ call.Type = res.TypedIdent.Type;
+ call.TypeParameters = SimpleTypeParamInstantiation.From(freeTypeVars, fnTypeVarActuals);
+
+ return call;
+ }
+ public override Cmd VisitCallCmd(CallCmd node) {
+ var baseResult = base.VisitCallCmd(node);
+ node = baseResult as CallCmd;
+ if (node == null) {
+ return baseResult; // apparently, the base visitor already turned the lambda into something else
+ }
+ // also visit the desugaring (which the StandardVisitor does not do)
+ node.VisitDesugaring(this);
+ return node;
+ }
+ }
+ }
+
+ class OldFinder : ReadOnlyVisitor
+ {
+ public readonly GSet<Variable> FreeOldVars = new GSet<Variable>();
+ public override Expr VisitOldExpr(OldExpr node) {
+ Set freeVars = new Set();
+ node.Expr.ComputeFreeVariables(freeVars);
+ foreach (var v in freeVars) {
+ // Note, "v" is either a Variable or a TypeVariable
+ if (v is Variable) {
+ FreeOldVars.Add((Variable)v);
+ }
+ }
+ return node; // don't visit subexpressions, since ComputeFreeVariables has already gone through those
+ }
+ public override BinderExpr VisitBinderExpr(BinderExpr node) {
+ base.VisitBinderExpr(node);
+ // visit attributes, even though StandardVisitor does not do that (but maybe it should?)
+ if (node.Attributes != null) {
+ this.Visit(node.Attributes);
+ }
+ return node;
+ }
+ }
+
+} // end namespace
diff --git a/Source/Core/LoopUnroll.cs b/Source/Core/LoopUnroll.cs
index df1be84c..036d5f73 100644
--- a/Source/Core/LoopUnroll.cs
+++ b/Source/Core/LoopUnroll.cs
@@ -1,286 +1,286 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System.Diagnostics.Contracts;
-using System.Collections.Generic;
-using Bpl = Microsoft.Boogie;
-using Microsoft.Boogie.GraphUtil;
-
-namespace Microsoft.Boogie {
- public class LoopUnroll {
- public static List<Block/*!*/>/*!*/ UnrollLoops(Block start, int unrollMaxDepth, bool soundLoopUnrolling) {
- Contract.Requires(start != null);
-
- Contract.Requires(0 <= unrollMaxDepth);
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<Block>>()));
- Dictionary<Block, GraphNode/*!*/> gd = new Dictionary<Block, GraphNode/*!*/>();
- HashSet<Block> beingVisited = new HashSet<Block>();
- GraphNode gStart = GraphNode.ComputeGraphInfo(null, start, gd, beingVisited);
-
- // Compute SCCs
- StronglyConnectedComponents<GraphNode/*!*/> sccs =
- new StronglyConnectedComponents<GraphNode/*!*/>(gd.Values, Preds, Succs);
- Contract.Assert(sccs != null);
- sccs.Compute();
- Dictionary<GraphNode/*!*/, SCC<GraphNode/*!*/>> containingSCC = new Dictionary<GraphNode/*!*/, SCC<GraphNode/*!*/>>();
- foreach (SCC<GraphNode/*!*/> scc in sccs) {
- foreach (GraphNode/*!*/ n in scc) {
- Contract.Assert(n != null);
- containingSCC[n] = scc;
- }
- }
-
- LoopUnroll lu = new LoopUnroll(unrollMaxDepth, soundLoopUnrolling, containingSCC, new List<Block/*!*/>());
- lu.Visit(gStart);
- lu.newBlockSeqGlobal.Reverse();
- return lu.newBlockSeqGlobal;
- }
-
- // This is supposed to "undo" to effect of loop unrolling
- // on block labels. It essentially removes the "#num" from the end
- // of lab, if there is something like this
- public static string sanitizeLabel(string lab)
- {
- if (!lab.Contains("#"))
- return lab;
-
- // Find the last occurrance of "#"
- int pos = lab.LastIndexOf('#');
-
- return lab.Substring(0, pos);
- }
-
- private static System.Collections.IEnumerable/*<GraphNode/*!>/*!*/ Succs(GraphNode n) {
- Contract.Requires(n != null);
- Contract.Ensures(Contract.Result<System.Collections.IEnumerable>() != null);
-
- List<GraphNode/*!*/>/*!*/ AllEdges = new List<GraphNode/*!*/>();
- AllEdges.AddRange(n.ForwardEdges);
- AllEdges.AddRange(n.BackEdges);
- return AllEdges;
- }
- private static System.Collections.IEnumerable/*<GraphNode!>*//*!*/ Preds(GraphNode n) {
- Contract.Requires(n != null);
- Contract.Ensures(Contract.Result<System.Collections.IEnumerable>() != null);
-
- return n.Predecessors;
- }
-
- class GraphNode {
- public readonly Block/*!*/ Block;
- public readonly List<Cmd>/*!*/ Body;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(Block != null);
- Contract.Invariant(Body != null);
- Contract.Invariant(cce.NonNullElements(ForwardEdges));
- Contract.Invariant(cce.NonNullElements(BackEdges));
- Contract.Invariant(cce.NonNullElements(Predecessors));
- Contract.Invariant(isCutPoint == (BackEdges.Count != 0));
- }
-
- bool isCutPoint; // is set during ComputeGraphInfo
- public bool IsCutPoint {
- get {
- return isCutPoint;
- }
- }
- [Rep]
- public readonly List<GraphNode/*!*/>/*!*/ ForwardEdges = new List<GraphNode/*!*/>();
- [Rep]
- public readonly List<GraphNode/*!*/>/*!*/ BackEdges = new List<GraphNode/*!*/>();
- [Rep]
- public readonly List<GraphNode/*!*/>/*!*/ Predecessors = new List<GraphNode/*!*/>();
-
- GraphNode(Block b, List<Cmd> body) {
- Contract.Requires(body != null);
- Contract.Requires(b != null);
- this.Block = b;
- this.Body = body;
- }
-
- static List<Cmd> GetOptimizedBody(List<Cmd> cmds) {
- Contract.Requires(cmds != null);
- Contract.Ensures(Contract.Result<List<Cmd>>() != null);
- int n = 0;
- foreach (Cmd c in cmds) {
- n++;
- PredicateCmd pc = c as PredicateCmd;
- if (pc != null && pc.Expr is LiteralExpr && ((LiteralExpr)pc.Expr).IsFalse) {
- // return a sequence consisting of the commands seen so far
- Cmd[] s = new Cmd[n];
- for (int i = 0; i < n; i++) {
- s[i] = cmds[i];
- }
- return new List<Cmd>(s);
- }
- }
- return cmds;
- }
-
- public static GraphNode ComputeGraphInfo(GraphNode from, Block b, Dictionary<Block/*!*/, GraphNode/*!*/>/*!*/ gd, HashSet<Block> beingVisited) {
- Contract.Requires(beingVisited != null);
- Contract.Requires(b != null);
- Contract.Requires(cce.NonNullDictionaryAndValues(gd));
- Contract.Ensures(Contract.Result<GraphNode>() != null);
- GraphNode g;
- if (gd.TryGetValue(b, out g)) {
- Contract.Assume(from != null);
- Contract.Assert(g != null);
- if (beingVisited.Contains(b)) {
- // it's a cut point
- g.isCutPoint = true;
- from.BackEdges.Add(g);
- g.Predecessors.Add(from);
- } else {
- from.ForwardEdges.Add(g);
- g.Predecessors.Add(from);
- }
-
- } else {
- List<Cmd> body = GetOptimizedBody(b.Cmds);
- g = new GraphNode(b, body);
- gd.Add(b, g);
- if (from != null) {
- from.ForwardEdges.Add(g);
- g.Predecessors.Add(from);
- }
-
- if (body != b.Cmds) {
- // the body was optimized -- there is no way through this block
- } else {
- beingVisited.Add(b);
-
- GotoCmd gcmd = b.TransferCmd as GotoCmd;
- if (gcmd != null) {
- Contract.Assume(gcmd.labelTargets != null);
- foreach (Block/*!*/ succ in gcmd.labelTargets) {
- Contract.Assert(succ != null);
- ComputeGraphInfo(g, succ, gd, beingVisited);
- }
- }
-
- beingVisited.Remove(b);
- }
- }
- return g;
- }
- }
-
- readonly List<Block/*!*/>/*!*/ newBlockSeqGlobal;
- readonly Dictionary<GraphNode/*!*/, SCC<GraphNode/*!*/>>/*!*/ containingSCC;
- readonly int c;
- readonly bool soundLoopUnrolling;
- readonly LoopUnroll next;
- readonly LoopUnroll/*!*/ head;
-
- Dictionary<Block, Block/*!*/>/*!*/ newBlocks = new Dictionary<Block, Block/*!*/>();
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(head != null);
- Contract.Invariant(cce.NonNullElements(newBlockSeqGlobal));
- Contract.Invariant(newBlocks != null && cce.NonNullElements(newBlocks.Values));
- }
-
-
- [NotDelayed]
- private LoopUnroll(int unrollMaxDepth, bool soundLoopUnrolling, Dictionary<GraphNode/*!*/, SCC<GraphNode/*!*/>>/*!*/ scc, List<Block/*!*/>/*!*/ newBlockSeqGlobal)
- : base() {
- Contract.Requires(cce.NonNullElements(newBlockSeqGlobal));
- Contract.Requires(cce.NonNullDictionaryAndValues(scc) && Contract.ForAll(scc.Values, v => cce.NonNullElements(v)));
- Contract.Requires(0 <= unrollMaxDepth);
- this.newBlockSeqGlobal = newBlockSeqGlobal;
- this.c = unrollMaxDepth;
- this.containingSCC = scc;
- this.head = this;
- if (unrollMaxDepth != 0) {
- next = new LoopUnroll(unrollMaxDepth - 1, soundLoopUnrolling, scc, newBlockSeqGlobal, this);
- }
- }
-
- private LoopUnroll(int unrollMaxDepth, bool soundLoopUnrolling, Dictionary<GraphNode/*!*/, SCC<GraphNode/*!*/>> scc, List<Block/*!*/>/*!*/ newBlockSeqGlobal, LoopUnroll head) {
- Contract.Requires(head != null);
- Contract.Requires(cce.NonNullDictionaryAndValues(scc));
- Contract.Requires(cce.NonNullElements(newBlockSeqGlobal));
- Contract.Requires(0 <= unrollMaxDepth);
- this.newBlockSeqGlobal = newBlockSeqGlobal;
- this.c = unrollMaxDepth;
- this.soundLoopUnrolling = soundLoopUnrolling;
- this.containingSCC = scc;
- this.head = head;
- if (unrollMaxDepth != 0) {
- next = new LoopUnroll(unrollMaxDepth - 1, soundLoopUnrolling, scc, newBlockSeqGlobal, head);
- }
- }
-
- Block Visit(GraphNode node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Block>() != null);
- Block orig = node.Block;
- Block nw;
- if (newBlocks.TryGetValue(orig, out nw)) {
- Contract.Assert(nw != null);
-
- } else {
- List<Cmd> body;
- TransferCmd tcmd;
- Contract.Assert(orig.TransferCmd != null);
-
- if (next == null && node.IsCutPoint) {
- // as the body, use the assert/assume commands that make up the loop invariant
- body = new List<Cmd>();
- foreach (Cmd/*!*/ c in node.Body) {
- Contract.Assert(c != null);
- if (c is PredicateCmd || c is CommentCmd) {
- body.Add(c);
- } else {
- break;
- }
- }
- if (soundLoopUnrolling) {
- body.Add(new AssertCmd(orig.tok, Bpl.Expr.False));
- } else {
- body.Add(new AssumeCmd(orig.tok, Bpl.Expr.False));
- }
- tcmd = new ReturnCmd(orig.TransferCmd.tok);
-
- } else {
- body = node.Body;
- List<Block> newSuccs = new List<Block>();
-
- foreach (GraphNode succ in node.ForwardEdges) {
- Block s;
- if (containingSCC[node] == containingSCC[succ]) {
- s = Visit(succ);
- } else {
- Contract.Assert(head != null); // follows from object invariant
- s = head.Visit(succ);
- }
- newSuccs.Add(s);
- }
-
- Contract.Assert(next != null || node.BackEdges.Count == 0); // follows from if-else test above and the GraphNode invariant
- foreach (GraphNode succ in node.BackEdges) {
- Contract.Assert(next != null); // since if we get here, node.BackEdges.Count != 0
- Block s = next.Visit(succ);
- newSuccs.Add(s);
- }
-
- if (newSuccs.Count == 0) {
- tcmd = new ReturnCmd(orig.TransferCmd.tok);
- } else {
- tcmd = new GotoCmd(orig.TransferCmd.tok, newSuccs);
- }
- }
-
- nw = new Block(orig.tok, orig.Label + "#" + this.c, body, tcmd);
- newBlocks.Add(orig, nw);
- newBlockSeqGlobal.Add(nw);
- }
-
- return nw;
- }
- }
-}
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+using System.Diagnostics.Contracts;
+using System.Collections.Generic;
+using Bpl = Microsoft.Boogie;
+using Microsoft.Boogie.GraphUtil;
+
+namespace Microsoft.Boogie {
+ public class LoopUnroll {
+ public static List<Block/*!*/>/*!*/ UnrollLoops(Block start, int unrollMaxDepth, bool soundLoopUnrolling) {
+ Contract.Requires(start != null);
+
+ Contract.Requires(0 <= unrollMaxDepth);
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<Block>>()));
+ Dictionary<Block, GraphNode/*!*/> gd = new Dictionary<Block, GraphNode/*!*/>();
+ HashSet<Block> beingVisited = new HashSet<Block>();
+ GraphNode gStart = GraphNode.ComputeGraphInfo(null, start, gd, beingVisited);
+
+ // Compute SCCs
+ StronglyConnectedComponents<GraphNode/*!*/> sccs =
+ new StronglyConnectedComponents<GraphNode/*!*/>(gd.Values, Preds, Succs);
+ Contract.Assert(sccs != null);
+ sccs.Compute();
+ Dictionary<GraphNode/*!*/, SCC<GraphNode/*!*/>> containingSCC = new Dictionary<GraphNode/*!*/, SCC<GraphNode/*!*/>>();
+ foreach (SCC<GraphNode/*!*/> scc in sccs) {
+ foreach (GraphNode/*!*/ n in scc) {
+ Contract.Assert(n != null);
+ containingSCC[n] = scc;
+ }
+ }
+
+ LoopUnroll lu = new LoopUnroll(unrollMaxDepth, soundLoopUnrolling, containingSCC, new List<Block/*!*/>());
+ lu.Visit(gStart);
+ lu.newBlockSeqGlobal.Reverse();
+ return lu.newBlockSeqGlobal;
+ }
+
+ // This is supposed to "undo" to effect of loop unrolling
+ // on block labels. It essentially removes the "#num" from the end
+ // of lab, if there is something like this
+ public static string sanitizeLabel(string lab)
+ {
+ if (!lab.Contains("#"))
+ return lab;
+
+ // Find the last occurrance of "#"
+ int pos = lab.LastIndexOf('#');
+
+ return lab.Substring(0, pos);
+ }
+
+ private static System.Collections.IEnumerable/*<GraphNode/*!>/*!*/ Succs(GraphNode n) {
+ Contract.Requires(n != null);
+ Contract.Ensures(Contract.Result<System.Collections.IEnumerable>() != null);
+
+ List<GraphNode/*!*/>/*!*/ AllEdges = new List<GraphNode/*!*/>();
+ AllEdges.AddRange(n.ForwardEdges);
+ AllEdges.AddRange(n.BackEdges);
+ return AllEdges;
+ }
+ private static System.Collections.IEnumerable/*<GraphNode!>*//*!*/ Preds(GraphNode n) {
+ Contract.Requires(n != null);
+ Contract.Ensures(Contract.Result<System.Collections.IEnumerable>() != null);
+
+ return n.Predecessors;
+ }
+
+ class GraphNode {
+ public readonly Block/*!*/ Block;
+ public readonly List<Cmd>/*!*/ Body;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(Block != null);
+ Contract.Invariant(Body != null);
+ Contract.Invariant(cce.NonNullElements(ForwardEdges));
+ Contract.Invariant(cce.NonNullElements(BackEdges));
+ Contract.Invariant(cce.NonNullElements(Predecessors));
+ Contract.Invariant(isCutPoint == (BackEdges.Count != 0));
+ }
+
+ bool isCutPoint; // is set during ComputeGraphInfo
+ public bool IsCutPoint {
+ get {
+ return isCutPoint;
+ }
+ }
+ [Rep]
+ public readonly List<GraphNode/*!*/>/*!*/ ForwardEdges = new List<GraphNode/*!*/>();
+ [Rep]
+ public readonly List<GraphNode/*!*/>/*!*/ BackEdges = new List<GraphNode/*!*/>();
+ [Rep]
+ public readonly List<GraphNode/*!*/>/*!*/ Predecessors = new List<GraphNode/*!*/>();
+
+ GraphNode(Block b, List<Cmd> body) {
+ Contract.Requires(body != null);
+ Contract.Requires(b != null);
+ this.Block = b;
+ this.Body = body;
+ }
+
+ static List<Cmd> GetOptimizedBody(List<Cmd> cmds) {
+ Contract.Requires(cmds != null);
+ Contract.Ensures(Contract.Result<List<Cmd>>() != null);
+ int n = 0;
+ foreach (Cmd c in cmds) {
+ n++;
+ PredicateCmd pc = c as PredicateCmd;
+ if (pc != null && pc.Expr is LiteralExpr && ((LiteralExpr)pc.Expr).IsFalse) {
+ // return a sequence consisting of the commands seen so far
+ Cmd[] s = new Cmd[n];
+ for (int i = 0; i < n; i++) {
+ s[i] = cmds[i];
+ }
+ return new List<Cmd>(s);
+ }
+ }
+ return cmds;
+ }
+
+ public static GraphNode ComputeGraphInfo(GraphNode from, Block b, Dictionary<Block/*!*/, GraphNode/*!*/>/*!*/ gd, HashSet<Block> beingVisited) {
+ Contract.Requires(beingVisited != null);
+ Contract.Requires(b != null);
+ Contract.Requires(cce.NonNullDictionaryAndValues(gd));
+ Contract.Ensures(Contract.Result<GraphNode>() != null);
+ GraphNode g;
+ if (gd.TryGetValue(b, out g)) {
+ Contract.Assume(from != null);
+ Contract.Assert(g != null);
+ if (beingVisited.Contains(b)) {
+ // it's a cut point
+ g.isCutPoint = true;
+ from.BackEdges.Add(g);
+ g.Predecessors.Add(from);
+ } else {
+ from.ForwardEdges.Add(g);
+ g.Predecessors.Add(from);
+ }
+
+ } else {
+ List<Cmd> body = GetOptimizedBody(b.Cmds);
+ g = new GraphNode(b, body);
+ gd.Add(b, g);
+ if (from != null) {
+ from.ForwardEdges.Add(g);
+ g.Predecessors.Add(from);
+ }
+
+ if (body != b.Cmds) {
+ // the body was optimized -- there is no way through this block
+ } else {
+ beingVisited.Add(b);
+
+ GotoCmd gcmd = b.TransferCmd as GotoCmd;
+ if (gcmd != null) {
+ Contract.Assume(gcmd.labelTargets != null);
+ foreach (Block/*!*/ succ in gcmd.labelTargets) {
+ Contract.Assert(succ != null);
+ ComputeGraphInfo(g, succ, gd, beingVisited);
+ }
+ }
+
+ beingVisited.Remove(b);
+ }
+ }
+ return g;
+ }
+ }
+
+ readonly List<Block/*!*/>/*!*/ newBlockSeqGlobal;
+ readonly Dictionary<GraphNode/*!*/, SCC<GraphNode/*!*/>>/*!*/ containingSCC;
+ readonly int c;
+ readonly bool soundLoopUnrolling;
+ readonly LoopUnroll next;
+ readonly LoopUnroll/*!*/ head;
+
+ Dictionary<Block, Block/*!*/>/*!*/ newBlocks = new Dictionary<Block, Block/*!*/>();
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(head != null);
+ Contract.Invariant(cce.NonNullElements(newBlockSeqGlobal));
+ Contract.Invariant(newBlocks != null && cce.NonNullElements(newBlocks.Values));
+ }
+
+
+ [NotDelayed]
+ private LoopUnroll(int unrollMaxDepth, bool soundLoopUnrolling, Dictionary<GraphNode/*!*/, SCC<GraphNode/*!*/>>/*!*/ scc, List<Block/*!*/>/*!*/ newBlockSeqGlobal)
+ : base() {
+ Contract.Requires(cce.NonNullElements(newBlockSeqGlobal));
+ Contract.Requires(cce.NonNullDictionaryAndValues(scc) && Contract.ForAll(scc.Values, v => cce.NonNullElements(v)));
+ Contract.Requires(0 <= unrollMaxDepth);
+ this.newBlockSeqGlobal = newBlockSeqGlobal;
+ this.c = unrollMaxDepth;
+ this.containingSCC = scc;
+ this.head = this;
+ if (unrollMaxDepth != 0) {
+ next = new LoopUnroll(unrollMaxDepth - 1, soundLoopUnrolling, scc, newBlockSeqGlobal, this);
+ }
+ }
+
+ private LoopUnroll(int unrollMaxDepth, bool soundLoopUnrolling, Dictionary<GraphNode/*!*/, SCC<GraphNode/*!*/>> scc, List<Block/*!*/>/*!*/ newBlockSeqGlobal, LoopUnroll head) {
+ Contract.Requires(head != null);
+ Contract.Requires(cce.NonNullDictionaryAndValues(scc));
+ Contract.Requires(cce.NonNullElements(newBlockSeqGlobal));
+ Contract.Requires(0 <= unrollMaxDepth);
+ this.newBlockSeqGlobal = newBlockSeqGlobal;
+ this.c = unrollMaxDepth;
+ this.soundLoopUnrolling = soundLoopUnrolling;
+ this.containingSCC = scc;
+ this.head = head;
+ if (unrollMaxDepth != 0) {
+ next = new LoopUnroll(unrollMaxDepth - 1, soundLoopUnrolling, scc, newBlockSeqGlobal, head);
+ }
+ }
+
+ Block Visit(GraphNode node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Block>() != null);
+ Block orig = node.Block;
+ Block nw;
+ if (newBlocks.TryGetValue(orig, out nw)) {
+ Contract.Assert(nw != null);
+
+ } else {
+ List<Cmd> body;
+ TransferCmd tcmd;
+ Contract.Assert(orig.TransferCmd != null);
+
+ if (next == null && node.IsCutPoint) {
+ // as the body, use the assert/assume commands that make up the loop invariant
+ body = new List<Cmd>();
+ foreach (Cmd/*!*/ c in node.Body) {
+ Contract.Assert(c != null);
+ if (c is PredicateCmd || c is CommentCmd) {
+ body.Add(c);
+ } else {
+ break;
+ }
+ }
+ if (soundLoopUnrolling) {
+ body.Add(new AssertCmd(orig.tok, Bpl.Expr.False));
+ } else {
+ body.Add(new AssumeCmd(orig.tok, Bpl.Expr.False));
+ }
+ tcmd = new ReturnCmd(orig.TransferCmd.tok);
+
+ } else {
+ body = node.Body;
+ List<Block> newSuccs = new List<Block>();
+
+ foreach (GraphNode succ in node.ForwardEdges) {
+ Block s;
+ if (containingSCC[node] == containingSCC[succ]) {
+ s = Visit(succ);
+ } else {
+ Contract.Assert(head != null); // follows from object invariant
+ s = head.Visit(succ);
+ }
+ newSuccs.Add(s);
+ }
+
+ Contract.Assert(next != null || node.BackEdges.Count == 0); // follows from if-else test above and the GraphNode invariant
+ foreach (GraphNode succ in node.BackEdges) {
+ Contract.Assert(next != null); // since if we get here, node.BackEdges.Count != 0
+ Block s = next.Visit(succ);
+ newSuccs.Add(s);
+ }
+
+ if (newSuccs.Count == 0) {
+ tcmd = new ReturnCmd(orig.TransferCmd.tok);
+ } else {
+ tcmd = new GotoCmd(orig.TransferCmd.tok, newSuccs);
+ }
+ }
+
+ nw = new Block(orig.tok, orig.Label + "#" + this.c, body, tcmd);
+ newBlocks.Add(orig, nw);
+ newBlockSeqGlobal.Add(nw);
+ }
+
+ return nw;
+ }
+ }
+}
diff --git a/Source/Core/Makefile b/Source/Core/Makefile
index 4d3f433a..2b0cf4e6 100644
--- a/Source/Core/Makefile
+++ b/Source/Core/Makefile
@@ -1,20 +1,20 @@
-COCO = Coco.exe
-
-# ###############################################################################
-# The frame files are no longer in this directory. They must be downloaded
-# from http://boogiepartners.codeplex.com/. Update the FRAME_DIR variable to
-# point to whatever directory you install that into.
-# ###############################################################################
-FRAME_DIR = ..\..\..\boogiepartners\CocoR\Modified
-
-# "all" depends on 2 files, really (Parser.cs and Scanner.cs), but they
-# are both generated in one go and I don't know a better way to tell
-# nmake that. --KRML
-all: Parser.cs
-
-Parser.cs: $(FRAME_DIR)\Scanner.frame $(FRAME_DIR)\Parser.frame BoogiePL.atg
- $(COCO) BoogiePL.atg -namespace Microsoft.Boogie -frames $(FRAME_DIR)
-
-clean:
- if exist Scanner.cs del Scanner.cs
- if exist Parser.cs del Parser.cs
+COCO = Coco.exe
+
+# ###############################################################################
+# The frame files are no longer in this directory. They must be downloaded
+# from https://github.com/boogie-org/boogie-partners . Update the FRAME_DIR variable to
+# point to whatever directory you install that into.
+# ###############################################################################
+FRAME_DIR = ..\..\..\boogiepartners\CocoR\Modified
+
+# "all" depends on 2 files, really (Parser.cs and Scanner.cs), but they
+# are both generated in one go and I don't know a better way to tell
+# nmake that. --KRML
+all: Parser.cs
+
+Parser.cs: $(FRAME_DIR)\Scanner.frame $(FRAME_DIR)\Parser.frame BoogiePL.atg
+ $(COCO) BoogiePL.atg -namespace Microsoft.Boogie -frames $(FRAME_DIR)
+
+clean:
+ if exist Scanner.cs del Scanner.cs
+ if exist Parser.cs del Parser.cs
diff --git a/Source/Core/OOLongUtil.cs b/Source/Core/OOLongUtil.cs
index 0d7bfc35..767b64a1 100644
--- a/Source/Core/OOLongUtil.cs
+++ b/Source/Core/OOLongUtil.cs
@@ -1,210 +1,210 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Diagnostics.Contracts;
-
-namespace Boogie.Util {
- public class TeeWriter : TextWriter {
- readonly TextWriter/*!*/ a;
- readonly TextWriter/*!*/ b;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(a != null);
- Contract.Invariant(b != null);
- }
-
-
- public TeeWriter(TextWriter a, TextWriter b) {
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- this.a = a;
- this.b = b;
- }
-
- public override System.Text.Encoding Encoding {
- get {
- return a.Encoding;
- }
- }
-
- public override void Close() {
- a.Close();
- b.Close();
- }
-
- public override void Flush() {
- a.Flush();
- b.Flush();
- }
-
- [Pure]
- public override string ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- return "<TeeWriter: " + a.ToString() + ", " + b.ToString() + ">";
- }
-
- public override void Write(char ch) {
- a.Write(ch);
- b.Write(ch);
- }
-
- public override void Write(string s) {
- a.Write(s);
- b.Write(s);
- }
- }
-
- /// <summary>
- /// A LineReader is a class that allows further subclasses to just override the ReadLine() method.
- /// It simply reads from the given "reader".
- /// </summary>
- public class LineReader : TextReader {
- [Rep]
- readonly TextReader/*!*/ reader;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(reader != null);
- Contract.Invariant(readAhead == null || (0 <= readAheadConsumed && readAheadConsumed < readAhead.Length));
- }
-
- string readAhead;
- int readAheadConsumed;
-
-
- public LineReader([Captured] TextReader reader) {
- Contract.Requires(reader != null);
- this.reader = reader;
- }
- public override void Close() {
- cce.BeginExpose(this);
- {
- reader.Close();
- }
- cce.EndExpose();
- }
- public override int Read() {
- cce.BeginExpose(this);
- try {
- while (readAhead == null) {
- readAhead = reader.ReadLine();
- if (readAhead == null) {
- // we're at EOF
- return -1;
- } else if (readAhead.Length > 0) {
- readAheadConsumed = 0;
- break;
- }
- }
- int res = readAhead[readAheadConsumed++];
- if (readAheadConsumed == readAhead.Length) {
- readAhead = null;
- }
- return res;
- } finally {
- cce.EndExpose();
- }
- }
- public override int Read(char[] buffer, int index, int count) {
-
- int n = 0;
- for (; n < count; n++) {
- int ch = Read();
- if (ch == -1) {
- break;
- }
- buffer[index + n] = (char)ch;
- }
- return n;
- }
- public override string ReadLine() {
- string res;
- if (readAhead != null) {
- cce.BeginExpose(this);
- {
- res = readAhead.Substring(readAheadConsumed);
- readAhead = null;
- }
- cce.EndExpose();
- } else {
- res = reader.ReadLine();
- }
- return res;
- }
- }
-
- public class IfdefReader : LineReader {
- [Rep]
- readonly List<string/*!*/>/*!*/ defines;
- [Rep]
- readonly List<bool>/*!*/ readState = new List<bool>();
- int ignoreCutoff = 0; // 0 means we're not ignoring
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(readState != null);
- Contract.Invariant(cce.NonNullElements(defines));
- Contract.Invariant(0 <= ignoreCutoff && ignoreCutoff <= readState.Count);
- }
-
-
-
- public IfdefReader([Captured] TextReader reader, [Captured] List<string/*!*/>/*!*/ defines)
- : base(reader) {
- Contract.Requires(reader != null);
- Contract.Requires(cce.NonNullElements(defines));
- this.defines = defines;
- }
-
- public override string ReadLine() {
- while (true) {
- string s = base.ReadLine();
- if (s == null) {
- return s;
- }
- string t = s.Trim();
- if (t.StartsWith("#if")) {
- string arg = t.Substring(3).TrimStart();
- bool sense = true;
- while (t.StartsWith("!")) {
- sense = !sense;
- t = t.Substring(1).TrimStart();
- }
- // push "true", since we're in a "then" branch
- readState.Add(true);
- if (ignoreCutoff == 0 && defines.Contains(arg) != sense) {
- ignoreCutoff = readState.Count; // start ignoring
- }
- } else if (t == "#else") {
- if (readState.Count == 0 || !readState[readState.Count - 1]) {
- return s; // malformed input; return the read line as if it were not special
- }
- // change the "true" to a "false" on top of the state, since we're now going into the "else" branch
- readState[readState.Count - 1] = false;
- if (ignoreCutoff == 0) {
- // the "then" branch had been included, so we'll ignore the "else" branch
- ignoreCutoff = readState.Count;
- } else if (ignoreCutoff == readState.Count) {
- // we had ignored the "then" branch, so we'll include the "else" branch
- ignoreCutoff = 0;
- }
- } else if (t == "#endif") {
- if (readState.Count == 0) {
- return s; // malformed input; return the read line as if it were not special
- }
- if (ignoreCutoff == readState.Count) {
- // we had ignored the branch that ends here; so, now we start including again
- ignoreCutoff = 0;
- }
- // pop
- readState.RemoveAt(readState.Count - 1);
- } else if (ignoreCutoff == 0) {
- return s;
- }
- }
- }
- }
-}
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Diagnostics.Contracts;
+
+namespace Boogie.Util {
+ public class TeeWriter : TextWriter {
+ readonly TextWriter/*!*/ a;
+ readonly TextWriter/*!*/ b;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(a != null);
+ Contract.Invariant(b != null);
+ }
+
+
+ public TeeWriter(TextWriter a, TextWriter b) {
+ Contract.Requires(b != null);
+ Contract.Requires(a != null);
+ this.a = a;
+ this.b = b;
+ }
+
+ public override System.Text.Encoding Encoding {
+ get {
+ return a.Encoding;
+ }
+ }
+
+ public override void Close() {
+ a.Close();
+ b.Close();
+ }
+
+ public override void Flush() {
+ a.Flush();
+ b.Flush();
+ }
+
+ [Pure]
+ public override string ToString() {
+ Contract.Ensures(Contract.Result<string>() != null);
+ return "<TeeWriter: " + a.ToString() + ", " + b.ToString() + ">";
+ }
+
+ public override void Write(char ch) {
+ a.Write(ch);
+ b.Write(ch);
+ }
+
+ public override void Write(string s) {
+ a.Write(s);
+ b.Write(s);
+ }
+ }
+
+ /// <summary>
+ /// A LineReader is a class that allows further subclasses to just override the ReadLine() method.
+ /// It simply reads from the given "reader".
+ /// </summary>
+ public class LineReader : TextReader {
+ [Rep]
+ readonly TextReader/*!*/ reader;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(reader != null);
+ Contract.Invariant(readAhead == null || (0 <= readAheadConsumed && readAheadConsumed < readAhead.Length));
+ }
+
+ string readAhead;
+ int readAheadConsumed;
+
+
+ public LineReader([Captured] TextReader reader) {
+ Contract.Requires(reader != null);
+ this.reader = reader;
+ }
+ public override void Close() {
+ cce.BeginExpose(this);
+ {
+ reader.Close();
+ }
+ cce.EndExpose();
+ }
+ public override int Read() {
+ cce.BeginExpose(this);
+ try {
+ while (readAhead == null) {
+ readAhead = reader.ReadLine();
+ if (readAhead == null) {
+ // we're at EOF
+ return -1;
+ } else if (readAhead.Length > 0) {
+ readAheadConsumed = 0;
+ break;
+ }
+ }
+ int res = readAhead[readAheadConsumed++];
+ if (readAheadConsumed == readAhead.Length) {
+ readAhead = null;
+ }
+ return res;
+ } finally {
+ cce.EndExpose();
+ }
+ }
+ public override int Read(char[] buffer, int index, int count) {
+
+ int n = 0;
+ for (; n < count; n++) {
+ int ch = Read();
+ if (ch == -1) {
+ break;
+ }
+ buffer[index + n] = (char)ch;
+ }
+ return n;
+ }
+ public override string ReadLine() {
+ string res;
+ if (readAhead != null) {
+ cce.BeginExpose(this);
+ {
+ res = readAhead.Substring(readAheadConsumed);
+ readAhead = null;
+ }
+ cce.EndExpose();
+ } else {
+ res = reader.ReadLine();
+ }
+ return res;
+ }
+ }
+
+ public class IfdefReader : LineReader {
+ [Rep]
+ readonly List<string/*!*/>/*!*/ defines;
+ [Rep]
+ readonly List<bool>/*!*/ readState = new List<bool>();
+ int ignoreCutoff = 0; // 0 means we're not ignoring
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(readState != null);
+ Contract.Invariant(cce.NonNullElements(defines));
+ Contract.Invariant(0 <= ignoreCutoff && ignoreCutoff <= readState.Count);
+ }
+
+
+
+ public IfdefReader([Captured] TextReader reader, [Captured] List<string/*!*/>/*!*/ defines)
+ : base(reader) {
+ Contract.Requires(reader != null);
+ Contract.Requires(cce.NonNullElements(defines));
+ this.defines = defines;
+ }
+
+ public override string ReadLine() {
+ while (true) {
+ string s = base.ReadLine();
+ if (s == null) {
+ return s;
+ }
+ string t = s.Trim();
+ if (t.StartsWith("#if")) {
+ string arg = t.Substring(3).TrimStart();
+ bool sense = true;
+ while (t.StartsWith("!")) {
+ sense = !sense;
+ t = t.Substring(1).TrimStart();
+ }
+ // push "true", since we're in a "then" branch
+ readState.Add(true);
+ if (ignoreCutoff == 0 && defines.Contains(arg) != sense) {
+ ignoreCutoff = readState.Count; // start ignoring
+ }
+ } else if (t == "#else") {
+ if (readState.Count == 0 || !readState[readState.Count - 1]) {
+ return s; // malformed input; return the read line as if it were not special
+ }
+ // change the "true" to a "false" on top of the state, since we're now going into the "else" branch
+ readState[readState.Count - 1] = false;
+ if (ignoreCutoff == 0) {
+ // the "then" branch had been included, so we'll ignore the "else" branch
+ ignoreCutoff = readState.Count;
+ } else if (ignoreCutoff == readState.Count) {
+ // we had ignored the "then" branch, so we'll include the "else" branch
+ ignoreCutoff = 0;
+ }
+ } else if (t == "#endif") {
+ if (readState.Count == 0) {
+ return s; // malformed input; return the read line as if it were not special
+ }
+ if (ignoreCutoff == readState.Count) {
+ // we had ignored the branch that ends here; so, now we start including again
+ ignoreCutoff = 0;
+ }
+ // pop
+ readState.RemoveAt(readState.Count - 1);
+ } else if (ignoreCutoff == 0) {
+ return s;
+ }
+ }
+ }
+ }
+}
diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs
index 7982f594..1f8d17d6 100644
--- a/Source/Core/Parser.cs
+++ b/Source/Core/Parser.cs
@@ -1,2425 +1,2425 @@
-using System.Collections;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-using Microsoft.Boogie;
-using Microsoft.Basetypes;
-using Bpl = Microsoft.Boogie;
-
-
-
-
-using System;
-using System.Diagnostics.Contracts;
-
-namespace Microsoft.Boogie {
-
-
-
-public class Parser {
- public const int _EOF = 0;
- public const int _ident = 1;
- public const int _bvlit = 2;
- public const int _digits = 3;
- 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;
- const bool x = false;
- const int minErrDist = 2;
-
- public Scanner/*!*/ scanner;
- public Errors/*!*/ errors;
-
- public Token/*!*/ t; // last recognized token
- public Token/*!*/ la; // lookahead token
- int errDist = minErrDist;
-
-readonly Program/*!*/ Pgm;
-
-readonly Expr/*!*/ dummyExpr;
-readonly Cmd/*!*/ dummyCmd;
-readonly Block/*!*/ dummyBlock;
-readonly Bpl.Type/*!*/ dummyType;
-readonly List<Expr>/*!*/ dummyExprSeq;
-readonly TransferCmd/*!*/ dummyTransferCmd;
-readonly StructuredCmd/*!*/ dummyStructuredCmd;
-
-///<summary>
-///Returns the number of parsing errors encountered. If 0, "program" returns as
-///the parsed program.
-///</summary>
-public static int Parse (string/*!*/ filename, /*maybe null*/ List<string/*!*/> 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<string/*!*/>();
- }
-
- 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<Cmd>(), new ReturnCmd(Token.NoToken));
- dummyType = new BasicType(Token.NoToken, SimpleType.Bool);
- dummyExprSeq = new List<Expr> ();
- 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, /*immutable=*/ false) {
- Contract.Requires(tok != null);
- this.Lower = lower;
- this.Upper = upper;
- }
- public override Bpl.Type/*!*/ ShallowType { get {Contract.Ensures(Contract.Result<Bpl.Type>() != 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<object>/*!*/ freeVars) { Contract.Assert(false);throw new cce.UnreachableException(); }
- public override int ComputeHashCode() {
- return base.GetHashCode();
- }
-}
-
-/*--------------------------------------------------------------------------*/
-
-
- public Parser(Scanner/*!*/ scanner, Errors/*!*/ errors) {
- this.scanner = scanner;
- this.errors = errors;
- Token/*!*/ tok = new Token();
- tok.val = "";
- this.la = tok;
- this.t = new Token(); // just to satisfy its non-null constraint
- }
-
- void SynErr (int n) {
- if (errDist >= minErrDist) errors.SynErr(la.filename, la.line, la.col, n);
- errDist = 0;
- }
-
- public void SemErr (string/*!*/ msg) {
- Contract.Requires(msg != null);
- if (errDist >= minErrDist) errors.SemErr(t, msg);
- errDist = 0;
- }
-
- public void SemErr(IToken/*!*/ tok, string/*!*/ msg) {
- Contract.Requires(tok != null);
- Contract.Requires(msg != null);
- errors.SemErr(tok, msg);
- }
-
- void Get () {
- for (;;) {
- t = la;
- la = scanner.Scan();
- if (la.kind <= maxT) { ++errDist; break; }
-
- la = t;
- }
- }
-
- void Expect (int n) {
- if (la.kind==n) Get(); else { SynErr(n); }
- }
-
- bool StartOf (int s) {
- return set[s, la.kind];
- }
-
- void ExpectWeak (int n, int follow) {
- if (la.kind == n) Get();
- else {
- SynErr(n);
- while (!StartOf(follow)) Get();
- }
- }
-
-
- bool WeakSeparator(int n, int syFol, int repFol) {
- int kind = la.kind;
- if (kind == n) {Get(); return true;}
- else if (StartOf(repFol)) {return false;}
- else {
- SynErr(n);
- while (!(set[syFol, kind] || set[repFol, kind] || set[0, kind])) {
- Get();
- kind = la.kind;
- }
- return StartOf(syFol);
- }
- }
-
-
- void BoogiePL() {
- List<Variable>/*!*/ vs;
- List<Declaration>/*!*/ ds;
- Axiom/*!*/ ax;
- List<Declaration/*!*/>/*!*/ ts;
- Procedure/*!*/ pr;
- Implementation im;
- Implementation/*!*/ nnim;
-
- while (StartOf(1)) {
- switch (la.kind) {
- case 21: {
- Consts(out vs);
- foreach(Bpl.Variable/*!*/ v in vs){
- Contract.Assert(v != null);
- Pgm.AddTopLevelDeclaration(v);
- }
-
- break;
- }
- case 25: {
- Function(out ds);
- foreach(Bpl.Declaration/*!*/ d in ds){
- Contract.Assert(d != null);
- Pgm.AddTopLevelDeclaration(d);
- }
-
- break;
- }
- case 29: {
- Axiom(out ax);
- Pgm.AddTopLevelDeclaration(ax);
- break;
- }
- case 30: {
- UserDefinedTypes(out ts);
- foreach(Declaration/*!*/ td in ts){
- Contract.Assert(td != null);
- Pgm.AddTopLevelDeclaration(td);
- }
-
- break;
- }
- case 7: {
- GlobalVars(out vs);
- foreach(Bpl.Variable/*!*/ v in vs){
- Contract.Assert(v != null);
- Pgm.AddTopLevelDeclaration(v);
- }
-
- break;
- }
- case 32: {
- Procedure(out pr, out im);
- Pgm.AddTopLevelDeclaration(pr);
- if (im != null) {
- Pgm.AddTopLevelDeclaration(im);
- }
-
- break;
- }
- case 33: {
- Implementation(out nnim);
- Pgm.AddTopLevelDeclaration(nnim);
- break;
- }
- }
- }
- Expect(0);
- }
-
- void Consts(out List<Variable>/*!*/ ds) {
- Contract.Ensures(Contract.ValueAtReturn(out ds) != null); IToken/*!*/ y; List<TypedIdent>/*!*/ xs;
- ds = new List<Variable>();
- bool u = false; QKeyValue kv = null;
- bool ChildrenComplete = false;
- List<ConstantParent/*!*/> Parents = null;
- Expect(21);
- y = t;
- while (la.kind == 27) {
- Attribute(ref kv);
- }
- if (la.kind == 22) {
- Get();
- u = true;
- }
- IdsType(out xs);
- if (la.kind == 23) {
- OrderSpec(out ChildrenComplete, out Parents);
- }
- bool makeClone = false;
- foreach(TypedIdent/*!*/ x in xs){
- Contract.Assert(x != null);
-
- // ensure that no sharing is introduced
- List<ConstantParent/*!*/> ParentsClone;
- if (makeClone && Parents != null) {
- ParentsClone = new List<ConstantParent/*!*/> ();
- 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));
- }
-
- Expect(8);
- }
-
- void Function(out List<Declaration>/*!*/ ds) {
- Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
- ds = new List<Declaration>(); IToken/*!*/ z;
- IToken/*!*/ typeParamTok;
- var typeParams = new List<TypeVariable>();
- var arguments = new List<Variable>();
- TypedIdent/*!*/ tyd;
- TypedIdent retTyd = null;
- Bpl.Type/*!*/ retTy;
- QKeyValue argKv = null;
- QKeyValue kv = null;
- Expr definition = null;
- Expr/*!*/ tmp;
-
- Expect(25);
- while (la.kind == 27) {
- Attribute(ref kv);
- }
- Ident(out z);
- if (la.kind == 19) {
- TypeParams(out typeParamTok, out typeParams);
- }
- Expect(9);
- if (StartOf(2)) {
- VarOrType(out tyd, out argKv);
- arguments.Add(new Formal(tyd.tok, tyd, true, argKv));
- while (la.kind == 12) {
- Get();
- VarOrType(out tyd, out argKv);
- arguments.Add(new Formal(tyd.tok, tyd, true, argKv));
- }
- }
- Expect(10);
- argKv = null;
- if (la.kind == 26) {
- Get();
- Expect(9);
- VarOrType(out retTyd, out argKv);
- Expect(10);
- } else if (la.kind == 11) {
- Get();
- Type(out retTy);
- retTyd = new TypedIdent(retTy.tok, TypedIdent.NoName, retTy);
- } else SynErr(99);
- if (la.kind == 27) {
- Get();
- Expression(out tmp);
- definition = tmp;
- Expect(28);
- } else if (la.kind == 8) {
- Get();
- } 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));
- }
- 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));
- }
- }
-
- }
-
- void Axiom(out Axiom/*!*/ m) {
- Contract.Ensures(Contract.ValueAtReturn(out m) != null); Expr/*!*/ e; QKeyValue kv = null;
- Expect(29);
- while (la.kind == 27) {
- Attribute(ref kv);
- }
- IToken/*!*/ x = t;
- Proposition(out e);
- Expect(8);
- m = new Axiom(x,e, null, kv);
- }
-
- void UserDefinedTypes(out List<Declaration/*!*/>/*!*/ ts) {
- Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out ts))); Declaration/*!*/ decl; QKeyValue kv = null; ts = new List<Declaration/*!*/> ();
- Expect(30);
- while (la.kind == 27) {
- Attribute(ref kv);
- }
- UserDefinedType(out decl, kv);
- ts.Add(decl);
- while (la.kind == 12) {
- Get();
- UserDefinedType(out decl, kv);
- ts.Add(decl);
- }
- Expect(8);
- }
-
- void GlobalVars(out List<Variable>/*!*/ ds) {
- Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
- QKeyValue kv = null;
- ds = new List<Variable>();
- var dsx = ds;
-
- Expect(7);
- while (la.kind == 27) {
- Attribute(ref kv);
- }
- IdsTypeWheres(true, "global variables", delegate(TypedIdent tyd) { dsx.Add(new GlobalVariable(tyd.tok, tyd, kv)); } );
- Expect(8);
- }
-
- void Procedure(out Procedure/*!*/ proc, out /*maybe null*/ Implementation impl) {
- Contract.Ensures(Contract.ValueAtReturn(out proc) != null); IToken/*!*/ x;
- List<TypeVariable>/*!*/ typeParams;
- List<Variable>/*!*/ ins, outs;
- List<Requires>/*!*/ pre = new List<Requires>();
- List<IdentifierExpr>/*!*/ mods = new List<IdentifierExpr>();
- List<Ensures>/*!*/ post = new List<Ensures>();
-
- List<Variable>/*!*/ locals = new List<Variable>();
- StmtList/*!*/ stmtList;
- QKeyValue kv = null;
- impl = null;
-
- Expect(32);
- ProcSignature(true, out x, out typeParams, out ins, out outs, out kv);
- if (la.kind == 8) {
- Get();
- while (StartOf(3)) {
- Spec(pre, mods, post);
- }
- } else if (StartOf(4)) {
- while (StartOf(3)) {
- Spec(pre, mods, post);
- }
- ImplBody(out locals, out stmtList);
- 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);
- proc = new Procedure(x, x.val, typeParams, ins, outs, pre, mods, post, kv);
- }
-
- void Implementation(out Implementation/*!*/ impl) {
- Contract.Ensures(Contract.ValueAtReturn(out impl) != null); IToken/*!*/ x;
- List<TypeVariable>/*!*/ typeParams;
- List<Variable>/*!*/ ins, outs;
- List<Variable>/*!*/ locals;
- StmtList/*!*/ stmtList;
- QKeyValue kv;
-
- Expect(33);
- ProcSignature(false, out x, out typeParams, out ins, out outs, out kv);
- ImplBody(out locals, out stmtList);
- impl = new Implementation(x, x.val, typeParams, ins, outs, locals, stmtList, kv, this.errors);
- }
-
- void Attribute(ref QKeyValue kv) {
- Trigger trig = null;
- AttributeOrTrigger(ref kv, ref trig);
- if (trig != null) this.SemErr("only attributes, not triggers, allowed here");
- }
-
- void IdsTypeWheres(bool allowWhereClauses, string context, System.Action<TypedIdent> action ) {
- IdsTypeWhere(allowWhereClauses, context, action);
- while (la.kind == 12) {
- Get();
- IdsTypeWhere(allowWhereClauses, context, action);
- }
- }
-
- void LocalVars(List<Variable>/*!*/ ds) {
- Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
- QKeyValue kv = null;
-
- Expect(7);
- while (la.kind == 27) {
- Attribute(ref kv);
- }
- IdsTypeWheres(true, "local variables", delegate(TypedIdent tyd) { ds.Add(new LocalVariable(tyd.tok, tyd, kv)); } );
- Expect(8);
- }
-
- void ProcFormals(bool incoming, bool allowWhereClauses, out List<Variable>/*!*/ ds) {
- Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
- ds = new List<Variable>();
- var dsx = ds;
- var context = allowWhereClauses ? "procedure formals" : "the 'implementation' copies of formals";
-
- Expect(9);
- if (la.kind == 1 || la.kind == 27) {
- AttrsIdsTypeWheres(allowWhereClauses, allowWhereClauses, context, delegate(TypedIdent tyd, QKeyValue kv) { dsx.Add(new Formal(tyd.tok, tyd, incoming, kv)); });
- }
- Expect(10);
- }
-
- void AttrsIdsTypeWheres(bool allowAttributes, bool allowWhereClauses, string context, System.Action<TypedIdent, QKeyValue> action ) {
- AttributesIdsTypeWhere(allowAttributes, allowWhereClauses, context, action);
- while (la.kind == 12) {
- Get();
- AttributesIdsTypeWhere(allowAttributes, allowWhereClauses, context, action);
- }
- }
-
- void BoundVars(IToken/*!*/ x, out List<Variable>/*!*/ ds) {
- Contract.Requires(x != null);
- Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
- List<TypedIdent>/*!*/ tyds = new List<TypedIdent>();
- ds = new List<Variable>();
- var dsx = ds;
-
- AttrsIdsTypeWheres(true, false, "bound variables", delegate(TypedIdent tyd, QKeyValue kv) { dsx.Add(new BoundVariable(tyd.tok, tyd, kv)); } );
- }
-
- void IdsType(out List<TypedIdent>/*!*/ tyds) {
- Contract.Ensures(Contract.ValueAtReturn(out tyds) != null); List<IToken>/*!*/ ids; Bpl.Type/*!*/ ty;
- Idents(out ids);
- Expect(11);
- Type(out ty);
- tyds = new List<TypedIdent>();
- foreach(Token/*!*/ id in ids){
- Contract.Assert(id != null);
- tyds.Add(new TypedIdent(id, id.val, ty, null));
- }
-
- }
-
- void Idents(out List<IToken>/*!*/ xs) {
- Contract.Ensures(Contract.ValueAtReturn(out xs) != null); IToken/*!*/ id; xs = new List<IToken>();
- Ident(out id);
- xs.Add(id);
- while (la.kind == 12) {
- Get();
- Ident(out id);
- xs.Add(id);
- }
- }
-
- void Type(out Bpl.Type/*!*/ ty) {
- Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken/*!*/ tok; ty = dummyType;
- if (StartOf(5)) {
- TypeAtom(out ty);
- } else if (la.kind == 1) {
- Ident(out tok);
- List<Bpl.Type>/*!*/ args = new List<Bpl.Type> ();
- if (StartOf(6)) {
- TypeArgs(args);
- }
- ty = new UnresolvedTypeIdentifier (tok, tok.val, args);
- } else if (la.kind == 17 || la.kind == 19) {
- MapType(out ty);
- } else SynErr(100);
- }
-
- void AttributesIdsTypeWhere(bool allowAttributes, bool allowWhereClauses, string context, System.Action<TypedIdent, QKeyValue> action ) {
- QKeyValue kv = null;
- while (la.kind == 27) {
- Attribute(ref kv);
- if (!allowAttributes) {
- kv = null;
- this.SemErr("attributes are not allowed on " + context);
- }
-
- }
- IdsTypeWhere(allowWhereClauses, context, delegate(TypedIdent tyd) { action(tyd, kv); });
- }
-
- void IdsTypeWhere(bool allowWhereClauses, string context, System.Action<TypedIdent> action ) {
- List<IToken>/*!*/ ids; Bpl.Type/*!*/ ty; Expr wh = null; Expr/*!*/ nne;
- Idents(out ids);
- Expect(11);
- Type(out ty);
- if (la.kind == 13) {
- Get();
- Expression(out nne);
- 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));
- }
-
- }
-
- void Expression(out Expr/*!*/ e0) {
- Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1;
- ImpliesExpression(false, out e0);
- while (la.kind == 55 || la.kind == 56) {
- EquivOp();
- x = t;
- ImpliesExpression(false, out e1);
- e0 = Expr.Binary(x, BinaryOperator.Opcode.Iff, e0, e1);
- }
- }
-
- void TypeAtom(out Bpl.Type/*!*/ ty) {
- Contract.Ensures(Contract.ValueAtReturn(out ty) != null); ty = dummyType;
- if (la.kind == 14) {
- Get();
- ty = new BasicType(t, SimpleType.Int);
- } else if (la.kind == 15) {
- Get();
- ty = new BasicType(t, SimpleType.Real);
- } else if (la.kind == 98) {
- Get();
- ty = FType();
- } else if (la.kind == 16) {
- Get();
- ty = new BasicType(t, SimpleType.Bool);
- } else if (la.kind == 9) {
- Get();
- Type(out ty);
- Expect(10);
- } 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);
- x = t;
- if (x.val.StartsWith("\\"))
- x.val = x.val.Substring(1);
-
- }
-
- void TypeArgs(List<Bpl.Type>/*!*/ ts) {
- Contract.Requires(ts != null); IToken/*!*/ tok; Bpl.Type/*!*/ ty;
- if (StartOf(5)) {
- TypeAtom(out ty);
- ts.Add(ty);
- if (StartOf(6)) {
- TypeArgs(ts);
- }
- } else if (la.kind == 1) {
- Ident(out tok);
- List<Bpl.Type>/*!*/ args = new List<Bpl.Type> ();
- ts.Add(new UnresolvedTypeIdentifier (tok, tok.val, args));
- if (StartOf(6)) {
- TypeArgs(ts);
- }
- } else if (la.kind == 17 || la.kind == 19) {
- MapType(out ty);
- ts.Add(ty);
- } else SynErr(102);
- }
-
- void MapType(out Bpl.Type/*!*/ ty) {
- Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken tok = null;
- IToken/*!*/ nnTok;
- List<Bpl.Type>/*!*/ arguments = new List<Bpl.Type>();
- Bpl.Type/*!*/ result;
- List<TypeVariable>/*!*/ typeParameters = new List<TypeVariable>();
-
- if (la.kind == 19) {
- TypeParams(out nnTok, out typeParameters);
- tok = nnTok;
- }
- Expect(17);
- if (tok == null) tok = t;
- if (StartOf(6)) {
- Types(arguments);
- }
- Expect(18);
- Type(out result);
- ty = new MapType(tok, typeParameters, arguments, result);
-
- }
-
- void TypeParams(out IToken/*!*/ tok, out List<TypeVariable>/*!*/ typeParams) {
- Contract.Ensures(Contract.ValueAtReturn(out tok) != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); List<IToken>/*!*/ typeParamToks;
- Expect(19);
- tok = t;
- Idents(out typeParamToks);
- Expect(20);
- typeParams = new List<TypeVariable> ();
- foreach(Token/*!*/ id in typeParamToks){
- Contract.Assert(id != null);
- typeParams.Add(new TypeVariable(id, id.val));}
-
- }
-
- void Types(List<Bpl.Type>/*!*/ ts) {
- Contract.Requires(ts != null); Bpl.Type/*!*/ ty;
- Type(out ty);
- ts.Add(ty);
- while (la.kind == 12) {
- Get();
- Type(out ty);
- ts.Add(ty);
- }
- }
-
- void OrderSpec(out bool ChildrenComplete, out List<ConstantParent/*!*/> Parents) {
- Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out Parents),true)); ChildrenComplete = false;
- Parents = null;
- bool u;
- IToken/*!*/ parent;
- Expect(23);
- Parents = new List<ConstantParent/*!*/> ();
- u = false;
- if (la.kind == 1 || la.kind == 22) {
- if (la.kind == 22) {
- Get();
- u = true;
- }
- Ident(out parent);
- Parents.Add(new ConstantParent (
- new IdentifierExpr(parent, parent.val), u));
- while (la.kind == 12) {
- Get();
- u = false;
- if (la.kind == 22) {
- Get();
- u = true;
- }
- Ident(out parent);
- Parents.Add(new ConstantParent (
- new IdentifierExpr(parent, parent.val), u));
- }
- }
- if (la.kind == 24) {
- Get();
- ChildrenComplete = true;
- }
- }
-
- void VarOrType(out TypedIdent/*!*/ tyd, out QKeyValue kv) {
- Contract.Ensures(Contract.ValueAtReturn(out tyd) != null);
- string/*!*/ varName = TypedIdent.NoName;
- Bpl.Type/*!*/ ty;
- IToken/*!*/ tok;
- kv = null;
-
- while (la.kind == 27) {
- Attribute(ref kv);
- }
- Type(out ty);
- tok = ty.tok;
- if (la.kind == 11) {
- Get();
- var uti = ty as UnresolvedTypeIdentifier;
- if (uti != null && uti.Arguments.Count == 0) {
- varName = uti.Name;
- } else {
- this.SemErr("expected identifier before ':'");
- }
-
- Type(out ty);
- }
- tyd = new TypedIdent(tok, varName, ty);
- }
-
- void Proposition(out Expr/*!*/ e) {
- Contract.Ensures(Contract.ValueAtReturn(out e) != null);
- Expression(out e);
- }
-
- void UserDefinedType(out Declaration/*!*/ decl, QKeyValue kv) {
- Contract.Ensures(Contract.ValueAtReturn(out decl) != null); IToken/*!*/ id; List<IToken>/*!*/ paramTokens = new List<IToken> ();
- Bpl.Type/*!*/ body = dummyType; bool synonym = false;
- Ident(out id);
- if (la.kind == 1) {
- WhiteSpaceIdents(out paramTokens);
- }
- if (la.kind == 31) {
- Get();
- Type(out body);
- synonym = true;
- }
- if (synonym) {
- List<TypeVariable>/*!*/ typeParams = new List<TypeVariable>();
- 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);
- }
-
- }
-
- void WhiteSpaceIdents(out List<IToken>/*!*/ xs) {
- Contract.Ensures(Contract.ValueAtReturn(out xs) != null); IToken/*!*/ id; xs = new List<IToken>();
- Ident(out id);
- xs.Add(id);
- while (la.kind == 1) {
- Ident(out id);
- xs.Add(id);
- }
- }
-
- void ProcSignature(bool allowWhereClausesOnFormals, out IToken/*!*/ name, out List<TypeVariable>/*!*/ typeParams,
-out List<Variable>/*!*/ ins, out List<Variable>/*!*/ 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<TypeVariable>();
- outs = new List<Variable>(); kv = null;
- while (la.kind == 27) {
- Attribute(ref kv);
- }
- Ident(out name);
- if (la.kind == 19) {
- TypeParams(out typeParamTok, out typeParams);
- }
- ProcFormals(true, allowWhereClausesOnFormals, out ins);
- if (la.kind == 26) {
- Get();
- ProcFormals(false, allowWhereClausesOnFormals, out outs);
- }
- }
-
- void Spec(List<Requires>/*!*/ pre, List<IdentifierExpr>/*!*/ mods, List<Ensures>/*!*/ post) {
- Contract.Requires(pre != null); Contract.Requires(mods != null); Contract.Requires(post != null); List<IToken>/*!*/ ms;
- if (la.kind == 34) {
- Get();
- if (la.kind == 1) {
- Idents(out ms);
- foreach(IToken/*!*/ m in ms){
- Contract.Assert(m != null);
- mods.Add(new IdentifierExpr(m, m.val));
- }
-
- }
- Expect(8);
- } else if (la.kind == 35) {
- Get();
- SpecPrePost(true, pre, post);
- } else if (la.kind == 36 || la.kind == 37) {
- SpecPrePost(false, pre, post);
- } else SynErr(103);
- }
-
- void ImplBody(out List<Variable>/*!*/ locals, out StmtList/*!*/ stmtList) {
- Contract.Ensures(Contract.ValueAtReturn(out locals) != null); Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); locals = new List<Variable>();
- Expect(27);
- while (la.kind == 7) {
- LocalVars(locals);
- }
- StmtList(out stmtList);
- }
-
- void SpecPrePost(bool free, List<Requires>/*!*/ pre, List<Ensures>/*!*/ post) {
- Contract.Requires(pre != null); Contract.Requires(post != null); Expr/*!*/ e; Token tok = null; QKeyValue kv = null;
- if (la.kind == 36) {
- Get();
- tok = t;
- while (la.kind == 27) {
- Attribute(ref kv);
- }
- Proposition(out e);
- Expect(8);
- pre.Add(new Requires(tok, free, e, null, kv));
- } else if (la.kind == 37) {
- Get();
- tok = t;
- while (la.kind == 27) {
- Attribute(ref kv);
- }
- Proposition(out e);
- Expect(8);
- post.Add(new Ensures(tok, free, e, null, kv));
- } else SynErr(104);
- }
-
- void StmtList(out StmtList/*!*/ stmtList) {
- Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); List<BigBlock/*!*/> bigblocks = new List<BigBlock/*!*/>();
- /* built-up state for the current BigBlock: */
- IToken startToken = null; string currentLabel = null;
- List<Cmd> 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;
-
- while (StartOf(7)) {
- if (StartOf(8)) {
- LabelOrCmd(out c, out label);
- if (c != null) {
- // LabelOrCmd read a Cmd
- Contract.Assert(label == null);
- if (startToken == null) { startToken = c.tok; cs = new List<Cmd>(); }
- 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<Cmd>();
- }
-
- } else if (la.kind == 40 || la.kind == 42 || la.kind == 45) {
- StructuredCmd(out ecn);
- ec = ecn;
- if (startToken == null) { startToken = ec.tok; cs = new List<Cmd>(); }
- Contract.Assert(cs != null);
- b = new BigBlock(startToken, currentLabel, cs, ec, null);
- bigblocks.Add(b);
- startToken = null; currentLabel = null; cs = null;
-
- } else {
- TransferCmd(out tcn);
- tc = tcn;
- if (startToken == null) { startToken = tc.tok; cs = new List<Cmd>(); }
- Contract.Assert(cs != null);
- b = new BigBlock(startToken, currentLabel, cs, null, tc);
- bigblocks.Add(b);
- startToken = null; currentLabel = null; cs = null;
-
- }
- }
- Expect(28);
- IToken/*!*/ endCurly = t;
- if (startToken == null && bigblocks.Count == 0) {
- startToken = t; cs = new List<Cmd>();
- }
- if (startToken != null) {
- Contract.Assert(cs != null);
- b = new BigBlock(startToken, currentLabel, cs, null, null);
- bigblocks.Add(b);
- }
-
- stmtList = new StmtList(bigblocks, endCurly);
-
- }
-
- void LabelOrCmd(out Cmd c, out IToken label) {
- IToken/*!*/ x; Expr/*!*/ e;
- List<IToken>/*!*/ xs;
- List<IdentifierExpr> ids;
- c = dummyCmd; label = null;
- Cmd/*!*/ cn;
- QKeyValue kv = null;
-
- switch (la.kind) {
- case 1: {
- LabelOrAssign(out c, out label);
- break;
- }
- case 46: {
- Get();
- x = t;
- while (la.kind == 27) {
- Attribute(ref kv);
- }
- Proposition(out e);
- c = new AssertCmd(x, e, kv);
- Expect(8);
- break;
- }
- case 47: {
- Get();
- x = t;
- while (la.kind == 27) {
- Attribute(ref kv);
- }
- Proposition(out e);
- c = new AssumeCmd(x, e, kv);
- Expect(8);
- break;
- }
- case 48: {
- Get();
- x = t;
- Idents(out xs);
- Expect(8);
- ids = new List<IdentifierExpr>();
- foreach(IToken/*!*/ y in xs){
- Contract.Assert(y != null);
- ids.Add(new IdentifierExpr(y, y.val));
- }
- c = new HavocCmd(x,ids);
-
- break;
- }
- case 35: case 51: case 52: {
- CallCmd(out cn);
- Expect(8);
- c = cn;
- break;
- }
- case 53: {
- ParCallCmd(out cn);
- c = cn;
- break;
- }
- case 49: {
- Get();
- x = t;
- Expect(8);
- c = new YieldCmd(x);
- break;
- }
- default: SynErr(105); break;
- }
- }
-
- void StructuredCmd(out StructuredCmd/*!*/ ec) {
- Contract.Ensures(Contract.ValueAtReturn(out ec) != null); ec = dummyStructuredCmd; Contract.Assume(cce.IsPeerConsistent(ec));
- IfCmd/*!*/ ifcmd; WhileCmd/*!*/ wcmd; BreakCmd/*!*/ bcmd;
-
- if (la.kind == 40) {
- IfCmd(out ifcmd);
- ec = ifcmd;
- } else if (la.kind == 42) {
- WhileCmd(out wcmd);
- ec = wcmd;
- } else if (la.kind == 45) {
- BreakCmd(out bcmd);
- ec = bcmd;
- } else SynErr(106);
- }
-
- void TransferCmd(out TransferCmd/*!*/ tc) {
- Contract.Ensures(Contract.ValueAtReturn(out tc) != null); tc = dummyTransferCmd;
- Token y; List<IToken>/*!*/ xs;
- List<String> ss = new List<String>();
-
- if (la.kind == 38) {
- Get();
- y = t;
- Idents(out xs);
- foreach(IToken/*!*/ s in xs){
- Contract.Assert(s != null);
- ss.Add(s.val); }
- tc = new GotoCmd(y, ss);
-
- } else if (la.kind == 39) {
- Get();
- tc = new ReturnCmd(t);
- } else SynErr(107);
- Expect(8);
- }
-
- void IfCmd(out IfCmd/*!*/ ifcmd) {
- Contract.Ensures(Contract.ValueAtReturn(out ifcmd) != null); IToken/*!*/ x;
- Expr guard;
- StmtList/*!*/ thn;
- IfCmd/*!*/ elseIf; IfCmd elseIfOption = null;
- StmtList/*!*/ els; StmtList elseOption = null;
-
- Expect(40);
- x = t;
- Guard(out guard);
- Expect(27);
- StmtList(out thn);
- if (la.kind == 41) {
- Get();
- if (la.kind == 40) {
- IfCmd(out elseIf);
- elseIfOption = elseIf;
- } else if (la.kind == 27) {
- Get();
- StmtList(out els);
- elseOption = els;
- } else SynErr(108);
- }
- ifcmd = new IfCmd(x, guard, thn, elseIfOption, elseOption);
- }
-
- void WhileCmd(out WhileCmd/*!*/ wcmd) {
- Contract.Ensures(Contract.ValueAtReturn(out wcmd) != null); IToken/*!*/ x; Token z;
- Expr guard; Expr/*!*/ e; bool isFree;
- List<PredicateCmd/*!*/> invariants = new List<PredicateCmd/*!*/>();
- StmtList/*!*/ body;
- QKeyValue kv = null;
-
- Expect(42);
- x = t;
- Guard(out guard);
- Contract.Assume(guard == null || cce.Owner.None(guard));
- while (la.kind == 35 || la.kind == 43) {
- isFree = false; z = la/*lookahead token*/;
- if (la.kind == 35) {
- Get();
- isFree = true;
- }
- Expect(43);
- while (la.kind == 27) {
- Attribute(ref kv);
- }
- Expression(out e);
- if (isFree) {
- invariants.Add(new AssumeCmd(z, e, kv));
- } else {
- invariants.Add(new AssertCmd(z, e, kv));
- }
- kv = null;
-
- Expect(8);
- }
- Expect(27);
- StmtList(out body);
- wcmd = new WhileCmd(x, guard, invariants, body);
- }
-
- void BreakCmd(out BreakCmd/*!*/ bcmd) {
- Contract.Ensures(Contract.ValueAtReturn(out bcmd) != null); IToken/*!*/ x; IToken/*!*/ y;
- string breakLabel = null;
-
- Expect(45);
- x = t;
- if (la.kind == 1) {
- Ident(out y);
- breakLabel = y.val;
- }
- Expect(8);
- bcmd = new BreakCmd(x, breakLabel);
- }
-
- void Guard(out Expr e) {
- Expr/*!*/ ee; e = null;
- Expect(9);
- if (la.kind == 44) {
- Get();
- e = null;
- } else if (StartOf(9)) {
- Expression(out ee);
- e = ee;
- } else SynErr(109);
- Expect(10);
- }
-
- void LabelOrAssign(out Cmd c, out IToken label) {
- IToken/*!*/ id; IToken/*!*/ x, y; Expr/*!*/ e0;
- c = dummyCmd; label = null;
- AssignLhs/*!*/ lhs;
- List<AssignLhs/*!*/>/*!*/ lhss;
- List<Expr/*!*/>/*!*/ rhss;
- List<Expr/*!*/>/*!*/ indexes;
-
- Ident(out id);
- x = t;
- if (la.kind == 11) {
- Get();
- c = null; label = x;
- } else if (la.kind == 12 || la.kind == 17 || la.kind == 50) {
- lhss = new List<AssignLhs/*!*/>();
- lhs = new SimpleAssignLhs(id, new IdentifierExpr(id, id.val));
- while (la.kind == 17) {
- MapAssignIndex(out y, out indexes);
- lhs = new MapAssignLhs(y, lhs, indexes);
- }
- lhss.Add(lhs);
- while (la.kind == 12) {
- Get();
- Ident(out id);
- lhs = new SimpleAssignLhs(id, new IdentifierExpr(id, id.val));
- while (la.kind == 17) {
- MapAssignIndex(out y, out indexes);
- lhs = new MapAssignLhs(y, lhs, indexes);
- }
- lhss.Add(lhs);
- }
- Expect(50);
- x = t; /* use location of := */
- Expression(out e0);
- rhss = new List<Expr/*!*/> ();
- rhss.Add(e0);
- while (la.kind == 12) {
- Get();
- Expression(out e0);
- rhss.Add(e0);
- }
- Expect(8);
- c = new AssignCmd(x, lhss, rhss);
- } else SynErr(110);
- }
-
- void CallCmd(out Cmd c) {
- Contract.Ensures(Contract.ValueAtReturn(out c) != null);
- IToken x;
- bool isAsync = false;
- bool isFree = false;
- QKeyValue kv = null;
- c = null;
-
- if (la.kind == 51) {
- Get();
- isAsync = true;
- }
- if (la.kind == 35) {
- Get();
- isFree = true;
- }
- Expect(52);
- x = t;
- while (la.kind == 27) {
- Attribute(ref kv);
- }
- CallParams(isAsync, isFree, kv, x, out c);
-
- }
-
- void ParCallCmd(out Cmd d) {
- Contract.Ensures(Contract.ValueAtReturn(out d) != null);
- IToken x;
- QKeyValue kv = null;
- Cmd c = null;
- List<CallCmd> callCmds = new List<CallCmd>();
-
- Expect(53);
- x = t;
- while (la.kind == 27) {
- Attribute(ref kv);
- }
- CallParams(false, false, kv, x, out c);
- callCmds.Add((CallCmd)c);
- while (la.kind == 54) {
- Get();
- CallParams(false, false, kv, x, out c);
- callCmds.Add((CallCmd)c);
- }
- Expect(8);
- d = new ParCallCmd(x, callCmds, kv);
- }
-
- void MapAssignIndex(out IToken/*!*/ x, out List<Expr/*!*/>/*!*/ indexes) {
- Contract.Ensures(Contract.ValueAtReturn(out x) != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out indexes))); indexes = new List<Expr/*!*/> ();
- Expr/*!*/ e;
-
- Expect(17);
- x = t;
- if (StartOf(9)) {
- Expression(out e);
- indexes.Add(e);
- while (la.kind == 12) {
- Get();
- Expression(out e);
- indexes.Add(e);
- }
- }
- Expect(18);
- }
-
- void CallParams(bool isAsync, bool isFree, QKeyValue kv, IToken x, out Cmd c) {
- List<IdentifierExpr> ids = new List<IdentifierExpr>();
- List<Expr> es = new List<Expr>();
- Expr en;
- IToken first;
- IToken p;
- c = null;
-
- Ident(out first);
- if (la.kind == 9) {
- Get();
- if (StartOf(9)) {
- Expression(out en);
- es.Add(en);
- while (la.kind == 12) {
- Get();
- Expression(out en);
- es.Add(en);
- }
- }
- Expect(10);
- c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync;
- } else if (la.kind == 12 || la.kind == 50) {
- ids.Add(new IdentifierExpr(first, first.val));
- if (la.kind == 12) {
- Get();
- Ident(out p);
- ids.Add(new IdentifierExpr(p, p.val));
- while (la.kind == 12) {
- Get();
- Ident(out p);
- ids.Add(new IdentifierExpr(p, p.val));
- }
- }
- Expect(50);
- Ident(out first);
- Expect(9);
- if (StartOf(9)) {
- Expression(out en);
- es.Add(en);
- while (la.kind == 12) {
- Get();
- Expression(out en);
- es.Add(en);
- }
- }
- Expect(10);
- c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync;
- } else SynErr(111);
- }
-
- void Expressions(out List<Expr>/*!*/ es) {
- Contract.Ensures(Contract.ValueAtReturn(out es) != null); Expr/*!*/ e; es = new List<Expr>();
- Expression(out e);
- es.Add(e);
- while (la.kind == 12) {
- Get();
- Expression(out e);
- es.Add(e);
- }
- }
-
- void ImpliesExpression(bool noExplies, out Expr/*!*/ e0) {
- Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1;
- LogicalExpression(out e0);
- if (StartOf(10)) {
- if (la.kind == 57 || la.kind == 58) {
- ImpliesOp();
- x = t;
- ImpliesExpression(true, out e1);
- e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e0, e1);
- } else {
- ExpliesOp();
- if (noExplies)
- this.SemErr("illegal mixture of ==> and <==, use parentheses to disambiguate");
- x = t;
- LogicalExpression(out e1);
- e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e1, e0);
- while (la.kind == 59 || la.kind == 60) {
- ExpliesOp();
- x = t;
- LogicalExpression(out e1);
- e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e1, e0);
- }
- }
- }
- }
-
- void EquivOp() {
- if (la.kind == 55) {
- Get();
- } else if (la.kind == 56) {
- Get();
- } else SynErr(112);
- }
-
- void LogicalExpression(out Expr/*!*/ e0) {
- Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1;
- RelationalExpression(out e0);
- if (StartOf(11)) {
- if (la.kind == 61 || la.kind == 62) {
- AndOp();
- x = t;
- RelationalExpression(out e1);
- e0 = Expr.Binary(x, BinaryOperator.Opcode.And, e0, e1);
- while (la.kind == 61 || la.kind == 62) {
- AndOp();
- x = t;
- RelationalExpression(out e1);
- e0 = Expr.Binary(x, BinaryOperator.Opcode.And, e0, e1);
- }
- } else {
- OrOp();
- x = t;
- RelationalExpression(out e1);
- e0 = Expr.Binary(x, BinaryOperator.Opcode.Or, e0, e1);
- while (la.kind == 63 || la.kind == 64) {
- OrOp();
- x = t;
- RelationalExpression(out e1);
- e0 = Expr.Binary(x, BinaryOperator.Opcode.Or, e0, e1);
- }
- }
- }
- }
-
- void ImpliesOp() {
- if (la.kind == 57) {
- Get();
- } else if (la.kind == 58) {
- Get();
- } else SynErr(113);
- }
-
- void ExpliesOp() {
- if (la.kind == 59) {
- Get();
- } else if (la.kind == 60) {
- Get();
- } else SynErr(114);
- }
-
- void RelationalExpression(out Expr/*!*/ e0) {
- Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op;
- BvTerm(out e0);
- if (StartOf(12)) {
- RelOp(out x, out op);
- BvTerm(out e1);
- e0 = Expr.Binary(x, op, e0, e1);
- }
- }
-
- void AndOp() {
- if (la.kind == 61) {
- Get();
- } else if (la.kind == 62) {
- Get();
- } else SynErr(115);
- }
-
- void OrOp() {
- if (la.kind == 63) {
- Get();
- } else if (la.kind == 64) {
- Get();
- } else SynErr(116);
- }
-
- void BvTerm(out Expr/*!*/ e0) {
- Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1;
- Term(out e0);
- while (la.kind == 73) {
- Get();
- x = t;
- Term(out e1);
- e0 = new BvConcatExpr(x, e0, e1);
- }
- }
-
- void RelOp(out IToken/*!*/ x, out BinaryOperator.Opcode op) {
- Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/;
- switch (la.kind) {
- case 65: {
- Get();
- x = t; op=BinaryOperator.Opcode.Eq;
- break;
- }
- case 19: {
- Get();
- x = t; op=BinaryOperator.Opcode.Lt;
- break;
- }
- case 20: {
- Get();
- x = t; op=BinaryOperator.Opcode.Gt;
- break;
- }
- case 66: {
- Get();
- x = t; op=BinaryOperator.Opcode.Le;
- break;
- }
- case 67: {
- Get();
- x = t; op=BinaryOperator.Opcode.Ge;
- break;
- }
- case 68: {
- Get();
- x = t; op=BinaryOperator.Opcode.Neq;
- break;
- }
- case 69: {
- Get();
- x = t; op=BinaryOperator.Opcode.Subtype;
- break;
- }
- case 70: {
- Get();
- x = t; op=BinaryOperator.Opcode.Neq;
- break;
- }
- case 71: {
- Get();
- x = t; op=BinaryOperator.Opcode.Le;
- break;
- }
- case 72: {
- Get();
- x = t; op=BinaryOperator.Opcode.Ge;
- break;
- }
- default: SynErr(117); break;
- }
- }
-
- void Term(out Expr/*!*/ e0) {
- Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op;
- Factor(out e0);
- while (la.kind == 74 || la.kind == 75) {
- AddOp(out x, out op);
- Factor(out e1);
- e0 = Expr.Binary(x, op, e0, e1);
- }
- }
-
- void Factor(out Expr/*!*/ e0) {
- Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op;
- Power(out e0);
- while (StartOf(13)) {
- MulOp(out x, out op);
- Power(out e1);
- e0 = Expr.Binary(x, op, e0, e1);
- }
- }
-
- void AddOp(out IToken/*!*/ x, out BinaryOperator.Opcode op) {
- Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/;
- if (la.kind == 74) {
- Get();
- x = t; op=BinaryOperator.Opcode.Add;
- } else if (la.kind == 75) {
- Get();
- x = t; op=BinaryOperator.Opcode.Sub;
- } else SynErr(118);
- }
-
- void Power(out Expr/*!*/ e0) {
- Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1;
- UnaryExpression(out e0);
- if (la.kind == 79) {
- Get();
- x = t;
- Power(out e1);
- e0 = Expr.Binary(x, BinaryOperator.Opcode.Pow, e0, e1);
- }
- }
-
- void MulOp(out IToken/*!*/ x, out BinaryOperator.Opcode op) {
- Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/;
- if (la.kind == 44) {
- Get();
- x = t; op=BinaryOperator.Opcode.Mul;
- } else if (la.kind == 76) {
- Get();
- x = t; op=BinaryOperator.Opcode.Div;
- } else if (la.kind == 77) {
- Get();
- x = t; op=BinaryOperator.Opcode.Mod;
- } else if (la.kind == 78) {
- Get();
- x = t; op=BinaryOperator.Opcode.RealDiv;
- } else SynErr(119);
- }
-
- void UnaryExpression(out Expr/*!*/ e) {
- Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x;
- e = dummyExpr;
-
- if (la.kind == 75) {
- Get();
- x = t;
- UnaryExpression(out e);
- e = Expr.Unary(x, UnaryOperator.Opcode.Neg, e);
- } else if (la.kind == 80 || la.kind == 81) {
- NegOp();
- x = t;
- UnaryExpression(out e);
- e = Expr.Unary(x, UnaryOperator.Opcode.Not, e);
- } else if (StartOf(14)) {
- CoercionExpression(out e);
- } else SynErr(120);
- }
-
- void NegOp() {
- if (la.kind == 80) {
- Get();
- } else if (la.kind == 81) {
- Get();
- } else SynErr(123);
- }
-
- void CoercionExpression(out Expr/*!*/ e) {
- Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x;
- Bpl.Type/*!*/ coercedTo;
- BigNum bn;
-
- ArrayExpression(out e);
- while (la.kind == 11) {
- Get();
- x = t;
- if (StartOf(6)) {
- Type(out coercedTo);
- e = Expr.CoerceType(x, e, coercedTo);
- } else if (la.kind == 3) {
- Nat(out bn);
- 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);
- }
-
- } else SynErr(124);
- }
- }
-
- void ArrayExpression(out Expr/*!*/ e) {
- Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x;
- Expr/*!*/ index0 = dummyExpr; Expr/*!*/ e1;
- bool store; bool bvExtract;
- List<Expr>/*!*/ allArgs = dummyExprSeq;
-
- AtomExpression(out e);
- while (la.kind == 17) {
- Get();
- x = t; allArgs = new List<Expr> ();
- allArgs.Add(e);
- store = false; bvExtract = false;
- if (StartOf(15)) {
- if (StartOf(9)) {
- Expression(out index0);
- if (index0 is BvBounds)
- bvExtract = true;
- else
- allArgs.Add(index0);
-
- while (la.kind == 12) {
- Get();
- Expression(out e1);
- if (bvExtract || e1 is BvBounds)
- this.SemErr("bitvectors only have one dimension");
- allArgs.Add(e1);
-
- }
- if (la.kind == 50) {
- Get();
- Expression(out e1);
- if (bvExtract || e1 is BvBounds)
- this.SemErr("assignment to bitvectors is not possible");
- allArgs.Add(e1); store = true;
-
- }
- } else {
- Get();
- Expression(out e1);
- allArgs.Add(e1); store = true;
- }
- }
- Expect(18);
- 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);
-
- }
- }
-
- void Nat(out BigNum n) {
- Expect(3);
- try {
- n = BigNum.FromString(t.val);
- } catch (FormatException) {
- this.SemErr("incorrectly formatted number");
- n = BigNum.ZERO;
- }
-
- }
-
- void AtomExpression(out Expr/*!*/ e) {
- Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; int n; BigNum bn; BigDec bd; BigFloat fp;
- List<Expr>/*!*/ es; List<Variable>/*!*/ ds; Trigger trig;
- List<TypeVariable>/*!*/ typeParams;
- IdentifierExpr/*!*/ id;
- QKeyValue kv;
- e = dummyExpr;
- List<Variable>/*!*/ locals;
- List<Block/*!*/>/*!*/ blocks;
-
- switch (la.kind) {
- case 82: {
- Get();
- e = new LiteralExpr(t, false);
- break;
- }
- case 83: {
- Get();
- e = new LiteralExpr(t, true);
- break;
- }
- case 3: {
- Nat(out bn);
- e = new LiteralExpr(t, bn);
- break;
- }
- case 5: case 6: {
- Dec(out bd);
- e = new LiteralExpr(t, bd);
- break;
- }
- case 97: {
- Float(out fp);
- e = new LiteralExpr(t, fp);
- break;
- }
- case 2: {
- BvLit(out bn, out n);
- e = new LiteralExpr(t, bn, n);
- break;
- }
- case 1: {
- Ident(out x);
- id = new IdentifierExpr(x, x.val); e = id;
- if (la.kind == 9) {
- Get();
- if (StartOf(9)) {
- Expressions(out es);
- e = new NAryExpr(x, new FunctionCall(id), es);
- } else if (la.kind == 10) {
- e = new NAryExpr(x, new FunctionCall(id), new List<Expr>());
- } else SynErr(125);
- Expect(10);
- }
- break;
- }
- case 84: {
- Get();
- x = t;
- Expect(9);
- Expression(out e);
- Expect(10);
- e = new OldExpr(x, e);
- break;
- }
- case 14: {
- Get();
- x = t;
- Expect(9);
- Expression(out e);
- Expect(10);
- e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToInt), new List<Expr>{ e });
- break;
- }
- case 15: {
- Get();
- x = t;
- Expect(9);
- Expression(out e);
- Expect(10);
- e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToReal), new List<Expr>{ e });
- 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<Expr> { e });
- break;
- }
- case 9: {
- Get();
- if (StartOf(9)) {
- Expression(out e);
- if (e is BvBounds)
- this.SemErr("parentheses around bitvector bounds " +
- "are not allowed");
- } else if (la.kind == 88 || la.kind == 89) {
- Forall();
- x = t;
- QuantifierBody(x, out typeParams, out ds, out kv, out trig, out e);
- if (typeParams.Count + ds.Count > 0)
- e = new ForallExpr(x, typeParams, ds, kv, trig, e);
- } else if (la.kind == 90 || la.kind == 91) {
- Exists();
- x = t;
- QuantifierBody(x, out typeParams, out ds, out kv, out trig, out e);
- if (typeParams.Count + ds.Count > 0)
- e = new ExistsExpr(x, typeParams, ds, kv, trig, e);
- } else if (la.kind == 92 || la.kind == 93) {
- Lambda();
- x = t;
- QuantifierBody(x, out typeParams, out ds, out kv, out trig, out e);
- if (trig != null)
- SemErr("triggers not allowed in lambda expressions");
- if (typeParams.Count + ds.Count > 0)
- e = new LambdaExpr(x, typeParams, ds, kv, e);
- } else SynErr(126);
- Expect(10);
- break;
- }
- case 40: {
- IfThenElseExpression(out e);
- break;
- }
- case 85: {
- CodeExpression(out locals, out blocks);
- e = new CodeExpr(locals, blocks);
- break;
- }
- default: SynErr(127); break;
- }
- }
-
- void Dec(out BigDec n) {
- string s = "";
- if (la.kind == 5) {
- Get();
- s = t.val;
- } else if (la.kind == 6) {
- Get();
- s = t.val;
- } else SynErr(128);
- try {
- n = BigDec.FromString(s);
- } catch (FormatException) {
- this.SemErr("incorrectly formatted number");
- n = BigDec.ZERO;
- }
-
- }
-
- /// <summary>
- /// Creates a floating point from the current token value
- /// </summary>
- /// <param name="n"></param>
- void Float(out BigFloat n)
- {
- try
- {
- if (la.kind == 97) {
- bool negative = false;
- int exp, sig, size;
- BigNum exp_val, sig_val, value;
- //Expected format = float(sign exp_val sig_val) || float<exp sig>(value)
- Get(); //Skip the float token
- if (la.val == "(") {
- Get();
- 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);
- BvLit(out sig_val, out sig);
- n = new BigFloat(negative, exp_val, sig_val, exp, sig);
- Expect(10); //)
- }
- else if (la.val == "<") {
- Get();
- Expect(3);
- exp = Int32.Parse(t.val);
- Expect(12);
- Expect(3);
- sig = Int32.Parse(t.val);
- Expect(20); //>
- Expect(9); //(
- 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);
- }
- Expect(10); //)
- }
- else {
- throw new FormatException();
- }
- }
- else {
- n = BigFloat.ZERO(8, 24);
- SynErr(137);
- }
- }
- catch (FormatException)
- {
- this.SemErr("incorrectly formatted floating point");
- n = BigFloat.ZERO(8, 24);
- }
- }
-
- void BvLit(out BigNum n, out int m) {
- Expect(2);
- 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;
- }
-
- }
-
- void Forall() {
- if (la.kind == 88) {
- Get();
- } else if (la.kind == 89) {
- Get();
- } else SynErr(129);
- }
-
- void QuantifierBody(IToken/*!*/ q, out List<TypeVariable>/*!*/ typeParams, out List<Variable>/*!*/ 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<TypeVariable> ();
- IToken/*!*/ tok;
- kv = null;
- ds = new List<Variable> ();
-
- if (la.kind == 19) {
- TypeParams(out tok, out typeParams);
- if (la.kind == 1 || la.kind == 27) {
- BoundVars(q, out ds);
- }
- } else if (la.kind == 1 || la.kind == 27) {
- BoundVars(q, out ds);
- } else SynErr(130);
- QSep();
- while (la.kind == 27) {
- AttributeOrTrigger(ref kv, ref trig);
- }
- Expression(out body);
- }
-
- void Exists() {
- if (la.kind == 90) {
- Get();
- } else if (la.kind == 91) {
- Get();
- } else SynErr(131);
- }
-
- void Lambda() {
- if (la.kind == 92) {
- Get();
- } else if (la.kind == 93) {
- Get();
- } else SynErr(132);
- }
-
- void IfThenElseExpression(out Expr/*!*/ e) {
- Contract.Ensures(Contract.ValueAtReturn(out e) != null);
- IToken/*!*/ tok;
- Expr/*!*/ e0, e1, e2;
- e = dummyExpr;
- Expect(40);
- tok = t;
- Expression(out e0);
- Expect(87);
- Expression(out e1);
- Expect(41);
- Expression(out e2);
- e = new NAryExpr(tok, new IfThenElse(tok), new List<Expr>{ e0, e1, e2 });
- }
-
- void CodeExpression(out List<Variable>/*!*/ locals, out List<Block/*!*/>/*!*/ blocks) {
- Contract.Ensures(Contract.ValueAtReturn(out locals) != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out blocks))); locals = new List<Variable>(); Block/*!*/ b;
- blocks = new List<Block/*!*/>();
-
- Expect(85);
- while (la.kind == 7) {
- LocalVars(locals);
- }
- SpecBlock(out b);
- blocks.Add(b);
- while (la.kind == 1) {
- SpecBlock(out b);
- blocks.Add(b);
- }
- Expect(86);
- }
-
- void SpecBlock(out Block/*!*/ b) {
- Contract.Ensures(Contract.ValueAtReturn(out b) != null); IToken/*!*/ x; IToken/*!*/ y;
- Cmd c; IToken label;
- List<Cmd> cs = new List<Cmd>();
- List<IToken>/*!*/ xs;
- List<String> ss = new List<String>();
- b = dummyBlock;
- Expr/*!*/ e;
-
- Ident(out x);
- Expect(11);
- while (StartOf(8)) {
- LabelOrCmd(out c, out label);
- if (c != null) {
- Contract.Assert(label == null);
- cs.Add(c);
- } else {
- Contract.Assert(label != null);
- SemErr("SpecBlock's can only have one label");
- }
-
- }
- if (la.kind == 38) {
- Get();
- y = t;
- Idents(out xs);
- foreach(IToken/*!*/ s in xs){
- Contract.Assert(s != null);
- ss.Add(s.val); }
- b = new Block(x,x.val,cs,new GotoCmd(y,ss));
-
- } else if (la.kind == 39) {
- Get();
- Expression(out e);
- b = new Block(x,x.val,cs,new ReturnExprCmd(t,e));
- } else SynErr(133);
- Expect(8);
- }
-
- void AttributeOrTrigger(ref QKeyValue kv, ref Trigger trig) {
- IToken/*!*/ tok; Expr/*!*/ e; List<Expr>/*!*/ es;
- string key;
- List<object/*!*/> parameters; object/*!*/ param;
-
- Expect(27);
- tok = t;
- if (la.kind == 11) {
- Get();
- Expect(1);
- key = t.val; parameters = new List<object/*!*/>();
- if (StartOf(16)) {
- AttributeParameter(out param);
- parameters.Add(param);
- while (la.kind == 12) {
- Get();
- AttributeParameter(out param);
- 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<Expr> { e }, null);
- } else {
- trig.AddLast(new Trigger(tok, false, new List<Expr> { 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));
- }
- }
-
- } else if (StartOf(9)) {
- Expression(out e);
- es = new List<Expr> { e };
- while (la.kind == 12) {
- Get();
- Expression(out e);
- es.Add(e);
- }
- if (trig==null) {
- trig = new Trigger(tok, true, es, null);
- } else {
- trig.AddLast(new Trigger(tok, true, es, null));
- }
-
- } else SynErr(134);
- Expect(28);
- }
-
- void AttributeParameter(out object/*!*/ o) {
- Contract.Ensures(Contract.ValueAtReturn(out o) != null);
- o = "error";
- Expr/*!*/ e;
-
- if (la.kind == 4) {
- Get();
- o = t.val.Substring(1, t.val.Length-2);
- } else if (StartOf(9)) {
- Expression(out e);
- o = e;
- } else SynErr(135);
- }
-
- void QSep() {
- if (la.kind == 94) {
- Get();
- } else if (la.kind == 95) {
- Get();
- } else SynErr(136);
- }
-
-
-
- public void Parse() {
- la = new Token();
- la.val = "";
- Get();
- BoogiePL();
- Expect(0);
-
- Expect(0);
- }
-
- 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,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},
- {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,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},
- {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, 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,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}
-
- };
-} // end Parser
-
-
-public class Errors {
- public int count = 0; // number of errors detected
- public System.IO.TextWriter/*!*/ errorStream = Console.Out; // error messages go to this stream
- public string errMsgFormat = "{0}({1},{2}): error: {3}"; // 0=filename, 1=line, 2=column, 3=text
- public string warningMsgFormat = "{0}({1},{2}): warning: {3}"; // 0=filename, 1=line, 2=column, 3=text
-
- public void SynErr(string filename, int line, int col, int n) {
- SynErr(filename, line, col, GetSyntaxErrorString(n));
- }
-
- public virtual void SynErr(string filename, int line, int col, string/*!*/ msg) {
- Contract.Requires(msg != null);
- errorStream.WriteLine(errMsgFormat, filename, line, col, msg);
- count++;
- }
-
- /// <summary>
- /// Returns a string corresponding to the syntax error of the given type
- /// Note that many of these errors (0-98) correspond to token types (e.g. the la token)
- /// </summary>
- /// <param name="n"></param>
- /// <returns></returns>
- string GetSyntaxErrorString(int n) {
- string s;
- switch (n) {
- case 0: s = "EOF expected"; break;
- case 1: s = "ident expected"; break;
- case 2: s = "bvlit expected"; break;
- case 3: s = "digits expected"; break;
- case 4: s = "string expected"; break;
- case 5: s = "decimal expected"; break;
- case 6: s = "float expected"; break;
- case 7: s = "\"var\" expected"; break;
- case 8: s = "\";\" expected"; break;
- case 9: s = "\"(\" expected"; break;
- case 10: s = "\")\" expected"; break;
- case 11: s = "\":\" expected"; break;
- case 12: s = "\",\" expected"; break;
- case 13: s = "\"where\" expected"; break;
- case 14: s = "\"int\" expected"; break;
- case 15: s = "\"real\" expected"; break;
- case 16: s = "\"bool\" expected"; break;
- case 17: s = "\"[\" expected"; break;
- case 18: s = "\"]\" expected"; break;
- case 19: s = "\"<\" expected"; break;
- case 20: s = "\">\" expected"; break;
- case 21: s = "\"const\" expected"; break;
- case 22: s = "\"unique\" expected"; break;
- case 23: s = "\"extends\" expected"; break;
- case 24: s = "\"complete\" expected"; break;
- case 25: s = "\"function\" expected"; break;
- case 26: s = "\"returns\" expected"; break;
- case 27: s = "\"{\" expected"; break;
- case 28: s = "\"}\" expected"; break;
- case 29: s = "\"axiom\" expected"; break;
- case 30: s = "\"type\" expected"; break;
- case 31: s = "\"=\" expected"; break;
- case 32: s = "\"procedure\" expected"; break;
- case 33: s = "\"implementation\" expected"; break;
- case 34: s = "\"modifies\" expected"; break;
- case 35: s = "\"free\" expected"; break;
- case 36: s = "\"requires\" expected"; break;
- case 37: s = "\"ensures\" expected"; break;
- case 38: s = "\"goto\" expected"; break;
- case 39: s = "\"return\" expected"; break;
- case 40: s = "\"if\" expected"; break;
- case 41: s = "\"else\" expected"; break;
- case 42: s = "\"while\" expected"; break;
- case 43: s = "\"invariant\" expected"; break;
- case 44: s = "\"*\" expected"; break;
- case 45: s = "\"break\" expected"; break;
- case 46: s = "\"assert\" expected"; break;
- case 47: s = "\"assume\" expected"; break;
- case 48: s = "\"havoc\" expected"; break;
- case 49: s = "\"yield\" expected"; break;
- case 50: s = "\":=\" expected"; break;
- case 51: s = "\"async\" expected"; break;
- case 52: s = "\"call\" expected"; break;
- case 53: s = "\"par\" expected"; break;
- case 54: s = "\"|\" expected"; break;
- case 55: s = "\"<==>\" expected"; break;
- case 56: s = "\"\\u21d4\" expected"; break;
- case 57: s = "\"==>\" expected"; break;
- case 58: s = "\"\\u21d2\" expected"; break;
- case 59: s = "\"<==\" expected"; break;
- case 60: s = "\"\\u21d0\" expected"; break;
- case 61: s = "\"&&\" expected"; break;
- case 62: s = "\"\\u2227\" expected"; break;
- case 63: s = "\"||\" expected"; break;
- case 64: s = "\"\\u2228\" expected"; break;
- case 65: s = "\"==\" expected"; break;
- case 66: s = "\"<=\" expected"; break;
- case 67: s = "\">=\" expected"; break;
- case 68: s = "\"!=\" expected"; break;
- case 69: s = "\"<:\" expected"; break;
- case 70: s = "\"\\u2260\" expected"; break;
- case 71: s = "\"\\u2264\" expected"; break;
- case 72: s = "\"\\u2265\" expected"; break;
- case 73: s = "\"++\" expected"; break;
- case 74: s = "\"+\" expected"; break;
- case 75: s = "\"-\" expected"; break;
- case 76: s = "\"div\" expected"; break;
- case 77: s = "\"mod\" expected"; break;
- case 78: s = "\"/\" expected"; break;
- case 79: s = "\"**\" expected"; break;
- case 80: s = "\"!\" expected"; break;
- case 81: s = "\"\\u00ac\" expected"; break;
- case 82: s = "\"false\" expected"; break;
- case 83: s = "\"true\" expected"; break;
- case 84: s = "\"old\" expected"; break;
- case 85: s = "\"|{\" expected"; break;
- case 86: s = "\"}|\" expected"; break;
- case 87: s = "\"then\" expected"; break;
- case 88: s = "\"forall\" expected"; break;
- case 89: s = "\"\\u2200\" expected"; break;
- case 90: s = "\"exists\" expected"; break;
- case 91: s = "\"\\u2203\" expected"; break;
- case 92: s = "\"lambda\" expected"; break;
- case 93: s = "\"\\u03bb\" expected"; break;
- case 94: s = "\"::\" expected"; break;
- case 95: s = "\"\\u2022\" expected"; break;
- case 96: s = "??? expected"; 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 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;
- case 137: s = "invalid Float"; break;
-
- default: s = "error " + n; break;
- }
- return s;
- }
-
- public void SemErr(IToken/*!*/ tok, string/*!*/ msg) { // semantic errors
- Contract.Requires(tok != null);
- Contract.Requires(msg != null);
- SemErr(tok.filename, tok.line, tok.col, msg);
- }
-
- public virtual void SemErr(string filename, int line, int col, string/*!*/ msg) {
- Contract.Requires(msg != null);
- errorStream.WriteLine(errMsgFormat, filename, line, col, msg);
- count++;
- }
-
- public void Warning(IToken/*!*/ tok, string/*!*/ msg) { // warnings
- Contract.Requires(tok != null);
- Contract.Requires(msg != null);
- Warning(tok.filename, tok.line, tok.col, msg);
- }
-
- public virtual void Warning(string filename, int line, int col, string msg) {
- Contract.Requires(msg != null);
- errorStream.WriteLine(warningMsgFormat, filename, line, col, msg);
- }
-} // Errors
-
-
-public class FatalError: Exception {
- public FatalError(string m): base(m) {}
-}
-
-
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using Microsoft.Boogie;
+using Microsoft.Basetypes;
+using Bpl = Microsoft.Boogie;
+
+
+
+
+using System;
+using System.Diagnostics.Contracts;
+
+namespace Microsoft.Boogie {
+
+
+
+public class Parser {
+ public const int _EOF = 0;
+ public const int _ident = 1;
+ public const int _bvlit = 2;
+ public const int _digits = 3;
+ 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;
+ const bool x = false;
+ const int minErrDist = 2;
+
+ public Scanner/*!*/ scanner;
+ public Errors/*!*/ errors;
+
+ public Token/*!*/ t; // last recognized token
+ public Token/*!*/ la; // lookahead token
+ int errDist = minErrDist;
+
+readonly Program/*!*/ Pgm;
+
+readonly Expr/*!*/ dummyExpr;
+readonly Cmd/*!*/ dummyCmd;
+readonly Block/*!*/ dummyBlock;
+readonly Bpl.Type/*!*/ dummyType;
+readonly List<Expr>/*!*/ dummyExprSeq;
+readonly TransferCmd/*!*/ dummyTransferCmd;
+readonly StructuredCmd/*!*/ dummyStructuredCmd;
+
+///<summary>
+///Returns the number of parsing errors encountered. If 0, "program" returns as
+///the parsed program.
+///</summary>
+public static int Parse (string/*!*/ filename, /*maybe null*/ List<string/*!*/> 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<string/*!*/>();
+ }
+
+ 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<Cmd>(), new ReturnCmd(Token.NoToken));
+ dummyType = new BasicType(Token.NoToken, SimpleType.Bool);
+ dummyExprSeq = new List<Expr> ();
+ 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, /*immutable=*/ false) {
+ Contract.Requires(tok != null);
+ this.Lower = lower;
+ this.Upper = upper;
+ }
+ public override Bpl.Type/*!*/ ShallowType { get {Contract.Ensures(Contract.Result<Bpl.Type>() != 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<object>/*!*/ freeVars) { Contract.Assert(false);throw new cce.UnreachableException(); }
+ public override int ComputeHashCode() {
+ return base.GetHashCode();
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+
+ public Parser(Scanner/*!*/ scanner, Errors/*!*/ errors) {
+ this.scanner = scanner;
+ this.errors = errors;
+ Token/*!*/ tok = new Token();
+ tok.val = "";
+ this.la = tok;
+ this.t = new Token(); // just to satisfy its non-null constraint
+ }
+
+ void SynErr (int n) {
+ if (errDist >= minErrDist) errors.SynErr(la.filename, la.line, la.col, n);
+ errDist = 0;
+ }
+
+ public void SemErr (string/*!*/ msg) {
+ Contract.Requires(msg != null);
+ if (errDist >= minErrDist) errors.SemErr(t, msg);
+ errDist = 0;
+ }
+
+ public void SemErr(IToken/*!*/ tok, string/*!*/ msg) {
+ Contract.Requires(tok != null);
+ Contract.Requires(msg != null);
+ errors.SemErr(tok, msg);
+ }
+
+ void Get () {
+ for (;;) {
+ t = la;
+ la = scanner.Scan();
+ if (la.kind <= maxT) { ++errDist; break; }
+
+ la = t;
+ }
+ }
+
+ void Expect (int n) {
+ if (la.kind==n) Get(); else { SynErr(n); }
+ }
+
+ bool StartOf (int s) {
+ return set[s, la.kind];
+ }
+
+ void ExpectWeak (int n, int follow) {
+ if (la.kind == n) Get();
+ else {
+ SynErr(n);
+ while (!StartOf(follow)) Get();
+ }
+ }
+
+
+ bool WeakSeparator(int n, int syFol, int repFol) {
+ int kind = la.kind;
+ if (kind == n) {Get(); return true;}
+ else if (StartOf(repFol)) {return false;}
+ else {
+ SynErr(n);
+ while (!(set[syFol, kind] || set[repFol, kind] || set[0, kind])) {
+ Get();
+ kind = la.kind;
+ }
+ return StartOf(syFol);
+ }
+ }
+
+
+ void BoogiePL() {
+ List<Variable>/*!*/ vs;
+ List<Declaration>/*!*/ ds;
+ Axiom/*!*/ ax;
+ List<Declaration/*!*/>/*!*/ ts;
+ Procedure/*!*/ pr;
+ Implementation im;
+ Implementation/*!*/ nnim;
+
+ while (StartOf(1)) {
+ switch (la.kind) {
+ case 21: {
+ Consts(out vs);
+ foreach(Bpl.Variable/*!*/ v in vs){
+ Contract.Assert(v != null);
+ Pgm.AddTopLevelDeclaration(v);
+ }
+
+ break;
+ }
+ case 25: {
+ Function(out ds);
+ foreach(Bpl.Declaration/*!*/ d in ds){
+ Contract.Assert(d != null);
+ Pgm.AddTopLevelDeclaration(d);
+ }
+
+ break;
+ }
+ case 29: {
+ Axiom(out ax);
+ Pgm.AddTopLevelDeclaration(ax);
+ break;
+ }
+ case 30: {
+ UserDefinedTypes(out ts);
+ foreach(Declaration/*!*/ td in ts){
+ Contract.Assert(td != null);
+ Pgm.AddTopLevelDeclaration(td);
+ }
+
+ break;
+ }
+ case 7: {
+ GlobalVars(out vs);
+ foreach(Bpl.Variable/*!*/ v in vs){
+ Contract.Assert(v != null);
+ Pgm.AddTopLevelDeclaration(v);
+ }
+
+ break;
+ }
+ case 32: {
+ Procedure(out pr, out im);
+ Pgm.AddTopLevelDeclaration(pr);
+ if (im != null) {
+ Pgm.AddTopLevelDeclaration(im);
+ }
+
+ break;
+ }
+ case 33: {
+ Implementation(out nnim);
+ Pgm.AddTopLevelDeclaration(nnim);
+ break;
+ }
+ }
+ }
+ Expect(0);
+ }
+
+ void Consts(out List<Variable>/*!*/ ds) {
+ Contract.Ensures(Contract.ValueAtReturn(out ds) != null); IToken/*!*/ y; List<TypedIdent>/*!*/ xs;
+ ds = new List<Variable>();
+ bool u = false; QKeyValue kv = null;
+ bool ChildrenComplete = false;
+ List<ConstantParent/*!*/> Parents = null;
+ Expect(21);
+ y = t;
+ while (la.kind == 27) {
+ Attribute(ref kv);
+ }
+ if (la.kind == 22) {
+ Get();
+ u = true;
+ }
+ IdsType(out xs);
+ if (la.kind == 23) {
+ OrderSpec(out ChildrenComplete, out Parents);
+ }
+ bool makeClone = false;
+ foreach(TypedIdent/*!*/ x in xs){
+ Contract.Assert(x != null);
+
+ // ensure that no sharing is introduced
+ List<ConstantParent/*!*/> ParentsClone;
+ if (makeClone && Parents != null) {
+ ParentsClone = new List<ConstantParent/*!*/> ();
+ 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));
+ }
+
+ Expect(8);
+ }
+
+ void Function(out List<Declaration>/*!*/ ds) {
+ Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
+ ds = new List<Declaration>(); IToken/*!*/ z;
+ IToken/*!*/ typeParamTok;
+ var typeParams = new List<TypeVariable>();
+ var arguments = new List<Variable>();
+ TypedIdent/*!*/ tyd;
+ TypedIdent retTyd = null;
+ Bpl.Type/*!*/ retTy;
+ QKeyValue argKv = null;
+ QKeyValue kv = null;
+ Expr definition = null;
+ Expr/*!*/ tmp;
+
+ Expect(25);
+ while (la.kind == 27) {
+ Attribute(ref kv);
+ }
+ Ident(out z);
+ if (la.kind == 19) {
+ TypeParams(out typeParamTok, out typeParams);
+ }
+ Expect(9);
+ if (StartOf(2)) {
+ VarOrType(out tyd, out argKv);
+ arguments.Add(new Formal(tyd.tok, tyd, true, argKv));
+ while (la.kind == 12) {
+ Get();
+ VarOrType(out tyd, out argKv);
+ arguments.Add(new Formal(tyd.tok, tyd, true, argKv));
+ }
+ }
+ Expect(10);
+ argKv = null;
+ if (la.kind == 26) {
+ Get();
+ Expect(9);
+ VarOrType(out retTyd, out argKv);
+ Expect(10);
+ } else if (la.kind == 11) {
+ Get();
+ Type(out retTy);
+ retTyd = new TypedIdent(retTy.tok, TypedIdent.NoName, retTy);
+ } else SynErr(99);
+ if (la.kind == 27) {
+ Get();
+ Expression(out tmp);
+ definition = tmp;
+ Expect(28);
+ } else if (la.kind == 8) {
+ Get();
+ } 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));
+ }
+ 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));
+ }
+ }
+
+ }
+
+ void Axiom(out Axiom/*!*/ m) {
+ Contract.Ensures(Contract.ValueAtReturn(out m) != null); Expr/*!*/ e; QKeyValue kv = null;
+ Expect(29);
+ while (la.kind == 27) {
+ Attribute(ref kv);
+ }
+ IToken/*!*/ x = t;
+ Proposition(out e);
+ Expect(8);
+ m = new Axiom(x,e, null, kv);
+ }
+
+ void UserDefinedTypes(out List<Declaration/*!*/>/*!*/ ts) {
+ Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out ts))); Declaration/*!*/ decl; QKeyValue kv = null; ts = new List<Declaration/*!*/> ();
+ Expect(30);
+ while (la.kind == 27) {
+ Attribute(ref kv);
+ }
+ UserDefinedType(out decl, kv);
+ ts.Add(decl);
+ while (la.kind == 12) {
+ Get();
+ UserDefinedType(out decl, kv);
+ ts.Add(decl);
+ }
+ Expect(8);
+ }
+
+ void GlobalVars(out List<Variable>/*!*/ ds) {
+ Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
+ QKeyValue kv = null;
+ ds = new List<Variable>();
+ var dsx = ds;
+
+ Expect(7);
+ while (la.kind == 27) {
+ Attribute(ref kv);
+ }
+ IdsTypeWheres(true, "global variables", delegate(TypedIdent tyd) { dsx.Add(new GlobalVariable(tyd.tok, tyd, kv)); } );
+ Expect(8);
+ }
+
+ void Procedure(out Procedure/*!*/ proc, out /*maybe null*/ Implementation impl) {
+ Contract.Ensures(Contract.ValueAtReturn(out proc) != null); IToken/*!*/ x;
+ List<TypeVariable>/*!*/ typeParams;
+ List<Variable>/*!*/ ins, outs;
+ List<Requires>/*!*/ pre = new List<Requires>();
+ List<IdentifierExpr>/*!*/ mods = new List<IdentifierExpr>();
+ List<Ensures>/*!*/ post = new List<Ensures>();
+
+ List<Variable>/*!*/ locals = new List<Variable>();
+ StmtList/*!*/ stmtList;
+ QKeyValue kv = null;
+ impl = null;
+
+ Expect(32);
+ ProcSignature(true, out x, out typeParams, out ins, out outs, out kv);
+ if (la.kind == 8) {
+ Get();
+ while (StartOf(3)) {
+ Spec(pre, mods, post);
+ }
+ } else if (StartOf(4)) {
+ while (StartOf(3)) {
+ Spec(pre, mods, post);
+ }
+ ImplBody(out locals, out stmtList);
+ 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);
+ proc = new Procedure(x, x.val, typeParams, ins, outs, pre, mods, post, kv);
+ }
+
+ void Implementation(out Implementation/*!*/ impl) {
+ Contract.Ensures(Contract.ValueAtReturn(out impl) != null); IToken/*!*/ x;
+ List<TypeVariable>/*!*/ typeParams;
+ List<Variable>/*!*/ ins, outs;
+ List<Variable>/*!*/ locals;
+ StmtList/*!*/ stmtList;
+ QKeyValue kv;
+
+ Expect(33);
+ ProcSignature(false, out x, out typeParams, out ins, out outs, out kv);
+ ImplBody(out locals, out stmtList);
+ impl = new Implementation(x, x.val, typeParams, ins, outs, locals, stmtList, kv, this.errors);
+ }
+
+ void Attribute(ref QKeyValue kv) {
+ Trigger trig = null;
+ AttributeOrTrigger(ref kv, ref trig);
+ if (trig != null) this.SemErr("only attributes, not triggers, allowed here");
+ }
+
+ void IdsTypeWheres(bool allowWhereClauses, string context, System.Action<TypedIdent> action ) {
+ IdsTypeWhere(allowWhereClauses, context, action);
+ while (la.kind == 12) {
+ Get();
+ IdsTypeWhere(allowWhereClauses, context, action);
+ }
+ }
+
+ void LocalVars(List<Variable>/*!*/ ds) {
+ Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
+ QKeyValue kv = null;
+
+ Expect(7);
+ while (la.kind == 27) {
+ Attribute(ref kv);
+ }
+ IdsTypeWheres(true, "local variables", delegate(TypedIdent tyd) { ds.Add(new LocalVariable(tyd.tok, tyd, kv)); } );
+ Expect(8);
+ }
+
+ void ProcFormals(bool incoming, bool allowWhereClauses, out List<Variable>/*!*/ ds) {
+ Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
+ ds = new List<Variable>();
+ var dsx = ds;
+ var context = allowWhereClauses ? "procedure formals" : "the 'implementation' copies of formals";
+
+ Expect(9);
+ if (la.kind == 1 || la.kind == 27) {
+ AttrsIdsTypeWheres(allowWhereClauses, allowWhereClauses, context, delegate(TypedIdent tyd, QKeyValue kv) { dsx.Add(new Formal(tyd.tok, tyd, incoming, kv)); });
+ }
+ Expect(10);
+ }
+
+ void AttrsIdsTypeWheres(bool allowAttributes, bool allowWhereClauses, string context, System.Action<TypedIdent, QKeyValue> action ) {
+ AttributesIdsTypeWhere(allowAttributes, allowWhereClauses, context, action);
+ while (la.kind == 12) {
+ Get();
+ AttributesIdsTypeWhere(allowAttributes, allowWhereClauses, context, action);
+ }
+ }
+
+ void BoundVars(IToken/*!*/ x, out List<Variable>/*!*/ ds) {
+ Contract.Requires(x != null);
+ Contract.Ensures(Contract.ValueAtReturn(out ds) != null);
+ List<TypedIdent>/*!*/ tyds = new List<TypedIdent>();
+ ds = new List<Variable>();
+ var dsx = ds;
+
+ AttrsIdsTypeWheres(true, false, "bound variables", delegate(TypedIdent tyd, QKeyValue kv) { dsx.Add(new BoundVariable(tyd.tok, tyd, kv)); } );
+ }
+
+ void IdsType(out List<TypedIdent>/*!*/ tyds) {
+ Contract.Ensures(Contract.ValueAtReturn(out tyds) != null); List<IToken>/*!*/ ids; Bpl.Type/*!*/ ty;
+ Idents(out ids);
+ Expect(11);
+ Type(out ty);
+ tyds = new List<TypedIdent>();
+ foreach(Token/*!*/ id in ids){
+ Contract.Assert(id != null);
+ tyds.Add(new TypedIdent(id, id.val, ty, null));
+ }
+
+ }
+
+ void Idents(out List<IToken>/*!*/ xs) {
+ Contract.Ensures(Contract.ValueAtReturn(out xs) != null); IToken/*!*/ id; xs = new List<IToken>();
+ Ident(out id);
+ xs.Add(id);
+ while (la.kind == 12) {
+ Get();
+ Ident(out id);
+ xs.Add(id);
+ }
+ }
+
+ void Type(out Bpl.Type/*!*/ ty) {
+ Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken/*!*/ tok; ty = dummyType;
+ if (StartOf(5)) {
+ TypeAtom(out ty);
+ } else if (la.kind == 1) {
+ Ident(out tok);
+ List<Bpl.Type>/*!*/ args = new List<Bpl.Type> ();
+ if (StartOf(6)) {
+ TypeArgs(args);
+ }
+ ty = new UnresolvedTypeIdentifier (tok, tok.val, args);
+ } else if (la.kind == 17 || la.kind == 19) {
+ MapType(out ty);
+ } else SynErr(100);
+ }
+
+ void AttributesIdsTypeWhere(bool allowAttributes, bool allowWhereClauses, string context, System.Action<TypedIdent, QKeyValue> action ) {
+ QKeyValue kv = null;
+ while (la.kind == 27) {
+ Attribute(ref kv);
+ if (!allowAttributes) {
+ kv = null;
+ this.SemErr("attributes are not allowed on " + context);
+ }
+
+ }
+ IdsTypeWhere(allowWhereClauses, context, delegate(TypedIdent tyd) { action(tyd, kv); });
+ }
+
+ void IdsTypeWhere(bool allowWhereClauses, string context, System.Action<TypedIdent> action ) {
+ List<IToken>/*!*/ ids; Bpl.Type/*!*/ ty; Expr wh = null; Expr/*!*/ nne;
+ Idents(out ids);
+ Expect(11);
+ Type(out ty);
+ if (la.kind == 13) {
+ Get();
+ Expression(out nne);
+ 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));
+ }
+
+ }
+
+ void Expression(out Expr/*!*/ e0) {
+ Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1;
+ ImpliesExpression(false, out e0);
+ while (la.kind == 55 || la.kind == 56) {
+ EquivOp();
+ x = t;
+ ImpliesExpression(false, out e1);
+ e0 = Expr.Binary(x, BinaryOperator.Opcode.Iff, e0, e1);
+ }
+ }
+
+ void TypeAtom(out Bpl.Type/*!*/ ty) {
+ Contract.Ensures(Contract.ValueAtReturn(out ty) != null); ty = dummyType;
+ if (la.kind == 14) {
+ Get();
+ ty = new BasicType(t, SimpleType.Int);
+ } else if (la.kind == 15) {
+ Get();
+ ty = new BasicType(t, SimpleType.Real);
+ } else if (la.kind == 98) {
+ Get();
+ ty = FType();
+ } else if (la.kind == 16) {
+ Get();
+ ty = new BasicType(t, SimpleType.Bool);
+ } else if (la.kind == 9) {
+ Get();
+ Type(out ty);
+ Expect(10);
+ } 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);
+ x = t;
+ if (x.val.StartsWith("\\"))
+ x.val = x.val.Substring(1);
+
+ }
+
+ void TypeArgs(List<Bpl.Type>/*!*/ ts) {
+ Contract.Requires(ts != null); IToken/*!*/ tok; Bpl.Type/*!*/ ty;
+ if (StartOf(5)) {
+ TypeAtom(out ty);
+ ts.Add(ty);
+ if (StartOf(6)) {
+ TypeArgs(ts);
+ }
+ } else if (la.kind == 1) {
+ Ident(out tok);
+ List<Bpl.Type>/*!*/ args = new List<Bpl.Type> ();
+ ts.Add(new UnresolvedTypeIdentifier (tok, tok.val, args));
+ if (StartOf(6)) {
+ TypeArgs(ts);
+ }
+ } else if (la.kind == 17 || la.kind == 19) {
+ MapType(out ty);
+ ts.Add(ty);
+ } else SynErr(102);
+ }
+
+ void MapType(out Bpl.Type/*!*/ ty) {
+ Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken tok = null;
+ IToken/*!*/ nnTok;
+ List<Bpl.Type>/*!*/ arguments = new List<Bpl.Type>();
+ Bpl.Type/*!*/ result;
+ List<TypeVariable>/*!*/ typeParameters = new List<TypeVariable>();
+
+ if (la.kind == 19) {
+ TypeParams(out nnTok, out typeParameters);
+ tok = nnTok;
+ }
+ Expect(17);
+ if (tok == null) tok = t;
+ if (StartOf(6)) {
+ Types(arguments);
+ }
+ Expect(18);
+ Type(out result);
+ ty = new MapType(tok, typeParameters, arguments, result);
+
+ }
+
+ void TypeParams(out IToken/*!*/ tok, out List<TypeVariable>/*!*/ typeParams) {
+ Contract.Ensures(Contract.ValueAtReturn(out tok) != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); List<IToken>/*!*/ typeParamToks;
+ Expect(19);
+ tok = t;
+ Idents(out typeParamToks);
+ Expect(20);
+ typeParams = new List<TypeVariable> ();
+ foreach(Token/*!*/ id in typeParamToks){
+ Contract.Assert(id != null);
+ typeParams.Add(new TypeVariable(id, id.val));}
+
+ }
+
+ void Types(List<Bpl.Type>/*!*/ ts) {
+ Contract.Requires(ts != null); Bpl.Type/*!*/ ty;
+ Type(out ty);
+ ts.Add(ty);
+ while (la.kind == 12) {
+ Get();
+ Type(out ty);
+ ts.Add(ty);
+ }
+ }
+
+ void OrderSpec(out bool ChildrenComplete, out List<ConstantParent/*!*/> Parents) {
+ Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out Parents),true)); ChildrenComplete = false;
+ Parents = null;
+ bool u;
+ IToken/*!*/ parent;
+ Expect(23);
+ Parents = new List<ConstantParent/*!*/> ();
+ u = false;
+ if (la.kind == 1 || la.kind == 22) {
+ if (la.kind == 22) {
+ Get();
+ u = true;
+ }
+ Ident(out parent);
+ Parents.Add(new ConstantParent (
+ new IdentifierExpr(parent, parent.val), u));
+ while (la.kind == 12) {
+ Get();
+ u = false;
+ if (la.kind == 22) {
+ Get();
+ u = true;
+ }
+ Ident(out parent);
+ Parents.Add(new ConstantParent (
+ new IdentifierExpr(parent, parent.val), u));
+ }
+ }
+ if (la.kind == 24) {
+ Get();
+ ChildrenComplete = true;
+ }
+ }
+
+ void VarOrType(out TypedIdent/*!*/ tyd, out QKeyValue kv) {
+ Contract.Ensures(Contract.ValueAtReturn(out tyd) != null);
+ string/*!*/ varName = TypedIdent.NoName;
+ Bpl.Type/*!*/ ty;
+ IToken/*!*/ tok;
+ kv = null;
+
+ while (la.kind == 27) {
+ Attribute(ref kv);
+ }
+ Type(out ty);
+ tok = ty.tok;
+ if (la.kind == 11) {
+ Get();
+ var uti = ty as UnresolvedTypeIdentifier;
+ if (uti != null && uti.Arguments.Count == 0) {
+ varName = uti.Name;
+ } else {
+ this.SemErr("expected identifier before ':'");
+ }
+
+ Type(out ty);
+ }
+ tyd = new TypedIdent(tok, varName, ty);
+ }
+
+ void Proposition(out Expr/*!*/ e) {
+ Contract.Ensures(Contract.ValueAtReturn(out e) != null);
+ Expression(out e);
+ }
+
+ void UserDefinedType(out Declaration/*!*/ decl, QKeyValue kv) {
+ Contract.Ensures(Contract.ValueAtReturn(out decl) != null); IToken/*!*/ id; List<IToken>/*!*/ paramTokens = new List<IToken> ();
+ Bpl.Type/*!*/ body = dummyType; bool synonym = false;
+ Ident(out id);
+ if (la.kind == 1) {
+ WhiteSpaceIdents(out paramTokens);
+ }
+ if (la.kind == 31) {
+ Get();
+ Type(out body);
+ synonym = true;
+ }
+ if (synonym) {
+ List<TypeVariable>/*!*/ typeParams = new List<TypeVariable>();
+ 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);
+ }
+
+ }
+
+ void WhiteSpaceIdents(out List<IToken>/*!*/ xs) {
+ Contract.Ensures(Contract.ValueAtReturn(out xs) != null); IToken/*!*/ id; xs = new List<IToken>();
+ Ident(out id);
+ xs.Add(id);
+ while (la.kind == 1) {
+ Ident(out id);
+ xs.Add(id);
+ }
+ }
+
+ void ProcSignature(bool allowWhereClausesOnFormals, out IToken/*!*/ name, out List<TypeVariable>/*!*/ typeParams,
+out List<Variable>/*!*/ ins, out List<Variable>/*!*/ 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<TypeVariable>();
+ outs = new List<Variable>(); kv = null;
+ while (la.kind == 27) {
+ Attribute(ref kv);
+ }
+ Ident(out name);
+ if (la.kind == 19) {
+ TypeParams(out typeParamTok, out typeParams);
+ }
+ ProcFormals(true, allowWhereClausesOnFormals, out ins);
+ if (la.kind == 26) {
+ Get();
+ ProcFormals(false, allowWhereClausesOnFormals, out outs);
+ }
+ }
+
+ void Spec(List<Requires>/*!*/ pre, List<IdentifierExpr>/*!*/ mods, List<Ensures>/*!*/ post) {
+ Contract.Requires(pre != null); Contract.Requires(mods != null); Contract.Requires(post != null); List<IToken>/*!*/ ms;
+ if (la.kind == 34) {
+ Get();
+ if (la.kind == 1) {
+ Idents(out ms);
+ foreach(IToken/*!*/ m in ms){
+ Contract.Assert(m != null);
+ mods.Add(new IdentifierExpr(m, m.val));
+ }
+
+ }
+ Expect(8);
+ } else if (la.kind == 35) {
+ Get();
+ SpecPrePost(true, pre, post);
+ } else if (la.kind == 36 || la.kind == 37) {
+ SpecPrePost(false, pre, post);
+ } else SynErr(103);
+ }
+
+ void ImplBody(out List<Variable>/*!*/ locals, out StmtList/*!*/ stmtList) {
+ Contract.Ensures(Contract.ValueAtReturn(out locals) != null); Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); locals = new List<Variable>();
+ Expect(27);
+ while (la.kind == 7) {
+ LocalVars(locals);
+ }
+ StmtList(out stmtList);
+ }
+
+ void SpecPrePost(bool free, List<Requires>/*!*/ pre, List<Ensures>/*!*/ post) {
+ Contract.Requires(pre != null); Contract.Requires(post != null); Expr/*!*/ e; Token tok = null; QKeyValue kv = null;
+ if (la.kind == 36) {
+ Get();
+ tok = t;
+ while (la.kind == 27) {
+ Attribute(ref kv);
+ }
+ Proposition(out e);
+ Expect(8);
+ pre.Add(new Requires(tok, free, e, null, kv));
+ } else if (la.kind == 37) {
+ Get();
+ tok = t;
+ while (la.kind == 27) {
+ Attribute(ref kv);
+ }
+ Proposition(out e);
+ Expect(8);
+ post.Add(new Ensures(tok, free, e, null, kv));
+ } else SynErr(104);
+ }
+
+ void StmtList(out StmtList/*!*/ stmtList) {
+ Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); List<BigBlock/*!*/> bigblocks = new List<BigBlock/*!*/>();
+ /* built-up state for the current BigBlock: */
+ IToken startToken = null; string currentLabel = null;
+ List<Cmd> 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;
+
+ while (StartOf(7)) {
+ if (StartOf(8)) {
+ LabelOrCmd(out c, out label);
+ if (c != null) {
+ // LabelOrCmd read a Cmd
+ Contract.Assert(label == null);
+ if (startToken == null) { startToken = c.tok; cs = new List<Cmd>(); }
+ 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<Cmd>();
+ }
+
+ } else if (la.kind == 40 || la.kind == 42 || la.kind == 45) {
+ StructuredCmd(out ecn);
+ ec = ecn;
+ if (startToken == null) { startToken = ec.tok; cs = new List<Cmd>(); }
+ Contract.Assert(cs != null);
+ b = new BigBlock(startToken, currentLabel, cs, ec, null);
+ bigblocks.Add(b);
+ startToken = null; currentLabel = null; cs = null;
+
+ } else {
+ TransferCmd(out tcn);
+ tc = tcn;
+ if (startToken == null) { startToken = tc.tok; cs = new List<Cmd>(); }
+ Contract.Assert(cs != null);
+ b = new BigBlock(startToken, currentLabel, cs, null, tc);
+ bigblocks.Add(b);
+ startToken = null; currentLabel = null; cs = null;
+
+ }
+ }
+ Expect(28);
+ IToken/*!*/ endCurly = t;
+ if (startToken == null && bigblocks.Count == 0) {
+ startToken = t; cs = new List<Cmd>();
+ }
+ if (startToken != null) {
+ Contract.Assert(cs != null);
+ b = new BigBlock(startToken, currentLabel, cs, null, null);
+ bigblocks.Add(b);
+ }
+
+ stmtList = new StmtList(bigblocks, endCurly);
+
+ }
+
+ void LabelOrCmd(out Cmd c, out IToken label) {
+ IToken/*!*/ x; Expr/*!*/ e;
+ List<IToken>/*!*/ xs;
+ List<IdentifierExpr> ids;
+ c = dummyCmd; label = null;
+ Cmd/*!*/ cn;
+ QKeyValue kv = null;
+
+ switch (la.kind) {
+ case 1: {
+ LabelOrAssign(out c, out label);
+ break;
+ }
+ case 46: {
+ Get();
+ x = t;
+ while (la.kind == 27) {
+ Attribute(ref kv);
+ }
+ Proposition(out e);
+ c = new AssertCmd(x, e, kv);
+ Expect(8);
+ break;
+ }
+ case 47: {
+ Get();
+ x = t;
+ while (la.kind == 27) {
+ Attribute(ref kv);
+ }
+ Proposition(out e);
+ c = new AssumeCmd(x, e, kv);
+ Expect(8);
+ break;
+ }
+ case 48: {
+ Get();
+ x = t;
+ Idents(out xs);
+ Expect(8);
+ ids = new List<IdentifierExpr>();
+ foreach(IToken/*!*/ y in xs){
+ Contract.Assert(y != null);
+ ids.Add(new IdentifierExpr(y, y.val));
+ }
+ c = new HavocCmd(x,ids);
+
+ break;
+ }
+ case 35: case 51: case 52: {
+ CallCmd(out cn);
+ Expect(8);
+ c = cn;
+ break;
+ }
+ case 53: {
+ ParCallCmd(out cn);
+ c = cn;
+ break;
+ }
+ case 49: {
+ Get();
+ x = t;
+ Expect(8);
+ c = new YieldCmd(x);
+ break;
+ }
+ default: SynErr(105); break;
+ }
+ }
+
+ void StructuredCmd(out StructuredCmd/*!*/ ec) {
+ Contract.Ensures(Contract.ValueAtReturn(out ec) != null); ec = dummyStructuredCmd; Contract.Assume(cce.IsPeerConsistent(ec));
+ IfCmd/*!*/ ifcmd; WhileCmd/*!*/ wcmd; BreakCmd/*!*/ bcmd;
+
+ if (la.kind == 40) {
+ IfCmd(out ifcmd);
+ ec = ifcmd;
+ } else if (la.kind == 42) {
+ WhileCmd(out wcmd);
+ ec = wcmd;
+ } else if (la.kind == 45) {
+ BreakCmd(out bcmd);
+ ec = bcmd;
+ } else SynErr(106);
+ }
+
+ void TransferCmd(out TransferCmd/*!*/ tc) {
+ Contract.Ensures(Contract.ValueAtReturn(out tc) != null); tc = dummyTransferCmd;
+ Token y; List<IToken>/*!*/ xs;
+ List<String> ss = new List<String>();
+
+ if (la.kind == 38) {
+ Get();
+ y = t;
+ Idents(out xs);
+ foreach(IToken/*!*/ s in xs){
+ Contract.Assert(s != null);
+ ss.Add(s.val); }
+ tc = new GotoCmd(y, ss);
+
+ } else if (la.kind == 39) {
+ Get();
+ tc = new ReturnCmd(t);
+ } else SynErr(107);
+ Expect(8);
+ }
+
+ void IfCmd(out IfCmd/*!*/ ifcmd) {
+ Contract.Ensures(Contract.ValueAtReturn(out ifcmd) != null); IToken/*!*/ x;
+ Expr guard;
+ StmtList/*!*/ thn;
+ IfCmd/*!*/ elseIf; IfCmd elseIfOption = null;
+ StmtList/*!*/ els; StmtList elseOption = null;
+
+ Expect(40);
+ x = t;
+ Guard(out guard);
+ Expect(27);
+ StmtList(out thn);
+ if (la.kind == 41) {
+ Get();
+ if (la.kind == 40) {
+ IfCmd(out elseIf);
+ elseIfOption = elseIf;
+ } else if (la.kind == 27) {
+ Get();
+ StmtList(out els);
+ elseOption = els;
+ } else SynErr(108);
+ }
+ ifcmd = new IfCmd(x, guard, thn, elseIfOption, elseOption);
+ }
+
+ void WhileCmd(out WhileCmd/*!*/ wcmd) {
+ Contract.Ensures(Contract.ValueAtReturn(out wcmd) != null); IToken/*!*/ x; Token z;
+ Expr guard; Expr/*!*/ e; bool isFree;
+ List<PredicateCmd/*!*/> invariants = new List<PredicateCmd/*!*/>();
+ StmtList/*!*/ body;
+ QKeyValue kv = null;
+
+ Expect(42);
+ x = t;
+ Guard(out guard);
+ Contract.Assume(guard == null || cce.Owner.None(guard));
+ while (la.kind == 35 || la.kind == 43) {
+ isFree = false; z = la/*lookahead token*/;
+ if (la.kind == 35) {
+ Get();
+ isFree = true;
+ }
+ Expect(43);
+ while (la.kind == 27) {
+ Attribute(ref kv);
+ }
+ Expression(out e);
+ if (isFree) {
+ invariants.Add(new AssumeCmd(z, e, kv));
+ } else {
+ invariants.Add(new AssertCmd(z, e, kv));
+ }
+ kv = null;
+
+ Expect(8);
+ }
+ Expect(27);
+ StmtList(out body);
+ wcmd = new WhileCmd(x, guard, invariants, body);
+ }
+
+ void BreakCmd(out BreakCmd/*!*/ bcmd) {
+ Contract.Ensures(Contract.ValueAtReturn(out bcmd) != null); IToken/*!*/ x; IToken/*!*/ y;
+ string breakLabel = null;
+
+ Expect(45);
+ x = t;
+ if (la.kind == 1) {
+ Ident(out y);
+ breakLabel = y.val;
+ }
+ Expect(8);
+ bcmd = new BreakCmd(x, breakLabel);
+ }
+
+ void Guard(out Expr e) {
+ Expr/*!*/ ee; e = null;
+ Expect(9);
+ if (la.kind == 44) {
+ Get();
+ e = null;
+ } else if (StartOf(9)) {
+ Expression(out ee);
+ e = ee;
+ } else SynErr(109);
+ Expect(10);
+ }
+
+ void LabelOrAssign(out Cmd c, out IToken label) {
+ IToken/*!*/ id; IToken/*!*/ x, y; Expr/*!*/ e0;
+ c = dummyCmd; label = null;
+ AssignLhs/*!*/ lhs;
+ List<AssignLhs/*!*/>/*!*/ lhss;
+ List<Expr/*!*/>/*!*/ rhss;
+ List<Expr/*!*/>/*!*/ indexes;
+
+ Ident(out id);
+ x = t;
+ if (la.kind == 11) {
+ Get();
+ c = null; label = x;
+ } else if (la.kind == 12 || la.kind == 17 || la.kind == 50) {
+ lhss = new List<AssignLhs/*!*/>();
+ lhs = new SimpleAssignLhs(id, new IdentifierExpr(id, id.val));
+ while (la.kind == 17) {
+ MapAssignIndex(out y, out indexes);
+ lhs = new MapAssignLhs(y, lhs, indexes);
+ }
+ lhss.Add(lhs);
+ while (la.kind == 12) {
+ Get();
+ Ident(out id);
+ lhs = new SimpleAssignLhs(id, new IdentifierExpr(id, id.val));
+ while (la.kind == 17) {
+ MapAssignIndex(out y, out indexes);
+ lhs = new MapAssignLhs(y, lhs, indexes);
+ }
+ lhss.Add(lhs);
+ }
+ Expect(50);
+ x = t; /* use location of := */
+ Expression(out e0);
+ rhss = new List<Expr/*!*/> ();
+ rhss.Add(e0);
+ while (la.kind == 12) {
+ Get();
+ Expression(out e0);
+ rhss.Add(e0);
+ }
+ Expect(8);
+ c = new AssignCmd(x, lhss, rhss);
+ } else SynErr(110);
+ }
+
+ void CallCmd(out Cmd c) {
+ Contract.Ensures(Contract.ValueAtReturn(out c) != null);
+ IToken x;
+ bool isAsync = false;
+ bool isFree = false;
+ QKeyValue kv = null;
+ c = null;
+
+ if (la.kind == 51) {
+ Get();
+ isAsync = true;
+ }
+ if (la.kind == 35) {
+ Get();
+ isFree = true;
+ }
+ Expect(52);
+ x = t;
+ while (la.kind == 27) {
+ Attribute(ref kv);
+ }
+ CallParams(isAsync, isFree, kv, x, out c);
+
+ }
+
+ void ParCallCmd(out Cmd d) {
+ Contract.Ensures(Contract.ValueAtReturn(out d) != null);
+ IToken x;
+ QKeyValue kv = null;
+ Cmd c = null;
+ List<CallCmd> callCmds = new List<CallCmd>();
+
+ Expect(53);
+ x = t;
+ while (la.kind == 27) {
+ Attribute(ref kv);
+ }
+ CallParams(false, false, kv, x, out c);
+ callCmds.Add((CallCmd)c);
+ while (la.kind == 54) {
+ Get();
+ CallParams(false, false, kv, x, out c);
+ callCmds.Add((CallCmd)c);
+ }
+ Expect(8);
+ d = new ParCallCmd(x, callCmds, kv);
+ }
+
+ void MapAssignIndex(out IToken/*!*/ x, out List<Expr/*!*/>/*!*/ indexes) {
+ Contract.Ensures(Contract.ValueAtReturn(out x) != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out indexes))); indexes = new List<Expr/*!*/> ();
+ Expr/*!*/ e;
+
+ Expect(17);
+ x = t;
+ if (StartOf(9)) {
+ Expression(out e);
+ indexes.Add(e);
+ while (la.kind == 12) {
+ Get();
+ Expression(out e);
+ indexes.Add(e);
+ }
+ }
+ Expect(18);
+ }
+
+ void CallParams(bool isAsync, bool isFree, QKeyValue kv, IToken x, out Cmd c) {
+ List<IdentifierExpr> ids = new List<IdentifierExpr>();
+ List<Expr> es = new List<Expr>();
+ Expr en;
+ IToken first;
+ IToken p;
+ c = null;
+
+ Ident(out first);
+ if (la.kind == 9) {
+ Get();
+ if (StartOf(9)) {
+ Expression(out en);
+ es.Add(en);
+ while (la.kind == 12) {
+ Get();
+ Expression(out en);
+ es.Add(en);
+ }
+ }
+ Expect(10);
+ c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync;
+ } else if (la.kind == 12 || la.kind == 50) {
+ ids.Add(new IdentifierExpr(first, first.val));
+ if (la.kind == 12) {
+ Get();
+ Ident(out p);
+ ids.Add(new IdentifierExpr(p, p.val));
+ while (la.kind == 12) {
+ Get();
+ Ident(out p);
+ ids.Add(new IdentifierExpr(p, p.val));
+ }
+ }
+ Expect(50);
+ Ident(out first);
+ Expect(9);
+ if (StartOf(9)) {
+ Expression(out en);
+ es.Add(en);
+ while (la.kind == 12) {
+ Get();
+ Expression(out en);
+ es.Add(en);
+ }
+ }
+ Expect(10);
+ c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync;
+ } else SynErr(111);
+ }
+
+ void Expressions(out List<Expr>/*!*/ es) {
+ Contract.Ensures(Contract.ValueAtReturn(out es) != null); Expr/*!*/ e; es = new List<Expr>();
+ Expression(out e);
+ es.Add(e);
+ while (la.kind == 12) {
+ Get();
+ Expression(out e);
+ es.Add(e);
+ }
+ }
+
+ void ImpliesExpression(bool noExplies, out Expr/*!*/ e0) {
+ Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1;
+ LogicalExpression(out e0);
+ if (StartOf(10)) {
+ if (la.kind == 57 || la.kind == 58) {
+ ImpliesOp();
+ x = t;
+ ImpliesExpression(true, out e1);
+ e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e0, e1);
+ } else {
+ ExpliesOp();
+ if (noExplies)
+ this.SemErr("illegal mixture of ==> and <==, use parentheses to disambiguate");
+ x = t;
+ LogicalExpression(out e1);
+ e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e1, e0);
+ while (la.kind == 59 || la.kind == 60) {
+ ExpliesOp();
+ x = t;
+ LogicalExpression(out e1);
+ e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e1, e0);
+ }
+ }
+ }
+ }
+
+ void EquivOp() {
+ if (la.kind == 55) {
+ Get();
+ } else if (la.kind == 56) {
+ Get();
+ } else SynErr(112);
+ }
+
+ void LogicalExpression(out Expr/*!*/ e0) {
+ Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1;
+ RelationalExpression(out e0);
+ if (StartOf(11)) {
+ if (la.kind == 61 || la.kind == 62) {
+ AndOp();
+ x = t;
+ RelationalExpression(out e1);
+ e0 = Expr.Binary(x, BinaryOperator.Opcode.And, e0, e1);
+ while (la.kind == 61 || la.kind == 62) {
+ AndOp();
+ x = t;
+ RelationalExpression(out e1);
+ e0 = Expr.Binary(x, BinaryOperator.Opcode.And, e0, e1);
+ }
+ } else {
+ OrOp();
+ x = t;
+ RelationalExpression(out e1);
+ e0 = Expr.Binary(x, BinaryOperator.Opcode.Or, e0, e1);
+ while (la.kind == 63 || la.kind == 64) {
+ OrOp();
+ x = t;
+ RelationalExpression(out e1);
+ e0 = Expr.Binary(x, BinaryOperator.Opcode.Or, e0, e1);
+ }
+ }
+ }
+ }
+
+ void ImpliesOp() {
+ if (la.kind == 57) {
+ Get();
+ } else if (la.kind == 58) {
+ Get();
+ } else SynErr(113);
+ }
+
+ void ExpliesOp() {
+ if (la.kind == 59) {
+ Get();
+ } else if (la.kind == 60) {
+ Get();
+ } else SynErr(114);
+ }
+
+ void RelationalExpression(out Expr/*!*/ e0) {
+ Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op;
+ BvTerm(out e0);
+ if (StartOf(12)) {
+ RelOp(out x, out op);
+ BvTerm(out e1);
+ e0 = Expr.Binary(x, op, e0, e1);
+ }
+ }
+
+ void AndOp() {
+ if (la.kind == 61) {
+ Get();
+ } else if (la.kind == 62) {
+ Get();
+ } else SynErr(115);
+ }
+
+ void OrOp() {
+ if (la.kind == 63) {
+ Get();
+ } else if (la.kind == 64) {
+ Get();
+ } else SynErr(116);
+ }
+
+ void BvTerm(out Expr/*!*/ e0) {
+ Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1;
+ Term(out e0);
+ while (la.kind == 73) {
+ Get();
+ x = t;
+ Term(out e1);
+ e0 = new BvConcatExpr(x, e0, e1);
+ }
+ }
+
+ void RelOp(out IToken/*!*/ x, out BinaryOperator.Opcode op) {
+ Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/;
+ switch (la.kind) {
+ case 65: {
+ Get();
+ x = t; op=BinaryOperator.Opcode.Eq;
+ break;
+ }
+ case 19: {
+ Get();
+ x = t; op=BinaryOperator.Opcode.Lt;
+ break;
+ }
+ case 20: {
+ Get();
+ x = t; op=BinaryOperator.Opcode.Gt;
+ break;
+ }
+ case 66: {
+ Get();
+ x = t; op=BinaryOperator.Opcode.Le;
+ break;
+ }
+ case 67: {
+ Get();
+ x = t; op=BinaryOperator.Opcode.Ge;
+ break;
+ }
+ case 68: {
+ Get();
+ x = t; op=BinaryOperator.Opcode.Neq;
+ break;
+ }
+ case 69: {
+ Get();
+ x = t; op=BinaryOperator.Opcode.Subtype;
+ break;
+ }
+ case 70: {
+ Get();
+ x = t; op=BinaryOperator.Opcode.Neq;
+ break;
+ }
+ case 71: {
+ Get();
+ x = t; op=BinaryOperator.Opcode.Le;
+ break;
+ }
+ case 72: {
+ Get();
+ x = t; op=BinaryOperator.Opcode.Ge;
+ break;
+ }
+ default: SynErr(117); break;
+ }
+ }
+
+ void Term(out Expr/*!*/ e0) {
+ Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op;
+ Factor(out e0);
+ while (la.kind == 74 || la.kind == 75) {
+ AddOp(out x, out op);
+ Factor(out e1);
+ e0 = Expr.Binary(x, op, e0, e1);
+ }
+ }
+
+ void Factor(out Expr/*!*/ e0) {
+ Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op;
+ Power(out e0);
+ while (StartOf(13)) {
+ MulOp(out x, out op);
+ Power(out e1);
+ e0 = Expr.Binary(x, op, e0, e1);
+ }
+ }
+
+ void AddOp(out IToken/*!*/ x, out BinaryOperator.Opcode op) {
+ Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/;
+ if (la.kind == 74) {
+ Get();
+ x = t; op=BinaryOperator.Opcode.Add;
+ } else if (la.kind == 75) {
+ Get();
+ x = t; op=BinaryOperator.Opcode.Sub;
+ } else SynErr(118);
+ }
+
+ void Power(out Expr/*!*/ e0) {
+ Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1;
+ UnaryExpression(out e0);
+ if (la.kind == 79) {
+ Get();
+ x = t;
+ Power(out e1);
+ e0 = Expr.Binary(x, BinaryOperator.Opcode.Pow, e0, e1);
+ }
+ }
+
+ void MulOp(out IToken/*!*/ x, out BinaryOperator.Opcode op) {
+ Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/;
+ if (la.kind == 44) {
+ Get();
+ x = t; op=BinaryOperator.Opcode.Mul;
+ } else if (la.kind == 76) {
+ Get();
+ x = t; op=BinaryOperator.Opcode.Div;
+ } else if (la.kind == 77) {
+ Get();
+ x = t; op=BinaryOperator.Opcode.Mod;
+ } else if (la.kind == 78) {
+ Get();
+ x = t; op=BinaryOperator.Opcode.RealDiv;
+ } else SynErr(119);
+ }
+
+ void UnaryExpression(out Expr/*!*/ e) {
+ Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x;
+ e = dummyExpr;
+
+ if (la.kind == 75) {
+ Get();
+ x = t;
+ UnaryExpression(out e);
+ e = Expr.Unary(x, UnaryOperator.Opcode.Neg, e);
+ } else if (la.kind == 80 || la.kind == 81) {
+ NegOp();
+ x = t;
+ UnaryExpression(out e);
+ e = Expr.Unary(x, UnaryOperator.Opcode.Not, e);
+ } else if (StartOf(14)) {
+ CoercionExpression(out e);
+ } else SynErr(120);
+ }
+
+ void NegOp() {
+ if (la.kind == 80) {
+ Get();
+ } else if (la.kind == 81) {
+ Get();
+ } else SynErr(123);
+ }
+
+ void CoercionExpression(out Expr/*!*/ e) {
+ Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x;
+ Bpl.Type/*!*/ coercedTo;
+ BigNum bn;
+
+ ArrayExpression(out e);
+ while (la.kind == 11) {
+ Get();
+ x = t;
+ if (StartOf(6)) {
+ Type(out coercedTo);
+ e = Expr.CoerceType(x, e, coercedTo);
+ } else if (la.kind == 3) {
+ Nat(out bn);
+ 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);
+ }
+
+ } else SynErr(124);
+ }
+ }
+
+ void ArrayExpression(out Expr/*!*/ e) {
+ Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x;
+ Expr/*!*/ index0 = dummyExpr; Expr/*!*/ e1;
+ bool store; bool bvExtract;
+ List<Expr>/*!*/ allArgs = dummyExprSeq;
+
+ AtomExpression(out e);
+ while (la.kind == 17) {
+ Get();
+ x = t; allArgs = new List<Expr> ();
+ allArgs.Add(e);
+ store = false; bvExtract = false;
+ if (StartOf(15)) {
+ if (StartOf(9)) {
+ Expression(out index0);
+ if (index0 is BvBounds)
+ bvExtract = true;
+ else
+ allArgs.Add(index0);
+
+ while (la.kind == 12) {
+ Get();
+ Expression(out e1);
+ if (bvExtract || e1 is BvBounds)
+ this.SemErr("bitvectors only have one dimension");
+ allArgs.Add(e1);
+
+ }
+ if (la.kind == 50) {
+ Get();
+ Expression(out e1);
+ if (bvExtract || e1 is BvBounds)
+ this.SemErr("assignment to bitvectors is not possible");
+ allArgs.Add(e1); store = true;
+
+ }
+ } else {
+ Get();
+ Expression(out e1);
+ allArgs.Add(e1); store = true;
+ }
+ }
+ Expect(18);
+ 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);
+
+ }
+ }
+
+ void Nat(out BigNum n) {
+ Expect(3);
+ try {
+ n = BigNum.FromString(t.val);
+ } catch (FormatException) {
+ this.SemErr("incorrectly formatted number");
+ n = BigNum.ZERO;
+ }
+
+ }
+
+ void AtomExpression(out Expr/*!*/ e) {
+ Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; int n; BigNum bn; BigDec bd; BigFloat fp;
+ List<Expr>/*!*/ es; List<Variable>/*!*/ ds; Trigger trig;
+ List<TypeVariable>/*!*/ typeParams;
+ IdentifierExpr/*!*/ id;
+ QKeyValue kv;
+ e = dummyExpr;
+ List<Variable>/*!*/ locals;
+ List<Block/*!*/>/*!*/ blocks;
+
+ switch (la.kind) {
+ case 82: {
+ Get();
+ e = new LiteralExpr(t, false);
+ break;
+ }
+ case 83: {
+ Get();
+ e = new LiteralExpr(t, true);
+ break;
+ }
+ case 3: {
+ Nat(out bn);
+ e = new LiteralExpr(t, bn);
+ break;
+ }
+ case 5: case 6: {
+ Dec(out bd);
+ e = new LiteralExpr(t, bd);
+ break;
+ }
+ case 97: {
+ Float(out fp);
+ e = new LiteralExpr(t, fp);
+ break;
+ }
+ case 2: {
+ BvLit(out bn, out n);
+ e = new LiteralExpr(t, bn, n);
+ break;
+ }
+ case 1: {
+ Ident(out x);
+ id = new IdentifierExpr(x, x.val); e = id;
+ if (la.kind == 9) {
+ Get();
+ if (StartOf(9)) {
+ Expressions(out es);
+ e = new NAryExpr(x, new FunctionCall(id), es);
+ } else if (la.kind == 10) {
+ e = new NAryExpr(x, new FunctionCall(id), new List<Expr>());
+ } else SynErr(125);
+ Expect(10);
+ }
+ break;
+ }
+ case 84: {
+ Get();
+ x = t;
+ Expect(9);
+ Expression(out e);
+ Expect(10);
+ e = new OldExpr(x, e);
+ break;
+ }
+ case 14: {
+ Get();
+ x = t;
+ Expect(9);
+ Expression(out e);
+ Expect(10);
+ e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToInt), new List<Expr>{ e });
+ break;
+ }
+ case 15: {
+ Get();
+ x = t;
+ Expect(9);
+ Expression(out e);
+ Expect(10);
+ e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToReal), new List<Expr>{ e });
+ 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<Expr> { e });
+ break;
+ }
+ case 9: {
+ Get();
+ if (StartOf(9)) {
+ Expression(out e);
+ if (e is BvBounds)
+ this.SemErr("parentheses around bitvector bounds " +
+ "are not allowed");
+ } else if (la.kind == 88 || la.kind == 89) {
+ Forall();
+ x = t;
+ QuantifierBody(x, out typeParams, out ds, out kv, out trig, out e);
+ if (typeParams.Count + ds.Count > 0)
+ e = new ForallExpr(x, typeParams, ds, kv, trig, e);
+ } else if (la.kind == 90 || la.kind == 91) {
+ Exists();
+ x = t;
+ QuantifierBody(x, out typeParams, out ds, out kv, out trig, out e);
+ if (typeParams.Count + ds.Count > 0)
+ e = new ExistsExpr(x, typeParams, ds, kv, trig, e);
+ } else if (la.kind == 92 || la.kind == 93) {
+ Lambda();
+ x = t;
+ QuantifierBody(x, out typeParams, out ds, out kv, out trig, out e);
+ if (trig != null)
+ SemErr("triggers not allowed in lambda expressions");
+ if (typeParams.Count + ds.Count > 0)
+ e = new LambdaExpr(x, typeParams, ds, kv, e);
+ } else SynErr(126);
+ Expect(10);
+ break;
+ }
+ case 40: {
+ IfThenElseExpression(out e);
+ break;
+ }
+ case 85: {
+ CodeExpression(out locals, out blocks);
+ e = new CodeExpr(locals, blocks);
+ break;
+ }
+ default: SynErr(127); break;
+ }
+ }
+
+ void Dec(out BigDec n) {
+ string s = "";
+ if (la.kind == 5) {
+ Get();
+ s = t.val;
+ } else if (la.kind == 6) {
+ Get();
+ s = t.val;
+ } else SynErr(128);
+ try {
+ n = BigDec.FromString(s);
+ } catch (FormatException) {
+ this.SemErr("incorrectly formatted number");
+ n = BigDec.ZERO;
+ }
+
+ }
+
+ /// <summary>
+ /// Creates a floating point from the current token value
+ /// </summary>
+ /// <param name="n"></param>
+ void Float(out BigFloat n)
+ {
+ try
+ {
+ if (la.kind == 97) {
+ bool negative = false;
+ int exp, sig, size;
+ BigNum exp_val, sig_val, value;
+ //Expected format = float(sign exp_val sig_val) || float<exp sig>(value)
+ Get(); //Skip the float token
+ if (la.val == "(") {
+ Get();
+ 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);
+ BvLit(out sig_val, out sig);
+ n = new BigFloat(negative, exp_val, sig_val, exp, sig);
+ Expect(10); //)
+ }
+ else if (la.val == "<") {
+ Get();
+ Expect(3);
+ exp = Int32.Parse(t.val);
+ Expect(12);
+ Expect(3);
+ sig = Int32.Parse(t.val);
+ Expect(20); //>
+ Expect(9); //(
+ 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);
+ }
+ Expect(10); //)
+ }
+ else {
+ throw new FormatException();
+ }
+ }
+ else {
+ n = BigFloat.ZERO(8, 24);
+ SynErr(137);
+ }
+ }
+ catch (FormatException)
+ {
+ this.SemErr("incorrectly formatted floating point");
+ n = BigFloat.ZERO(8, 24);
+ }
+ }
+
+ void BvLit(out BigNum n, out int m) {
+ Expect(2);
+ 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;
+ }
+
+ }
+
+ void Forall() {
+ if (la.kind == 88) {
+ Get();
+ } else if (la.kind == 89) {
+ Get();
+ } else SynErr(129);
+ }
+
+ void QuantifierBody(IToken/*!*/ q, out List<TypeVariable>/*!*/ typeParams, out List<Variable>/*!*/ 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<TypeVariable> ();
+ IToken/*!*/ tok;
+ kv = null;
+ ds = new List<Variable> ();
+
+ if (la.kind == 19) {
+ TypeParams(out tok, out typeParams);
+ if (la.kind == 1 || la.kind == 27) {
+ BoundVars(q, out ds);
+ }
+ } else if (la.kind == 1 || la.kind == 27) {
+ BoundVars(q, out ds);
+ } else SynErr(130);
+ QSep();
+ while (la.kind == 27) {
+ AttributeOrTrigger(ref kv, ref trig);
+ }
+ Expression(out body);
+ }
+
+ void Exists() {
+ if (la.kind == 90) {
+ Get();
+ } else if (la.kind == 91) {
+ Get();
+ } else SynErr(131);
+ }
+
+ void Lambda() {
+ if (la.kind == 92) {
+ Get();
+ } else if (la.kind == 93) {
+ Get();
+ } else SynErr(132);
+ }
+
+ void IfThenElseExpression(out Expr/*!*/ e) {
+ Contract.Ensures(Contract.ValueAtReturn(out e) != null);
+ IToken/*!*/ tok;
+ Expr/*!*/ e0, e1, e2;
+ e = dummyExpr;
+ Expect(40);
+ tok = t;
+ Expression(out e0);
+ Expect(87);
+ Expression(out e1);
+ Expect(41);
+ Expression(out e2);
+ e = new NAryExpr(tok, new IfThenElse(tok), new List<Expr>{ e0, e1, e2 });
+ }
+
+ void CodeExpression(out List<Variable>/*!*/ locals, out List<Block/*!*/>/*!*/ blocks) {
+ Contract.Ensures(Contract.ValueAtReturn(out locals) != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out blocks))); locals = new List<Variable>(); Block/*!*/ b;
+ blocks = new List<Block/*!*/>();
+
+ Expect(85);
+ while (la.kind == 7) {
+ LocalVars(locals);
+ }
+ SpecBlock(out b);
+ blocks.Add(b);
+ while (la.kind == 1) {
+ SpecBlock(out b);
+ blocks.Add(b);
+ }
+ Expect(86);
+ }
+
+ void SpecBlock(out Block/*!*/ b) {
+ Contract.Ensures(Contract.ValueAtReturn(out b) != null); IToken/*!*/ x; IToken/*!*/ y;
+ Cmd c; IToken label;
+ List<Cmd> cs = new List<Cmd>();
+ List<IToken>/*!*/ xs;
+ List<String> ss = new List<String>();
+ b = dummyBlock;
+ Expr/*!*/ e;
+
+ Ident(out x);
+ Expect(11);
+ while (StartOf(8)) {
+ LabelOrCmd(out c, out label);
+ if (c != null) {
+ Contract.Assert(label == null);
+ cs.Add(c);
+ } else {
+ Contract.Assert(label != null);
+ SemErr("SpecBlock's can only have one label");
+ }
+
+ }
+ if (la.kind == 38) {
+ Get();
+ y = t;
+ Idents(out xs);
+ foreach(IToken/*!*/ s in xs){
+ Contract.Assert(s != null);
+ ss.Add(s.val); }
+ b = new Block(x,x.val,cs,new GotoCmd(y,ss));
+
+ } else if (la.kind == 39) {
+ Get();
+ Expression(out e);
+ b = new Block(x,x.val,cs,new ReturnExprCmd(t,e));
+ } else SynErr(133);
+ Expect(8);
+ }
+
+ void AttributeOrTrigger(ref QKeyValue kv, ref Trigger trig) {
+ IToken/*!*/ tok; Expr/*!*/ e; List<Expr>/*!*/ es;
+ string key;
+ List<object/*!*/> parameters; object/*!*/ param;
+
+ Expect(27);
+ tok = t;
+ if (la.kind == 11) {
+ Get();
+ Expect(1);
+ key = t.val; parameters = new List<object/*!*/>();
+ if (StartOf(16)) {
+ AttributeParameter(out param);
+ parameters.Add(param);
+ while (la.kind == 12) {
+ Get();
+ AttributeParameter(out param);
+ 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<Expr> { e }, null);
+ } else {
+ trig.AddLast(new Trigger(tok, false, new List<Expr> { 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));
+ }
+ }
+
+ } else if (StartOf(9)) {
+ Expression(out e);
+ es = new List<Expr> { e };
+ while (la.kind == 12) {
+ Get();
+ Expression(out e);
+ es.Add(e);
+ }
+ if (trig==null) {
+ trig = new Trigger(tok, true, es, null);
+ } else {
+ trig.AddLast(new Trigger(tok, true, es, null));
+ }
+
+ } else SynErr(134);
+ Expect(28);
+ }
+
+ void AttributeParameter(out object/*!*/ o) {
+ Contract.Ensures(Contract.ValueAtReturn(out o) != null);
+ o = "error";
+ Expr/*!*/ e;
+
+ if (la.kind == 4) {
+ Get();
+ o = t.val.Substring(1, t.val.Length-2);
+ } else if (StartOf(9)) {
+ Expression(out e);
+ o = e;
+ } else SynErr(135);
+ }
+
+ void QSep() {
+ if (la.kind == 94) {
+ Get();
+ } else if (la.kind == 95) {
+ Get();
+ } else SynErr(136);
+ }
+
+
+
+ public void Parse() {
+ la = new Token();
+ la.val = "";
+ Get();
+ BoogiePL();
+ Expect(0);
+
+ Expect(0);
+ }
+
+ 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,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},
+ {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,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},
+ {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, 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,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}
+
+ };
+} // end Parser
+
+
+public class Errors {
+ public int count = 0; // number of errors detected
+ public System.IO.TextWriter/*!*/ errorStream = Console.Out; // error messages go to this stream
+ public string errMsgFormat = "{0}({1},{2}): error: {3}"; // 0=filename, 1=line, 2=column, 3=text
+ public string warningMsgFormat = "{0}({1},{2}): warning: {3}"; // 0=filename, 1=line, 2=column, 3=text
+
+ public void SynErr(string filename, int line, int col, int n) {
+ SynErr(filename, line, col, GetSyntaxErrorString(n));
+ }
+
+ public virtual void SynErr(string filename, int line, int col, string/*!*/ msg) {
+ Contract.Requires(msg != null);
+ errorStream.WriteLine(errMsgFormat, filename, line, col, msg);
+ count++;
+ }
+
+ /// <summary>
+ /// Returns a string corresponding to the syntax error of the given type
+ /// Note that many of these errors (0-98) correspond to token types (e.g. the la token)
+ /// </summary>
+ /// <param name="n"></param>
+ /// <returns></returns>
+ string GetSyntaxErrorString(int n) {
+ string s;
+ switch (n) {
+ case 0: s = "EOF expected"; break;
+ case 1: s = "ident expected"; break;
+ case 2: s = "bvlit expected"; break;
+ case 3: s = "digits expected"; break;
+ case 4: s = "string expected"; break;
+ case 5: s = "decimal expected"; break;
+ case 6: s = "float expected"; break;
+ case 7: s = "\"var\" expected"; break;
+ case 8: s = "\";\" expected"; break;
+ case 9: s = "\"(\" expected"; break;
+ case 10: s = "\")\" expected"; break;
+ case 11: s = "\":\" expected"; break;
+ case 12: s = "\",\" expected"; break;
+ case 13: s = "\"where\" expected"; break;
+ case 14: s = "\"int\" expected"; break;
+ case 15: s = "\"real\" expected"; break;
+ case 16: s = "\"bool\" expected"; break;
+ case 17: s = "\"[\" expected"; break;
+ case 18: s = "\"]\" expected"; break;
+ case 19: s = "\"<\" expected"; break;
+ case 20: s = "\">\" expected"; break;
+ case 21: s = "\"const\" expected"; break;
+ case 22: s = "\"unique\" expected"; break;
+ case 23: s = "\"extends\" expected"; break;
+ case 24: s = "\"complete\" expected"; break;
+ case 25: s = "\"function\" expected"; break;
+ case 26: s = "\"returns\" expected"; break;
+ case 27: s = "\"{\" expected"; break;
+ case 28: s = "\"}\" expected"; break;
+ case 29: s = "\"axiom\" expected"; break;
+ case 30: s = "\"type\" expected"; break;
+ case 31: s = "\"=\" expected"; break;
+ case 32: s = "\"procedure\" expected"; break;
+ case 33: s = "\"implementation\" expected"; break;
+ case 34: s = "\"modifies\" expected"; break;
+ case 35: s = "\"free\" expected"; break;
+ case 36: s = "\"requires\" expected"; break;
+ case 37: s = "\"ensures\" expected"; break;
+ case 38: s = "\"goto\" expected"; break;
+ case 39: s = "\"return\" expected"; break;
+ case 40: s = "\"if\" expected"; break;
+ case 41: s = "\"else\" expected"; break;
+ case 42: s = "\"while\" expected"; break;
+ case 43: s = "\"invariant\" expected"; break;
+ case 44: s = "\"*\" expected"; break;
+ case 45: s = "\"break\" expected"; break;
+ case 46: s = "\"assert\" expected"; break;
+ case 47: s = "\"assume\" expected"; break;
+ case 48: s = "\"havoc\" expected"; break;
+ case 49: s = "\"yield\" expected"; break;
+ case 50: s = "\":=\" expected"; break;
+ case 51: s = "\"async\" expected"; break;
+ case 52: s = "\"call\" expected"; break;
+ case 53: s = "\"par\" expected"; break;
+ case 54: s = "\"|\" expected"; break;
+ case 55: s = "\"<==>\" expected"; break;
+ case 56: s = "\"\\u21d4\" expected"; break;
+ case 57: s = "\"==>\" expected"; break;
+ case 58: s = "\"\\u21d2\" expected"; break;
+ case 59: s = "\"<==\" expected"; break;
+ case 60: s = "\"\\u21d0\" expected"; break;
+ case 61: s = "\"&&\" expected"; break;
+ case 62: s = "\"\\u2227\" expected"; break;
+ case 63: s = "\"||\" expected"; break;
+ case 64: s = "\"\\u2228\" expected"; break;
+ case 65: s = "\"==\" expected"; break;
+ case 66: s = "\"<=\" expected"; break;
+ case 67: s = "\">=\" expected"; break;
+ case 68: s = "\"!=\" expected"; break;
+ case 69: s = "\"<:\" expected"; break;
+ case 70: s = "\"\\u2260\" expected"; break;
+ case 71: s = "\"\\u2264\" expected"; break;
+ case 72: s = "\"\\u2265\" expected"; break;
+ case 73: s = "\"++\" expected"; break;
+ case 74: s = "\"+\" expected"; break;
+ case 75: s = "\"-\" expected"; break;
+ case 76: s = "\"div\" expected"; break;
+ case 77: s = "\"mod\" expected"; break;
+ case 78: s = "\"/\" expected"; break;
+ case 79: s = "\"**\" expected"; break;
+ case 80: s = "\"!\" expected"; break;
+ case 81: s = "\"\\u00ac\" expected"; break;
+ case 82: s = "\"false\" expected"; break;
+ case 83: s = "\"true\" expected"; break;
+ case 84: s = "\"old\" expected"; break;
+ case 85: s = "\"|{\" expected"; break;
+ case 86: s = "\"}|\" expected"; break;
+ case 87: s = "\"then\" expected"; break;
+ case 88: s = "\"forall\" expected"; break;
+ case 89: s = "\"\\u2200\" expected"; break;
+ case 90: s = "\"exists\" expected"; break;
+ case 91: s = "\"\\u2203\" expected"; break;
+ case 92: s = "\"lambda\" expected"; break;
+ case 93: s = "\"\\u03bb\" expected"; break;
+ case 94: s = "\"::\" expected"; break;
+ case 95: s = "\"\\u2022\" expected"; break;
+ case 96: s = "??? expected"; 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 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;
+ case 137: s = "invalid Float"; break;
+
+ default: s = "error " + n; break;
+ }
+ return s;
+ }
+
+ public void SemErr(IToken/*!*/ tok, string/*!*/ msg) { // semantic errors
+ Contract.Requires(tok != null);
+ Contract.Requires(msg != null);
+ SemErr(tok.filename, tok.line, tok.col, msg);
+ }
+
+ public virtual void SemErr(string filename, int line, int col, string/*!*/ msg) {
+ Contract.Requires(msg != null);
+ errorStream.WriteLine(errMsgFormat, filename, line, col, msg);
+ count++;
+ }
+
+ public void Warning(IToken/*!*/ tok, string/*!*/ msg) { // warnings
+ Contract.Requires(tok != null);
+ Contract.Requires(msg != null);
+ Warning(tok.filename, tok.line, tok.col, msg);
+ }
+
+ public virtual void Warning(string filename, int line, int col, string msg) {
+ Contract.Requires(msg != null);
+ errorStream.WriteLine(warningMsgFormat, filename, line, col, msg);
+ }
+} // Errors
+
+
+public class FatalError: Exception {
+ public FatalError(string m): base(m) {}
+}
+
+
} \ No newline at end of file
diff --git a/Source/Core/Readme.txt b/Source/Core/Readme.txt
index 1b0606a6..dfdd8050 100644
--- a/Source/Core/Readme.txt
+++ b/Source/Core/Readme.txt
@@ -1,61 +1,61 @@
-// ----------------------------------------------------------------------------
-// Boogie-PL
-//
-// Readme
-// ws 5/9/03
-// ----------------------------------------------------------------------------
-
-
-This directory cointains the Boogie Procedural Language (BoogiePL)
-implementataion and "1" sample program.
-
-
-Scanner and parser are generated with Coco (ann LL1 parser generator for EBNFs)
-(see http://www.ssw.uni-linz.ac.at/Research/Projects/Coco/CSharp/)
-
- The input file is
- BoogiePL.atg
- then simply call
- ..\Coco\bin\Debug\Coco.exe BoogiePL.atg
- it then uses (as input)
- Scanner.frame
- Parser.frame
- as templates to generate an LL1 parser into
- Scanner.cs
- Parser.cs
- as output
-
-The Csharp excutable then contains
-
- BoogiePL.cs -- main program
- Absy -- abstract syntax for BoogiePL
- Error.cs -- error handling (contains still some oldstuff)
- Parser.cs -- generated parser
- Scanner.cs -- generated scanner
- PureCollections.cs -- sets/maps/tuples/ (contains still some oldstuff)
-
-The directory Samples contains one parsing example
- Parsing1.pl
-Please check it for the syntax, alternatively consult BoogiePL.atg
-
-Here is its output:
- C:\Boogie> bin\debug\Boogiepl.exe samples\Parsing1.pl
-
- Boogie Procedural Language Version 0.1 Copyright (c) Microsoft 2003
- Parsing samples\Parsing1.pl <<<=== here is what is does
- 0 errors detected
-
-Things left to do:
-
- BoogiePL needs a tiny context analysis
- checking names, updates, arities, OLD, etc.
- (ws will do until 5/8)
-
- BoogiePL Absy might be too flexible
- simplify (if one things so..) (Mike/Rustan will do)
-
- BoogiePL needs more examples/experiences
- (all of us..)
-
-
-
+// ----------------------------------------------------------------------------
+// Boogie-PL
+//
+// Readme
+// ws 5/9/03
+// ----------------------------------------------------------------------------
+
+
+This directory cointains the Boogie Procedural Language (BoogiePL)
+implementataion and "1" sample program.
+
+
+Scanner and parser are generated with Coco (ann LL1 parser generator for EBNFs)
+(see http://www.ssw.uni-linz.ac.at/Research/Projects/Coco/CSharp/)
+
+ The input file is
+ BoogiePL.atg
+ then simply call
+ ..\Coco\bin\Debug\Coco.exe BoogiePL.atg
+ it then uses (as input)
+ Scanner.frame
+ Parser.frame
+ as templates to generate an LL1 parser into
+ Scanner.cs
+ Parser.cs
+ as output
+
+The Csharp excutable then contains
+
+ BoogiePL.cs -- main program
+ Absy -- abstract syntax for BoogiePL
+ Error.cs -- error handling (contains still some oldstuff)
+ Parser.cs -- generated parser
+ Scanner.cs -- generated scanner
+ PureCollections.cs -- sets/maps/tuples/ (contains still some oldstuff)
+
+The directory Samples contains one parsing example
+ Parsing1.pl
+Please check it for the syntax, alternatively consult BoogiePL.atg
+
+Here is its output:
+ C:\Boogie> bin\debug\Boogiepl.exe samples\Parsing1.pl
+
+ Boogie Procedural Language Version 0.1 Copyright (c) Microsoft 2003
+ Parsing samples\Parsing1.pl <<<=== here is what is does
+ 0 errors detected
+
+Things left to do:
+
+ BoogiePL needs a tiny context analysis
+ checking names, updates, arities, OLD, etc.
+ (ws will do until 5/8)
+
+ BoogiePL Absy might be too flexible
+ simplify (if one things so..) (Mike/Rustan will do)
+
+ BoogiePL needs more examples/experiences
+ (all of us..)
+
+
+
diff --git a/Source/Core/ResolutionContext.cs b/Source/Core/ResolutionContext.cs
index bf1a5629..279e00bf 100644
--- a/Source/Core/ResolutionContext.cs
+++ b/Source/Core/ResolutionContext.cs
@@ -1,629 +1,641 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-namespace Microsoft.Boogie {
- using System.Collections;
- using System.Collections.Generic;
- using System;
- using System.Linq;
- using System.Diagnostics.Contracts;
-
- [ContractClass(typeof(IErrorSinkContracts))]
- public interface IErrorSink {
- void Error(IToken/*!*/ tok, string/*!*/ msg);
- }
- [ContractClassFor(typeof(IErrorSink))]
- public abstract class IErrorSinkContracts : IErrorSink {
- #region IErrorSink Members
- public void Error(IToken tok, string msg) {
- Contract.Requires(tok != null);
- Contract.Requires(msg != null);
- throw new NotImplementedException();
- }
- #endregion
- }
-
- public class CheckingContext {
- // ------------------------------ Error counting ------------------------------
-
- IErrorSink errorSink;
- int errors;
-
- public CheckingContext(IErrorSink errorSink) {
- this.errorSink = errorSink;
- }
-
- public int ErrorCount {
- get {
- return errors;
- }
- set {
- errors = value;
- }
- }
-
- public void Error(Absy subject, string msg, params object[] args) {
- Contract.Requires(args != null);
- Contract.Requires(msg != null);
- Contract.Requires(subject != null);
- Error(subject.tok, msg, args);
- }
-
- public virtual void Error(IToken tok, string msg) {
- Contract.Requires(msg != null);
- Contract.Requires(tok != null);
- errors++;
- if (errorSink == null) {
- ConsoleColor col = Console.ForegroundColor;
- Console.ForegroundColor = ConsoleColor.Red;
- Console.WriteLine("{0}({1},{2}): Error: {3}",
- tok.filename, tok.line, tok.col - 1,
- msg);
- Console.ForegroundColor = col;
- } else {
- errorSink.Error(tok, msg);
- }
- }
-
- private string Format(string msg, params object[] args) {
- Contract.Requires(msg != null);
- Contract.Ensures(Contract.Result<string>() != null);
- if (System.Type.GetType("Mono.Runtime") != null) { // MONO
- // something in mono seems to be broken so that calling
- // NamedDeclarations.ToString (and similar ToString methods)
- // causes a stack overflow. We therefore convert those to
- // strings by hand
- object[] fixedArgs = new object[cce.NonNull(args).Length];
- for (int i = 0; i < args.Length; ++i) {
- if (args[i] is NamedDeclaration) {
- fixedArgs[i] = cce.NonNull((NamedDeclaration)args[i]).Name;
- } else if (args[i] is Type) {
- System.IO.StringWriter buffer = new System.IO.StringWriter();
- using (TokenTextWriter stream = new TokenTextWriter("<buffer>", buffer, /*setTokens=*/ false, /*pretty=*/ false)) {
- cce.NonNull((Type)args[i]).Emit(stream);
- }
- fixedArgs[i] = buffer.ToString();
- } else if (args[i] is Expr) {
- System.IO.StringWriter buffer = new System.IO.StringWriter();
- using (TokenTextWriter stream = new TokenTextWriter("<buffer>", buffer, /*setTokens=*/ false, /*pretty=*/ false)) {
- cce.NonNull((Expr/*!*/)args[i]).Emit(stream, 0, false);
- }
- fixedArgs[i] = buffer.ToString();
- } else {
- fixedArgs[i] = args[i];
- }
- }
- args = fixedArgs;
- }
- return string.Format(msg, args);
- }
-
- public void Error(IToken tok, string msg, params object[] args) {
- Contract.Requires(msg != null);
- Contract.Requires(tok != null);
- Error(tok, Format(msg, args));
- }
-
- public void Warning(Absy subject, string msg, params object[] args) {
- Contract.Requires(args != null);
- Contract.Requires(msg != null);
- Contract.Requires(subject != null);
- Warning(subject.tok, msg, args);
- }
-
- public virtual void Warning(IToken tok, string msg) {
- Contract.Requires(msg != null);
- Contract.Requires(tok != null);
- // warnings are currently always written to the console
- ConsoleColor col = Console.ForegroundColor;
- Console.ForegroundColor = ConsoleColor.DarkYellow;
- Console.WriteLine("{0}({1},{2}): Warning: {3}",
- tok.filename, tok.line, tok.col - 1,
- msg);
- Console.ForegroundColor = col;
- }
-
- public void Warning(IToken tok, string msg, params object[] args) {
- Contract.Requires(msg != null);
- Contract.Requires(tok != null);
- Warning(tok, Format(msg, args));
- }
- }
-
- public class ResolutionContext : CheckingContext {
- public ResolutionContext(IErrorSink errorSink)
- : base(errorSink) {
- }
-
- // ------------------------------ Boogie 2 Types -------------------------
-
- // user-defined types, which can be either TypeCtorDecl or TypeSynonymDecl
- Hashtable /*string->NamedDeclaration*//*!*/ types = new Hashtable /*string->NamedDeclaration*/ ();
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(types != null);
- Contract.Invariant(cce.NonNullElements(typeBinders));
- Contract.Invariant(varContext != null);
- Contract.Invariant(funcdures != null);
- }
-
-
- /// <summary>
- /// Checks if name coincides with the name of a bitvector type. If so, reports an error and
- /// returns true; otherwise, returns false.
- /// </summary>
- private bool CheckBvNameClashes(Absy absy, string name) {
- Contract.Requires(name != null);
- Contract.Requires(absy != null);
- if (name.StartsWith("bv") && name.Length > 2) {
- for (int i = 2; i < name.Length; ++i)
- if (!char.IsDigit(name[i]))
- return false;
- Error(absy, "type name: {0} is registered for bitvectors", name);
- return true;
- }
- return false;
- }
-
- public void AddType(NamedDeclaration td) {
- Contract.Requires(td != null);
- Contract.Requires((td is TypeCtorDecl) || (td is TypeSynonymDecl));
- Contract.Requires(td.Name != null);
-
- string name = td.Name;
- if (CheckBvNameClashes(td, name))
- return; // error has already been reported
-
- var previous = (NamedDeclaration)types[name];
- if (previous == null) {
- types.Add(name, td);
- } else {
- var r = (NamedDeclaration)SelectNonExtern(td, previous);
- if (r == null) {
- Error(td, "more than one declaration of type name: {0}", name);
- } else {
- types[name] = r;
- }
- }
- }
-
- /// <summary>
- /// Returns the declaration of the named type, or null if
- /// no such type is declared. Also return null if the type
- /// declared with the given name is not a constructor but a
- /// type synonym
- /// </summary>
- /// <param name="name"></param>
- /// <returns></returns>
- public TypeCtorDecl LookUpType(string name) {
- Contract.Requires(name != null);
- return types[name] as TypeCtorDecl;
- }
-
- public TypeSynonymDecl LookUpTypeSynonym(string name) {
- Contract.Requires(name != null);
- return types[name] as TypeSynonymDecl;
- }
-
- // ------------------------------ Boogie 2 Type Binders ------------------------------
-
- List<TypeVariable/*!*/>/*!*/ typeBinders = new List<TypeVariable/*!*/>(5);
-
- public void AddTypeBinder(TypeVariable td) {
- Contract.Requires(td != null);
- if (CheckBvNameClashes(td, td.Name)) {
- return;
- }
- if (types.ContainsKey(td.Name)) {
- Error(td, "name is already reserved for type constructor: {0}", td.Name);
- return;
- }
- for (int i = 0; i < typeBinders.Count; i++) {
- if (typeBinders[i].Name == td.Name) {
- Error(td, "more than one declaration of type variable: {0}", td.Name);
- return;
- }
- }
- typeBinders.Add(td);
- }
-
- public int TypeBinderState {
- get {
- return typeBinders.Count;
- }
- set {
- typeBinders.RemoveRange(value, typeBinders.Count - value);
- }
- }
-
- /// <summary>
- /// Returns the declaration of the named type binder, or null if
- /// no such binder is declared.
- /// </summary>
- public TypeVariable LookUpTypeBinder(string name) {
- Contract.Requires(name != null);
- for (int i = typeBinders.Count; 0 <= --i; ) {
- TypeVariable/*!*/ td = typeBinders[i];
- Contract.Assert(td != null);
- if (td.Name == name) {
- return td;
- }
- }
- return null; // not present
- }
-
- // ------------------------------ Variables ------------------------------
-
- class VarContextNode {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(VarSymbols != null);
- }
-
- public readonly Hashtable /*string->Variable*//*!*/ VarSymbols = new Hashtable /*string->Variable*/();
- public /*maybe null*/ VarContextNode ParentContext;
- public readonly bool Opaque;
- readonly ISet<string> assignedAssumptionVariables = new HashSet<string>();
-
- public bool HasVariableBeenAssigned(string name)
- {
- Contract.Requires(name != null);
-
- if (assignedAssumptionVariables.Contains(name))
- {
- return true;
- }
- else if (ParentContext != null)
- {
- return ParentContext.HasVariableBeenAssigned(name);
- }
- else
- {
- return false;
- }
- }
-
- public bool MarkVariableAsAssigned(string name)
- {
- Contract.Requires(name != null);
-
- if (VarSymbols.Contains(name))
- {
- if (assignedAssumptionVariables.Contains(name))
- {
- return false;
- }
- assignedAssumptionVariables.Add(name);
- return true;
- }
- else if (ParentContext != null)
- {
- return ParentContext.MarkVariableAsAssigned(name);
- }
- else
- {
- return false;
- }
- }
-
- public VarContextNode(/*maybe null*/ VarContextNode parentContext, bool opaque) {
- ParentContext = parentContext;
- Opaque = opaque;
- }
- }
-
- // symbolic constants, global variables, local variables, formals, expression-bound variables
- VarContextNode/*!*/ varContext = new VarContextNode(null, false);
-
- /// <summary>
- /// Adds a variable context.
- /// </summary>
- public void PushVarContext() {
- varContext = new VarContextNode(varContext, false);
- }
-
- /// <summary>
- /// Adds an opaque variable context, that is, one that blocks all previously pushed contexts.
- /// </summary>
- public void PushOpaqueVarContext() {
- varContext = new VarContextNode(varContext, true);
- }
-
- /// <summary>
- /// Requires there to be more than one variable context.
- /// </summary>
- public void PopVarContext() {
- Contract.Assert(varContext.ParentContext != null);
- varContext = varContext.ParentContext;
- }
-
- public void AddVariable(Variable var, bool global) {
- Contract.Requires(var != null);
- var previous = FindVariable(cce.NonNull(var.Name), !global);
- if (previous == null) {
- varContext.VarSymbols.Add(var.Name, var);
- } else {
- var r = (Variable)SelectNonExtern(var, previous);
- if (r == null) {
- Error(var, "more than one declaration of variable name: {0}", var.Name);
- } else {
- varContext.VarSymbols[var.Name] = r;
- }
- }
- }
-
- /// <summary>
- /// Returns the declaration of the named variable, or null if
- /// no such variable is declared.
- /// </summary>
- /// <param name="name"></param>
- /// <returns></returns>
- public Variable LookUpVariable(string name) {
- Contract.Requires(name != null);
- return FindVariable(name, false);
- }
-
- Variable FindVariable(string name, bool ignoreTopLevelVars) {
- Contract.Requires(name != null);
- VarContextNode c = varContext;
- bool lookOnlyForConstants = false;
- do {
- if (ignoreTopLevelVars && c.ParentContext == null) {
- // this is the top level and we're asked to ignore the top level; hence, we're done
- break;
- }
-
- Variable var = (Variable)c.VarSymbols[name];
- if (var != null && (!lookOnlyForConstants || var is Constant)) {
- return var;
- }
- // not at this level
-
- if (c.Opaque) {
- // from here on, only constants can be looked up
- lookOnlyForConstants = true;
- }
- c = c.ParentContext;
- } while (c != null);
-
- // not present in the relevant levels
- return null;
- }
-
- public bool HasVariableBeenAssigned(string name)
- {
- Contract.Requires(name != null);
-
- return varContext.HasVariableBeenAssigned(name);
- }
-
- public void MarkVariableAsAssigned(string name)
- {
- Contract.Requires(name != null);
-
- var success = varContext.MarkVariableAsAssigned(name);
- Contract.Assume(success);
- }
-
- Hashtable axioms = new Hashtable();
-
- public void AddAxiom(Axiom axiom) {
- string axiomName = QKeyValue.FindStringAttribute(axiom.Attributes, "name");
- if (axiomName == null)
- return;
- var previous = (Axiom)axioms[axiomName];
- if (previous == null) {
- axioms.Add(axiomName, axiom);
- }
- else {
- var r = (Axiom)SelectNonExtern(axiom, previous);
- if (r == null) {
- Error(axiom, "more than one declaration of axiom name: {0}", axiomName);
- }
- else {
- axioms[axiomName] = r;
- }
- }
- }
-
- // ------------------------------ Functions/Procedures ------------------------------
-
- // uninterpreted function symbols, procedures
- Hashtable /*string->DeclWithFormals*//*!*/ funcdures = new Hashtable /*string->DeclWithFormals*/ ();
-
- public void AddProcedure(DeclWithFormals proc) {
- Contract.Requires(proc != null);
- Contract.Requires(proc.Name != null);
-
- string name = proc.Name;
- var previous = (DeclWithFormals)funcdures[name];
- if (previous == null) {
- funcdures.Add(name, proc);
- } else {
- var r = (DeclWithFormals)SelectNonExtern(proc, previous);
- if (r == null) {
- Error(proc, "more than one declaration of function/procedure name: {0}", name);
- } else {
- funcdures[name] = r;
- }
- }
- }
-
- /// <summary>
- /// If both "a" and "b" have an ":extern" attribute, returns either one.
- /// If one of "a" and "b" has an ":extern" attribute, returns that one.
- /// If neither of "a" and "b" has an ":extern" attribute, returns null.
- /// If a non-value value is returned, this method also adds the ":ignore"
- /// attribute to the declaration NOT returned.
- /// </summary>
- Declaration SelectNonExtern(Declaration a, Declaration b) {
- Contract.Requires(a != null);
- Contract.Requires(b != null);
- Contract.Ensures(Contract.Result<Declaration>() == null || Contract.Result<Declaration>() == a || Contract.Result<Declaration>() == b);
-
- Declaration ignore, keep;
- if (QKeyValue.FindBoolAttribute(a.Attributes, "extern")) {
- ignore = a;
- keep = b;
- } else if (QKeyValue.FindBoolAttribute(b.Attributes, "extern")) {
- ignore = b;
- keep = a;
- } else {
- return null;
- }
- // prepend :ignore attribute
- ignore.Attributes = new QKeyValue(ignore.tok, "ignore", new List<object/*!*/>(), ignore.Attributes);
- return keep;
- }
-
- /// <summary>
- /// Returns the declaration of the named function/procedure, or null if
- /// no such function or procedure is declared.
- /// </summary>
- /// <param name="name"></param>
- /// <returns></returns>
- public DeclWithFormals LookUpProcedure(string name) {
- Contract.Requires(name != null);
- return (DeclWithFormals)funcdures[name];
- }
-
- // ------------------------------ Blocks ------------------------------
-
- class ProcedureContext {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(Blocks != null);
- }
-
- public readonly Hashtable/*!*/ /*string->Block!*/ Blocks;
- public readonly ProcedureContext Next;
- public ProcedureContext(ProcedureContext next) {
- Blocks = new Hashtable /*string->Block!*/ ();
- Next = next;
- }
- }
- /*maybe null*/
- ProcedureContext procedureContext; // stack of procedure contexts
- public bool HasProcedureContext {
- get {
- return procedureContext != null;
- }
- }
-
- /// <summary>
- /// Pushes a new procedure context.
- /// </summary>
- public void PushProcedureContext() {
- Contract.Ensures(HasProcedureContext);
- procedureContext = new ProcedureContext(procedureContext);
- }
-
- /// <summary>
- /// Requires there to be a procedure context. Pops it.
- /// </summary>
- public void PopProcedureContext() {
- Contract.Requires(HasProcedureContext);
- Contract.Assert(procedureContext != null); // follows from precondition
- procedureContext = procedureContext.Next;
- }
-
- /// <summary>
- /// Requires there to be a procedure context.
- /// </summary>
- /// <param name="block"></param>
- public void AddBlock(Block block) {
- Contract.Requires(block != null);
- Contract.Requires(HasProcedureContext);
- Contract.Assert(procedureContext != null); // follows from precondition
- Hashtable/*!*/ /*string->Block!*/ blocks = procedureContext.Blocks;
- Contract.Assert(blocks != null);
- if (blocks[block.Label] != null) {
- Error(block, "more than one declaration of block name: {0}", block.Label);
- } else {
- blocks.Add(block.Label, block);
- }
- }
-
- /// <summary>
- /// Requires there to be a procedure context.
- /// Returns the declaration of the named block, or null if
- /// no such block is declared.
- /// </summary>
- /// <param name="name"></param>
- /// <returns></returns>
- public Block LookUpBlock(string name) {
- Contract.Requires(name != null);
- Contract.Requires(HasProcedureContext);
- Contract.Assert(procedureContext != null); // follows from precondition
- Hashtable/*!*/ /*string->Block!*/ blocks = procedureContext.Blocks;
- Contract.Assert(blocks != null);
- return (Block)blocks[name];
- }
-
- // ------------------------------ Flags ------------------------------
-
- public enum State {
- StateLess,
- Single,
- Two
- }
- State stateMode = State.Single;
-
- /// <summary>
- /// To increase our confidence in that the caller knows what it's doing, we only allow
- /// the state mode to be changed in and out of the State.Single mode.
- /// </summary>
- public State StateMode {
- get {
- return stateMode;
- }
- set {
- Contract.Assert(value != stateMode);
- Contract.Assert(stateMode == State.Single || value == State.Single);
- cce.BeginExpose(this);
- {
- stateMode = value;
- }
- cce.EndExpose();
- }
- }
-
- bool triggerMode = false;
-
- /// <summary>
- /// Setting TriggerMode is allowed only if the setting has the effect of toggling the
- /// boolean. That is, TriggerMode can be set to true only if it previously was false,
- /// and TriggerMode can be set to false only if it previously was true.
- /// </summary>
- public bool TriggerMode {
- get {
- return triggerMode;
- }
- set {
- Contract.Assert(triggerMode != value);
- cce.BeginExpose(this);
- {
- triggerMode = value;
- }
- cce.EndExpose();
- }
- }
- }
-
- public class TypecheckingContext : CheckingContext {
- public List<IdentifierExpr> Frame; // used in checking the assignment targets of implementation bodies
- public bool Yields;
-
- public TypecheckingContext(IErrorSink errorSink)
- : base(errorSink) {
- }
-
- public bool InFrame(Variable v) {
- Contract.Requires(v != null);
- Contract.Requires(Frame != null);
- return Frame.Any(f => f.Decl == v);
- }
- }
-}
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+namespace Microsoft.Boogie {
+ using System.Collections;
+ using System.Collections.Generic;
+ using System;
+ using System.Linq;
+ using System.Diagnostics.Contracts;
+
+ [ContractClass(typeof(IErrorSinkContracts))]
+ public interface IErrorSink {
+ void Error(IToken/*!*/ tok, string/*!*/ msg);
+ }
+ [ContractClassFor(typeof(IErrorSink))]
+ public abstract class IErrorSinkContracts : IErrorSink {
+ #region IErrorSink Members
+ public void Error(IToken tok, string msg) {
+ Contract.Requires(tok != null);
+ Contract.Requires(msg != null);
+ throw new NotImplementedException();
+ }
+ #endregion
+ }
+
+ public class CheckingContext {
+ // ------------------------------ Error counting ------------------------------
+
+ IErrorSink errorSink;
+ int errors;
+
+ public CheckingContext(IErrorSink errorSink) {
+ this.errorSink = errorSink;
+ }
+
+ public int ErrorCount {
+ get {
+ return errors;
+ }
+ set {
+ errors = value;
+ }
+ }
+
+ public void Error(Absy subject, string msg, params object[] args) {
+ Contract.Requires(args != null);
+ Contract.Requires(msg != null);
+ Contract.Requires(subject != null);
+ Error(subject.tok, msg, args);
+ }
+
+ public virtual void Error(IToken tok, string msg) {
+ Contract.Requires(msg != null);
+ Contract.Requires(tok != null);
+ errors++;
+ if (errorSink == null) {
+ ConsoleColor col = Console.ForegroundColor;
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine("{0}({1},{2}): Error: {3}",
+ tok.filename, tok.line, tok.col - 1,
+ msg);
+ Console.ForegroundColor = col;
+ } else {
+ errorSink.Error(tok, msg);
+ }
+ }
+
+ private string Format(string msg, params object[] args) {
+ Contract.Requires(msg != null);
+ Contract.Ensures(Contract.Result<string>() != null);
+ if (System.Type.GetType("Mono.Runtime") != null) { // MONO
+ // something in mono seems to be broken so that calling
+ // NamedDeclarations.ToString (and similar ToString methods)
+ // causes a stack overflow. We therefore convert those to
+ // strings by hand
+ object[] fixedArgs = new object[cce.NonNull(args).Length];
+ for (int i = 0; i < args.Length; ++i) {
+ if (args[i] is NamedDeclaration) {
+ fixedArgs[i] = cce.NonNull((NamedDeclaration)args[i]).Name;
+ } else if (args[i] is Type) {
+ System.IO.StringWriter buffer = new System.IO.StringWriter();
+ using (TokenTextWriter stream = new TokenTextWriter("<buffer>", buffer, /*setTokens=*/ false, /*pretty=*/ false)) {
+ cce.NonNull((Type)args[i]).Emit(stream);
+ }
+ fixedArgs[i] = buffer.ToString();
+ } else if (args[i] is Expr) {
+ System.IO.StringWriter buffer = new System.IO.StringWriter();
+ using (TokenTextWriter stream = new TokenTextWriter("<buffer>", buffer, /*setTokens=*/ false, /*pretty=*/ false)) {
+ cce.NonNull((Expr/*!*/)args[i]).Emit(stream, 0, false);
+ }
+ fixedArgs[i] = buffer.ToString();
+ } else {
+ fixedArgs[i] = args[i];
+ }
+ }
+ args = fixedArgs;
+ }
+ return string.Format(msg, args);
+ }
+
+ public void Error(IToken tok, string msg, params object[] args) {
+ Contract.Requires(msg != null);
+ Contract.Requires(tok != null);
+ Error(tok, Format(msg, args));
+ }
+
+ public void Warning(Absy subject, string msg, params object[] args) {
+ Contract.Requires(args != null);
+ Contract.Requires(msg != null);
+ Contract.Requires(subject != null);
+ Warning(subject.tok, msg, args);
+ }
+
+ public virtual void Warning(IToken tok, string msg) {
+ Contract.Requires(msg != null);
+ Contract.Requires(tok != null);
+ // warnings are currently always written to the console
+ ConsoleColor col = Console.ForegroundColor;
+ Console.ForegroundColor = ConsoleColor.DarkYellow;
+ Console.WriteLine("{0}({1},{2}): Warning: {3}",
+ tok.filename, tok.line, tok.col - 1,
+ msg);
+ Console.ForegroundColor = col;
+ }
+
+ public void Warning(IToken tok, string msg, params object[] args) {
+ Contract.Requires(msg != null);
+ Contract.Requires(tok != null);
+ Warning(tok, Format(msg, args));
+ }
+ }
+
+ public class ResolutionContext : CheckingContext {
+ public ResolutionContext(IErrorSink errorSink)
+ : base(errorSink) {
+ }
+
+ // ------------------------------ Boogie 2 Types -------------------------
+
+ // user-defined types, which can be either TypeCtorDecl or TypeSynonymDecl
+ Hashtable /*string->NamedDeclaration*//*!*/ types = new Hashtable /*string->NamedDeclaration*/ ();
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(types != null);
+ Contract.Invariant(cce.NonNullElements(typeBinders));
+ Contract.Invariant(varContext != null);
+ Contract.Invariant(funcdures != null);
+ }
+
+
+ /// <summary>
+ /// Checks if name coincides with the name of a bitvector type. If so, reports an error and
+ /// returns true; otherwise, returns false.
+ /// </summary>
+ private bool CheckBvNameClashes(Absy absy, string name) {
+ Contract.Requires(name != null);
+ Contract.Requires(absy != null);
+ if (name.StartsWith("bv") && name.Length > 2) {
+ for (int i = 2; i < name.Length; ++i)
+ if (!char.IsDigit(name[i]))
+ return false;
+ Error(absy, "type name: {0} is registered for bitvectors", name);
+ return true;
+ }
+ return false;
+ }
+
+ public void AddType(NamedDeclaration td) {
+ Contract.Requires(td != null);
+ Contract.Requires((td is TypeCtorDecl) || (td is TypeSynonymDecl));
+ Contract.Requires(td.Name != null);
+
+ string name = td.Name;
+ if (CheckBvNameClashes(td, name))
+ return; // error has already been reported
+
+ var previous = (NamedDeclaration)types[name];
+ if (previous == null) {
+ types.Add(name, td);
+ } else {
+ var r = (NamedDeclaration)SelectNonExtern(td, previous);
+ if (r == null) {
+ Error(td, "more than one declaration of type name: {0}", name);
+ } else {
+ types[name] = r;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Returns the declaration of the named type, or null if
+ /// no such type is declared. Also return null if the type
+ /// declared with the given name is not a constructor but a
+ /// type synonym
+ /// </summary>
+ /// <param name="name"></param>
+ /// <returns></returns>
+ public TypeCtorDecl LookUpType(string name) {
+ Contract.Requires(name != null);
+ return types[name] as TypeCtorDecl;
+ }
+
+ public TypeSynonymDecl LookUpTypeSynonym(string name) {
+ Contract.Requires(name != null);
+ return types[name] as TypeSynonymDecl;
+ }
+
+ // ------------------------------ Boogie 2 Type Binders ------------------------------
+
+ List<TypeVariable/*!*/>/*!*/ typeBinders = new List<TypeVariable/*!*/>(5);
+
+ public void AddTypeBinder(TypeVariable td) {
+ Contract.Requires(td != null);
+ if (CheckBvNameClashes(td, td.Name)) {
+ return;
+ }
+ if (types.ContainsKey(td.Name)) {
+ Error(td, "name is already reserved for type constructor: {0}", td.Name);
+ return;
+ }
+ for (int i = 0; i < typeBinders.Count; i++) {
+ if (typeBinders[i].Name == td.Name) {
+ Error(td, "more than one declaration of type variable: {0}", td.Name);
+ return;
+ }
+ }
+ typeBinders.Add(td);
+ }
+
+ public int TypeBinderState {
+ get {
+ return typeBinders.Count;
+ }
+ set {
+ typeBinders.RemoveRange(value, typeBinders.Count - value);
+ }
+ }
+
+ /// <summary>
+ /// Returns the declaration of the named type binder, or null if
+ /// no such binder is declared.
+ /// </summary>
+ public TypeVariable LookUpTypeBinder(string name) {
+ Contract.Requires(name != null);
+ for (int i = typeBinders.Count; 0 <= --i; ) {
+ TypeVariable/*!*/ td = typeBinders[i];
+ Contract.Assert(td != null);
+ if (td.Name == name) {
+ return td;
+ }
+ }
+ return null; // not present
+ }
+
+ // ------------------------------ Variables ------------------------------
+
+ class VarContextNode {
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(VarSymbols != null);
+ }
+
+ public readonly Hashtable /*string->Variable*//*!*/ VarSymbols = new Hashtable /*string->Variable*/();
+ public /*maybe null*/ VarContextNode ParentContext;
+ public readonly bool Opaque;
+ readonly ISet<string> assignedAssumptionVariables = new HashSet<string>();
+
+ public bool HasVariableBeenAssigned(string name)
+ {
+ Contract.Requires(name != null);
+
+ if (assignedAssumptionVariables.Contains(name))
+ {
+ return true;
+ }
+ else if (ParentContext != null)
+ {
+ return ParentContext.HasVariableBeenAssigned(name);
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public bool MarkVariableAsAssigned(string name)
+ {
+ Contract.Requires(name != null);
+
+ if (VarSymbols.Contains(name))
+ {
+ if (assignedAssumptionVariables.Contains(name))
+ {
+ return false;
+ }
+ assignedAssumptionVariables.Add(name);
+ return true;
+ }
+ else if (ParentContext != null)
+ {
+ return ParentContext.MarkVariableAsAssigned(name);
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public VarContextNode(/*maybe null*/ VarContextNode parentContext, bool opaque) {
+ ParentContext = parentContext;
+ Opaque = opaque;
+ }
+ }
+
+ // symbolic constants, global variables, local variables, formals, expression-bound variables
+ VarContextNode/*!*/ varContext = new VarContextNode(null, false);
+
+ /// <summary>
+ /// Adds a variable context.
+ /// </summary>
+ public void PushVarContext() {
+ varContext = new VarContextNode(varContext, false);
+ }
+
+ /// <summary>
+ /// Adds an opaque variable context, that is, one that blocks all previously pushed contexts.
+ /// </summary>
+ public void PushOpaqueVarContext() {
+ varContext = new VarContextNode(varContext, true);
+ }
+
+ /// <summary>
+ /// Requires there to be more than one variable context.
+ /// </summary>
+ public void PopVarContext() {
+ Contract.Assert(varContext.ParentContext != null);
+ varContext = varContext.ParentContext;
+ }
+
+ public readonly ISet<string> StatementIds = new HashSet<string>();
+
+ public void AddStatementId(IToken tok, string name)
+ {
+ if (StatementIds.Contains(name))
+ {
+ Error(tok, "more than one statement with same id: " + name);
+ return;
+ }
+ StatementIds.Add(name);
+ }
+
+ public void AddVariable(Variable var, bool global) {
+ Contract.Requires(var != null);
+ var previous = FindVariable(cce.NonNull(var.Name), !global);
+ if (previous == null) {
+ varContext.VarSymbols.Add(var.Name, var);
+ } else {
+ var r = (Variable)SelectNonExtern(var, previous);
+ if (r == null) {
+ Error(var, "more than one declaration of variable name: {0}", var.Name);
+ } else {
+ varContext.VarSymbols[var.Name] = r;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Returns the declaration of the named variable, or null if
+ /// no such variable is declared.
+ /// </summary>
+ /// <param name="name"></param>
+ /// <returns></returns>
+ public Variable LookUpVariable(string name) {
+ Contract.Requires(name != null);
+ return FindVariable(name, false);
+ }
+
+ Variable FindVariable(string name, bool ignoreTopLevelVars) {
+ Contract.Requires(name != null);
+ VarContextNode c = varContext;
+ bool lookOnlyForConstants = false;
+ do {
+ if (ignoreTopLevelVars && c.ParentContext == null) {
+ // this is the top level and we're asked to ignore the top level; hence, we're done
+ break;
+ }
+
+ Variable var = (Variable)c.VarSymbols[name];
+ if (var != null && (!lookOnlyForConstants || var is Constant)) {
+ return var;
+ }
+ // not at this level
+
+ if (c.Opaque) {
+ // from here on, only constants can be looked up
+ lookOnlyForConstants = true;
+ }
+ c = c.ParentContext;
+ } while (c != null);
+
+ // not present in the relevant levels
+ return null;
+ }
+
+ public bool HasVariableBeenAssigned(string name)
+ {
+ Contract.Requires(name != null);
+
+ return varContext.HasVariableBeenAssigned(name);
+ }
+
+ public void MarkVariableAsAssigned(string name)
+ {
+ Contract.Requires(name != null);
+
+ var success = varContext.MarkVariableAsAssigned(name);
+ Contract.Assume(success);
+ }
+
+ Hashtable axioms = new Hashtable();
+
+ public void AddAxiom(Axiom axiom) {
+ string axiomName = QKeyValue.FindStringAttribute(axiom.Attributes, "name");
+ if (axiomName == null)
+ return;
+ var previous = (Axiom)axioms[axiomName];
+ if (previous == null) {
+ axioms.Add(axiomName, axiom);
+ }
+ else {
+ var r = (Axiom)SelectNonExtern(axiom, previous);
+ if (r == null) {
+ Error(axiom, "more than one declaration of axiom name: {0}", axiomName);
+ }
+ else {
+ axioms[axiomName] = r;
+ }
+ }
+ }
+
+ // ------------------------------ Functions/Procedures ------------------------------
+
+ // uninterpreted function symbols, procedures
+ Hashtable /*string->DeclWithFormals*//*!*/ funcdures = new Hashtable /*string->DeclWithFormals*/ ();
+
+ public void AddProcedure(DeclWithFormals proc) {
+ Contract.Requires(proc != null);
+ Contract.Requires(proc.Name != null);
+
+ string name = proc.Name;
+ var previous = (DeclWithFormals)funcdures[name];
+ if (previous == null) {
+ funcdures.Add(name, proc);
+ } else {
+ var r = (DeclWithFormals)SelectNonExtern(proc, previous);
+ if (r == null) {
+ Error(proc, "more than one declaration of function/procedure name: {0}", name);
+ } else {
+ funcdures[name] = r;
+ }
+ }
+ }
+
+ /// <summary>
+ /// If both "a" and "b" have an ":extern" attribute, returns either one.
+ /// If one of "a" and "b" has an ":extern" attribute, returns that one.
+ /// If neither of "a" and "b" has an ":extern" attribute, returns null.
+ /// If a non-value value is returned, this method also adds the ":ignore"
+ /// attribute to the declaration NOT returned.
+ /// </summary>
+ Declaration SelectNonExtern(Declaration a, Declaration b) {
+ Contract.Requires(a != null);
+ Contract.Requires(b != null);
+ Contract.Ensures(Contract.Result<Declaration>() == null || Contract.Result<Declaration>() == a || Contract.Result<Declaration>() == b);
+
+ Declaration ignore, keep;
+ if (QKeyValue.FindBoolAttribute(a.Attributes, "extern")) {
+ ignore = a;
+ keep = b;
+ } else if (QKeyValue.FindBoolAttribute(b.Attributes, "extern")) {
+ ignore = b;
+ keep = a;
+ } else {
+ return null;
+ }
+ // prepend :ignore attribute
+ ignore.Attributes = new QKeyValue(ignore.tok, "ignore", new List<object/*!*/>(), ignore.Attributes);
+ return keep;
+ }
+
+ /// <summary>
+ /// Returns the declaration of the named function/procedure, or null if
+ /// no such function or procedure is declared.
+ /// </summary>
+ /// <param name="name"></param>
+ /// <returns></returns>
+ public DeclWithFormals LookUpProcedure(string name) {
+ Contract.Requires(name != null);
+ return (DeclWithFormals)funcdures[name];
+ }
+
+ // ------------------------------ Blocks ------------------------------
+
+ class ProcedureContext {
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(Blocks != null);
+ }
+
+ public readonly Hashtable/*!*/ /*string->Block!*/ Blocks;
+ public readonly ProcedureContext Next;
+ public ProcedureContext(ProcedureContext next) {
+ Blocks = new Hashtable /*string->Block!*/ ();
+ Next = next;
+ }
+ }
+ /*maybe null*/
+ ProcedureContext procedureContext; // stack of procedure contexts
+ public bool HasProcedureContext {
+ get {
+ return procedureContext != null;
+ }
+ }
+
+ /// <summary>
+ /// Pushes a new procedure context.
+ /// </summary>
+ public void PushProcedureContext() {
+ Contract.Ensures(HasProcedureContext);
+ procedureContext = new ProcedureContext(procedureContext);
+ }
+
+ /// <summary>
+ /// Requires there to be a procedure context. Pops it.
+ /// </summary>
+ public void PopProcedureContext() {
+ Contract.Requires(HasProcedureContext);
+ Contract.Assert(procedureContext != null); // follows from precondition
+ procedureContext = procedureContext.Next;
+ }
+
+ /// <summary>
+ /// Requires there to be a procedure context.
+ /// </summary>
+ /// <param name="block"></param>
+ public void AddBlock(Block block) {
+ Contract.Requires(block != null);
+ Contract.Requires(HasProcedureContext);
+ Contract.Assert(procedureContext != null); // follows from precondition
+ Hashtable/*!*/ /*string->Block!*/ blocks = procedureContext.Blocks;
+ Contract.Assert(blocks != null);
+ if (blocks[block.Label] != null) {
+ Error(block, "more than one declaration of block name: {0}", block.Label);
+ } else {
+ blocks.Add(block.Label, block);
+ }
+ }
+
+ /// <summary>
+ /// Requires there to be a procedure context.
+ /// Returns the declaration of the named block, or null if
+ /// no such block is declared.
+ /// </summary>
+ /// <param name="name"></param>
+ /// <returns></returns>
+ public Block LookUpBlock(string name) {
+ Contract.Requires(name != null);
+ Contract.Requires(HasProcedureContext);
+ Contract.Assert(procedureContext != null); // follows from precondition
+ Hashtable/*!*/ /*string->Block!*/ blocks = procedureContext.Blocks;
+ Contract.Assert(blocks != null);
+ return (Block)blocks[name];
+ }
+
+ // ------------------------------ Flags ------------------------------
+
+ public enum State {
+ StateLess,
+ Single,
+ Two
+ }
+ State stateMode = State.Single;
+
+ /// <summary>
+ /// To increase our confidence in that the caller knows what it's doing, we only allow
+ /// the state mode to be changed in and out of the State.Single mode.
+ /// </summary>
+ public State StateMode {
+ get {
+ return stateMode;
+ }
+ set {
+ Contract.Assert(value != stateMode);
+ Contract.Assert(stateMode == State.Single || value == State.Single);
+ cce.BeginExpose(this);
+ {
+ stateMode = value;
+ }
+ cce.EndExpose();
+ }
+ }
+
+ bool triggerMode = false;
+
+ /// <summary>
+ /// Setting TriggerMode is allowed only if the setting has the effect of toggling the
+ /// boolean. That is, TriggerMode can be set to true only if it previously was false,
+ /// and TriggerMode can be set to false only if it previously was true.
+ /// </summary>
+ public bool TriggerMode {
+ get {
+ return triggerMode;
+ }
+ set {
+ Contract.Assert(triggerMode != value);
+ cce.BeginExpose(this);
+ {
+ triggerMode = value;
+ }
+ cce.EndExpose();
+ }
+ }
+ }
+
+ public class TypecheckingContext : CheckingContext {
+ public List<IdentifierExpr> Frame; // used in checking the assignment targets of implementation bodies
+ public bool Yields;
+
+ public TypecheckingContext(IErrorSink errorSink)
+ : base(errorSink) {
+ }
+
+ public bool InFrame(Variable v) {
+ Contract.Requires(v != null);
+ Contract.Requires(Frame != null);
+ return Frame.Any(f => f.Decl == v);
+ }
+ }
+}
diff --git a/Source/Core/Scanner.cs b/Source/Core/Scanner.cs
index ca7db1e1..69023555 100644
--- a/Source/Core/Scanner.cs
+++ b/Source/Core/Scanner.cs
@@ -1,823 +1,823 @@
-
-using System;
-using System.IO;
-using System.Collections;
-using System.Collections.Generic;
-using System.Text;
-using System.Diagnostics.Contracts;
-using Microsoft.Boogie;
-
-
-namespace Microsoft.Boogie {
-
-//-----------------------------------------------------------------------------------
-// Buffer
-//-----------------------------------------------------------------------------------
-public class Buffer {
- // This Buffer supports the following cases:
- // 1) seekable stream (file)
- // a) whole stream in buffer
- // b) part of stream in buffer
- // 2) non seekable stream (network, console)
-
- public const int EOF = 65535 + 1; // char.MaxValue + 1;
- const int MIN_BUFFER_LENGTH = 1024; // 1KB
- const int MAX_BUFFER_LENGTH = MIN_BUFFER_LENGTH * 64; // 64KB
- byte[]/*!*/ buf; // input buffer
- int bufStart; // position of first byte in buffer relative to input stream
- int bufLen; // length of buffer
- int fileLen; // length of input stream (may change if the stream is no file)
- int bufPos; // current position in buffer
- Stream/*!*/ stream; // input stream (seekable)
- bool isUserStream; // was the stream opened by the user?
-
- [ContractInvariantMethod]
- void ObjectInvariant(){
- Contract.Invariant(buf != null);
- Contract.Invariant(stream != null);
- }
-
-// [NotDelayed]
- public Buffer (Stream/*!*/ s, bool isUserStream) : base() {
- Contract.Requires(s != null);
- stream = s; this.isUserStream = isUserStream;
-
- int fl, bl;
- if (s.CanSeek) {
- fl = (int) s.Length;
- bl = fl < MAX_BUFFER_LENGTH ? fl : MAX_BUFFER_LENGTH; // Math.Min(fileLen, MAX_BUFFER_LENGTH);
- bufStart = Int32.MaxValue; // nothing in the buffer so far
- } else {
- fl = bl = bufStart = 0;
- }
-
- buf = new byte[(bl>0) ? bl : MIN_BUFFER_LENGTH];
- fileLen = fl; bufLen = bl;
-
- if (fileLen > 0) Pos = 0; // setup buffer to position 0 (start)
- else bufPos = 0; // index 0 is already after the file, thus Pos = 0 is invalid
- if (bufLen == fileLen && s.CanSeek) Close();
- }
-
- protected Buffer(Buffer/*!*/ b) { // called in UTF8Buffer constructor
- Contract.Requires(b != null);
- buf = b.buf;
- bufStart = b.bufStart;
- bufLen = b.bufLen;
- fileLen = b.fileLen;
- bufPos = b.bufPos;
- stream = b.stream;
- // keep destructor from closing the stream
- //b.stream = null;
- isUserStream = b.isUserStream;
- // keep destructor from closing the stream
- b.isUserStream = true;
- }
-
- ~Buffer() { Close(); }
-
- protected void Close() {
- if (!isUserStream && stream != null) {
- stream.Close();
- //stream = null;
- }
- }
-
- public virtual int Read () {
- if (bufPos < bufLen) {
- return buf[bufPos++];
- } else if (Pos < fileLen) {
- Pos = Pos; // shift buffer start to Pos
- return buf[bufPos++];
- } else if (stream != null && !stream.CanSeek && ReadNextStreamChunk() > 0) {
- return buf[bufPos++];
- } else {
- return EOF;
- }
- }
-
- public int Peek () {
- int curPos = Pos;
- int ch = Read();
- Pos = curPos;
- return ch;
- }
-
- public string/*!*/ GetString (int beg, int end) {
- Contract.Ensures(Contract.Result<string>() != null);
- int len = 0;
- char[] buf = new char[end - beg];
- int oldPos = Pos;
- Pos = beg;
- while (Pos < end) buf[len++] = (char) Read();
- Pos = oldPos;
- return new String(buf, 0, len);
- }
-
- public int Pos {
- get { return bufPos + bufStart; }
- set {
- if (value >= fileLen && stream != null && !stream.CanSeek) {
- // Wanted position is after buffer and the stream
- // is not seek-able e.g. network or console,
- // thus we have to read the stream manually till
- // the wanted position is in sight.
- while (value >= fileLen && ReadNextStreamChunk() > 0);
- }
-
- if (value < 0 || value > fileLen) {
- throw new FatalError("buffer out of bounds access, position: " + value);
- }
-
- if (value >= bufStart && value < bufStart + bufLen) { // already in buffer
- bufPos = value - bufStart;
- } else if (stream != null) { // must be swapped in
- stream.Seek(value, SeekOrigin.Begin);
- bufLen = stream.Read(buf, 0, buf.Length);
- bufStart = value; bufPos = 0;
- } else {
- // set the position to the end of the file, Pos will return fileLen.
- bufPos = fileLen - bufStart;
- }
- }
- }
-
- // Read the next chunk of bytes from the stream, increases the buffer
- // if needed and updates the fields fileLen and bufLen.
- // Returns the number of bytes read.
- private int ReadNextStreamChunk() {
- int free = buf.Length - bufLen;
- if (free == 0) {
- // in the case of a growing input stream
- // we can neither seek in the stream, nor can we
- // foresee the maximum length, thus we must adapt
- // the buffer size on demand.
- byte[] newBuf = new byte[bufLen * 2];
- Array.Copy(buf, newBuf, bufLen);
- buf = newBuf;
- free = bufLen;
- }
- int read = stream.Read(buf, bufLen, free);
- if (read > 0) {
- fileLen = bufLen = (bufLen + read);
- return read;
- }
- // end of stream reached
- return 0;
- }
-}
-
-//-----------------------------------------------------------------------------------
-// UTF8Buffer
-//-----------------------------------------------------------------------------------
-public class UTF8Buffer: Buffer {
- public UTF8Buffer(Buffer/*!*/ b): base(b) {Contract.Requires(b != null);}
-
- public override int Read() {
- int ch;
- do {
- ch = base.Read();
- // until we find a utf8 start (0xxxxxxx or 11xxxxxx)
- } while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EOF));
- if (ch < 128 || ch == EOF) {
- // nothing to do, first 127 chars are the same in ascii and utf8
- // 0xxxxxxx or end of file character
- } else if ((ch & 0xF0) == 0xF0) {
- // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- int c1 = ch & 0x07; ch = base.Read();
- int c2 = ch & 0x3F; ch = base.Read();
- int c3 = ch & 0x3F; ch = base.Read();
- int c4 = ch & 0x3F;
- ch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4;
- } else if ((ch & 0xE0) == 0xE0) {
- // 1110xxxx 10xxxxxx 10xxxxxx
- int c1 = ch & 0x0F; ch = base.Read();
- int c2 = ch & 0x3F; ch = base.Read();
- int c3 = ch & 0x3F;
- ch = (((c1 << 6) | c2) << 6) | c3;
- } else if ((ch & 0xC0) == 0xC0) {
- // 110xxxxx 10xxxxxx
- int c1 = ch & 0x1F; ch = base.Read();
- int c2 = ch & 0x3F;
- ch = (c1 << 6) | c2;
- }
- return ch;
- }
-}
-
-//-----------------------------------------------------------------------------------
-// Scanner
-//-----------------------------------------------------------------------------------
-public class Scanner {
- const char EOL = '\n';
- const int eofSym = 0; /* pdt */
- const int maxT = 96;
- const int noSym = 96;
-
-
- [ContractInvariantMethod]
- void objectInvariant(){
- Contract.Invariant(this._buffer != null);
- Contract.Invariant(t != null);
- Contract.Invariant(start != null);
- Contract.Invariant(tokens != null);
- Contract.Invariant(pt != null);
- Contract.Invariant(tval != null);
- Contract.Invariant(Filename != null);
- Contract.Invariant(errorHandler != null);
- }
-
- private Buffer/*!*/ _buffer; // scanner buffer
-
- public Buffer/*!*/ buffer {
- get {
- Contract.Ensures(Contract.Result<Buffer>() != null);
- return this._buffer;
- }
- set {
- Contract.Requires(value != null);
- this._buffer = value;
- }
- }
-
- Token/*!*/ t; // current token
- int ch; // current input character
- int pos; // byte position of current character
- int charPos;
- int col; // column number of current character
- int line; // line number of current character
- int oldEols; // EOLs that appeared in a comment;
- static readonly Hashtable/*!*/ start; // maps first token character to start state
-
- Token/*!*/ tokens; // list of tokens already peeked (first token is a dummy)
- Token/*!*/ pt; // current peek token
-
- char[]/*!*/ tval = new char[128]; // text of current token
- int tlen; // length of current token
-
- private string/*!*/ Filename;
- private Errors/*!*/ errorHandler;
-
- static Scanner() {
- start = new Hashtable(128);
- for (int i = 35; i <= 36; ++i) start[i] = 2;
- for (int i = 39; i <= 39; ++i) start[i] = 2;
- for (int i = 46; i <= 46; ++i) start[i] = 2;
- for (int i = 63; i <= 63; ++i) start[i] = 2;
- for (int i = 65; i <= 90; ++i) start[i] = 2;
- for (int i = 94; i <= 122; ++i) start[i] = 2;
- for (int i = 126; i <= 126; ++i) start[i] = 2;
- for (int i = 48; i <= 57; ++i) start[i] = 16;
- for (int i = 34; i <= 34; ++i) start[i] = 6;
- start[92] = 1;
- start[59] = 19;
- start[40] = 20;
- start[41] = 21;
- start[58] = 55;
- start[44] = 22;
- start[91] = 23;
- start[93] = 24;
- start[60] = 56;
- start[62] = 57;
- start[123] = 25;
- start[125] = 58;
- start[61] = 59;
- start[42] = 60;
- start[124] = 61;
- start[8660] = 28;
- start[8658] = 30;
- start[8656] = 31;
- start[38] = 32;
- start[8743] = 34;
- start[8744] = 36;
- start[33] = 62;
- start[8800] = 40;
- start[8804] = 41;
- start[8805] = 42;
- start[43] = 63;
- start[45] = 44;
- start[47] = 45;
- start[172] = 47;
- start[8704] = 50;
- start[8707] = 51;
- start[955] = 52;
- start[8226] = 54;
- start[Buffer.EOF] = -1;
-
- }
-
-// [NotDelayed]
- public Scanner (string/*!*/ fileName, Errors/*!*/ errorHandler, bool useBaseName = false) : base() {
- Contract.Requires(fileName != null);
- Contract.Requires(errorHandler != null);
- this.errorHandler = errorHandler;
- pt = tokens = new Token(); // first token is a dummy
- t = new Token(); // dummy because t is a non-null field
- try {
- Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
- this._buffer = new Buffer(stream, false);
- Filename = useBaseName? GetBaseName(fileName): fileName;
- Init();
- } catch (IOException) {
- throw new FatalError("Cannot open file " + fileName);
- }
- }
-
-// [NotDelayed]
- public Scanner (Stream/*!*/ s, Errors/*!*/ errorHandler, string/*!*/ fileName, bool useBaseName = false) : base() {
- Contract.Requires(s != null);
- Contract.Requires(errorHandler != null);
- Contract.Requires(fileName != null);
- pt = tokens = new Token(); // first token is a dummy
- t = new Token(); // dummy because t is a non-null field
- this._buffer = new Buffer(s, true);
- this.errorHandler = errorHandler;
- this.Filename = useBaseName? GetBaseName(fileName) : fileName;
- Init();
- }
-
- string GetBaseName(string fileName) {
- return System.IO.Path.GetFileName(fileName); // Return basename
- }
-
- void Init() {
- pos = -1; line = 1; col = 0;
- oldEols = 0;
- NextCh();
- if (ch == 0xEF) { // check optional byte order mark for UTF-8
- NextCh(); int ch1 = ch;
- NextCh(); int ch2 = ch;
- if (ch1 != 0xBB || ch2 != 0xBF) {
- throw new FatalError(String.Format("illegal byte order mark: EF {0,2:X} {1,2:X}", ch1, ch2));
- }
- buffer = new UTF8Buffer(buffer); col = 0;
- NextCh();
- }
- pt = tokens = new Token(); // first token is a dummy
- }
-
- string/*!*/ ReadToEOL(){
- Contract.Ensures(Contract.Result<string>() != null);
- int p = buffer.Pos;
- int ch = buffer.Read();
- // replace isolated '\r' by '\n' in order to make
- // eol handling uniform across Windows, Unix and Mac
- if (ch == '\r' && buffer.Peek() != '\n') ch = EOL;
- while (ch != EOL && ch != Buffer.EOF){
- ch = buffer.Read();
- // replace isolated '\r' by '\n' in order to make
- // eol handling uniform across Windows, Unix and Mac
- if (ch == '\r' && buffer.Peek() != '\n') ch = EOL;
- }
- string/*!*/ s = buffer.GetString(p, buffer.Pos);
- Contract.Assert(s!=null);
- return s;
- }
-
- void NextCh() {
- if (oldEols > 0) { ch = EOL; oldEols--; }
- else {
-// pos = buffer.Pos;
-// ch = buffer.Read(); col++;
-// // replace isolated '\r' by '\n' in order to make
-// // eol handling uniform across Windows, Unix and Mac
-// if (ch == '\r' && buffer.Peek() != '\n') ch = EOL;
-// if (ch == EOL) { line++; col = 0; }
-
- while (true) {
- pos = buffer.Pos;
- ch = buffer.Read(); col++;
- // replace isolated '\r' by '\n' in order to make
- // eol handling uniform across Windows, Unix and Mac
- if (ch == '\r' && buffer.Peek() != '\n') ch = EOL;
- if (ch == EOL) {
- line++; col = 0;
- } else if (ch == '#' && col == 1) {
- int prLine = line;
- int prColumn = 0;
-
- string/*!*/ hashLine = ReadToEOL();
- Contract.Assert(hashLine!=null);
- col = 0;
- line++;
-
- hashLine = hashLine.TrimEnd(null);
- if (hashLine.StartsWith("line ") || hashLine == "line") {
- // parse #line pragma: #line num [filename]
- string h = hashLine.Substring(4).TrimStart(null);
- int x = h.IndexOf(' ');
- if (x == -1) {
- x = h.Length; // this will be convenient below when we look for a filename
- }
- try {
- int li = int.Parse(h.Substring(0, x));
-
- h = h.Substring(x).Trim();
-
- // act on #line
- line = li;
- if (h.Length != 0) {
- // a filename was specified
- Filename = h;
- }
- continue; // successfully parsed and acted on the #line pragma
-
- } catch (FormatException) {
- // just fall down through to produce an error message
- }
- this.errorHandler.SemErr(Filename, prLine, prColumn, "Malformed (#line num [filename]) pragma: #" + hashLine);
- continue;
- }
-
- this.errorHandler.SemErr(Filename, prLine, prColumn, "Unrecognized pragma: #" + hashLine);
- continue;
- }
- return;
- }
-
-
- }
-
- }
-
- void AddCh() {
- if (tlen >= tval.Length) {
- char[] newBuf = new char[2 * tval.Length];
- Array.Copy(tval, 0, newBuf, 0, tval.Length);
- tval = newBuf;
- }
- if (ch != Buffer.EOF) {
- tval[tlen++] = (char) ch;
- NextCh();
- }
- }
-
-
-
- bool Comment0() {
- int level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos;
- NextCh();
- if (ch == '/') {
- NextCh();
- for(;;) {
- if (ch == 10) {
- level--;
- if (level == 0) { oldEols = line - line0; NextCh(); return true; }
- NextCh();
- } else if (ch == Buffer.EOF) return false;
- else NextCh();
- }
- } else {
- buffer.Pos = pos0; NextCh(); line = line0; col = col0; charPos = charPos0;
- }
- return false;
- }
-
- bool Comment1() {
- int level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos;
- NextCh();
- if (ch == '*') {
- NextCh();
- for(;;) {
- if (ch == '*') {
- NextCh();
- if (ch == '/') {
- level--;
- if (level == 0) { oldEols = line - line0; NextCh(); return true; }
- NextCh();
- }
- } else if (ch == '/') {
- NextCh();
- if (ch == '*') {
- level++; NextCh();
- }
- } else if (ch == Buffer.EOF) return false;
- else NextCh();
- }
- } else {
- buffer.Pos = pos0; NextCh(); line = line0; col = col0; charPos = charPos0;
- }
- return false;
- }
-
-
- void CheckLiteral() {
- switch (t.val) {
- case "var": t.kind = 7; break;
- case "where": t.kind = 13; break;
- 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": 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;
- case "complete": t.kind = 24; break;
- case "function": t.kind = 25; break;
- case "returns": t.kind = 26; break;
- case "axiom": t.kind = 29; break;
- case "type": t.kind = 30; break;
- case "procedure": t.kind = 32; break;
- case "implementation": t.kind = 33; break;
- case "modifies": t.kind = 34; break;
- case "free": t.kind = 35; break;
- case "requires": t.kind = 36; break;
- case "ensures": t.kind = 37; break;
- case "goto": t.kind = 38; break;
- case "return": t.kind = 39; break;
- case "if": t.kind = 40; break;
- case "else": t.kind = 41; break;
- case "while": t.kind = 42; break;
- case "invariant": t.kind = 43; break;
- case "break": t.kind = 45; break;
- case "assert": t.kind = 46; break;
- case "assume": t.kind = 47; break;
- case "havoc": t.kind = 48; break;
- case "yield": t.kind = 49; break;
- case "async": t.kind = 51; break;
- case "call": t.kind = 52; break;
- case "par": t.kind = 53; break;
- case "div": t.kind = 76; break;
- case "mod": t.kind = 77; break;
- case "false": t.kind = 82; break;
- case "true": t.kind = 83; break;
- case "old": t.kind = 84; break;
- case "then": t.kind = 87; break;
- case "forall": t.kind = 88; break;
- case "exists": t.kind = 90; break;
- case "lambda": t.kind = 92; break;
- default: break;
- }
- }
-
- Token/*!*/ NextToken() {
- Contract.Ensures(Contract.Result<Token>() != null);
- while (ch == ' ' ||
- ch >= 9 && ch <= 10 || ch == 13
- ) NextCh();
- if (ch == '/' && Comment0() ||ch == '/' && Comment1()) return NextToken();
- int recKind = noSym;
- int recEnd = pos;
- t = new Token();
- t.pos = pos; t.col = col; t.line = line;
- t.filename = this.Filename;
- int state;
- if (start.ContainsKey(ch)) {
- Contract.Assert(start[ch] != null);
- state = (int) start[ch];
- }
- else { state = 0; }
- tlen = 0; AddCh();
-
- switch (state) {
- case -1: { t.kind = eofSym; break; } // NextCh already done
- case 0: {
- if (recKind != noSym) {
- tlen = recEnd - t.pos;
- SetScannerBehindT();
- }
- t.kind = recKind; break;
- } // NextCh already done
- case 1:
- if (ch >= '#' && ch <= '$' || ch == 39 || ch == '.' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch >= '^' && ch <= 'z' || ch == '~') {AddCh(); goto case 2;}
- else {goto case 0;}
- case 2:
- recEnd = pos; recKind = 1;
- if (ch >= '#' && ch <= '$' || ch == 39 || ch == '.' || ch >= '0' && ch <= '9' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch >= '^' && ch <= 'z' || ch == '~') {AddCh(); goto case 2;}
- else {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;}
- case 3:
- if (ch == 'v') {AddCh(); goto case 4;}
- else {goto case 0;}
- case 4:
- if (ch >= '0' && ch <= '9') {AddCh(); goto case 5;}
- else {goto case 0;}
- case 5:
- recEnd = pos; recKind = 2;
- if (ch >= '0' && ch <= '9') {AddCh(); goto case 5;}
- else {t.kind = 2; break;}
- case 6:
- if (ch == '"') {AddCh(); goto case 7;}
- else if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); goto case 6;}
- else if (ch == 92) {AddCh(); goto case 17;}
- else {goto case 0;}
- case 7:
- {t.kind = 4; break;}
- case 8:
- if (ch >= '0' && ch <= '9') {AddCh(); goto case 10;}
- else if (ch == '-') {AddCh(); goto case 9;}
- else {goto case 0;}
- case 9:
- if (ch >= '0' && ch <= '9') {AddCh(); goto case 10;}
- else {goto case 0;}
- case 10:
- recEnd = pos; recKind = 5;
- if (ch >= '0' && ch <= '9') {AddCh(); goto case 10;}
- else {t.kind = 5; break;}
- case 11:
- if (ch >= '0' && ch <= '9') {AddCh(); goto case 12;}
- else {goto case 0;}
- case 12:
- recEnd = pos; recKind = 6;
- if (ch >= '0' && ch <= '9') {AddCh(); goto case 12;}
- else if (ch == 'e') {AddCh(); goto case 13;}
- else {t.kind = 6; break;}
- case 13:
- if (ch >= '0' && ch <= '9') {AddCh(); goto case 15;}
- else if (ch == '-') {AddCh(); goto case 14;}
- else {goto case 0;}
- case 14:
- if (ch >= '0' && ch <= '9') {AddCh(); goto case 15;}
- else {goto case 0;}
- case 15:
- recEnd = pos; recKind = 6;
- if (ch >= '0' && ch <= '9') {AddCh(); goto case 15;}
- else {t.kind = 6; break;}
- case 16:
- recEnd = pos; recKind = 3;
- if (ch >= '0' && ch <= '9') {AddCh(); goto case 16;}
- else if (ch == 'b') {AddCh(); goto case 3;}
- else if (ch == 'e') {AddCh(); goto case 8;}
- else if (ch == '.') {AddCh(); goto case 11;}
- else {t.kind = 3; break;}
- case 17:
- if (ch == '"') {AddCh(); goto case 18;}
- else if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); goto case 6;}
- else if (ch == 92) {AddCh(); goto case 17;}
- else {goto case 0;}
- case 18:
- recEnd = pos; recKind = 4;
- if (ch == '"') {AddCh(); goto case 7;}
- else if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); goto case 6;}
- else if (ch == 92) {AddCh(); goto case 17;}
- else {t.kind = 4; break;}
- case 19:
- {t.kind = 8; break;}
- case 20:
- {t.kind = 9; break;}
- case 21:
- {t.kind = 10; break;}
- case 22:
- {t.kind = 12; break;}
- case 23:
- {t.kind = 17; break;}
- case 24:
- {t.kind = 18; break;}
- case 25:
- {t.kind = 27; break;}
- case 26:
- {t.kind = 50; break;}
- case 27:
- {t.kind = 55; break;}
- case 28:
- {t.kind = 56; break;}
- case 29:
- {t.kind = 57; break;}
- case 30:
- {t.kind = 58; break;}
- case 31:
- {t.kind = 60; break;}
- case 32:
- if (ch == '&') {AddCh(); goto case 33;}
- else {goto case 0;}
- case 33:
- {t.kind = 61; break;}
- case 34:
- {t.kind = 62; break;}
- case 35:
- {t.kind = 63; break;}
- case 36:
- {t.kind = 64; break;}
- case 37:
- {t.kind = 67; break;}
- case 38:
- {t.kind = 68; break;}
- case 39:
- {t.kind = 69; break;}
- case 40:
- {t.kind = 70; break;}
- case 41:
- {t.kind = 71; break;}
- case 42:
- {t.kind = 72; break;}
- case 43:
- {t.kind = 73; break;}
- case 44:
- {t.kind = 75; break;}
- case 45:
- {t.kind = 78; break;}
- case 46:
- {t.kind = 79; break;}
- case 47:
- {t.kind = 81; break;}
- case 48:
- {t.kind = 85; break;}
- case 49:
- {t.kind = 86; break;}
- case 50:
- {t.kind = 89; break;}
- case 51:
- {t.kind = 91; break;}
- case 52:
- {t.kind = 93; break;}
- case 53:
- {t.kind = 94; break;}
- case 54:
- {t.kind = 95; break;}
- case 55:
- recEnd = pos; recKind = 11;
- if (ch == '=') {AddCh(); goto case 26;}
- else if (ch == ':') {AddCh(); goto case 53;}
- else {t.kind = 11; break;}
- case 56:
- recEnd = pos; recKind = 19;
- if (ch == '=') {AddCh(); goto case 64;}
- else if (ch == ':') {AddCh(); goto case 39;}
- else {t.kind = 19; break;}
- case 57:
- recEnd = pos; recKind = 20;
- if (ch == '=') {AddCh(); goto case 37;}
- else {t.kind = 20; break;}
- case 58:
- recEnd = pos; recKind = 28;
- if (ch == '|') {AddCh(); goto case 49;}
- else {t.kind = 28; break;}
- case 59:
- recEnd = pos; recKind = 31;
- if (ch == '=') {AddCh(); goto case 65;}
- else {t.kind = 31; break;}
- case 60:
- recEnd = pos; recKind = 44;
- if (ch == '*') {AddCh(); goto case 46;}
- else {t.kind = 44; break;}
- case 61:
- recEnd = pos; recKind = 54;
- if (ch == '|') {AddCh(); goto case 35;}
- else if (ch == '{') {AddCh(); goto case 48;}
- else {t.kind = 54; break;}
- case 62:
- recEnd = pos; recKind = 80;
- if (ch == '=') {AddCh(); goto case 38;}
- else {t.kind = 80; break;}
- case 63:
- recEnd = pos; recKind = 74;
- if (ch == '+') {AddCh(); goto case 43;}
- else {t.kind = 74; break;}
- case 64:
- recEnd = pos; recKind = 66;
- if (ch == '=') {AddCh(); goto case 66;}
- else {t.kind = 66; break;}
- case 65:
- recEnd = pos; recKind = 65;
- if (ch == '>') {AddCh(); goto case 29;}
- else {t.kind = 65; break;}
- case 66:
- recEnd = pos; recKind = 59;
- if (ch == '>') {AddCh(); goto case 27;}
- else {t.kind = 59; break;}
-
- }
- t.val = new String(tval, 0, tlen);
- return t;
- }
-
- private void SetScannerBehindT() {
- buffer.Pos = t.pos;
- NextCh();
- line = t.line; col = t.col;
- for (int i = 0; i < tlen; i++) NextCh();
- }
-
- // get the next token (possibly a token already seen during peeking)
- public Token/*!*/ Scan () {
- Contract.Ensures(Contract.Result<Token>() != null);
- if (tokens.next == null) {
- return NextToken();
- } else {
- pt = tokens = tokens.next;
- return tokens;
- }
- }
-
- // peek for the next token, ignore pragmas
- public Token/*!*/ Peek () {
- Contract.Ensures(Contract.Result<Token>() != null);
- do {
- if (pt.next == null) {
- pt.next = NextToken();
- }
- pt = pt.next;
- } while (pt.kind > maxT); // skip pragmas
-
- return pt;
- }
-
- // make sure that peeking starts at the current scan position
- public void ResetPeek () { pt = tokens; }
-
-} // end Scanner
-
-public delegate void ErrorProc(int n, string filename, int line, int col);
-
-
+
+using System;
+using System.IO;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using System.Diagnostics.Contracts;
+using Microsoft.Boogie;
+
+
+namespace Microsoft.Boogie {
+
+//-----------------------------------------------------------------------------------
+// Buffer
+//-----------------------------------------------------------------------------------
+public class Buffer {
+ // This Buffer supports the following cases:
+ // 1) seekable stream (file)
+ // a) whole stream in buffer
+ // b) part of stream in buffer
+ // 2) non seekable stream (network, console)
+
+ public const int EOF = 65535 + 1; // char.MaxValue + 1;
+ const int MIN_BUFFER_LENGTH = 1024; // 1KB
+ const int MAX_BUFFER_LENGTH = MIN_BUFFER_LENGTH * 64; // 64KB
+ byte[]/*!*/ buf; // input buffer
+ int bufStart; // position of first byte in buffer relative to input stream
+ int bufLen; // length of buffer
+ int fileLen; // length of input stream (may change if the stream is no file)
+ int bufPos; // current position in buffer
+ Stream/*!*/ stream; // input stream (seekable)
+ bool isUserStream; // was the stream opened by the user?
+
+ [ContractInvariantMethod]
+ void ObjectInvariant(){
+ Contract.Invariant(buf != null);
+ Contract.Invariant(stream != null);
+ }
+
+// [NotDelayed]
+ public Buffer (Stream/*!*/ s, bool isUserStream) : base() {
+ Contract.Requires(s != null);
+ stream = s; this.isUserStream = isUserStream;
+
+ int fl, bl;
+ if (s.CanSeek) {
+ fl = (int) s.Length;
+ bl = fl < MAX_BUFFER_LENGTH ? fl : MAX_BUFFER_LENGTH; // Math.Min(fileLen, MAX_BUFFER_LENGTH);
+ bufStart = Int32.MaxValue; // nothing in the buffer so far
+ } else {
+ fl = bl = bufStart = 0;
+ }
+
+ buf = new byte[(bl>0) ? bl : MIN_BUFFER_LENGTH];
+ fileLen = fl; bufLen = bl;
+
+ if (fileLen > 0) Pos = 0; // setup buffer to position 0 (start)
+ else bufPos = 0; // index 0 is already after the file, thus Pos = 0 is invalid
+ if (bufLen == fileLen && s.CanSeek) Close();
+ }
+
+ protected Buffer(Buffer/*!*/ b) { // called in UTF8Buffer constructor
+ Contract.Requires(b != null);
+ buf = b.buf;
+ bufStart = b.bufStart;
+ bufLen = b.bufLen;
+ fileLen = b.fileLen;
+ bufPos = b.bufPos;
+ stream = b.stream;
+ // keep destructor from closing the stream
+ //b.stream = null;
+ isUserStream = b.isUserStream;
+ // keep destructor from closing the stream
+ b.isUserStream = true;
+ }
+
+ ~Buffer() { Close(); }
+
+ protected void Close() {
+ if (!isUserStream && stream != null) {
+ stream.Close();
+ //stream = null;
+ }
+ }
+
+ public virtual int Read () {
+ if (bufPos < bufLen) {
+ return buf[bufPos++];
+ } else if (Pos < fileLen) {
+ Pos = Pos; // shift buffer start to Pos
+ return buf[bufPos++];
+ } else if (stream != null && !stream.CanSeek && ReadNextStreamChunk() > 0) {
+ return buf[bufPos++];
+ } else {
+ return EOF;
+ }
+ }
+
+ public int Peek () {
+ int curPos = Pos;
+ int ch = Read();
+ Pos = curPos;
+ return ch;
+ }
+
+ public string/*!*/ GetString (int beg, int end) {
+ Contract.Ensures(Contract.Result<string>() != null);
+ int len = 0;
+ char[] buf = new char[end - beg];
+ int oldPos = Pos;
+ Pos = beg;
+ while (Pos < end) buf[len++] = (char) Read();
+ Pos = oldPos;
+ return new String(buf, 0, len);
+ }
+
+ public int Pos {
+ get { return bufPos + bufStart; }
+ set {
+ if (value >= fileLen && stream != null && !stream.CanSeek) {
+ // Wanted position is after buffer and the stream
+ // is not seek-able e.g. network or console,
+ // thus we have to read the stream manually till
+ // the wanted position is in sight.
+ while (value >= fileLen && ReadNextStreamChunk() > 0);
+ }
+
+ if (value < 0 || value > fileLen) {
+ throw new FatalError("buffer out of bounds access, position: " + value);
+ }
+
+ if (value >= bufStart && value < bufStart + bufLen) { // already in buffer
+ bufPos = value - bufStart;
+ } else if (stream != null) { // must be swapped in
+ stream.Seek(value, SeekOrigin.Begin);
+ bufLen = stream.Read(buf, 0, buf.Length);
+ bufStart = value; bufPos = 0;
+ } else {
+ // set the position to the end of the file, Pos will return fileLen.
+ bufPos = fileLen - bufStart;
+ }
+ }
+ }
+
+ // Read the next chunk of bytes from the stream, increases the buffer
+ // if needed and updates the fields fileLen and bufLen.
+ // Returns the number of bytes read.
+ private int ReadNextStreamChunk() {
+ int free = buf.Length - bufLen;
+ if (free == 0) {
+ // in the case of a growing input stream
+ // we can neither seek in the stream, nor can we
+ // foresee the maximum length, thus we must adapt
+ // the buffer size on demand.
+ byte[] newBuf = new byte[bufLen * 2];
+ Array.Copy(buf, newBuf, bufLen);
+ buf = newBuf;
+ free = bufLen;
+ }
+ int read = stream.Read(buf, bufLen, free);
+ if (read > 0) {
+ fileLen = bufLen = (bufLen + read);
+ return read;
+ }
+ // end of stream reached
+ return 0;
+ }
+}
+
+//-----------------------------------------------------------------------------------
+// UTF8Buffer
+//-----------------------------------------------------------------------------------
+public class UTF8Buffer: Buffer {
+ public UTF8Buffer(Buffer/*!*/ b): base(b) {Contract.Requires(b != null);}
+
+ public override int Read() {
+ int ch;
+ do {
+ ch = base.Read();
+ // until we find a utf8 start (0xxxxxxx or 11xxxxxx)
+ } while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EOF));
+ if (ch < 128 || ch == EOF) {
+ // nothing to do, first 127 chars are the same in ascii and utf8
+ // 0xxxxxxx or end of file character
+ } else if ((ch & 0xF0) == 0xF0) {
+ // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ int c1 = ch & 0x07; ch = base.Read();
+ int c2 = ch & 0x3F; ch = base.Read();
+ int c3 = ch & 0x3F; ch = base.Read();
+ int c4 = ch & 0x3F;
+ ch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4;
+ } else if ((ch & 0xE0) == 0xE0) {
+ // 1110xxxx 10xxxxxx 10xxxxxx
+ int c1 = ch & 0x0F; ch = base.Read();
+ int c2 = ch & 0x3F; ch = base.Read();
+ int c3 = ch & 0x3F;
+ ch = (((c1 << 6) | c2) << 6) | c3;
+ } else if ((ch & 0xC0) == 0xC0) {
+ // 110xxxxx 10xxxxxx
+ int c1 = ch & 0x1F; ch = base.Read();
+ int c2 = ch & 0x3F;
+ ch = (c1 << 6) | c2;
+ }
+ return ch;
+ }
+}
+
+//-----------------------------------------------------------------------------------
+// Scanner
+//-----------------------------------------------------------------------------------
+public class Scanner {
+ const char EOL = '\n';
+ const int eofSym = 0; /* pdt */
+ const int maxT = 96;
+ const int noSym = 96;
+
+
+ [ContractInvariantMethod]
+ void objectInvariant(){
+ Contract.Invariant(this._buffer != null);
+ Contract.Invariant(t != null);
+ Contract.Invariant(start != null);
+ Contract.Invariant(tokens != null);
+ Contract.Invariant(pt != null);
+ Contract.Invariant(tval != null);
+ Contract.Invariant(Filename != null);
+ Contract.Invariant(errorHandler != null);
+ }
+
+ private Buffer/*!*/ _buffer; // scanner buffer
+
+ public Buffer/*!*/ buffer {
+ get {
+ Contract.Ensures(Contract.Result<Buffer>() != null);
+ return this._buffer;
+ }
+ set {
+ Contract.Requires(value != null);
+ this._buffer = value;
+ }
+ }
+
+ Token/*!*/ t; // current token
+ int ch; // current input character
+ int pos; // byte position of current character
+ int charPos;
+ int col; // column number of current character
+ int line; // line number of current character
+ int oldEols; // EOLs that appeared in a comment;
+ static readonly Hashtable/*!*/ start; // maps first token character to start state
+
+ Token/*!*/ tokens; // list of tokens already peeked (first token is a dummy)
+ Token/*!*/ pt; // current peek token
+
+ char[]/*!*/ tval = new char[128]; // text of current token
+ int tlen; // length of current token
+
+ private string/*!*/ Filename;
+ private Errors/*!*/ errorHandler;
+
+ static Scanner() {
+ start = new Hashtable(128);
+ for (int i = 35; i <= 36; ++i) start[i] = 2;
+ for (int i = 39; i <= 39; ++i) start[i] = 2;
+ for (int i = 46; i <= 46; ++i) start[i] = 2;
+ for (int i = 63; i <= 63; ++i) start[i] = 2;
+ for (int i = 65; i <= 90; ++i) start[i] = 2;
+ for (int i = 94; i <= 122; ++i) start[i] = 2;
+ for (int i = 126; i <= 126; ++i) start[i] = 2;
+ for (int i = 48; i <= 57; ++i) start[i] = 16;
+ for (int i = 34; i <= 34; ++i) start[i] = 6;
+ start[92] = 1;
+ start[59] = 19;
+ start[40] = 20;
+ start[41] = 21;
+ start[58] = 55;
+ start[44] = 22;
+ start[91] = 23;
+ start[93] = 24;
+ start[60] = 56;
+ start[62] = 57;
+ start[123] = 25;
+ start[125] = 58;
+ start[61] = 59;
+ start[42] = 60;
+ start[124] = 61;
+ start[8660] = 28;
+ start[8658] = 30;
+ start[8656] = 31;
+ start[38] = 32;
+ start[8743] = 34;
+ start[8744] = 36;
+ start[33] = 62;
+ start[8800] = 40;
+ start[8804] = 41;
+ start[8805] = 42;
+ start[43] = 63;
+ start[45] = 44;
+ start[47] = 45;
+ start[172] = 47;
+ start[8704] = 50;
+ start[8707] = 51;
+ start[955] = 52;
+ start[8226] = 54;
+ start[Buffer.EOF] = -1;
+
+ }
+
+// [NotDelayed]
+ public Scanner (string/*!*/ fileName, Errors/*!*/ errorHandler, bool useBaseName = false) : base() {
+ Contract.Requires(fileName != null);
+ Contract.Requires(errorHandler != null);
+ this.errorHandler = errorHandler;
+ pt = tokens = new Token(); // first token is a dummy
+ t = new Token(); // dummy because t is a non-null field
+ try {
+ Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
+ this._buffer = new Buffer(stream, false);
+ Filename = useBaseName? GetBaseName(fileName): fileName;
+ Init();
+ } catch (IOException) {
+ throw new FatalError("Cannot open file " + fileName);
+ }
+ }
+
+// [NotDelayed]
+ public Scanner (Stream/*!*/ s, Errors/*!*/ errorHandler, string/*!*/ fileName, bool useBaseName = false) : base() {
+ Contract.Requires(s != null);
+ Contract.Requires(errorHandler != null);
+ Contract.Requires(fileName != null);
+ pt = tokens = new Token(); // first token is a dummy
+ t = new Token(); // dummy because t is a non-null field
+ this._buffer = new Buffer(s, true);
+ this.errorHandler = errorHandler;
+ this.Filename = useBaseName? GetBaseName(fileName) : fileName;
+ Init();
+ }
+
+ string GetBaseName(string fileName) {
+ return System.IO.Path.GetFileName(fileName); // Return basename
+ }
+
+ void Init() {
+ pos = -1; line = 1; col = 0;
+ oldEols = 0;
+ NextCh();
+ if (ch == 0xEF) { // check optional byte order mark for UTF-8
+ NextCh(); int ch1 = ch;
+ NextCh(); int ch2 = ch;
+ if (ch1 != 0xBB || ch2 != 0xBF) {
+ throw new FatalError(String.Format("illegal byte order mark: EF {0,2:X} {1,2:X}", ch1, ch2));
+ }
+ buffer = new UTF8Buffer(buffer); col = 0;
+ NextCh();
+ }
+ pt = tokens = new Token(); // first token is a dummy
+ }
+
+ string/*!*/ ReadToEOL(){
+ Contract.Ensures(Contract.Result<string>() != null);
+ int p = buffer.Pos;
+ int ch = buffer.Read();
+ // replace isolated '\r' by '\n' in order to make
+ // eol handling uniform across Windows, Unix and Mac
+ if (ch == '\r' && buffer.Peek() != '\n') ch = EOL;
+ while (ch != EOL && ch != Buffer.EOF){
+ ch = buffer.Read();
+ // replace isolated '\r' by '\n' in order to make
+ // eol handling uniform across Windows, Unix and Mac
+ if (ch == '\r' && buffer.Peek() != '\n') ch = EOL;
+ }
+ string/*!*/ s = buffer.GetString(p, buffer.Pos);
+ Contract.Assert(s!=null);
+ return s;
+ }
+
+ void NextCh() {
+ if (oldEols > 0) { ch = EOL; oldEols--; }
+ else {
+// pos = buffer.Pos;
+// ch = buffer.Read(); col++;
+// // replace isolated '\r' by '\n' in order to make
+// // eol handling uniform across Windows, Unix and Mac
+// if (ch == '\r' && buffer.Peek() != '\n') ch = EOL;
+// if (ch == EOL) { line++; col = 0; }
+
+ while (true) {
+ pos = buffer.Pos;
+ ch = buffer.Read(); col++;
+ // replace isolated '\r' by '\n' in order to make
+ // eol handling uniform across Windows, Unix and Mac
+ if (ch == '\r' && buffer.Peek() != '\n') ch = EOL;
+ if (ch == EOL) {
+ line++; col = 0;
+ } else if (ch == '#' && col == 1) {
+ int prLine = line;
+ int prColumn = 0;
+
+ string/*!*/ hashLine = ReadToEOL();
+ Contract.Assert(hashLine!=null);
+ col = 0;
+ line++;
+
+ hashLine = hashLine.TrimEnd(null);
+ if (hashLine.StartsWith("line ") || hashLine == "line") {
+ // parse #line pragma: #line num [filename]
+ string h = hashLine.Substring(4).TrimStart(null);
+ int x = h.IndexOf(' ');
+ if (x == -1) {
+ x = h.Length; // this will be convenient below when we look for a filename
+ }
+ try {
+ int li = int.Parse(h.Substring(0, x));
+
+ h = h.Substring(x).Trim();
+
+ // act on #line
+ line = li;
+ if (h.Length != 0) {
+ // a filename was specified
+ Filename = h;
+ }
+ continue; // successfully parsed and acted on the #line pragma
+
+ } catch (FormatException) {
+ // just fall down through to produce an error message
+ }
+ this.errorHandler.SemErr(Filename, prLine, prColumn, "Malformed (#line num [filename]) pragma: #" + hashLine);
+ continue;
+ }
+
+ this.errorHandler.SemErr(Filename, prLine, prColumn, "Unrecognized pragma: #" + hashLine);
+ continue;
+ }
+ return;
+ }
+
+
+ }
+
+ }
+
+ void AddCh() {
+ if (tlen >= tval.Length) {
+ char[] newBuf = new char[2 * tval.Length];
+ Array.Copy(tval, 0, newBuf, 0, tval.Length);
+ tval = newBuf;
+ }
+ if (ch != Buffer.EOF) {
+ tval[tlen++] = (char) ch;
+ NextCh();
+ }
+ }
+
+
+
+ bool Comment0() {
+ int level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos;
+ NextCh();
+ if (ch == '/') {
+ NextCh();
+ for(;;) {
+ if (ch == 10) {
+ level--;
+ if (level == 0) { oldEols = line - line0; NextCh(); return true; }
+ NextCh();
+ } else if (ch == Buffer.EOF) return false;
+ else NextCh();
+ }
+ } else {
+ buffer.Pos = pos0; NextCh(); line = line0; col = col0; charPos = charPos0;
+ }
+ return false;
+ }
+
+ bool Comment1() {
+ int level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos;
+ NextCh();
+ if (ch == '*') {
+ NextCh();
+ for(;;) {
+ if (ch == '*') {
+ NextCh();
+ if (ch == '/') {
+ level--;
+ if (level == 0) { oldEols = line - line0; NextCh(); return true; }
+ NextCh();
+ }
+ } else if (ch == '/') {
+ NextCh();
+ if (ch == '*') {
+ level++; NextCh();
+ }
+ } else if (ch == Buffer.EOF) return false;
+ else NextCh();
+ }
+ } else {
+ buffer.Pos = pos0; NextCh(); line = line0; col = col0; charPos = charPos0;
+ }
+ return false;
+ }
+
+
+ void CheckLiteral() {
+ switch (t.val) {
+ case "var": t.kind = 7; break;
+ case "where": t.kind = 13; break;
+ 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": 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;
+ case "complete": t.kind = 24; break;
+ case "function": t.kind = 25; break;
+ case "returns": t.kind = 26; break;
+ case "axiom": t.kind = 29; break;
+ case "type": t.kind = 30; break;
+ case "procedure": t.kind = 32; break;
+ case "implementation": t.kind = 33; break;
+ case "modifies": t.kind = 34; break;
+ case "free": t.kind = 35; break;
+ case "requires": t.kind = 36; break;
+ case "ensures": t.kind = 37; break;
+ case "goto": t.kind = 38; break;
+ case "return": t.kind = 39; break;
+ case "if": t.kind = 40; break;
+ case "else": t.kind = 41; break;
+ case "while": t.kind = 42; break;
+ case "invariant": t.kind = 43; break;
+ case "break": t.kind = 45; break;
+ case "assert": t.kind = 46; break;
+ case "assume": t.kind = 47; break;
+ case "havoc": t.kind = 48; break;
+ case "yield": t.kind = 49; break;
+ case "async": t.kind = 51; break;
+ case "call": t.kind = 52; break;
+ case "par": t.kind = 53; break;
+ case "div": t.kind = 76; break;
+ case "mod": t.kind = 77; break;
+ case "false": t.kind = 82; break;
+ case "true": t.kind = 83; break;
+ case "old": t.kind = 84; break;
+ case "then": t.kind = 87; break;
+ case "forall": t.kind = 88; break;
+ case "exists": t.kind = 90; break;
+ case "lambda": t.kind = 92; break;
+ default: break;
+ }
+ }
+
+ Token/*!*/ NextToken() {
+ Contract.Ensures(Contract.Result<Token>() != null);
+ while (ch == ' ' ||
+ ch >= 9 && ch <= 10 || ch == 13
+ ) NextCh();
+ if (ch == '/' && Comment0() ||ch == '/' && Comment1()) return NextToken();
+ int recKind = noSym;
+ int recEnd = pos;
+ t = new Token();
+ t.pos = pos; t.col = col; t.line = line;
+ t.filename = this.Filename;
+ int state;
+ if (start.ContainsKey(ch)) {
+ Contract.Assert(start[ch] != null);
+ state = (int) start[ch];
+ }
+ else { state = 0; }
+ tlen = 0; AddCh();
+
+ switch (state) {
+ case -1: { t.kind = eofSym; break; } // NextCh already done
+ case 0: {
+ if (recKind != noSym) {
+ tlen = recEnd - t.pos;
+ SetScannerBehindT();
+ }
+ t.kind = recKind; break;
+ } // NextCh already done
+ case 1:
+ if (ch >= '#' && ch <= '$' || ch == 39 || ch == '.' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch >= '^' && ch <= 'z' || ch == '~') {AddCh(); goto case 2;}
+ else {goto case 0;}
+ case 2:
+ recEnd = pos; recKind = 1;
+ if (ch >= '#' && ch <= '$' || ch == 39 || ch == '.' || ch >= '0' && ch <= '9' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch >= '^' && ch <= 'z' || ch == '~') {AddCh(); goto case 2;}
+ else {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;}
+ case 3:
+ if (ch == 'v') {AddCh(); goto case 4;}
+ else {goto case 0;}
+ case 4:
+ if (ch >= '0' && ch <= '9') {AddCh(); goto case 5;}
+ else {goto case 0;}
+ case 5:
+ recEnd = pos; recKind = 2;
+ if (ch >= '0' && ch <= '9') {AddCh(); goto case 5;}
+ else {t.kind = 2; break;}
+ case 6:
+ if (ch == '"') {AddCh(); goto case 7;}
+ else if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); goto case 6;}
+ else if (ch == 92) {AddCh(); goto case 17;}
+ else {goto case 0;}
+ case 7:
+ {t.kind = 4; break;}
+ case 8:
+ if (ch >= '0' && ch <= '9') {AddCh(); goto case 10;}
+ else if (ch == '-') {AddCh(); goto case 9;}
+ else {goto case 0;}
+ case 9:
+ if (ch >= '0' && ch <= '9') {AddCh(); goto case 10;}
+ else {goto case 0;}
+ case 10:
+ recEnd = pos; recKind = 5;
+ if (ch >= '0' && ch <= '9') {AddCh(); goto case 10;}
+ else {t.kind = 5; break;}
+ case 11:
+ if (ch >= '0' && ch <= '9') {AddCh(); goto case 12;}
+ else {goto case 0;}
+ case 12:
+ recEnd = pos; recKind = 6;
+ if (ch >= '0' && ch <= '9') {AddCh(); goto case 12;}
+ else if (ch == 'e') {AddCh(); goto case 13;}
+ else {t.kind = 6; break;}
+ case 13:
+ if (ch >= '0' && ch <= '9') {AddCh(); goto case 15;}
+ else if (ch == '-') {AddCh(); goto case 14;}
+ else {goto case 0;}
+ case 14:
+ if (ch >= '0' && ch <= '9') {AddCh(); goto case 15;}
+ else {goto case 0;}
+ case 15:
+ recEnd = pos; recKind = 6;
+ if (ch >= '0' && ch <= '9') {AddCh(); goto case 15;}
+ else {t.kind = 6; break;}
+ case 16:
+ recEnd = pos; recKind = 3;
+ if (ch >= '0' && ch <= '9') {AddCh(); goto case 16;}
+ else if (ch == 'b') {AddCh(); goto case 3;}
+ else if (ch == 'e') {AddCh(); goto case 8;}
+ else if (ch == '.') {AddCh(); goto case 11;}
+ else {t.kind = 3; break;}
+ case 17:
+ if (ch == '"') {AddCh(); goto case 18;}
+ else if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); goto case 6;}
+ else if (ch == 92) {AddCh(); goto case 17;}
+ else {goto case 0;}
+ case 18:
+ recEnd = pos; recKind = 4;
+ if (ch == '"') {AddCh(); goto case 7;}
+ else if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); goto case 6;}
+ else if (ch == 92) {AddCh(); goto case 17;}
+ else {t.kind = 4; break;}
+ case 19:
+ {t.kind = 8; break;}
+ case 20:
+ {t.kind = 9; break;}
+ case 21:
+ {t.kind = 10; break;}
+ case 22:
+ {t.kind = 12; break;}
+ case 23:
+ {t.kind = 17; break;}
+ case 24:
+ {t.kind = 18; break;}
+ case 25:
+ {t.kind = 27; break;}
+ case 26:
+ {t.kind = 50; break;}
+ case 27:
+ {t.kind = 55; break;}
+ case 28:
+ {t.kind = 56; break;}
+ case 29:
+ {t.kind = 57; break;}
+ case 30:
+ {t.kind = 58; break;}
+ case 31:
+ {t.kind = 60; break;}
+ case 32:
+ if (ch == '&') {AddCh(); goto case 33;}
+ else {goto case 0;}
+ case 33:
+ {t.kind = 61; break;}
+ case 34:
+ {t.kind = 62; break;}
+ case 35:
+ {t.kind = 63; break;}
+ case 36:
+ {t.kind = 64; break;}
+ case 37:
+ {t.kind = 67; break;}
+ case 38:
+ {t.kind = 68; break;}
+ case 39:
+ {t.kind = 69; break;}
+ case 40:
+ {t.kind = 70; break;}
+ case 41:
+ {t.kind = 71; break;}
+ case 42:
+ {t.kind = 72; break;}
+ case 43:
+ {t.kind = 73; break;}
+ case 44:
+ {t.kind = 75; break;}
+ case 45:
+ {t.kind = 78; break;}
+ case 46:
+ {t.kind = 79; break;}
+ case 47:
+ {t.kind = 81; break;}
+ case 48:
+ {t.kind = 85; break;}
+ case 49:
+ {t.kind = 86; break;}
+ case 50:
+ {t.kind = 89; break;}
+ case 51:
+ {t.kind = 91; break;}
+ case 52:
+ {t.kind = 93; break;}
+ case 53:
+ {t.kind = 94; break;}
+ case 54:
+ {t.kind = 95; break;}
+ case 55:
+ recEnd = pos; recKind = 11;
+ if (ch == '=') {AddCh(); goto case 26;}
+ else if (ch == ':') {AddCh(); goto case 53;}
+ else {t.kind = 11; break;}
+ case 56:
+ recEnd = pos; recKind = 19;
+ if (ch == '=') {AddCh(); goto case 64;}
+ else if (ch == ':') {AddCh(); goto case 39;}
+ else {t.kind = 19; break;}
+ case 57:
+ recEnd = pos; recKind = 20;
+ if (ch == '=') {AddCh(); goto case 37;}
+ else {t.kind = 20; break;}
+ case 58:
+ recEnd = pos; recKind = 28;
+ if (ch == '|') {AddCh(); goto case 49;}
+ else {t.kind = 28; break;}
+ case 59:
+ recEnd = pos; recKind = 31;
+ if (ch == '=') {AddCh(); goto case 65;}
+ else {t.kind = 31; break;}
+ case 60:
+ recEnd = pos; recKind = 44;
+ if (ch == '*') {AddCh(); goto case 46;}
+ else {t.kind = 44; break;}
+ case 61:
+ recEnd = pos; recKind = 54;
+ if (ch == '|') {AddCh(); goto case 35;}
+ else if (ch == '{') {AddCh(); goto case 48;}
+ else {t.kind = 54; break;}
+ case 62:
+ recEnd = pos; recKind = 80;
+ if (ch == '=') {AddCh(); goto case 38;}
+ else {t.kind = 80; break;}
+ case 63:
+ recEnd = pos; recKind = 74;
+ if (ch == '+') {AddCh(); goto case 43;}
+ else {t.kind = 74; break;}
+ case 64:
+ recEnd = pos; recKind = 66;
+ if (ch == '=') {AddCh(); goto case 66;}
+ else {t.kind = 66; break;}
+ case 65:
+ recEnd = pos; recKind = 65;
+ if (ch == '>') {AddCh(); goto case 29;}
+ else {t.kind = 65; break;}
+ case 66:
+ recEnd = pos; recKind = 59;
+ if (ch == '>') {AddCh(); goto case 27;}
+ else {t.kind = 59; break;}
+
+ }
+ t.val = new String(tval, 0, tlen);
+ return t;
+ }
+
+ private void SetScannerBehindT() {
+ buffer.Pos = t.pos;
+ NextCh();
+ line = t.line; col = t.col;
+ for (int i = 0; i < tlen; i++) NextCh();
+ }
+
+ // get the next token (possibly a token already seen during peeking)
+ public Token/*!*/ Scan () {
+ Contract.Ensures(Contract.Result<Token>() != null);
+ if (tokens.next == null) {
+ return NextToken();
+ } else {
+ pt = tokens = tokens.next;
+ return tokens;
+ }
+ }
+
+ // peek for the next token, ignore pragmas
+ public Token/*!*/ Peek () {
+ Contract.Ensures(Contract.Result<Token>() != null);
+ do {
+ if (pt.next == null) {
+ pt.next = NextToken();
+ }
+ pt = pt.next;
+ } while (pt.kind > maxT); // skip pragmas
+
+ return pt;
+ }
+
+ // make sure that peeking starts at the current scan position
+ public void ResetPeek () { pt = tokens; }
+
+} // end Scanner
+
+public delegate void ErrorProc(int n, string filename, int line, int col);
+
+
} \ No newline at end of file
diff --git a/Source/Core/StandardVisitor.cs b/Source/Core/StandardVisitor.cs
index 97215cfb..c3d8a672 100644
--- a/Source/Core/StandardVisitor.cs
+++ b/Source/Core/StandardVisitor.cs
@@ -1,1167 +1,1167 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-//---------------------------------------------------------------------------------------------
-// BoogiePL - StandardVisitor.cs
-//---------------------------------------------------------------------------------------------
-
-using System.Collections.Generic;
-using System.Diagnostics.Contracts;
-using System.Linq;
-
-namespace Microsoft.Boogie {
- [ContractClass(typeof(VisitorContracts))]
- /// <summary>
- /// Base for all classes that process the Absy using the visitor pattern.
- /// </summary>
- public abstract class Visitor {
- /// <summary>
- /// Switches on node.NodeType to call a visitor method that has been specialized for node.
- /// </summary>
- /// <param name="a">The Absy node to be visited.</param>
- /// <returns> Returns null if node is null. Otherwise returns an updated node (possibly a different object).</returns>
- public abstract Absy/*!*/ Visit(Absy/*!*/ node);
-
- /// <summary>
- /// Transfers the state from one visitor to another. This enables separate visitor instances to cooperative process a single IR.
- /// </summary>
- public virtual void TransferStateTo(Visitor targetVisitor) {
- }
-
- public virtual IList<Expr> VisitExprSeq(IList<Expr> list) {
- Contract.Requires(list != null);
- Contract.Ensures(Contract.Result<IList<Expr>>() != null);
- lock (list)
- {
- for (int i = 0, n = list.Count; i < n; i++)
- list[i] = (Expr)this.Visit(cce.NonNull(list[i]));
- }
- return list;
- }
- }
- [ContractClassFor(typeof(Visitor))]
- abstract class VisitorContracts : Visitor {
- public override Absy Visit(Absy node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Absy>() != null);
-
- throw new System.NotImplementedException();
- }
- }
-
- /// <summary>
- /// Walks an IR, mutating it into a new form. (For a subclass that does not mutate the IR, see ReadOnlyVisitor.)
- /// </summary>
- public abstract class StandardVisitor : Visitor {
- public Visitor callingVisitor;
-
- public StandardVisitor() {
- }
- public StandardVisitor(Visitor callingVisitor) {
- this.callingVisitor = callingVisitor;
- }
- public override Absy Visit(Absy node) {
- return node.StdDispatch(this);
- }
- public virtual Cmd VisitAssertCmd(AssertCmd node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- node.Expr = this.VisitExpr(node.Expr);
- return node;
- }
- public virtual Cmd VisitAssignCmd(AssignCmd node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- for (int i = 0; i < node.Lhss.Count; ++i) {
- node.SetLhs(i, cce.NonNull((AssignLhs)this.Visit(node.Lhss[i])));
- node.SetRhs(i, cce.NonNull((Expr/*!*/)this.Visit(node.Rhss[i])));
- }
- return node;
- }
- public virtual Cmd VisitAssumeCmd(AssumeCmd node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- node.Expr = this.VisitExpr(node.Expr);
- return node;
- }
- public virtual AtomicRE VisitAtomicRE(AtomicRE node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<AtomicRE>() != null);
- node.b = this.VisitBlock(node.b);
- return node;
- }
- public virtual Axiom VisitAxiom(Axiom node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Axiom>() != null);
- node.Expr = this.VisitExpr(node.Expr);
- return node;
- }
- public virtual Type VisitBasicType(BasicType node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- return this.VisitType(node);
- }
- public virtual Type VisitFloatType(FloatType node)
- {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- return this.VisitType(node);
- }
- public virtual Expr VisitBvConcatExpr(BvConcatExpr node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- node.E0 = this.VisitExpr(node.E0);
- node.E1 = this.VisitExpr(node.E1);
- return node;
- }
- public virtual Type VisitBvType(BvType node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- return this.VisitType(node);
- }
- public virtual Type VisitBvTypeProxy(BvTypeProxy node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- // if the type proxy is instantiated with some more
- // specific type, we visit the instantiation
- if (node.ProxyFor != null)
- return (Type)this.Visit(node.ProxyFor);
- return this.VisitType(node);
- }
- public virtual Block VisitBlock(Block node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Block>() != null);
- node.Cmds = this.VisitCmdSeq(node.Cmds);
- node.TransferCmd = (TransferCmd)this.Visit(cce.NonNull(node.TransferCmd));
- return node;
- }
- public virtual Expr VisitCodeExpr(CodeExpr node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- node.LocVars = this.VisitVariableSeq(node.LocVars);
- node.Blocks = this.VisitBlockList(node.Blocks);
- return node;
- }
- public virtual List<Block> VisitBlockSeq(List<Block> blockSeq) {
- Contract.Requires(blockSeq != null);
- Contract.Ensures(Contract.Result<List<Block>>() != null);
- lock (blockSeq)
- {
- for (int i = 0, n = blockSeq.Count; i < n; i++)
- blockSeq[i] = this.VisitBlock(cce.NonNull(blockSeq[i]));
- }
- return blockSeq;
- }
- public virtual List<Block/*!*/>/*!*/ VisitBlockList(List<Block/*!*/>/*!*/ blocks) {
- Contract.Requires(blocks != null);
- Contract.Ensures(Contract.Result<List<Block>>() != null);
- for (int i = 0, n = blocks.Count; i < n; i++) {
- blocks[i] = this.VisitBlock(blocks[i]);
- }
- return blocks;
- }
- public virtual BoundVariable VisitBoundVariable(BoundVariable node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<BoundVariable>() != null);
- node = (BoundVariable)this.VisitVariable(node);
- return node;
- }
- public virtual Cmd VisitCallCmd(CallCmd node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- for (int i = 0; i < node.Ins.Count; ++i)
- if (node.Ins[i] != null)
- node.Ins[i] = this.VisitExpr(cce.NonNull(node.Ins[i]));
- for (int i = 0; i < node.Outs.Count; ++i)
- if (node.Outs[i] != null)
- node.Outs[i] = (IdentifierExpr)this.VisitIdentifierExpr(cce.NonNull(node.Outs[i]));
- return node;
- }
- public virtual Cmd VisitParCallCmd(ParCallCmd node)
- {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- for (int i = 0; i < node.CallCmds.Count; i++)
- {
- if (node.CallCmds[i] != null)
- node.CallCmds[i] = (CallCmd)this.VisitCallCmd(node.CallCmds[i]);
- }
- return node;
- }
- public virtual List<Cmd> VisitCmdSeq(List<Cmd> cmdSeq) {
- Contract.Requires(cmdSeq != null);
- Contract.Ensures(Contract.Result<List<Cmd>>() != null);
- lock (cmdSeq)
- {
- for (int i = 0, n = cmdSeq.Count; i < n; i++)
- cmdSeq[i] = (Cmd)this.Visit(cce.NonNull(cmdSeq[i])); // call general Visit so subtypes of Cmd get visited by their particular visitor
- }
- return cmdSeq;
- }
- public virtual Choice VisitChoice(Choice node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Choice>() != null);
- node.rs = this.VisitRESeq(node.rs);
- return node;
- }
- public virtual Cmd VisitCommentCmd(CommentCmd node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- return node;
- }
- public virtual Constant VisitConstant(Constant node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Constant>() != null);
- return node;
- }
- public virtual CtorType VisitCtorType(CtorType node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<CtorType>() != null);
- lock (node)
- {
- for (int i = 0; i < node.Arguments.Count; ++i)
- node.Arguments[i] = cce.NonNull((Type/*!*/)this.Visit(node.Arguments[i]));
- }
- return node;
- }
- public virtual Declaration VisitDeclaration(Declaration node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Declaration>() != null);
- return node;
- }
- public virtual List<Declaration/*!*/>/*!*/ VisitDeclarationList(List<Declaration/*!*/>/*!*/ declarationList) {
- Contract.Requires(declarationList != null);
- Contract.Ensures(Contract.Result<List<Declaration>>() != null);
- for (int i = 0, n = declarationList.Count; i < n; i++)
- declarationList[i] = cce.NonNull((Declaration/*!*/)this.Visit(declarationList[i]));
- return declarationList;
- }
- public virtual DeclWithFormals VisitDeclWithFormals(DeclWithFormals node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<DeclWithFormals>() != null);
- node.InParams = this.VisitVariableSeq(node.InParams);
- node.OutParams = this.VisitVariableSeq(node.OutParams);
- return node;
- }
- public virtual Expr VisitExistsExpr(ExistsExpr node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- node = (ExistsExpr)this.VisitQuantifierExpr(node);
- return node;
- }
- public virtual Expr VisitBvExtractExpr(BvExtractExpr node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- node.Bitvector = this.VisitExpr(node.Bitvector);
- return node;
- }
- public virtual Expr VisitExpr(Expr node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- Expr e = (Expr)this.Visit(node);
- return e;
- }
- public override IList<Expr> VisitExprSeq(IList<Expr> exprSeq) {
- //Contract.Requires(exprSeq != null);
- Contract.Ensures(Contract.Result<IList<Expr>>() != null);
- for (int i = 0, n = exprSeq.Count; i < n; i++)
- exprSeq[i] = this.VisitExpr(cce.NonNull(exprSeq[i]));
- return exprSeq;
- }
- public virtual Requires VisitRequires(Requires @requires) {
- Contract.Requires(@requires != null);
- Contract.Ensures(Contract.Result<Requires>() != null);
- @requires.Condition = this.VisitExpr(@requires.Condition);
- return @requires;
- }
- public virtual List<Requires> VisitRequiresSeq(List<Requires> requiresSeq) {
- Contract.Requires(requiresSeq != null);
- Contract.Ensures(Contract.Result<List<Requires>>() != null);
- for (int i = 0, n = requiresSeq.Count; i < n; i++)
- requiresSeq[i] = this.VisitRequires(requiresSeq[i]);
- return requiresSeq;
- }
- public virtual Ensures VisitEnsures(Ensures @ensures) {
- Contract.Requires(@ensures != null);
- Contract.Ensures(Contract.Result<Ensures>() != null);
- @ensures.Condition = this.VisitExpr(@ensures.Condition);
- return @ensures;
- }
- public virtual List<Ensures> VisitEnsuresSeq(List<Ensures> ensuresSeq) {
- Contract.Requires(ensuresSeq != null);
- Contract.Ensures(Contract.Result<List<Ensures>>() != null);
- for (int i = 0, n = ensuresSeq.Count; i < n; i++)
- ensuresSeq[i] = this.VisitEnsures(ensuresSeq[i]);
- return ensuresSeq;
- }
- public virtual Expr VisitForallExpr(ForallExpr node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- node = (ForallExpr)this.VisitQuantifierExpr(node);
- return node;
- }
- public virtual Expr VisitLambdaExpr(LambdaExpr node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- node = (LambdaExpr)this.VisitBinderExpr(node);
- return node;
- }
- public virtual Formal VisitFormal(Formal node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Formal>() != null);
- return node;
- }
- public virtual Function VisitFunction(Function node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Function>() != null);
- node = (Function)this.VisitDeclWithFormals(node);
- if (node.Body != null)
- node.Body = this.VisitExpr(node.Body);
- return node;
- }
- public virtual GlobalVariable VisitGlobalVariable(GlobalVariable node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<GlobalVariable>() != null);
- node = (GlobalVariable)this.VisitVariable(node);
- return node;
- }
- public virtual GotoCmd VisitGotoCmd(GotoCmd node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<GotoCmd>() != null);
- // do not visit the labelTargets, or control-flow loops will lead to a looping visitor
- return node;
- }
- public virtual Cmd VisitHavocCmd(HavocCmd node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- node.Vars = this.VisitIdentifierExprSeq(node.Vars);
- return node;
- }
- public virtual Expr VisitIdentifierExpr(IdentifierExpr node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- if (node.Decl != null)
- node.Decl = this.VisitVariable(node.Decl);
- return node;
- }
- public virtual List<IdentifierExpr> VisitIdentifierExprSeq(List<IdentifierExpr> identifierExprSeq) {
- Contract.Requires(identifierExprSeq != null);
- Contract.Ensures(Contract.Result<List<IdentifierExpr>>() != null);
- lock (identifierExprSeq)
- {
- for (int i = 0, n = identifierExprSeq.Count; i < n; i++)
- identifierExprSeq[i] = (IdentifierExpr)this.VisitIdentifierExpr(cce.NonNull(identifierExprSeq[i]));
- }
- return identifierExprSeq;
- }
- public virtual Implementation VisitImplementation(Implementation node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Implementation>() != null);
- node.LocVars = this.VisitVariableSeq(node.LocVars);
- node.Blocks = this.VisitBlockList(node.Blocks);
- node.Proc = this.VisitProcedure(cce.NonNull(node.Proc));
- node = (Implementation)this.VisitDeclWithFormals(node); // do this first or last?
- return node;
- }
- public virtual Expr VisitLiteralExpr(LiteralExpr node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- return node;
- }
-
- public virtual LocalVariable VisitLocalVariable(LocalVariable node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<LocalVariable>() != null);
- return node;
- }
-
- public virtual AssignLhs VisitMapAssignLhs(MapAssignLhs node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<AssignLhs>() != null);
- node.Map = cce.NonNull((AssignLhs)this.Visit(node.Map));
- for (int i = 0; i < node.Indexes.Count; ++i)
- node.Indexes[i] = cce.NonNull((Expr)this.Visit(node.Indexes[i]));
- return node;
- }
- public virtual MapType VisitMapType(MapType node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<MapType>() != null);
- // not doing anything about the bound variables ... maybe
- // these should be visited as well ...
- //
- // NOTE: when overriding this method, you have to make sure that
- // the bound variables of the map type are updated correctly
- lock (node.Arguments)
- {
- for (int i = 0; i < node.Arguments.Count; ++i)
- node.Arguments[i] = cce.NonNull((Type/*!*/)this.Visit(node.Arguments[i]));
- }
- node.Result = cce.NonNull((Type/*!*/)this.Visit(node.Result));
- return node;
- }
- public virtual Type VisitMapTypeProxy(MapTypeProxy node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- // if the type proxy is instantiated with some more
- // specific type, we visit the instantiation
- if (node.ProxyFor != null)
- return (Type)this.Visit(node.ProxyFor);
- return this.VisitType(node);
- }
-
- public virtual Expr VisitNAryExpr(NAryExpr node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- node.Args = this.VisitExprSeq(node.Args);
- return node;
- }
- public virtual Expr VisitOldExpr(OldExpr node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- node.Expr = this.VisitExpr(node.Expr);
- return node;
- }
- public virtual Procedure VisitProcedure(Procedure node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Procedure>() != null);
- node.Ensures = this.VisitEnsuresSeq(node.Ensures);
- node.InParams = this.VisitVariableSeq(node.InParams);
- node.Modifies = this.VisitIdentifierExprSeq(node.Modifies);
- node.OutParams = this.VisitVariableSeq(node.OutParams);
- node.Requires = this.VisitRequiresSeq(node.Requires);
- return node;
- }
- public virtual Program VisitProgram(Program node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Program>() != null);
- var decls = node.TopLevelDeclarations.ToList();
- node.ClearTopLevelDeclarations();
- node.AddTopLevelDeclarations(this.VisitDeclarationList(decls));
- return node;
- }
- public virtual QKeyValue VisitQKeyValue(QKeyValue node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<QKeyValue>() != null);
- var newParams = new List<object>();
- for (int i = 0, n = node.Params.Count; i < n; i++) {
- var e = node.Params[i] as Expr;
- newParams.Add(e != null ? this.Visit(e) : node.Params[i]);
- }
- node.ClearParams();
- node.AddParams(newParams);
- if (node.Next != null) {
- node.Next = (QKeyValue)this.Visit(node.Next);
- }
- return node;
- }
- public virtual BinderExpr VisitBinderExpr(BinderExpr node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<BinderExpr>() != null);
- node.Body = this.VisitExpr(node.Body);
- node.Dummies = this.VisitVariableSeq(node.Dummies);
- //node.Type = this.VisitType(node.Type);
- return node;
- }
- public virtual QuantifierExpr VisitQuantifierExpr(QuantifierExpr node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<QuantifierExpr>() != null);
- node = cce.NonNull((QuantifierExpr)this.VisitBinderExpr(node));
- if (node.Triggers != null) {
- node.Triggers = this.VisitTrigger(node.Triggers);
- }
- return node;
- }
- public virtual Cmd VisitRE(RE node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- return (Cmd)this.Visit(node); // Call general visit so subtypes get visited by their particular visitor
- }
- public virtual List<RE> VisitRESeq(List<RE> reSeq) {
- Contract.Requires(reSeq != null);
- Contract.Ensures(Contract.Result<List<RE>>() != null);
- for (int i = 0, n = reSeq.Count; i < n; i++)
- reSeq[i] = (RE)this.VisitRE(cce.NonNull(reSeq[i]));
- return reSeq;
- }
- public virtual ReturnCmd VisitReturnCmd(ReturnCmd node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<ReturnCmd>() != null);
- return (ReturnCmd)this.VisitTransferCmd(node);
- }
- public virtual ReturnExprCmd VisitReturnExprCmd(ReturnExprCmd node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<ReturnExprCmd>() != null);
- node.Expr = this.VisitExpr(node.Expr);
- return node;
- }
- public virtual Sequential VisitSequential(Sequential node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Sequential>() != null);
- node.first = (RE)this.VisitRE(node.first);
- node.second = (RE)this.VisitRE(node.second);
- return node;
- }
- public virtual AssignLhs VisitSimpleAssignLhs(SimpleAssignLhs node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<AssignLhs>() != null);
- node.AssignedVariable =
- (IdentifierExpr)this.VisitIdentifierExpr(node.AssignedVariable);
- return node;
- }
- public virtual Cmd VisitStateCmd(StateCmd node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- node.Locals = this.VisitVariableSeq(node.Locals);
- node.Cmds = this.VisitCmdSeq(node.Cmds);
- return node;
- }
- public virtual TransferCmd VisitTransferCmd(TransferCmd node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<TransferCmd>() != null);
- return node;
- }
- public virtual Trigger VisitTrigger(Trigger node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Trigger>() != null);
- Trigger origNext = node.Next;
- if (origNext != null) {
- Trigger newNext = this.VisitTrigger(origNext);
- if (newNext != origNext) {
- node = new Trigger(node.tok, node.Pos, node.Tr.ToList());
- node.Next = newNext;
- }
- }
- node.Tr = this.VisitExprSeq(node.Tr.ToList());
- return node;
- }
- // called by default for all nullary type constructors and type variables
- public virtual Type VisitType(Type node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- return node;
- }
- public virtual TypedIdent VisitTypedIdent(TypedIdent node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<TypedIdent>() != null);
- node.Type = (Type)this.Visit(node.Type);
- return node;
- }
- public virtual Declaration VisitTypeCtorDecl(TypeCtorDecl node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Declaration>() != null);
- return this.VisitDeclaration(node);
- }
- public virtual Type VisitTypeSynonymAnnotation(TypeSynonymAnnotation node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- node.ExpandedType = cce.NonNull((Type/*!*/)this.Visit(node.ExpandedType));
- lock (node.Arguments)
- {
- for (int i = 0; i < node.Arguments.Count; ++i)
- node.Arguments[i] = cce.NonNull((Type/*!*/)this.Visit(node.Arguments[i]));
- }
- return node;
- }
- public virtual Declaration VisitTypeSynonymDecl(TypeSynonymDecl node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Declaration>() != null);
- return this.VisitDeclaration(node);
- }
- public virtual Type VisitTypeVariable(TypeVariable node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- return this.VisitType(node);
- }
- public virtual Type VisitTypeProxy(TypeProxy node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- // if the type proxy is instantiated with some more
- // specific type, we visit the instantiation
- if (node.ProxyFor != null)
- return cce.NonNull((Type/*!*/)this.Visit(node.ProxyFor));
- return this.VisitType(node);
- }
- public virtual Type VisitUnresolvedTypeIdentifier(UnresolvedTypeIdentifier node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- return this.VisitType(node);
- }
- public virtual Variable VisitVariable(Variable node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Variable>() != null);
- node.TypedIdent = this.VisitTypedIdent(node.TypedIdent);
- return node;
- }
- public virtual List<Variable> VisitVariableSeq(List<Variable> variableSeq) {
- Contract.Requires(variableSeq != null);
- Contract.Ensures(Contract.Result<List<Variable>>() != null);
- lock (variableSeq)
- {
- for (int i = 0, n = variableSeq.Count; i < n; i++)
- variableSeq[i] = this.VisitVariable(cce.NonNull(variableSeq[i]));
- }
- return variableSeq;
- }
- public virtual YieldCmd VisitYieldCmd(YieldCmd node)
- {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<YieldCmd>() != null);
- return node;
- }
- public virtual Cmd VisitAssertEnsuresCmd(AssertEnsuresCmd node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- node.Ensures = this.VisitEnsures(node.Ensures);
- node.Expr = this.VisitExpr(node.Expr);
- return node;
- }
- public virtual Cmd VisitAssertRequiresCmd(AssertRequiresCmd node) {
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Cmd>() != null);
- node.Requires = this.VisitRequires(node.Requires);
- node.Expr = this.VisitExpr(node.Expr);
- return node;
- }
- }
-
- /// <summary>
- /// A ReadOnlyVisitor visits all the nodes of a given Absy. The visitor may collect information from
- /// the nodes, may change fields contained in the data structure, but may not replace any nodes in the
- /// data structure. To enforce this, all Visit...(node) methods have a postcondition that says that
- /// the return value is equal to the given "node".
- /// </summary>
- public abstract class ReadOnlyVisitor : StandardVisitor
- {
- public ReadOnlyVisitor()
- {
- }
- public ReadOnlyVisitor(Visitor callingVisitor)
- {
- this.callingVisitor = callingVisitor;
- }
- public override Absy Visit(Absy node)
- {
- Contract.Ensures(Contract.Result<Absy>() == node);
- return node.StdDispatch(this);
- }
- public override Cmd VisitAssertCmd(AssertCmd node)
- {
- Contract.Ensures(Contract.Result<Cmd>() == node);
- this.VisitExpr(node.Expr);
- return node;
- }
- public override Cmd VisitAssignCmd(AssignCmd node)
- {
- Contract.Ensures(Contract.Result<Cmd>() == node);
- for (int i = 0; i < node.Lhss.Count; ++i)
- {
- this.Visit(node.Lhss[i]);
- this.Visit(node.Rhss[i]);
- }
- return node;
- }
- public override Cmd VisitAssumeCmd(AssumeCmd node)
- {
- Contract.Ensures(Contract.Result<Cmd>() == node);
- this.VisitExpr(node.Expr);
- return node;
- }
- public override AtomicRE VisitAtomicRE(AtomicRE node)
- {
- Contract.Ensures(Contract.Result<AtomicRE>() == node);
- this.VisitBlock(node.b);
- return node;
- }
- public override Axiom VisitAxiom(Axiom node)
- {
- Contract.Ensures(Contract.Result<Axiom>() == node);
- this.VisitExpr(node.Expr);
- return node;
- }
- public override Type VisitBasicType(BasicType node)
- {
- Contract.Ensures(Contract.Result<Type>() == node);
- return this.VisitType(node);
- }
- public override Expr VisitBvConcatExpr(BvConcatExpr node)
- {
- Contract.Ensures(Contract.Result<Expr>() == node);
- this.VisitExpr(node.E0);
- this.VisitExpr(node.E1);
- return node;
- }
- public override Type VisitBvType(BvType node)
- {
- Contract.Ensures(Contract.Result<Type>() == node);
- return this.VisitType(node);
- }
- public override Type VisitBvTypeProxy(BvTypeProxy node)
- {
- Contract.Ensures(Contract.Result<Type>() == node);
- // if the type proxy is instantiated with some more
- // specific type, we visit the instantiation
- if (node.ProxyFor != null)
- this.Visit(node.ProxyFor);
- return this.VisitType(node);
- }
- public override Block VisitBlock(Block node)
- {
- Contract.Ensures(Contract.Result<Block>() == node);
- this.VisitCmdSeq(node.Cmds);
- this.Visit(cce.NonNull(node.TransferCmd));
- return node;
- }
- public override Expr VisitCodeExpr(CodeExpr node)
- {
- Contract.Ensures(Contract.Result<Expr>() == node);
- this.VisitVariableSeq(node.LocVars);
- this.VisitBlockList(node.Blocks);
- return node;
- }
- public override List<Block> VisitBlockSeq(List<Block> blockSeq)
- {
- Contract.Ensures(Contract.Result<List<Block>>() == blockSeq);
- for (int i = 0, n = blockSeq.Count; i < n; i++)
- this.VisitBlock(cce.NonNull(blockSeq[i]));
- return blockSeq;
- }
- public override List<Block/*!*/>/*!*/ VisitBlockList(List<Block/*!*/>/*!*/ blocks)
- {
- Contract.Ensures(Contract.Result<List<Block>>() == blocks);
- for (int i = 0, n = blocks.Count; i < n; i++)
- {
- this.VisitBlock(blocks[i]);
- }
- return blocks;
- }
- public override BoundVariable VisitBoundVariable(BoundVariable node)
- {
- Contract.Ensures(Contract.Result<BoundVariable>() == node);
- return (BoundVariable)this.VisitVariable(node);
- }
- public override Cmd VisitCallCmd(CallCmd node)
- {
- Contract.Ensures(Contract.Result<Cmd>() == node);
- for (int i = 0; i < node.Ins.Count; ++i)
- if (node.Ins[i] != null)
- this.VisitExpr(node.Ins[i]);
- for (int i = 0; i < node.Outs.Count; ++i)
- if (node.Outs[i] != null)
- this.VisitIdentifierExpr(node.Outs[i]);
- return node;
- }
- public override Cmd VisitParCallCmd(ParCallCmd node)
- {
- Contract.Ensures(Contract.Result<Cmd>() == node);
- for (int i = 0; i < node.CallCmds.Count; i++)
- {
- if (node.CallCmds[i] != null)
- this.VisitCallCmd(node.CallCmds[i]);
- }
- return node;
- }
- public override List<Cmd> VisitCmdSeq(List<Cmd> cmdSeq)
- {
- Contract.Ensures(Contract.Result<List<Cmd>>() == cmdSeq);
- for (int i = 0, n = cmdSeq.Count; i < n; i++)
- this.Visit(cce.NonNull(cmdSeq[i])); // call general Visit so subtypes of Cmd get visited by their particular visitor
- return cmdSeq;
- }
- public override Choice VisitChoice(Choice node)
- {
- Contract.Ensures(Contract.Result<Choice>() == node);
- this.VisitRESeq(node.rs);
- return node;
- }
- public override Cmd VisitCommentCmd(CommentCmd node)
- {
- Contract.Ensures(Contract.Result<Cmd>() == node);
- return node;
- }
- public override Constant VisitConstant(Constant node)
- {
- Contract.Ensures(Contract.Result<Constant>() == node);
- return node;
- }
- public override CtorType VisitCtorType(CtorType node)
- {
- Contract.Ensures(Contract.Result<CtorType>() == node);
- for (int i = 0; i < node.Arguments.Count; ++i)
- this.Visit(node.Arguments[i]);
- return node;
- }
- public override Declaration VisitDeclaration(Declaration node)
- {
- Contract.Ensures(Contract.Result<Declaration>() == node);
- return node;
- }
- public override List<Declaration/*!*/>/*!*/ VisitDeclarationList(List<Declaration/*!*/>/*!*/ declarationList)
- {
- Contract.Ensures(Contract.Result<List<Declaration>>() == declarationList);
- for (int i = 0, n = declarationList.Count; i < n; i++)
- this.Visit(declarationList[i]);
- return declarationList;
- }
- public override DeclWithFormals VisitDeclWithFormals(DeclWithFormals node)
- {
- Contract.Ensures(Contract.Result<DeclWithFormals>() == node);
- this.VisitVariableSeq(node.InParams);
- this.VisitVariableSeq(node.OutParams);
- return node;
- }
- public override Expr VisitExistsExpr(ExistsExpr node)
- {
- Contract.Ensures(Contract.Result<Expr>() == node);
- return (ExistsExpr)this.VisitQuantifierExpr(node);
- }
- public override Expr VisitBvExtractExpr(BvExtractExpr node)
- {
- Contract.Ensures(Contract.Result<Expr>() == node);
- this.VisitExpr(node.Bitvector);
- return node;
- }
- public override Expr VisitExpr(Expr node)
- {
- Contract.Ensures(Contract.Result<Expr>() == node);
- return (Expr)this.Visit(node);
- }
- public override IList<Expr> VisitExprSeq(IList<Expr> exprSeq)
- {
- Contract.Ensures(Contract.Result<IList<Expr>>() == exprSeq);
- for (int i = 0, n = exprSeq.Count; i < n; i++)
- this.VisitExpr(cce.NonNull(exprSeq[i]));
- return exprSeq;
- }
- public override Requires VisitRequires(Requires requires)
- {
- Contract.Ensures(Contract.Result<Requires>() == requires);
- this.VisitExpr(requires.Condition);
- return requires;
- }
- public override List<Requires> VisitRequiresSeq(List<Requires> requiresSeq)
- {
- Contract.Ensures(Contract.Result<List<Requires>>() == requiresSeq);
- for (int i = 0, n = requiresSeq.Count; i < n; i++)
- this.VisitRequires(requiresSeq[i]);
- return requiresSeq;
- }
- public override Ensures VisitEnsures(Ensures ensures)
- {
- Contract.Ensures(Contract.Result<Ensures>() == ensures);
- this.VisitExpr(ensures.Condition);
- return ensures;
- }
- public override List<Ensures> VisitEnsuresSeq(List<Ensures> ensuresSeq)
- {
- Contract.Ensures(Contract.Result<List<Ensures>>() == ensuresSeq);
- for (int i = 0, n = ensuresSeq.Count; i < n; i++)
- this.VisitEnsures(ensuresSeq[i]);
- return ensuresSeq;
- }
- public override Expr VisitForallExpr(ForallExpr node)
- {
- Contract.Ensures(Contract.Result<Expr>() == node);
- return (ForallExpr)this.VisitQuantifierExpr(node);
- }
- public override Expr VisitLambdaExpr(LambdaExpr node) {
- Contract.Ensures(Contract.Result<Expr>() == node);
- return this.VisitBinderExpr(node);
- }
- public override Formal VisitFormal(Formal node)
- {
- Contract.Ensures(Contract.Result<Formal>() == node);
- return node;
- }
- public override Function VisitFunction(Function node)
- {
- Contract.Ensures(Contract.Result<Function>() == node);
- node = (Function)this.VisitDeclWithFormals(node);
- if (node.Body != null)
- this.VisitExpr(node.Body);
- return node;
- }
- public override GlobalVariable VisitGlobalVariable(GlobalVariable node)
- {
- Contract.Ensures(Contract.Result<GlobalVariable>() == node);
- return (GlobalVariable)this.VisitVariable(node);
- }
- public override GotoCmd VisitGotoCmd(GotoCmd node)
- {
- Contract.Ensures(Contract.Result<GotoCmd>() == node);
- // do not visit the labelTargets, or control-flow loops will lead to a looping visitor
- return node;
- }
- public override Cmd VisitHavocCmd(HavocCmd node)
- {
- Contract.Ensures(Contract.Result<Cmd>() == node);
- this.VisitIdentifierExprSeq(node.Vars);
- return node;
- }
- public override Expr VisitIdentifierExpr(IdentifierExpr node)
- {
- Contract.Ensures(Contract.Result<Expr>() == node);
- if (node.Decl != null)
- this.VisitVariable(node.Decl);
- return node;
- }
- public override List<IdentifierExpr> VisitIdentifierExprSeq(List<IdentifierExpr> identifierExprSeq)
- {
- Contract.Ensures(Contract.Result<List<IdentifierExpr>>() == identifierExprSeq);
- for (int i = 0, n = identifierExprSeq.Count; i < n; i++)
- this.VisitIdentifierExpr(cce.NonNull(identifierExprSeq[i]));
- return identifierExprSeq;
- }
- public override Implementation VisitImplementation(Implementation node)
- {
- Contract.Ensures(Contract.Result<Implementation>() == node);
- this.VisitVariableSeq(node.LocVars);
- this.VisitBlockList(node.Blocks);
- this.VisitProcedure(cce.NonNull(node.Proc));
- return (Implementation)this.VisitDeclWithFormals(node); // do this first or last?
- }
- public override Expr VisitLiteralExpr(LiteralExpr node)
- {
- Contract.Ensures(Contract.Result<Expr>() == node);
- return node;
- }
-
- public override LocalVariable VisitLocalVariable(LocalVariable node)
- {
- Contract.Ensures(Contract.Result<LocalVariable>() == node);
- return node;
- }
-
- public override AssignLhs VisitMapAssignLhs(MapAssignLhs node)
- {
- Contract.Ensures(Contract.Result<AssignLhs>() == node);
- this.Visit(node.Map);
- for (int i = 0; i < node.Indexes.Count; ++i)
- this.Visit(node.Indexes[i]);
- return node;
- }
- public override MapType VisitMapType(MapType node)
- {
- Contract.Ensures(Contract.Result<MapType>() == node);
- // not doing anything about the bound variables ... maybe
- // these should be visited as well ...
- //
- // NOTE: when overriding this method, you have to make sure that
- // the bound variables of the map type are updated correctly
- for (int i = 0; i < node.Arguments.Count; ++i)
- this.Visit(node.Arguments[i]);
- this.Visit(node.Result);
- return node;
- }
- public override Type VisitMapTypeProxy(MapTypeProxy node)
- {
- Contract.Ensures(Contract.Result<Type>() == node);
- // if the type proxy is instantiated with some more
- // specific type, we visit the instantiation
- if (node.ProxyFor != null)
- this.Visit(node.ProxyFor);
- return this.VisitType(node);
- }
-
- public override Expr VisitNAryExpr(NAryExpr node)
- {
- Contract.Ensures(Contract.Result<Expr>() == node);
- this.VisitExprSeq(node.Args);
- return node;
- }
- public override Expr VisitOldExpr(OldExpr node)
- {
- Contract.Ensures(Contract.Result<Expr>() == node);
- this.VisitExpr(node.Expr);
- return node;
- }
- public override Procedure VisitProcedure(Procedure node)
- {
- Contract.Ensures(Contract.Result<Procedure>() == node);
- this.VisitEnsuresSeq(node.Ensures);
- this.VisitVariableSeq(node.InParams);
- this.VisitIdentifierExprSeq(node.Modifies);
- this.VisitVariableSeq(node.OutParams);
- this.VisitRequiresSeq(node.Requires);
- return node;
- }
- public override Program VisitProgram(Program node)
- {
- Contract.Ensures(Contract.Result<Program>() == node);
- this.VisitDeclarationList(node.TopLevelDeclarations.ToList());
- return node;
- }
- public override QKeyValue VisitQKeyValue(QKeyValue node) {
- Contract.Ensures(Contract.Result<QKeyValue>() == node);
- for (int i = 0, n = node.Params.Count; i < n; i++) {
- var e = node.Params[i] as Expr;
- if (e != null) {
- this.Visit(e);
- }
- }
- if (node.Next != null) {
- this.Visit(node.Next);
- }
- return node;
- }
- public override BinderExpr VisitBinderExpr(BinderExpr node)
- {
- Contract.Ensures(Contract.Result<BinderExpr>() == node);
- this.VisitExpr(node.Body);
- this.VisitVariableSeq(node.Dummies);
- // this.VisitType(node.Type);
- return node;
- }
- public override QuantifierExpr VisitQuantifierExpr(QuantifierExpr node)
- {
- Contract.Ensures(Contract.Result<QuantifierExpr>() == node);
- this.VisitBinderExpr(node);
- if (node.Triggers != null)
- {
- this.VisitTrigger(node.Triggers);
- }
- return node;
- }
- public override Cmd VisitRE(RE node)
- {
- Contract.Ensures(Contract.Result<Cmd>() == node);
- return (Cmd)this.Visit(node); // Call general visit so subtypes get visited by their particular visitor
- }
- public override List<RE> VisitRESeq(List<RE> reSeq)
- {
- Contract.Ensures(Contract.Result<List<RE>>() == reSeq);
- for (int i = 0, n = reSeq.Count; i < n; i++)
- this.VisitRE(cce.NonNull(reSeq[i]));
- return reSeq;
- }
- public override ReturnCmd VisitReturnCmd(ReturnCmd node)
- {
- Contract.Ensures(Contract.Result<ReturnCmd>() == node);
- return (ReturnCmd)this.VisitTransferCmd(node);
- }
- public override ReturnExprCmd VisitReturnExprCmd(ReturnExprCmd node)
- {
- Contract.Ensures(Contract.Result<ReturnExprCmd>() == node);
- this.VisitExpr(node.Expr);
- return node;
- }
- public override Sequential VisitSequential(Sequential node)
- {
- Contract.Ensures(Contract.Result<Sequential>() == node);
- this.VisitRE(node.first);
- this.VisitRE(node.second);
- return node;
- }
- public override AssignLhs VisitSimpleAssignLhs(SimpleAssignLhs node)
- {
- Contract.Ensures(Contract.Result<AssignLhs>() == node);
- this.VisitIdentifierExpr(node.AssignedVariable);
- return node;
- }
- public override Cmd VisitStateCmd(StateCmd node)
- {
- Contract.Ensures(Contract.Result<Cmd>() == node);
- this.VisitVariableSeq(node.Locals);
- this.VisitCmdSeq(node.Cmds);
- return node;
- }
- public override TransferCmd VisitTransferCmd(TransferCmd node)
- {
- Contract.Ensures(Contract.Result<TransferCmd>() == node);
- return node;
- }
- public override Trigger VisitTrigger(Trigger node)
- {
- Contract.Ensures(Contract.Result<Trigger>() == node);
- Trigger origNext = node.Next;
- if (origNext != null)
- {
- this.VisitTrigger(origNext);
- }
- this.VisitExprSeq(node.Tr.ToList());
- return node;
- }
- // called by default for all nullary type constructors and type variables
- public override Type VisitType(Type node)
- {
- Contract.Ensures(Contract.Result<Type>() == node);
- return node;
- }
- public override TypedIdent VisitTypedIdent(TypedIdent node)
- {
- Contract.Ensures(Contract.Result<TypedIdent>() == node);
- this.Visit(node.Type);
- return node;
- }
- public override Declaration VisitTypeCtorDecl(TypeCtorDecl node)
- {
- Contract.Ensures(Contract.Result<Declaration>() == node);
- return this.VisitDeclaration(node);
- }
- public override Type VisitTypeSynonymAnnotation(TypeSynonymAnnotation node)
- {
- Contract.Ensures(Contract.Result<Type>() == node);
- node.ExpandedType = cce.NonNull((Type/*!*/)this.Visit(node.ExpandedType));
- for (int i = 0; i < node.Arguments.Count; ++i)
- this.Visit(node.Arguments[i]);
- return node;
- }
- public override Declaration VisitTypeSynonymDecl(TypeSynonymDecl node)
- {
- Contract.Ensures(Contract.Result<Declaration>() == node);
- return this.VisitDeclaration(node);
- }
- public override Type VisitTypeVariable(TypeVariable node)
- {
- Contract.Ensures(Contract.Result<Type>() == node);
- return this.VisitType(node);
- }
- public override Type VisitTypeProxy(TypeProxy node)
- {
- Contract.Ensures(Contract.Result<Type>() == node);
- // if the type proxy is instantiated with some more
- // specific type, we visit the instantiation
- if (node.ProxyFor != null)
- this.Visit(node.ProxyFor);
- return this.VisitType(node);
- }
- public override Type VisitUnresolvedTypeIdentifier(UnresolvedTypeIdentifier node)
- {
- Contract.Ensures(Contract.Result<Type>() == node);
- return this.VisitType(node);
- }
- public override Variable VisitVariable(Variable node)
- {
- Contract.Ensures(Contract.Result<Variable>() == node);
- this.VisitTypedIdent(node.TypedIdent);
- return node;
- }
- public override List<Variable> VisitVariableSeq(List<Variable> variableSeq)
- {
- Contract.Ensures(Contract.Result<List<Variable>>() == variableSeq);
- for (int i = 0, n = variableSeq.Count; i < n; i++)
- this.VisitVariable(cce.NonNull(variableSeq[i]));
- return variableSeq;
- }
- public override YieldCmd VisitYieldCmd(YieldCmd node)
- {
- Contract.Ensures(Contract.Result<YieldCmd>() == node);
- return node;
- }
- public override Cmd VisitAssertEnsuresCmd(AssertEnsuresCmd node)
- {
- Contract.Ensures(Contract.Result<Cmd>() == node);
- this.VisitEnsures(node.Ensures);
- this.VisitExpr(node.Expr);
- return node;
- }
- public override Cmd VisitAssertRequiresCmd(AssertRequiresCmd node)
- {
- Contract.Ensures(Contract.Result<Cmd>() == node);
- this.VisitRequires(node.Requires);
- this.VisitExpr(node.Expr);
- return node;
- }
- }
-}
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------------
+// BoogiePL - StandardVisitor.cs
+//---------------------------------------------------------------------------------------------
+
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Linq;
+
+namespace Microsoft.Boogie {
+ [ContractClass(typeof(VisitorContracts))]
+ /// <summary>
+ /// Base for all classes that process the Absy using the visitor pattern.
+ /// </summary>
+ public abstract class Visitor {
+ /// <summary>
+ /// Switches on node.NodeType to call a visitor method that has been specialized for node.
+ /// </summary>
+ /// <param name="a">The Absy node to be visited.</param>
+ /// <returns> Returns null if node is null. Otherwise returns an updated node (possibly a different object).</returns>
+ public abstract Absy/*!*/ Visit(Absy/*!*/ node);
+
+ /// <summary>
+ /// Transfers the state from one visitor to another. This enables separate visitor instances to cooperative process a single IR.
+ /// </summary>
+ public virtual void TransferStateTo(Visitor targetVisitor) {
+ }
+
+ public virtual IList<Expr> VisitExprSeq(IList<Expr> list) {
+ Contract.Requires(list != null);
+ Contract.Ensures(Contract.Result<IList<Expr>>() != null);
+ lock (list)
+ {
+ for (int i = 0, n = list.Count; i < n; i++)
+ list[i] = (Expr)this.Visit(cce.NonNull(list[i]));
+ }
+ return list;
+ }
+ }
+ [ContractClassFor(typeof(Visitor))]
+ abstract class VisitorContracts : Visitor {
+ public override Absy Visit(Absy node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Absy>() != null);
+
+ throw new System.NotImplementedException();
+ }
+ }
+
+ /// <summary>
+ /// Walks an IR, mutating it into a new form. (For a subclass that does not mutate the IR, see ReadOnlyVisitor.)
+ /// </summary>
+ public abstract class StandardVisitor : Visitor {
+ public Visitor callingVisitor;
+
+ public StandardVisitor() {
+ }
+ public StandardVisitor(Visitor callingVisitor) {
+ this.callingVisitor = callingVisitor;
+ }
+ public override Absy Visit(Absy node) {
+ return node.StdDispatch(this);
+ }
+ public virtual Cmd VisitAssertCmd(AssertCmd node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ node.Expr = this.VisitExpr(node.Expr);
+ return node;
+ }
+ public virtual Cmd VisitAssignCmd(AssignCmd node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ for (int i = 0; i < node.Lhss.Count; ++i) {
+ node.SetLhs(i, cce.NonNull((AssignLhs)this.Visit(node.Lhss[i])));
+ node.SetRhs(i, cce.NonNull((Expr/*!*/)this.Visit(node.Rhss[i])));
+ }
+ return node;
+ }
+ public virtual Cmd VisitAssumeCmd(AssumeCmd node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ node.Expr = this.VisitExpr(node.Expr);
+ return node;
+ }
+ public virtual AtomicRE VisitAtomicRE(AtomicRE node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<AtomicRE>() != null);
+ node.b = this.VisitBlock(node.b);
+ return node;
+ }
+ public virtual Axiom VisitAxiom(Axiom node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Axiom>() != null);
+ node.Expr = this.VisitExpr(node.Expr);
+ return node;
+ }
+ public virtual Type VisitBasicType(BasicType node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ return this.VisitType(node);
+ }
+ public virtual Type VisitFloatType(FloatType node)
+ {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ return this.VisitType(node);
+ }
+ public virtual Expr VisitBvConcatExpr(BvConcatExpr node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ node.E0 = this.VisitExpr(node.E0);
+ node.E1 = this.VisitExpr(node.E1);
+ return node;
+ }
+ public virtual Type VisitBvType(BvType node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ return this.VisitType(node);
+ }
+ public virtual Type VisitBvTypeProxy(BvTypeProxy node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ // if the type proxy is instantiated with some more
+ // specific type, we visit the instantiation
+ if (node.ProxyFor != null)
+ return (Type)this.Visit(node.ProxyFor);
+ return this.VisitType(node);
+ }
+ public virtual Block VisitBlock(Block node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Block>() != null);
+ node.Cmds = this.VisitCmdSeq(node.Cmds);
+ node.TransferCmd = (TransferCmd)this.Visit(cce.NonNull(node.TransferCmd));
+ return node;
+ }
+ public virtual Expr VisitCodeExpr(CodeExpr node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ node.LocVars = this.VisitVariableSeq(node.LocVars);
+ node.Blocks = this.VisitBlockList(node.Blocks);
+ return node;
+ }
+ public virtual List<Block> VisitBlockSeq(List<Block> blockSeq) {
+ Contract.Requires(blockSeq != null);
+ Contract.Ensures(Contract.Result<List<Block>>() != null);
+ lock (blockSeq)
+ {
+ for (int i = 0, n = blockSeq.Count; i < n; i++)
+ blockSeq[i] = this.VisitBlock(cce.NonNull(blockSeq[i]));
+ }
+ return blockSeq;
+ }
+ public virtual List<Block/*!*/>/*!*/ VisitBlockList(List<Block/*!*/>/*!*/ blocks) {
+ Contract.Requires(blocks != null);
+ Contract.Ensures(Contract.Result<List<Block>>() != null);
+ for (int i = 0, n = blocks.Count; i < n; i++) {
+ blocks[i] = this.VisitBlock(blocks[i]);
+ }
+ return blocks;
+ }
+ public virtual BoundVariable VisitBoundVariable(BoundVariable node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<BoundVariable>() != null);
+ node = (BoundVariable)this.VisitVariable(node);
+ return node;
+ }
+ public virtual Cmd VisitCallCmd(CallCmd node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ for (int i = 0; i < node.Ins.Count; ++i)
+ if (node.Ins[i] != null)
+ node.Ins[i] = this.VisitExpr(cce.NonNull(node.Ins[i]));
+ for (int i = 0; i < node.Outs.Count; ++i)
+ if (node.Outs[i] != null)
+ node.Outs[i] = (IdentifierExpr)this.VisitIdentifierExpr(cce.NonNull(node.Outs[i]));
+ return node;
+ }
+ public virtual Cmd VisitParCallCmd(ParCallCmd node)
+ {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ for (int i = 0; i < node.CallCmds.Count; i++)
+ {
+ if (node.CallCmds[i] != null)
+ node.CallCmds[i] = (CallCmd)this.VisitCallCmd(node.CallCmds[i]);
+ }
+ return node;
+ }
+ public virtual List<Cmd> VisitCmdSeq(List<Cmd> cmdSeq) {
+ Contract.Requires(cmdSeq != null);
+ Contract.Ensures(Contract.Result<List<Cmd>>() != null);
+ lock (cmdSeq)
+ {
+ for (int i = 0, n = cmdSeq.Count; i < n; i++)
+ cmdSeq[i] = (Cmd)this.Visit(cce.NonNull(cmdSeq[i])); // call general Visit so subtypes of Cmd get visited by their particular visitor
+ }
+ return cmdSeq;
+ }
+ public virtual Choice VisitChoice(Choice node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Choice>() != null);
+ node.rs = this.VisitRESeq(node.rs);
+ return node;
+ }
+ public virtual Cmd VisitCommentCmd(CommentCmd node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ return node;
+ }
+ public virtual Constant VisitConstant(Constant node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Constant>() != null);
+ return node;
+ }
+ public virtual CtorType VisitCtorType(CtorType node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<CtorType>() != null);
+ lock (node)
+ {
+ for (int i = 0; i < node.Arguments.Count; ++i)
+ node.Arguments[i] = cce.NonNull((Type/*!*/)this.Visit(node.Arguments[i]));
+ }
+ return node;
+ }
+ public virtual Declaration VisitDeclaration(Declaration node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Declaration>() != null);
+ return node;
+ }
+ public virtual List<Declaration/*!*/>/*!*/ VisitDeclarationList(List<Declaration/*!*/>/*!*/ declarationList) {
+ Contract.Requires(declarationList != null);
+ Contract.Ensures(Contract.Result<List<Declaration>>() != null);
+ for (int i = 0, n = declarationList.Count; i < n; i++)
+ declarationList[i] = cce.NonNull((Declaration/*!*/)this.Visit(declarationList[i]));
+ return declarationList;
+ }
+ public virtual DeclWithFormals VisitDeclWithFormals(DeclWithFormals node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<DeclWithFormals>() != null);
+ node.InParams = this.VisitVariableSeq(node.InParams);
+ node.OutParams = this.VisitVariableSeq(node.OutParams);
+ return node;
+ }
+ public virtual Expr VisitExistsExpr(ExistsExpr node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ node = (ExistsExpr)this.VisitQuantifierExpr(node);
+ return node;
+ }
+ public virtual Expr VisitBvExtractExpr(BvExtractExpr node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ node.Bitvector = this.VisitExpr(node.Bitvector);
+ return node;
+ }
+ public virtual Expr VisitExpr(Expr node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ Expr e = (Expr)this.Visit(node);
+ return e;
+ }
+ public override IList<Expr> VisitExprSeq(IList<Expr> exprSeq) {
+ //Contract.Requires(exprSeq != null);
+ Contract.Ensures(Contract.Result<IList<Expr>>() != null);
+ for (int i = 0, n = exprSeq.Count; i < n; i++)
+ exprSeq[i] = this.VisitExpr(cce.NonNull(exprSeq[i]));
+ return exprSeq;
+ }
+ public virtual Requires VisitRequires(Requires @requires) {
+ Contract.Requires(@requires != null);
+ Contract.Ensures(Contract.Result<Requires>() != null);
+ @requires.Condition = this.VisitExpr(@requires.Condition);
+ return @requires;
+ }
+ public virtual List<Requires> VisitRequiresSeq(List<Requires> requiresSeq) {
+ Contract.Requires(requiresSeq != null);
+ Contract.Ensures(Contract.Result<List<Requires>>() != null);
+ for (int i = 0, n = requiresSeq.Count; i < n; i++)
+ requiresSeq[i] = this.VisitRequires(requiresSeq[i]);
+ return requiresSeq;
+ }
+ public virtual Ensures VisitEnsures(Ensures @ensures) {
+ Contract.Requires(@ensures != null);
+ Contract.Ensures(Contract.Result<Ensures>() != null);
+ @ensures.Condition = this.VisitExpr(@ensures.Condition);
+ return @ensures;
+ }
+ public virtual List<Ensures> VisitEnsuresSeq(List<Ensures> ensuresSeq) {
+ Contract.Requires(ensuresSeq != null);
+ Contract.Ensures(Contract.Result<List<Ensures>>() != null);
+ for (int i = 0, n = ensuresSeq.Count; i < n; i++)
+ ensuresSeq[i] = this.VisitEnsures(ensuresSeq[i]);
+ return ensuresSeq;
+ }
+ public virtual Expr VisitForallExpr(ForallExpr node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ node = (ForallExpr)this.VisitQuantifierExpr(node);
+ return node;
+ }
+ public virtual Expr VisitLambdaExpr(LambdaExpr node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ node = (LambdaExpr)this.VisitBinderExpr(node);
+ return node;
+ }
+ public virtual Formal VisitFormal(Formal node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Formal>() != null);
+ return node;
+ }
+ public virtual Function VisitFunction(Function node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Function>() != null);
+ node = (Function)this.VisitDeclWithFormals(node);
+ if (node.Body != null)
+ node.Body = this.VisitExpr(node.Body);
+ return node;
+ }
+ public virtual GlobalVariable VisitGlobalVariable(GlobalVariable node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<GlobalVariable>() != null);
+ node = (GlobalVariable)this.VisitVariable(node);
+ return node;
+ }
+ public virtual GotoCmd VisitGotoCmd(GotoCmd node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<GotoCmd>() != null);
+ // do not visit the labelTargets, or control-flow loops will lead to a looping visitor
+ return node;
+ }
+ public virtual Cmd VisitHavocCmd(HavocCmd node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ node.Vars = this.VisitIdentifierExprSeq(node.Vars);
+ return node;
+ }
+ public virtual Expr VisitIdentifierExpr(IdentifierExpr node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ if (node.Decl != null)
+ node.Decl = this.VisitVariable(node.Decl);
+ return node;
+ }
+ public virtual List<IdentifierExpr> VisitIdentifierExprSeq(List<IdentifierExpr> identifierExprSeq) {
+ Contract.Requires(identifierExprSeq != null);
+ Contract.Ensures(Contract.Result<List<IdentifierExpr>>() != null);
+ lock (identifierExprSeq)
+ {
+ for (int i = 0, n = identifierExprSeq.Count; i < n; i++)
+ identifierExprSeq[i] = (IdentifierExpr)this.VisitIdentifierExpr(cce.NonNull(identifierExprSeq[i]));
+ }
+ return identifierExprSeq;
+ }
+ public virtual Implementation VisitImplementation(Implementation node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Implementation>() != null);
+ node.LocVars = this.VisitVariableSeq(node.LocVars);
+ node.Blocks = this.VisitBlockList(node.Blocks);
+ node.Proc = this.VisitProcedure(cce.NonNull(node.Proc));
+ node = (Implementation)this.VisitDeclWithFormals(node); // do this first or last?
+ return node;
+ }
+ public virtual Expr VisitLiteralExpr(LiteralExpr node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ return node;
+ }
+
+ public virtual LocalVariable VisitLocalVariable(LocalVariable node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<LocalVariable>() != null);
+ return node;
+ }
+
+ public virtual AssignLhs VisitMapAssignLhs(MapAssignLhs node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<AssignLhs>() != null);
+ node.Map = cce.NonNull((AssignLhs)this.Visit(node.Map));
+ for (int i = 0; i < node.Indexes.Count; ++i)
+ node.Indexes[i] = cce.NonNull((Expr)this.Visit(node.Indexes[i]));
+ return node;
+ }
+ public virtual MapType VisitMapType(MapType node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<MapType>() != null);
+ // not doing anything about the bound variables ... maybe
+ // these should be visited as well ...
+ //
+ // NOTE: when overriding this method, you have to make sure that
+ // the bound variables of the map type are updated correctly
+ lock (node.Arguments)
+ {
+ for (int i = 0; i < node.Arguments.Count; ++i)
+ node.Arguments[i] = cce.NonNull((Type/*!*/)this.Visit(node.Arguments[i]));
+ }
+ node.Result = cce.NonNull((Type/*!*/)this.Visit(node.Result));
+ return node;
+ }
+ public virtual Type VisitMapTypeProxy(MapTypeProxy node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ // if the type proxy is instantiated with some more
+ // specific type, we visit the instantiation
+ if (node.ProxyFor != null)
+ return (Type)this.Visit(node.ProxyFor);
+ return this.VisitType(node);
+ }
+
+ public virtual Expr VisitNAryExpr(NAryExpr node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ node.Args = this.VisitExprSeq(node.Args);
+ return node;
+ }
+ public virtual Expr VisitOldExpr(OldExpr node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ node.Expr = this.VisitExpr(node.Expr);
+ return node;
+ }
+ public virtual Procedure VisitProcedure(Procedure node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Procedure>() != null);
+ node.Ensures = this.VisitEnsuresSeq(node.Ensures);
+ node.InParams = this.VisitVariableSeq(node.InParams);
+ node.Modifies = this.VisitIdentifierExprSeq(node.Modifies);
+ node.OutParams = this.VisitVariableSeq(node.OutParams);
+ node.Requires = this.VisitRequiresSeq(node.Requires);
+ return node;
+ }
+ public virtual Program VisitProgram(Program node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Program>() != null);
+ var decls = node.TopLevelDeclarations.ToList();
+ node.ClearTopLevelDeclarations();
+ node.AddTopLevelDeclarations(this.VisitDeclarationList(decls));
+ return node;
+ }
+ public virtual QKeyValue VisitQKeyValue(QKeyValue node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<QKeyValue>() != null);
+ var newParams = new List<object>();
+ for (int i = 0, n = node.Params.Count; i < n; i++) {
+ var e = node.Params[i] as Expr;
+ newParams.Add(e != null ? this.Visit(e) : node.Params[i]);
+ }
+ node.ClearParams();
+ node.AddParams(newParams);
+ if (node.Next != null) {
+ node.Next = (QKeyValue)this.Visit(node.Next);
+ }
+ return node;
+ }
+ public virtual BinderExpr VisitBinderExpr(BinderExpr node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<BinderExpr>() != null);
+ node.Body = this.VisitExpr(node.Body);
+ node.Dummies = this.VisitVariableSeq(node.Dummies);
+ //node.Type = this.VisitType(node.Type);
+ return node;
+ }
+ public virtual QuantifierExpr VisitQuantifierExpr(QuantifierExpr node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<QuantifierExpr>() != null);
+ node = cce.NonNull((QuantifierExpr)this.VisitBinderExpr(node));
+ if (node.Triggers != null) {
+ node.Triggers = this.VisitTrigger(node.Triggers);
+ }
+ return node;
+ }
+ public virtual Cmd VisitRE(RE node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ return (Cmd)this.Visit(node); // Call general visit so subtypes get visited by their particular visitor
+ }
+ public virtual List<RE> VisitRESeq(List<RE> reSeq) {
+ Contract.Requires(reSeq != null);
+ Contract.Ensures(Contract.Result<List<RE>>() != null);
+ for (int i = 0, n = reSeq.Count; i < n; i++)
+ reSeq[i] = (RE)this.VisitRE(cce.NonNull(reSeq[i]));
+ return reSeq;
+ }
+ public virtual ReturnCmd VisitReturnCmd(ReturnCmd node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<ReturnCmd>() != null);
+ return (ReturnCmd)this.VisitTransferCmd(node);
+ }
+ public virtual ReturnExprCmd VisitReturnExprCmd(ReturnExprCmd node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<ReturnExprCmd>() != null);
+ node.Expr = this.VisitExpr(node.Expr);
+ return node;
+ }
+ public virtual Sequential VisitSequential(Sequential node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Sequential>() != null);
+ node.first = (RE)this.VisitRE(node.first);
+ node.second = (RE)this.VisitRE(node.second);
+ return node;
+ }
+ public virtual AssignLhs VisitSimpleAssignLhs(SimpleAssignLhs node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<AssignLhs>() != null);
+ node.AssignedVariable =
+ (IdentifierExpr)this.VisitIdentifierExpr(node.AssignedVariable);
+ return node;
+ }
+ public virtual Cmd VisitStateCmd(StateCmd node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ node.Locals = this.VisitVariableSeq(node.Locals);
+ node.Cmds = this.VisitCmdSeq(node.Cmds);
+ return node;
+ }
+ public virtual TransferCmd VisitTransferCmd(TransferCmd node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<TransferCmd>() != null);
+ return node;
+ }
+ public virtual Trigger VisitTrigger(Trigger node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Trigger>() != null);
+ Trigger origNext = node.Next;
+ if (origNext != null) {
+ Trigger newNext = this.VisitTrigger(origNext);
+ if (newNext != origNext) {
+ node = new Trigger(node.tok, node.Pos, node.Tr.ToList());
+ node.Next = newNext;
+ }
+ }
+ node.Tr = this.VisitExprSeq(node.Tr.ToList());
+ return node;
+ }
+ // called by default for all nullary type constructors and type variables
+ public virtual Type VisitType(Type node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ return node;
+ }
+ public virtual TypedIdent VisitTypedIdent(TypedIdent node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<TypedIdent>() != null);
+ node.Type = (Type)this.Visit(node.Type);
+ return node;
+ }
+ public virtual Declaration VisitTypeCtorDecl(TypeCtorDecl node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Declaration>() != null);
+ return this.VisitDeclaration(node);
+ }
+ public virtual Type VisitTypeSynonymAnnotation(TypeSynonymAnnotation node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ node.ExpandedType = cce.NonNull((Type/*!*/)this.Visit(node.ExpandedType));
+ lock (node.Arguments)
+ {
+ for (int i = 0; i < node.Arguments.Count; ++i)
+ node.Arguments[i] = cce.NonNull((Type/*!*/)this.Visit(node.Arguments[i]));
+ }
+ return node;
+ }
+ public virtual Declaration VisitTypeSynonymDecl(TypeSynonymDecl node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Declaration>() != null);
+ return this.VisitDeclaration(node);
+ }
+ public virtual Type VisitTypeVariable(TypeVariable node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ return this.VisitType(node);
+ }
+ public virtual Type VisitTypeProxy(TypeProxy node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ // if the type proxy is instantiated with some more
+ // specific type, we visit the instantiation
+ if (node.ProxyFor != null)
+ return cce.NonNull((Type/*!*/)this.Visit(node.ProxyFor));
+ return this.VisitType(node);
+ }
+ public virtual Type VisitUnresolvedTypeIdentifier(UnresolvedTypeIdentifier node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ return this.VisitType(node);
+ }
+ public virtual Variable VisitVariable(Variable node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Variable>() != null);
+ node.TypedIdent = this.VisitTypedIdent(node.TypedIdent);
+ return node;
+ }
+ public virtual List<Variable> VisitVariableSeq(List<Variable> variableSeq) {
+ Contract.Requires(variableSeq != null);
+ Contract.Ensures(Contract.Result<List<Variable>>() != null);
+ lock (variableSeq)
+ {
+ for (int i = 0, n = variableSeq.Count; i < n; i++)
+ variableSeq[i] = this.VisitVariable(cce.NonNull(variableSeq[i]));
+ }
+ return variableSeq;
+ }
+ public virtual YieldCmd VisitYieldCmd(YieldCmd node)
+ {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<YieldCmd>() != null);
+ return node;
+ }
+ public virtual Cmd VisitAssertEnsuresCmd(AssertEnsuresCmd node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ node.Ensures = this.VisitEnsures(node.Ensures);
+ node.Expr = this.VisitExpr(node.Expr);
+ return node;
+ }
+ public virtual Cmd VisitAssertRequiresCmd(AssertRequiresCmd node) {
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Cmd>() != null);
+ node.Requires = this.VisitRequires(node.Requires);
+ node.Expr = this.VisitExpr(node.Expr);
+ return node;
+ }
+ }
+
+ /// <summary>
+ /// A ReadOnlyVisitor visits all the nodes of a given Absy. The visitor may collect information from
+ /// the nodes, may change fields contained in the data structure, but may not replace any nodes in the
+ /// data structure. To enforce this, all Visit...(node) methods have a postcondition that says that
+ /// the return value is equal to the given "node".
+ /// </summary>
+ public abstract class ReadOnlyVisitor : StandardVisitor
+ {
+ public ReadOnlyVisitor()
+ {
+ }
+ public ReadOnlyVisitor(Visitor callingVisitor)
+ {
+ this.callingVisitor = callingVisitor;
+ }
+ public override Absy Visit(Absy node)
+ {
+ Contract.Ensures(Contract.Result<Absy>() == node);
+ return node.StdDispatch(this);
+ }
+ public override Cmd VisitAssertCmd(AssertCmd node)
+ {
+ Contract.Ensures(Contract.Result<Cmd>() == node);
+ this.VisitExpr(node.Expr);
+ return node;
+ }
+ public override Cmd VisitAssignCmd(AssignCmd node)
+ {
+ Contract.Ensures(Contract.Result<Cmd>() == node);
+ for (int i = 0; i < node.Lhss.Count; ++i)
+ {
+ this.Visit(node.Lhss[i]);
+ this.Visit(node.Rhss[i]);
+ }
+ return node;
+ }
+ public override Cmd VisitAssumeCmd(AssumeCmd node)
+ {
+ Contract.Ensures(Contract.Result<Cmd>() == node);
+ this.VisitExpr(node.Expr);
+ return node;
+ }
+ public override AtomicRE VisitAtomicRE(AtomicRE node)
+ {
+ Contract.Ensures(Contract.Result<AtomicRE>() == node);
+ this.VisitBlock(node.b);
+ return node;
+ }
+ public override Axiom VisitAxiom(Axiom node)
+ {
+ Contract.Ensures(Contract.Result<Axiom>() == node);
+ this.VisitExpr(node.Expr);
+ return node;
+ }
+ public override Type VisitBasicType(BasicType node)
+ {
+ Contract.Ensures(Contract.Result<Type>() == node);
+ return this.VisitType(node);
+ }
+ public override Expr VisitBvConcatExpr(BvConcatExpr node)
+ {
+ Contract.Ensures(Contract.Result<Expr>() == node);
+ this.VisitExpr(node.E0);
+ this.VisitExpr(node.E1);
+ return node;
+ }
+ public override Type VisitBvType(BvType node)
+ {
+ Contract.Ensures(Contract.Result<Type>() == node);
+ return this.VisitType(node);
+ }
+ public override Type VisitBvTypeProxy(BvTypeProxy node)
+ {
+ Contract.Ensures(Contract.Result<Type>() == node);
+ // if the type proxy is instantiated with some more
+ // specific type, we visit the instantiation
+ if (node.ProxyFor != null)
+ this.Visit(node.ProxyFor);
+ return this.VisitType(node);
+ }
+ public override Block VisitBlock(Block node)
+ {
+ Contract.Ensures(Contract.Result<Block>() == node);
+ this.VisitCmdSeq(node.Cmds);
+ this.Visit(cce.NonNull(node.TransferCmd));
+ return node;
+ }
+ public override Expr VisitCodeExpr(CodeExpr node)
+ {
+ Contract.Ensures(Contract.Result<Expr>() == node);
+ this.VisitVariableSeq(node.LocVars);
+ this.VisitBlockList(node.Blocks);
+ return node;
+ }
+ public override List<Block> VisitBlockSeq(List<Block> blockSeq)
+ {
+ Contract.Ensures(Contract.Result<List<Block>>() == blockSeq);
+ for (int i = 0, n = blockSeq.Count; i < n; i++)
+ this.VisitBlock(cce.NonNull(blockSeq[i]));
+ return blockSeq;
+ }
+ public override List<Block/*!*/>/*!*/ VisitBlockList(List<Block/*!*/>/*!*/ blocks)
+ {
+ Contract.Ensures(Contract.Result<List<Block>>() == blocks);
+ for (int i = 0, n = blocks.Count; i < n; i++)
+ {
+ this.VisitBlock(blocks[i]);
+ }
+ return blocks;
+ }
+ public override BoundVariable VisitBoundVariable(BoundVariable node)
+ {
+ Contract.Ensures(Contract.Result<BoundVariable>() == node);
+ return (BoundVariable)this.VisitVariable(node);
+ }
+ public override Cmd VisitCallCmd(CallCmd node)
+ {
+ Contract.Ensures(Contract.Result<Cmd>() == node);
+ for (int i = 0; i < node.Ins.Count; ++i)
+ if (node.Ins[i] != null)
+ this.VisitExpr(node.Ins[i]);
+ for (int i = 0; i < node.Outs.Count; ++i)
+ if (node.Outs[i] != null)
+ this.VisitIdentifierExpr(node.Outs[i]);
+ return node;
+ }
+ public override Cmd VisitParCallCmd(ParCallCmd node)
+ {
+ Contract.Ensures(Contract.Result<Cmd>() == node);
+ for (int i = 0; i < node.CallCmds.Count; i++)
+ {
+ if (node.CallCmds[i] != null)
+ this.VisitCallCmd(node.CallCmds[i]);
+ }
+ return node;
+ }
+ public override List<Cmd> VisitCmdSeq(List<Cmd> cmdSeq)
+ {
+ Contract.Ensures(Contract.Result<List<Cmd>>() == cmdSeq);
+ for (int i = 0, n = cmdSeq.Count; i < n; i++)
+ this.Visit(cce.NonNull(cmdSeq[i])); // call general Visit so subtypes of Cmd get visited by their particular visitor
+ return cmdSeq;
+ }
+ public override Choice VisitChoice(Choice node)
+ {
+ Contract.Ensures(Contract.Result<Choice>() == node);
+ this.VisitRESeq(node.rs);
+ return node;
+ }
+ public override Cmd VisitCommentCmd(CommentCmd node)
+ {
+ Contract.Ensures(Contract.Result<Cmd>() == node);
+ return node;
+ }
+ public override Constant VisitConstant(Constant node)
+ {
+ Contract.Ensures(Contract.Result<Constant>() == node);
+ return node;
+ }
+ public override CtorType VisitCtorType(CtorType node)
+ {
+ Contract.Ensures(Contract.Result<CtorType>() == node);
+ for (int i = 0; i < node.Arguments.Count; ++i)
+ this.Visit(node.Arguments[i]);
+ return node;
+ }
+ public override Declaration VisitDeclaration(Declaration node)
+ {
+ Contract.Ensures(Contract.Result<Declaration>() == node);
+ return node;
+ }
+ public override List<Declaration/*!*/>/*!*/ VisitDeclarationList(List<Declaration/*!*/>/*!*/ declarationList)
+ {
+ Contract.Ensures(Contract.Result<List<Declaration>>() == declarationList);
+ for (int i = 0, n = declarationList.Count; i < n; i++)
+ this.Visit(declarationList[i]);
+ return declarationList;
+ }
+ public override DeclWithFormals VisitDeclWithFormals(DeclWithFormals node)
+ {
+ Contract.Ensures(Contract.Result<DeclWithFormals>() == node);
+ this.VisitVariableSeq(node.InParams);
+ this.VisitVariableSeq(node.OutParams);
+ return node;
+ }
+ public override Expr VisitExistsExpr(ExistsExpr node)
+ {
+ Contract.Ensures(Contract.Result<Expr>() == node);
+ return (ExistsExpr)this.VisitQuantifierExpr(node);
+ }
+ public override Expr VisitBvExtractExpr(BvExtractExpr node)
+ {
+ Contract.Ensures(Contract.Result<Expr>() == node);
+ this.VisitExpr(node.Bitvector);
+ return node;
+ }
+ public override Expr VisitExpr(Expr node)
+ {
+ Contract.Ensures(Contract.Result<Expr>() == node);
+ return (Expr)this.Visit(node);
+ }
+ public override IList<Expr> VisitExprSeq(IList<Expr> exprSeq)
+ {
+ Contract.Ensures(Contract.Result<IList<Expr>>() == exprSeq);
+ for (int i = 0, n = exprSeq.Count; i < n; i++)
+ this.VisitExpr(cce.NonNull(exprSeq[i]));
+ return exprSeq;
+ }
+ public override Requires VisitRequires(Requires requires)
+ {
+ Contract.Ensures(Contract.Result<Requires>() == requires);
+ this.VisitExpr(requires.Condition);
+ return requires;
+ }
+ public override List<Requires> VisitRequiresSeq(List<Requires> requiresSeq)
+ {
+ Contract.Ensures(Contract.Result<List<Requires>>() == requiresSeq);
+ for (int i = 0, n = requiresSeq.Count; i < n; i++)
+ this.VisitRequires(requiresSeq[i]);
+ return requiresSeq;
+ }
+ public override Ensures VisitEnsures(Ensures ensures)
+ {
+ Contract.Ensures(Contract.Result<Ensures>() == ensures);
+ this.VisitExpr(ensures.Condition);
+ return ensures;
+ }
+ public override List<Ensures> VisitEnsuresSeq(List<Ensures> ensuresSeq)
+ {
+ Contract.Ensures(Contract.Result<List<Ensures>>() == ensuresSeq);
+ for (int i = 0, n = ensuresSeq.Count; i < n; i++)
+ this.VisitEnsures(ensuresSeq[i]);
+ return ensuresSeq;
+ }
+ public override Expr VisitForallExpr(ForallExpr node)
+ {
+ Contract.Ensures(Contract.Result<Expr>() == node);
+ return (ForallExpr)this.VisitQuantifierExpr(node);
+ }
+ public override Expr VisitLambdaExpr(LambdaExpr node) {
+ Contract.Ensures(Contract.Result<Expr>() == node);
+ return this.VisitBinderExpr(node);
+ }
+ public override Formal VisitFormal(Formal node)
+ {
+ Contract.Ensures(Contract.Result<Formal>() == node);
+ return node;
+ }
+ public override Function VisitFunction(Function node)
+ {
+ Contract.Ensures(Contract.Result<Function>() == node);
+ node = (Function)this.VisitDeclWithFormals(node);
+ if (node.Body != null)
+ this.VisitExpr(node.Body);
+ return node;
+ }
+ public override GlobalVariable VisitGlobalVariable(GlobalVariable node)
+ {
+ Contract.Ensures(Contract.Result<GlobalVariable>() == node);
+ return (GlobalVariable)this.VisitVariable(node);
+ }
+ public override GotoCmd VisitGotoCmd(GotoCmd node)
+ {
+ Contract.Ensures(Contract.Result<GotoCmd>() == node);
+ // do not visit the labelTargets, or control-flow loops will lead to a looping visitor
+ return node;
+ }
+ public override Cmd VisitHavocCmd(HavocCmd node)
+ {
+ Contract.Ensures(Contract.Result<Cmd>() == node);
+ this.VisitIdentifierExprSeq(node.Vars);
+ return node;
+ }
+ public override Expr VisitIdentifierExpr(IdentifierExpr node)
+ {
+ Contract.Ensures(Contract.Result<Expr>() == node);
+ if (node.Decl != null)
+ this.VisitVariable(node.Decl);
+ return node;
+ }
+ public override List<IdentifierExpr> VisitIdentifierExprSeq(List<IdentifierExpr> identifierExprSeq)
+ {
+ Contract.Ensures(Contract.Result<List<IdentifierExpr>>() == identifierExprSeq);
+ for (int i = 0, n = identifierExprSeq.Count; i < n; i++)
+ this.VisitIdentifierExpr(cce.NonNull(identifierExprSeq[i]));
+ return identifierExprSeq;
+ }
+ public override Implementation VisitImplementation(Implementation node)
+ {
+ Contract.Ensures(Contract.Result<Implementation>() == node);
+ this.VisitVariableSeq(node.LocVars);
+ this.VisitBlockList(node.Blocks);
+ this.VisitProcedure(cce.NonNull(node.Proc));
+ return (Implementation)this.VisitDeclWithFormals(node); // do this first or last?
+ }
+ public override Expr VisitLiteralExpr(LiteralExpr node)
+ {
+ Contract.Ensures(Contract.Result<Expr>() == node);
+ return node;
+ }
+
+ public override LocalVariable VisitLocalVariable(LocalVariable node)
+ {
+ Contract.Ensures(Contract.Result<LocalVariable>() == node);
+ return node;
+ }
+
+ public override AssignLhs VisitMapAssignLhs(MapAssignLhs node)
+ {
+ Contract.Ensures(Contract.Result<AssignLhs>() == node);
+ this.Visit(node.Map);
+ for (int i = 0; i < node.Indexes.Count; ++i)
+ this.Visit(node.Indexes[i]);
+ return node;
+ }
+ public override MapType VisitMapType(MapType node)
+ {
+ Contract.Ensures(Contract.Result<MapType>() == node);
+ // not doing anything about the bound variables ... maybe
+ // these should be visited as well ...
+ //
+ // NOTE: when overriding this method, you have to make sure that
+ // the bound variables of the map type are updated correctly
+ for (int i = 0; i < node.Arguments.Count; ++i)
+ this.Visit(node.Arguments[i]);
+ this.Visit(node.Result);
+ return node;
+ }
+ public override Type VisitMapTypeProxy(MapTypeProxy node)
+ {
+ Contract.Ensures(Contract.Result<Type>() == node);
+ // if the type proxy is instantiated with some more
+ // specific type, we visit the instantiation
+ if (node.ProxyFor != null)
+ this.Visit(node.ProxyFor);
+ return this.VisitType(node);
+ }
+
+ public override Expr VisitNAryExpr(NAryExpr node)
+ {
+ Contract.Ensures(Contract.Result<Expr>() == node);
+ this.VisitExprSeq(node.Args);
+ return node;
+ }
+ public override Expr VisitOldExpr(OldExpr node)
+ {
+ Contract.Ensures(Contract.Result<Expr>() == node);
+ this.VisitExpr(node.Expr);
+ return node;
+ }
+ public override Procedure VisitProcedure(Procedure node)
+ {
+ Contract.Ensures(Contract.Result<Procedure>() == node);
+ this.VisitEnsuresSeq(node.Ensures);
+ this.VisitVariableSeq(node.InParams);
+ this.VisitIdentifierExprSeq(node.Modifies);
+ this.VisitVariableSeq(node.OutParams);
+ this.VisitRequiresSeq(node.Requires);
+ return node;
+ }
+ public override Program VisitProgram(Program node)
+ {
+ Contract.Ensures(Contract.Result<Program>() == node);
+ this.VisitDeclarationList(node.TopLevelDeclarations.ToList());
+ return node;
+ }
+ public override QKeyValue VisitQKeyValue(QKeyValue node) {
+ Contract.Ensures(Contract.Result<QKeyValue>() == node);
+ for (int i = 0, n = node.Params.Count; i < n; i++) {
+ var e = node.Params[i] as Expr;
+ if (e != null) {
+ this.Visit(e);
+ }
+ }
+ if (node.Next != null) {
+ this.Visit(node.Next);
+ }
+ return node;
+ }
+ public override BinderExpr VisitBinderExpr(BinderExpr node)
+ {
+ Contract.Ensures(Contract.Result<BinderExpr>() == node);
+ this.VisitExpr(node.Body);
+ this.VisitVariableSeq(node.Dummies);
+ // this.VisitType(node.Type);
+ return node;
+ }
+ public override QuantifierExpr VisitQuantifierExpr(QuantifierExpr node)
+ {
+ Contract.Ensures(Contract.Result<QuantifierExpr>() == node);
+ this.VisitBinderExpr(node);
+ if (node.Triggers != null)
+ {
+ this.VisitTrigger(node.Triggers);
+ }
+ return node;
+ }
+ public override Cmd VisitRE(RE node)
+ {
+ Contract.Ensures(Contract.Result<Cmd>() == node);
+ return (Cmd)this.Visit(node); // Call general visit so subtypes get visited by their particular visitor
+ }
+ public override List<RE> VisitRESeq(List<RE> reSeq)
+ {
+ Contract.Ensures(Contract.Result<List<RE>>() == reSeq);
+ for (int i = 0, n = reSeq.Count; i < n; i++)
+ this.VisitRE(cce.NonNull(reSeq[i]));
+ return reSeq;
+ }
+ public override ReturnCmd VisitReturnCmd(ReturnCmd node)
+ {
+ Contract.Ensures(Contract.Result<ReturnCmd>() == node);
+ return (ReturnCmd)this.VisitTransferCmd(node);
+ }
+ public override ReturnExprCmd VisitReturnExprCmd(ReturnExprCmd node)
+ {
+ Contract.Ensures(Contract.Result<ReturnExprCmd>() == node);
+ this.VisitExpr(node.Expr);
+ return node;
+ }
+ public override Sequential VisitSequential(Sequential node)
+ {
+ Contract.Ensures(Contract.Result<Sequential>() == node);
+ this.VisitRE(node.first);
+ this.VisitRE(node.second);
+ return node;
+ }
+ public override AssignLhs VisitSimpleAssignLhs(SimpleAssignLhs node)
+ {
+ Contract.Ensures(Contract.Result<AssignLhs>() == node);
+ this.VisitIdentifierExpr(node.AssignedVariable);
+ return node;
+ }
+ public override Cmd VisitStateCmd(StateCmd node)
+ {
+ Contract.Ensures(Contract.Result<Cmd>() == node);
+ this.VisitVariableSeq(node.Locals);
+ this.VisitCmdSeq(node.Cmds);
+ return node;
+ }
+ public override TransferCmd VisitTransferCmd(TransferCmd node)
+ {
+ Contract.Ensures(Contract.Result<TransferCmd>() == node);
+ return node;
+ }
+ public override Trigger VisitTrigger(Trigger node)
+ {
+ Contract.Ensures(Contract.Result<Trigger>() == node);
+ Trigger origNext = node.Next;
+ if (origNext != null)
+ {
+ this.VisitTrigger(origNext);
+ }
+ this.VisitExprSeq(node.Tr.ToList());
+ return node;
+ }
+ // called by default for all nullary type constructors and type variables
+ public override Type VisitType(Type node)
+ {
+ Contract.Ensures(Contract.Result<Type>() == node);
+ return node;
+ }
+ public override TypedIdent VisitTypedIdent(TypedIdent node)
+ {
+ Contract.Ensures(Contract.Result<TypedIdent>() == node);
+ this.Visit(node.Type);
+ return node;
+ }
+ public override Declaration VisitTypeCtorDecl(TypeCtorDecl node)
+ {
+ Contract.Ensures(Contract.Result<Declaration>() == node);
+ return this.VisitDeclaration(node);
+ }
+ public override Type VisitTypeSynonymAnnotation(TypeSynonymAnnotation node)
+ {
+ Contract.Ensures(Contract.Result<Type>() == node);
+ node.ExpandedType = cce.NonNull((Type/*!*/)this.Visit(node.ExpandedType));
+ for (int i = 0; i < node.Arguments.Count; ++i)
+ this.Visit(node.Arguments[i]);
+ return node;
+ }
+ public override Declaration VisitTypeSynonymDecl(TypeSynonymDecl node)
+ {
+ Contract.Ensures(Contract.Result<Declaration>() == node);
+ return this.VisitDeclaration(node);
+ }
+ public override Type VisitTypeVariable(TypeVariable node)
+ {
+ Contract.Ensures(Contract.Result<Type>() == node);
+ return this.VisitType(node);
+ }
+ public override Type VisitTypeProxy(TypeProxy node)
+ {
+ Contract.Ensures(Contract.Result<Type>() == node);
+ // if the type proxy is instantiated with some more
+ // specific type, we visit the instantiation
+ if (node.ProxyFor != null)
+ this.Visit(node.ProxyFor);
+ return this.VisitType(node);
+ }
+ public override Type VisitUnresolvedTypeIdentifier(UnresolvedTypeIdentifier node)
+ {
+ Contract.Ensures(Contract.Result<Type>() == node);
+ return this.VisitType(node);
+ }
+ public override Variable VisitVariable(Variable node)
+ {
+ Contract.Ensures(Contract.Result<Variable>() == node);
+ this.VisitTypedIdent(node.TypedIdent);
+ return node;
+ }
+ public override List<Variable> VisitVariableSeq(List<Variable> variableSeq)
+ {
+ Contract.Ensures(Contract.Result<List<Variable>>() == variableSeq);
+ for (int i = 0, n = variableSeq.Count; i < n; i++)
+ this.VisitVariable(cce.NonNull(variableSeq[i]));
+ return variableSeq;
+ }
+ public override YieldCmd VisitYieldCmd(YieldCmd node)
+ {
+ Contract.Ensures(Contract.Result<YieldCmd>() == node);
+ return node;
+ }
+ public override Cmd VisitAssertEnsuresCmd(AssertEnsuresCmd node)
+ {
+ Contract.Ensures(Contract.Result<Cmd>() == node);
+ this.VisitEnsures(node.Ensures);
+ this.VisitExpr(node.Expr);
+ return node;
+ }
+ public override Cmd VisitAssertRequiresCmd(AssertRequiresCmd node)
+ {
+ Contract.Ensures(Contract.Result<Cmd>() == node);
+ this.VisitRequires(node.Requires);
+ this.VisitExpr(node.Expr);
+ return node;
+ }
+ }
+}
diff --git a/Source/Core/TypeAmbiguitySeeker.cs b/Source/Core/TypeAmbiguitySeeker.cs
index 753385a1..6f57ad43 100644
--- a/Source/Core/TypeAmbiguitySeeker.cs
+++ b/Source/Core/TypeAmbiguitySeeker.cs
@@ -1,123 +1,123 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.Diagnostics.Contracts;
-using System.Collections.Generic;
-
-// Visitor to search for types proxies that could not completely be
-// determined by type inference. If this happens, a warning is
-// generated and the proxies are instantiated in a more or less arbitrary
-// fashion.
-
-namespace Microsoft.Boogie {
-
- public class TypeAmbiguitySeeker : ReadOnlyVisitor {
-
- private readonly InTypeSeeker/*!*/ inTypeSeeker = new InTypeSeeker();
- private readonly TypecheckingContext/*!*/ TC;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(inTypeSeeker != null);
- Contract.Invariant(TC != null);
- }
-
-
- public TypeAmbiguitySeeker(TypecheckingContext tc) {
- Contract.Requires(tc != null);
- TC = tc;
- }
-
- private void CheckTypeParams(Absy node, TypeParamInstantiation insts) {
- Contract.Requires(insts != null);
- Contract.Requires(node != null);
- foreach (TypeVariable/*!*/ var in insts.FormalTypeParams) {
- Contract.Assert(var != null);
- Type/*!*/ inst = insts[var];
- Contract.Assert(inst != null);
-
- inTypeSeeker.FoundAmbiguity = false;
- inTypeSeeker.Visit(inst);
- if (inTypeSeeker.FoundAmbiguity)
- TC.Warning(node,
- "type parameter {0} is ambiguous, instantiating to {1}",
- var, inst);
- }
- }
-
- public override Expr VisitNAryExpr(NAryExpr node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Expr>() != null);
- CheckTypeParams(node, cce.NonNull(node.TypeParameters));
- return base.VisitNAryExpr(node);
- }
-
- public override AssignLhs VisitMapAssignLhs(MapAssignLhs node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<AssignLhs>() != null);
- CheckTypeParams(node, cce.NonNull(node.TypeParameters));
- return base.VisitMapAssignLhs(node);
- }
- }
-
- internal class InTypeSeeker : ReadOnlyVisitor {
-
- internal bool FoundAmbiguity = false;
-
- // called when an uninstantiated proxy was found
- private Type Instantiate(Type node, Type inst) {
- Contract.Requires(inst != null);
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Type>() == node);
- FoundAmbiguity = true;
- bool success = node.Unify(inst);
- Contract.Assert(success);
- return node;
- }
-
- public override Type VisitTypeProxy(TypeProxy node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- if (node.ProxyFor != null)
- return base.VisitTypeProxy(node);
-
- return Instantiate(node, Type.Int);
- }
-
- public override Type VisitMapTypeProxy(MapTypeProxy node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- if (node.ProxyFor != null)
- return base.VisitMapTypeProxy(node);
-
- List<TypeVariable>/*!*/ typeParams = new List<TypeVariable>();
- List<Type>/*!*/ arguments = new List<Type>();
- for (int i = 0; i < node.Arity; ++i) {
- TypeVariable/*!*/ param = new TypeVariable(Token.NoToken, "arg" + i);
- Contract.Assert(param != null);
- typeParams.Add(param);
- arguments.Add(param);
- }
- TypeVariable/*!*/ result = new TypeVariable(Token.NoToken, "res");
- Contract.Assert(result != null);
- typeParams.Add(result);
-
- Type/*!*/ instantiation = new MapType(Token.NoToken, typeParams, arguments, result);
- Contract.Assert(instantiation != null);
-
- return Instantiate(node, instantiation);
- }
-
- public override Type VisitBvTypeProxy(BvTypeProxy node) {
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<Type>() != null);
- if (node.ProxyFor != null)
- return base.VisitBvTypeProxy(node);
-
- return Instantiate(node, new BvType(node.MinBits));
- }
- }
-
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+using System;
+using System.Diagnostics.Contracts;
+using System.Collections.Generic;
+
+// Visitor to search for types proxies that could not completely be
+// determined by type inference. If this happens, a warning is
+// generated and the proxies are instantiated in a more or less arbitrary
+// fashion.
+
+namespace Microsoft.Boogie {
+
+ public class TypeAmbiguitySeeker : ReadOnlyVisitor {
+
+ private readonly InTypeSeeker/*!*/ inTypeSeeker = new InTypeSeeker();
+ private readonly TypecheckingContext/*!*/ TC;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(inTypeSeeker != null);
+ Contract.Invariant(TC != null);
+ }
+
+
+ public TypeAmbiguitySeeker(TypecheckingContext tc) {
+ Contract.Requires(tc != null);
+ TC = tc;
+ }
+
+ private void CheckTypeParams(Absy node, TypeParamInstantiation insts) {
+ Contract.Requires(insts != null);
+ Contract.Requires(node != null);
+ foreach (TypeVariable/*!*/ var in insts.FormalTypeParams) {
+ Contract.Assert(var != null);
+ Type/*!*/ inst = insts[var];
+ Contract.Assert(inst != null);
+
+ inTypeSeeker.FoundAmbiguity = false;
+ inTypeSeeker.Visit(inst);
+ if (inTypeSeeker.FoundAmbiguity)
+ TC.Warning(node,
+ "type parameter {0} is ambiguous, instantiating to {1}",
+ var, inst);
+ }
+ }
+
+ public override Expr VisitNAryExpr(NAryExpr node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Expr>() != null);
+ CheckTypeParams(node, cce.NonNull(node.TypeParameters));
+ return base.VisitNAryExpr(node);
+ }
+
+ public override AssignLhs VisitMapAssignLhs(MapAssignLhs node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<AssignLhs>() != null);
+ CheckTypeParams(node, cce.NonNull(node.TypeParameters));
+ return base.VisitMapAssignLhs(node);
+ }
+ }
+
+ internal class InTypeSeeker : ReadOnlyVisitor {
+
+ internal bool FoundAmbiguity = false;
+
+ // called when an uninstantiated proxy was found
+ private Type Instantiate(Type node, Type inst) {
+ Contract.Requires(inst != null);
+ Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Type>() == node);
+ FoundAmbiguity = true;
+ bool success = node.Unify(inst);
+ Contract.Assert(success);
+ return node;
+ }
+
+ public override Type VisitTypeProxy(TypeProxy node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ if (node.ProxyFor != null)
+ return base.VisitTypeProxy(node);
+
+ return Instantiate(node, Type.Int);
+ }
+
+ public override Type VisitMapTypeProxy(MapTypeProxy node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ if (node.ProxyFor != null)
+ return base.VisitMapTypeProxy(node);
+
+ List<TypeVariable>/*!*/ typeParams = new List<TypeVariable>();
+ List<Type>/*!*/ arguments = new List<Type>();
+ for (int i = 0; i < node.Arity; ++i) {
+ TypeVariable/*!*/ param = new TypeVariable(Token.NoToken, "arg" + i);
+ Contract.Assert(param != null);
+ typeParams.Add(param);
+ arguments.Add(param);
+ }
+ TypeVariable/*!*/ result = new TypeVariable(Token.NoToken, "res");
+ Contract.Assert(result != null);
+ typeParams.Add(result);
+
+ Type/*!*/ instantiation = new MapType(Token.NoToken, typeParams, arguments, result);
+ Contract.Assert(instantiation != null);
+
+ return Instantiate(node, instantiation);
+ }
+
+ public override Type VisitBvTypeProxy(BvTypeProxy node) {
+ //Contract.Requires(node != null);
+ Contract.Ensures(Contract.Result<Type>() != null);
+ if (node.ProxyFor != null)
+ return base.VisitBvTypeProxy(node);
+
+ return Instantiate(node, new BvType(node.MinBits));
+ }
+ }
+
} \ No newline at end of file
diff --git a/Source/Core/Util.cs b/Source/Core/Util.cs
index 3b8412b9..f201aef8 100644
--- a/Source/Core/Util.cs
+++ b/Source/Core/Util.cs
@@ -1,688 +1,688 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-namespace Microsoft.Boogie {
- using System;
- using System.IO;
- using System.Collections;
- using System.Diagnostics.Contracts;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
-
- public static class LinqExtender
- {
- public static string Concat(this IEnumerable<string> strings, string separator)
- {
- var sb = new StringBuilder();
- var first = true;
- foreach (var s in strings) {
- if (!first)
- sb.Append(separator);
- first = false;
- sb.Append(s);
- }
- return sb.ToString();
- }
-
- public static IEnumerable<T> Concat1<T>(this IEnumerable<T> objects, T final)
- {
- foreach (var s in objects) {
- yield return s;
- }
- yield return final;
- }
-
- public static string MapConcat<T>(this IEnumerable<T> objects, Func<T,string> toString, string separator)
- {
- var sb = new StringBuilder();
- var first = true;
- foreach (var s in objects) {
- if (!first)
- sb.Append(separator);
- first = false;
- sb.Append(toString(s));
- }
- return sb.ToString();
- }
-
- public static IEnumerable<T> SkipEnd<T>(this IEnumerable<T> source, int count)
- {
- var l = source.ToList();
- if (count >= l.Count)
- return Enumerable.Empty<T>();
- l.RemoveRange(l.Count - count, count);
- return l;
- }
-
- public static void Iter<T>(this IEnumerable<T> coll, Action<T> fn)
- {
- foreach (var e in coll) fn(e);
- }
-
- public static IEnumerable<Tuple<TSource1, TSource2>> Zip<TSource1, TSource2>(this IEnumerable<TSource1> source1, IEnumerable<TSource2> source2)
- {
- return source1.Zip(source2, (e1, e2) => new Tuple<TSource1, TSource2>(e1, e2));
- }
- }
-
- public class TokenTextWriter : IDisposable {
- string/*!*/ filename;
- TextWriter/*!*/ writer;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(filename != null);
- Contract.Invariant(writer != null);
- }
-
- bool setTokens = true;
- int line = 1;
- int col;
- public bool UseForComputingChecksums;
-
- private const int indent_size = 2;
- protected static string Indent(int level) {
- Contract.Ensures(Contract.Result<string>() != null);
- return new string(' ', (indent_size * level));
- }
-
-
- // Keywords, this array *must* be sorted
- public static readonly string[]/*!*/ BplKeywords =
- {
- "assert",
- "assume",
- "axiom",
- "bool",
- "break",
- "call",
- "cast",
- "const",
- "else",
- "ensures",
- "exists",
- "false",
- "forall",
- "free",
- "function",
- "goto",
- "havoc",
- "if",
- "implementation",
- "int",
- "invariant",
- "modifies",
- "old",
- "procedure",
- "public",
- "requires",
- "return",
- "returns",
- "true",
- "type",
- "unique",
- "var",
- "where",
- "while",
- };
-
- // "Pretty" printing: not very efficient, and not necessarily very pretty, but helps a bit
- private readonly bool pretty;
-
- // The stack of writers in a current separator-block.
- // The string is an optional identifier that allows you
- // to not start a new indentation for e.g. "&&" in "a && b && c".
- // When the pretty printing is finished, this should be empty.
- Stack<KeyValuePair<string, List<TextWriter>>> wstk;
-
- // The original writer: where everything should finally end up.
- TextWriter actual_writer;
-
- public bool push(string type = null) {
- if (pretty) {
- if (wstk == null) {
- wstk = new Stack<KeyValuePair<string, List<TextWriter>>>();
- actual_writer = writer;
- }
- if (wstk.Count > 0 && wstk.Peek().Key == type && type != null) {
- sep();
- return false; // don't actually pop this thing (send this bool to pop)
- } else {
- wstk.Push(new KeyValuePair<string, List<TextWriter>>(type, new List<TextWriter> { }));
- sep();
- return true; // this needs to be popped
- }
- } else {
- return false;
- }
- }
-
- public void pop(bool do_it = true) {
- if (pretty) {
- if (do_it) {
- List<TextWriter> ws = wstk.Pop().Value;
- // try to figure out if you should insert line breaks between
- // them or print them on one single line
- // this breaks down when there are newlines inserted
- List<String> ss = new List<String>();
- int len = 0;
- foreach (TextWriter w in ws) {
- foreach (String s in w.ToString().Split(new String[] { "\r\n", "\n" }, StringSplitOptions.None)) {
- if (s.Length > 0) {
- ss.Add(s);
- len += s.Length;
- // len = Math.Max(len, s.Length);
- }
- }
- }
- // figure out which is the next writer to use
- List<TextWriter> tw = wstk.Count > 0 ? wstk.Peek().Value : null;
- if (tw == null) {
- writer = actual_writer;
- } else {
- writer = tw.Last();
- }
- // write the strings (we would like to know WHERE we are in the document here)
- if (len > 80 /* - wstk.Count * 2 */) {
- for (int i = 0; i < ss.Count; i++) {
- if (i != ss.Count - 1) {
- writer.WriteLine(ss[i]);
- writer.Write(" ");
- } else {
- writer.Write(ss[i]);
- }
- }
- } else {
- foreach (String s in ss) {
- writer.Write(s);
- }
- }
- }
- }
- }
-
- public void sep() {
- if (pretty) {
- List<TextWriter> ws = wstk.Peek().Value;
-
- writer = new StringWriter();
- wstk.Peek().Value.Add(writer);
- }
- }
-
- private IToken/*!*/ CurrentToken {
- get {
- Contract.Ensures(Contract.Result<IToken>() != null);
-
- Token token = new Token();
- token.filename = filename;
- token.line = line;
- token.col = col;
- return token;
- }
- }
-
- public void SetToken(Absy absy) {
- Contract.Requires(absy != null);
- this.SetToken(t => absy.tok = t);
- }
-
- public void SetToken(IfThenElse expr)
- {
- Contract.Requires(expr != null);
- this.SetToken(t => expr.tok = t);
- }
-
- public void SetToken(Action<IToken> setter) {
- Contract.Requires(setter != null);
- if (this.setTokens) {
- setter(this.CurrentToken);
- }
- }
-
- public void SetToken(ref IToken tok) {
- Contract.Requires(tok != null);
- if (this.setTokens) {
- tok = this.CurrentToken;
- }
- }
-
- public static string SanitizeIdentifier(string name) {
- Contract.Requires(name != null);
- Contract.Ensures(Contract.Result<string>() != null);
- int index = Array.BinarySearch(TokenTextWriter.BplKeywords, name);
- if (index >= 0) {
- return "\\" + name;
- } else if (name.Length > 2 && name[0] == 'b' && name[1] == 'v') {
- int dummy;
- return int.TryParse(name.Substring(2), out dummy) ? "\\" + name : name;
- } else if (name.Contains('@')) {
- return SanitizeIdentifier(name.Replace("@", "#AT#"));
- } else {
- return name;
- }
- }
-
- public TokenTextWriter(string filename)
- : this(filename, false)
- {
- }
-
- public TokenTextWriter(string filename, bool pretty)
- : base() {
- Contract.Requires(filename != null);
- this.pretty = pretty;
- this.filename = filename;
- this.writer = new StreamWriter(filename);
- }
-
- public TokenTextWriter(string filename, bool setTokens, bool pretty)
- : base() {
- Contract.Requires(filename != null);
- this.pretty = pretty;
- this.filename = filename;
- this.writer = new StreamWriter(filename);
- this.setTokens = setTokens;
- }
-
- public TokenTextWriter(string filename, TextWriter writer, bool setTokens, bool pretty)
- : base() {
- Contract.Requires(writer != null);
- Contract.Requires(filename != null);
- this.pretty = pretty;
- this.filename = filename;
- this.writer = writer;
- this.setTokens = setTokens;
- }
-
- public TokenTextWriter(string filename, TextWriter writer, bool pretty)
- : base() {
- Contract.Requires(writer != null);
- Contract.Requires(filename != null);
- this.pretty = pretty;
- this.filename = filename;
- this.writer = writer;
- }
-
- public TokenTextWriter(TextWriter writer)
- : this(writer, false)
- {
- }
-
- public TokenTextWriter(TextWriter writer, bool pretty)
- : base() {
- Contract.Requires(writer != null);
- this.pretty = pretty;
- this.filename = "<no file>";
- this.writer = writer;
- }
-
- public void Write(string text) {
- Contract.Requires(text != null);
- this.writer.Write(text);
- this.col += text.Length;
- }
-
- public void WriteIndent(int level) {
- if (!UseForComputingChecksums)
- {
- this.Write(Indent(level));
- }
- }
-
- public void Write(string text, params object[] args) {
- Contract.Requires(text != null);
- this.Write(string.Format(text, args));
- }
-
- public void Write(int level, string text) {
- Contract.Requires(text != null);
- this.WriteIndent(level);
- this.Write(text);
- }
-
- public void Write(int level, string text, params object[] args) {
- Contract.Requires(text != null);
- this.WriteIndent(level);
- this.Write(text, args);
- }
-
- public void Write(Absy node, string text) {
- Contract.Requires(text != null);
- Contract.Requires(node != null);
- this.SetToken(node);
- this.Write(text);
- }
-
- public void Write(Absy node, string text, params string[] args) {
- Contract.Requires(text != null);
- Contract.Requires(node != null);
- this.SetToken(node);
- this.Write(text, args);
- }
-
- public void Write(Absy node, int level, string text) {
- Contract.Requires(text != null);
- Contract.Requires(node != null);
- this.WriteIndent(level);
- this.SetToken(node);
- this.Write(text);
- }
-
- public void Write(Absy node, int level, string text, params object[] args) {
- Contract.Requires(text != null);
- Contract.Requires(node != null);
- this.WriteIndent(level);
- this.SetToken(node);
- this.Write(text, args);
- }
-
- public void WriteLine() {
- this.writer.WriteLine();
- this.line++;
- this.col = 0;
- }
-
- public void WriteLine(string text) {
- Contract.Requires(text != null);
- this.writer.WriteLine(text);
- this.line++;
- this.col = 0;
- }
-
- public void WriteText(string text) {
- Contract.Requires(text != null);
- int processed = 0;
- while (true) {
- int n = text.IndexOf('\n', processed);
- if (n == -1) {
- this.writer.Write(text);
- this.col += text.Length - processed;
- return;
- }
- processed = n + 1;
- this.line++;
- this.col = 0;
- }
- }
-
- public void WriteLine(string text, params object[] args) {
- Contract.Requires(text != null);
- this.WriteLine(string.Format(text, args));
- }
-
- public void WriteLine(int level, string text) {
- Contract.Requires(text != null);
- this.WriteIndent(level);
- this.WriteLine(text);
- }
-
- public void WriteLine(int level, string text, params object[] args) {
- Contract.Requires(text != null);
- this.WriteIndent(level);
- this.WriteLine(text, args);
- }
-
- public void WriteLine(Absy node, string text) {
- Contract.Requires(text != null);
- Contract.Requires(node != null);
- this.SetToken(node);
- this.WriteLine(text);
- }
-
- public void WriteLine(Absy node, int level, string text) {
- Contract.Requires(text != null);
- Contract.Requires(node != null);
- this.SetToken(node);
- this.WriteLine(level, text);
- }
-
- public void WriteLine(Absy node, int level, string text, params object[] args) {
- Contract.Requires(text != null);
- Contract.Requires(node != null);
- this.SetToken(node);
- this.WriteLine(level, text, args);
- }
-
- public void Close() {
- this.writer.Close();
- }
-
- public void Dispose() {
- this.Close();
- }
- }
-
- public class Helpers {
- public static string BeautifyBplString(string s) {
- Contract.Requires(s != null);
- Contract.Ensures(Contract.Result<string>() != null);
- // strip "^" if it is the first character, change "$result" to "result"
- if (s.StartsWith("^") || s == "$result") {
- s = s.Substring(1);
- } else if (s.StartsWith("call")) {
- s = s.Substring(s.IndexOf('@') + 1);
- if (s.StartsWith("formal@")) {
- s = "(value of formal parameter: " + s.Substring(7) + ")";
- }
- }
- // strip "$in" from the end of identifier names
- if (s.EndsWith("$in")) {
- return "(initial value of: " + s.Substring(0, s.Length - 3) + ")";
- } else {
- return s;
- }
- }
- public static string PrettyPrintBplExpr(Expr e) {
- Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<string>() != null);
- // anything that is unknown will just be printed via ToString
- // OldExpr and QuantifierExpr, BvExtractExpr, BvConcatExpr are ignored for now
- // LiteralExpr is printed as itself by ToString
- if (e is IdentifierExpr) {
- string s = e.ToString();
- return Helpers.BeautifyBplString(s);
- } else if (e is NAryExpr) {
- NAryExpr ne = (NAryExpr)e;
- IAppliable fun = ne.Fun;
- var eSeq = ne.Args;
- if (fun != null) {
- if ((fun.FunctionName == "$Length" || fun.FunctionName == "$StringLength") && eSeq.Count == 1) {
- Expr e0 = eSeq[0];
- if (e0 != null) {
- string s0 = PrettyPrintBplExpr(e0);
- return s0 + ".Length";
- }
- //unexpected, just fall outside to the default
- } else if (fun.FunctionName == "$typeof" && eSeq.Count == 1) {
- Expr e0 = eSeq[0];
- if (e0 != null) {
- string s0 = PrettyPrintBplExpr(e0);
- return "(the dynamic type of: " + s0 + ")";
- }
- //unexpected, just fall outside to the default
- } else if (fun.FunctionName == "IntArrayGet" && eSeq.Count == 2) {
- Expr e0 = eSeq[0];
- Expr e1 = eSeq[1];
- if (e0 != null && e1 != null) {
- string s0 = PrettyPrintBplExpr(e0);
- string s1 = PrettyPrintBplExpr(e1);
- return s0 + "[" + s1 + "]";
- }
- //unexpected, just fall outside to the default
- } else if (fun.FunctionName == "$Is" && eSeq.Count == 2) {
- Expr e0 = eSeq[0];
- Expr e1 = eSeq[1];
- if (e0 != null && e1 != null) {
- string s0 = PrettyPrintBplExpr(e0);
- string s1 = PrettyPrintBplExpr(e1);
- return "(" + s0 + " == null || (" + s0 + " is " + s1 + "))";
- }
- //unexpected, just fall outside to the default
- } else if (fun.FunctionName == "$IsNotNull" && eSeq.Count == 2) {
- Expr e0 = eSeq[0];
- Expr e1 = eSeq[1];
- if (e0 != null && e1 != null) {
- string s0 = PrettyPrintBplExpr(e0);
- string s1 = PrettyPrintBplExpr(e1);
- return "(" + s0 + " is " + s1 + ")";
- }
- //unexpected, just fall outside to the default
- } else if (fun is MapSelect && eSeq.Count <= 3) {
- // only maps with up to two arguments are supported right now (here)
- if (cce.NonNull(eSeq[0]).ToString() == "$Heap") {
- //print Index0.Index1, unless Index1 is "$elements", then just print Index0
- string s0 = PrettyPrintBplExpr(cce.NonNull(eSeq[1]));
- if (eSeq.Count > 2) {
- string s1 = PrettyPrintBplExpr(cce.NonNull(eSeq[2]));
- if (s1 == "$elements") {
- return s0;
- } else {
- if (eSeq[2] is IdentifierExpr) {
- // strip the class name out of a fieldname
- s1 = s1.Substring(s1.LastIndexOf('.') + 1);
- }
- return s0 + "." + s1;
- }
- }
- }
- //unexpected, just fall outside to the default
- } else if (fun is Microsoft.Boogie.BinaryOperator && eSeq.Count == 2) {
- Microsoft.Boogie.BinaryOperator f = (Microsoft.Boogie.BinaryOperator)fun;
- Expr e0 = eSeq[0];
- Expr e1 = eSeq[1];
- if (e0 != null && e1 != null) {
- string s0 = PrettyPrintBplExpr(e0);
- string s1 = PrettyPrintBplExpr(e1);
- string op = "";
- switch (f.Op) {
- case Microsoft.Boogie.BinaryOperator.Opcode.Add:
- op = " + ";
- break;
- case Microsoft.Boogie.BinaryOperator.Opcode.And:
- op = " && ";
- break;
- case Microsoft.Boogie.BinaryOperator.Opcode.Div:
- op = " div ";
- break;
- case Microsoft.Boogie.BinaryOperator.Opcode.Eq:
- op = " == ";
- break;
- case Microsoft.Boogie.BinaryOperator.Opcode.Ge:
- op = " >= ";
- break;
- case Microsoft.Boogie.BinaryOperator.Opcode.Gt:
- op = " > ";
- break;
- case Microsoft.Boogie.BinaryOperator.Opcode.Iff:
- op = " <==> ";
- break;
- case Microsoft.Boogie.BinaryOperator.Opcode.Imp:
- op = " ==> ";
- break;
- case Microsoft.Boogie.BinaryOperator.Opcode.Le:
- op = " <= ";
- break;
- case Microsoft.Boogie.BinaryOperator.Opcode.Lt:
- op = " < ";
- break;
- case Microsoft.Boogie.BinaryOperator.Opcode.Mod:
- op = " mod ";
- break;
- case Microsoft.Boogie.BinaryOperator.Opcode.Mul:
- op = " * ";
- break;
- case Microsoft.Boogie.BinaryOperator.Opcode.Neq:
- op = " != ";
- break;
- case Microsoft.Boogie.BinaryOperator.Opcode.Or:
- op = " || ";
- break;
- case Microsoft.Boogie.BinaryOperator.Opcode.Pow:
- op = " ** ";
- break;
- case Microsoft.Boogie.BinaryOperator.Opcode.RealDiv:
- op = " / ";
- break;
- case Microsoft.Boogie.BinaryOperator.Opcode.Sub:
- op = " - ";
- break;
- case Microsoft.Boogie.BinaryOperator.Opcode.Subtype:
- op = " <: ";
- break;
- default:
- op = " ";
- break;
- }
- return "(" + s0 + op + s1 + ")";
- }
- //unexpected, just fall outside to the default
- } else {
- string s = fun.FunctionName + "(";
- for (int i = 0; i < eSeq.Count; i++) {
- Expr ex = eSeq[i];
- Contract.Assume(ex != null);
- if (i > 0) {
- s += ", ";
- }
- string t = PrettyPrintBplExpr(ex);
- if (t.StartsWith("(") && t.EndsWith(")")) {
- t = t.Substring(1, t.Length - 2);
- }
- s += t;
- }
- s += ")";
- return s;
- //unexpected, just fall outside to the default
- }
- }
- }
-
- return e.ToString();
- }
-
- private static readonly DateTime StartUp = DateTime.UtcNow;
-
- public static void ExtraTraceInformation(string point) {
- Contract.Requires(point != null);
- if (CommandLineOptions.Clo.TraceTimes) {
- DateTime now = DateTime.UtcNow;
- TimeSpan timeSinceStartUp = now - StartUp;
- Console.WriteLine(">>> {0} [{1} s]", point, timeSinceStartUp.TotalSeconds);
- }
- }
-
- // Substitute @PROC@ in a filename with the given descName
- public static string SubstituteAtPROC(string descName, string fileName) {
- Contract.Requires(fileName != null);
- Contract.Requires(descName != null);
- Contract.Ensures(Contract.Result<string>() != null);
- System.Text.StringBuilder/*!*/ sb =
- new System.Text.StringBuilder(descName.Length);
- // quote the name, characters like ^ cause trouble in CMD
- // while $ could cause trouble in SH
- foreach (char c in descName) {
- if (Char.IsLetterOrDigit(c) || c == '.') {
- sb.Append(c);
- } else {
- sb.Append('_');
- }
- }
- string pn = sb.ToString();
- // We attempt to avoid filenames that are too long, but we only
- // do it by truncating the @PROC@ replacement, which leaves unchanged
- // any filename extension specified by the user. We base our
- // calculations on that there is at most one occurrence of @PROC@.
- if (180 <= fileName.Length - 6 + pn.Length) {
- pn = pn.Substring(0, Math.Max(180 - (fileName.Length - 6), 0)) + "-n" + System.Threading.Interlocked.Increment(ref sequenceId);
- }
-
- return fileName.Replace("@PROC@", pn);
- }
-
- private static int sequenceId = -1;
-
- }
-}
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+namespace Microsoft.Boogie {
+ using System;
+ using System.IO;
+ using System.Collections;
+ using System.Diagnostics.Contracts;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ public static class LinqExtender
+ {
+ public static string Concat(this IEnumerable<string> strings, string separator)
+ {
+ var sb = new StringBuilder();
+ var first = true;
+ foreach (var s in strings) {
+ if (!first)
+ sb.Append(separator);
+ first = false;
+ sb.Append(s);
+ }
+ return sb.ToString();
+ }
+
+ public static IEnumerable<T> Concat1<T>(this IEnumerable<T> objects, T final)
+ {
+ foreach (var s in objects) {
+ yield return s;
+ }
+ yield return final;
+ }
+
+ public static string MapConcat<T>(this IEnumerable<T> objects, Func<T,string> toString, string separator)
+ {
+ var sb = new StringBuilder();
+ var first = true;
+ foreach (var s in objects) {
+ if (!first)
+ sb.Append(separator);
+ first = false;
+ sb.Append(toString(s));
+ }
+ return sb.ToString();
+ }
+
+ public static IEnumerable<T> SkipEnd<T>(this IEnumerable<T> source, int count)
+ {
+ var l = source.ToList();
+ if (count >= l.Count)
+ return Enumerable.Empty<T>();
+ l.RemoveRange(l.Count - count, count);
+ return l;
+ }
+
+ public static void Iter<T>(this IEnumerable<T> coll, Action<T> fn)
+ {
+ foreach (var e in coll) fn(e);
+ }
+
+ public static IEnumerable<Tuple<TSource1, TSource2>> Zip<TSource1, TSource2>(this IEnumerable<TSource1> source1, IEnumerable<TSource2> source2)
+ {
+ return source1.Zip(source2, (e1, e2) => new Tuple<TSource1, TSource2>(e1, e2));
+ }
+ }
+
+ public class TokenTextWriter : IDisposable {
+ string/*!*/ filename;
+ TextWriter/*!*/ writer;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(filename != null);
+ Contract.Invariant(writer != null);
+ }
+
+ bool setTokens = true;
+ int line = 1;
+ int col;
+ public bool UseForComputingChecksums;
+
+ private const int indent_size = 2;
+ protected static string Indent(int level) {
+ Contract.Ensures(Contract.Result<string>() != null);
+ return new string(' ', (indent_size * level));
+ }
+
+
+ // Keywords, this array *must* be sorted
+ public static readonly string[]/*!*/ BplKeywords =
+ {
+ "assert",
+ "assume",
+ "axiom",
+ "bool",
+ "break",
+ "call",
+ "cast",
+ "const",
+ "else",
+ "ensures",
+ "exists",
+ "false",
+ "forall",
+ "free",
+ "function",
+ "goto",
+ "havoc",
+ "if",
+ "implementation",
+ "int",
+ "invariant",
+ "modifies",
+ "old",
+ "procedure",
+ "public",
+ "requires",
+ "return",
+ "returns",
+ "true",
+ "type",
+ "unique",
+ "var",
+ "where",
+ "while",
+ };
+
+ // "Pretty" printing: not very efficient, and not necessarily very pretty, but helps a bit
+ private readonly bool pretty;
+
+ // The stack of writers in a current separator-block.
+ // The string is an optional identifier that allows you
+ // to not start a new indentation for e.g. "&&" in "a && b && c".
+ // When the pretty printing is finished, this should be empty.
+ Stack<KeyValuePair<string, List<TextWriter>>> wstk;
+
+ // The original writer: where everything should finally end up.
+ TextWriter actual_writer;
+
+ public bool push(string type = null) {
+ if (pretty) {
+ if (wstk == null) {
+ wstk = new Stack<KeyValuePair<string, List<TextWriter>>>();
+ actual_writer = writer;
+ }
+ if (wstk.Count > 0 && wstk.Peek().Key == type && type != null) {
+ sep();
+ return false; // don't actually pop this thing (send this bool to pop)
+ } else {
+ wstk.Push(new KeyValuePair<string, List<TextWriter>>(type, new List<TextWriter> { }));
+ sep();
+ return true; // this needs to be popped
+ }
+ } else {
+ return false;
+ }
+ }
+
+ public void pop(bool do_it = true) {
+ if (pretty) {
+ if (do_it) {
+ List<TextWriter> ws = wstk.Pop().Value;
+ // try to figure out if you should insert line breaks between
+ // them or print them on one single line
+ // this breaks down when there are newlines inserted
+ List<String> ss = new List<String>();
+ int len = 0;
+ foreach (TextWriter w in ws) {
+ foreach (String s in w.ToString().Split(new String[] { "\r\n", "\n" }, StringSplitOptions.None)) {
+ if (s.Length > 0) {
+ ss.Add(s);
+ len += s.Length;
+ // len = Math.Max(len, s.Length);
+ }
+ }
+ }
+ // figure out which is the next writer to use
+ List<TextWriter> tw = wstk.Count > 0 ? wstk.Peek().Value : null;
+ if (tw == null) {
+ writer = actual_writer;
+ } else {
+ writer = tw.Last();
+ }
+ // write the strings (we would like to know WHERE we are in the document here)
+ if (len > 80 /* - wstk.Count * 2 */) {
+ for (int i = 0; i < ss.Count; i++) {
+ if (i != ss.Count - 1) {
+ writer.WriteLine(ss[i]);
+ writer.Write(" ");
+ } else {
+ writer.Write(ss[i]);
+ }
+ }
+ } else {
+ foreach (String s in ss) {
+ writer.Write(s);
+ }
+ }
+ }
+ }
+ }
+
+ public void sep() {
+ if (pretty) {
+ List<TextWriter> ws = wstk.Peek().Value;
+
+ writer = new StringWriter();
+ wstk.Peek().Value.Add(writer);
+ }
+ }
+
+ private IToken/*!*/ CurrentToken {
+ get {
+ Contract.Ensures(Contract.Result<IToken>() != null);
+
+ Token token = new Token();
+ token.filename = filename;
+ token.line = line;
+ token.col = col;
+ return token;
+ }
+ }
+
+ public void SetToken(Absy absy) {
+ Contract.Requires(absy != null);
+ this.SetToken(t => absy.tok = t);
+ }
+
+ public void SetToken(IfThenElse expr)
+ {
+ Contract.Requires(expr != null);
+ this.SetToken(t => expr.tok = t);
+ }
+
+ public void SetToken(Action<IToken> setter) {
+ Contract.Requires(setter != null);
+ if (this.setTokens) {
+ setter(this.CurrentToken);
+ }
+ }
+
+ public void SetToken(ref IToken tok) {
+ Contract.Requires(tok != null);
+ if (this.setTokens) {
+ tok = this.CurrentToken;
+ }
+ }
+
+ public static string SanitizeIdentifier(string name) {
+ Contract.Requires(name != null);
+ Contract.Ensures(Contract.Result<string>() != null);
+ int index = Array.BinarySearch(TokenTextWriter.BplKeywords, name);
+ if (index >= 0) {
+ return "\\" + name;
+ } else if (name.Length > 2 && name[0] == 'b' && name[1] == 'v') {
+ int dummy;
+ return int.TryParse(name.Substring(2), out dummy) ? "\\" + name : name;
+ } else if (name.Contains('@')) {
+ return SanitizeIdentifier(name.Replace("@", "#AT#"));
+ } else {
+ return name;
+ }
+ }
+
+ public TokenTextWriter(string filename)
+ : this(filename, false)
+ {
+ }
+
+ public TokenTextWriter(string filename, bool pretty)
+ : base() {
+ Contract.Requires(filename != null);
+ this.pretty = pretty;
+ this.filename = filename;
+ this.writer = new StreamWriter(filename);
+ }
+
+ public TokenTextWriter(string filename, bool setTokens, bool pretty)
+ : base() {
+ Contract.Requires(filename != null);
+ this.pretty = pretty;
+ this.filename = filename;
+ this.writer = new StreamWriter(filename);
+ this.setTokens = setTokens;
+ }
+
+ public TokenTextWriter(string filename, TextWriter writer, bool setTokens, bool pretty)
+ : base() {
+ Contract.Requires(writer != null);
+ Contract.Requires(filename != null);
+ this.pretty = pretty;
+ this.filename = filename;
+ this.writer = writer;
+ this.setTokens = setTokens;
+ }
+
+ public TokenTextWriter(string filename, TextWriter writer, bool pretty)
+ : base() {
+ Contract.Requires(writer != null);
+ Contract.Requires(filename != null);
+ this.pretty = pretty;
+ this.filename = filename;
+ this.writer = writer;
+ }
+
+ public TokenTextWriter(TextWriter writer)
+ : this(writer, false)
+ {
+ }
+
+ public TokenTextWriter(TextWriter writer, bool pretty)
+ : base() {
+ Contract.Requires(writer != null);
+ this.pretty = pretty;
+ this.filename = "<no file>";
+ this.writer = writer;
+ }
+
+ public void Write(string text) {
+ Contract.Requires(text != null);
+ this.writer.Write(text);
+ this.col += text.Length;
+ }
+
+ public void WriteIndent(int level) {
+ if (!UseForComputingChecksums)
+ {
+ this.Write(Indent(level));
+ }
+ }
+
+ public void Write(string text, params object[] args) {
+ Contract.Requires(text != null);
+ this.Write(string.Format(text, args));
+ }
+
+ public void Write(int level, string text) {
+ Contract.Requires(text != null);
+ this.WriteIndent(level);
+ this.Write(text);
+ }
+
+ public void Write(int level, string text, params object[] args) {
+ Contract.Requires(text != null);
+ this.WriteIndent(level);
+ this.Write(text, args);
+ }
+
+ public void Write(Absy node, string text) {
+ Contract.Requires(text != null);
+ Contract.Requires(node != null);
+ this.SetToken(node);
+ this.Write(text);
+ }
+
+ public void Write(Absy node, string text, params string[] args) {
+ Contract.Requires(text != null);
+ Contract.Requires(node != null);
+ this.SetToken(node);
+ this.Write(text, args);
+ }
+
+ public void Write(Absy node, int level, string text) {
+ Contract.Requires(text != null);
+ Contract.Requires(node != null);
+ this.WriteIndent(level);
+ this.SetToken(node);
+ this.Write(text);
+ }
+
+ public void Write(Absy node, int level, string text, params object[] args) {
+ Contract.Requires(text != null);
+ Contract.Requires(node != null);
+ this.WriteIndent(level);
+ this.SetToken(node);
+ this.Write(text, args);
+ }
+
+ public void WriteLine() {
+ this.writer.WriteLine();
+ this.line++;
+ this.col = 0;
+ }
+
+ public void WriteLine(string text) {
+ Contract.Requires(text != null);
+ this.writer.WriteLine(text);
+ this.line++;
+ this.col = 0;
+ }
+
+ public void WriteText(string text) {
+ Contract.Requires(text != null);
+ int processed = 0;
+ while (true) {
+ int n = text.IndexOf('\n', processed);
+ if (n == -1) {
+ this.writer.Write(text);
+ this.col += text.Length - processed;
+ return;
+ }
+ processed = n + 1;
+ this.line++;
+ this.col = 0;
+ }
+ }
+
+ public void WriteLine(string text, params object[] args) {
+ Contract.Requires(text != null);
+ this.WriteLine(string.Format(text, args));
+ }
+
+ public void WriteLine(int level, string text) {
+ Contract.Requires(text != null);
+ this.WriteIndent(level);
+ this.WriteLine(text);
+ }
+
+ public void WriteLine(int level, string text, params object[] args) {
+ Contract.Requires(text != null);
+ this.WriteIndent(level);
+ this.WriteLine(text, args);
+ }
+
+ public void WriteLine(Absy node, string text) {
+ Contract.Requires(text != null);
+ Contract.Requires(node != null);
+ this.SetToken(node);
+ this.WriteLine(text);
+ }
+
+ public void WriteLine(Absy node, int level, string text) {
+ Contract.Requires(text != null);
+ Contract.Requires(node != null);
+ this.SetToken(node);
+ this.WriteLine(level, text);
+ }
+
+ public void WriteLine(Absy node, int level, string text, params object[] args) {
+ Contract.Requires(text != null);
+ Contract.Requires(node != null);
+ this.SetToken(node);
+ this.WriteLine(level, text, args);
+ }
+
+ public void Close() {
+ this.writer.Close();
+ }
+
+ public void Dispose() {
+ this.Close();
+ }
+ }
+
+ public class Helpers {
+ public static string BeautifyBplString(string s) {
+ Contract.Requires(s != null);
+ Contract.Ensures(Contract.Result<string>() != null);
+ // strip "^" if it is the first character, change "$result" to "result"
+ if (s.StartsWith("^") || s == "$result") {
+ s = s.Substring(1);
+ } else if (s.StartsWith("call")) {
+ s = s.Substring(s.IndexOf('@') + 1);
+ if (s.StartsWith("formal@")) {
+ s = "(value of formal parameter: " + s.Substring(7) + ")";
+ }
+ }
+ // strip "$in" from the end of identifier names
+ if (s.EndsWith("$in")) {
+ return "(initial value of: " + s.Substring(0, s.Length - 3) + ")";
+ } else {
+ return s;
+ }
+ }
+ public static string PrettyPrintBplExpr(Expr e) {
+ Contract.Requires(e != null);
+ Contract.Ensures(Contract.Result<string>() != null);
+ // anything that is unknown will just be printed via ToString
+ // OldExpr and QuantifierExpr, BvExtractExpr, BvConcatExpr are ignored for now
+ // LiteralExpr is printed as itself by ToString
+ if (e is IdentifierExpr) {
+ string s = e.ToString();
+ return Helpers.BeautifyBplString(s);
+ } else if (e is NAryExpr) {
+ NAryExpr ne = (NAryExpr)e;
+ IAppliable fun = ne.Fun;
+ var eSeq = ne.Args;
+ if (fun != null) {
+ if ((fun.FunctionName == "$Length" || fun.FunctionName == "$StringLength") && eSeq.Count == 1) {
+ Expr e0 = eSeq[0];
+ if (e0 != null) {
+ string s0 = PrettyPrintBplExpr(e0);
+ return s0 + ".Length";
+ }
+ //unexpected, just fall outside to the default
+ } else if (fun.FunctionName == "$typeof" && eSeq.Count == 1) {
+ Expr e0 = eSeq[0];
+ if (e0 != null) {
+ string s0 = PrettyPrintBplExpr(e0);
+ return "(the dynamic type of: " + s0 + ")";
+ }
+ //unexpected, just fall outside to the default
+ } else if (fun.FunctionName == "IntArrayGet" && eSeq.Count == 2) {
+ Expr e0 = eSeq[0];
+ Expr e1 = eSeq[1];
+ if (e0 != null && e1 != null) {
+ string s0 = PrettyPrintBplExpr(e0);
+ string s1 = PrettyPrintBplExpr(e1);
+ return s0 + "[" + s1 + "]";
+ }
+ //unexpected, just fall outside to the default
+ } else if (fun.FunctionName == "$Is" && eSeq.Count == 2) {
+ Expr e0 = eSeq[0];
+ Expr e1 = eSeq[1];
+ if (e0 != null && e1 != null) {
+ string s0 = PrettyPrintBplExpr(e0);
+ string s1 = PrettyPrintBplExpr(e1);
+ return "(" + s0 + " == null || (" + s0 + " is " + s1 + "))";
+ }
+ //unexpected, just fall outside to the default
+ } else if (fun.FunctionName == "$IsNotNull" && eSeq.Count == 2) {
+ Expr e0 = eSeq[0];
+ Expr e1 = eSeq[1];
+ if (e0 != null && e1 != null) {
+ string s0 = PrettyPrintBplExpr(e0);
+ string s1 = PrettyPrintBplExpr(e1);
+ return "(" + s0 + " is " + s1 + ")";
+ }
+ //unexpected, just fall outside to the default
+ } else if (fun is MapSelect && eSeq.Count <= 3) {
+ // only maps with up to two arguments are supported right now (here)
+ if (cce.NonNull(eSeq[0]).ToString() == "$Heap") {
+ //print Index0.Index1, unless Index1 is "$elements", then just print Index0
+ string s0 = PrettyPrintBplExpr(cce.NonNull(eSeq[1]));
+ if (eSeq.Count > 2) {
+ string s1 = PrettyPrintBplExpr(cce.NonNull(eSeq[2]));
+ if (s1 == "$elements") {
+ return s0;
+ } else {
+ if (eSeq[2] is IdentifierExpr) {
+ // strip the class name out of a fieldname
+ s1 = s1.Substring(s1.LastIndexOf('.') + 1);
+ }
+ return s0 + "." + s1;
+ }
+ }
+ }
+ //unexpected, just fall outside to the default
+ } else if (fun is Microsoft.Boogie.BinaryOperator && eSeq.Count == 2) {
+ Microsoft.Boogie.BinaryOperator f = (Microsoft.Boogie.BinaryOperator)fun;
+ Expr e0 = eSeq[0];
+ Expr e1 = eSeq[1];
+ if (e0 != null && e1 != null) {
+ string s0 = PrettyPrintBplExpr(e0);
+ string s1 = PrettyPrintBplExpr(e1);
+ string op = "";
+ switch (f.Op) {
+ case Microsoft.Boogie.BinaryOperator.Opcode.Add:
+ op = " + ";
+ break;
+ case Microsoft.Boogie.BinaryOperator.Opcode.And:
+ op = " && ";
+ break;
+ case Microsoft.Boogie.BinaryOperator.Opcode.Div:
+ op = " div ";
+ break;
+ case Microsoft.Boogie.BinaryOperator.Opcode.Eq:
+ op = " == ";
+ break;
+ case Microsoft.Boogie.BinaryOperator.Opcode.Ge:
+ op = " >= ";
+ break;
+ case Microsoft.Boogie.BinaryOperator.Opcode.Gt:
+ op = " > ";
+ break;
+ case Microsoft.Boogie.BinaryOperator.Opcode.Iff:
+ op = " <==> ";
+ break;
+ case Microsoft.Boogie.BinaryOperator.Opcode.Imp:
+ op = " ==> ";
+ break;
+ case Microsoft.Boogie.BinaryOperator.Opcode.Le:
+ op = " <= ";
+ break;
+ case Microsoft.Boogie.BinaryOperator.Opcode.Lt:
+ op = " < ";
+ break;
+ case Microsoft.Boogie.BinaryOperator.Opcode.Mod:
+ op = " mod ";
+ break;
+ case Microsoft.Boogie.BinaryOperator.Opcode.Mul:
+ op = " * ";
+ break;
+ case Microsoft.Boogie.BinaryOperator.Opcode.Neq:
+ op = " != ";
+ break;
+ case Microsoft.Boogie.BinaryOperator.Opcode.Or:
+ op = " || ";
+ break;
+ case Microsoft.Boogie.BinaryOperator.Opcode.Pow:
+ op = " ** ";
+ break;
+ case Microsoft.Boogie.BinaryOperator.Opcode.RealDiv:
+ op = " / ";
+ break;
+ case Microsoft.Boogie.BinaryOperator.Opcode.Sub:
+ op = " - ";
+ break;
+ case Microsoft.Boogie.BinaryOperator.Opcode.Subtype:
+ op = " <: ";
+ break;
+ default:
+ op = " ";
+ break;
+ }
+ return "(" + s0 + op + s1 + ")";
+ }
+ //unexpected, just fall outside to the default
+ } else {
+ string s = fun.FunctionName + "(";
+ for (int i = 0; i < eSeq.Count; i++) {
+ Expr ex = eSeq[i];
+ Contract.Assume(ex != null);
+ if (i > 0) {
+ s += ", ";
+ }
+ string t = PrettyPrintBplExpr(ex);
+ if (t.StartsWith("(") && t.EndsWith(")")) {
+ t = t.Substring(1, t.Length - 2);
+ }
+ s += t;
+ }
+ s += ")";
+ return s;
+ //unexpected, just fall outside to the default
+ }
+ }
+ }
+
+ return e.ToString();
+ }
+
+ private static readonly DateTime StartUp = DateTime.UtcNow;
+
+ public static void ExtraTraceInformation(string point) {
+ Contract.Requires(point != null);
+ if (CommandLineOptions.Clo.TraceTimes) {
+ DateTime now = DateTime.UtcNow;
+ TimeSpan timeSinceStartUp = now - StartUp;
+ Console.WriteLine(">>> {0} [{1} s]", point, timeSinceStartUp.TotalSeconds);
+ }
+ }
+
+ // Substitute @PROC@ in a filename with the given descName
+ public static string SubstituteAtPROC(string descName, string fileName) {
+ Contract.Requires(fileName != null);
+ Contract.Requires(descName != null);
+ Contract.Ensures(Contract.Result<string>() != null);
+ System.Text.StringBuilder/*!*/ sb =
+ new System.Text.StringBuilder(descName.Length);
+ // quote the name, characters like ^ cause trouble in CMD
+ // while $ could cause trouble in SH
+ foreach (char c in descName) {
+ if (Char.IsLetterOrDigit(c) || c == '.') {
+ sb.Append(c);
+ } else {
+ sb.Append('_');
+ }
+ }
+ string pn = sb.ToString();
+ // We attempt to avoid filenames that are too long, but we only
+ // do it by truncating the @PROC@ replacement, which leaves unchanged
+ // any filename extension specified by the user. We base our
+ // calculations on that there is at most one occurrence of @PROC@.
+ if (180 <= fileName.Length - 6 + pn.Length) {
+ pn = pn.Substring(0, Math.Max(180 - (fileName.Length - 6), 0)) + "-n" + System.Threading.Interlocked.Increment(ref sequenceId);
+ }
+
+ return fileName.Replace("@PROC@", pn);
+ }
+
+ private static int sequenceId = -1;
+
+ }
+}
diff --git a/Source/Core/VCExp.cs b/Source/Core/VCExp.cs
index 87b8f3e6..63dca024 100644
--- a/Source/Core/VCExp.cs
+++ b/Source/Core/VCExp.cs
@@ -1,238 +1,238 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.IO;
-using System.Collections;
-using System.Collections.Generic;
-using System.Reflection;
-using System.Text;
-using System.Diagnostics.Contracts;
-using Microsoft.Basetypes;
-namespace Microsoft.Boogie {
-
- public class ProverOptions {
- public class OptionException : Exception {
- public OptionException(string msg)
- : base(msg) {
- Contract.Requires(msg != null);
- }
- }
-
- public string/*?*/ LogFilename = null;
- public bool AppendLogFile = false;
- public bool SeparateLogFiles = false;
- // Say (DBG_WAS_VALID) or (DBG_WAS_INVALID) after query
- public bool ForceLogStatus = false;
- public int TimeLimit = 0;
- public int MemoryLimit = 0;
- public int Verbosity = 0;
- public string ProverPath;
-
- private string/*!*/ stringRepr = "";
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(stringRepr != null);
- }
-
-
- [Pure]
- public override string ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- return stringRepr;
- }
-
- // The usual thing to override.
- protected virtual bool Parse(string opt) {
- Contract.Requires(opt != null);
- return ParseString(opt, "LOG_FILE", ref LogFilename) ||
- ParseBool(opt, "APPEND_LOG_FILE", ref AppendLogFile) ||
- ParseBool(opt, "FORCE_LOG_STATUS", ref ForceLogStatus) ||
- ParseInt(opt, "MEMORY_LIMIT", ref MemoryLimit) ||
- ParseInt(opt, "VERBOSITY", ref Verbosity) ||
- ParseInt(opt, "TIME_LIMIT", ref TimeLimit) ||
- ParseString(opt, "PROVER_PATH", ref ProverPath);
- // || base.Parse(opt)
- }
-
- public virtual string Help
- {
- get
- {
- return
-@"
-Generic prover options :
-~~~~~~~~~~~~~~~~~~~~~~~
-LOG_FILE=<string> Log input for the theorem prover. The string @PROC@ in the filename
- causes there to be one prover log file per verification condition,
- and is expanded to the name of the procedure that the verification
- condition is for.
-APPEND_LOG_FILE=<bool> Append, rather than overwrite the log file.
-MEMORY_LIMIT=<int> Memory limit of the prover in megabytes.
-VERBOSITY=<int> The higher, the more verbose.
-TIME_LIMIT=<int> Time limit per verification condition in miliseconds.
-PROVER_PATH=<string> Path to the prover to use.
-
-The generic options may or may not be used by the prover plugin.
-";
-
- }
- }
-
- public virtual void Parse(IEnumerable<string/*!*/>/*!*/ opts) {
- Contract.Requires(cce.NonNullElements(opts));
- StringBuilder sb = new StringBuilder(stringRepr);
- Contract.Assert(sb != null);
- foreach (string/*!*/ opt in opts) {
- Contract.Assert(opt != null);
- if (!Parse(opt)) {
- ReportError("Unrecognised prover option: " + opt);
- }
- sb.Append(opt).Append(" ");
- }
- stringRepr = sb.ToString();
- PostParse();
- }
-
- public virtual void PostParse() {
- if (LogFilename != null && LogFilename.Contains("@PROC@")) {
- SeparateLogFiles = true;
- }
- }
-
- protected void ReportError(string msg) {
- Contract.Requires(msg != null);
- throw new OptionException(msg + "\n\n" + Help);
- }
-
- protected virtual bool ParseString(string opt, string name, ref string field) {
- Contract.Requires(name != null);
- Contract.Requires(opt != null);
- if (opt.Length >= name.Length && opt.StartsWith(name)) {
- if (opt.Length == name.Length) {
- field = "";
- return true;
- } else if (opt[name.Length] == '=' || opt[name.Length] == ':') {
- field = opt.Substring(name.Length + 1);
- return true;
- }
- }
- return false;
- }
-
- protected virtual bool ParseBool(string opt, string name, ref bool field) {
- Contract.Requires(name != null);
- Contract.Requires(opt != null);
- string tmp = null;
- if (ParseString(opt, name, ref tmp))
- switch (cce.NonNull(tmp).ToLower()) {
- case "1":
- case "true":
- case "":
- field = true;
- return true;
- case "0":
- case "false":
- field = false;
- return true;
- default:
- ReportError("Invalid Boolean option \"" + opt + "\"");
- return false;
- }
- return false;
- }
-
- protected virtual bool ParseInt(string opt, string name, ref int field) {
- Contract.Requires(name != null);
- Contract.Requires(opt != null);
- string tmp = null;
- int t2;
- if (ParseString(opt, name, ref tmp)) {
- if (int.TryParse(cce.NonNull(tmp), out t2)) {
- field = t2;
- return true;
- } else {
- ReportError("Invalid integer option \"" + opt + "\"");
- }
- }
- return false;
- }
-
- public virtual TextWriter OpenLog(string/*?*/ descName) {
- if (LogFilename != null) {
- string filename = LogFilename;
- Contract.Assert(filename != null);
- if (descName != null)
- filename = Helpers.SubstituteAtPROC(descName, filename);
- return new StreamWriter(filename, AppendLogFile);
- } else {
- return null;
- }
- }
- }
-
- [ContractClass(typeof(ProverFactoryContracts))]
- public abstract class ProverFactory {
- // Really returns ProverInterface.
- //public abstract object! SpawnProver(ProverOptions! options, object! ctxt);
- public abstract object SpawnProver(ProverOptions options, object ctxt);
-
- // Really returns ProverContext
- public abstract object/*!*/ NewProverContext(ProverOptions/*!*/ options);
-
- public virtual ProverOptions BlankProverOptions() {
- Contract.Ensures(Contract.Result<ProverOptions>() != null);
- return new ProverOptions();
- }
-
- // return true if the prover supports DAG AST as opposed to LET AST
- public virtual bool SupportsDags {
- get {
- return false;
- }
- }
-
- public virtual CommandLineOptions.VCVariety DefaultVCVariety {
- get {
- Contract.Ensures(Contract.Result<CommandLineOptions.VCVariety>() != CommandLineOptions.VCVariety.Unspecified);
- return CommandLineOptions.VCVariety.DagIterative;
- }
- }
-
- public virtual bool SupportsLabels(ProverOptions options) {
- return true;
- }
-
- public virtual void Close() {
- }
-
- public static ProverFactory Load(string proverName) {
- Contract.Requires(proverName != null);
- Contract.Ensures(Contract.Result<ProverFactory>() != null);
- Contract.Ensures(cce.IsNew(Contract.Result<ProverFactory>()) && cce.Owner.New(Contract.Result<ProverFactory>()));
- string/*!*/ path;
- if (proverName.IndexOf("/") > 0 || proverName.IndexOf("\\") > 0) {
- path = proverName;
- } else {
- string codebase = cce.NonNull(System.IO.Path.GetDirectoryName(
- cce.NonNull(System.Reflection.Assembly.GetExecutingAssembly().Location)));
- path = System.IO.Path.Combine(codebase, "Provers." + proverName + ".dll");
- }
- Assembly asm = cce.NonNull(Assembly.LoadFrom(path));
- string name = cce.NonNull(asm.GetName().Name);
- System.Type factoryType = cce.NonNull(asm.GetType("Microsoft.Boogie." + name.Replace("Provers.", "") + ".Factory"));
- return cce.NonNull((ProverFactory/*!*/)Activator.CreateInstance(factoryType));
- }
- }
- [ContractClassFor(typeof(ProverFactory))]
- public abstract class ProverFactoryContracts : ProverFactory {
- public override object NewProverContext(ProverOptions options) {
- Contract.Requires(options != null);
- Contract.Ensures(Contract.Result<object>() != null);
-
- throw new NotImplementedException();
- }
- }
-}
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+using System;
+using System.IO;
+using System.Collections;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+using System.Diagnostics.Contracts;
+using Microsoft.Basetypes;
+namespace Microsoft.Boogie {
+
+ public class ProverOptions {
+ public class OptionException : Exception {
+ public OptionException(string msg)
+ : base(msg) {
+ Contract.Requires(msg != null);
+ }
+ }
+
+ public string/*?*/ LogFilename = null;
+ public bool AppendLogFile = false;
+ public bool SeparateLogFiles = false;
+ // Say (DBG_WAS_VALID) or (DBG_WAS_INVALID) after query
+ public bool ForceLogStatus = false;
+ public int TimeLimit = 0;
+ public int MemoryLimit = 0;
+ public int Verbosity = 0;
+ public string ProverPath;
+
+ private string/*!*/ stringRepr = "";
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(stringRepr != null);
+ }
+
+
+ [Pure]
+ public override string ToString() {
+ Contract.Ensures(Contract.Result<string>() != null);
+ return stringRepr;
+ }
+
+ // The usual thing to override.
+ protected virtual bool Parse(string opt) {
+ Contract.Requires(opt != null);
+ return ParseString(opt, "LOG_FILE", ref LogFilename) ||
+ ParseBool(opt, "APPEND_LOG_FILE", ref AppendLogFile) ||
+ ParseBool(opt, "FORCE_LOG_STATUS", ref ForceLogStatus) ||
+ ParseInt(opt, "MEMORY_LIMIT", ref MemoryLimit) ||
+ ParseInt(opt, "VERBOSITY", ref Verbosity) ||
+ ParseInt(opt, "TIME_LIMIT", ref TimeLimit) ||
+ ParseString(opt, "PROVER_PATH", ref ProverPath);
+ // || base.Parse(opt)
+ }
+
+ public virtual string Help
+ {
+ get
+ {
+ return
+@"
+Generic prover options :
+~~~~~~~~~~~~~~~~~~~~~~~
+LOG_FILE=<string> Log input for the theorem prover. The string @PROC@ in the filename
+ causes there to be one prover log file per verification condition,
+ and is expanded to the name of the procedure that the verification
+ condition is for.
+APPEND_LOG_FILE=<bool> Append, rather than overwrite the log file.
+MEMORY_LIMIT=<int> Memory limit of the prover in megabytes.
+VERBOSITY=<int> The higher, the more verbose.
+TIME_LIMIT=<int> Time limit per verification condition in miliseconds.
+PROVER_PATH=<string> Path to the prover to use.
+
+The generic options may or may not be used by the prover plugin.
+";
+
+ }
+ }
+
+ public virtual void Parse(IEnumerable<string/*!*/>/*!*/ opts) {
+ Contract.Requires(cce.NonNullElements(opts));
+ StringBuilder sb = new StringBuilder(stringRepr);
+ Contract.Assert(sb != null);
+ foreach (string/*!*/ opt in opts) {
+ Contract.Assert(opt != null);
+ if (!Parse(opt)) {
+ ReportError("Unrecognised prover option: " + opt);
+ }
+ sb.Append(opt).Append(" ");
+ }
+ stringRepr = sb.ToString();
+ PostParse();
+ }
+
+ public virtual void PostParse() {
+ if (LogFilename != null && LogFilename.Contains("@PROC@")) {
+ SeparateLogFiles = true;
+ }
+ }
+
+ protected void ReportError(string msg) {
+ Contract.Requires(msg != null);
+ throw new OptionException(msg + "\n\n" + Help);
+ }
+
+ protected virtual bool ParseString(string opt, string name, ref string field) {
+ Contract.Requires(name != null);
+ Contract.Requires(opt != null);
+ if (opt.Length >= name.Length && opt.StartsWith(name)) {
+ if (opt.Length == name.Length) {
+ field = "";
+ return true;
+ } else if (opt[name.Length] == '=' || opt[name.Length] == ':') {
+ field = opt.Substring(name.Length + 1);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected virtual bool ParseBool(string opt, string name, ref bool field) {
+ Contract.Requires(name != null);
+ Contract.Requires(opt != null);
+ string tmp = null;
+ if (ParseString(opt, name, ref tmp))
+ switch (cce.NonNull(tmp).ToLower()) {
+ case "1":
+ case "true":
+ case "":
+ field = true;
+ return true;
+ case "0":
+ case "false":
+ field = false;
+ return true;
+ default:
+ ReportError("Invalid Boolean option \"" + opt + "\"");
+ return false;
+ }
+ return false;
+ }
+
+ protected virtual bool ParseInt(string opt, string name, ref int field) {
+ Contract.Requires(name != null);
+ Contract.Requires(opt != null);
+ string tmp = null;
+ int t2;
+ if (ParseString(opt, name, ref tmp)) {
+ if (int.TryParse(cce.NonNull(tmp), out t2)) {
+ field = t2;
+ return true;
+ } else {
+ ReportError("Invalid integer option \"" + opt + "\"");
+ }
+ }
+ return false;
+ }
+
+ public virtual TextWriter OpenLog(string/*?*/ descName) {
+ if (LogFilename != null) {
+ string filename = LogFilename;
+ Contract.Assert(filename != null);
+ if (descName != null)
+ filename = Helpers.SubstituteAtPROC(descName, filename);
+ return new StreamWriter(filename, AppendLogFile);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ [ContractClass(typeof(ProverFactoryContracts))]
+ public abstract class ProverFactory {
+ // Really returns ProverInterface.
+ //public abstract object! SpawnProver(ProverOptions! options, object! ctxt);
+ public abstract object SpawnProver(ProverOptions options, object ctxt);
+
+ // Really returns ProverContext
+ public abstract object/*!*/ NewProverContext(ProverOptions/*!*/ options);
+
+ public virtual ProverOptions BlankProverOptions() {
+ Contract.Ensures(Contract.Result<ProverOptions>() != null);
+ return new ProverOptions();
+ }
+
+ // return true if the prover supports DAG AST as opposed to LET AST
+ public virtual bool SupportsDags {
+ get {
+ return false;
+ }
+ }
+
+ public virtual CommandLineOptions.VCVariety DefaultVCVariety {
+ get {
+ Contract.Ensures(Contract.Result<CommandLineOptions.VCVariety>() != CommandLineOptions.VCVariety.Unspecified);
+ return CommandLineOptions.VCVariety.DagIterative;
+ }
+ }
+
+ public virtual bool SupportsLabels(ProverOptions options) {
+ return true;
+ }
+
+ public virtual void Close() {
+ }
+
+ public static ProverFactory Load(string proverName) {
+ Contract.Requires(proverName != null);
+ Contract.Ensures(Contract.Result<ProverFactory>() != null);
+ Contract.Ensures(cce.IsNew(Contract.Result<ProverFactory>()) && cce.Owner.New(Contract.Result<ProverFactory>()));
+ string/*!*/ path;
+ if (proverName.IndexOf("/") > 0 || proverName.IndexOf("\\") > 0) {
+ path = proverName;
+ } else {
+ string codebase = cce.NonNull(System.IO.Path.GetDirectoryName(
+ cce.NonNull(System.Reflection.Assembly.GetExecutingAssembly().Location)));
+ path = System.IO.Path.Combine(codebase, "Provers." + proverName + ".dll");
+ }
+ Assembly asm = cce.NonNull(Assembly.LoadFrom(path));
+ string name = cce.NonNull(asm.GetName().Name);
+ System.Type factoryType = cce.NonNull(asm.GetType("Microsoft.Boogie." + name.Replace("Provers.", "") + ".Factory"));
+ return cce.NonNull((ProverFactory/*!*/)Activator.CreateInstance(factoryType));
+ }
+ }
+ [ContractClassFor(typeof(ProverFactory))]
+ public abstract class ProverFactoryContracts : ProverFactory {
+ public override object NewProverContext(ProverOptions options) {
+ Contract.Requires(options != null);
+ Contract.Ensures(Contract.Result<object>() != null);
+
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/Source/Core/VariableDependenceAnalyser.cs b/Source/Core/VariableDependenceAnalyser.cs
index ab12a47e..30e1dbf3 100644
--- a/Source/Core/VariableDependenceAnalyser.cs
+++ b/Source/Core/VariableDependenceAnalyser.cs
@@ -1,646 +1,646 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Diagnostics;
-using Microsoft.Boogie;
-using Microsoft.Boogie.GraphUtil;
-
-
-namespace Microsoft.Boogie {
-
- public interface IVariableDependenceAnalyser {
-
- void Analyse();
- VariableDescriptor MakeDescriptor(string proc, Variable v);
- HashSet<VariableDescriptor> DependsOn(VariableDescriptor v);
- void dump();
- void ShowDependencyChain(VariableDescriptor source, VariableDescriptor target);
- bool VariableRelevantToAnalysis(Variable v, string proc);
- bool Ignoring(Variable v, string proc);
-
- }
-
- public abstract class VariableDescriptor : IComparable {
- internal readonly string Name;
- internal VariableDescriptor(string Name) {
- this.Name = Name;
- }
-
- public override string ToString() {
- return Name;
- }
-
- public override bool Equals(object that) {
-
- if (object.ReferenceEquals(this, that)) {
- return true;
- }
-
- VariableDescriptor thatDescriptor = that as VariableDescriptor;
-
- if (thatDescriptor == null) {
- return false;
- }
-
- return this.Name.Equals(thatDescriptor.Name);
- }
-
- public override int GetHashCode() {
- return Name.GetHashCode();
- }
-
- public int CompareTo(object that) {
- return this.ToString().CompareTo(that.ToString());
- }
-
- }
-
- public class LocalDescriptor : VariableDescriptor {
- internal readonly string Proc;
- public LocalDescriptor(string Proc, string Name)
- : base(Name) {
- this.Proc = Proc;
- }
-
- public override string ToString() {
- return Proc + "." + base.ToString();
- }
-
- public override bool Equals(object that) {
-
- if (object.ReferenceEquals(this, that)) {
- return true;
- }
-
- LocalDescriptor thatDescriptor = that as LocalDescriptor;
-
- if (thatDescriptor == null) {
- return false;
- }
-
- return base.Equals(thatDescriptor) &&
- this.Proc.Equals(thatDescriptor.Proc);
-
- }
-
- public override int GetHashCode() {
- return (33 * base.GetHashCode())
- + this.Proc.GetHashCode();
- }
-
- }
-
- public class GlobalDescriptor : VariableDescriptor {
- public GlobalDescriptor(string name) : base(name) { }
-
- public override bool Equals(object that) {
-
- if (object.ReferenceEquals(this, that)) {
- return true;
- }
-
- GlobalDescriptor thatDescriptor = that as GlobalDescriptor;
-
- if (thatDescriptor == null) {
- return false;
- }
-
- return base.Equals(thatDescriptor);
-
- }
-
- public override int GetHashCode() {
- return base.GetHashCode();
- }
-
- }
-
- /// <summary>
- /// Given a Boogie program, computes a graph that over-approximates dependences
- /// between program variables.
- /// </summary>
- public class VariableDependenceAnalyser : IVariableDependenceAnalyser {
-
- private Graph<VariableDescriptor> dependsOnNonTransitive;
- private Program prog;
- private Dictionary<Block, HashSet<Block>> BlockToControllingBlocks;
- private Dictionary<Block, HashSet<VariableDescriptor>> ControllingBlockToVariables;
-
- public VariableDependenceAnalyser(Program prog) {
- this.prog = prog;
- dependsOnNonTransitive = new Graph<VariableDescriptor>();
- }
-
-
- private void Initialise() {
- foreach (var descriptor in
- prog.Variables.Where(Item => VariableRelevantToAnalysis(Item, null)).
- Select(Variable => Variable.Name).
- Select(Name => new GlobalDescriptor(Name))) {
- dependsOnNonTransitive.AddEdge(descriptor, descriptor);
- }
-
- foreach (var Proc in prog.NonInlinedProcedures()) {
-
- List<Variable> parameters = new List<Variable>();
- parameters.AddRange(Proc.InParams);
- parameters.AddRange(Proc.OutParams);
- foreach (var descriptor in
- parameters.Select(Variable => Variable.Name).Select(Name => new LocalDescriptor(Proc.Name, Name))) {
- dependsOnNonTransitive.AddEdge(descriptor, descriptor);
- }
- }
-
- foreach (var Impl in prog.NonInlinedImplementations()) {
-
- List<Variable> locals = new List<Variable>();
- locals.AddRange(Impl.LocVars);
- foreach (var descriptor in
- locals.Select(Variable => Variable.Name).Select(Name => new LocalDescriptor(Impl.Name, Name))) {
- dependsOnNonTransitive.AddEdge(descriptor, descriptor);
- }
- }
- }
-
- private List<VariableDescriptor> ComputeDependencyChain(VariableDescriptor source, VariableDescriptor target, HashSet<VariableDescriptor> visited) {
- if(source.Equals(target)) {
- return new List<VariableDescriptor> { target };
- }
-
- visited.Add(source);
-
- foreach(var w in dependsOnNonTransitive.Successors(source)) {
- if(visited.Contains(w)) {
- continue;
- }
- var result = ComputeDependencyChain(w, target, visited);
- if(result != null) {
- result.Insert(0, source);
- return result;
- }
- }
-
- return null;
-
- }
-
- public void ShowDependencyChain(VariableDescriptor source, VariableDescriptor target) {
- var chain = ComputeDependencyChain(source, target, new HashSet<VariableDescriptor>());
- if(chain == null) {
- Console.WriteLine("No chain between " + source + " and " + target);
- } else {
- bool first = true;
- foreach(var v in chain) {
- if(first) {
- first = false;
- } else {
- Console.Write(" -> ");
- }
- Console.Write(v);
- }
- }
- Console.WriteLine(); Console.WriteLine();
- }
-
- public void Analyse() {
-
- /* The algorithm is as follows:
- *
- * 1. Build global control dependence graph. First build control dependence graph for each procedure,
- * and union them. Then examine each procedure. If block B is control-dependent on block C, make
- * every block that can be indirectly reached via a call from B control-dependent on C.
- *
- * 2. Take transitive closure of global control dependence graph.
- *
- * 3. For every block B such that some other block is control-dependent on B, determine those variables
- * which B tests. If B tests v, and C is control-depdendent on B, we say that v "controls" the
- * statements appearing in C.
- *
- * 4. Consider each statement to work out variable dependences. v may depend on u if:
- * - there is a statement v := e where u appears in e
- * - there is a statement call ... := foo(..., e, ...) where v is formal in parameter of foo
- * corresponding to e and u appears in e
- * - there is a statement call ..., v, ... := foo(...) where u is formal out parameter of foo
- * correspondnig to v
- * - there is a statement v := ... controlled by u
- * - there is a statement call ... := foo(...) controlled by u where v is a formal in parameter
- * of foo
- * - there is a statement call ..., v, ... := foo(...) controlled by u
- *
- * 5. Finialise variable dependence graph by taking its transitive closure.
- *
- */
-
- if (CommandLineOptions.Clo.Trace) {
- Console.WriteLine("Variable dependence analysis: Initialising");
- }
-
- Initialise();
-
- if (CommandLineOptions.Clo.Trace) {
- Console.WriteLine("Variable dependence analysis: Computing control dependence info");
- }
-
- BlockToControllingBlocks = ComputeGlobalControlDependences();
-
- if (CommandLineOptions.Clo.Trace) {
- Console.WriteLine("Variable dependence analysis: Computing control dependence variables");
- }
-
- ControllingBlockToVariables = ComputeControllingVariables(BlockToControllingBlocks);
- foreach (var Impl in prog.NonInlinedImplementations()) {
-
- if (CommandLineOptions.Clo.Trace) {
- Console.WriteLine("Variable dependence analysis: Analysing " + Impl.Name);
- }
-
- Analyse(Impl);
- }
- }
-
- private void Analyse(Implementation Impl) {
- string proc = Impl.Name;
- foreach (Block b in Impl.Blocks) {
- Analyse(proc, b);
- }
- }
-
- private void Analyse(string proc, Block b) {
- foreach (Cmd cmd in b.Cmds) {
- AssignCmd assign = cmd as AssignCmd;
- if (assign != null) {
- HandleAssign(proc, b, assign);
- }
- CallCmd call = cmd as CallCmd;
- if (call != null) {
- HandleCall(proc, b, call);
- }
- }
- }
-
- private void HandleCall(string proc, Block b, CallCmd call) {
- foreach (var formalActualPair in call.Proc.InParams.Zip(call.Ins)) {
- var formalIn = MakeDescriptor(call.callee, formalActualPair.Item1);
- AddDependences(formalIn, GetReferencedVariables(formalActualPair.Item2, proc),
- "referenced in in-param in call to " + proc, call.tok);
- AddControlDependences(b, formalIn, " in param assigned under control dependence in call to " + proc, call.tok);
- }
-
- foreach (var formalActualPair in call.Proc.OutParams.Zip(call.Outs)) {
- var actualOut = MakeDescriptor(proc, formalActualPair.Item2.Decl);
- AddDependences(actualOut, GetReferencedVariables(new IdentifierExpr(Token.NoToken, formalActualPair.Item1), call.callee),
- "receiving variable for out-param in call to " + proc, call.tok);
- AddControlDependences(b, actualOut, " receiving variable assigned under control dependence in call to " + proc, call.tok);
- }
-
- }
-
- private void HandleAssign(string proc, Block b, AssignCmd assign) {
- foreach (var assignPair in assign.Lhss.Zip(assign.Rhss).Where
- (Item => VariableRelevantToAnalysis(Item.Item1.DeepAssignedVariable, proc))) {
- VariableDescriptor assignedVariable = MakeDescriptor(proc, assignPair.Item1.DeepAssignedVariable);
- AddDependences(assignedVariable, GetReferencedVariables(assignPair.Item1, proc),
- "LHS of assignment", assign.tok);
- AddDependences(assignedVariable, GetReferencedVariables(assignPair.Item2, proc),
- "RHS of assignment", assign.tok);
- AddControlDependences(b, assignedVariable, "Variable assigned under control dependence", assign.tok);
- }
- }
-
- private void AddControlDependences(Block b, VariableDescriptor v, string reason, IToken tok) {
- if (!BlockToControllingBlocks.ContainsKey(b)) {
- return;
- }
- foreach (var controller in BlockToControllingBlocks[b]) {
- AddDependences(v, ControllingBlockToVariables[controller], reason + " controlling block at (" + controller.tok.line + ":" + controller.tok.col + ")", tok);
- }
- }
-
- private IEnumerable<VariableDescriptor> GetReferencedVariables(Absy node, string proc) {
- var VarCollector = new VariableCollector();
- VarCollector.Visit(node);
- return VarCollector.usedVars.Where(Item => VariableRelevantToAnalysis(Item, proc)).
- Select(Item => MakeDescriptor(proc, Item));
- }
-
- void AddDependences(VariableDescriptor v, IEnumerable<VariableDescriptor> vs, string reason, IToken tok) {
- foreach (var n in vs) {
- if(CommandLineOptions.Clo.DebugStagedHoudini) {
- Console.WriteLine("Adding dependence " + v + " -> " + n + ", reason: " + reason + "(" + tok.line + ":" + tok.col + ")");
- }
- dependsOnNonTransitive.AddEdge(v, n);
- }
- }
-
- private Dictionary<Block, HashSet<VariableDescriptor>> ComputeControllingVariables(Dictionary<Block, HashSet<Block>> GlobalCtrlDep) {
- Dictionary<Block, HashSet<VariableDescriptor>> result = new Dictionary<Block, HashSet<VariableDescriptor>>();
- foreach (var Impl in prog.NonInlinedImplementations()) {
- foreach (var b in Impl.Blocks) {
- result[b] = GetControlDependencyVariables(Impl.Name, b);
- }
- }
- return result;
- }
-
- private HashSet<VariableDescriptor> GetControlDependencyVariables(string proc, Block b) {
-
- // This method works under the assumption that assume statements
- // relevant to control flow between basic blocks have the "partition" attribute
-
- HashSet<VariableDescriptor> result = new HashSet<VariableDescriptor>();
- var gotoCmd = b.TransferCmd as GotoCmd;
- if (gotoCmd != null && gotoCmd.labelTargets.Count >= 2) {
- foreach (Block succ in gotoCmd.labelTargets) {
- foreach (Cmd c in succ.Cmds) {
- AssumeCmd a = c as AssumeCmd;
- if (a != null && QKeyValue.FindBoolAttribute(a.Attributes, "partition")) {
- var VarCollector = new VariableCollector();
- VarCollector.VisitExpr(a.Expr);
- result.UnionWith(VarCollector.usedVars.Where(Item => VariableRelevantToAnalysis(Item, proc)).
- Select(Item => MakeDescriptor(proc, Item)));
- }
- else {
- break;
- }
- }
- }
- }
- return result;
- }
-
- private HashSet<VariableDescriptor> IgnoredVariables = null;
-
- public bool Ignoring(Variable v, string proc) {
-
- if (IgnoredVariables == null) {
- MakeIgnoreList();
- }
-
- if(proc != null && IgnoredVariables.Contains(new LocalDescriptor(proc, v.Name))) {
- return true;
- }
-
- if(IgnoredVariables.Contains(new GlobalDescriptor(v.Name))) {
- return true;
- }
-
- return false;
-
- }
-
- public bool VariableRelevantToAnalysis(Variable v, string proc) {
- return !(v is Constant || Ignoring(v, proc));
- }
-
- private void MakeIgnoreList()
- {
- IgnoredVariables = new HashSet<VariableDescriptor>();
- if(CommandLineOptions.Clo.VariableDependenceIgnore == null) {
- return;
- }
- try {
- var file = System.IO.File.OpenText(CommandLineOptions.Clo.VariableDependenceIgnore);
- while(!file.EndOfStream) {
- string line = file.ReadLine();
- string[] tokens = line.Split(' ');
- if(tokens.Count() == 0) {
- continue;
- }
- if(tokens.Count() > 2) {
- Console.Error.WriteLine("Ignoring malformed line of ignored variables file: " + line);
- continue;
- }
- if(tokens.Count() == 1) {
- IgnoredVariables.Add(new GlobalDescriptor(tokens[0]));
- continue;
- }
- Debug.Assert(tokens.Count() == 2);
- IgnoredVariables.Add(new LocalDescriptor(tokens[0], tokens[1]));
- }
- } catch(System.IO.IOException e) {
- Console.Error.WriteLine("Error reading from ignored variables file " + CommandLineOptions.Clo.VariableDependenceIgnore + ": " + e);
- }
- }
-
- private Dictionary<Block, HashSet<Block>> ComputeGlobalControlDependences() {
-
- Dictionary<Block, HashSet<Block>> GlobalCtrlDep = new Dictionary<Block, HashSet<Block>>();
- Dictionary<Implementation, Dictionary<Block, HashSet<Block>>> LocalCtrlDeps = new Dictionary<Implementation, Dictionary<Block, HashSet<Block>>>();
-
- // Work out and union together local control dependences
- foreach (var Impl in prog.NonInlinedImplementations()) {
- Graph<Block> blockGraph = prog.ProcessLoops(Impl);
- LocalCtrlDeps[Impl] = blockGraph.ControlDependence();
- foreach (var KeyValue in LocalCtrlDeps[Impl]) {
- GlobalCtrlDep.Add(KeyValue.Key, KeyValue.Value);
- }
- }
-
- Graph<Implementation> callGraph = Program.BuildCallGraph(prog);
-
- // Add inter-procedural control dependence nodes based on calls
- foreach (var Impl in prog.NonInlinedImplementations()) {
- foreach (var b in Impl.Blocks) {
- foreach (var cmd in b.Cmds.OfType<CallCmd>()) {
- var DirectCallee = GetImplementation(cmd.callee);
- if (DirectCallee != null) {
- HashSet<Implementation> IndirectCallees = ComputeIndirectCallees(callGraph, DirectCallee);
- foreach (var control in GetControllingBlocks(b, LocalCtrlDeps[Impl])) {
- foreach (var c in IndirectCallees.Select(Item => Item.Blocks).SelectMany(Item => Item)) {
- GlobalCtrlDep[control].Add(c);
- }
- }
- }
- }
- }
- }
-
- // Compute transitive closure
- GlobalCtrlDep.TransitiveClosure();
-
- // Finally reverse the dependences
-
- Dictionary<Block, HashSet<Block>> result = new Dictionary<Block, HashSet<Block>>();
-
- foreach (var KeyValue in GlobalCtrlDep) {
- foreach (var v in KeyValue.Value) {
- if (!result.ContainsKey(v)) {
- result[v] = new HashSet<Block>();
- }
- result[v].Add(KeyValue.Key);
- }
- }
-
- return result;
- }
-
- private HashSet<Implementation> ComputeIndirectCallees(Graph<Implementation> callGraph, Implementation DirectCallee) {
- return ComputeIndirectCallees(callGraph, DirectCallee, new HashSet<Implementation>());
- }
-
- private HashSet<Implementation> ComputeIndirectCallees(Graph<Implementation> callGraph, Implementation DirectCallee, HashSet<Implementation> seen) {
- if (seen.Contains(DirectCallee)) {
- return new HashSet<Implementation>();
- }
- HashSet<Implementation> result = new HashSet<Implementation>();
- result.Add(DirectCallee);
- seen.Add(DirectCallee);
- foreach (var succ in callGraph.Successors(DirectCallee)) {
- result.UnionWith(ComputeIndirectCallees(callGraph, succ, seen));
- }
- return result;
- }
-
- private HashSet<Block> GetControllingBlocks(Block b, Dictionary<Block, HashSet<Block>> ctrlDep) {
- HashSet<Block> result = new HashSet<Block>();
- foreach (var KeyValue in ctrlDep) {
- if (KeyValue.Value.Contains(b)) {
- result.Add(KeyValue.Key);
- }
- }
- return result;
- }
-
- private Implementation GetImplementation(string proc) {
- foreach (var Impl in prog.Implementations) {
- if (Impl.Name.Equals(proc)) {
- return Impl;
- }
- }
- return null;
- }
-
- public VariableDescriptor MakeDescriptor(string proc, Variable v) {
-
- // Check whether there is an (Impl, v) match
- var MatchingLocals = dependsOnNonTransitive.Nodes.Where(Item => Item is LocalDescriptor).Select(
- Item => (LocalDescriptor)Item).Where(Item => Item.Proc.Equals(proc) &&
- Item.Name.Equals(v.Name));
- if (MatchingLocals.Count() > 0) {
- Debug.Assert(MatchingLocals.Count() == 1);
- return MatchingLocals.ToArray()[0];
- }
-
- // It must be a global with same name as v
- return dependsOnNonTransitive.Nodes.Where(Item => Item is GlobalDescriptor &&
- Item.Name.Equals(v.Name)).ToArray()[0];
- }
-
- private Dictionary<SCC<VariableDescriptor>, HashSet<VariableDescriptor>> DependsOnCache = new Dictionary<SCC<VariableDescriptor>, HashSet<VariableDescriptor>>();
-
- private Graph<SCC<VariableDescriptor>> DependsOnSCCsDAG;
- private Dictionary<VariableDescriptor, SCC<VariableDescriptor>> VariableDescriptorToSCC;
-
- public HashSet<VariableDescriptor> DependsOn(VariableDescriptor v) {
- if (DependsOnSCCsDAG == null) {
- if (CommandLineOptions.Clo.Trace) {
- Console.WriteLine("Variable dependence: computing SCCs");
- }
- Adjacency<VariableDescriptor> next = new Adjacency<VariableDescriptor>(dependsOnNonTransitive.Successors);
- Adjacency<VariableDescriptor> prev = new Adjacency<VariableDescriptor>(dependsOnNonTransitive.Predecessors);
- StronglyConnectedComponents<VariableDescriptor> DependsOnSCCs = new StronglyConnectedComponents<VariableDescriptor>(
- dependsOnNonTransitive.Nodes, next, prev);
- DependsOnSCCs.Compute();
-
- VariableDescriptorToSCC = new Dictionary<VariableDescriptor, SCC<VariableDescriptor>>();
- foreach (var scc in DependsOnSCCs) {
- foreach (var s in scc) {
- VariableDescriptorToSCC[s] = scc;
- }
- }
-
- DependsOnSCCsDAG = new Graph<SCC<VariableDescriptor>>();
- foreach (var edge in dependsOnNonTransitive.Edges) {
- if (VariableDescriptorToSCC[edge.Item1] != VariableDescriptorToSCC[edge.Item2]) {
- DependsOnSCCsDAG.AddEdge(VariableDescriptorToSCC[edge.Item1], VariableDescriptorToSCC[edge.Item2]);
- }
- }
-
- SCC<VariableDescriptor> dummy = new SCC<VariableDescriptor>();
- foreach (var n in dependsOnNonTransitive.Nodes) {
- DependsOnSCCsDAG.AddEdge(VariableDescriptorToSCC[n], dummy);
- }
-
- if (CommandLineOptions.Clo.Trace) {
- Console.WriteLine("Variable dependence: SCCs computed!");
- }
- }
- return DependsOn(VariableDescriptorToSCC[v]);
- }
-
- public HashSet<VariableDescriptor> DependsOn(SCC<VariableDescriptor> vSCC) {
-
- if (!DependsOnCache.ContainsKey(vSCC)) {
- HashSet<VariableDescriptor> result = new HashSet<VariableDescriptor>();
- if (vSCC.Count() > 0) {
- result.UnionWith(vSCC);
- foreach (var wSCC in DependsOnSCCsDAG.Successors(vSCC)) {
- result.UnionWith(DependsOn(wSCC));
- }
- }
- DependsOnCache[vSCC] = result;
- }
- return DependsOnCache[vSCC];
- }
-
- public void dump() {
-
- Console.WriteLine("Variable dependence information");
- Console.WriteLine("===============================");
-
- Console.WriteLine("Global variables");
- Console.WriteLine("================");
-
- foreach (var GlobalEntry in dependsOnNonTransitive.Nodes.Where(Item => Item is GlobalDescriptor)) {
- dump(GlobalEntry);
- }
-
- foreach (var proc in Procedures()) {
- Console.WriteLine("Variables of " + proc);
- Console.WriteLine("=====================");
- foreach (var LocalEntry in dependsOnNonTransitive.Nodes.Where(Item => Item is LocalDescriptor
- && ((LocalDescriptor)Item).Proc.Equals(proc))) {
- dump(LocalEntry);
- }
- }
- }
-
- private void dump(VariableDescriptor vd) {
- Console.Write(vd + " <- {");
- bool first = true;
-
- var SortedDependents = DependsOn(vd).ToList();
- SortedDependents.Sort();
- foreach (var Descriptor in SortedDependents) {
- Console.Write((first ? "" : ",") + "\n " + Descriptor);
- if (first) {
- first = false;
- }
- }
- Debug.Assert(!first);
- Console.WriteLine("\n}\n");
- }
-
- private HashSet<string> Procedures() {
- return new HashSet<string>(dependsOnNonTransitive.Nodes.Where(Item =>
- Item is LocalDescriptor).Select(Item => ((LocalDescriptor)Item).Proc));
- }
-
- }
-
- public static class Helper {
-
- public static IEnumerable<Procedure> NonInlinedProcedures(this Program prog) {
- return prog.Procedures.
- Where(Item => QKeyValue.FindIntAttribute(Item.Attributes, "inline", -1) == -1);
- }
-
- public static IEnumerable<Implementation> NonInlinedImplementations(this Program prog) {
- return prog.Implementations.
- Where(Item => QKeyValue.FindIntAttribute(Item.Proc.Attributes, "inline", -1) == -1);
- }
-
- }
-
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Diagnostics;
+using Microsoft.Boogie;
+using Microsoft.Boogie.GraphUtil;
+
+
+namespace Microsoft.Boogie {
+
+ public interface IVariableDependenceAnalyser {
+
+ void Analyse();
+ VariableDescriptor MakeDescriptor(string proc, Variable v);
+ HashSet<VariableDescriptor> DependsOn(VariableDescriptor v);
+ void dump();
+ void ShowDependencyChain(VariableDescriptor source, VariableDescriptor target);
+ bool VariableRelevantToAnalysis(Variable v, string proc);
+ bool Ignoring(Variable v, string proc);
+
+ }
+
+ public abstract class VariableDescriptor : IComparable {
+ internal readonly string Name;
+ internal VariableDescriptor(string Name) {
+ this.Name = Name;
+ }
+
+ public override string ToString() {
+ return Name;
+ }
+
+ public override bool Equals(object that) {
+
+ if (object.ReferenceEquals(this, that)) {
+ return true;
+ }
+
+ VariableDescriptor thatDescriptor = that as VariableDescriptor;
+
+ if (thatDescriptor == null) {
+ return false;
+ }
+
+ return this.Name.Equals(thatDescriptor.Name);
+ }
+
+ public override int GetHashCode() {
+ return Name.GetHashCode();
+ }
+
+ public int CompareTo(object that) {
+ return this.ToString().CompareTo(that.ToString());
+ }
+
+ }
+
+ public class LocalDescriptor : VariableDescriptor {
+ internal readonly string Proc;
+ public LocalDescriptor(string Proc, string Name)
+ : base(Name) {
+ this.Proc = Proc;
+ }
+
+ public override string ToString() {
+ return Proc + "." + base.ToString();
+ }
+
+ public override bool Equals(object that) {
+
+ if (object.ReferenceEquals(this, that)) {
+ return true;
+ }
+
+ LocalDescriptor thatDescriptor = that as LocalDescriptor;
+
+ if (thatDescriptor == null) {
+ return false;
+ }
+
+ return base.Equals(thatDescriptor) &&
+ this.Proc.Equals(thatDescriptor.Proc);
+
+ }
+
+ public override int GetHashCode() {
+ return (33 * base.GetHashCode())
+ + this.Proc.GetHashCode();
+ }
+
+ }
+
+ public class GlobalDescriptor : VariableDescriptor {
+ public GlobalDescriptor(string name) : base(name) { }
+
+ public override bool Equals(object that) {
+
+ if (object.ReferenceEquals(this, that)) {
+ return true;
+ }
+
+ GlobalDescriptor thatDescriptor = that as GlobalDescriptor;
+
+ if (thatDescriptor == null) {
+ return false;
+ }
+
+ return base.Equals(thatDescriptor);
+
+ }
+
+ public override int GetHashCode() {
+ return base.GetHashCode();
+ }
+
+ }
+
+ /// <summary>
+ /// Given a Boogie program, computes a graph that over-approximates dependences
+ /// between program variables.
+ /// </summary>
+ public class VariableDependenceAnalyser : IVariableDependenceAnalyser {
+
+ private Graph<VariableDescriptor> dependsOnNonTransitive;
+ private Program prog;
+ private Dictionary<Block, HashSet<Block>> BlockToControllingBlocks;
+ private Dictionary<Block, HashSet<VariableDescriptor>> ControllingBlockToVariables;
+
+ public VariableDependenceAnalyser(Program prog) {
+ this.prog = prog;
+ dependsOnNonTransitive = new Graph<VariableDescriptor>();
+ }
+
+
+ private void Initialise() {
+ foreach (var descriptor in
+ prog.Variables.Where(Item => VariableRelevantToAnalysis(Item, null)).
+ Select(Variable => Variable.Name).
+ Select(Name => new GlobalDescriptor(Name))) {
+ dependsOnNonTransitive.AddEdge(descriptor, descriptor);
+ }
+
+ foreach (var Proc in prog.NonInlinedProcedures()) {
+
+ List<Variable> parameters = new List<Variable>();
+ parameters.AddRange(Proc.InParams);
+ parameters.AddRange(Proc.OutParams);
+ foreach (var descriptor in
+ parameters.Select(Variable => Variable.Name).Select(Name => new LocalDescriptor(Proc.Name, Name))) {
+ dependsOnNonTransitive.AddEdge(descriptor, descriptor);
+ }
+ }
+
+ foreach (var Impl in prog.NonInlinedImplementations()) {
+
+ List<Variable> locals = new List<Variable>();
+ locals.AddRange(Impl.LocVars);
+ foreach (var descriptor in
+ locals.Select(Variable => Variable.Name).Select(Name => new LocalDescriptor(Impl.Name, Name))) {
+ dependsOnNonTransitive.AddEdge(descriptor, descriptor);
+ }
+ }
+ }
+
+ private List<VariableDescriptor> ComputeDependencyChain(VariableDescriptor source, VariableDescriptor target, HashSet<VariableDescriptor> visited) {
+ if(source.Equals(target)) {
+ return new List<VariableDescriptor> { target };
+ }
+
+ visited.Add(source);
+
+ foreach(var w in dependsOnNonTransitive.Successors(source)) {
+ if(visited.Contains(w)) {
+ continue;
+ }
+ var result = ComputeDependencyChain(w, target, visited);
+ if(result != null) {
+ result.Insert(0, source);
+ return result;
+ }
+ }
+
+ return null;
+
+ }
+
+ public void ShowDependencyChain(VariableDescriptor source, VariableDescriptor target) {
+ var chain = ComputeDependencyChain(source, target, new HashSet<VariableDescriptor>());
+ if(chain == null) {
+ Console.WriteLine("No chain between " + source + " and " + target);
+ } else {
+ bool first = true;
+ foreach(var v in chain) {
+ if(first) {
+ first = false;
+ } else {
+ Console.Write(" -> ");
+ }
+ Console.Write(v);
+ }
+ }
+ Console.WriteLine(); Console.WriteLine();
+ }
+
+ public void Analyse() {
+
+ /* The algorithm is as follows:
+ *
+ * 1. Build global control dependence graph. First build control dependence graph for each procedure,
+ * and union them. Then examine each procedure. If block B is control-dependent on block C, make
+ * every block that can be indirectly reached via a call from B control-dependent on C.
+ *
+ * 2. Take transitive closure of global control dependence graph.
+ *
+ * 3. For every block B such that some other block is control-dependent on B, determine those variables
+ * which B tests. If B tests v, and C is control-depdendent on B, we say that v "controls" the
+ * statements appearing in C.
+ *
+ * 4. Consider each statement to work out variable dependences. v may depend on u if:
+ * - there is a statement v := e where u appears in e
+ * - there is a statement call ... := foo(..., e, ...) where v is formal in parameter of foo
+ * corresponding to e and u appears in e
+ * - there is a statement call ..., v, ... := foo(...) where u is formal out parameter of foo
+ * correspondnig to v
+ * - there is a statement v := ... controlled by u
+ * - there is a statement call ... := foo(...) controlled by u where v is a formal in parameter
+ * of foo
+ * - there is a statement call ..., v, ... := foo(...) controlled by u
+ *
+ * 5. Finialise variable dependence graph by taking its transitive closure.
+ *
+ */
+
+ if (CommandLineOptions.Clo.Trace) {
+ Console.WriteLine("Variable dependence analysis: Initialising");
+ }
+
+ Initialise();
+
+ if (CommandLineOptions.Clo.Trace) {
+ Console.WriteLine("Variable dependence analysis: Computing control dependence info");
+ }
+
+ BlockToControllingBlocks = ComputeGlobalControlDependences();
+
+ if (CommandLineOptions.Clo.Trace) {
+ Console.WriteLine("Variable dependence analysis: Computing control dependence variables");
+ }
+
+ ControllingBlockToVariables = ComputeControllingVariables(BlockToControllingBlocks);
+ foreach (var Impl in prog.NonInlinedImplementations()) {
+
+ if (CommandLineOptions.Clo.Trace) {
+ Console.WriteLine("Variable dependence analysis: Analysing " + Impl.Name);
+ }
+
+ Analyse(Impl);
+ }
+ }
+
+ private void Analyse(Implementation Impl) {
+ string proc = Impl.Name;
+ foreach (Block b in Impl.Blocks) {
+ Analyse(proc, b);
+ }
+ }
+
+ private void Analyse(string proc, Block b) {
+ foreach (Cmd cmd in b.Cmds) {
+ AssignCmd assign = cmd as AssignCmd;
+ if (assign != null) {
+ HandleAssign(proc, b, assign);
+ }
+ CallCmd call = cmd as CallCmd;
+ if (call != null) {
+ HandleCall(proc, b, call);
+ }
+ }
+ }
+
+ private void HandleCall(string proc, Block b, CallCmd call) {
+ foreach (var formalActualPair in call.Proc.InParams.Zip(call.Ins)) {
+ var formalIn = MakeDescriptor(call.callee, formalActualPair.Item1);
+ AddDependences(formalIn, GetReferencedVariables(formalActualPair.Item2, proc),
+ "referenced in in-param in call to " + proc, call.tok);
+ AddControlDependences(b, formalIn, " in param assigned under control dependence in call to " + proc, call.tok);
+ }
+
+ foreach (var formalActualPair in call.Proc.OutParams.Zip(call.Outs)) {
+ var actualOut = MakeDescriptor(proc, formalActualPair.Item2.Decl);
+ AddDependences(actualOut, GetReferencedVariables(new IdentifierExpr(Token.NoToken, formalActualPair.Item1), call.callee),
+ "receiving variable for out-param in call to " + proc, call.tok);
+ AddControlDependences(b, actualOut, " receiving variable assigned under control dependence in call to " + proc, call.tok);
+ }
+
+ }
+
+ private void HandleAssign(string proc, Block b, AssignCmd assign) {
+ foreach (var assignPair in assign.Lhss.Zip(assign.Rhss).Where
+ (Item => VariableRelevantToAnalysis(Item.Item1.DeepAssignedVariable, proc))) {
+ VariableDescriptor assignedVariable = MakeDescriptor(proc, assignPair.Item1.DeepAssignedVariable);
+ AddDependences(assignedVariable, GetReferencedVariables(assignPair.Item1, proc),
+ "LHS of assignment", assign.tok);
+ AddDependences(assignedVariable, GetReferencedVariables(assignPair.Item2, proc),
+ "RHS of assignment", assign.tok);
+ AddControlDependences(b, assignedVariable, "Variable assigned under control dependence", assign.tok);
+ }
+ }
+
+ private void AddControlDependences(Block b, VariableDescriptor v, string reason, IToken tok) {
+ if (!BlockToControllingBlocks.ContainsKey(b)) {
+ return;
+ }
+ foreach (var controller in BlockToControllingBlocks[b]) {
+ AddDependences(v, ControllingBlockToVariables[controller], reason + " controlling block at (" + controller.tok.line + ":" + controller.tok.col + ")", tok);
+ }
+ }
+
+ private IEnumerable<VariableDescriptor> GetReferencedVariables(Absy node, string proc) {
+ var VarCollector = new VariableCollector();
+ VarCollector.Visit(node);
+ return VarCollector.usedVars.Where(Item => VariableRelevantToAnalysis(Item, proc)).
+ Select(Item => MakeDescriptor(proc, Item));
+ }
+
+ void AddDependences(VariableDescriptor v, IEnumerable<VariableDescriptor> vs, string reason, IToken tok) {
+ foreach (var n in vs) {
+ if(CommandLineOptions.Clo.DebugStagedHoudini) {
+ Console.WriteLine("Adding dependence " + v + " -> " + n + ", reason: " + reason + "(" + tok.line + ":" + tok.col + ")");
+ }
+ dependsOnNonTransitive.AddEdge(v, n);
+ }
+ }
+
+ private Dictionary<Block, HashSet<VariableDescriptor>> ComputeControllingVariables(Dictionary<Block, HashSet<Block>> GlobalCtrlDep) {
+ Dictionary<Block, HashSet<VariableDescriptor>> result = new Dictionary<Block, HashSet<VariableDescriptor>>();
+ foreach (var Impl in prog.NonInlinedImplementations()) {
+ foreach (var b in Impl.Blocks) {
+ result[b] = GetControlDependencyVariables(Impl.Name, b);
+ }
+ }
+ return result;
+ }
+
+ private HashSet<VariableDescriptor> GetControlDependencyVariables(string proc, Block b) {
+
+ // This method works under the assumption that assume statements
+ // relevant to control flow between basic blocks have the "partition" attribute
+
+ HashSet<VariableDescriptor> result = new HashSet<VariableDescriptor>();
+ var gotoCmd = b.TransferCmd as GotoCmd;
+ if (gotoCmd != null && gotoCmd.labelTargets.Count >= 2) {
+ foreach (Block succ in gotoCmd.labelTargets) {
+ foreach (Cmd c in succ.Cmds) {
+ AssumeCmd a = c as AssumeCmd;
+ if (a != null && QKeyValue.FindBoolAttribute(a.Attributes, "partition")) {
+ var VarCollector = new VariableCollector();
+ VarCollector.VisitExpr(a.Expr);
+ result.UnionWith(VarCollector.usedVars.Where(Item => VariableRelevantToAnalysis(Item, proc)).
+ Select(Item => MakeDescriptor(proc, Item)));
+ }
+ else {
+ break;
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ private HashSet<VariableDescriptor> IgnoredVariables = null;
+
+ public bool Ignoring(Variable v, string proc) {
+
+ if (IgnoredVariables == null) {
+ MakeIgnoreList();
+ }
+
+ if(proc != null && IgnoredVariables.Contains(new LocalDescriptor(proc, v.Name))) {
+ return true;
+ }
+
+ if(IgnoredVariables.Contains(new GlobalDescriptor(v.Name))) {
+ return true;
+ }
+
+ return false;
+
+ }
+
+ public bool VariableRelevantToAnalysis(Variable v, string proc) {
+ return !(v is Constant || Ignoring(v, proc));
+ }
+
+ private void MakeIgnoreList()
+ {
+ IgnoredVariables = new HashSet<VariableDescriptor>();
+ if(CommandLineOptions.Clo.VariableDependenceIgnore == null) {
+ return;
+ }
+ try {
+ var file = System.IO.File.OpenText(CommandLineOptions.Clo.VariableDependenceIgnore);
+ while(!file.EndOfStream) {
+ string line = file.ReadLine();
+ string[] tokens = line.Split(' ');
+ if(tokens.Count() == 0) {
+ continue;
+ }
+ if(tokens.Count() > 2) {
+ Console.Error.WriteLine("Ignoring malformed line of ignored variables file: " + line);
+ continue;
+ }
+ if(tokens.Count() == 1) {
+ IgnoredVariables.Add(new GlobalDescriptor(tokens[0]));
+ continue;
+ }
+ Debug.Assert(tokens.Count() == 2);
+ IgnoredVariables.Add(new LocalDescriptor(tokens[0], tokens[1]));
+ }
+ } catch(System.IO.IOException e) {
+ Console.Error.WriteLine("Error reading from ignored variables file " + CommandLineOptions.Clo.VariableDependenceIgnore + ": " + e);
+ }
+ }
+
+ private Dictionary<Block, HashSet<Block>> ComputeGlobalControlDependences() {
+
+ Dictionary<Block, HashSet<Block>> GlobalCtrlDep = new Dictionary<Block, HashSet<Block>>();
+ Dictionary<Implementation, Dictionary<Block, HashSet<Block>>> LocalCtrlDeps = new Dictionary<Implementation, Dictionary<Block, HashSet<Block>>>();
+
+ // Work out and union together local control dependences
+ foreach (var Impl in prog.NonInlinedImplementations()) {
+ Graph<Block> blockGraph = prog.ProcessLoops(Impl);
+ LocalCtrlDeps[Impl] = blockGraph.ControlDependence();
+ foreach (var KeyValue in LocalCtrlDeps[Impl]) {
+ GlobalCtrlDep.Add(KeyValue.Key, KeyValue.Value);
+ }
+ }
+
+ Graph<Implementation> callGraph = Program.BuildCallGraph(prog);
+
+ // Add inter-procedural control dependence nodes based on calls
+ foreach (var Impl in prog.NonInlinedImplementations()) {
+ foreach (var b in Impl.Blocks) {
+ foreach (var cmd in b.Cmds.OfType<CallCmd>()) {
+ var DirectCallee = GetImplementation(cmd.callee);
+ if (DirectCallee != null) {
+ HashSet<Implementation> IndirectCallees = ComputeIndirectCallees(callGraph, DirectCallee);
+ foreach (var control in GetControllingBlocks(b, LocalCtrlDeps[Impl])) {
+ foreach (var c in IndirectCallees.Select(Item => Item.Blocks).SelectMany(Item => Item)) {
+ GlobalCtrlDep[control].Add(c);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Compute transitive closure
+ GlobalCtrlDep.TransitiveClosure();
+
+ // Finally reverse the dependences
+
+ Dictionary<Block, HashSet<Block>> result = new Dictionary<Block, HashSet<Block>>();
+
+ foreach (var KeyValue in GlobalCtrlDep) {
+ foreach (var v in KeyValue.Value) {
+ if (!result.ContainsKey(v)) {
+ result[v] = new HashSet<Block>();
+ }
+ result[v].Add(KeyValue.Key);
+ }
+ }
+
+ return result;
+ }
+
+ private HashSet<Implementation> ComputeIndirectCallees(Graph<Implementation> callGraph, Implementation DirectCallee) {
+ return ComputeIndirectCallees(callGraph, DirectCallee, new HashSet<Implementation>());
+ }
+
+ private HashSet<Implementation> ComputeIndirectCallees(Graph<Implementation> callGraph, Implementation DirectCallee, HashSet<Implementation> seen) {
+ if (seen.Contains(DirectCallee)) {
+ return new HashSet<Implementation>();
+ }
+ HashSet<Implementation> result = new HashSet<Implementation>();
+ result.Add(DirectCallee);
+ seen.Add(DirectCallee);
+ foreach (var succ in callGraph.Successors(DirectCallee)) {
+ result.UnionWith(ComputeIndirectCallees(callGraph, succ, seen));
+ }
+ return result;
+ }
+
+ private HashSet<Block> GetControllingBlocks(Block b, Dictionary<Block, HashSet<Block>> ctrlDep) {
+ HashSet<Block> result = new HashSet<Block>();
+ foreach (var KeyValue in ctrlDep) {
+ if (KeyValue.Value.Contains(b)) {
+ result.Add(KeyValue.Key);
+ }
+ }
+ return result;
+ }
+
+ private Implementation GetImplementation(string proc) {
+ foreach (var Impl in prog.Implementations) {
+ if (Impl.Name.Equals(proc)) {
+ return Impl;
+ }
+ }
+ return null;
+ }
+
+ public VariableDescriptor MakeDescriptor(string proc, Variable v) {
+
+ // Check whether there is an (Impl, v) match
+ var MatchingLocals = dependsOnNonTransitive.Nodes.Where(Item => Item is LocalDescriptor).Select(
+ Item => (LocalDescriptor)Item).Where(Item => Item.Proc.Equals(proc) &&
+ Item.Name.Equals(v.Name));
+ if (MatchingLocals.Count() > 0) {
+ Debug.Assert(MatchingLocals.Count() == 1);
+ return MatchingLocals.ToArray()[0];
+ }
+
+ // It must be a global with same name as v
+ return dependsOnNonTransitive.Nodes.Where(Item => Item is GlobalDescriptor &&
+ Item.Name.Equals(v.Name)).ToArray()[0];
+ }
+
+ private Dictionary<SCC<VariableDescriptor>, HashSet<VariableDescriptor>> DependsOnCache = new Dictionary<SCC<VariableDescriptor>, HashSet<VariableDescriptor>>();
+
+ private Graph<SCC<VariableDescriptor>> DependsOnSCCsDAG;
+ private Dictionary<VariableDescriptor, SCC<VariableDescriptor>> VariableDescriptorToSCC;
+
+ public HashSet<VariableDescriptor> DependsOn(VariableDescriptor v) {
+ if (DependsOnSCCsDAG == null) {
+ if (CommandLineOptions.Clo.Trace) {
+ Console.WriteLine("Variable dependence: computing SCCs");
+ }
+ Adjacency<VariableDescriptor> next = new Adjacency<VariableDescriptor>(dependsOnNonTransitive.Successors);
+ Adjacency<VariableDescriptor> prev = new Adjacency<VariableDescriptor>(dependsOnNonTransitive.Predecessors);
+ StronglyConnectedComponents<VariableDescriptor> DependsOnSCCs = new StronglyConnectedComponents<VariableDescriptor>(
+ dependsOnNonTransitive.Nodes, next, prev);
+ DependsOnSCCs.Compute();
+
+ VariableDescriptorToSCC = new Dictionary<VariableDescriptor, SCC<VariableDescriptor>>();
+ foreach (var scc in DependsOnSCCs) {
+ foreach (var s in scc) {
+ VariableDescriptorToSCC[s] = scc;
+ }
+ }
+
+ DependsOnSCCsDAG = new Graph<SCC<VariableDescriptor>>();
+ foreach (var edge in dependsOnNonTransitive.Edges) {
+ if (VariableDescriptorToSCC[edge.Item1] != VariableDescriptorToSCC[edge.Item2]) {
+ DependsOnSCCsDAG.AddEdge(VariableDescriptorToSCC[edge.Item1], VariableDescriptorToSCC[edge.Item2]);
+ }
+ }
+
+ SCC<VariableDescriptor> dummy = new SCC<VariableDescriptor>();
+ foreach (var n in dependsOnNonTransitive.Nodes) {
+ DependsOnSCCsDAG.AddEdge(VariableDescriptorToSCC[n], dummy);
+ }
+
+ if (CommandLineOptions.Clo.Trace) {
+ Console.WriteLine("Variable dependence: SCCs computed!");
+ }
+ }
+ return DependsOn(VariableDescriptorToSCC[v]);
+ }
+
+ public HashSet<VariableDescriptor> DependsOn(SCC<VariableDescriptor> vSCC) {
+
+ if (!DependsOnCache.ContainsKey(vSCC)) {
+ HashSet<VariableDescriptor> result = new HashSet<VariableDescriptor>();
+ if (vSCC.Count() > 0) {
+ result.UnionWith(vSCC);
+ foreach (var wSCC in DependsOnSCCsDAG.Successors(vSCC)) {
+ result.UnionWith(DependsOn(wSCC));
+ }
+ }
+ DependsOnCache[vSCC] = result;
+ }
+ return DependsOnCache[vSCC];
+ }
+
+ public void dump() {
+
+ Console.WriteLine("Variable dependence information");
+ Console.WriteLine("===============================");
+
+ Console.WriteLine("Global variables");
+ Console.WriteLine("================");
+
+ foreach (var GlobalEntry in dependsOnNonTransitive.Nodes.Where(Item => Item is GlobalDescriptor)) {
+ dump(GlobalEntry);
+ }
+
+ foreach (var proc in Procedures()) {
+ Console.WriteLine("Variables of " + proc);
+ Console.WriteLine("=====================");
+ foreach (var LocalEntry in dependsOnNonTransitive.Nodes.Where(Item => Item is LocalDescriptor
+ && ((LocalDescriptor)Item).Proc.Equals(proc))) {
+ dump(LocalEntry);
+ }
+ }
+ }
+
+ private void dump(VariableDescriptor vd) {
+ Console.Write(vd + " <- {");
+ bool first = true;
+
+ var SortedDependents = DependsOn(vd).ToList();
+ SortedDependents.Sort();
+ foreach (var Descriptor in SortedDependents) {
+ Console.Write((first ? "" : ",") + "\n " + Descriptor);
+ if (first) {
+ first = false;
+ }
+ }
+ Debug.Assert(!first);
+ Console.WriteLine("\n}\n");
+ }
+
+ private HashSet<string> Procedures() {
+ return new HashSet<string>(dependsOnNonTransitive.Nodes.Where(Item =>
+ Item is LocalDescriptor).Select(Item => ((LocalDescriptor)Item).Proc));
+ }
+
+ }
+
+ public static class Helper {
+
+ public static IEnumerable<Procedure> NonInlinedProcedures(this Program prog) {
+ return prog.Procedures.
+ Where(Item => QKeyValue.FindIntAttribute(Item.Attributes, "inline", -1) == -1);
+ }
+
+ public static IEnumerable<Implementation> NonInlinedImplementations(this Program prog) {
+ return prog.Implementations.
+ Where(Item => QKeyValue.FindIntAttribute(Item.Proc.Attributes, "inline", -1) == -1);
+ }
+
+ }
+
+}
diff --git a/Source/Core/Xml.cs b/Source/Core/Xml.cs
index dcc19b34..58a2c5b0 100644
--- a/Source/Core/Xml.cs
+++ b/Source/Core/Xml.cs
@@ -1,316 +1,316 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.IO;
-using System.Xml;
-using System.Collections.Generic;
-using System.Diagnostics.Contracts;
-namespace Microsoft.Boogie {
-
- public class XmlSink {
- string/*!*/ filename;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(filename != null);
- }
-
- [Rep]
- XmlWriter wr;
- public bool IsOpen {
- get {
- return wr != null;
- }
- }
-
- public XmlSink(string filename) {
- Contract.Requires(filename != null);
- this.filename = filename;
- }
-
- /// <summary>
- /// Returns null on success, in which case the caller should eventually invoke Close.
- /// Returns an error string on failure.
- /// </summary>
- public string Open() {
- //modifies this.*;
- Contract.Ensures(IsOpen);
- if (wr != null) {
- Close();
- }
- cce.BeginExpose(this);
- {
- XmlWriterSettings settings = new XmlWriterSettings();
- settings.Indent = true;
- wr = XmlWriter.Create(filename, settings);
- wr.WriteStartDocument();
- wr.WriteStartElement("boogie");
- wr.WriteAttributeString("version", CommandLineOptions.Clo.VersionNumber);
- wr.WriteAttributeString("commandLine", Environment.CommandLine);
- }
- cce.EndExpose();
- return null; // success
- }
-
- public void Close() {
- //modifies this.*;
- if (wr != null) {
- cce.BeginExpose(this);
- {
- wr.WriteEndDocument();
- wr.Close();
- wr = null;
- }
- cce.EndExpose();
- }
- }
-
- const string DateTimeFormatString = "u";
-
- public void WriteStartMethod(string methodName, DateTime startTime) {
- Contract.Requires(methodName != null);
- Contract.Requires(IsOpen);
- //modifies this.*;
- Contract.Ensures(IsOpen);
- Contract.Assert(wr != null);
- cce.BeginExpose(this);
- {
- wr.WriteStartElement("method");
- wr.WriteAttributeString("name", methodName);
- wr.WriteAttributeString("startTime", startTime.ToString(DateTimeFormatString));
- }
- cce.EndExpose();
- }
-
- public void WriteEndMethod(string outcome, DateTime endTime, TimeSpan elapsed) {
- Contract.Requires(outcome != null);
- Contract.Requires(IsOpen);
- //modifies this.*;
- Contract.Ensures(IsOpen);
- Contract.Assert(wr != null);
- cce.BeginExpose(this);
- {
- wr.WriteStartElement("conclusion");
- wr.WriteAttributeString("endTime", endTime.ToString(DateTimeFormatString));
- wr.WriteAttributeString("duration", elapsed.TotalSeconds.ToString());
- wr.WriteAttributeString("outcome", outcome);
-
- wr.WriteEndElement(); // outcome
- wr.WriteEndElement(); // method
- }
- cce.EndExpose();
- }
-
- public void WriteError(string message, IToken errorToken, IToken relatedToken, List<Block> trace) {
- Contract.Requires(errorToken != null);
- Contract.Requires(message != null);
- Contract.Requires(IsOpen && (trace == null || cce.Owner.Different(this, trace)));
- //modifies this.*, errorToken.*, relatedToken.*, trace.*;
- Contract.Ensures(IsOpen);
- Contract.Assert(wr != null);
- cce.BeginExpose(this);
- {
- wr.WriteStartElement("error");
- wr.WriteAttributeString("message", message);
- WriteTokenAttributes(errorToken);
- if (relatedToken != null) {
- wr.WriteStartElement("related");
- WriteTokenAttributes(relatedToken);
- wr.WriteEndElement();
- }
- if (trace != null) {
- wr.WriteStartElement("trace");
- {
- foreach (object bo in trace) {
- cce.LoopInvariant(wr != null);
- Contract.Assume(bo is Block);
- Block b = (Block)bo;
- wr.WriteStartElement("traceNode");
- {
- WriteTokenAttributes(b.tok);
- wr.WriteAttributeString("label", b.Label);
- }
- wr.WriteEndElement();
- }
- wr.WriteEndElement();
- }
- }
- wr.WriteEndElement();
- }
- cce.EndExpose();
- }
-
-#if CCI
- public void WriteError(string message, Cci.Node offendingNode, List<Block> trace) {
- Contract.Requires(offendingNode != null);
- Contract.Requires(message != null);
- Contract.Requires(IsOpen && cce.Owner.Different(this, offendingNode));
- Contract.Requires(trace == null || cce.Owner.Different(this, trace));
- //modifies this.*, offendingNode.*, trace.*;
- Contract.Ensures(IsOpen);
- Contract.Assert(wr != null);
- cce.BeginExpose(this);
- {
- wr.WriteStartElement("error");
- wr.WriteAttributeString("message", message);
- WriteTokenAttributes(offendingNode);
- if (trace != null) {
- wr.WriteStartElement("trace");
- {
- foreach (object bo in trace) {
- cce.LoopInvariant(wr != null);
- Contract.Assume(bo is Block);
- Block b = (Block)bo;
- wr.WriteStartElement("traceNode");
- {
- this.WriteTokenAttributes(b.tok);
- wr.WriteAttributeString("label", b.Label);
- }
- wr.WriteEndElement();
- }
- wr.WriteEndElement();
- }
- }
- wr.WriteEndElement();
- }
- cce.EndExpose();
- }
-#endif
-
- [Inside]
- private void WriteTokenAttributes(IToken tok) {
- Contract.Requires(wr != null && cce.IsPeerConsistent(wr));
- //modifies this.0, wr.*;
- if (tok != null && tok.filename != null) {
- wr.WriteAttributeString("file", tok.filename);
- wr.WriteAttributeString("line", tok.line.ToString());
- wr.WriteAttributeString("column", tok.col.ToString());
- }
- }
-
-#if CCI
- [Inside]
- private void WriteTokenAttributes(Cci.Node node) {
- Contract.Requires(node != null);
- Contract.Requires(wr != null && cce.IsPeerConsistent(wr));
- //modifies this.0, wr.*;
- Contract.Assert(wr != null);
- if (node.SourceContext.Document != null) {
- wr.WriteAttributeString("file", node.SourceContext.Document.Name);
- wr.WriteAttributeString("line", node.SourceContext.StartLine.ToString());
- wr.WriteAttributeString("column", node.SourceContext.StartColumn.ToString());
- }
- }
-#endif
-
- public void WriteStartInference(string inferenceName) {
- Contract.Requires(inferenceName != null);
- Contract.Requires(IsOpen);
- //modifies this.*;
- Contract.Ensures(IsOpen);
- Contract.Assert(wr != null);
- cce.BeginExpose(this);
- {
- wr.WriteStartElement("inference");
- wr.WriteAttributeString("name", inferenceName);
- }
- cce.EndExpose();
- }
-
- public void WriteEndInference() {
- Contract.Requires(IsOpen);
- //modifies this.*;
- Contract.Ensures(IsOpen);
- Contract.Assert(wr != null);
- cce.BeginExpose(this);
- {
- wr.WriteEndElement(); // inference
- }
- cce.EndExpose();
- }
-
- public void WriteContractParaAssignment(string varName, string val) {
- Contract.Requires(varName != null);
- Contract.Requires(IsOpen);
- //modifies this.*;
- Contract.Ensures(IsOpen);
- Contract.Assert(wr != null);
- cce.BeginExpose(this);
- {
- wr.WriteStartElement("assignment");
- wr.WriteAttributeString("name", varName);
- wr.WriteAttributeString("value", val);
- wr.WriteEndElement();
- }
- cce.EndExpose();
- }
-
- public void WriteStartFile(string filename) {
- Contract.Requires(filename != null);
- Contract.Requires(IsOpen);
- //modifies this.*;
- Contract.Ensures(IsOpen);
- Contract.Assert(wr != null);
- cce.BeginExpose(this);
- {
- wr.WriteStartElement("file");
- wr.WriteAttributeString("name", filename);
- }
- cce.EndExpose();
- }
-
- public void WriteEndFile() {
- Contract.Requires(IsOpen);
- //modifies this.*;
- Contract.Ensures(IsOpen);
- Contract.Assert(wr != null);
- cce.BeginExpose(this);
- {
- wr.WriteEndElement();
- }
- cce.EndExpose();
- }
-
- public void WriteFileFragment(string fragment) {
- Contract.Requires(fragment != null);
- Contract.Requires(IsOpen);
- //modifies this.*;
- Contract.Ensures(IsOpen);
- Contract.Assert(wr != null);
- cce.BeginExpose(this);
- {
- wr.WriteStartElement("fileFragment");
- wr.WriteAttributeString("name", fragment);
- wr.WriteEndElement();
- }
- cce.EndExpose();
- }
- }
-
- public class XmlFileScope : IDisposable {
- [Peer]
- [SpecPublic]
- XmlSink sink;
-
- [Captured]
- public XmlFileScope(XmlSink sink, string filename) {
- Contract.Requires(filename != null);
- Contract.Requires(sink == null || sink.IsOpen);
- //modifies sink.*;
- if (sink != null) {
- sink.WriteStartFile(filename); // invoke this method while "sink" is still peer consistent
- cce.Owner.AssignSame(this, sink);
- this.sink = sink;
- }
- }
-
- public void Dispose() {
- if (sink != null) {
- Contract.Assume(sink.IsOpen);
- sink.WriteEndFile();
- }
- }
- }
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+using System;
+using System.IO;
+using System.Xml;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+namespace Microsoft.Boogie {
+
+ public class XmlSink {
+ string/*!*/ filename;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(filename != null);
+ }
+
+ [Rep]
+ XmlWriter wr;
+ public bool IsOpen {
+ get {
+ return wr != null;
+ }
+ }
+
+ public XmlSink(string filename) {
+ Contract.Requires(filename != null);
+ this.filename = filename;
+ }
+
+ /// <summary>
+ /// Returns null on success, in which case the caller should eventually invoke Close.
+ /// Returns an error string on failure.
+ /// </summary>
+ public string Open() {
+ //modifies this.*;
+ Contract.Ensures(IsOpen);
+ if (wr != null) {
+ Close();
+ }
+ cce.BeginExpose(this);
+ {
+ XmlWriterSettings settings = new XmlWriterSettings();
+ settings.Indent = true;
+ wr = XmlWriter.Create(filename, settings);
+ wr.WriteStartDocument();
+ wr.WriteStartElement("boogie");
+ wr.WriteAttributeString("version", CommandLineOptions.Clo.VersionNumber);
+ wr.WriteAttributeString("commandLine", Environment.CommandLine);
+ }
+ cce.EndExpose();
+ return null; // success
+ }
+
+ public void Close() {
+ //modifies this.*;
+ if (wr != null) {
+ cce.BeginExpose(this);
+ {
+ wr.WriteEndDocument();
+ wr.Close();
+ wr = null;
+ }
+ cce.EndExpose();
+ }
+ }
+
+ const string DateTimeFormatString = "u";
+
+ public void WriteStartMethod(string methodName, DateTime startTime) {
+ Contract.Requires(methodName != null);
+ Contract.Requires(IsOpen);
+ //modifies this.*;
+ Contract.Ensures(IsOpen);
+ Contract.Assert(wr != null);
+ cce.BeginExpose(this);
+ {
+ wr.WriteStartElement("method");
+ wr.WriteAttributeString("name", methodName);
+ wr.WriteAttributeString("startTime", startTime.ToString(DateTimeFormatString));
+ }
+ cce.EndExpose();
+ }
+
+ public void WriteEndMethod(string outcome, DateTime endTime, TimeSpan elapsed) {
+ Contract.Requires(outcome != null);
+ Contract.Requires(IsOpen);
+ //modifies this.*;
+ Contract.Ensures(IsOpen);
+ Contract.Assert(wr != null);
+ cce.BeginExpose(this);
+ {
+ wr.WriteStartElement("conclusion");
+ wr.WriteAttributeString("endTime", endTime.ToString(DateTimeFormatString));
+ wr.WriteAttributeString("duration", elapsed.TotalSeconds.ToString());
+ wr.WriteAttributeString("outcome", outcome);
+
+ wr.WriteEndElement(); // outcome
+ wr.WriteEndElement(); // method
+ }
+ cce.EndExpose();
+ }
+
+ public void WriteError(string message, IToken errorToken, IToken relatedToken, List<Block> trace) {
+ Contract.Requires(errorToken != null);
+ Contract.Requires(message != null);
+ Contract.Requires(IsOpen && (trace == null || cce.Owner.Different(this, trace)));
+ //modifies this.*, errorToken.*, relatedToken.*, trace.*;
+ Contract.Ensures(IsOpen);
+ Contract.Assert(wr != null);
+ cce.BeginExpose(this);
+ {
+ wr.WriteStartElement("error");
+ wr.WriteAttributeString("message", message);
+ WriteTokenAttributes(errorToken);
+ if (relatedToken != null) {
+ wr.WriteStartElement("related");
+ WriteTokenAttributes(relatedToken);
+ wr.WriteEndElement();
+ }
+ if (trace != null) {
+ wr.WriteStartElement("trace");
+ {
+ foreach (object bo in trace) {
+ cce.LoopInvariant(wr != null);
+ Contract.Assume(bo is Block);
+ Block b = (Block)bo;
+ wr.WriteStartElement("traceNode");
+ {
+ WriteTokenAttributes(b.tok);
+ wr.WriteAttributeString("label", b.Label);
+ }
+ wr.WriteEndElement();
+ }
+ wr.WriteEndElement();
+ }
+ }
+ wr.WriteEndElement();
+ }
+ cce.EndExpose();
+ }
+
+#if CCI
+ public void WriteError(string message, Cci.Node offendingNode, List<Block> trace) {
+ Contract.Requires(offendingNode != null);
+ Contract.Requires(message != null);
+ Contract.Requires(IsOpen && cce.Owner.Different(this, offendingNode));
+ Contract.Requires(trace == null || cce.Owner.Different(this, trace));
+ //modifies this.*, offendingNode.*, trace.*;
+ Contract.Ensures(IsOpen);
+ Contract.Assert(wr != null);
+ cce.BeginExpose(this);
+ {
+ wr.WriteStartElement("error");
+ wr.WriteAttributeString("message", message);
+ WriteTokenAttributes(offendingNode);
+ if (trace != null) {
+ wr.WriteStartElement("trace");
+ {
+ foreach (object bo in trace) {
+ cce.LoopInvariant(wr != null);
+ Contract.Assume(bo is Block);
+ Block b = (Block)bo;
+ wr.WriteStartElement("traceNode");
+ {
+ this.WriteTokenAttributes(b.tok);
+ wr.WriteAttributeString("label", b.Label);
+ }
+ wr.WriteEndElement();
+ }
+ wr.WriteEndElement();
+ }
+ }
+ wr.WriteEndElement();
+ }
+ cce.EndExpose();
+ }
+#endif
+
+ [Inside]
+ private void WriteTokenAttributes(IToken tok) {
+ Contract.Requires(wr != null && cce.IsPeerConsistent(wr));
+ //modifies this.0, wr.*;
+ if (tok != null && tok.filename != null) {
+ wr.WriteAttributeString("file", tok.filename);
+ wr.WriteAttributeString("line", tok.line.ToString());
+ wr.WriteAttributeString("column", tok.col.ToString());
+ }
+ }
+
+#if CCI
+ [Inside]
+ private void WriteTokenAttributes(Cci.Node node) {
+ Contract.Requires(node != null);
+ Contract.Requires(wr != null && cce.IsPeerConsistent(wr));
+ //modifies this.0, wr.*;
+ Contract.Assert(wr != null);
+ if (node.SourceContext.Document != null) {
+ wr.WriteAttributeString("file", node.SourceContext.Document.Name);
+ wr.WriteAttributeString("line", node.SourceContext.StartLine.ToString());
+ wr.WriteAttributeString("column", node.SourceContext.StartColumn.ToString());
+ }
+ }
+#endif
+
+ public void WriteStartInference(string inferenceName) {
+ Contract.Requires(inferenceName != null);
+ Contract.Requires(IsOpen);
+ //modifies this.*;
+ Contract.Ensures(IsOpen);
+ Contract.Assert(wr != null);
+ cce.BeginExpose(this);
+ {
+ wr.WriteStartElement("inference");
+ wr.WriteAttributeString("name", inferenceName);
+ }
+ cce.EndExpose();
+ }
+
+ public void WriteEndInference() {
+ Contract.Requires(IsOpen);
+ //modifies this.*;
+ Contract.Ensures(IsOpen);
+ Contract.Assert(wr != null);
+ cce.BeginExpose(this);
+ {
+ wr.WriteEndElement(); // inference
+ }
+ cce.EndExpose();
+ }
+
+ public void WriteContractParaAssignment(string varName, string val) {
+ Contract.Requires(varName != null);
+ Contract.Requires(IsOpen);
+ //modifies this.*;
+ Contract.Ensures(IsOpen);
+ Contract.Assert(wr != null);
+ cce.BeginExpose(this);
+ {
+ wr.WriteStartElement("assignment");
+ wr.WriteAttributeString("name", varName);
+ wr.WriteAttributeString("value", val);
+ wr.WriteEndElement();
+ }
+ cce.EndExpose();
+ }
+
+ public void WriteStartFile(string filename) {
+ Contract.Requires(filename != null);
+ Contract.Requires(IsOpen);
+ //modifies this.*;
+ Contract.Ensures(IsOpen);
+ Contract.Assert(wr != null);
+ cce.BeginExpose(this);
+ {
+ wr.WriteStartElement("file");
+ wr.WriteAttributeString("name", filename);
+ }
+ cce.EndExpose();
+ }
+
+ public void WriteEndFile() {
+ Contract.Requires(IsOpen);
+ //modifies this.*;
+ Contract.Ensures(IsOpen);
+ Contract.Assert(wr != null);
+ cce.BeginExpose(this);
+ {
+ wr.WriteEndElement();
+ }
+ cce.EndExpose();
+ }
+
+ public void WriteFileFragment(string fragment) {
+ Contract.Requires(fragment != null);
+ Contract.Requires(IsOpen);
+ //modifies this.*;
+ Contract.Ensures(IsOpen);
+ Contract.Assert(wr != null);
+ cce.BeginExpose(this);
+ {
+ wr.WriteStartElement("fileFragment");
+ wr.WriteAttributeString("name", fragment);
+ wr.WriteEndElement();
+ }
+ cce.EndExpose();
+ }
+ }
+
+ public class XmlFileScope : IDisposable {
+ [Peer]
+ [SpecPublic]
+ XmlSink sink;
+
+ [Captured]
+ public XmlFileScope(XmlSink sink, string filename) {
+ Contract.Requires(filename != null);
+ Contract.Requires(sink == null || sink.IsOpen);
+ //modifies sink.*;
+ if (sink != null) {
+ sink.WriteStartFile(filename); // invoke this method while "sink" is still peer consistent
+ cce.Owner.AssignSame(this, sink);
+ this.sink = sink;
+ }
+ }
+
+ public void Dispose() {
+ if (sink != null) {
+ Contract.Assume(sink.IsOpen);
+ sink.WriteEndFile();
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/Source/Core/cce.cs b/Source/Core/cce.cs
index ef594484..1e0b12a5 100644
--- a/Source/Core/cce.cs
+++ b/Source/Core/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;
-
-/// <summary>
-/// A class containing static methods to extend the functionality of Code Contracts
-/// </summary>
-
-public static class cce {
- //[Pure]
- //public static bool NonNullElements<T>(Microsoft.Dafny.Graph<T> collection) {
- // return collection != null && cce.NonNullElements(collection.TopologicallySortedComponents());
- //}
- [Pure]
- public static T NonNull<T>(T t) {
- Contract.Assert(t != null);
- return t;
- }
- [Pure]
- public static bool NonNullElements<T>(IEnumerable<T> collection) {
- return collection != null && Contract.ForAll(collection, c => c != null);
- }
- [Pure]
- public static bool NonNullElements<TKey, TValue>(IDictionary<TKey, TValue> 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);
- //}
- /// <summary>
- /// For possibly-null lists of non-null elements
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="collection"></param>
- /// <param name="nullability">If true, the collection is treated as an IEnumerable&lt;T!&gt;?, rather than an IEnumerable&lt;T!&gt;!</param>
- /// <returns></returns>
- [Pure]
- public static bool NonNullElements<T>(IEnumerable<T> 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<TKey, TValue>(KeyValuePair<TKey, TValue> kvp) {
- return kvp.Key != null && kvp.Value != null;
- }
- [Pure]
- public static bool NonNullElements<T>(IEnumerator<T> iEnumerator) {
- return iEnumerator != null;
- }
- //[Pure]
- //public static bool NonNullElements<T>(Graphing.Graph<T> 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<T> toList<T>(PureCollections.Sequence s) {
- // List<T> toRet = new List<T>();
- // 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;
+
+/// <summary>
+/// A class containing static methods to extend the functionality of Code Contracts
+/// </summary>
+
+public static class cce {
+ //[Pure]
+ //public static bool NonNullElements<T>(Microsoft.Dafny.Graph<T> collection) {
+ // return collection != null && cce.NonNullElements(collection.TopologicallySortedComponents());
+ //}
+ [Pure]
+ public static T NonNull<T>(T t) {
+ Contract.Assert(t != null);
+ return t;
+ }
+ [Pure]
+ public static bool NonNullElements<T>(IEnumerable<T> collection) {
+ return collection != null && Contract.ForAll(collection, c => c != null);
+ }
+ [Pure]
+ public static bool NonNullElements<TKey, TValue>(IDictionary<TKey, TValue> 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);
+ //}
+ /// <summary>
+ /// For possibly-null lists of non-null elements
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="collection"></param>
+ /// <param name="nullability">If true, the collection is treated as an IEnumerable&lt;T!&gt;?, rather than an IEnumerable&lt;T!&gt;!</param>
+ /// <returns></returns>
+ [Pure]
+ public static bool NonNullElements<T>(IEnumerable<T> 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<TKey, TValue>(KeyValuePair<TKey, TValue> kvp) {
+ return kvp.Key != null && kvp.Value != null;
+ }
+ [Pure]
+ public static bool NonNullElements<T>(IEnumerator<T> iEnumerator) {
+ return iEnumerator != null;
+ }
+ //[Pure]
+ //public static bool NonNullElements<T>(Graphing.Graph<T> 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<T> toList<T>(PureCollections.Sequence s) {
+ // List<T> toRet = new List<T>();
+ // 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