Implemented overloaded versions of Parse and TryParse functions for BigInteger.
[mono.git] / mcs / class / System.Core / System.Linq.jvm / ExpressionInterpreter.cs
index 5c33a74e9ed978383e24c4a0187b5791bd6b4963..4d550d1ac5ad9715dbb11e37b1a99a8627995b8b 100644 (file)
-using System;\r
-using System.Collections;\r
-using System.Collections.Generic;\r
-using System.Collections.ObjectModel;\r
-using System.Linq;\r
-using System.Text;\r
-using System.Reflection;\r
-using System.Collections.Specialized;\r
-using System.Linq.Expressions;\r
-\r
-namespace System.Linq.jvm\r
-{\r
-    class ExpressionInterpreter : ExpressionVisitor\r
-    {\r
\r
-        LambdaExpression _exp;\r
-\r
-        object[] _args;\r
-\r
-        object _value = null;\r
-\r
-        public object Value\r
-        {\r
-            get { return _value; }\r
-        }\r
-\r
-        public ExpressionInterpreter(object[] args)\r
-        {\r
-            _args = args;\r
-        }\r
-\r
-\r
-        public void Run(LambdaExpression exp)\r
-        {\r
-            _exp = exp;\r
-            Visit(exp.Body);\r
-        }\r
-\r
-        protected override void Visit(Expression expression)\r
-        {\r
-            if (expression == null)\r
-            {\r
-                return;\r
-            }\r
-            if (expression.NodeType == ExpressionType.Power)\r
-            {\r
-                VisitBinary((BinaryExpression)expression);\r
-            }\r
-            else\r
-            {\r
-                base.Visit(expression);\r
-            }\r
-        }\r
-\r
-        private void VisitCoalesce(BinaryExpression binary)\r
-        {\r
-            Visit(binary.Left);\r
-            if (_value == null)\r
-            {\r
-                Visit(binary.Right);\r
-            }\r
-        }\r
-\r
-        private void VisitAndAlso(BinaryExpression binary)\r
-        {\r
-            object right = null;\r
-            object left = null;\r
-\r
-            Visit(binary.Left);\r
-            right = _value;\r
-\r
-            if (right == null || ((bool)right))\r
-            {\r
-                Visit(binary.Right);\r
-                left = _value;\r
-            }\r
-\r
-            _value = Math.And(right, left);\r
-            \r
-        }\r
-\r
-        private void VisitOrElse(BinaryExpression binary)\r
-        {\r
-            object right = null;\r
-            object left = null;\r
-\r
-            Visit(binary.Left);\r
-            right = _value;\r
-\r
-            if (right == null || !((bool)right))\r
-            {\r
-                Visit(binary.Right);\r
-                left = _value;\r
-            }\r
-            _value = Math.Or(right, left);\r
-        }\r
-\r
-        private void VisitCommonBinary(BinaryExpression binary)\r
-        {\r
-            try\r
-            {\r
-                Visit(binary.Left);\r
-                object left = _value;\r
-                Visit(binary.Right);\r
-                object right = _value;\r
-\r
-                if (binary.Method != null)\r
-                {\r
-                    _value = binary.Method.Invoke(null, new object[] { left, right });\r
-                    return;\r
-                }\r
-\r
-                TypeCode tc = Type.GetTypeCode(binary.Type);\r
-\r
-                switch (binary.NodeType)\r
-                {\r
-                    case ExpressionType.ArrayIndex:\r
-                        _value = ((Array)left).GetValue((int)right);\r
-                        return;\r
-                    case ExpressionType.Equal:\r
-                        _value = left.Equals(right);\r
-                        return;\r
-                    case ExpressionType.NotEqual:\r
-                        _value = !left.Equals(right);\r
-                        return;\r
-                    case ExpressionType.LessThan:\r
-                        _value = (Comparer.Default.Compare(left, right) < 0);\r
-                        return;\r
-                    case ExpressionType.LessThanOrEqual:\r
-                        _value = (Comparer.Default.Compare(left, right) <= 0);\r
-                        return;\r
-                    case ExpressionType.GreaterThan:\r
-                        _value = (Comparer.Default.Compare(left, right) > 0);\r
-                        return;\r
-                    case ExpressionType.GreaterThanOrEqual:\r
-                        _value = (Comparer.Default.Compare(left, right) >= 0);\r
-                        return;\r
-                    case ExpressionType.RightShift:\r
-                        _value = Math.RightShift(left, Convert.ToInt32(right), tc);\r
-                        return;\r
-                    case ExpressionType.LeftShift:\r
-                        _value = Math.LeftShift(left, Convert.ToInt32(right), tc);\r
-                        return;\r
-                    default:\r
-                        _value = Math.Evaluate(left, right, binary.Type, binary.NodeType);\r
-                        break;\r
-\r
-                }\r
-            }\r
-            catch (OverflowException)\r
-            {\r
-                throw;\r
-            }\r
-            catch (Exception e)\r
-            {\r
-\r
-                throw new NotImplementedException(\r
-                    string.Format(\r
-                    "Interpriter for BinaryExpression with NodeType {0} is not implimented",\r
-                    binary.NodeType),\r
-                    e);\r
-            }\r
-        }\r
-\r
-        protected override void VisitBinary(BinaryExpression binary)\r
-        {\r
-            switch (binary.NodeType)\r
-            {\r
-                case ExpressionType.AndAlso:\r
-                    VisitAndAlso(binary);\r
-                    return;\r
-                case ExpressionType.OrElse:\r
-                    VisitOrElse(binary);\r
-                    return;\r
-                case ExpressionType.Coalesce:\r
-                    VisitCoalesce(binary);\r
-                    return;\r
-                default:\r
-                    VisitCommonBinary(binary);\r
-                    break;\r
-            }\r
-        }\r
-\r
-        protected override void VisitUnary(UnaryExpression unary)\r
-        {\r
-            Visit(unary.Operand);\r
-            object o = _value;\r
-\r
-            if (unary.Method != null)\r
-            {\r
-                _value = unary.Method.Invoke(null, new object[] { o });\r
-                return;\r
-            }\r
-\r
-            switch (unary.NodeType)\r
-            {\r
-                case ExpressionType.TypeAs:\r
-                    if (!Math.IsType(unary.Type, o))\r
-                    {\r
-                        _value = null;\r
-                    }\r
-                    return;\r
-                case ExpressionType.ArrayLength:\r
-                    _value = ((Array)o).Length;\r
-                    return;\r
-                case ExpressionType.Negate:\r
-                    _value = Math.Negete(o, Type.GetTypeCode(unary.Type));\r
-                    return;\r
-                case ExpressionType.NegateChecked:\r
-                    _value = Math.NegeteChecked(o, Type.GetTypeCode(unary.Type));\r
-                    return;\r
-                case ExpressionType.Not:\r
-                    _value = ! Convert.ToBoolean(o);\r
-                    return;\r
-                case ExpressionType.UnaryPlus:\r
-                    _value = o;\r
-                    return;\r
-                case ExpressionType.Convert:\r
-                    _value = Math.ConvertToTypeUnchecked(o, unary.Type);\r
-                    return;\r
-                case ExpressionType.ConvertChecked:\r
-                    _value = Math.ConvertToTypeChecked(o, unary.Type);\r
-                    return;\r
-            }\r
-            throw new NotImplementedException(\r
-                string.Format(\r
-                "Interpriter for UnaryExpression with NodeType {0} is not implimented",\r
-                unary.NodeType));\r
-\r
-        }\r
-\r
-        protected override void VisitNew(NewExpression nex)\r
-        {\r
-            if (nex.Constructor == null)\r
-            {\r
-                _value = System.Activator.CreateInstance(nex.Type);\r
-            }\r
-            else\r
-            {\r
-                object[] parameters = VisitListExpressions(nex.Arguments);\r
-                _value = nex.Constructor.Invoke(parameters);\r
-            }\r
-        }\r
-\r
-        protected override void VisitTypeIs(TypeBinaryExpression type)\r
-        {\r
-            Visit(type.Expression);\r
-            _value = Math.IsType(type.TypeOperand, _value);\r
-        }\r
-\r
-        private void VisitMemberInfo(MemberInfo mi)\r
-        {\r
-            object o = _value;\r
-            switch (mi.MemberType)\r
-            {\r
-                case MemberTypes.Field:\r
-                    _value = ((FieldInfo)mi).GetValue(o);\r
-                    return;\r
-                case MemberTypes.Property:\r
-                    _value = ((PropertyInfo)mi).GetValue(o, null);\r
-                    return;\r
-            }\r
-\r
-            throw new NotImplementedException(\r
-                string.Format(\r
-                "Interpriter for MemberInfo with MemberType {0} is not implimented",\r
-                mi.MemberType));\r
-        }\r
-\r
-        protected override void VisitMemberAccess(MemberExpression member)\r
-        {\r
-            Visit(member.Expression);\r
-            VisitMemberInfo(member.Member);\r
-        }\r
-\r
-\r
-        protected override void VisitNewArray(NewArrayExpression newArray)\r
-        {\r
-            switch (newArray.NodeType)\r
-            {\r
-                case ExpressionType.NewArrayInit:\r
-                    VisitNewArrayInit(newArray);\r
-                    return;\r
-                case ExpressionType.NewArrayBounds:\r
-                    VisitNewArrayBounds(newArray);\r
-                    return;\r
-            }\r
-            throw new NotImplementedException(\r
-               string.Format(\r
-               "Interpriter for VisitNewArray with NodeType {0} is not implimented",\r
-               newArray.NodeType));\r
-        }\r
-\r
-        private void VisitNewArrayBounds(NewArrayExpression newArray)\r
-        {\r
-            int[] lengths = new int[newArray.Expressions.Count];\r
-            for (int i = 0; i < lengths.Length; i++)\r
-            {\r
-                Visit(newArray.Expressions[i]);\r
-                lengths[i] = (int)_value;\r
-            }\r
-            _value = Array.CreateInstance(newArray.Type.GetElementType(), lengths);\r
-\r
-        }\r
-\r
-        private void VisitNewArrayInit(NewArrayExpression newArray)\r
-        {\r
-            Array arr = Array.CreateInstance(\r
-                        newArray.Type.GetElementType(),\r
-                        newArray.Expressions.Count);\r
-            for (int i = 0; i < arr.Length; i++)\r
-            {\r
-                Visit(newArray.Expressions[i]);\r
-                arr.SetValue(_value, i);\r
-            }\r
-            _value = arr;\r
-        }\r
-\r
-        protected override void VisitConditional(ConditionalExpression conditional)\r
-        {\r
-            Visit(conditional.Test);\r
-            if ((bool)_value)\r
-            {\r
-                Visit(conditional.IfTrue);\r
-            }\r
-            else\r
-            {\r
-                Visit(conditional.IfFalse);\r
-            }\r
-        }\r
-\r
-        protected override void VisitMethodCall(MethodCallExpression call)\r
-        {\r
-            if (call.Object != null)\r
-            {\r
-                Visit(call.Object);\r
-            }\r
-            object callObject = _value;\r
-            object[] arguments = VisitListExpressions(call.Arguments);\r
-            _value = call.Method.Invoke(callObject, arguments);\r
-        }\r
-\r
-        protected override void VisitParameter(ParameterExpression parameter)\r
-        {\r
-            for (int i = 0; i < _exp.Parameters.Count; i++)\r
-            {\r
-                if (_exp.Parameters[i].Name.Equals(parameter.Name))\r
-                {\r
-                    _value = _args[i];\r
-                    return;\r
-                }\r
-            }\r
-            _value = null;\r
-        }\r
-\r
-        protected override void VisitConstant(ConstantExpression constant)\r
-        {\r
-            _value = constant.Value;\r
-        }\r
-\r
-        protected override void VisitInvocation(InvocationExpression invocation)\r
-        {\r
-            Visit(invocation.Expression);\r
-            object o = _value;\r
-            object[] arguments = VisitListExpressions(invocation.Arguments);\r
-            _value = ((Delegate)o).DynamicInvoke(arguments);\r
-        }\r
-\r
-        protected override void VisitMemberListBinding(MemberListBinding binding)\r
-        {\r
-            object o = _value;\r
-            try\r
-            {\r
-                VisitMemberInfo(binding.Member);\r
-                base.VisitMemberListBinding(binding);\r
-            }\r
-            finally\r
-            {\r
-                _value = o;\r
-            }\r
-        }\r
-\r
-        protected override void VisitElementInitializer(ElementInit initializer)\r
-        {\r
-            object o = _value;\r
-            try\r
-            {\r
-                object[] arguments =\r
-                    VisitListExpressions(initializer.Arguments);\r
-                initializer.AddMethod.Invoke(o, arguments);\r
-\r
-            }\r
-            finally\r
-            {\r
-                _value = o;\r
-            }\r
-        }\r
-\r
-        protected override void VisitMemberMemberBinding(MemberMemberBinding binding)\r
-        {\r
-            object o = _value;\r
-            try\r
-            {\r
-                VisitMemberInfo(binding.Member);\r
-                base.VisitMemberMemberBinding(binding);\r
-            }\r
-            finally\r
-            {\r
-                _value = o;\r
-            }\r
-        }\r
-\r
-        protected override void VisitMemberAssignment(MemberAssignment assignment)\r
-        {\r
-            object o = _value;\r
-            try\r
-            {\r
-                Visit(assignment.Expression);\r
-                switch (assignment.Member.MemberType)\r
-                {\r
-                    case MemberTypes.Field:\r
-                        ((FieldInfo)assignment.Member).SetValue(o, _value);\r
-                        return;\r
-                    case MemberTypes.Property:\r
-                        ((PropertyInfo)assignment.Member).SetValue(o, _value, null);\r
-                        return;\r
-                }\r
-                throw new NotImplementedException(\r
-                    string.Format(\r
-                    "Interpriter for MemberExpression with MemberType {0} is not implimented",\r
-                    assignment.Member.MemberType));\r
-            }\r
-            finally\r
-            {\r
-                _value = o;\r
-            }\r
-        }\r
-\r
-        private object[] VisitListExpressions(ReadOnlyCollection<Expression> collection)\r
-        {\r
-            object o = _value;\r
-            try\r
-            {\r
-                object[] results = new object[collection.Count];\r
-                for (int i = 0; i < results.Length; i++)\r
-                {\r
-                    Visit(collection[i]);\r
-                    results[i] = _value;\r
-                }\r
-\r
-                return results;\r
-            }\r
-            finally\r
-            {\r
-                _value = o;\r
-            }\r
-        }\r
-\r
-    }\r
-\r
-}\r
+//
+// ExpressionInterpreter.cs
+//
+// (C) 2008 Mainsoft, Inc. (http://www.mainsoft.com)
+// (C) 2008 db4objects, Inc. (http://www.db4o.com)
+// (C) 2010 Novell, Inc. (http://www.novell.com)
+//
+// 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.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace System.Linq.jvm {
+
+       struct LambdaInfo {
+               public readonly LambdaExpression Lambda;
+               public readonly object [] Arguments;
+
+               public LambdaInfo (LambdaExpression lambda, object [] arguments)
+               {
+                       this.Lambda = lambda;
+                       this.Arguments = arguments;
+               }
+       }
+
+       class HoistedVariableDetector : ExpressionVisitor {
+
+               readonly Dictionary<ParameterExpression, LambdaExpression> parameter_to_lambda =
+                       new Dictionary<ParameterExpression, LambdaExpression> ();
+
+               Dictionary<LambdaExpression, List<ParameterExpression>> hoisted_map;
+
+               LambdaExpression lambda;
+
+               public Dictionary<LambdaExpression, List<ParameterExpression>> Process (LambdaExpression lambda)
+               {
+                       Visit (lambda);
+                       return hoisted_map;
+               }
+
+               protected override void VisitLambda (LambdaExpression lambda)
+               {
+                       this.lambda = lambda;
+                       foreach (var parameter in lambda.Parameters)
+                               parameter_to_lambda [parameter] = lambda;
+                       base.VisitLambda (lambda);
+               }
+
+               protected override void VisitParameter (ParameterExpression parameter)
+               {
+                       if (lambda.Parameters.Contains (parameter))
+                               return;
+
+                       Hoist (parameter);
+               }
+
+               void Hoist (ParameterExpression parameter)
+               {
+                       LambdaExpression lambda;
+                       if (!parameter_to_lambda.TryGetValue (parameter, out lambda))
+                               return;
+
+                       if (hoisted_map == null)
+                               hoisted_map = new Dictionary<LambdaExpression, List<ParameterExpression>> ();
+
+                       List<ParameterExpression> hoisted;
+                       if (!hoisted_map.TryGetValue (lambda, out hoisted)) {
+                               hoisted = new List<ParameterExpression> ();
+                               hoisted_map [lambda] = hoisted;
+                       }
+
+                       hoisted.Add (parameter);
+               }
+       }
+
+
+       class ExpressionInterpreter : ExpressionVisitor {
+
+               readonly Stack<LambdaInfo> lambdas = new Stack<LambdaInfo> ();
+               readonly Stack<object> stack = new Stack<object> ();
+
+               readonly Dictionary<LambdaExpression, List<ParameterExpression>> hoisted_map;
+               readonly Dictionary<ParameterExpression, object> hoisted_values;
+
+               void Push (object value)
+               {
+                       stack.Push (value);
+               }
+
+               object Pop ()
+               {
+                       return stack.Pop ();
+               }
+
+               public ExpressionInterpreter (LambdaExpression lambda)
+               {
+                       hoisted_map = new HoistedVariableDetector ().Process (lambda);
+
+                       if (hoisted_map != null)
+                               hoisted_values = new Dictionary<ParameterExpression, object> ();
+               }
+
+               private void VisitCoalesce (BinaryExpression binary)
+               {
+                       Visit (binary.Left);
+
+                       var left = Pop ();
+
+                       if (left == null) {
+                               Visit (binary.Right);
+                               return;
+                       }
+
+                       if (binary.Conversion == null) {
+                               Push (left);
+                               return;
+                       }
+
+                       Push (Invoke (binary.Conversion.Compile (this), new [] { left }));
+               }
+
+               void VisitAndAlso (BinaryExpression binary)
+               {
+                       object left = null;
+                       object right = null;
+
+                       Visit (binary.Left);
+
+                       left = Pop ();
+
+                       if (left == null || ((bool) left)) {
+                               Visit (binary.Right);
+                               right = Pop ();
+                       }
+
+                       Push (Math.And (left, right));
+               }
+
+               void VisitUserDefinedAndAlso (BinaryExpression binary)
+               {
+                       object left = null;
+                       object right = null;
+
+                       Visit (binary.Left);
+
+                       left = Pop ();
+
+                       if (InvokeFalseOperator (binary, left)) {
+                               Push (left);
+                               return;
+                       }
+
+                       Visit (binary.Right);
+                       right = Pop ();
+
+                       if (binary.IsLiftedToNull && right == null) {
+                               Push (null);
+                               return;
+                       }
+
+                       Push (InvokeMethod (binary.Method, null, new [] { left, right }));
+               }
+
+               static bool InvokeTrueOperator (BinaryExpression binary, object target)
+               {
+                       return (bool) InvokeMethod (GetTrueOperator (binary), null, new [] { target });
+               }
+
+               static bool InvokeFalseOperator (BinaryExpression binary, object target)
+               {
+                       return (bool) InvokeMethod (GetFalseOperator (binary), null, new [] { target });
+               }
+
+               static MethodInfo GetFalseOperator (BinaryExpression binary)
+               {
+                       return Expression.GetFalseOperator (binary.Left.Type.GetNotNullableType ());
+               }
+
+               static MethodInfo GetTrueOperator (BinaryExpression binary)
+               {
+                       return Expression.GetTrueOperator (binary.Left.Type.GetNotNullableType ());
+               }
+
+               void VisitOrElse (BinaryExpression binary)
+               {
+                       object left = null;
+                       object right = null;
+
+                       Visit (binary.Left);
+                       left = Pop ();
+
+                       if (left == null || !((bool) left)) {
+                               Visit (binary.Right);
+                               right = Pop ();
+                       }
+
+                       Push (Math.Or (left, right));
+               }
+
+               void VisitUserDefinedOrElse (BinaryExpression binary)
+               {
+                       object left = null;
+                       object right = null;
+
+                       Visit (binary.Left);
+                       left = Pop ();
+
+                       if (InvokeTrueOperator (binary, left)) {
+                               Push (left);
+                               return;
+                       }
+
+                       Visit (binary.Right);
+                       right = Pop ();
+
+                       if (binary.IsLiftedToNull && right == null) {
+                               Push (null);
+                               return;
+                       }
+
+                       Push (InvokeMethod (binary.Method, null, new [] { left, right }));
+               }
+
+               void VisitLogicalBinary (BinaryExpression binary)
+               {
+                       Visit (binary.Left);
+                       Visit (binary.Right);
+
+                       var right = Pop ();
+                       var left = Pop ();
+
+                       Push (Math.Evaluate (left, right, binary.Type, binary.NodeType));
+               }
+
+               void VisitArithmeticBinary (BinaryExpression binary)
+               {
+                       Visit (binary.Left);
+                       Visit (binary.Right);
+
+                       if (IsNullBinaryLifting (binary))
+                               return;
+
+                       var right = Pop ();
+                       var left = Pop ();
+
+                       switch (binary.NodeType) {
+                       case ExpressionType.RightShift:
+                               Push (Math.RightShift (left, Convert.ToInt32 (right), Type.GetTypeCode (binary.Type.GetNotNullableType ())));
+                               return;
+                       case ExpressionType.LeftShift:
+                               Push (Math.LeftShift (left, Convert.ToInt32 (right), Type.GetTypeCode (binary.Type.GetNotNullableType ())));
+                               return;
+                       default:
+                               Push (Math.Evaluate (left, right, binary.Type, binary.NodeType));
+                               break;
+                       }
+               }
+
+               bool IsNullRelationalBinaryLifting (BinaryExpression binary)
+               {
+                       var right = Pop ();
+                       var left = Pop ();
+
+                       if (binary.IsLifted && (left == null || right == null)) {
+                               if (binary.IsLiftedToNull) {
+                                       Push (null);
+                                       return true;
+                               }
+
+                               switch (binary.NodeType) {
+                               case ExpressionType.Equal:
+                                       Push (BinaryEqual (binary, left, right));
+                                       break;
+                               case ExpressionType.NotEqual:
+                                       Push (BinaryNotEqual (binary, left, right));
+                                       break;
+                               default:
+                                       Push (false);
+                                       break;
+                               }
+
+                               return true;
+                       }
+
+                       Push (left);
+                       Push (right);
+
+                       return false;
+               }
+
+               void VisitRelationalBinary (BinaryExpression binary)
+               {
+                       Visit (binary.Left);
+                       Visit (binary.Right);
+
+                       if (IsNullRelationalBinaryLifting (binary))
+                               return;
+
+                       var right = Pop ();
+                       var left = Pop ();
+
+                       switch (binary.NodeType) {
+                       case ExpressionType.Equal:
+                               Push (BinaryEqual (binary, left, right));
+                               return;
+                       case ExpressionType.NotEqual:
+                               Push (BinaryNotEqual (binary, left, right));
+                               return;
+                       case ExpressionType.LessThan:
+                               Push (Comparer<object>.Default.Compare (left, right) < 0);
+                               return;
+                       case ExpressionType.LessThanOrEqual:
+                               Push (Comparer<object>.Default.Compare (left, right) <= 0);
+                               return;
+                       case ExpressionType.GreaterThan:
+                               Push (Comparer<object>.Default.Compare (left, right) > 0);
+                               return;
+                       case ExpressionType.GreaterThanOrEqual:
+                               Push (Comparer<object>.Default.Compare (left, right) >= 0);
+                               return;
+                       }
+               }
+
+               void VisitLogicalShortCircuitBinary (BinaryExpression binary)
+               {
+                       switch (binary.NodeType) {
+                       case ExpressionType.AndAlso:
+                               VisitAndAlso (binary);
+                               return;
+                       case ExpressionType.OrElse:
+                               VisitOrElse (binary);
+                               return;
+                       }
+               }
+
+               void VisitArrayIndex (BinaryExpression binary)
+               {
+                       Visit (binary.Left);
+                       var left = Pop ();
+                       Visit (binary.Right);
+                       var right = Pop ();
+
+                       Push (((Array) left).GetValue ((int) right));
+               }
+
+               bool IsNullBinaryLifting (BinaryExpression binary)
+               {
+                       var right = Pop ();
+                       var left = Pop ();
+
+                       if (binary.IsLifted && (right == null || left == null)) {
+                               if (binary.IsLiftedToNull)
+                                       Push (null);
+                               else
+                                       Push (GetDefaultValue (binary.Type));
+
+                               return true;
+                       }
+
+                       Push (left);
+                       Push (right);
+
+                       return false;
+               }
+
+               static object GetDefaultValue (Type type)
+               {
+                       var array = (Array) Array.CreateInstance (type, 1);
+                       return array.GetValue (0);
+               }
+
+               void VisitUserDefinedBinary (BinaryExpression binary)
+               {
+                       switch (binary.NodeType) {
+                       case ExpressionType.AndAlso:
+                       case ExpressionType.OrElse:
+                               VisitUserDefinedLogicalShortCircuitBinary (binary);
+                               return;
+                       case ExpressionType.Equal:
+                       case ExpressionType.NotEqual:
+                               VisitUserDefinedRelationalBinary (binary);
+                               return;
+                       default:
+                               VisitUserDefinedCommonBinary (binary);
+                               return;
+                       }
+               }
+
+               void VisitUserDefinedLogicalShortCircuitBinary (BinaryExpression binary)
+               {
+                       switch (binary.NodeType) {
+                       case ExpressionType.AndAlso:
+                               VisitUserDefinedAndAlso (binary);
+                               return;
+                       case ExpressionType.OrElse:
+                               VisitUserDefinedOrElse (binary);
+                               return;
+                       }
+               }
+
+               void VisitUserDefinedRelationalBinary (BinaryExpression binary)
+               {
+                       Visit (binary.Left);
+                       Visit (binary.Right);
+
+                       if (IsNullRelationalBinaryLifting (binary))
+                               return;
+
+                       var right = Pop ();
+                       var left = Pop ();
+
+                       Push (InvokeBinary (binary, left, right));
+               }
+
+               void VisitUserDefinedCommonBinary (BinaryExpression binary)
+               {
+                       Visit (binary.Left);
+                       Visit (binary.Right);
+
+                       if (IsNullBinaryLifting (binary))
+                               return;
+
+                       var right = Pop ();
+                       var left = Pop ();
+
+                       Push (InvokeBinary (binary, left, right));
+               }
+
+               object InvokeBinary (BinaryExpression binary, object left, object right)
+               {
+                       return InvokeMethod (binary.Method, null, new [] { left, right });
+               }
+
+               bool BinaryEqual (BinaryExpression binary, object left, object right)
+               {
+                       if (typeof (ValueType).IsAssignableFrom (binary.Right.Type))
+                               return ValueType.Equals (left, right);
+                       else
+                               return left == right;
+               }
+
+               bool BinaryNotEqual (BinaryExpression binary, object left, object right)
+               {
+                       if (typeof (ValueType).IsAssignableFrom (binary.Right.Type))
+                               return !ValueType.Equals (left, right);
+                       else
+                               return left != right;
+               }
+
+               protected override void VisitBinary (BinaryExpression binary)
+               {
+                       if (binary.Method != null) {
+                               VisitUserDefinedBinary (binary);
+                               return;
+                       }
+
+                       switch (binary.NodeType) {
+                       case ExpressionType.ArrayIndex:
+                               VisitArrayIndex (binary);
+                               return;
+                       case ExpressionType.Coalesce:
+                               VisitCoalesce (binary);
+                               return;
+                       case ExpressionType.AndAlso:
+                       case ExpressionType.OrElse:
+                               VisitLogicalShortCircuitBinary (binary);
+                               return;
+                       case ExpressionType.Equal:
+                       case ExpressionType.NotEqual:
+                       case ExpressionType.GreaterThan:
+                       case ExpressionType.GreaterThanOrEqual:
+                       case ExpressionType.LessThan:
+                       case ExpressionType.LessThanOrEqual:
+                               VisitRelationalBinary (binary);
+                               return;
+                       case ExpressionType.And:
+                       case ExpressionType.Or:
+                               VisitLogicalBinary (binary);
+                               return;
+                       case ExpressionType.Power:
+                       case ExpressionType.Add:
+                       case ExpressionType.AddChecked:
+                       case ExpressionType.Divide:
+                       case ExpressionType.ExclusiveOr:
+                       case ExpressionType.LeftShift:
+                       case ExpressionType.Modulo:
+                       case ExpressionType.Multiply:
+                       case ExpressionType.MultiplyChecked:
+                       case ExpressionType.RightShift:
+                       case ExpressionType.Subtract:
+                       case ExpressionType.SubtractChecked:
+                               VisitArithmeticBinary (binary);
+                               return;
+                       }
+               }
+
+               void VisitTypeAs (UnaryExpression unary)
+               {
+                       Visit (unary.Operand);
+
+                       var value = Pop ();
+                       if (value == null || !Math.IsType (unary.Type, value))
+                               Push (null);
+                       else
+                               Push (value);
+               }
+
+               void VisitArrayLength (UnaryExpression unary)
+               {
+                       Visit (unary.Operand);
+
+                       var array = (Array) Pop ();
+                       Push (array.Length);
+               }
+
+               void VisitConvert (UnaryExpression unary)
+               {
+                       if (unary.NodeType == ExpressionType.ConvertChecked)
+                               VisitConvertChecked (unary);
+                       else
+                               VisitConvertUnchecked (unary);
+               }
+
+               void VisitConvertChecked (UnaryExpression unary)
+               {
+                       VisitConvert (unary, Math.ConvertToTypeChecked);
+               }
+
+               void VisitConvertUnchecked (UnaryExpression unary)
+               {
+                       VisitConvert (unary, Math.ConvertToTypeUnchecked);
+               }
+
+               void VisitConvert (UnaryExpression unary, Func<object, Type, Type, object> converter)
+               {
+                       Visit (unary.Operand);
+                       Push (converter (Pop (), unary.Operand.Type, unary.Type));
+               }
+
+               bool IsNullUnaryLifting (UnaryExpression unary)
+               {
+                       var value = Pop ();
+
+                       if (unary.IsLifted && value == null) {
+                               if (unary.IsLiftedToNull) {
+                                       Push (null);
+                                       return true;
+                               } else {
+                                       throw new InvalidOperationException ();
+                               }
+                       }
+
+                       Push (value);
+                       return false;
+               }
+
+               void VisitQuote (UnaryExpression unary)
+               {
+                       Push (unary.Operand);
+               }
+
+               void VisitUserDefinedUnary (UnaryExpression unary)
+               {
+                       Visit (unary.Operand);
+
+                       if (IsNullUnaryLifting (unary))
+                               return;
+
+                       var value = Pop ();
+
+                       Push (InvokeUnary (unary, value));
+               }
+
+               object InvokeUnary (UnaryExpression unary, object value)
+               {
+                       return InvokeMethod (unary.Method, null, new [] { value });
+               }
+
+               void VisitArithmeticUnary (UnaryExpression unary)
+               {
+                       Visit (unary.Operand);
+
+                       if (IsNullUnaryLifting (unary))
+                               return;
+
+                       var value = Pop ();
+
+                       switch (unary.NodeType) {
+                       case ExpressionType.Not:
+                               if (unary.Type.GetNotNullableType () == typeof (bool))
+                                       Push (!Convert.ToBoolean (value));
+                               else
+                                       Push (~Convert.ToInt32 (value));
+                               return;
+                       case ExpressionType.Negate:
+                               Push (Math.Negate (value, Type.GetTypeCode (unary.Type.GetNotNullableType ())));
+                               return;
+                       case ExpressionType.NegateChecked:
+                               Push (Math.NegateChecked (value, Type.GetTypeCode (unary.Type.GetNotNullableType ())));
+                               return;
+                       case ExpressionType.UnaryPlus:
+                               Push (value);
+                               return;
+                       }
+               }
+
+               protected override void VisitUnary (UnaryExpression unary)
+               {
+                       if (unary.Method != null) {
+                               VisitUserDefinedUnary (unary);
+                               return;
+                       }
+
+                       switch (unary.NodeType) {
+                       case ExpressionType.Quote:
+                               VisitQuote (unary);
+                               return;
+                       case ExpressionType.TypeAs:
+                               VisitTypeAs (unary);
+                               return;
+                       case ExpressionType.ArrayLength:
+                               VisitArrayLength (unary);
+                               return;
+                       case ExpressionType.Convert:
+                       case ExpressionType.ConvertChecked:
+                               VisitConvert (unary);
+                               return;
+                       case ExpressionType.Negate:
+                       case ExpressionType.NegateChecked:
+                       case ExpressionType.Not:
+                       case ExpressionType.UnaryPlus:
+                               VisitArithmeticUnary (unary);
+                               return;
+                       default:
+                               throw new NotImplementedException (unary.NodeType.ToString ());
+                       }
+               }
+
+               protected override void VisitNew (NewExpression nex)
+               {
+                       if (nex.Constructor == null)
+                               Push (Activator.CreateInstance (nex.Type));
+                       else
+                               Push (InvokeConstructor (nex.Constructor, VisitListExpressions (nex.Arguments)));
+               }
+
+               static object InvokeConstructor (ConstructorInfo constructor, object [] arguments)
+               {
+                       try {
+                               return constructor.Invoke (arguments);
+                       } catch (TargetInvocationException e) {
+                               throw e.InnerException;
+                       }
+               }
+
+               protected override void VisitTypeIs (TypeBinaryExpression type)
+               {
+                       Visit (type.Expression);
+                       Push (Math.IsType (type.TypeOperand, Pop ()));
+               }
+
+               void VisitMemberInfo (MemberInfo mi)
+               {
+                       mi.OnFieldOrProperty (
+                               field => {
+                                       object target = null;
+                                       if (!field.IsStatic)
+                                               target = Pop ();
+
+                                       Push (field.GetValue (target));
+                               },
+                               property => {
+                                       object target = null;
+                                       var getter = property.GetGetMethod (true);
+                                       if (!getter.IsStatic)
+                                               target = Pop ();
+
+                                       Push (property.GetValue (target, null));
+                               });
+               }
+
+               protected override void VisitMemberAccess (MemberExpression member)
+               {
+                       Visit (member.Expression);
+                       VisitMemberInfo (member.Member);
+               }
+
+               protected override void VisitNewArray (NewArrayExpression newArray)
+               {
+                       switch (newArray.NodeType) {
+                       case ExpressionType.NewArrayInit:
+                               VisitNewArrayInit (newArray);
+                               return;
+                       case ExpressionType.NewArrayBounds:
+                               VisitNewArrayBounds (newArray);
+                               return;
+                       }
+
+                       throw new NotSupportedException ();
+               }
+
+               void VisitNewArrayBounds (NewArrayExpression newArray)
+               {
+                       var lengths = new int [newArray.Expressions.Count];
+                       for (int i = 0; i < lengths.Length; i++) {
+                               Visit (newArray.Expressions [i]);
+                               lengths [i] = (int) Pop ();
+                       }
+
+                       Push (Array.CreateInstance (newArray.Type.GetElementType (), lengths));
+               }
+
+               void VisitNewArrayInit (NewArrayExpression newArray)
+               {
+                       var array = Array.CreateInstance (
+                               newArray.Type.GetElementType (),
+                               newArray.Expressions.Count);
+
+                       for (int i = 0; i < array.Length; i++) {
+                               Visit (newArray.Expressions [i]);
+                               array.SetValue (Pop (), i);
+                       }
+
+                       Push (array);
+               }
+
+               protected override void VisitConditional (ConditionalExpression conditional)
+               {
+                       Visit (conditional.Test);
+
+                       if ((bool) Pop ())
+                               Visit (conditional.IfTrue);
+                       else
+                               Visit (conditional.IfFalse);
+               }
+
+               protected override void VisitMethodCall (MethodCallExpression call)
+               {
+                       object instance = null;
+                       if (call.Object != null) {
+                               Visit (call.Object);
+                               instance = Pop ();
+                       }
+
+                       Push (InvokeMethod (call.Method, instance, VisitListExpressions (call.Arguments)));
+               }
+
+               protected override void VisitParameter (ParameterExpression parameter)
+               {
+                       var info = lambdas.Peek ();
+
+                       var lambda = info.Lambda;
+                       var arguments = info.Arguments;
+
+                       var index = GetParameterIndex (lambda, parameter);
+                       if (index >= 0) {
+                               Push (arguments [index]);
+                               return;
+                       }
+
+                       object value;
+                       if (hoisted_values.TryGetValue (parameter, out value)) {
+                               Push (value);
+                               return;
+                       }
+
+                       throw new ArgumentException ();
+               }
+
+               protected override void VisitConstant (ConstantExpression constant)
+               {
+                       Push (constant.Value);
+               }
+
+               protected override void VisitInvocation (InvocationExpression invocation)
+               {
+                       Visit (invocation.Expression);
+                       Push (Invoke ((Delegate) Pop (), VisitListExpressions (invocation.Arguments)));
+               }
+
+               static object Invoke (Delegate dlg, object [] arguments)
+               {
+                       return InvokeMethod (dlg.Method, dlg.Target, arguments);
+               }
+
+               static object InvokeMethod (MethodBase method, object obj, object [] arguments)
+               {
+                       try {
+                               return method.Invoke (obj, arguments);
+                       } catch (TargetInvocationException e) {
+                               throw e.InnerException;
+                       }
+               }
+
+               protected override void VisitMemberListBinding (MemberListBinding binding)
+               {
+                       var value = Pop ();
+                       Push (value);
+                       VisitMemberInfo (binding.Member);
+                       VisitElementInitializerList (binding.Initializers);
+                       Pop (); // pop the member
+                       Push (value); // push the original target
+               }
+
+               protected override void VisitElementInitializer (ElementInit initializer)
+               {
+                       object target = null;
+                       if (!initializer.AddMethod.IsStatic)
+                               target = Pop ();
+
+                       var arguments = VisitListExpressions (initializer.Arguments);
+                       InvokeMethod (initializer.AddMethod, target, arguments);
+
+                       if (!initializer.AddMethod.IsStatic)
+                               Push (target);
+               }
+
+               protected override void VisitMemberMemberBinding (MemberMemberBinding binding)
+               {
+                       var value = Pop ();
+                       Push (value);
+                       VisitMemberInfo (binding.Member);
+                       VisitBindingList (binding.Bindings);
+                       Pop ();
+                       Push (value);
+               }
+
+               protected override void VisitMemberAssignment (MemberAssignment assignment)
+               {
+                       Visit (assignment.Expression);
+
+                       var value = Pop ();
+
+                       assignment.Member.OnFieldOrProperty (
+                               field => {
+                                       object target = null;
+                                       if (!field.IsStatic)
+                                               target = Pop ();
+
+                                       field.SetValue (target, value);
+
+                                       if (!field.IsStatic)
+                                               Push (target);
+                               },
+                               property => {
+                                       object target = null;
+                                       var getter = property.GetGetMethod (true);
+                                       if (!getter.IsStatic)
+                                               target = Pop ();
+
+                                       property.SetValue (target, value, null);
+
+                                       if (!getter.IsStatic)
+                                               Push (target);
+                               });
+               }
+
+               protected override void VisitLambda (LambdaExpression lambda)
+               {
+                       Push (lambda.Compile (this));
+               }
+
+               private object [] VisitListExpressions (ReadOnlyCollection<Expression> collection)
+               {
+                       object [] results = new object [collection.Count];
+                       for (int i = 0; i < results.Length; i++) {
+                               Visit (collection [i]);
+                               results [i] = Pop ();
+                       }
+
+                       return results;
+               }
+
+               void StoreHoistedVariables (LambdaExpression lambda, object [] arguments)
+               {
+                       if (hoisted_map == null)
+                               return;
+
+                       List<ParameterExpression> variables;
+                       if (!hoisted_map.TryGetValue (lambda, out variables))
+                               return;
+
+                       foreach (var variable in variables)
+                               StoreHoistedVariable (variable, lambda, arguments);
+               }
+
+               void StoreHoistedVariable (ParameterExpression variable, LambdaExpression lambda, object [] arguments)
+               {
+                       var index = GetParameterIndex (lambda, variable);
+                       if (index < 0)
+                               return;
+
+                       hoisted_values [variable] = arguments [index];
+               }
+
+               static int GetParameterIndex (LambdaExpression lambda, ParameterExpression parameter)
+               {
+                       return lambda.Parameters.IndexOf (parameter);
+               }
+
+               public object Interpret (LambdaExpression lambda, object [] arguments)
+               {
+                       lambdas.Push (new LambdaInfo (lambda, arguments));
+
+                       StoreHoistedVariables (lambda, arguments);
+
+                       Visit (lambda.Body);
+
+                       lambdas.Pop ();
+
+                       if (lambda.GetReturnType () != typeof (void))
+                               return Pop ();
+
+                       return null;
+               }
+       }
+}