The base architecture for code-contracts analysis
[mono.git] / mcs / class / Mono.CodeContracts / Mono.CodeContracts.Static.Proving / BoxedExpression.cs
1 // 
2 // BoxedExpression.cs
3 // 
4 // Authors:
5 //      Alexander Chebaturkin (chebaturkin@gmail.com)
6 // 
7 // Copyright (C) 2011 Alexander Chebaturkin
8 // 
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //  
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 // 
28
29 using System;
30 using System.Collections;
31 using System.Collections.Generic;
32 using System.IO;
33 using System.Linq;
34 using Mono.CodeContracts.Static.AST;
35 using Mono.CodeContracts.Static.AST.Visitors;
36 using Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding;
37 using Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths;
38 using Mono.CodeContracts.Static.ControlFlow;
39 using Mono.CodeContracts.Static.DataStructures;
40
41 namespace Mono.CodeContracts.Static.Proving {
42         internal abstract class BoxedExpression {
43                 public virtual bool IsVariable
44                 {
45                         get { return false; }
46                 }
47
48                 public virtual bool IsBooleanTyped
49                 {
50                         get { return false; }
51                 }
52
53                 public virtual object UnderlyingVariable
54                 {
55                         get { return false; }
56                 }
57
58                 public virtual PathElement[] AccessPath
59                 {
60                         get { return null; }
61                 }
62
63                 public virtual bool IsConstant
64                 {
65                         get { return false; }
66                 }
67
68                 public virtual object Constant
69                 {
70                         get { throw new InvalidOperationException (); }
71                 }
72
73                 public virtual object ConstantType
74                 {
75                         get { throw new InvalidOperationException (); }
76                 }
77
78                 public virtual bool IsSizeof
79                 {
80                         get { return false; }
81                 }
82
83                 public virtual bool IsUnary
84                 {
85                         get { return false; }
86                 }
87
88                 public virtual UnaryOperator UnaryOperator
89                 {
90                         get { throw new InvalidOperationException (); }
91                 }
92
93                 public virtual BoxedExpression UnaryArgument
94                 {
95                         get { throw new InvalidOperationException (); }
96                 }
97
98                 public virtual bool IsBinary
99                 {
100                         get { return false; }
101                 }
102
103                 public virtual BinaryOperator BinaryOperator
104                 {
105                         get { throw new InvalidOperationException (); }
106                 }
107
108                 public virtual BoxedExpression BinaryLeftArgument
109                 {
110                         get { throw new InvalidOperationException (); }
111                 }
112
113                 public virtual BoxedExpression BinaryRightArgument
114                 {
115                         get { throw new InvalidOperationException (); }
116                 }
117
118                 public virtual bool IsIsinst
119                 {
120                         get { return false; }
121                 }
122
123                 public virtual bool IsNull
124                 {
125                         get { return false; }
126                 }
127
128                 public virtual bool IsCast
129                 {
130                         get { return false; }
131                 }
132
133                 public virtual bool IsResult
134                 {
135                         get { return false; }
136                 }
137
138                 public virtual bool TryGetType (out object type)
139                 {
140                         type = null;
141                         return false;
142                 }
143
144                 public virtual bool IsBinaryExpression (out BinaryOperator op, out BoxedExpression left, out BoxedExpression right)
145                 {
146                         op = BinaryOperator.Add;
147                         left = null;
148                         right = null;
149                         return false;
150                 }
151
152                 public virtual bool IsUnaryExpression (out UnaryOperator op, out BoxedExpression argument)
153                 {
154                         op = UnaryOperator.Conv_i;
155                         argument = null;
156                         return false;
157                 }
158
159                 public virtual bool IsIsinstExpression (out BoxedExpression expr, out TypeNode type)
160                 {
161                         expr = null;
162                         type = null;
163                         return false;
164                 }
165
166                 public abstract void AddFreeVariables (HashSet<BoxedExpression> set);
167
168                 public virtual BoxedExpression Substitute (BoxedExpression what, BoxedExpression replace)
169                 {
170                         if (this == what || Equals (what))
171                                 return replace;
172
173                         return RecursiveSubstitute (what, replace);
174                 }
175
176                 public abstract BoxedExpression Substitute<Variable> (Func<Variable, BoxedExpression, BoxedExpression> map);
177
178                 protected internal virtual BoxedExpression RecursiveSubstitute (BoxedExpression what, BoxedExpression replace)
179                 {
180                         return this;
181                 }
182
183                 public abstract Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
184                         where Visitor : IILVisitor<PC, Dummy, Dummy, Data, Result>;
185
186                 public static BoxedExpression Var (object var)
187                 {
188                         return new VariableExpression (var);
189                 }
190
191                 public static BoxedExpression For<Variable, Expression> (Expression external, IFullExpressionDecoder<Variable, Expression> decoder)
192                         where Expression : IEquatable<Expression>
193                 {
194                         return new ExternalBox<Variable, Expression> (external, decoder);
195                 }
196
197                 public static BoxedExpression MakeIsinst (TypeNode type, BoxedExpression arg)
198                 {
199                         return new IsinstExpression (arg, type);
200                 }
201
202                 public static BoxedExpression Convert<Variable, ExternalExpression> (ExternalExpression expr, IFullExpressionDecoder<Variable, ExternalExpression> decoder)
203                 {
204                         TypeNode type;
205                         object value;
206                         if (decoder.IsConstant (expr, out value, out type))
207                                 return new ConstantExpression (value, type);
208                         if (decoder.IsNull (expr))
209                                 return new ConstantExpression (null, null);
210
211                         object variable;
212                         if (decoder.IsVariable (expr, out variable)) {
213                                 LispList<PathElement> variableAccessPath = decoder.GetVariableAccessPath (expr);
214                                 return new VariableExpression (variable, variableAccessPath);
215                         }
216
217                         if (decoder.IsSizeof (expr, out type)) {
218                                 int sizeAsConstant;
219                                 return decoder.TrySizeOfAsConstant (expr, out sizeAsConstant) ? new SizeOfExpression (type, sizeAsConstant) : new SizeOfExpression (type);
220                         }
221
222                         ExternalExpression arg;
223                         if (decoder.IsIsinst (expr, out arg, out type))
224                                 return new IsinstExpression (Convert (arg, decoder), type);
225
226                         UnaryOperator op;
227                         if (decoder.IsUnaryExpression (expr, out op, out arg))
228                                 return new UnaryExpression (op, Convert (arg, decoder));
229
230                         BinaryOperator bop;
231                         ExternalExpression left;
232                         ExternalExpression right;
233                         if (!decoder.IsBinaryExpression (expr, out bop, out left, out right))
234                                 throw new InvalidOperationException ();
235
236                         return new BinaryExpression (bop, Convert (left, decoder), Convert (right, decoder));
237                 }
238
239                 #region Nested type: AssertExpression
240                 public class AssertExpression : ContractExpression {
241                         public AssertExpression (BoxedExpression condition, EdgeTag tag, APC pc) : base (condition, tag, pc)
242                         {
243                         }
244
245                         #region Overrides of ContractExpression
246                         public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
247                         {
248                                 return visitor.Assert (pc, this.Tag, Dummy.Value, data);
249                         }
250
251                         public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
252                         {
253                                 BoxedExpression cond = this.Condition.Substitute (map);
254                                 if (cond == this.Condition)
255                                         return this;
256                                 if (cond == null)
257                                         return null;
258
259                                 return new AssertExpression (cond, this.Tag, this.Apc);
260                         }
261                         #endregion
262                 }
263                 #endregion
264
265                 #region Nested type: AssumeExpression
266                 public class AssumeExpression : ContractExpression {
267                         public AssumeExpression (BoxedExpression condition, EdgeTag tag, APC pc)
268                                 : base (condition, tag, pc)
269                         {
270                         }
271
272                         #region Overrides of ContractExpression
273                         public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
274                         {
275                                 return visitor.Assume (pc, this.Tag, Dummy.Value, data);
276                         }
277
278                         public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
279                         {
280                                 BoxedExpression cond = this.Condition.Substitute (map);
281                                 if (cond == this.Condition)
282                                         return this;
283                                 if (cond == null)
284                                         return null;
285
286                                 return new AssumeExpression (cond, this.Tag, this.Apc);
287                         }
288                         #endregion
289                 }
290                 #endregion
291
292                 #region Nested type: BinaryExpression
293                 public class BinaryExpression : BoxedExpression {
294                         public readonly BoxedExpression Left;
295                         public readonly BinaryOperator Op;
296                         public readonly BoxedExpression Right;
297
298                         public BinaryExpression (BinaryOperator op, BoxedExpression left, BoxedExpression right)
299                         {
300                                 this.Op = op;
301                                 this.Left = left;
302                                 this.Right = right;
303                         }
304
305                         public override bool IsBinary
306                         {
307                                 get { return true; }
308                         }
309
310                         public override BoxedExpression BinaryLeftArgument
311                         {
312                                 get { return this.Left; }
313                         }
314
315                         public override BoxedExpression BinaryRightArgument
316                         {
317                                 get { return this.Right; }
318                         }
319
320                         public override BinaryOperator BinaryOperator
321                         {
322                                 get { return this.Op; }
323                         }
324
325                         public override bool IsBinaryExpression (out BinaryOperator op, out BoxedExpression left, out BoxedExpression right)
326                         {
327                                 op = this.Op;
328                                 left = this.Left;
329                                 right = this.Right;
330                                 return true;
331                         }
332
333                         #region Overrides of BoxedExpression
334                         public override void AddFreeVariables (HashSet<BoxedExpression> set)
335                         {
336                                 this.Left.AddFreeVariables (set);
337                                 this.Right.AddFreeVariables (set);
338                         }
339
340                         protected internal override BoxedExpression RecursiveSubstitute (BoxedExpression what, BoxedExpression replace)
341                         {
342                                 BoxedExpression left = this.Left.Substitute (what, replace);
343                                 BoxedExpression right = this.Right.Substitute (what, replace);
344                                 if (left == this.Left && right == this.Right)
345                                         return this;
346
347                                 return new BinaryExpression (this.Op, left, right);
348                         }
349
350                         public override BoxedExpression Substitute<Variable> (Func<Variable, BoxedExpression, BoxedExpression> map)
351                         {
352                                 BoxedExpression left = this.Left.Substitute (map);
353                                 if (left == null)
354                                         return null;
355
356                                 BoxedExpression right = this.Right.Substitute (map);
357                                 if (right == null)
358                                         return null;
359
360                                 if (this.Left == left && this.Right == right)
361                                         return this;
362                                 return new BinaryExpression (this.Op, left, right);
363                         }
364
365                         public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
366                         {
367                                 return visitor.Binary (pc, this.Op, Dummy.Value, Dummy.Value, Dummy.Value, data);
368                         }
369                         #endregion
370                 }
371                 #endregion
372
373                 #region Nested type: CastExpression
374                 public class CastExpression : BoxedExpression {
375                         public readonly TypeNode CastToType;
376                         public readonly BoxedExpression Expr;
377
378                         public CastExpression (TypeNode castToType, BoxedExpression expr)
379                         {
380                                 this.CastToType = castToType;
381                                 this.Expr = expr;
382                         }
383
384                         public override bool IsCast
385                         {
386                                 get { return true; }
387                         }
388
389                         public override PathElement[] AccessPath
390                         {
391                                 get { return this.Expr.AccessPath; }
392                         }
393
394                         public override BoxedExpression BinaryLeftArgument
395                         {
396                                 get { return this.Expr.BinaryLeftArgument; }
397                         }
398
399                         public override BoxedExpression BinaryRightArgument
400                         {
401                                 get { return this.Expr.BinaryRightArgument; }
402                         }
403
404                         public override BinaryOperator BinaryOperator
405                         {
406                                 get { return this.Expr.BinaryOperator; }
407                         }
408
409                         public override object Constant
410                         {
411                                 get { return this.Expr.Constant; }
412                         }
413
414                         public override object ConstantType
415                         {
416                                 get { return this.Expr.ConstantType; }
417                         }
418
419                         public override bool IsBinary
420                         {
421                                 get { return this.Expr.IsBinary; }
422                         }
423
424                         public override bool IsBooleanTyped
425                         {
426                                 get { return this.Expr.IsBooleanTyped; }
427                         }
428
429                         public override bool IsConstant
430                         {
431                                 get { return this.Expr.IsConstant; }
432                         }
433
434
435                         public override bool IsSizeof
436                         {
437                                 get { return this.Expr.IsSizeof; }
438                         }
439
440                         public override bool IsNull
441                         {
442                                 get { return this.Expr.IsNull; }
443                         }
444
445                         public override bool IsIsinst
446                         {
447                                 get { return this.Expr.IsIsinst; }
448                         }
449
450                         public override bool IsResult
451                         {
452                                 get { return this.Expr.IsResult; }
453                         }
454
455                         public override bool IsUnary
456                         {
457                                 get { return this.Expr.IsUnary; }
458                         }
459
460                         public override bool IsVariable
461                         {
462                                 get { return this.Expr.IsVariable; }
463                         }
464
465                         public override BoxedExpression UnaryArgument
466                         {
467                                 get { return this.Expr.UnaryArgument; }
468                         }
469
470                         public override UnaryOperator UnaryOperator
471                         {
472                                 get { return this.Expr.UnaryOperator; }
473                         }
474
475                         public override object UnderlyingVariable
476                         {
477                                 get { return this.Expr.UnderlyingVariable; }
478                         }
479
480
481                         public override void AddFreeVariables (HashSet<BoxedExpression> set)
482                         {
483                                 this.Expr.AddFreeVariables (set);
484                         }
485
486                         public override BoxedExpression Substitute<Variable> (Func<Variable, BoxedExpression, BoxedExpression> map)
487                         {
488                                 return this.Expr.Substitute (map);
489                         }
490
491                         public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
492                         {
493                                 return this.Expr.ForwardDecode<Data, Result, Visitor> (pc, visitor, data);
494                         }
495
496                         public override bool IsBinaryExpression (out BinaryOperator op, out BoxedExpression left, out BoxedExpression right)
497                         {
498                                 return this.Expr.IsBinaryExpression (out op, out left, out right);
499                         }
500
501                         protected internal override BoxedExpression RecursiveSubstitute (BoxedExpression what, BoxedExpression replace)
502                         {
503                                 return this.Expr.RecursiveSubstitute (what, replace);
504                         }
505
506                         public override BoxedExpression Substitute (BoxedExpression what, BoxedExpression replace)
507                         {
508                                 return this.Expr.Substitute (what, replace);
509                         }
510
511                         public override bool IsUnaryExpression (out UnaryOperator op, out BoxedExpression argument)
512                         {
513                                 return this.Expr.IsUnaryExpression (out op, out argument);
514                         }
515                 }
516                 #endregion
517
518                 #region Nested type: ConstantExpression
519                 public class ConstantExpression : BoxedExpression {
520                         public readonly TypeNode Type;
521                         public readonly object Value;
522                         private readonly bool is_boolean;
523
524                         public ConstantExpression (object value, TypeNode type)
525                                 : this (value, type, false)
526                         {
527                         }
528
529                         public ConstantExpression (object value, TypeNode type, bool isBoolean)
530                         {
531                                 this.Value = value;
532                                 this.Type = type;
533                                 this.is_boolean = isBoolean;
534                         }
535
536                         public override bool IsBooleanTyped
537                         {
538                                 get { return this.is_boolean; }
539                         }
540
541                         public override bool IsConstant
542                         {
543                                 get { return true; }
544                         }
545
546                         public override object Constant
547                         {
548                                 get { return this.Value; }
549                         }
550
551                         public override object ConstantType
552                         {
553                                 get { return this.Type; }
554                         }
555
556                         public override bool IsNull
557                         {
558                                 get
559                                 {
560                                         if (this.Value == null)
561                                                 return true;
562
563                                         var conv = this.Value as IConvertible;
564                                         if (conv != null) {
565                                                 try {
566                                                         if (conv.ToInt32 (null) == 0)
567                                                                 return true;
568                                                 } catch {
569                                                         return false;
570                                                 }
571                                         }
572
573                                         return false;
574                                 }
575                         }
576
577                         public override void AddFreeVariables (HashSet<BoxedExpression> set)
578                         {
579                         }
580
581                         public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
582                         {
583                                 return this;
584                         }
585
586                         public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
587                         {
588                                 if (this.Value == null)
589                                         return visitor.LoadNull (pc, Dummy.Value, data);
590
591                                 return visitor.LoadConst (pc, this.Type, this.Value, Dummy.Value, data);
592                         }
593                 }
594                 #endregion
595
596                 #region Nested type: ContractExpression
597                 public abstract class ContractExpression : BoxedExpression {
598                         public readonly APC Apc;
599                         public readonly BoxedExpression Condition;
600                         public readonly EdgeTag Tag;
601
602                         public ContractExpression (BoxedExpression condition, EdgeTag tag, APC pc)
603                         {
604                                 this.Tag = tag;
605                                 this.Condition = condition;
606                                 this.Apc = pc;
607                         }
608
609                         public override void AddFreeVariables (HashSet<BoxedExpression> set)
610                         {
611                                 this.Condition.AddFreeVariables (set);
612                         }
613
614                         public abstract override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data);
615                         public abstract override BoxedExpression Substitute<Variable> (Func<Variable, BoxedExpression, BoxedExpression> map);
616                 }
617                 #endregion
618
619                 #region Nested type: ExternalBox
620                 public class ExternalBox<Variable, LabeledSymbol> : BoxedExpression
621                         where LabeledSymbol : IEquatable<LabeledSymbol> {
622                         private readonly IFullExpressionDecoder<Variable, LabeledSymbol> decoder;
623                         private readonly LabeledSymbol expr;
624                         private Optional<Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression>> binary;
625
626                         private Optional<Tuple<bool, object, TypeNode>> constant;
627                         private Optional<Tuple<bool, BoxedExpression, TypeNode>> isInst;
628                         private Optional<Pair<bool, object>> isVar;
629                         private Optional<Pair<bool, TypeNode>> type;
630                         private Optional<Tuple<bool, UnaryOperator, BoxedExpression>> unary;
631                         private Optional<object> var;
632
633                         public ExternalBox (LabeledSymbol external, IFullExpressionDecoder<Variable, LabeledSymbol> decoder)
634                         {
635                                 this.expr = external;
636                                 this.decoder = decoder;
637                         }
638
639                         public override bool IsBinary
640                         {
641                                 get
642                                 {
643                                         Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> binary;
644                                         TryGetBinaryFromCache (out binary);
645                                         return binary.Item1;
646                                 }
647                         }
648
649                         public override BinaryOperator BinaryOperator
650                         {
651                                 get
652                                 {
653                                         Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> binary;
654                                         bool res = TryGetBinaryFromCache (out binary);
655                                         if (!res)
656                                                 throw new InvalidOperationException ();
657
658                                         return binary.Item2;
659                                 }
660                         }
661
662                         public override BoxedExpression BinaryLeftArgument
663                         {
664                                 get
665                                 {
666                                         Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> binary;
667                                         bool res = TryGetBinaryFromCache (out binary);
668                                         if (!res)
669                                                 throw new InvalidOperationException ();
670
671                                         return binary.Item3;
672                                 }
673                         }
674
675                         public override BoxedExpression BinaryRightArgument
676                         {
677                                 get
678                                 {
679                                         Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> binary;
680                                         bool res = TryGetBinaryFromCache (out binary);
681                                         if (!res)
682                                                 throw new InvalidOperationException ();
683
684                                         return binary.Item4;
685                                 }
686                         }
687
688                         public override bool IsConstant
689                         {
690                                 get
691                                 {
692                                         Tuple<bool, object, TypeNode> consta;
693                                         TryGetConstantFromCache (out consta);
694
695                                         return consta.Item1;
696                                 }
697                         }
698
699                         public override object Constant
700                         {
701                                 get
702                                 {
703                                         Tuple<bool, object, TypeNode> consta;
704                                         if (!TryGetConstantFromCache (out consta))
705                                                 throw new InvalidOperationException ();
706
707                                         return consta.Item2;
708                                 }
709                         }
710
711                         public override object ConstantType
712                         {
713                                 get
714                                 {
715                                         Tuple<bool, object, TypeNode> consta;
716                                         if (!TryGetConstantFromCache (out consta))
717                                                 throw new InvalidOperationException();
718
719                                         return consta.Item3;
720                                 }
721                         }
722
723                         public override bool IsIsinst
724                         {
725                                 get
726                                 {
727                                         Tuple<bool, BoxedExpression, TypeNode> isinst;
728                                         TryGetIsInstFromCache (out isinst);
729                                         return isinst.Item1;
730                                 }
731                         }
732
733                         public override bool IsNull
734                         {
735                                 get { return this.decoder.IsNull (this.expr); }
736                         }
737
738                         public override bool IsUnary
739                         {
740                                 get
741                                 {
742                                         Tuple<bool, UnaryOperator, BoxedExpression> unary;
743                                         TryGetUnaryFromCache (out unary);
744                                         return unary.Item1;
745                                 }
746                         }
747
748                         public override UnaryOperator UnaryOperator
749                         {
750                                 get
751                                 {
752                                         Tuple<bool, UnaryOperator, BoxedExpression> unary;
753                                         if (!TryGetUnaryFromCache (out unary))
754                                                 throw new InvalidOperationException();
755                                         return unary.Item2;
756                                 }
757                         }
758
759                         public override BoxedExpression UnaryArgument
760                         {
761                                 get
762                                 {
763                                         Tuple<bool, UnaryOperator, BoxedExpression> unary;
764                                         if (!TryGetUnaryFromCache (out unary))
765                                                 throw new InvalidOperationException ();
766                                         return unary.Item3;
767                                 }
768                         }
769
770                         public override bool IsSizeof
771                         {
772                                 get
773                                 {
774                                         TypeNode type;
775                                         return this.decoder.IsSizeof (this.expr, out type);
776                                 }
777                         }
778
779                         public override bool IsVariable
780                         {
781                                 get
782                                 {
783                                         Pair<bool, object> var1;
784                                         TryGetIsVariableFromCache (out var1);
785                                         return var1.Key;
786                                 }
787                         }
788
789                         public override object UnderlyingVariable
790                         {
791                                 get
792                                 {
793                                         if (!this.var.IsValid)
794                                                 this.var = this.decoder.UnderlyingVariable (this.expr);
795
796                                         return this.var.Value;
797                                 }
798                         }
799
800                         private bool TryGetBinaryFromCache (out Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> binary)
801                         {
802                                 if (this.binary.IsValid) {
803                                         binary = this.binary.Value;
804                                         return true;
805                                 }
806                                 BinaryOperator op;
807                                 LabeledSymbol left;
808                                 LabeledSymbol right;
809                                 bool res = this.decoder.IsBinaryExpression (this.expr, out op, out left, out right);
810                                 this.binary = binary = new Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> (res, op, For (left, this.decoder), For (right, this.decoder));
811
812                                 return res;
813                         }
814
815                         private bool TryGetUnaryFromCache (out Tuple<bool, UnaryOperator, BoxedExpression> unary)
816                         {
817                                 if (this.unary.IsValid) {
818                                         unary = this.unary.Value;
819                                         return true;
820                                 }
821                                 UnaryOperator op;
822                                 LabeledSymbol arg;
823                                 bool res = this.decoder.IsUnaryExpression (this.expr, out op, out arg);
824                                 this.unary = unary = new Tuple<bool, UnaryOperator, BoxedExpression> (res, op, For (arg, this.decoder));
825
826                                 return res;
827                         }
828
829                         private bool TryGetIsInstFromCache (out Tuple<bool, BoxedExpression, TypeNode> isinst)
830                         {
831                                 if (this.isInst.IsValid) {
832                                         isinst = this.isInst.Value;
833                                         return true;
834                                 }
835
836                                 LabeledSymbol arg;
837                                 TypeNode type;
838                                 bool res = this.decoder.IsIsinst (this.expr, out arg, out type);
839                                 this.isInst = isinst = new Tuple<bool, BoxedExpression, TypeNode> (res, For (arg, this.decoder), type);
840
841                                 return res;
842                         }
843
844                         private bool TryGetConstantFromCache (out Tuple<bool, object, TypeNode> result)
845                         {
846                                 if (this.constant.IsValid) {
847                                         result = this.constant.Value;
848                                         return true;
849                                 }
850                                 object value;
851                                 TypeNode type;
852                                 bool res = this.decoder.IsConstant (this.expr, out value, out type);
853                                 this.constant = result = new Tuple<bool, object, TypeNode> (res, value, type);
854
855                                 return res;
856                         }
857
858                         private bool TryGetTypeFromCache (out Pair<bool, TypeNode> result)
859                         {
860                                 if (this.type.IsValid) {
861                                         result = this.type.Value;
862                                         return true;
863                                 }
864
865                                 TypeNode type;
866                                 bool res = this.decoder.TryGetType (this.expr, out type);
867                                 this.type = result = new Pair<bool, TypeNode> (res, type);
868
869                                 return res;
870                         }
871
872                         private bool TryGetIsVariableFromCache (out Pair<bool, object> result)
873                         {
874                                 if (this.isVar.IsValid) {
875                                         result = this.isVar.Value;
876                                         return true;
877                                 }
878
879                                 object value;
880                                 bool res = this.decoder.IsVariable (this.expr, out value);
881                                 this.isVar = result = new Pair<bool, object> (res, value);
882
883                                 return res;
884                         }
885
886                         public override bool IsBinaryExpression (out BinaryOperator op, out BoxedExpression left, out BoxedExpression right)
887                         {
888                                 Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> bin;
889                                 if (!TryGetBinaryFromCache (out bin) || !bin.Item1) {
890                                         op = BinaryOperator.Add;
891                                         left = null;
892                                         right = null;
893                                         return false;
894                                 }
895
896                                 op = bin.Item2;
897                                 left = bin.Item3;
898                                 right = bin.Item4;
899                                 return true;
900                         }
901
902                         public override bool IsIsinstExpression (out BoxedExpression expr, out TypeNode type)
903                         {
904                                 Tuple<bool, BoxedExpression, TypeNode> isinst;
905                                 if (!TryGetIsInstFromCache (out isinst) || !isinst.Item1) {
906                                         expr = null;
907                                         type = null;
908                                         return false;
909                                 }
910
911                                 expr = isinst.Item2;
912                                 type = isinst.Item3;
913                                 return true;
914                         }
915
916                         public override bool IsUnaryExpression (out UnaryOperator op, out BoxedExpression argument)
917                         {
918                                 Tuple<bool, UnaryOperator, BoxedExpression> unary;
919                                 if (!TryGetUnaryFromCache (out unary) || !unary.Item1) {
920                                         op = UnaryOperator.Conv_i;
921                                         argument = null;
922                                         return false;
923                                 }
924
925                                 op = unary.Item2;
926                                 argument = unary.Item3;
927                                 return true;
928                         }
929
930                         protected internal override BoxedExpression RecursiveSubstitute (BoxedExpression what, BoxedExpression replace)
931                         {
932                                 return Convert (this.expr, this.decoder).Substitute (what, replace);
933                         }
934
935                         public override void AddFreeVariables (HashSet<BoxedExpression> set)
936                         {
937                                 this.decoder.AddFreeVariables (this.expr, new SetWrapper (set, this.decoder));
938                         }
939
940                         public override BoxedExpression Substitute<V> (Func<V, BoxedExpression, BoxedExpression> map)
941                         {
942                                 return Convert (this.expr, this.decoder).Substitute (map);
943                         }
944
945                         public override bool TryGetType (out object type)
946                         {
947                                 Pair<bool, TypeNode> result;
948                                 if (!TryGetTypeFromCache (out result) || !result.Key) {
949                                         type = null;
950                                         return false;
951                                 }
952
953                                 type = result.Value;
954                                 return true;
955                         }
956
957                         public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
958                         {
959                                 Tuple<bool, object, TypeNode> constant;
960                                 if (TryGetConstantFromCache (out constant)) {
961                                         if (constant.Item2 != null)
962                                                 return visitor.LoadConst (pc, constant.Item3, constant, Dummy.Value, data);
963
964                                         return visitor.LoadNull (pc, Dummy.Value, data);
965                                 }
966
967                                 UnaryOperator op;
968                                 LabeledSymbol arg;
969                                 if (this.decoder.IsUnaryExpression (this.expr, out op, out arg))
970                                         return visitor.Unary (pc, op, false, Dummy.Value, Dummy.Value, data);
971
972                                 BinaryOperator bop;
973                                 LabeledSymbol left;
974                                 LabeledSymbol right;
975                                 if (this.decoder.IsBinaryExpression (this.expr, out bop, out left, out right))
976                                         return visitor.Binary (pc, bop, Dummy.Value, Dummy.Value, Dummy.Value, data);
977                                 TypeNode type;
978                                 if (this.decoder.IsIsinst (this.expr, out arg, out type))
979                                         return visitor.Isinst (pc, type, Dummy.Value, Dummy.Value, data);
980                                 if (this.decoder.IsNull (this.expr))
981                                         return visitor.LoadNull (pc, Dummy.Value, data);
982                                 if (this.decoder.IsSizeof (this.expr, out type))
983                                         return visitor.Sizeof (pc, type, Dummy.Value, data);
984
985                                 return visitor.Nop (pc, data);
986                         }
987
988                         #region Nested type: SetWrapper
989                         private struct SetWrapper : ISet<LabeledSymbol>, IEnumerable<LabeledSymbol> {
990                                 private readonly IFullExpressionDecoder<Variable, LabeledSymbol> decoder;
991                                 private readonly HashSet<BoxedExpression> set;
992
993                                 #region Implementation of IEnumerable
994                                 public IEnumerator<LabeledSymbol> GetEnumerator ()
995                                 {
996                                         throw new NotImplementedException ();
997                                 }
998
999                                 IEnumerator IEnumerable.GetEnumerator ()
1000                                 {
1001                                         return GetEnumerator ();
1002                                 }
1003                                 #endregion
1004
1005                                 public SetWrapper (HashSet<BoxedExpression> set, IFullExpressionDecoder<Variable, LabeledSymbol> decoder)
1006                                 {
1007                                         this.set = set;
1008                                         this.decoder = decoder;
1009                                 }
1010
1011                                 #region Implementation of ICollection<ExternalExpression>
1012                                 public void Add (LabeledSymbol item)
1013                                 {
1014                                         this.set.Add (For (item, this.decoder));
1015                                 }
1016
1017                                 bool ISet<LabeledSymbol>.Add (LabeledSymbol item)
1018                                 {
1019                                         Add (item);
1020                                         return true;
1021                                 }
1022
1023                                 public void UnionWith (IEnumerable<LabeledSymbol> other)
1024                                 {
1025                                         throw new NotImplementedException ();
1026                                 }
1027
1028                                 public void IntersectWith (IEnumerable<LabeledSymbol> other)
1029                                 {
1030                                         throw new NotImplementedException ();
1031                                 }
1032
1033                                 public void ExceptWith (IEnumerable<LabeledSymbol> other)
1034                                 {
1035                                         throw new NotImplementedException ();
1036                                 }
1037
1038                                 public void SymmetricExceptWith (IEnumerable<LabeledSymbol> other)
1039                                 {
1040                                         throw new NotImplementedException ();
1041                                 }
1042
1043                                 public bool IsSubsetOf (IEnumerable<LabeledSymbol> other)
1044                                 {
1045                                         throw new NotImplementedException ();
1046                                 }
1047
1048                                 public bool IsSupersetOf (IEnumerable<LabeledSymbol> other)
1049                                 {
1050                                         throw new NotImplementedException ();
1051                                 }
1052
1053                                 public bool IsProperSupersetOf (IEnumerable<LabeledSymbol> other)
1054                                 {
1055                                         throw new NotImplementedException ();
1056                                 }
1057
1058                                 public bool IsProperSubsetOf (IEnumerable<LabeledSymbol> other)
1059                                 {
1060                                         throw new NotImplementedException ();
1061                                 }
1062
1063                                 public bool Overlaps (IEnumerable<LabeledSymbol> other)
1064                                 {
1065                                         throw new NotImplementedException ();
1066                                 }
1067
1068                                 public bool SetEquals (IEnumerable<LabeledSymbol> other)
1069                                 {
1070                                         throw new NotImplementedException ();
1071                                 }
1072
1073
1074                                 public void Clear ()
1075                                 {
1076                                         throw new NotImplementedException ();
1077                                 }
1078
1079                                 public bool Contains (LabeledSymbol item)
1080                                 {
1081                                         throw new NotImplementedException ();
1082                                 }
1083
1084                                 public void CopyTo (LabeledSymbol[] array, int arrayIndex)
1085                                 {
1086                                         throw new NotImplementedException ();
1087                                 }
1088
1089                                 public bool Remove (LabeledSymbol item)
1090                                 {
1091                                         throw new NotImplementedException ();
1092                                 }
1093
1094                                 public int Count
1095                                 {
1096                                         get { throw new NotImplementedException (); }
1097                                 }
1098
1099                                 public bool IsReadOnly
1100                                 {
1101                                         get { throw new NotImplementedException (); }
1102                                 }
1103                                 #endregion
1104                         }
1105                         #endregion
1106                         }
1107                 #endregion
1108
1109                 #region Nested type: IsinstExpression
1110                 public class IsinstExpression : BoxedExpression {
1111                         private readonly BoxedExpression arg;
1112                         private readonly TypeNode type;
1113
1114                         public IsinstExpression (BoxedExpression boxedExpression, TypeNode type)
1115                         {
1116                                 this.arg = boxedExpression;
1117                                 this.type = type;
1118                         }
1119
1120                         public override bool IsIsinst
1121                         {
1122                                 get { return true; }
1123                         }
1124
1125                         public override BoxedExpression UnaryArgument
1126                         {
1127                                 get { return this.arg; }
1128                         }
1129
1130                         public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
1131                         {
1132                                 return visitor.Isinst (pc, this.type, Dummy.Value, Dummy.Value, data);
1133                         }
1134
1135                         public override void AddFreeVariables (HashSet<BoxedExpression> set)
1136                         {
1137                                 this.arg.AddFreeVariables (set);
1138                         }
1139
1140                         public override BoxedExpression Substitute<Variable> (Func<Variable, BoxedExpression, BoxedExpression> map)
1141                         {
1142                                 BoxedExpression arg = this.arg.Substitute (map);
1143                                 if (arg == this.arg)
1144                                         return this;
1145                                 if (arg == null)
1146                                         return null;
1147
1148                                 return new IsinstExpression (arg, this.type);
1149                         }
1150                 }
1151                 #endregion
1152
1153                 #region Nested type: OldExpression
1154                 public class OldExpression : BoxedExpression {
1155                         private const string ContractOldValueTemplate = "Contract.OldValue({0})";
1156
1157                         public readonly BoxedExpression Old;
1158                         public readonly TypeNode Type;
1159
1160                         public OldExpression (BoxedExpression old, TypeNode type)
1161                         {
1162                                 this.Old = old;
1163                                 this.Type = type;
1164                         }
1165
1166                         #region Overrides of BoxedExpression
1167                         public override void AddFreeVariables (HashSet<BoxedExpression> set)
1168                         {
1169                                 this.Old.AddFreeVariables (set);
1170                         }
1171
1172                         public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
1173                         {
1174                                 BoxedExpression old = this.Old.Substitute (map);
1175                                 if (old == this.Old)
1176                                         return this;
1177                                 if (old == null)
1178                                         return null;
1179
1180                                 return new OldExpression (old, this.Type);
1181                         }
1182
1183                         public override bool IsBinaryExpression (out BinaryOperator op, out BoxedExpression left, out BoxedExpression right)
1184                         {
1185                                 return this.Old.IsBinaryExpression (out op, out left, out right);
1186                         }
1187
1188                         public override bool IsUnaryExpression (out UnaryOperator op, out BoxedExpression argument)
1189                         {
1190                                 return this.Old.IsUnaryExpression (out op, out argument);
1191                         }
1192
1193                         public override bool IsIsinstExpression (out BoxedExpression expr, out TypeNode type)
1194                         {
1195                                 return this.Old.IsIsinstExpression (out expr, out type);
1196                         }
1197
1198                         public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
1199                         {
1200                                 return visitor.EndOld (pc, new PC (pc.Node, 0), this.Type, Dummy.Value, Dummy.Value, data);
1201                         }
1202                         #endregion
1203
1204                         public override PathElement[] AccessPath
1205                         {
1206                                 get { return this.Old.AccessPath; }
1207                         }
1208
1209                         public override BoxedExpression BinaryLeftArgument
1210                         {
1211                                 get { return this.Old.BinaryLeftArgument; }
1212                         }
1213
1214                         public override BoxedExpression BinaryRightArgument
1215                         {
1216                                 get { return this.Old.BinaryRightArgument; }
1217                         }
1218
1219                         public override BinaryOperator BinaryOperator
1220                         {
1221                                 get { return this.Old.BinaryOperator; }
1222                         }
1223
1224                         public override object Constant
1225                         {
1226                                 get { return this.Old.Constant; }
1227                         }
1228
1229                         public override object ConstantType
1230                         {
1231                                 get { return this.Old.ConstantType; }
1232                         }
1233
1234                         public override bool IsBinary
1235                         {
1236                                 get { return this.Old.IsBinary; }
1237                         }
1238
1239                         public override bool IsConstant
1240                         {
1241                                 get { return this.Old.IsConstant; }
1242                         }
1243
1244                         public override bool IsSizeof
1245                         {
1246                                 get { return this.Old.IsSizeof; }
1247                         }
1248
1249                         public override bool IsNull
1250                         {
1251                                 get { return this.Old.IsNull; }
1252                         }
1253
1254                         public override bool IsIsinst
1255                         {
1256                                 get { return this.Old.IsIsinst; }
1257                         }
1258
1259                         public override bool IsUnary
1260                         {
1261                                 get { return this.Old.IsUnary; }
1262                         }
1263
1264                         public override bool IsVariable
1265                         {
1266                                 get { return this.Old.IsVariable; }
1267                         }
1268
1269                         public override BoxedExpression UnaryArgument
1270                         {
1271                                 get { return this.Old.UnaryArgument; }
1272                         }
1273
1274                         public override UnaryOperator UnaryOperator
1275                         {
1276                                 get { return this.Old.UnaryOperator; }
1277                         }
1278
1279                         public override object UnderlyingVariable
1280                         {
1281                                 get { return this.Old.UnderlyingVariable; }
1282                         }
1283                 }
1284                 #endregion
1285
1286                 #region Nested type: PC
1287                 public struct PC {
1288                         public readonly int Index;
1289                         public readonly BoxedExpression Node;
1290
1291                         public PC (BoxedExpression expr, int index)
1292                         {
1293                                 this.Node = expr;
1294                                 this.Index = index;
1295                         }
1296                 }
1297                 #endregion
1298
1299                 #region Nested type: ResultExpression
1300                 public class ResultExpression : BoxedExpression {
1301                         private const string ContractResultTemplate = "Contract.Result<{0}>()";
1302
1303                         public readonly TypeNode Type;
1304
1305                         public ResultExpression (TypeNode type)
1306                         {
1307                                 this.Type = type;
1308                         }
1309
1310                         public override bool IsResult
1311                         {
1312                                 get { return true; }
1313                         }
1314
1315                         public override void AddFreeVariables (HashSet<BoxedExpression> set)
1316                         {
1317                         }
1318
1319                         public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
1320                         {
1321                                 return this;
1322                         }
1323
1324                         public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
1325                         {
1326                                 return visitor.LoadResult (pc, this.Type, Dummy.Value, Dummy.Value, data);
1327                         }
1328                 }
1329                 #endregion
1330
1331                 #region Nested type: SizeOfExpression
1332                 public class SizeOfExpression : BoxedExpression {
1333                         public readonly int SizeAsConstant;
1334                         public readonly TypeNode Type;
1335
1336                         public SizeOfExpression (TypeNode type, int sizeAsConstant)
1337                         {
1338                                 this.Type = type;
1339                                 this.SizeAsConstant = sizeAsConstant;
1340                         }
1341
1342                         public SizeOfExpression (TypeNode type)
1343                                 : this (type, -1)
1344                         {
1345                         }
1346
1347                         public override bool IsSizeof
1348                         {
1349                                 get { return true; }
1350                         }
1351
1352                         public override void AddFreeVariables (HashSet<BoxedExpression> set)
1353                         {
1354                         }
1355
1356                         public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
1357                         {
1358                                 return this;
1359                         }
1360
1361                         public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
1362                         {
1363                                 return visitor.Sizeof (pc, this.Type, Dummy.Value, data);
1364                         }
1365                 }
1366                 #endregion
1367
1368                 #region Nested type: UnaryExpression
1369                 public class UnaryExpression : BoxedExpression {
1370                         public readonly BoxedExpression Argument;
1371                         public readonly UnaryOperator Op;
1372
1373                         public UnaryExpression (UnaryOperator op, BoxedExpression argument)
1374                         {
1375                                 this.Op = op;
1376                                 this.Argument = argument;
1377                         }
1378
1379                         public override bool IsUnary
1380                         {
1381                                 get { return true; }
1382                         }
1383
1384                         public override BoxedExpression UnaryArgument
1385                         {
1386                                 get { return this.Argument; }
1387                         }
1388
1389                         public override UnaryOperator UnaryOperator
1390                         {
1391                                 get { return this.Op; }
1392                         }
1393
1394                         public override bool IsUnaryExpression (out UnaryOperator op, out BoxedExpression argument)
1395                         {
1396                                 op = this.Op;
1397                                 argument = this.Argument;
1398                                 return true;
1399                         }
1400
1401                         public override void AddFreeVariables (HashSet<BoxedExpression> set)
1402                         {
1403                                 this.Argument.AddFreeVariables (set);
1404                         }
1405
1406                         public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
1407                         {
1408                                 BoxedExpression argument = this.Argument.Substitute (map);
1409                                 if (argument == this.Argument)
1410                                         return this;
1411                                 if (argument == null)
1412                                         return null;
1413
1414                                 return new UnaryExpression (this.Op, argument);
1415                         }
1416
1417                         protected internal override BoxedExpression RecursiveSubstitute (BoxedExpression what, BoxedExpression replace)
1418                         {
1419                                 BoxedExpression argument = this.Argument.Substitute (what, replace);
1420
1421                                 if (argument == this.Argument)
1422                                         return this;
1423
1424                                 return new UnaryExpression (this.Op, argument);
1425                         }
1426
1427                         public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
1428                         {
1429                                 return visitor.Unary (pc, this.Op, false, Dummy.Value, Dummy.Value, data);
1430                         }
1431
1432                         public override bool Equals (object obj)
1433                         {
1434                                 if (this == obj)
1435                                         return true;
1436
1437                                 var unary = obj as UnaryExpression;
1438                                 return unary != null && this.Op == unary.Op && this.Argument.Equals (unary.Argument);
1439                         }
1440
1441                         public override int GetHashCode ()
1442                         {
1443                                 return this.Op.GetHashCode () * 13 + (this.Argument == null ? 0 : this.Argument.GetHashCode ());
1444                         }
1445
1446                 }
1447                 #endregion
1448
1449                 #region Nested type: ValueAtReturnExpression
1450                 public class ValueAtReturnExpression : BoxedExpression {
1451                         private const string ContractValueAtReturnTemplate = "Contract.ValueAtReturn({0})";
1452
1453                         public readonly TypeNode Type;
1454                         public readonly BoxedExpression Value;
1455
1456                         public ValueAtReturnExpression (BoxedExpression old, TypeNode type)
1457                         {
1458                                 this.Value = old;
1459                                 this.Type = type;
1460                         }
1461
1462                         #region Overrides of BoxedExpression
1463                         public override void AddFreeVariables (HashSet<BoxedExpression> set)
1464                         {
1465                                 this.Value.AddFreeVariables (set);
1466                         }
1467
1468                         public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
1469                         {
1470                                 BoxedExpression value = this.Value.Substitute (map);
1471                                 if (value == this.Value)
1472                                         return this;
1473                                 if (value == null)
1474                                         return null;
1475
1476                                 return new ValueAtReturnExpression (value, this.Type);
1477                         }
1478
1479                         public override bool IsBinaryExpression (out BinaryOperator op, out BoxedExpression left, out BoxedExpression right)
1480                         {
1481                                 return this.Value.IsBinaryExpression (out op, out left, out right);
1482                         }
1483
1484                         public override bool IsUnaryExpression (out UnaryOperator op, out BoxedExpression argument)
1485                         {
1486                                 return this.Value.IsUnaryExpression (out op, out argument);
1487                         }
1488
1489                         public override bool IsIsinstExpression (out BoxedExpression expr, out TypeNode type)
1490                         {
1491                                 return this.Value.IsIsinstExpression (out expr, out type);
1492                         }
1493
1494                         public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
1495                         {
1496                                 throw new NotImplementedException ();
1497                         }
1498                         #endregion
1499
1500                         public override PathElement[] AccessPath
1501                         {
1502                                 get { return this.Value.AccessPath; }
1503                         }
1504
1505                         public override BoxedExpression BinaryLeftArgument
1506                         {
1507                                 get { return this.Value.BinaryLeftArgument; }
1508                         }
1509
1510                         public override BoxedExpression BinaryRightArgument
1511                         {
1512                                 get { return this.Value.BinaryRightArgument; }
1513                         }
1514
1515                         public override BinaryOperator BinaryOperator
1516                         {
1517                                 get { return this.Value.BinaryOperator; }
1518                         }
1519
1520                         public override object Constant
1521                         {
1522                                 get { return this.Value.Constant; }
1523                         }
1524
1525                         public override object ConstantType
1526                         {
1527                                 get { return this.Value.ConstantType; }
1528                         }
1529
1530                         public override bool IsBinary
1531                         {
1532                                 get { return this.Value.IsBinary; }
1533                         }
1534
1535                         public override bool IsConstant
1536                         {
1537                                 get { return this.Value.IsConstant; }
1538                         }
1539
1540                         public override bool IsSizeof
1541                         {
1542                                 get { return this.Value.IsSizeof; }
1543                         }
1544
1545                         public override bool IsNull
1546                         {
1547                                 get { return this.Value.IsNull; }
1548                         }
1549
1550                         public override bool IsIsinst
1551                         {
1552                                 get { return this.Value.IsIsinst; }
1553                         }
1554
1555                         public override bool IsUnary
1556                         {
1557                                 get { return this.Value.IsUnary; }
1558                         }
1559
1560                         public override bool IsVariable
1561                         {
1562                                 get { return this.Value.IsVariable; }
1563                         }
1564
1565                         public override BoxedExpression UnaryArgument
1566                         {
1567                                 get { return this.Value.UnaryArgument; }
1568                         }
1569
1570                         public override UnaryOperator UnaryOperator
1571                         {
1572                                 get { return this.Value.UnaryOperator; }
1573                         }
1574
1575                         public override object UnderlyingVariable
1576                         {
1577                                 get { return this.Value.UnderlyingVariable; }
1578                         }
1579                 }
1580                 #endregion
1581
1582                 #region Nested type: VariableExpression
1583                 public class VariableExpression : BoxedExpression {
1584                         private readonly PathElement[] Path;
1585                         private readonly object UnderlyingVar;
1586                         public readonly object VarType;
1587
1588                         public VariableExpression (object var)
1589                                 : this (var, (LispList<PathElement>) null)
1590                         {
1591                         }
1592
1593                         public VariableExpression (object var, LispList<PathElement> path)
1594                         {
1595                                 this.UnderlyingVar = var;
1596                                 this.Path = path != null ? path.AsEnumerable ().ToArray () : null;
1597                         }
1598
1599                         public VariableExpression (object var, LispList<PathElement> path, object type)
1600                                 : this (var, path)
1601                         {
1602                                 this.VarType = type;
1603                         }
1604
1605                         public VariableExpression (object var, PathElement[] path)
1606                         {
1607                                 this.UnderlyingVar = var;
1608                                 this.Path = path;
1609                         }
1610
1611                         public VariableExpression (object var, PathElement[] path, object type)
1612                                 : this (var, path)
1613                         {
1614                                 this.VarType = type;
1615                         }
1616
1617                         public override bool IsVariable
1618                         {
1619                                 get { return true; }
1620                         }
1621
1622                         public override object UnderlyingVariable
1623                         {
1624                                 get { return this.UnderlyingVar; }
1625                         }
1626
1627                         public override PathElement[] AccessPath
1628                         {
1629                                 get { return this.Path; }
1630                         }
1631
1632                         public override bool IsBooleanTyped
1633                         {
1634                                 get { return this.Path != null && this.Path [this.Path.Length - 1].IsBooleanTyped; }
1635                         }
1636
1637                         public override bool TryGetType (out object type)
1638                         {
1639                                 type = this.VarType;
1640                                 return type != null;
1641                         }
1642
1643                         public override void AddFreeVariables (HashSet<BoxedExpression> set)
1644                         {
1645                                 set.Add (this);
1646                         }
1647
1648                         protected internal override BoxedExpression RecursiveSubstitute (BoxedExpression what, BoxedExpression replace)
1649                         {
1650                                 var varExpr = what as VariableExpression;
1651                                 if (varExpr != null && varExpr.UnderlyingVar.Equals (this.UnderlyingVar))
1652                                         return replace;
1653
1654                                 return this;
1655                         }
1656
1657                         public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
1658                         {
1659                                 return visitor.Nop (pc, data);
1660                         }
1661
1662                         public override bool Equals (object obj)
1663                         {
1664                                 if (this == obj)
1665                                         return true;
1666                                 var boxedExpression = obj as BoxedExpression;
1667                                 if (boxedExpression != null && boxedExpression.IsVariable)
1668                                         return this.UnderlyingVar.Equals (boxedExpression.UnderlyingVariable);
1669
1670                                 return false;
1671                         }
1672
1673                         public override int GetHashCode ()
1674                         {
1675                                 return this.UnderlyingVariable != null ? 0 : this.UnderlyingVariable.GetHashCode ();
1676                         }
1677
1678                         public override BoxedExpression Substitute<Variable> (Func<Variable, BoxedExpression, BoxedExpression> map)
1679                         {
1680                                 if (!(this.UnderlyingVar is Variable))
1681                                         return this;
1682                                 var variable = ((Variable) this.UnderlyingVar);
1683                                 return map (variable, this);
1684                         }
1685                 }
1686                 #endregion
1687         }
1688 }