Exemple #1
0
 public override Expression Reduce()
 {
     return(Expression.Call(null, MethodHelpers.IntegerRangeMethodInfo,
                            VelocityExpressions.ConvertIfNeeded(Left, typeof(object)),
                            VelocityExpressions.ConvertIfNeeded(Right, typeof(object))
                            ));
 }
Exemple #2
0
        public Expression ConvertMethodParameters(OverloadResolutionData <MethodInfo> resolvedMethod, Expression target, DynamicMetaObject[] args)//, Type[] argTypeArray)
        {
            if (resolvedMethod == null)
            {
                throw new ArgumentNullException(nameof(resolvedMethod));
            }

            if (args == null)
            {
                throw new ArgumentNullException(nameof(args));
            }

            var argExpressions = _overloadResolver.CreateParameterExpressions(resolvedMethod, args);
            var method         = resolvedMethod.FunctionMember;

            Expression result = Expression.Call(
                VelocityExpressions.ConvertIfNeeded(target, method.DeclaringType),
                method,
                argExpressions
                );

            if (method.ReturnType == typeof(void))
            {
                result = Expression.Block(
                    result,
                    Constants.VoidReturnValue
                    );
            }

            return(result);
        }
        public override DynamicMetaObject FallbackGetIndex(DynamicMetaObject target, DynamicMetaObject[] indexes, DynamicMetaObject errorSuggestion)
        {
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }
            if (indexes == null)
            {
                throw new ArgumentNullException(nameof(indexes));
            }

            if (!target.HasValue || indexes.Any(x => !x.HasValue))
            {
                return(Defer(target, indexes));
            }

            if (target.Value == null)
            {
                return(BinderHelper.NullTargetResult(target, errorSuggestion));
            }

            var index        = _indexerResolver.ReadableIndexer(target, indexes);
            var restrictions = BinderHelper.CreateCommonRestrictions(target, indexes);

            if (index == null)
            {
                return(BinderHelper.UnresolveableResult(restrictions, errorSuggestion));
            }

            return(new DynamicMetaObject(VelocityExpressions.ConvertIfNeeded(index, ReturnType), restrictions));
        }
Exemple #4
0
        private DynamicMetaObject Equality(VelocityOperator operatorType, DynamicMetaObject left, DynamicMetaObject right, DynamicMetaObject errorSuggestion)
        {
            var        op = _operatorResolver.Resolve(operatorType, left.RuntimeType, right.RuntimeType);
            Expression result;

            if (op != null)
            {
                var leftExpr  = VelocityExpressions.ConvertIfNeeded(left.Expression, op.Parameters[0]);
                var rightExpr = VelocityExpressions.ConvertIfNeeded(right.Expression, op.Parameters[1]);

                result = operatorType == VelocityOperator.Equal
                                        ? Expression.Equal(leftExpr, rightExpr, false, op.FunctionMember)
                                        : Expression.NotEqual(leftExpr, rightExpr, false, op.FunctionMember);
            }
            else if (left.RuntimeType == typeof(string) && (right.RuntimeType?.IsEnum ?? false))
            {
                var method = MethodHelpers.GenericStringEnumComparer.MakeGenericMethod(right.RuntimeType);
                result = Expression.Equal(right.Expression, left.Expression, false, method);
                if (operatorType == VelocityOperator.NotEqual)
                {
                    result = Expression.Not(result);
                }
            }
            else if (right.RuntimeType == typeof(string) && (left.RuntimeType?.IsEnum ?? false))
            {
                var method = MethodHelpers.GenericStringEnumComparer.MakeGenericMethod(left.RuntimeType);
                result = Expression.Equal(left.Expression, right.Expression, false, method);
                if (operatorType == VelocityOperator.NotEqual)
                {
                    result = Expression.Not(result);
                }
            }
            else if (errorSuggestion != null)
            {
                return(null);
            }
            else if (left.LimitType.IsAssignableFrom(right.LimitType) || right.LimitType.IsAssignableFrom(left.LimitType))
            {
                var leftExpr  = VelocityExpressions.ConvertIfNeeded(left.Expression, typeof(object));
                var rightExpr = VelocityExpressions.ConvertIfNeeded(right.Expression, typeof(object));

                result = Expression.Equal(leftExpr, rightExpr, false, MethodHelpers.ObjectEquals);
                if (operatorType == VelocityOperator.NotEqual)
                {
                    result = Expression.Not(result);
                }
            }
            else
            {
                result = operatorType == VelocityOperator.Equal
                                        ? Constants.False
                                        : Constants.True;
            }

            var restrictions = BinderHelper.CreateCommonRestrictions(left, right);

            result = VelocityExpressions.ConvertIfNeeded(result, ReturnType);

            return(new DynamicMetaObject(result, restrictions));
        }
Exemple #5
0
        public override Expression Reduce()
        {
            var body = ImmutableList.CreateBuilder <Expression>();

            //Initalise the index to 0
            Expression indexInitalise = Expression.Assign(_internalIndex, Constants.Zero);

            if (LoopIndex != null)
            {
                indexInitalise = Expression.Assign(LoopIndex, VelocityExpressions.ConvertIfNeeded(indexInitalise, LoopIndex.Type));
            }
            body.Add(indexInitalise);

            // Do the main loop - this handles the #BeforeAll, #Before,#Odd,#Even,#After & #Each templates
            body.Add(new ForeachExpression(Enumerable, BuildItemBody(), LoopVariable, _break, null));


            //If we have a NoData or AfterAll template, execute that after we've finished the loop.
            if (NoData != null || AfterAll != null)
            {
                body.Add(Expression.IfThenElse(
                             Expression.Equal(_internalIndex, Constants.Zero),
                             NoData ?? Constants.EmptyExpression,
                             AfterAll ?? Constants.EmptyExpression
                             ));
            }

            return(Expression.Block(
                       typeof(void),
                       new[] { _internalIndex, },
                       body.ToImmutable()
                       ));
        }
Exemple #6
0
        private Expression BuildItemBody()
        {
            var bodyExpressions = new List <Expression>();

            //First, increment the item index
            //TODO: For NVelocity compatibility, check if this is the right place to increment the index - should it instead be after the BeforeAll/Between templates>
            Expression indexIncrement = Expression.PreIncrementAssign(_internalIndex);

            if (LoopIndex != null)
            {
                indexIncrement = Expression.Assign(LoopIndex, VelocityExpressions.ConvertIfNeeded(indexIncrement, LoopIndex.Type));
            }
            bodyExpressions.Add(indexIncrement);

            //For the first item, output the #BeforeAll template, for all others #Between
            if (BeforeAll != null || Between != null)
            {
                bodyExpressions.Add(
                    Expression.IfThenElse(
                        Expression.Equal(_internalIndex, _constantOne),
                        BeforeAll ?? Constants.EmptyExpression,
                        Between ?? Constants.EmptyExpression
                        )
                    );
            }

            //Next comes the #Before template
            if (Before != null)
            {
                bodyExpressions.Add(Before);
            }


            //Next come the #Odd / #Even
            if (Even != null || Odd != null)
            {
                bodyExpressions.Add(
                    Expression.IfThenElse(
                        Expression.Equal(Constants.Zero, Expression.Modulo(_internalIndex, _constantTwo)),
                        Even ?? Constants.EmptyExpression,
                        Odd ?? Constants.EmptyExpression
                        )
                    );
            }

            // Next up #Each
            if (Each != null)
            {
                bodyExpressions.Add(Each);
            }

            // Finally comes #After
            if (After != null)
            {
                bodyExpressions.Add(After);
            }

            return(Expression.Block(bodyExpressions));
        }
Exemple #7
0
        protected virtual Expression ArrayIndexer(DynamicMetaObject target, DynamicMetaObject[] args)
        {
            var type = target.LimitType;

            if (args.All(x => (typeof(int)).IsAssignableFrom(x.LimitType)))
            {
                var targetExpression = VelocityExpressions.ConvertIfNeeded(target.Expression, type);
                return(Expression.ArrayAccess(targetExpression, args.Select(x => x.Expression)));
            }
            return(null);
        }
Exemple #8
0
        private DynamicMetaObject Relational(VelocityOperator operatorType, DynamicMetaObject left, DynamicMetaObject right, DynamicMetaObject errorSuggestion)
        {
            var op = _operatorResolver.Resolve(operatorType, left.RuntimeType, right.RuntimeType);

            if (op == null)
            {
                if (operatorType == VelocityOperator.GreaterThanOrEqual || operatorType == VelocityOperator.LessThanOrEqual)
                {
                    return(Equality(VelocityOperator.Equal, left, right, errorSuggestion));
                }
                else
                {
                    return(null);
                }
            }


            var leftExpr  = VelocityExpressions.ConvertIfNeeded(left.Expression, op.Parameters[0]);
            var rightExpr = VelocityExpressions.ConvertIfNeeded(right.Expression, op.Parameters[1]);

            Expression result;

            switch (operatorType)
            {
            case VelocityOperator.GreaterThan:
                result = Expression.GreaterThan(leftExpr, rightExpr, false, op.FunctionMember);
                break;

            case VelocityOperator.GreaterThanOrEqual:
                result = Expression.GreaterThanOrEqual(leftExpr, rightExpr, false, op.FunctionMember);
                break;

            case VelocityOperator.LessThan:
                result = Expression.LessThan(leftExpr, rightExpr, false, op.FunctionMember);
                break;

            case VelocityOperator.LessThanOrEqual:
                result = Expression.LessThanOrEqual(leftExpr, rightExpr, false, op.FunctionMember);
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(Operation));
            }

            var restrictions = BinderHelper.CreateCommonRestrictions(left, right);

            result = VelocityExpressions.ConvertIfNeeded(result, ReturnType);

            return(new DynamicMetaObject(result, restrictions));
        }
Exemple #9
0
        private Expression AddOverflowHandling(Expression operation, Expression left, Expression right)
        {
            if (!TypeHelper.IsInteger(left.Type) || !TypeHelper.IsInteger(right.Type))
            {
                return(operation);
            }

            Func <Expression, Expression, Expression> overflowHandler;


            switch (Operation)
            {
            case ExpressionType.Add:
                overflowHandler = Expression.Add;
                break;

            case ExpressionType.Subtract:
                overflowHandler = Expression.Subtract;
                break;

            case ExpressionType.Multiply:
                overflowHandler = Expression.Multiply;
                break;

            default:
                return(operation);
            }

            var overflowExpression = overflowHandler(
                BigIntegerHelper.ConvertToBigInteger(left),
                BigIntegerHelper.ConvertToBigInteger(right)
                );


            var useSignedIntegerTypes = TypeHelper.IsSignedInteger(left.Type);
            //Pass the final result into ReduceBigInteger(...) to return a more recognizable primitive
            var overflowFallback = VelocityExpressions.ConvertIfNeeded(
                Expression.Call(MethodHelpers.ReduceBigIntegerMethodInfo, overflowExpression, Expression.Constant(useSignedIntegerTypes)),
                ReturnType
                );

            return(Expression.TryCatch(
                       VelocityExpressions.ConvertIfNeeded(operation, ReturnType),
                       Expression.Catch(typeof(ArithmeticException),
                                        overflowFallback
                                        )
                       ));
        }
Exemple #10
0
        public override DynamicMetaObject FallbackInvokeMember(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)
        {
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }
            if (args == null)
            {
                throw new ArgumentNullException(nameof(args));
            }

            if (!target.HasValue || args.Any(x => !x.HasValue))
            {
                return(Defer(target, args));
            }

            if (target == null)
            {
                return(BinderHelper.NullTargetResult(target, errorSuggestion));
            }


            // If an argument has a null value, use a null type so that the resolution algorithm can do implicit null conversions
            var argTypes = args.Select(x => x.Value == null ? null : x.RuntimeType).ToImmutableList();

            OverloadResolutionData <MethodInfo> method = _methodResolver.ResolveMethod(target.LimitType.GetTypeInfo(), Name, argTypes);

            var restrictions = BinderHelper.CreateCommonRestrictions(target, args);

            if (method == null)
            {
                var log = BindingEventSource.Log;
                if (log.IsEnabled())
                {
                    var argTypeString = string.Join(",", argTypes.Select(x => x.FullName).ToArray());
                    log.InvokeMemberResolutionFailure(Name, target.LimitType.FullName, argTypeString);
                }

                return(BinderHelper.UnresolveableResult(restrictions, errorSuggestion));
            }

            var methodExpression = _methodResolver.ConvertMethodParameters(method, target.Expression, args);

            return(new DynamicMetaObject(
                       VelocityExpressions.ConvertIfNeeded(methodExpression, ReturnType),
                       restrictions
                       ));
        }
        public override DynamicMetaObject FallbackSetMember(DynamicMetaObject target, DynamicMetaObject value, DynamicMetaObject errorSuggestion)
        {
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }
            if (value == null)
            {
                throw new ArgumentNullException(nameof(target));
            }

            if (!target.HasValue || !value.HasValue)
            {
                return(Defer(target, value));
            }

            if (target.Value == null)
            {
                return(BinderHelper.NullTargetResult(target, errorSuggestion));
            }
            if (value.Value == null)
            {
                return(BinderHelper.SetNullValue(this, value));
            }


            var memberAccess = _memberResolver.MemberExpression(Name, target, MemberAccessMode.Write);

            var restrictions = BinderHelper.CreateCommonRestrictions(target);

            if (memberAccess == null || !memberAccess.Type.IsAssignableFrom(value.RuntimeType))
            {
                BindingEventSource.Log.SetMemberResolutionFailure(Name, target.RuntimeType.FullName, value.RuntimeType.FullName);
                return(BinderHelper.UnresolveableResult(restrictions, errorSuggestion));
            }

            var result = VelocityExpressions.BoxIfNeeded(
                Expression.Assign(
                    memberAccess,
                    VelocityExpressions.ConvertIfNeeded(value, memberAccess.Type)
                    )
                );

            return(new DynamicMetaObject(result, restrictions));
        }
Exemple #12
0
        private DynamicMetaObject AddSubtractMultiply(VelocityOperator operatorType, DynamicMetaObject left, DynamicMetaObject right)
        {
            var op = _operatorResolver.Resolve(operatorType, left.RuntimeType, right.RuntimeType);

            if (op == null)
            {
                return(null);
            }

            var targetExpr = VelocityExpressions.ConvertIfNeeded(left, op.Parameters[0]);
            var argExpr    = VelocityExpressions.ConvertIfNeeded(right, op.Parameters[1]);

            Func <Expression, Expression, MethodInfo, Expression> operationFunc;

            switch (operatorType)
            {
            case VelocityOperator.Add:
                operationFunc = Expression.AddChecked;
                break;

            case VelocityOperator.Subtract:
                operationFunc = Expression.SubtractChecked;
                break;

            case VelocityOperator.Multiply:
                operationFunc = Expression.MultiplyChecked;
                break;

            default:
                throw new InvalidOperationException();
            }

            Expression operation = operationFunc(targetExpr, argExpr, op.FunctionMember);

            if (op.FunctionMember == null)
            {
                operation = AddOverflowHandling(operation, left.Expression, right.Expression);
            }

            operation = VelocityExpressions.ConvertIfNeeded(operation, ReturnType);

            var restrictions = BinderHelper.CreateCommonRestrictions(left, right);

            return(new DynamicMetaObject(operation, restrictions));
        }
Exemple #13
0
        public override Expression Reduce()
        {
            var expression = Value;

            if (expression.Type == typeof(bool) || expression.Type == typeof(bool?))
            {
                return(expression);
            }

            else if (!TypeHelper.IsNullableType(Value.Type))
            {
                return(Constants.True);
            }

            expression = VelocityExpressions.ConvertIfNeeded(expression, typeof(object));

            return(Expression.Convert(expression, typeof(bool), MethodHelpers.BooleanCoercionMethodInfo));
        }
Exemple #14
0
        public override DynamicMetaObject FallbackSetIndex(DynamicMetaObject target, DynamicMetaObject[] indexes, DynamicMetaObject value, DynamicMetaObject errorSuggestion)
        {
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }
            if (indexes == null)
            {
                throw new ArgumentNullException(nameof(indexes));
            }
            if (indexes == null)
            {
                throw new ArgumentNullException(nameof(indexes));
            }

            if (!target.HasValue || !value.HasValue || indexes.Any(x => !x.HasValue))
            {
                return(Defer(target, indexes.Concat(new[] { value }).ToArray()));
            }

            if (target.Value == null)
            {
                return(BinderHelper.NullTargetResult(target, errorSuggestion));
            }
            if (value.Value == null)
            {
                return(BinderHelper.SetNullValue(this, value));
            }

            var restrictions = BinderHelper.CreateCommonRestrictions(target, indexes)
                               .Merge(BinderHelper.CreateCommonRestrictions(value));

            var index = _indexerResolver.WriteableIndexer(target, indexes);

            if (index == null || !index.Type.IsAssignableFrom(value.RuntimeType))
            {
                return(BinderHelper.UnresolveableResult(restrictions, errorSuggestion));
            }

            var assignment = Expression.Assign(index, VelocityExpressions.ConvertIfNeeded(value.Expression, index.Type));

            return(new DynamicMetaObject(VelocityExpressions.ConvertIfNeeded(assignment, ReturnType), restrictions));
        }
Exemple #15
0
        public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
        {
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }

            if (!target.HasValue)
            {
                return(Defer(target));
            }

            if (target.Value == null)
            {
                return(BinderHelper.NullTargetResult(target, errorSuggestion));
            }

            Expression result       = null;
            var        restrictions = BinderHelper.CreateCommonRestrictions(target);

            try
            {
                result = _memberResolver.MemberExpression(Name, target, MemberAccessMode.Read);
            }
            catch (AmbiguousMatchException)
            {
                BindingEventSource.Log.GetMemberResolutionAmbiguous(Name, target.RuntimeType.FullName);
                return(BinderHelper.UnresolveableResult(restrictions, errorSuggestion));
            }


            if (result == null)
            {
                BindingEventSource.Log.GetMemberResolutionFailure(Name, target.RuntimeType.FullName);
                return(BinderHelper.UnresolveableResult(restrictions, errorSuggestion));
            }

            return(new DynamicMetaObject(
                       VelocityExpressions.ConvertIfNeeded(result, ReturnType),
                       restrictions
                       ));
        }
Exemple #16
0
        private Expression IndexExpression(DynamicMetaObject target, DynamicMetaObject[] args, IEnumerable <PropertyInfo> candidateProperties)
        {
            var typeArgs = args.Select(x => x.LimitType).ToImmutableArray();

            var candidateData = candidateProperties.Select(x => new FunctionMemberData <PropertyInfo>(x, x.GetIndexParameters()));

            var result = _overloadResolver.Resolve(candidateData, typeArgs);

            if (result == null)
            {
                return(null);
            }

            var argExpressions = _overloadResolver.CreateParameterExpressions(result, args);
            var indexer        = result.FunctionMember;

            var targetExpression = VelocityExpressions.ConvertIfNeeded(target.Expression, indexer.DeclaringType);

            return(Expression.MakeIndex(targetExpression, indexer, argExpressions));
        }
Exemple #17
0
        public override Expression Reduce()
        {
            var dictionaryInit = Expression.New(
                _dictionaryConstructorInfo,
                Expression.Constant(Values.Count)
                );

            if (!Values.Any())
            {
                return(dictionaryInit);
            }

            var initializers = Values.Select(x => Expression.ElementInit(
                                                 _dictionaryAddMemberInfo,
                                                 x.Key,
                                                 VelocityExpressions.ConvertIfNeeded(x.Value, typeof(object))
                                                 ));

            return(Expression.ListInit(dictionaryInit, initializers));
        }
        public IImmutableList<Expression> CreateParameterExpressions<T>(OverloadResolutionData<T> overload, DynamicMetaObject[] args)
            where T : MemberInfo
        {
            if (overload == null)
                throw new ArgumentNullException(nameof(overload));

            if (args == null)
                throw new ArgumentNullException(nameof(args));

            var parameters = overload.Parameters;

            bool isInExpandedForm = overload.ApplicableForm == ApplicableForm.Expanded;

            int fixedParams = isInExpandedForm
                ? parameters.Length - 1
                : parameters.Length;

            var argExpressionBuilder = ImmutableArray.CreateBuilder<Expression>(parameters.Length);

            for (int i = 0; i < fixedParams; i++)
            {
                var parameter = parameters[i];
                argExpressionBuilder.Add(VelocityExpressions.ConvertIfNeeded(args[i], parameter));
            }
            if (isInExpandedForm)
            {
                var lastParameter = overload.Parameters.Last();

                var elementType = lastParameter.GetElementType();
                argExpressionBuilder.Add(Expression.NewArrayInit(
                    elementType,
                    args.Skip(fixedParams)
                        .Select(x => VelocityExpressions.ConvertIfNeeded(x, elementType))
                    ));
            }

            return argExpressionBuilder.ToImmutable();
        }
Exemple #19
0
 public void MakeBinaryOperandsCompatible(Type leftType, Type rightType, ref Expression leftExpression, ref Expression rightExpression)
 {
     if (CanBeConverted(leftType, rightType))
     {
         leftExpression = VelocityExpressions.ConvertIfNeeded(leftExpression, rightType);
     }
     else if (CanBeConverted(rightType, leftType))
     {
         rightExpression = VelocityExpressions.ConvertIfNeeded(rightExpression, leftType);
     }
     else if (leftType == typeof(string) && (rightType == typeof(char) || rightType.IsEnum))
     {
         rightExpression = Expression.Call(rightExpression, MethodHelpers.ToStringMethodInfo);
     }
     else if (rightType == typeof(string) && (leftType == typeof(char) || leftType.IsEnum))
     {
         leftExpression = Expression.Call(leftExpression, MethodHelpers.ToStringMethodInfo);
     }
     else if (leftType != rightType && TypeHelper.IsInteger(leftType) && TypeHelper.IsInteger(rightType))
     {
         leftExpression  = BigIntegerHelper.ConvertToBigInteger(leftExpression);
         rightExpression = BigIntegerHelper.ConvertToBigInteger(rightExpression);
     }
 }
Exemple #20
0
 public override Expression Reduce() => VelocityExpressions.ConvertIfNeeded(new VariableExpression(Name), Type);
        public Expression MemberExpression(string name, Type type, Expression expression, MemberAccessMode mode)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }

            MemberInfo member = null;

            try
            {
                member = GetMember(name, type, false, mode);
            }
            catch (AmbiguousMatchException)
            {
                member = GetMember(name, type, true, mode);
            }


            if (member == null)
            {
                //If no matching property or field, fall back to indexer with string param
                var indexer = type.GetProperty("Item", _caseSensitiveBindingFlags, null, null, new[] { typeof(string) }, null) as PropertyInfo;
                if (indexer != null)
                {
                    return(Expression.MakeIndex(
                               VelocityExpressions.ConvertIfNeeded(expression, indexer.DeclaringType),
                               indexer,
                               new[] { Expression.Constant(name) }
                               ));
                }

                if (type.IsArray && name.Equals("count", StringComparison.OrdinalIgnoreCase))
                {
                    return(MemberExpression("Length", type, expression, mode));
                }
            }
            else
            {
                var property = member as PropertyInfo;
                if (property != null)
                {
                    return(Expression.Property(
                               //VelocityExpressions.ConvertReturnTypeIfNeeded(target, member),
                               VelocityExpressions.ConvertIfNeeded(expression, property.DeclaringType),
                               property
                               ));
                }
                else
                {
                    var field = member as FieldInfo;
                    if (field != null)
                    {
                        return(Expression.Field(
                                   //VelocityExpressions.ConvertReturnTypeIfNeeded(target, member),
                                   VelocityExpressions.ConvertIfNeeded(expression, field.DeclaringType),
                                   field
                                   ));
                    }
                }
            }

            return(null);
        }
Exemple #22
0
        public override Expression Reduce()
        {
            var objValues = Values.Select(x => VelocityExpressions.ConvertIfNeeded(x, typeof(object)));

            return(Expression.New(MethodHelpers.ListConstructorInfo, Expression.NewArrayInit(typeof(object), objValues)));
        }
Exemple #23
0
        public override Expression Reduce()
        {
            var left  = Left;
            var right = Right;

            if (left is ReferenceExpression)
            {
                left = left.Reduce();
            }

            if (left is GlobalVariableExpression)
            {
                throw new NotSupportedException("Cannot assign to a Global Variable");
            }

            var getMember = left as PropertyAccessExpression;

            if (getMember != null)
            {
                return(new SetMemberExpression(getMember.Target, right, _binderFactory.GetSetMemberBinder(getMember.Name)));
            }

            var indexer = left as IndexInvocationExpression;

            if (indexer != null)
            {
                return(new SetIndexExpression(indexer.Target, right, indexer.Arguments, _binderFactory.GetSetIndexBinder(indexer.Arguments.Count)));
            }


            bool rightIsNullableType = TypeHelper.IsNullableType(right.Type);

            bool isVariableExpression = left is VariableExpression;

            if (isVariableExpression)
            {
                left = left.Reduce();
            }
            else if (left is MethodInvocationExpression || left is MethodCallExpression || left is ConstantExpression)
            {
                return(Constants.EmptyExpression);
            }

            if (!left.Type.IsAssignableFrom(right.Type))
            {
                //If we can't assign from right to left, but can from left to right
                // Then we may be able to assign at runtime
                if (right.Type.IsAssignableFrom(left.Type))
                {
                    right = Expression.TypeAs(right, left.Type);
                }
                else
                {
                    //TODO: Log
                    return(Constants.EmptyExpression);
                }
            }
            else
            {
                right = VelocityExpressions.ConvertIfNeeded(right, left.Type);
            }



            //However, if the expression is guaranteed to be a value type (i.e. not nullable), why bother?
            //Similarly if it's a variable expression, the null handling is handled inside VelocityContext
            if (isVariableExpression || !rightIsNullableType)
            {
                return(Expression.Block(typeof(void), Expression.Assign(left, right)));
            }

            var tempResult = right.Type == typeof(object)
                ? _objectTemp
                : Expression.Parameter(right.Type, "setDirectiveTemp");

            return(new TemporaryVariableScopeExpression(tempResult,
                                                        Expression.IfThen(
                                                            //Store the result of the right hand side in to a temporary variable
                                                            //If the temporary variable is not equal to null
                                                            Expression.NotEqual(Expression.Assign(tempResult, right), Expression.Constant(null, right.Type)),
                                                            //Make the assignment
                                                            Expression.Assign(left, tempResult)
                                                            )
                                                        ));
        }
Exemple #24
0
 public Expression Convert(Expression target, Type to) => VelocityExpressions.ConvertIfNeeded(target, to);
Exemple #25
0
        private DynamicMetaObject Division(VelocityOperator operatorType, DynamicMetaObject left, DynamicMetaObject right)
        {
            var op = _operatorResolver.Resolve(operatorType, left.RuntimeType, right.RuntimeType);

            if (op == null)
            {
                return(null);
            }

            var restrictions = BinderHelper.CreateCommonRestrictions(left, right);

            Expression result = null;

            // For signed integers, Division can fail in two ways
            // 1. Divide by Zero: RHS = 0 (Divide by Zero)
            // 2. Overflow - RHS = -1 && LHS = int.MinValue (or long.MinValue)
            // Rather than catching an exception as we do for Add & Subtract, we can detect these cases directly, avoiding
            // exception handling
            // Floating-point division can't fail
            // Decimal division can overflow, so needs an exception handler
            if (op.FunctionMember == null)
            {
                //Divide by Zero
                var argZero = GetZeroExpression(right);
                if (argZero != null)
                {
                    BindingRestrictions zeroRestriction;
                    if (argZero.Value.Equals(right.Value))
                    {
                        zeroRestriction = BindingRestrictions.GetExpressionRestriction(Expression.Equal(argZero, VelocityExpressions.ConvertIfNeeded(right.Expression, argZero.Type)));
                        result          = Constants.VelocityUnresolvableResult;
                    }
                    else
                    {
                        zeroRestriction = BindingRestrictions.GetExpressionRestriction(Expression.NotEqual(argZero, VelocityExpressions.ConvertIfNeeded(right.Expression, argZero.Type)));
                    }
                    restrictions = restrictions.Merge(zeroRestriction);
                }

                //Overflow
                ConstantExpression lhsMax = null;
                if (left.RuntimeType == typeof(int))
                {
                    lhsMax = _maxInt;
                }

                if (left.RuntimeType == typeof(long))
                {
                    lhsMax = _maxLong;
                }

                if (lhsMax != null)
                {
                    var negativeOne = GetNegativeOneExpression(right);

                    if (negativeOne != null)
                    {
                        BindingRestrictions overflowRestrictions;
                        if (left.Value.Equals(lhsMax.Value) && right.Value.Equals(negativeOne.Value))
                        {
                            result = Constants.VelocityUnresolvableResult;
                            overflowRestrictions = BindingRestrictions.GetExpressionRestriction(
                                Expression.AndAlso(
                                    Expression.Equal(left.Expression, lhsMax),
                                    Expression.Equal(right.Expression, negativeOne)
                                    )
                                );
                        }
                        else
                        {
                            overflowRestrictions = BindingRestrictions.GetExpressionRestriction(
                                Expression.OrElse(
                                    Expression.NotEqual(lhsMax, VelocityExpressions.ConvertIfNeeded(left.Expression, lhsMax.Type)),
                                    Expression.NotEqual(negativeOne, VelocityExpressions.ConvertIfNeeded(right.Expression, lhsMax.Type))
                                    )
                                );
                        }
                        restrictions = restrictions.Merge(overflowRestrictions);
                    }
                }
            }

            if (result == null)
            {
                var targetExpr = VelocityExpressions.ConvertIfNeeded(left, op.Parameters[0]);
                var argExpr    = VelocityExpressions.ConvertIfNeeded(right, op.Parameters[1]);
                if (Operation == ExpressionType.Divide)
                {
                    result = Expression.Divide(targetExpr, argExpr, op.FunctionMember);
                }
                else if (Operation == ExpressionType.Modulo)
                {
                    result = Expression.Modulo(targetExpr, argExpr, op.FunctionMember);
                }
                else
                {
                    throw new InvalidOperationException();
                }
            }

            if (op.Parameters[0] == typeof(decimal) && op.Parameters[1] == typeof(decimal))
            {
                result = Expression.TryCatch(
                    VelocityExpressions.ConvertIfNeeded(result, ReturnType),
                    Expression.Catch(typeof(ArithmeticException),
                                     Constants.VelocityUnresolvableResult
                                     )
                    );
            }

            var operation = VelocityExpressions.ConvertIfNeeded(result, ReturnType);

            return(new DynamicMetaObject(operation, restrictions));
        }