// // 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 set); public virtual BoxedExpression Substitute (BoxedExpression what, BoxedExpression replace) { if (this == what || Equals (what)) return replace; return RecursiveSubstitute (what, replace); } public abstract BoxedExpression Substitute (Func map); protected internal virtual BoxedExpression RecursiveSubstitute (BoxedExpression what, BoxedExpression replace) { return this; } public abstract Result ForwardDecode (PC pc, Visitor visitor, Data data) where Visitor : IILVisitor; 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 (Expression external, IFullExpressionDecoder decoder) where Expression : IEquatable { return new ExternalBox (external, decoder); } public static BoxedExpression MakeIsinst (TypeNode type, BoxedExpression arg) { return new IsinstExpression (arg, type); } public static BoxedExpression Convert (ExternalExpression expr, IFullExpressionDecoder 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 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 (PC pc, Visitor visitor, Data data) { return visitor.Assert (pc, this.Tag, Dummy.Value, data); } public override BoxedExpression Substitute (Func 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 (PC pc, Visitor visitor, Data data) { return visitor.Assume (pc, this.Tag, Dummy.Value, data); } public override BoxedExpression Substitute (Func 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 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 (Func 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 (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 set) { this.Expr.AddFreeVariables (set); } public override BoxedExpression Substitute (Func map) { return this.Expr.Substitute (map); } public override Result ForwardDecode (PC pc, Visitor visitor, Data data) { return this.Expr.ForwardDecode (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 set) { } public override BoxedExpression Substitute (Func map) { return this; } public override Result ForwardDecode (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 set) { this.Condition.AddFreeVariables (set); } public abstract override Result ForwardDecode (PC pc, Visitor visitor, Data data); public abstract override BoxedExpression Substitute (Func map); } #endregion #region Nested type: ExternalBox public class ExternalBox : BoxedExpression where LabeledSymbol : IEquatable { private readonly IFullExpressionDecoder decoder; private readonly LabeledSymbol expr; private Optional> binary; private Optional> constant; private Optional> isInst; private Optional> isVar; private Optional> type; private Optional> unary; private Optional var; public ExternalBox (LabeledSymbol external, IFullExpressionDecoder decoder) { this.expr = external; this.decoder = decoder; } public override bool IsBinary { get { Tuple binary; TryGetBinaryFromCache (out binary); return binary.Item1; } } public override BinaryOperator BinaryOperator { get { Tuple binary; bool res = TryGetBinaryFromCache (out binary); if (!res) throw new InvalidOperationException (); return binary.Item2; } } public override BoxedExpression BinaryLeftArgument { get { Tuple binary; bool res = TryGetBinaryFromCache (out binary); if (!res) throw new InvalidOperationException (); return binary.Item3; } } public override BoxedExpression BinaryRightArgument { get { Tuple binary; bool res = TryGetBinaryFromCache (out binary); if (!res) throw new InvalidOperationException (); return binary.Item4; } } public override bool IsConstant { get { Tuple consta; TryGetConstantFromCache (out consta); return consta.Item1; } } public override object Constant { get { Tuple consta; if (!TryGetConstantFromCache (out consta)) throw new InvalidOperationException (); return consta.Item2; } } public override object ConstantType { get { Tuple consta; if (!TryGetConstantFromCache (out consta)) throw new InvalidOperationException(); return consta.Item3; } } public override bool IsIsinst { get { Tuple isinst; TryGetIsInstFromCache (out isinst); return isinst.Item1; } } public override bool IsNull { get { return this.decoder.IsNull (this.expr); } } public override bool IsUnary { get { Tuple unary; TryGetUnaryFromCache (out unary); return unary.Item1; } } public override UnaryOperator UnaryOperator { get { Tuple unary; if (!TryGetUnaryFromCache (out unary)) throw new InvalidOperationException(); return unary.Item2; } } public override BoxedExpression UnaryArgument { get { Tuple 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 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 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 (res, op, For (left, this.decoder), For (right, this.decoder)); return res; } private bool TryGetUnaryFromCache (out Tuple 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 (res, op, For (arg, this.decoder)); return res; } private bool TryGetIsInstFromCache (out Tuple 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 (res, For (arg, this.decoder), type); return res; } private bool TryGetConstantFromCache (out Tuple 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 (res, value, type); return res; } private bool TryGetTypeFromCache (out Pair 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 (res, type); return res; } private bool TryGetIsVariableFromCache (out Pair 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 (res, value); return res; } public override bool IsBinaryExpression (out BinaryOperator op, out BoxedExpression left, out BoxedExpression right) { Tuple 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 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 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 set) { this.decoder.AddFreeVariables (this.expr, new SetWrapper (set, this.decoder)); } public override BoxedExpression Substitute (Func map) { return Convert (this.expr, this.decoder).Substitute (map); } public override bool TryGetType (out object type) { Pair result; if (!TryGetTypeFromCache (out result) || !result.Key) { type = null; return false; } type = result.Value; return true; } public override Result ForwardDecode (PC pc, Visitor visitor, Data data) { Tuple 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, IEnumerable { private readonly IFullExpressionDecoder decoder; private readonly HashSet set; #region Implementation of IEnumerable public IEnumerator GetEnumerator () { throw new NotImplementedException (); } IEnumerator IEnumerable.GetEnumerator () { return GetEnumerator (); } #endregion public SetWrapper (HashSet set, IFullExpressionDecoder decoder) { this.set = set; this.decoder = decoder; } #region Implementation of ICollection public void Add (LabeledSymbol item) { this.set.Add (For (item, this.decoder)); } bool ISet.Add (LabeledSymbol item) { Add (item); return true; } public void UnionWith (IEnumerable other) { throw new NotImplementedException (); } public void IntersectWith (IEnumerable other) { throw new NotImplementedException (); } public void ExceptWith (IEnumerable other) { throw new NotImplementedException (); } public void SymmetricExceptWith (IEnumerable other) { throw new NotImplementedException (); } public bool IsSubsetOf (IEnumerable other) { throw new NotImplementedException (); } public bool IsSupersetOf (IEnumerable other) { throw new NotImplementedException (); } public bool IsProperSupersetOf (IEnumerable other) { throw new NotImplementedException (); } public bool IsProperSubsetOf (IEnumerable other) { throw new NotImplementedException (); } public bool Overlaps (IEnumerable other) { throw new NotImplementedException (); } public bool SetEquals (IEnumerable 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 (PC pc, Visitor visitor, Data data) { return visitor.Isinst (pc, this.type, Dummy.Value, Dummy.Value, data); } public override void AddFreeVariables (HashSet set) { this.arg.AddFreeVariables (set); } public override BoxedExpression Substitute (Func 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 set) { this.Old.AddFreeVariables (set); } public override BoxedExpression Substitute (Func 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 (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 set) { } public override BoxedExpression Substitute (Func map) { return this; } public override Result ForwardDecode (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 set) { } public override BoxedExpression Substitute (Func map) { return this; } public override Result ForwardDecode (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 set) { this.Argument.AddFreeVariables (set); } public override BoxedExpression Substitute (Func 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 (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 set) { this.Value.AddFreeVariables (set); } public override BoxedExpression Substitute (Func 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 (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) null) { } public VariableExpression (object var, Sequence path) { this.UnderlyingVar = var; this.Path = path != null ? path.AsEnumerable ().ToArray () : null; } public VariableExpression (object var, Sequence 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 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 (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 (Func map) { if (!(this.UnderlyingVar is Variable)) return this; var variable = ((Variable) this.UnderlyingVar); return map (variable, this); } } #endregion } }