diff options
Diffstat (limited to 'Source/Core')
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<T!>?, rather than an IEnumerable<T!>!</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<T!>?, rather than an IEnumerable<T!>!</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 |