Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

1716 lines
42 KiB
C#

//
// BoxedExpression.cs
//
// Authors:
// Alexander Chebaturkin (chebaturkin@gmail.com)
//
// Copyright (C) 2011 Alexander Chebaturkin
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Mono.CodeContracts.Static.AST;
using Mono.CodeContracts.Static.AST.Visitors;
using Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding;
using Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths;
using Mono.CodeContracts.Static.ControlFlow;
using Mono.CodeContracts.Static.DataStructures;
using Mono.CodeContracts.Static.Providers;
namespace Mono.CodeContracts.Static.Proving {
internal abstract class BoxedExpression {
public virtual bool IsVariable
{
get { return false; }
}
public virtual bool IsBooleanTyped
{
get { return false; }
}
public virtual object UnderlyingVariable
{
get { return false; }
}
public virtual PathElement[] AccessPath
{
get { return null; }
}
public virtual bool IsConstant
{
get { return false; }
}
public virtual object Constant
{
get { throw new InvalidOperationException (); }
}
public virtual object ConstantType
{
get { throw new InvalidOperationException (); }
}
public virtual bool IsSizeof
{
get { return false; }
}
public virtual bool IsUnary
{
get { return false; }
}
public virtual UnaryOperator UnaryOperator
{
get { throw new InvalidOperationException (); }
}
public virtual BoxedExpression UnaryArgument
{
get { throw new InvalidOperationException (); }
}
public virtual bool IsBinary
{
get { return false; }
}
public virtual BinaryOperator BinaryOperator
{
get { throw new InvalidOperationException (); }
}
public virtual BoxedExpression BinaryLeftArgument
{
get { throw new InvalidOperationException (); }
}
public virtual BoxedExpression BinaryRightArgument
{
get { throw new InvalidOperationException (); }
}
public virtual bool IsIsinst
{
get { return false; }
}
public virtual bool IsNull
{
get { return false; }
}
public virtual bool IsCast
{
get { return false; }
}
public virtual bool IsResult
{
get { return false; }
}
public virtual bool TryGetType (out object type)
{
type = null;
return false;
}
public virtual bool IsBinaryExpression (out BinaryOperator op, out BoxedExpression left, out BoxedExpression right)
{
op = BinaryOperator.Add;
left = null;
right = null;
return false;
}
public virtual bool IsUnaryExpression (out UnaryOperator op, out BoxedExpression argument)
{
op = UnaryOperator.Conv_i;
argument = null;
return false;
}
public virtual bool Sizeof (out int size)
{
return false.Without (out size);
}
public virtual bool IsIsinstExpression (out BoxedExpression expr, out TypeNode type)
{
expr = null;
type = null;
return false;
}
public abstract void AddFreeVariables (HashSet<BoxedExpression> set);
public virtual BoxedExpression Substitute (BoxedExpression what, BoxedExpression replace)
{
if (this == what || Equals (what))
return replace;
return RecursiveSubstitute (what, replace);
}
public abstract BoxedExpression Substitute<Variable> (Func<Variable, BoxedExpression, BoxedExpression> map);
protected internal virtual BoxedExpression RecursiveSubstitute (BoxedExpression what, BoxedExpression replace)
{
return this;
}
public abstract Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
where Visitor : IILVisitor<PC, Dummy, Dummy, Data, Result>;
public static BoxedExpression Var (object var)
{
return new VariableExpression (var);
}
public static BoxedExpression Const (object value, TypeNode type)
{
return new ConstantExpression (value, type);
}
public static BoxedExpression For<Variable, Expression> (Expression external, IFullExpressionDecoder<Variable, Expression> decoder)
where Expression : IEquatable<Expression>
{
return new ExternalBox<Variable, Expression> (external, decoder);
}
public static BoxedExpression MakeIsinst (TypeNode type, BoxedExpression arg)
{
return new IsinstExpression (arg, type);
}
public static BoxedExpression Convert<Variable, ExternalExpression> (ExternalExpression expr, IFullExpressionDecoder<Variable, ExternalExpression> decoder)
{
TypeNode type;
object value;
if (decoder.IsConstant (expr, out value, out type))
return new ConstantExpression (value, type);
if (decoder.IsNull (expr))
return new ConstantExpression (null, null);
object variable;
if (decoder.IsVariable (expr, out variable)) {
Sequence<PathElement> variableAccessPath = decoder.GetVariableAccessPath (expr);
return new VariableExpression (variable, variableAccessPath);
}
if (decoder.IsSizeof (expr, out type)) {
int sizeAsConstant;
return decoder.TrySizeOfAsConstant (expr, out sizeAsConstant) ? new SizeOfExpression (type, sizeAsConstant) : new SizeOfExpression (type);
}
ExternalExpression arg;
if (decoder.IsIsinst (expr, out arg, out type))
return new IsinstExpression (Convert (arg, decoder), type);
UnaryOperator op;
if (decoder.IsUnaryExpression (expr, out op, out arg))
return new UnaryExpression (op, Convert (arg, decoder));
BinaryOperator bop;
ExternalExpression left;
ExternalExpression right;
if (!decoder.IsBinaryExpression (expr, out bop, out left, out right))
throw new InvalidOperationException ();
return new BinaryExpression (bop, Convert (left, decoder), Convert (right, decoder));
}
public static BoxedExpression Binary (BinaryOperator bop, BoxedExpression left, BoxedExpression right)
{
return new BinaryExpression (bop, left, right);
}
public static BoxedExpression Unary (UnaryOperator op, BoxedExpression arg)
{
return new UnaryExpression (op, arg);
}
#region Nested type: AssertExpression
public class AssertExpression : ContractExpression {
public AssertExpression (BoxedExpression condition, EdgeTag tag, APC pc) : base (condition, tag, pc)
{
}
#region Overrides of ContractExpression
public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
{
return visitor.Assert (pc, this.Tag, Dummy.Value, data);
}
public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
{
BoxedExpression cond = this.Condition.Substitute (map);
if (cond == this.Condition)
return this;
if (cond == null)
return null;
return new AssertExpression (cond, this.Tag, this.Apc);
}
#endregion
}
#endregion
#region Nested type: AssumeExpression
public class AssumeExpression : ContractExpression {
public AssumeExpression (BoxedExpression condition, EdgeTag tag, APC pc)
: base (condition, tag, pc)
{
}
#region Overrides of ContractExpression
public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
{
return visitor.Assume (pc, this.Tag, Dummy.Value, data);
}
public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
{
BoxedExpression cond = this.Condition.Substitute (map);
if (cond == this.Condition)
return this;
if (cond == null)
return null;
return new AssumeExpression (cond, this.Tag, this.Apc);
}
#endregion
}
#endregion
#region Nested type: BinaryExpression
public class BinaryExpression : BoxedExpression {
public readonly BoxedExpression Left;
public readonly BinaryOperator Op;
public readonly BoxedExpression Right;
public BinaryExpression (BinaryOperator op, BoxedExpression left, BoxedExpression right)
{
this.Op = op;
this.Left = left;
this.Right = right;
}
public override bool IsBinary
{
get { return true; }
}
public override BoxedExpression BinaryLeftArgument
{
get { return this.Left; }
}
public override BoxedExpression BinaryRightArgument
{
get { return this.Right; }
}
public override BinaryOperator BinaryOperator
{
get { return this.Op; }
}
public override bool IsBinaryExpression (out BinaryOperator op, out BoxedExpression left, out BoxedExpression right)
{
op = this.Op;
left = this.Left;
right = this.Right;
return true;
}
#region Overrides of BoxedExpression
public override void AddFreeVariables (HashSet<BoxedExpression> set)
{
this.Left.AddFreeVariables (set);
this.Right.AddFreeVariables (set);
}
protected internal override BoxedExpression RecursiveSubstitute (BoxedExpression what, BoxedExpression replace)
{
BoxedExpression left = this.Left.Substitute (what, replace);
BoxedExpression right = this.Right.Substitute (what, replace);
if (left == this.Left && right == this.Right)
return this;
return new BinaryExpression (this.Op, left, right);
}
public override BoxedExpression Substitute<Variable> (Func<Variable, BoxedExpression, BoxedExpression> map)
{
BoxedExpression left = this.Left.Substitute (map);
if (left == null)
return null;
BoxedExpression right = this.Right.Substitute (map);
if (right == null)
return null;
if (this.Left == left && this.Right == right)
return this;
return new BinaryExpression (this.Op, left, right);
}
public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
{
return visitor.Binary (pc, this.Op, Dummy.Value, Dummy.Value, Dummy.Value, data);
}
#endregion
}
#endregion
#region Nested type: CastExpression
public class CastExpression : BoxedExpression {
public readonly TypeNode CastToType;
public readonly BoxedExpression Expr;
public CastExpression (TypeNode castToType, BoxedExpression expr)
{
this.CastToType = castToType;
this.Expr = expr;
}
public override bool IsCast
{
get { return true; }
}
public override PathElement[] AccessPath
{
get { return this.Expr.AccessPath; }
}
public override BoxedExpression BinaryLeftArgument
{
get { return this.Expr.BinaryLeftArgument; }
}
public override BoxedExpression BinaryRightArgument
{
get { return this.Expr.BinaryRightArgument; }
}
public override BinaryOperator BinaryOperator
{
get { return this.Expr.BinaryOperator; }
}
public override object Constant
{
get { return this.Expr.Constant; }
}
public override object ConstantType
{
get { return this.Expr.ConstantType; }
}
public override bool IsBinary
{
get { return this.Expr.IsBinary; }
}
public override bool IsBooleanTyped
{
get { return this.Expr.IsBooleanTyped; }
}
public override bool IsConstant
{
get { return this.Expr.IsConstant; }
}
public override bool IsSizeof
{
get { return this.Expr.IsSizeof; }
}
public override bool IsNull
{
get { return this.Expr.IsNull; }
}
public override bool IsIsinst
{
get { return this.Expr.IsIsinst; }
}
public override bool IsResult
{
get { return this.Expr.IsResult; }
}
public override bool IsUnary
{
get { return this.Expr.IsUnary; }
}
public override bool IsVariable
{
get { return this.Expr.IsVariable; }
}
public override BoxedExpression UnaryArgument
{
get { return this.Expr.UnaryArgument; }
}
public override UnaryOperator UnaryOperator
{
get { return this.Expr.UnaryOperator; }
}
public override object UnderlyingVariable
{
get { return this.Expr.UnderlyingVariable; }
}
public override void AddFreeVariables (HashSet<BoxedExpression> set)
{
this.Expr.AddFreeVariables (set);
}
public override BoxedExpression Substitute<Variable> (Func<Variable, BoxedExpression, BoxedExpression> map)
{
return this.Expr.Substitute (map);
}
public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
{
return this.Expr.ForwardDecode<Data, Result, Visitor> (pc, visitor, data);
}
public override bool IsBinaryExpression (out BinaryOperator op, out BoxedExpression left, out BoxedExpression right)
{
return this.Expr.IsBinaryExpression (out op, out left, out right);
}
protected internal override BoxedExpression RecursiveSubstitute (BoxedExpression what, BoxedExpression replace)
{
return this.Expr.RecursiveSubstitute (what, replace);
}
public override BoxedExpression Substitute (BoxedExpression what, BoxedExpression replace)
{
return this.Expr.Substitute (what, replace);
}
public override bool IsUnaryExpression (out UnaryOperator op, out BoxedExpression argument)
{
return this.Expr.IsUnaryExpression (out op, out argument);
}
}
#endregion
#region Nested type: ConstantExpression
public class ConstantExpression : BoxedExpression {
public readonly TypeNode Type;
public readonly object Value;
private readonly bool is_boolean;
public ConstantExpression (object value, TypeNode type)
: this (value, type, false)
{
}
public ConstantExpression (object value, TypeNode type, bool isBoolean)
{
this.Value = value;
this.Type = type;
this.is_boolean = isBoolean;
}
public override bool IsBooleanTyped
{
get { return this.is_boolean; }
}
public override bool IsConstant
{
get { return true; }
}
public override object Constant
{
get { return this.Value; }
}
public override object ConstantType
{
get { return this.Type; }
}
public override bool IsNull
{
get
{
if (this.Value == null)
return true;
var conv = this.Value as IConvertible;
if (conv != null) {
try {
if (conv.ToInt32 (null) == 0)
return true;
} catch {
return false;
}
}
return false;
}
}
public override void AddFreeVariables (HashSet<BoxedExpression> set)
{
}
public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
{
return this;
}
public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
{
if (this.Value == null)
return visitor.LoadNull (pc, Dummy.Value, data);
return visitor.LoadConst (pc, this.Type, this.Value, Dummy.Value, data);
}
}
#endregion
#region Nested type: ContractExpression
public abstract class ContractExpression : BoxedExpression {
public readonly APC Apc;
public readonly BoxedExpression Condition;
public readonly EdgeTag Tag;
public ContractExpression (BoxedExpression condition, EdgeTag tag, APC pc)
{
this.Tag = tag;
this.Condition = condition;
this.Apc = pc;
}
public override void AddFreeVariables (HashSet<BoxedExpression> set)
{
this.Condition.AddFreeVariables (set);
}
public abstract override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data);
public abstract override BoxedExpression Substitute<Variable> (Func<Variable, BoxedExpression, BoxedExpression> map);
}
#endregion
#region Nested type: ExternalBox
public class ExternalBox<Variable, LabeledSymbol> : BoxedExpression
where LabeledSymbol : IEquatable<LabeledSymbol> {
private readonly IFullExpressionDecoder<Variable, LabeledSymbol> decoder;
private readonly LabeledSymbol expr;
private Optional<Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression>> binary;
private Optional<Tuple<bool, object, TypeNode>> constant;
private Optional<Tuple<bool, BoxedExpression, TypeNode>> isInst;
private Optional<Pair<bool, object>> isVar;
private Optional<Pair<bool, TypeNode>> type;
private Optional<Tuple<bool, UnaryOperator, BoxedExpression>> unary;
private Optional<object> var;
public ExternalBox (LabeledSymbol external, IFullExpressionDecoder<Variable, LabeledSymbol> decoder)
{
this.expr = external;
this.decoder = decoder;
}
public override bool IsBinary
{
get
{
Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> binary;
TryGetBinaryFromCache (out binary);
return binary.Item1;
}
}
public override BinaryOperator BinaryOperator
{
get
{
Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> binary;
bool res = TryGetBinaryFromCache (out binary);
if (!res)
throw new InvalidOperationException ();
return binary.Item2;
}
}
public override BoxedExpression BinaryLeftArgument
{
get
{
Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> binary;
bool res = TryGetBinaryFromCache (out binary);
if (!res)
throw new InvalidOperationException ();
return binary.Item3;
}
}
public override BoxedExpression BinaryRightArgument
{
get
{
Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> binary;
bool res = TryGetBinaryFromCache (out binary);
if (!res)
throw new InvalidOperationException ();
return binary.Item4;
}
}
public override bool IsConstant
{
get
{
Tuple<bool, object, TypeNode> consta;
TryGetConstantFromCache (out consta);
return consta.Item1;
}
}
public override object Constant
{
get
{
Tuple<bool, object, TypeNode> consta;
if (!TryGetConstantFromCache (out consta))
throw new InvalidOperationException ();
return consta.Item2;
}
}
public override object ConstantType
{
get
{
Tuple<bool, object, TypeNode> consta;
if (!TryGetConstantFromCache (out consta))
throw new InvalidOperationException();
return consta.Item3;
}
}
public override bool IsIsinst
{
get
{
Tuple<bool, BoxedExpression, TypeNode> isinst;
TryGetIsInstFromCache (out isinst);
return isinst.Item1;
}
}
public override bool IsNull
{
get { return this.decoder.IsNull (this.expr); }
}
public override bool IsUnary
{
get
{
Tuple<bool, UnaryOperator, BoxedExpression> unary;
TryGetUnaryFromCache (out unary);
return unary.Item1;
}
}
public override UnaryOperator UnaryOperator
{
get
{
Tuple<bool, UnaryOperator, BoxedExpression> unary;
if (!TryGetUnaryFromCache (out unary))
throw new InvalidOperationException();
return unary.Item2;
}
}
public override BoxedExpression UnaryArgument
{
get
{
Tuple<bool, UnaryOperator, BoxedExpression> unary;
if (!TryGetUnaryFromCache (out unary))
throw new InvalidOperationException ();
return unary.Item3;
}
}
public override bool IsSizeof
{
get
{
TypeNode type;
return this.decoder.IsSizeof (this.expr, out type);
}
}
public override bool IsVariable
{
get
{
Pair<bool, object> var1;
TryGetIsVariableFromCache (out var1);
return var1.Key;
}
}
public override object UnderlyingVariable
{
get
{
if (!this.var.IsValid)
this.var = this.decoder.UnderlyingVariable (this.expr);
return this.var.Value;
}
}
private bool TryGetBinaryFromCache (out Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> binary)
{
if (this.binary.IsValid) {
binary = this.binary.Value;
return true;
}
BinaryOperator op;
LabeledSymbol left;
LabeledSymbol right;
bool res = this.decoder.IsBinaryExpression (this.expr, out op, out left, out right);
this.binary = binary = new Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> (res, op, For (left, this.decoder), For (right, this.decoder));
return res;
}
private bool TryGetUnaryFromCache (out Tuple<bool, UnaryOperator, BoxedExpression> unary)
{
if (this.unary.IsValid) {
unary = this.unary.Value;
return true;
}
UnaryOperator op;
LabeledSymbol arg;
bool res = this.decoder.IsUnaryExpression (this.expr, out op, out arg);
this.unary = unary = new Tuple<bool, UnaryOperator, BoxedExpression> (res, op, For (arg, this.decoder));
return res;
}
private bool TryGetIsInstFromCache (out Tuple<bool, BoxedExpression, TypeNode> isinst)
{
if (this.isInst.IsValid) {
isinst = this.isInst.Value;
return true;
}
LabeledSymbol arg;
TypeNode type;
bool res = this.decoder.IsIsinst (this.expr, out arg, out type);
this.isInst = isinst = new Tuple<bool, BoxedExpression, TypeNode> (res, For (arg, this.decoder), type);
return res;
}
private bool TryGetConstantFromCache (out Tuple<bool, object, TypeNode> result)
{
if (this.constant.IsValid) {
result = this.constant.Value;
return true;
}
object value;
TypeNode type;
bool res = this.decoder.IsConstant (this.expr, out value, out type);
this.constant = result = new Tuple<bool, object, TypeNode> (res, value, type);
return res;
}
private bool TryGetTypeFromCache (out Pair<bool, TypeNode> result)
{
if (this.type.IsValid) {
result = this.type.Value;
return true;
}
TypeNode type;
bool res = this.decoder.TryGetType (this.expr, out type);
this.type = result = new Pair<bool, TypeNode> (res, type);
return res;
}
private bool TryGetIsVariableFromCache (out Pair<bool, object> result)
{
if (this.isVar.IsValid) {
result = this.isVar.Value;
return true;
}
object value;
bool res = this.decoder.IsVariable (this.expr, out value);
this.isVar = result = new Pair<bool, object> (res, value);
return res;
}
public override bool IsBinaryExpression (out BinaryOperator op, out BoxedExpression left, out BoxedExpression right)
{
Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> bin;
if (!TryGetBinaryFromCache (out bin) || !bin.Item1) {
op = BinaryOperator.Add;
left = null;
right = null;
return false;
}
op = bin.Item2;
left = bin.Item3;
right = bin.Item4;
return true;
}
public override bool IsIsinstExpression (out BoxedExpression expr, out TypeNode type)
{
Tuple<bool, BoxedExpression, TypeNode> isinst;
if (!TryGetIsInstFromCache (out isinst) || !isinst.Item1) {
expr = null;
type = null;
return false;
}
expr = isinst.Item2;
type = isinst.Item3;
return true;
}
public override bool IsUnaryExpression (out UnaryOperator op, out BoxedExpression argument)
{
Tuple<bool, UnaryOperator, BoxedExpression> unary;
if (!TryGetUnaryFromCache (out unary) || !unary.Item1) {
op = UnaryOperator.Conv_i;
argument = null;
return false;
}
op = unary.Item2;
argument = unary.Item3;
return true;
}
protected internal override BoxedExpression RecursiveSubstitute (BoxedExpression what, BoxedExpression replace)
{
return Convert (this.expr, this.decoder).Substitute (what, replace);
}
public override void AddFreeVariables (HashSet<BoxedExpression> set)
{
this.decoder.AddFreeVariables (this.expr, new SetWrapper (set, this.decoder));
}
public override BoxedExpression Substitute<V> (Func<V, BoxedExpression, BoxedExpression> map)
{
return Convert (this.expr, this.decoder).Substitute (map);
}
public override bool TryGetType (out object type)
{
Pair<bool, TypeNode> result;
if (!TryGetTypeFromCache (out result) || !result.Key) {
type = null;
return false;
}
type = result.Value;
return true;
}
public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
{
Tuple<bool, object, TypeNode> constant;
if (TryGetConstantFromCache (out constant)) {
if (constant.Item2 != null)
return visitor.LoadConst (pc, constant.Item3, constant, Dummy.Value, data);
return visitor.LoadNull (pc, Dummy.Value, data);
}
UnaryOperator op;
LabeledSymbol arg;
if (this.decoder.IsUnaryExpression (this.expr, out op, out arg))
return visitor.Unary (pc, op, false, Dummy.Value, Dummy.Value, data);
BinaryOperator bop;
LabeledSymbol left;
LabeledSymbol right;
if (this.decoder.IsBinaryExpression (this.expr, out bop, out left, out right))
return visitor.Binary (pc, bop, Dummy.Value, Dummy.Value, Dummy.Value, data);
TypeNode type;
if (this.decoder.IsIsinst (this.expr, out arg, out type))
return visitor.Isinst (pc, type, Dummy.Value, Dummy.Value, data);
if (this.decoder.IsNull (this.expr))
return visitor.LoadNull (pc, Dummy.Value, data);
if (this.decoder.IsSizeof (this.expr, out type))
return visitor.Sizeof (pc, type, Dummy.Value, data);
return visitor.Nop (pc, data);
}
#region Nested type: SetWrapper
private struct SetWrapper : ISet<LabeledSymbol>, IEnumerable<LabeledSymbol> {
private readonly IFullExpressionDecoder<Variable, LabeledSymbol> decoder;
private readonly HashSet<BoxedExpression> set;
#region Implementation of IEnumerable
public IEnumerator<LabeledSymbol> GetEnumerator ()
{
throw new NotImplementedException ();
}
IEnumerator IEnumerable.GetEnumerator ()
{
return GetEnumerator ();
}
#endregion
public SetWrapper (HashSet<BoxedExpression> set, IFullExpressionDecoder<Variable, LabeledSymbol> decoder)
{
this.set = set;
this.decoder = decoder;
}
#region Implementation of ICollection<ExternalExpression>
public void Add (LabeledSymbol item)
{
this.set.Add (For (item, this.decoder));
}
bool ISet<LabeledSymbol>.Add (LabeledSymbol item)
{
Add (item);
return true;
}
public void UnionWith (IEnumerable<LabeledSymbol> other)
{
throw new NotImplementedException ();
}
public void IntersectWith (IEnumerable<LabeledSymbol> other)
{
throw new NotImplementedException ();
}
public void ExceptWith (IEnumerable<LabeledSymbol> other)
{
throw new NotImplementedException ();
}
public void SymmetricExceptWith (IEnumerable<LabeledSymbol> other)
{
throw new NotImplementedException ();
}
public bool IsSubsetOf (IEnumerable<LabeledSymbol> other)
{
throw new NotImplementedException ();
}
public bool IsSupersetOf (IEnumerable<LabeledSymbol> other)
{
throw new NotImplementedException ();
}
public bool IsProperSupersetOf (IEnumerable<LabeledSymbol> other)
{
throw new NotImplementedException ();
}
public bool IsProperSubsetOf (IEnumerable<LabeledSymbol> other)
{
throw new NotImplementedException ();
}
public bool Overlaps (IEnumerable<LabeledSymbol> other)
{
throw new NotImplementedException ();
}
public bool SetEquals (IEnumerable<LabeledSymbol> other)
{
throw new NotImplementedException ();
}
public void Clear ()
{
throw new NotImplementedException ();
}
public bool Contains (LabeledSymbol item)
{
throw new NotImplementedException ();
}
public void CopyTo (LabeledSymbol[] array, int arrayIndex)
{
throw new NotImplementedException ();
}
public bool Remove (LabeledSymbol item)
{
throw new NotImplementedException ();
}
public int Count
{
get { throw new NotImplementedException (); }
}
public bool IsReadOnly
{
get { throw new NotImplementedException (); }
}
#endregion
}
#endregion
}
#endregion
#region Nested type: IsinstExpression
public class IsinstExpression : BoxedExpression {
private readonly BoxedExpression arg;
private readonly TypeNode type;
public IsinstExpression (BoxedExpression boxedExpression, TypeNode type)
{
this.arg = boxedExpression;
this.type = type;
}
public override bool IsIsinst
{
get { return true; }
}
public override BoxedExpression UnaryArgument
{
get { return this.arg; }
}
public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
{
return visitor.Isinst (pc, this.type, Dummy.Value, Dummy.Value, data);
}
public override void AddFreeVariables (HashSet<BoxedExpression> set)
{
this.arg.AddFreeVariables (set);
}
public override BoxedExpression Substitute<Variable> (Func<Variable, BoxedExpression, BoxedExpression> map)
{
BoxedExpression arg = this.arg.Substitute (map);
if (arg == this.arg)
return this;
if (arg == null)
return null;
return new IsinstExpression (arg, this.type);
}
}
#endregion
#region Nested type: OldExpression
public class OldExpression : BoxedExpression {
private const string ContractOldValueTemplate = "Contract.OldValue({0})";
public readonly BoxedExpression Old;
public readonly TypeNode Type;
public OldExpression (BoxedExpression old, TypeNode type)
{
this.Old = old;
this.Type = type;
}
#region Overrides of BoxedExpression
public override void AddFreeVariables (HashSet<BoxedExpression> set)
{
this.Old.AddFreeVariables (set);
}
public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
{
BoxedExpression old = this.Old.Substitute (map);
if (old == this.Old)
return this;
if (old == null)
return null;
return new OldExpression (old, this.Type);
}
public override bool IsBinaryExpression (out BinaryOperator op, out BoxedExpression left, out BoxedExpression right)
{
return this.Old.IsBinaryExpression (out op, out left, out right);
}
public override bool IsUnaryExpression (out UnaryOperator op, out BoxedExpression argument)
{
return this.Old.IsUnaryExpression (out op, out argument);
}
public override bool IsIsinstExpression (out BoxedExpression expr, out TypeNode type)
{
return this.Old.IsIsinstExpression (out expr, out type);
}
public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
{
return visitor.EndOld (pc, new PC (pc.Node, 0), this.Type, Dummy.Value, Dummy.Value, data);
}
#endregion
public override PathElement[] AccessPath
{
get { return this.Old.AccessPath; }
}
public override BoxedExpression BinaryLeftArgument
{
get { return this.Old.BinaryLeftArgument; }
}
public override BoxedExpression BinaryRightArgument
{
get { return this.Old.BinaryRightArgument; }
}
public override BinaryOperator BinaryOperator
{
get { return this.Old.BinaryOperator; }
}
public override object Constant
{
get { return this.Old.Constant; }
}
public override object ConstantType
{
get { return this.Old.ConstantType; }
}
public override bool IsBinary
{
get { return this.Old.IsBinary; }
}
public override bool IsConstant
{
get { return this.Old.IsConstant; }
}
public override bool IsSizeof
{
get { return this.Old.IsSizeof; }
}
public override bool IsNull
{
get { return this.Old.IsNull; }
}
public override bool IsIsinst
{
get { return this.Old.IsIsinst; }
}
public override bool IsUnary
{
get { return this.Old.IsUnary; }
}
public override bool IsVariable
{
get { return this.Old.IsVariable; }
}
public override BoxedExpression UnaryArgument
{
get { return this.Old.UnaryArgument; }
}
public override UnaryOperator UnaryOperator
{
get { return this.Old.UnaryOperator; }
}
public override object UnderlyingVariable
{
get { return this.Old.UnderlyingVariable; }
}
}
#endregion
#region Nested type: PC
public struct PC {
public readonly int Index;
public readonly BoxedExpression Node;
public PC (BoxedExpression expr, int index)
{
this.Node = expr;
this.Index = index;
}
}
#endregion
#region Nested type: ResultExpression
public class ResultExpression : BoxedExpression {
private const string ContractResultTemplate = "Contract.Result<{0}>()";
public readonly TypeNode Type;
public ResultExpression (TypeNode type)
{
this.Type = type;
}
public override bool IsResult
{
get { return true; }
}
public override void AddFreeVariables (HashSet<BoxedExpression> set)
{
}
public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
{
return this;
}
public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
{
return visitor.LoadResult (pc, this.Type, Dummy.Value, Dummy.Value, data);
}
}
#endregion
#region Nested type: SizeOfExpression
public class SizeOfExpression : BoxedExpression {
public readonly int SizeAsConstant;
public readonly TypeNode Type;
public SizeOfExpression (TypeNode type, int sizeAsConstant)
{
this.Type = type;
this.SizeAsConstant = sizeAsConstant;
}
public SizeOfExpression (TypeNode type)
: this (type, -1)
{
}
public override bool IsSizeof
{
get { return true; }
}
public override bool Sizeof (out int size)
{
size = SizeAsConstant;
return size >= 0;
}
public override void AddFreeVariables (HashSet<BoxedExpression> set)
{
}
public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
{
return this;
}
public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
{
return visitor.Sizeof (pc, this.Type, Dummy.Value, data);
}
}
#endregion
#region Nested type: UnaryExpression
public class UnaryExpression : BoxedExpression {
public readonly BoxedExpression Argument;
public readonly UnaryOperator Op;
public UnaryExpression (UnaryOperator op, BoxedExpression argument)
{
this.Op = op;
this.Argument = argument;
}
public override bool IsUnary
{
get { return true; }
}
public override BoxedExpression UnaryArgument
{
get { return this.Argument; }
}
public override UnaryOperator UnaryOperator
{
get { return this.Op; }
}
public override bool IsUnaryExpression (out UnaryOperator op, out BoxedExpression argument)
{
op = this.Op;
argument = this.Argument;
return true;
}
public override void AddFreeVariables (HashSet<BoxedExpression> set)
{
this.Argument.AddFreeVariables (set);
}
public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
{
BoxedExpression argument = this.Argument.Substitute (map);
if (argument == this.Argument)
return this;
if (argument == null)
return null;
return new UnaryExpression (this.Op, argument);
}
protected internal override BoxedExpression RecursiveSubstitute (BoxedExpression what, BoxedExpression replace)
{
BoxedExpression argument = this.Argument.Substitute (what, replace);
if (argument == this.Argument)
return this;
return new UnaryExpression (this.Op, argument);
}
public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
{
return visitor.Unary (pc, this.Op, false, Dummy.Value, Dummy.Value, data);
}
public override bool Equals (object obj)
{
if (this == obj)
return true;
var unary = obj as UnaryExpression;
return unary != null && this.Op == unary.Op && this.Argument.Equals (unary.Argument);
}
public override int GetHashCode ()
{
return this.Op.GetHashCode () * 13 + (this.Argument == null ? 0 : this.Argument.GetHashCode ());
}
}
#endregion
#region Nested type: ValueAtReturnExpression
public class ValueAtReturnExpression : BoxedExpression {
private const string ContractValueAtReturnTemplate = "Contract.ValueAtReturn({0})";
public readonly TypeNode Type;
public readonly BoxedExpression Value;
public ValueAtReturnExpression (BoxedExpression old, TypeNode type)
{
this.Value = old;
this.Type = type;
}
#region Overrides of BoxedExpression
public override void AddFreeVariables (HashSet<BoxedExpression> set)
{
this.Value.AddFreeVariables (set);
}
public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
{
BoxedExpression value = this.Value.Substitute (map);
if (value == this.Value)
return this;
if (value == null)
return null;
return new ValueAtReturnExpression (value, this.Type);
}
public override bool IsBinaryExpression (out BinaryOperator op, out BoxedExpression left, out BoxedExpression right)
{
return this.Value.IsBinaryExpression (out op, out left, out right);
}
public override bool IsUnaryExpression (out UnaryOperator op, out BoxedExpression argument)
{
return this.Value.IsUnaryExpression (out op, out argument);
}
public override bool IsIsinstExpression (out BoxedExpression expr, out TypeNode type)
{
return this.Value.IsIsinstExpression (out expr, out type);
}
public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
{
throw new NotImplementedException ();
}
#endregion
public override PathElement[] AccessPath
{
get { return this.Value.AccessPath; }
}
public override BoxedExpression BinaryLeftArgument
{
get { return this.Value.BinaryLeftArgument; }
}
public override BoxedExpression BinaryRightArgument
{
get { return this.Value.BinaryRightArgument; }
}
public override BinaryOperator BinaryOperator
{
get { return this.Value.BinaryOperator; }
}
public override object Constant
{
get { return this.Value.Constant; }
}
public override object ConstantType
{
get { return this.Value.ConstantType; }
}
public override bool IsBinary
{
get { return this.Value.IsBinary; }
}
public override bool IsConstant
{
get { return this.Value.IsConstant; }
}
public override bool IsSizeof
{
get { return this.Value.IsSizeof; }
}
public override bool IsNull
{
get { return this.Value.IsNull; }
}
public override bool IsIsinst
{
get { return this.Value.IsIsinst; }
}
public override bool IsUnary
{
get { return this.Value.IsUnary; }
}
public override bool IsVariable
{
get { return this.Value.IsVariable; }
}
public override BoxedExpression UnaryArgument
{
get { return this.Value.UnaryArgument; }
}
public override UnaryOperator UnaryOperator
{
get { return this.Value.UnaryOperator; }
}
public override object UnderlyingVariable
{
get { return this.Value.UnderlyingVariable; }
}
}
#endregion
#region Nested type: VariableExpression
public class VariableExpression : BoxedExpression {
private readonly PathElement[] Path;
private readonly object UnderlyingVar;
public readonly object VarType;
public VariableExpression (object var)
: this (var, (Sequence<PathElement>) null)
{
}
public VariableExpression (object var, Sequence<PathElement> path)
{
this.UnderlyingVar = var;
this.Path = path != null ? path.AsEnumerable ().ToArray () : null;
}
public VariableExpression (object var, Sequence<PathElement> path, object type)
: this (var, path)
{
this.VarType = type;
}
public VariableExpression (object var, PathElement[] path)
{
this.UnderlyingVar = var;
this.Path = path;
}
public VariableExpression (object var, PathElement[] path, object type)
: this (var, path)
{
this.VarType = type;
}
public override bool IsVariable
{
get { return true; }
}
public override object UnderlyingVariable
{
get { return this.UnderlyingVar; }
}
public override PathElement[] AccessPath
{
get { return this.Path; }
}
public override bool IsBooleanTyped
{
get { return this.Path != null && this.Path [this.Path.Length - 1].IsBooleanTyped; }
}
public override bool TryGetType (out object type)
{
type = this.VarType;
return type != null;
}
public override void AddFreeVariables (HashSet<BoxedExpression> set)
{
set.Add (this);
}
protected internal override BoxedExpression RecursiveSubstitute (BoxedExpression what, BoxedExpression replace)
{
var varExpr = what as VariableExpression;
if (varExpr != null && varExpr.UnderlyingVar.Equals (this.UnderlyingVar))
return replace;
return this;
}
public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
{
return visitor.Nop (pc, data);
}
public override bool Equals (object obj)
{
if (this == obj)
return true;
var boxedExpression = obj as BoxedExpression;
if (boxedExpression != null && boxedExpression.IsVariable)
return this.UnderlyingVar.Equals (boxedExpression.UnderlyingVariable);
return false;
}
public override int GetHashCode ()
{
return this.UnderlyingVariable != null ? 0 : this.UnderlyingVariable.GetHashCode ();
}
public override BoxedExpression Substitute<Variable> (Func<Variable, BoxedExpression, BoxedExpression> map)
{
if (!(this.UnderlyingVar is Variable))
return this;
var variable = ((Variable) this.UnderlyingVar);
return map (variable, this);
}
}
#endregion
}
}