public override Expression Reduce() { return(Expression.Call(null, MethodHelpers.IntegerRangeMethodInfo, VelocityExpressions.ConvertIfNeeded(Left, typeof(object)), VelocityExpressions.ConvertIfNeeded(Right, typeof(object)) )); }
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); }
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)); }
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() )); }
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)); }
public Expression VisitOrExpression([NotNull] VelocityParser.OrExpressionContext context) { var left = VelocityExpressions.CoerceToBoolean(Visit(context.expression(0))); var right = VelocityExpressions.CoerceToBoolean(Visit(context.expression(1))); return(Expression.OrElse(left, right)); }
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)); }
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); }
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)); }
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 )); }
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 ) )); }
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)); }
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)); }
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)); }
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)); }
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 )); }
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)); }
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(); }
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); } }
public override Expression Reduce() => VelocityExpressions.ConvertIfNeeded(new VariableExpression(Name), Type);
public Expression Convert(Expression target, Type to) => VelocityExpressions.ConvertIfNeeded(target, to);
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); }
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) ) )); }
public Expression VisitUnaryExpression([NotNull] VelocityParser.UnaryExpressionContext context) { var target = Visit(context.expression()); return(Expression.Not(VelocityExpressions.CoerceToBoolean(target))); }
public override Expression Reduce() { var objValues = Values.Select(x => VelocityExpressions.ConvertIfNeeded(x, typeof(object))); return(Expression.New(MethodHelpers.ListConstructorInfo, Expression.NewArrayInit(typeof(object), objValues))); }
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)); }