| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831 |
- //
- // ExpressionInterpreter.cs
- //
- // (C) 2008 Mainsoft, Inc. (http://www.mainsoft.com)
- // (C) 2008 db4objects, Inc. (http://www.db4o.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;
- using System.Collections;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Linq.Expressions;
- using System.Reflection;
- namespace System.Linq.jvm {
- class ExpressionInterpreter : ExpressionVisitor {
- LambdaExpression lambda;
- object [] arguments;
- Stack<object> stack = new Stack<object> ();
- void Push (object value)
- {
- stack.Push (value);
- }
- object Pop ()
- {
- return stack.Pop ();
- }
- public ExpressionInterpreter (LambdaExpression lambda, object [] arguments)
- {
- this.lambda = lambda;
- this.arguments = arguments;
- }
- 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 (), 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.Default.Compare (left, right) < 0);
- return;
- case ExpressionType.LessThanOrEqual:
- Push (Comparer.Default.Compare (left, right) <= 0);
- return;
- case ExpressionType.GreaterThan:
- Push (Comparer.Default.Compare (left, right) > 0);
- return;
- case ExpressionType.GreaterThanOrEqual:
- Push (Comparer.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)
- {
- for (int i = 0; i < lambda.Parameters.Count; i++) {
- if (lambda.Parameters [i] != parameter)
- continue;
- Push (arguments [i]);
- 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 ());
- }
- 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;
- }
- public static object Interpret (LambdaExpression lambda, object [] arguments)
- {
- var interpreter = new ExpressionInterpreter (lambda, arguments);
- interpreter.Visit (lambda.Body);
- if (lambda.GetReturnType () != typeof (void))
- return interpreter.Pop ();
- return null;
- }
- }
- }
|