private static void DumpExpression(CodeExpression e) { /* * System.CodeDom.CodeArgumentReferenceExpression * System.CodeDom.CodeArrayCreateExpression * System.CodeDom.CodeArrayIndexerExpression * System.CodeDom.CodeBaseReferenceExpression * System.CodeDom.CodeBinaryOperatorExpression * System.CodeDom.CodeCastExpression * System.CodeDom.CodeDefaultValueExpression * System.CodeDom.CodeDelegateCreateExpression * System.CodeDom.CodeDelegateInvokeExpression * System.CodeDom.CodeDirectionExpression * System.CodeDom.CodeEventReferenceExpression * System.CodeDom.CodeFieldReferenceExpression * System.CodeDom.CodeIndexerExpression * System.CodeDom.CodeMethodInvokeExpression * System.CodeDom.CodeMethodReferenceExpression * System.CodeDom.CodeObjectCreateExpression * System.CodeDom.CodeParameterDeclarationExpression * System.CodeDom.CodePrimitiveExpression * System.CodeDom.CodePropertyReferenceExpression * System.CodeDom.CodePropertySetValueReferenceExpression * System.CodeDom.CodeSnippetExpression * System.CodeDom.CodeThisReferenceExpression * System.CodeDom.CodeTypeOfExpression * System.CodeDom.CodeTypeReferenceExpression * System.CodeDom.CodeVariableReferenceExpression */ if (e == null) { return; } if (e is CodeFieldReferenceExpression cfre) { DumpExpression(cfre.TargetObject); WriteLineIndent("F: " + cfre.FieldName); } else if (e is CodeObjectCreateExpression coce) { var tr = coce.CreateType as CodeTypeReference; WriteLineIndent(tr.BaseType + "{}"); DumpExpressionList(coce.Parameters); } else if (e is CodeMethodInvokeExpression cmie) { DumpExpression(cmie.Method.TargetObject); WriteLineIndent("M: " + cmie.Method.MethodName); DumpExpressionList(cmie.Parameters); } else if (e is CodePropertyReferenceExpression cpre) { DumpExpression(cpre.TargetObject); WriteLineIndent("P: " + cpre.PropertyName); } else if (e is CodePrimitiveExpression cpe) { WriteLineIndent(cpe.ToString()); WriteLineIndent(cpe.Value.ToString()); } else if (e is CodeCastExpression cce) { WriteLineIndent(cce.TargetType.ToString()); DumpExpression(cce.Expression); } else if (e is CodeThisReferenceExpression) { WriteLineIndent("SELF"); } else if (e is CodeBinaryOperatorExpression cboe) { DumpExpression(cboe.Left); CodeBinaryOperatorType opType = cboe.Operator; WriteLineIndent(opType.ToString()); DumpExpression(cboe.Right); } else if (e is CodeTypeReferenceExpression ctre) { var tr = ctre.Type; WriteLineIndent(tr.BaseType); } else if (e is CodeBaseReferenceExpression) { WriteLineIndent("SUPER"); } else { WriteLineIndent(e.GetType().FullName); } }
private static object EvaluateBinaryOperation(CodeBinaryOperatorExpression binaryExpr, Type lhsType, object lhsValue, CodeBinaryOperatorType operation, Type rhsType, object rhsValue) { Literal literal; Literal literal2; ArithmeticLiteral literal3; ArithmeticLiteral literal4; RuleEvaluationException exception; switch (operation) { case CodeBinaryOperatorType.Add: literal3 = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (literal3 == null) { break; } literal4 = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (literal4 == null) { break; } return(literal3.Add(literal4)); case CodeBinaryOperatorType.Subtract: literal3 = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (literal3 == null) { break; } literal4 = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (literal4 == null) { break; } return(literal3.Subtract(literal4)); case CodeBinaryOperatorType.Multiply: literal3 = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (literal3 == null) { break; } literal4 = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (literal4 == null) { break; } return(literal3.Multiply(literal4)); case CodeBinaryOperatorType.Divide: literal3 = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (literal3 == null) { break; } literal4 = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (literal4 == null) { break; } return(literal3.Divide(literal4)); case CodeBinaryOperatorType.Modulus: literal3 = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (literal3 == null) { break; } literal4 = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (literal4 == null) { break; } return(literal3.Modulus(literal4)); case CodeBinaryOperatorType.IdentityInequality: return(lhsValue != rhsValue); case CodeBinaryOperatorType.IdentityEquality: return(lhsValue == rhsValue); case CodeBinaryOperatorType.ValueEquality: literal = Literal.MakeLiteral(lhsType, lhsValue); if (literal == null) { break; } literal2 = Literal.MakeLiteral(rhsType, rhsValue); if (literal2 == null) { break; } return(literal.Equal(literal2)); case CodeBinaryOperatorType.BitwiseOr: literal3 = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (literal3 == null) { break; } literal4 = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (literal4 == null) { break; } return(literal3.BitOr(literal4)); case CodeBinaryOperatorType.BitwiseAnd: literal3 = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (literal3 == null) { break; } literal4 = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (literal4 == null) { break; } return(literal3.BitAnd(literal4)); case CodeBinaryOperatorType.LessThan: literal = Literal.MakeLiteral(lhsType, lhsValue); if (literal == null) { break; } literal2 = Literal.MakeLiteral(rhsType, rhsValue); if (literal2 == null) { break; } return(literal.LessThan(literal2)); case CodeBinaryOperatorType.LessThanOrEqual: literal = Literal.MakeLiteral(lhsType, lhsValue); if (literal == null) { break; } literal2 = Literal.MakeLiteral(rhsType, rhsValue); if (literal2 == null) { break; } return(literal.LessThanOrEqual(literal2)); case CodeBinaryOperatorType.GreaterThan: literal = Literal.MakeLiteral(lhsType, lhsValue); if (literal == null) { break; } literal2 = Literal.MakeLiteral(rhsType, rhsValue); if (literal2 == null) { break; } return(literal.GreaterThan(literal2)); case CodeBinaryOperatorType.GreaterThanOrEqual: literal = Literal.MakeLiteral(lhsType, lhsValue); if (literal == null) { break; } literal2 = Literal.MakeLiteral(rhsType, rhsValue); if (literal2 == null) { break; } return(literal.GreaterThanOrEqual(literal2)); default: exception = new RuleEvaluationException(string.Format(CultureInfo.CurrentCulture, Messages.BinaryOpNotSupported, new object[] { operation.ToString() })); exception.Data["ErrorObject"] = binaryExpr; throw exception; } exception = new RuleEvaluationException(string.Format(CultureInfo.CurrentCulture, Messages.BinaryOpFails, new object[] { operation.ToString(), RuleDecompiler.DecompileType(lhsType), RuleDecompiler.DecompileType(rhsType) })); exception.Data["ErrorObject"] = binaryExpr; throw exception; }
private static void dumpExpression(CodeExpression e) { /* * System.CodeDom.CodeArgumentReferenceExpression * System.CodeDom.CodeArrayCreateExpression * System.CodeDom.CodeArrayIndexerExpression * System.CodeDom.CodeBaseReferenceExpression * System.CodeDom.CodeBinaryOperatorExpression * System.CodeDom.CodeCastExpression * System.CodeDom.CodeDefaultValueExpression * System.CodeDom.CodeDelegateCreateExpression * System.CodeDom.CodeDelegateInvokeExpression * System.CodeDom.CodeDirectionExpression * System.CodeDom.CodeEventReferenceExpression * System.CodeDom.CodeFieldReferenceExpression * System.CodeDom.CodeIndexerExpression * System.CodeDom.CodeMethodInvokeExpression * System.CodeDom.CodeMethodReferenceExpression * System.CodeDom.CodeObjectCreateExpression * System.CodeDom.CodeParameterDeclarationExpression * System.CodeDom.CodePrimitiveExpression * System.CodeDom.CodePropertyReferenceExpression * System.CodeDom.CodePropertySetValueReferenceExpression * System.CodeDom.CodeSnippetExpression * System.CodeDom.CodeThisReferenceExpression * System.CodeDom.CodeTypeOfExpression * System.CodeDom.CodeTypeReferenceExpression * System.CodeDom.CodeVariableReferenceExpression */ if (e == null) { return; } if (e is CodeFieldReferenceExpression) { CodeFieldReferenceExpression exp = (CodeFieldReferenceExpression)e; dumpExpression(exp.TargetObject); writeLineIndent("F: " + exp.FieldName); } else if (e is CodeObjectCreateExpression) { var exp = (CodeObjectCreateExpression)e; var tr = exp.CreateType as CodeTypeReference; writeLineIndent(tr.BaseType + "{}"); dumpExpressionList(exp.Parameters); } else if (e is CodeMethodInvokeExpression) { var exp = (CodeMethodInvokeExpression)e; dumpExpression(exp.Method.TargetObject); writeLineIndent("M: " + exp.Method.MethodName); dumpExpressionList(exp.Parameters); } else if (e is CodePropertyReferenceExpression) { var exp = (CodePropertyReferenceExpression)e; dumpExpression(exp.TargetObject); writeLineIndent("P: " + exp.PropertyName); } else if (e is CodePrimitiveExpression) { var exp = (CodePrimitiveExpression)e; writeLineIndent(exp.ToString()); writeLineIndent(exp.Value.ToString()); } else if (e is CodeCastExpression) { var exp = (CodeCastExpression)e; writeLineIndent(exp.TargetType.ToString()); dumpExpression(exp.Expression); } else if (e is CodeThisReferenceExpression) { writeLineIndent("SELF"); } else if (e is CodeBinaryOperatorExpression) { var exp = (CodeBinaryOperatorExpression)e; dumpExpression(exp.Left); CodeBinaryOperatorType opType = exp.Operator; writeLineIndent(opType.ToString()); dumpExpression(exp.Right); } else if (e is CodeTypeReferenceExpression) { var exp = (CodeTypeReferenceExpression)e; var tr = exp.Type; writeLineIndent(tr.BaseType); } else if (e is CodeBaseReferenceExpression) { writeLineIndent("SUPER"); } else { writeLineIndent(e.GetType().FullName); } }
internal static RuleBinaryExpressionInfo AllowedComparison( Type lhs, CodeExpression lhsExpression, Type rhs, CodeExpression rhsExpression, CodeBinaryOperatorType comparison, RuleValidation validator, out ValidationError error) { // note that null values come in as a NullLiteral type TypeFlags lhsFlags, rhsFlags; // are the types supported? if ((supportedTypes.TryGetValue(lhs, out lhsFlags)) && (supportedTypes.TryGetValue(rhs, out rhsFlags))) { // both sides supported if (lhsFlags == rhsFlags) { // both sides the same type, so it's allowed // only allow equality on booleans if ((lhsFlags == TypeFlags.Bool) && (comparison != CodeBinaryOperatorType.ValueEquality)) { string message = string.Format(CultureInfo.CurrentCulture, Messages.RelationalOpBadTypes, comparison.ToString(), RuleDecompiler.DecompileType(lhs), RuleDecompiler.DecompileType(rhs)); error = new ValidationError(message, ErrorNumbers.Error_OperandTypesIncompatible); return null; } error = null; return new RuleBinaryExpressionInfo(lhs, rhs, typeof(bool)); } // if not the same, only certain combinations allowed switch (lhsFlags | rhsFlags) { case TypeFlags.Decimal | TypeFlags.SignedNumbers: case TypeFlags.Decimal | TypeFlags.UnsignedNumbers: case TypeFlags.Decimal | TypeFlags.ULong: case TypeFlags.Float | TypeFlags.SignedNumbers: case TypeFlags.Float | TypeFlags.UnsignedNumbers: case TypeFlags.Float | TypeFlags.ULong: case TypeFlags.ULong | TypeFlags.UnsignedNumbers: case TypeFlags.SignedNumbers | TypeFlags.UnsignedNumbers: error = null; return new RuleBinaryExpressionInfo(lhs, rhs, typeof(bool)); } string message2 = string.Format(CultureInfo.CurrentCulture, Messages.RelationalOpBadTypes, comparison.ToString(), (lhs == typeof(NullLiteral)) ? Messages.NullValue : RuleDecompiler.DecompileType(lhs), (rhs == typeof(NullLiteral)) ? Messages.NullValue : RuleDecompiler.DecompileType(rhs)); error = new ValidationError(message2, ErrorNumbers.Error_OperandTypesIncompatible); return null; } else { // see if they override the operator MethodInfo operatorOverride = MapOperatorToMethod(comparison, lhs, lhsExpression, rhs, rhsExpression, validator, out error); if (operatorOverride != null) return new RuleBinaryExpressionInfo(lhs, rhs, operatorOverride); // unable to evaluate, so return false return null; } }
[SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] // bogus since the casts are in different case statements internal static MethodInfo MapOperatorToMethod( CodeBinaryOperatorType op, Type lhs, CodeExpression lhsExpression, Type rhs, CodeExpression rhsExpression, RuleValidation validator, out ValidationError error) { // determine what the method name should be string methodName; string message; OperatorGrouping group; switch (op) { case CodeBinaryOperatorType.ValueEquality: methodName = "op_Equality"; group = OperatorGrouping.Equality; break; case CodeBinaryOperatorType.GreaterThan: methodName = "op_GreaterThan"; group = OperatorGrouping.Relational; break; case CodeBinaryOperatorType.GreaterThanOrEqual: methodName = "op_GreaterThanOrEqual"; group = OperatorGrouping.Relational; break; case CodeBinaryOperatorType.LessThan: methodName = "op_LessThan"; group = OperatorGrouping.Relational; break; case CodeBinaryOperatorType.LessThanOrEqual: methodName = "op_LessThanOrEqual"; group = OperatorGrouping.Relational; break; case CodeBinaryOperatorType.Add: methodName = "op_Addition"; group = OperatorGrouping.Arithmetic; break; case CodeBinaryOperatorType.Subtract: methodName = "op_Subtraction"; group = OperatorGrouping.Arithmetic; break; case CodeBinaryOperatorType.Multiply: methodName = "op_Multiply"; group = OperatorGrouping.Arithmetic; break; case CodeBinaryOperatorType.Divide: methodName = "op_Division"; group = OperatorGrouping.Arithmetic; break; case CodeBinaryOperatorType.Modulus: methodName = "op_Modulus"; group = OperatorGrouping.Arithmetic; break; case CodeBinaryOperatorType.BitwiseAnd: methodName = "op_BitwiseAnd"; group = OperatorGrouping.Arithmetic; break; case CodeBinaryOperatorType.BitwiseOr: methodName = "op_BitwiseOr"; group = OperatorGrouping.Arithmetic; break; default: Debug.Assert(false, "Operator " + op.ToString() + " not implemented"); message = string.Format(CultureInfo.CurrentCulture, Messages.BinaryOpNotSupported, op.ToString()); error = new ValidationError(message, ErrorNumbers.Error_CodeExpressionNotHandled); return null; } // NOTE: types maybe NullLiteral, which signifies the constant "null" List<MethodInfo> candidates = new List<MethodInfo>(); bool lhsNullable = ConditionHelper.IsNullableValueType(lhs); bool rhsNullable = ConditionHelper.IsNullableValueType(rhs); Type lhsType0 = (lhsNullable) ? Nullable.GetUnderlyingType(lhs) : lhs; Type rhsType0 = (rhsNullable) ? Nullable.GetUnderlyingType(rhs) : rhs; // special cases for enums if (lhsType0.IsEnum) { // only 3 cases (U = underlying type of E): // E = E + U // U = E - E // E = E - U // plus the standard comparisons (E == E, E > E, etc.) // need to also allow E == 0 Type underlyingType; switch (op) { case CodeBinaryOperatorType.Add: underlyingType = EnumHelper.GetUnderlyingType(lhsType0); if ((underlyingType != null) && (RuleValidation.TypesAreAssignable(rhsType0, underlyingType, rhsExpression, out error))) { error = null; return new EnumOperationMethodInfo(lhs, op, rhs, false); } break; case CodeBinaryOperatorType.Subtract: underlyingType = EnumHelper.GetUnderlyingType(lhsType0); if (underlyingType != null) { if (lhsType0 == rhsType0) { // E - E error = null; return new EnumOperationMethodInfo(lhs, op, rhs, false); } else if (DecimalIntegerLiteralZero(rhs, rhsExpression as CodePrimitiveExpression)) { // E - 0, can convert 0 to E error = null; return new EnumOperationMethodInfo(lhs, op, rhs, true); } else if (RuleValidation.TypesAreAssignable(rhsType0, underlyingType, rhsExpression, out error)) { // expression not passed to TypesAreAssignable, so not looking for constants (since 0 is all we care about) error = null; return new EnumOperationMethodInfo(lhs, op, rhs, false); } } break; case CodeBinaryOperatorType.ValueEquality: case CodeBinaryOperatorType.LessThan: case CodeBinaryOperatorType.LessThanOrEqual: case CodeBinaryOperatorType.GreaterThan: case CodeBinaryOperatorType.GreaterThanOrEqual: if (lhsType0 == rhsType0) { error = null; return new EnumOperationMethodInfo(lhs, op, rhs, false); } else if (lhsNullable && (rhs == typeof(NullLiteral))) { // handle enum? op null // treat the rhs as the same nullable enum error = null; return new EnumOperationMethodInfo(lhs, op, lhs, false); } else if (DecimalIntegerLiteralZero(rhs, rhsExpression as CodePrimitiveExpression)) { error = null; return new EnumOperationMethodInfo(lhs, op, rhs, true); } break; } // can't do it, sorry // but check if there is a user-defined operator that works } else if (rhsType0.IsEnum) { // lhs != enum, so only 2 cases (U = underlying type of E): // E = U + E // E = U - E // comparisons are E == E, etc., so if the lhs is not an enum, too bad // although we need to check for 0 == E Type underlyingType; switch (op) { case CodeBinaryOperatorType.Add: underlyingType = EnumHelper.GetUnderlyingType(rhsType0); if ((underlyingType != null) && (RuleValidation.TypesAreAssignable(lhsType0, underlyingType, lhsExpression, out error))) { error = null; return new EnumOperationMethodInfo(lhs, op, rhs, false); } break; case CodeBinaryOperatorType.Subtract: underlyingType = EnumHelper.GetUnderlyingType(rhsType0); if (underlyingType != null) { CodePrimitiveExpression primitive = lhsExpression as CodePrimitiveExpression; if (DecimalIntegerLiteralZero(lhs, primitive)) { // 0 - E, can convert 0 to E error = null; return new EnumOperationMethodInfo(lhs, op, rhs, true); } else if (RuleValidation.TypesAreAssignable(lhsType0, underlyingType, lhsExpression, out error)) { // expression not passed to TypesAreAssignable, so not looking for constants (since 0 is all we care about) error = null; return new EnumOperationMethodInfo(lhs, op, rhs, false); } } break; case CodeBinaryOperatorType.ValueEquality: case CodeBinaryOperatorType.LessThan: case CodeBinaryOperatorType.LessThanOrEqual: case CodeBinaryOperatorType.GreaterThan: case CodeBinaryOperatorType.GreaterThanOrEqual: if (rhsNullable && (lhs == typeof(NullLiteral))) { // handle null op enum? // treat the lhs as the same nullable enum type error = null; return new EnumOperationMethodInfo(rhs, op, rhs, false); } else if (DecimalIntegerLiteralZero(lhs, lhsExpression as CodePrimitiveExpression)) { error = null; return new EnumOperationMethodInfo(lhs, op, rhs, true); } break; } // can't do it, sorry // but check if there is a user-defined operator that works } // enum specific operations already handled, see if one side (or both) define operators AddOperatorOverloads(lhsType0, methodName, lhs, rhs, candidates); AddOperatorOverloads(rhsType0, methodName, lhs, rhs, candidates); if (lhsNullable || rhsNullable || (lhs == typeof(NullLiteral)) || (rhs == typeof(NullLiteral))) { // need to add in lifted methods AddLiftedOperators(lhsType0, methodName, group, lhsType0, rhsType0, candidates); AddLiftedOperators(rhsType0, methodName, group, lhsType0, rhsType0, candidates); } if (candidates.Count == 0) { // no overrides, so get the default list methodName = methodName.Substring(3); // strip off the op_ foreach (MethodInfo mi in typeof(DefaultOperators).GetMethods()) { if (mi.Name == methodName) { ParameterInfo[] parameters = mi.GetParameters(); Type parm1 = parameters[0].ParameterType; Type parm2 = parameters[1].ParameterType; if (RuleValidation.ImplicitConversion(lhs, parm1) && RuleValidation.ImplicitConversion(rhs, parm2)) { candidates.Add(mi); } } } // if no candidates and ==, can we use object == object? if ((candidates.Count == 0) && ("Equality" == methodName)) { // C# 7.9.6 // references must be compatible // no boxing // value types can't be compared if ((!lhs.IsValueType) && (!rhs.IsValueType)) { // they are not classes, so references need to be compatible // also check for null (which is NullLiteral type) -- null is compatible with any object type if ((lhs == typeof(NullLiteral)) || (rhs == typeof(NullLiteral)) || (lhs.IsAssignableFrom(rhs)) || (rhs.IsAssignableFrom(lhs))) { candidates.Add(ObjectEquality); } } } // if no candidates and nullable, add lifted operators if ((candidates.Count == 0) && ((lhsNullable || rhsNullable || (lhs == typeof(NullLiteral)) || (rhs == typeof(NullLiteral))))) { foreach (MethodInfo mi in typeof(DefaultOperators).GetMethods()) { if (mi.Name == methodName) { ParameterInfo[] parameters = mi.GetParameters(); MethodInfo liftedMethod = EvaluateLiftedMethod(mi, parameters, group, lhsType0, rhsType0); if (liftedMethod != null) candidates.Add(liftedMethod); } } } } if (candidates.Count == 1) { // only 1, so it is it error = null; return candidates[0]; } else if (candidates.Count == 0) { // nothing matched message = string.Format(CultureInfo.CurrentCulture, (group == OperatorGrouping.Arithmetic) ? Messages.ArithOpBadTypes : Messages.RelationalOpBadTypes, op.ToString(), (lhs == typeof(NullLiteral)) ? Messages.NullValue : RuleDecompiler.DecompileType(lhs), (rhs == typeof(NullLiteral)) ? Messages.NullValue : RuleDecompiler.DecompileType(rhs)); error = new ValidationError(message, ErrorNumbers.Error_OperandTypesIncompatible); return null; } else { // more than 1, so pick the best one MethodInfo bestFit = validator.FindBestCandidate(null, candidates, lhs, rhs); if (bestFit != null) { error = null; return bestFit; } // must be ambiguous. Since there are at least 2 choices, show only the first 2 message = string.Format(CultureInfo.CurrentCulture, Messages.AmbiguousOperator, op.ToString(), RuleDecompiler.DecompileMethod(candidates[0]), RuleDecompiler.DecompileMethod(candidates[1])); error = new ValidationError(message, ErrorNumbers.Error_OperandTypesIncompatible); return null; } }
internal static RuleBinaryExpressionInfo ResultType(CodeBinaryOperatorType operation, Type lhs, CodeExpression lhsExpression, Type rhs, CodeExpression rhsExpression, RuleValidation validator, out ValidationError error) { TypeFlags flags; TypeFlags flags2; if (supportedTypes.TryGetValue(lhs, out flags) && supportedTypes.TryGetValue(rhs, out flags2)) { Type resultType = ResultType(operation, flags, flags2); if (resultType != null) { error = null; return(new RuleBinaryExpressionInfo(lhs, rhs, resultType)); } string errorText = string.Format(CultureInfo.CurrentCulture, Messages.ArithOpBadTypes, new object[] { operation.ToString(), (lhs == typeof(NullLiteral)) ? Messages.NullValue : RuleDecompiler.DecompileType(lhs), (rhs == typeof(NullLiteral)) ? Messages.NullValue : RuleDecompiler.DecompileType(rhs) }); error = new ValidationError(errorText, 0x545); return(null); } MethodInfo mi = Literal.MapOperatorToMethod(operation, lhs, lhsExpression, rhs, rhsExpression, validator, out error); if (mi != null) { return(new RuleBinaryExpressionInfo(lhs, rhs, mi)); } return(null); }
private static object EvaluateBinaryOperation(CodeBinaryOperatorExpression binaryExpr, Type lhsType, object lhsValue, CodeBinaryOperatorType operation, Type rhsType, object rhsValue) { Literal literal; Literal literal2; ArithmeticLiteral literal3; ArithmeticLiteral literal4; RuleEvaluationException exception; switch (operation) { case CodeBinaryOperatorType.Add: literal3 = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (literal3 == null) { break; } literal4 = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (literal4 == null) { break; } return literal3.Add(literal4); case CodeBinaryOperatorType.Subtract: literal3 = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (literal3 == null) { break; } literal4 = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (literal4 == null) { break; } return literal3.Subtract(literal4); case CodeBinaryOperatorType.Multiply: literal3 = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (literal3 == null) { break; } literal4 = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (literal4 == null) { break; } return literal3.Multiply(literal4); case CodeBinaryOperatorType.Divide: literal3 = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (literal3 == null) { break; } literal4 = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (literal4 == null) { break; } return literal3.Divide(literal4); case CodeBinaryOperatorType.Modulus: literal3 = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (literal3 == null) { break; } literal4 = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (literal4 == null) { break; } return literal3.Modulus(literal4); case CodeBinaryOperatorType.IdentityInequality: return (lhsValue != rhsValue); case CodeBinaryOperatorType.IdentityEquality: return (lhsValue == rhsValue); case CodeBinaryOperatorType.ValueEquality: literal = Literal.MakeLiteral(lhsType, lhsValue); if (literal == null) { break; } literal2 = Literal.MakeLiteral(rhsType, rhsValue); if (literal2 == null) { break; } return literal.Equal(literal2); case CodeBinaryOperatorType.BitwiseOr: literal3 = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (literal3 == null) { break; } literal4 = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (literal4 == null) { break; } return literal3.BitOr(literal4); case CodeBinaryOperatorType.BitwiseAnd: literal3 = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (literal3 == null) { break; } literal4 = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (literal4 == null) { break; } return literal3.BitAnd(literal4); case CodeBinaryOperatorType.LessThan: literal = Literal.MakeLiteral(lhsType, lhsValue); if (literal == null) { break; } literal2 = Literal.MakeLiteral(rhsType, rhsValue); if (literal2 == null) { break; } return literal.LessThan(literal2); case CodeBinaryOperatorType.LessThanOrEqual: literal = Literal.MakeLiteral(lhsType, lhsValue); if (literal == null) { break; } literal2 = Literal.MakeLiteral(rhsType, rhsValue); if (literal2 == null) { break; } return literal.LessThanOrEqual(literal2); case CodeBinaryOperatorType.GreaterThan: literal = Literal.MakeLiteral(lhsType, lhsValue); if (literal == null) { break; } literal2 = Literal.MakeLiteral(rhsType, rhsValue); if (literal2 == null) { break; } return literal.GreaterThan(literal2); case CodeBinaryOperatorType.GreaterThanOrEqual: literal = Literal.MakeLiteral(lhsType, lhsValue); if (literal == null) { break; } literal2 = Literal.MakeLiteral(rhsType, rhsValue); if (literal2 == null) { break; } return literal.GreaterThanOrEqual(literal2); default: exception = new RuleEvaluationException(string.Format(CultureInfo.CurrentCulture, Messages.BinaryOpNotSupported, new object[] { operation.ToString() })); exception.Data["ErrorObject"] = binaryExpr; throw exception; } exception = new RuleEvaluationException(string.Format(CultureInfo.CurrentCulture, Messages.BinaryOpFails, new object[] { operation.ToString(), RuleDecompiler.DecompileType(lhsType), RuleDecompiler.DecompileType(rhsType) })); exception.Data["ErrorObject"] = binaryExpr; throw exception; }
private NodeType Translate(CodeBinaryOperatorType oper){ switch(oper){ case CodeBinaryOperatorType.Add : return NodeType.Add; case CodeBinaryOperatorType.BitwiseAnd : return NodeType.And; case CodeBinaryOperatorType.BitwiseOr : return NodeType.Or; case CodeBinaryOperatorType.BooleanAnd : return NodeType.LogicalAnd; case CodeBinaryOperatorType.BooleanOr : return NodeType.LogicalOr; case CodeBinaryOperatorType.Divide : return NodeType.Div; case CodeBinaryOperatorType.GreaterThan : return NodeType.Gt; case CodeBinaryOperatorType.GreaterThanOrEqual : return NodeType.Ge; case CodeBinaryOperatorType.IdentityEquality: return NodeType.Eq; case CodeBinaryOperatorType.IdentityInequality: return NodeType.Ne; case CodeBinaryOperatorType.LessThan : return NodeType.Lt; case CodeBinaryOperatorType.LessThanOrEqual : return NodeType.Le; case CodeBinaryOperatorType.Modulus : return NodeType.Rem; case CodeBinaryOperatorType.Multiply : return NodeType.Mul; case CodeBinaryOperatorType.Subtract : return NodeType.Sub; case CodeBinaryOperatorType.ValueEquality : return NodeType.Eq; } Debug.Assert(false); this.HandleError(Error.DidNotExpect, "CodeBinaryOperatorType value == "+oper.ToString()); return NodeType.Nop; }
internal static RuleBinaryExpressionInfo ResultType( CodeBinaryOperatorType operation, Type lhs, CodeExpression lhsExpression, Type rhs, CodeExpression rhsExpression, RuleValidation validator, out ValidationError error) { // do we support the types natively? TypeFlags lhsType, rhsType; if (supportedTypes.TryGetValue(lhs, out lhsType) && supportedTypes.TryGetValue(rhs, out rhsType)) { Type resultType = ResultType(operation, lhsType, rhsType); if (resultType != null) { error = null; return new RuleBinaryExpressionInfo(lhs, rhs, resultType); } else { string message = string.Format(CultureInfo.CurrentCulture, Messages.ArithOpBadTypes, operation.ToString(), (lhs == typeof(NullLiteral)) ? Messages.NullValue : RuleDecompiler.DecompileType(lhs), (rhs == typeof(NullLiteral)) ? Messages.NullValue : RuleDecompiler.DecompileType(rhs)); error = new ValidationError(message, ErrorNumbers.Error_OperandTypesIncompatible); return null; } } else { // not natively supported, see if user overrides operator MethodInfo opOverload = Literal.MapOperatorToMethod(operation, lhs, lhsExpression, rhs, rhsExpression, validator, out error); if (opOverload != null) return new RuleBinaryExpressionInfo(lhs, rhs, opOverload); else return null; } }
internal static RuleBinaryExpressionInfo AllowedComparison(Type lhs, CodeExpression lhsExpression, Type rhs, CodeExpression rhsExpression, CodeBinaryOperatorType comparison, RuleValidation validator, out ValidationError error) { TypeFlags flags; TypeFlags flags2; if (!supportedTypes.TryGetValue(lhs, out flags) || !supportedTypes.TryGetValue(rhs, out flags2)) { MethodInfo mi = MapOperatorToMethod(comparison, lhs, lhsExpression, rhs, rhsExpression, validator, out error); if (mi != null) { return new RuleBinaryExpressionInfo(lhs, rhs, mi); } return null; } if (flags == flags2) { if ((flags == TypeFlags.Bool) && (comparison != CodeBinaryOperatorType.ValueEquality)) { string str = string.Format(CultureInfo.CurrentCulture, Messages.RelationalOpBadTypes, new object[] { comparison.ToString(), RuleDecompiler.DecompileType(lhs), RuleDecompiler.DecompileType(rhs) }); error = new ValidationError(str, 0x545); return null; } error = null; return new RuleBinaryExpressionInfo(lhs, rhs, typeof(bool)); } switch ((flags | flags2)) { case (TypeFlags.ULong | TypeFlags.UnsignedNumbers): case (TypeFlags.Float | TypeFlags.SignedNumbers): case (TypeFlags.Float | TypeFlags.UnsignedNumbers): case (TypeFlags.Float | TypeFlags.ULong): case (TypeFlags.UnsignedNumbers | TypeFlags.SignedNumbers): case (TypeFlags.Decimal | TypeFlags.SignedNumbers): case (TypeFlags.Decimal | TypeFlags.UnsignedNumbers): case (TypeFlags.Decimal | TypeFlags.ULong): error = null; return new RuleBinaryExpressionInfo(lhs, rhs, typeof(bool)); } string errorText = string.Format(CultureInfo.CurrentCulture, Messages.RelationalOpBadTypes, new object[] { comparison.ToString(), (lhs == typeof(NullLiteral)) ? Messages.NullValue : RuleDecompiler.DecompileType(lhs), (rhs == typeof(NullLiteral)) ? Messages.NullValue : RuleDecompiler.DecompileType(rhs) }); error = new ValidationError(errorText, 0x545); return null; }
internal static MethodInfo MapOperatorToMethod(CodeBinaryOperatorType op, Type lhs, CodeExpression lhsExpression, Type rhs, CodeExpression rhsExpression, RuleValidation validator, out ValidationError error) { string str; string str2; OperatorGrouping arithmetic; switch (op) { case CodeBinaryOperatorType.Add: str = "op_Addition"; arithmetic = OperatorGrouping.Arithmetic; break; case CodeBinaryOperatorType.Subtract: str = "op_Subtraction"; arithmetic = OperatorGrouping.Arithmetic; break; case CodeBinaryOperatorType.Multiply: str = "op_Multiply"; arithmetic = OperatorGrouping.Arithmetic; break; case CodeBinaryOperatorType.Divide: str = "op_Division"; arithmetic = OperatorGrouping.Arithmetic; break; case CodeBinaryOperatorType.Modulus: str = "op_Modulus"; arithmetic = OperatorGrouping.Arithmetic; break; case CodeBinaryOperatorType.ValueEquality: str = "op_Equality"; arithmetic = OperatorGrouping.Equality; break; case CodeBinaryOperatorType.BitwiseOr: str = "op_BitwiseOr"; arithmetic = OperatorGrouping.Arithmetic; break; case CodeBinaryOperatorType.BitwiseAnd: str = "op_BitwiseAnd"; arithmetic = OperatorGrouping.Arithmetic; break; case CodeBinaryOperatorType.LessThan: str = "op_LessThan"; arithmetic = OperatorGrouping.Relational; break; case CodeBinaryOperatorType.LessThanOrEqual: str = "op_LessThanOrEqual"; arithmetic = OperatorGrouping.Relational; break; case CodeBinaryOperatorType.GreaterThan: str = "op_GreaterThan"; arithmetic = OperatorGrouping.Relational; break; case CodeBinaryOperatorType.GreaterThanOrEqual: str = "op_GreaterThanOrEqual"; arithmetic = OperatorGrouping.Relational; break; default: str2 = string.Format(CultureInfo.CurrentCulture, Messages.BinaryOpNotSupported, new object[] { op.ToString() }); error = new ValidationError(str2, 0x548); return null; } List<MethodInfo> candidates = new List<MethodInfo>(); bool flag = ConditionHelper.IsNullableValueType(lhs); bool flag2 = ConditionHelper.IsNullableValueType(rhs); Type rhsType = flag ? Nullable.GetUnderlyingType(lhs) : lhs; Type type = flag2 ? Nullable.GetUnderlyingType(rhs) : rhs; if (!rhsType.IsEnum) { if (type.IsEnum) { Type underlyingType; switch (op) { case CodeBinaryOperatorType.Add: underlyingType = EnumHelper.GetUnderlyingType(type); if ((underlyingType == null) || !RuleValidation.TypesAreAssignable(rhsType, underlyingType, lhsExpression, out error)) { break; } error = null; return new EnumOperationMethodInfo(lhs, op, rhs, false); case CodeBinaryOperatorType.Subtract: { underlyingType = EnumHelper.GetUnderlyingType(type); if (underlyingType == null) { break; } CodePrimitiveExpression expression = lhsExpression as CodePrimitiveExpression; if (!DecimalIntegerLiteralZero(lhs, expression)) { if (!RuleValidation.TypesAreAssignable(rhsType, underlyingType, lhsExpression, out error)) { break; } error = null; return new EnumOperationMethodInfo(lhs, op, rhs, false); } error = null; return new EnumOperationMethodInfo(lhs, op, rhs, true); } case CodeBinaryOperatorType.ValueEquality: case CodeBinaryOperatorType.LessThan: case CodeBinaryOperatorType.LessThanOrEqual: case CodeBinaryOperatorType.GreaterThan: case CodeBinaryOperatorType.GreaterThanOrEqual: if (!flag2 || !(lhs == typeof(NullLiteral))) { if (DecimalIntegerLiteralZero(lhs, lhsExpression as CodePrimitiveExpression)) { error = null; return new EnumOperationMethodInfo(lhs, op, rhs, true); } break; } error = null; return new EnumOperationMethodInfo(rhs, op, rhs, false); } } } else { Type type3; switch (op) { case CodeBinaryOperatorType.Add: type3 = EnumHelper.GetUnderlyingType(rhsType); if ((type3 == null) || !RuleValidation.TypesAreAssignable(type, type3, rhsExpression, out error)) { break; } error = null; return new EnumOperationMethodInfo(lhs, op, rhs, false); case CodeBinaryOperatorType.Subtract: type3 = EnumHelper.GetUnderlyingType(rhsType); if (type3 == null) { break; } if (!(rhsType == type)) { if (DecimalIntegerLiteralZero(rhs, rhsExpression as CodePrimitiveExpression)) { error = null; return new EnumOperationMethodInfo(lhs, op, rhs, true); } if (!RuleValidation.TypesAreAssignable(type, type3, rhsExpression, out error)) { break; } error = null; return new EnumOperationMethodInfo(lhs, op, rhs, false); } error = null; return new EnumOperationMethodInfo(lhs, op, rhs, false); case CodeBinaryOperatorType.ValueEquality: case CodeBinaryOperatorType.LessThan: case CodeBinaryOperatorType.LessThanOrEqual: case CodeBinaryOperatorType.GreaterThan: case CodeBinaryOperatorType.GreaterThanOrEqual: if (!(rhsType == type)) { if (flag && (rhs == typeof(NullLiteral))) { error = null; return new EnumOperationMethodInfo(lhs, op, lhs, false); } if (!DecimalIntegerLiteralZero(rhs, rhsExpression as CodePrimitiveExpression)) { break; } error = null; return new EnumOperationMethodInfo(lhs, op, rhs, true); } error = null; return new EnumOperationMethodInfo(lhs, op, rhs, false); } } AddOperatorOverloads(rhsType, str, lhs, rhs, candidates); AddOperatorOverloads(type, str, lhs, rhs, candidates); if ((flag || flag2) || ((lhs == typeof(NullLiteral)) || (rhs == typeof(NullLiteral)))) { AddLiftedOperators(rhsType, str, arithmetic, rhsType, type, candidates); AddLiftedOperators(type, str, arithmetic, rhsType, type, candidates); } if (candidates.Count == 0) { str = str.Substring(3); foreach (MethodInfo info in typeof(DefaultOperators).GetMethods()) { if (info.Name == str) { ParameterInfo[] parameters = info.GetParameters(); Type parameterType = parameters[0].ParameterType; Type toType = parameters[1].ParameterType; if (RuleValidation.ImplicitConversion(lhs, parameterType) && RuleValidation.ImplicitConversion(rhs, toType)) { candidates.Add(info); } } } if ((((candidates.Count == 0) && ("Equality" == str)) && (!lhs.IsValueType && !rhs.IsValueType)) && (((lhs == typeof(NullLiteral)) || (rhs == typeof(NullLiteral))) || (lhs.IsAssignableFrom(rhs) || rhs.IsAssignableFrom(lhs)))) { candidates.Add(ObjectEquality); } if ((candidates.Count == 0) && ((flag || flag2) || ((lhs == typeof(NullLiteral)) || (rhs == typeof(NullLiteral))))) { foreach (MethodInfo info2 in typeof(DefaultOperators).GetMethods()) { if (info2.Name == str) { ParameterInfo[] infoArray2 = info2.GetParameters(); MethodInfo item = EvaluateLiftedMethod(info2, infoArray2, arithmetic, rhsType, type); if (item != null) { candidates.Add(item); } } } } } if (candidates.Count == 1) { error = null; return candidates[0]; } if (candidates.Count == 0) { str2 = string.Format(CultureInfo.CurrentCulture, (arithmetic == OperatorGrouping.Arithmetic) ? Messages.ArithOpBadTypes : Messages.RelationalOpBadTypes, new object[] { op.ToString(), (lhs == typeof(NullLiteral)) ? Messages.NullValue : RuleDecompiler.DecompileType(lhs), (rhs == typeof(NullLiteral)) ? Messages.NullValue : RuleDecompiler.DecompileType(rhs) }); error = new ValidationError(str2, 0x545); return null; } MethodInfo info4 = validator.FindBestCandidate(null, candidates, new Type[] { lhs, rhs }); if (info4 != null) { error = null; return info4; } str2 = string.Format(CultureInfo.CurrentCulture, Messages.AmbiguousOperator, new object[] { op.ToString(), RuleDecompiler.DecompileMethod(candidates[0]), RuleDecompiler.DecompileMethod(candidates[1]) }); error = new ValidationError(str2, 0x545); return null; }
private static object EvaluateBinaryOperation(CodeBinaryOperatorExpression binaryExpr, Type lhsType, object lhsValue, CodeBinaryOperatorType operation, Type rhsType, object rhsValue) { Literal leftLiteral; Literal rightLiteral; ArithmeticLiteral leftArithmetic; ArithmeticLiteral rightArithmetic; string message; RuleEvaluationException exception; switch (operation) { case CodeBinaryOperatorType.Add: leftArithmetic = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (leftArithmetic == null) break; rightArithmetic = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (rightArithmetic == null) break; return leftArithmetic.Add(rightArithmetic); case CodeBinaryOperatorType.Subtract: leftArithmetic = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (leftArithmetic == null) break; rightArithmetic = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (rightArithmetic == null) break; return leftArithmetic.Subtract(rightArithmetic); case CodeBinaryOperatorType.Multiply: leftArithmetic = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (leftArithmetic == null) break; rightArithmetic = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (rightArithmetic == null) break; return leftArithmetic.Multiply(rightArithmetic); case CodeBinaryOperatorType.Divide: leftArithmetic = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (leftArithmetic == null) break; rightArithmetic = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (rightArithmetic == null) break; return leftArithmetic.Divide(rightArithmetic); case CodeBinaryOperatorType.Modulus: leftArithmetic = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (leftArithmetic == null) break; rightArithmetic = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (rightArithmetic == null) break; return leftArithmetic.Modulus(rightArithmetic); case CodeBinaryOperatorType.BitwiseAnd: leftArithmetic = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (leftArithmetic == null) break; rightArithmetic = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (rightArithmetic == null) break; return leftArithmetic.BitAnd(rightArithmetic); case CodeBinaryOperatorType.BitwiseOr: leftArithmetic = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); if (leftArithmetic == null) break; rightArithmetic = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); if (rightArithmetic == null) break; return leftArithmetic.BitOr(rightArithmetic); case CodeBinaryOperatorType.ValueEquality: leftLiteral = Literal.MakeLiteral(lhsType, lhsValue); if (leftLiteral == null) break; rightLiteral = Literal.MakeLiteral(rhsType, rhsValue); if (rightLiteral == null) break; return leftLiteral.Equal(rightLiteral); case CodeBinaryOperatorType.IdentityEquality: return lhsValue == rhsValue; case CodeBinaryOperatorType.IdentityInequality: return lhsValue != rhsValue; case CodeBinaryOperatorType.LessThan: leftLiteral = Literal.MakeLiteral(lhsType, lhsValue); if (leftLiteral == null) break; rightLiteral = Literal.MakeLiteral(rhsType, rhsValue); if (rightLiteral == null) break; return leftLiteral.LessThan(rightLiteral); case CodeBinaryOperatorType.LessThanOrEqual: leftLiteral = Literal.MakeLiteral(lhsType, lhsValue); if (leftLiteral == null) break; rightLiteral = Literal.MakeLiteral(rhsType, rhsValue); if (rightLiteral == null) break; return leftLiteral.LessThanOrEqual(rightLiteral); case CodeBinaryOperatorType.GreaterThan: leftLiteral = Literal.MakeLiteral(lhsType, lhsValue); if (leftLiteral == null) break; rightLiteral = Literal.MakeLiteral(rhsType, rhsValue); if (rightLiteral == null) break; return leftLiteral.GreaterThan(rightLiteral); case CodeBinaryOperatorType.GreaterThanOrEqual: leftLiteral = Literal.MakeLiteral(lhsType, lhsValue); if (leftLiteral == null) break; rightLiteral = Literal.MakeLiteral(rhsType, rhsValue); if (rightLiteral == null) break; return leftLiteral.GreaterThanOrEqual(rightLiteral); default: // should never happen // BooleanAnd & BooleanOr short-circuited before call // Assign disallowed at validation time message = string.Format(CultureInfo.CurrentCulture, Messages.BinaryOpNotSupported, operation.ToString()); exception = new RuleEvaluationException(message); exception.Data[RuleUserDataKeys.ErrorObject] = binaryExpr; throw exception; } message = string.Format(CultureInfo.CurrentCulture, Messages.BinaryOpFails, operation.ToString(), RuleDecompiler.DecompileType(lhsType), RuleDecompiler.DecompileType(rhsType)); exception = new RuleEvaluationException(message); exception.Data[RuleUserDataKeys.ErrorObject] = binaryExpr; throw exception; }