private static void EmitNumericConversion(ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) { if ( !(typeFrom.IsEnum || TypeUtil.IsNumeric(typeFrom)) || !(typeTo.IsEnum || TypeUtil.IsNumeric(typeTo)) ) { throw new InvalidOperationException("Unhandled convert"); } bool isFromUnsigned = TypeUtil.IsUnsigned(typeFrom); bool isFromFloatingPoint = TypeUtil.IsFloatingPoint(typeFrom); if (typeTo == typeof(Single)) { if (isFromUnsigned) { il.Emit(OpCodes.Conv_R_Un); } il.Emit(OpCodes.Conv_R4); } else if (typeTo == typeof(Double)) { if (isFromUnsigned) { il.Emit(OpCodes.Conv_R_Un); } il.Emit(OpCodes.Conv_R8); } else { TypeCode tc = Type.GetTypeCode(typeTo); if (isChecked) { // Overflow checking needs to know if the source value on the IL stack is unsigned or not. if (isFromUnsigned) { switch (tc) { case TypeCode.SByte: il.Emit(OpCodes.Conv_Ovf_I1_Un); break; case TypeCode.Int16: il.Emit(OpCodes.Conv_Ovf_I2_Un); break; case TypeCode.Int32: il.Emit(OpCodes.Conv_Ovf_I4_Un); break; case TypeCode.Int64: il.Emit(OpCodes.Conv_Ovf_I8_Un); break; case TypeCode.Byte: il.Emit(OpCodes.Conv_Ovf_U1_Un); break; case TypeCode.UInt16: case TypeCode.Char: il.Emit(OpCodes.Conv_Ovf_U2_Un); break; case TypeCode.UInt32: il.Emit(OpCodes.Conv_Ovf_U4_Un); break; case TypeCode.UInt64: il.Emit(OpCodes.Conv_Ovf_U8_Un); break; default: throw new InvalidOperationException("Unhandled convert"); } } else { switch (tc) { case TypeCode.SByte: il.Emit(OpCodes.Conv_Ovf_I1); break; case TypeCode.Int16: il.Emit(OpCodes.Conv_Ovf_I2); break; case TypeCode.Int32: il.Emit(OpCodes.Conv_Ovf_I4); break; case TypeCode.Int64: il.Emit(OpCodes.Conv_Ovf_I8); break; case TypeCode.Byte: il.Emit(OpCodes.Conv_Ovf_U1); break; case TypeCode.UInt16: case TypeCode.Char: il.Emit(OpCodes.Conv_Ovf_U2); break; case TypeCode.UInt32: il.Emit(OpCodes.Conv_Ovf_U4); break; case TypeCode.UInt64: il.Emit(OpCodes.Conv_Ovf_U8); break; default: throw new InvalidOperationException("Unhandled convert"); } } } else { switch (tc) { case TypeCode.SByte: il.Emit(OpCodes.Conv_I1); break; case TypeCode.Byte: il.Emit(OpCodes.Conv_U1); break; case TypeCode.Int16: il.Emit(OpCodes.Conv_I2); break; case TypeCode.UInt16: case TypeCode.Char: il.Emit(OpCodes.Conv_U2); break; case TypeCode.Int32: il.Emit(OpCodes.Conv_I4); break; case TypeCode.UInt32: il.Emit(OpCodes.Conv_U4); break; case TypeCode.Int64: if (isFromUnsigned) { il.Emit(OpCodes.Conv_U8); } else { il.Emit(OpCodes.Conv_I8); } break; case TypeCode.UInt64: if (isFromUnsigned || isFromFloatingPoint) { il.Emit(OpCodes.Conv_U8); } else { il.Emit(OpCodes.Conv_I8); } break; default: throw new InvalidOperationException("Unhandled convert"); } } } }
public void MethodCall(MethodCall methodCall) { bool isStatic = methodCall.Operand is TypeAccess; if (!isStatic) { bool emitBox = false; bool emitStoreLoad = false; if ( (methodCall.Operand is FieldAccess || methodCall.Operand is Constant) && methodCall.Operand.Type.IsValueType && !methodCall.MethodInfo.DeclaringType.IsValueType ) { emitBox = true; } else if ( methodCall.Operand.Type.IsValueType && ( !(methodCall.Operand is FieldAccess) || methodCall.MethodInfo.DeclaringType.IsValueType ) ) { emitStoreLoad = true; } // Signal field access that we're using the field as a // parameter. _fieldAsParameter = methodCall.Operand is FieldAccess && methodCall.MethodInfo.DeclaringType.IsValueType && !emitStoreLoad; try { methodCall.Operand.Accept(this); } finally { _fieldAsParameter = false; } if (emitBox) { _il.Emit(OpCodes.Box, methodCall.Operand.Type); } else if (emitStoreLoad) { Debug.Assert(methodCall.Operand.Type == methodCall.MethodInfo.DeclaringType); var builder = _il.DeclareLocal(methodCall.Operand.Type); _il.Emit(OpCodes.Stloc, builder); _il.Emit(OpCodes.Ldloca, builder); } } var parameters = methodCall.MethodInfo.GetParameters(); var arguments = methodCall.Arguments; bool paramsMethod = parameters.Length > 0 && parameters[parameters.Length - 1].GetCustomAttributes(typeof(ParamArrayAttribute), true).Length == 1; int mandatoryParameterCount = paramsMethod ? parameters.Length - 1 : parameters.Length; for (int i = 0; i < mandatoryParameterCount; i++) { Emit(arguments[i], parameters[i].ParameterType); } if (paramsMethod) { var paramsType = parameters[parameters.Length - 1].ParameterType; var elementType = paramsType.GetElementType(); bool emitted = false; // When the params argument is missing, a new array is issued. if (arguments.Count == mandatoryParameterCount) { ILUtil.EmitEmptyArray(_il, elementType); emitted = true; } else if (arguments.Count == mandatoryParameterCount + 1) { var lastArgument = arguments[arguments.Count - 1]; // Null arguments are passed blindly. if (lastArgument is Constant constant && constant.Value == null) { ILUtil.EmitNull(_il); emitted = true; } else { // So are array arguments that can be casted. if ( lastArgument.Type.IsArray && TypeUtil.CanCastImplicitely(lastArgument.Type, paramsType, false) ) { Emit(lastArgument, paramsType); emitted = true; } } } // If we didn't find a shortcut, emit the array with all // arguments. if (!emitted) { ILUtil.EmitArray( _il, elementType, arguments.Count - mandatoryParameterCount, p => Emit(arguments[mandatoryParameterCount + p], elementType) ); } }
public override IExpression Cast(Cast cast) { if (cast.CastType == CastType.Convert) { var constant = cast.Operand as Constant; if (TypeUtil.CanCastImplicitely( cast.Operand.Type, cast.Type, constant != null && constant.Value == null )) { return(new Cast(cast.Operand, cast.Type)); } string methodName = null; switch (Type.GetTypeCode(cast.Type)) { case TypeCode.Boolean: methodName = "ToBoolean"; break; case TypeCode.Byte: methodName = "ToByte"; break; case TypeCode.Char: methodName = "ToChar"; break; case TypeCode.DateTime: methodName = "ToDate"; break; case TypeCode.Decimal: methodName = "ToDecimal"; break; case TypeCode.Double: methodName = "ToDouble"; break; case TypeCode.Int32: methodName = "ToInteger"; break; case TypeCode.Int64: methodName = "ToLong"; break; case TypeCode.SByte: methodName = "ToSByte"; break; case TypeCode.Int16: methodName = "ToShort"; break; case TypeCode.Single: methodName = "ToSingle"; break; case TypeCode.String: methodName = "ToString"; break; case TypeCode.UInt32: methodName = "ToUInteger"; break; case TypeCode.UInt64: methodName = "ToULong"; break; case TypeCode.UInt16: methodName = "ToUShort"; break; } if (methodName != null) { var method = _resolver.FindOperatorMethod( methodName, Array.Empty <Type>(), null, new[] { cast.Operand.Type } ); Debug.Assert(method != null && method.ReturnType == cast.Type); return(new MethodCall( new TypeAccess(method.DeclaringType), method, new[] { cast.Operand } )); } else { return(new Cast(cast.Operand, cast.Type)); } } return(base.Cast(cast)); }
public override IExpression BinaryExpression(BinaryExpression binaryExpression) { var left = binaryExpression.Left.Accept(this); var right = binaryExpression.Right.Accept(this); if ( ( binaryExpression.ExpressionType == ExpressionType.Add && (left.Type == typeof(string) || right.Type == typeof(string)) ) || binaryExpression.ExpressionType == ExpressionType.Concat ) { return(_resolver.ResolveMethod( new TypeAccess(typeof(string)), "Concat", FlattenConcatArguments(binaryExpression.Left, binaryExpression.Right) )); } else if (binaryExpression.ExpressionType == ExpressionType.Power) { return(_resolver.ResolveMethod( new TypeAccess(typeof(Math)), "Pow", new[] { left, right } )); } else if (_resolver.DynamicExpression.Language == ExpressionLanguage.VisualBasic) { // Special handling for Visual Basic. string methodName = null; switch (binaryExpression.ExpressionType) { case ExpressionType.Compares: methodName = "CompareObjectEqual"; break; case ExpressionType.NotCompares: methodName = "CompareObjectNotEqual"; break; case ExpressionType.Greater: methodName = "CompareObjectGreater"; break; case ExpressionType.GreaterOrEquals: methodName = "CompareObjectGreaterEqual"; break; case ExpressionType.Less: methodName = "CompareObjectLess"; break; case ExpressionType.LessOrEquals: methodName = "CompareObjectLessEqual"; break; } // Is this an operator for which we have a method? if (methodName != null) { // Should we output a normal comparison anyway? if (TypeUtil.IsConvertible(left.Type) && TypeUtil.IsConvertible(right.Type)) { var expressionType = binaryExpression.ExpressionType; // Coerce Compares/NotCompares to Equals/NotEquals. if (expressionType == ExpressionType.Compares) { expressionType = ExpressionType.Equals; } else if (expressionType == ExpressionType.NotCompares) { expressionType = ExpressionType.NotEquals; } if ( left == binaryExpression.Left && right == binaryExpression.Right && expressionType == binaryExpression.ExpressionType ) { return(binaryExpression); } else { return(new BinaryExpression(left, right, expressionType, binaryExpression.Type, binaryExpression.CommonType)); } } else { var method = typeof(Operators).GetMethod(methodName); Debug.Assert(method.ReturnType == typeof(object)); return(new Cast( new MethodCall( new TypeAccess(typeof(Operators)), method, new[] { left, right, new Constant(false) } ), typeof(bool) )); } } } if (left == binaryExpression.Left && right == binaryExpression.Right) { return(binaryExpression); } else { return(new BinaryExpression(left, right, binaryExpression.ExpressionType, binaryExpression.Type)); } }
private void BinaryArithicExpression(BinaryExpression binaryExpression) { // Reference compares. if ( !binaryExpression.Left.Type.IsValueType && !binaryExpression.Right.Type.IsValueType && ( binaryExpression.ExpressionType == ExpressionType.Equals || binaryExpression.ExpressionType == ExpressionType.NotEquals ) ) { binaryExpression.Left.Accept(this); binaryExpression.Right.Accept(this); _il.Emit(OpCodes.Ceq); if (binaryExpression.ExpressionType == ExpressionType.NotEquals) { _il.Emit(OpCodes.Ldc_I4_0); _il.Emit(OpCodes.Ceq); } return; } Emit(binaryExpression.Left, binaryExpression.CommonType); Emit(binaryExpression.Right, binaryExpression.CommonType); switch (binaryExpression.ExpressionType) { case ExpressionType.Equals: case ExpressionType.NotEquals: _il.Emit(OpCodes.Ceq); if (binaryExpression.ExpressionType == ExpressionType.NotEquals) { _il.Emit(OpCodes.Ldc_I4_0); _il.Emit(OpCodes.Ceq); } break; case ExpressionType.Greater: case ExpressionType.LessOrEquals: if (TypeUtil.IsUnsigned(binaryExpression.CommonType)) { _il.Emit(OpCodes.Cgt_Un); } else { _il.Emit(OpCodes.Cgt); } if (binaryExpression.ExpressionType == ExpressionType.LessOrEquals) { _il.Emit(OpCodes.Ldc_I4_0); _il.Emit(OpCodes.Ceq); } break; case ExpressionType.Less: case ExpressionType.GreaterOrEquals: if (TypeUtil.IsUnsigned(binaryExpression.CommonType)) { _il.Emit(OpCodes.Clt_Un); } else { _il.Emit(OpCodes.Clt); } if (binaryExpression.ExpressionType == ExpressionType.GreaterOrEquals) { _il.Emit(OpCodes.Ldc_I4_0); _il.Emit(OpCodes.Ceq); } break; case ExpressionType.Add: if (_compiler._resolver.Options.Checked && TypeUtil.IsInteger(binaryExpression.CommonType)) { if (TypeUtil.IsUnsigned(binaryExpression.CommonType)) { _il.Emit(OpCodes.Add_Ovf_Un); } else { _il.Emit(OpCodes.Add_Ovf); } } else { _il.Emit(OpCodes.Add); } break; case ExpressionType.Divide: if (TypeUtil.IsUnsigned(binaryExpression.CommonType)) { _il.Emit(OpCodes.Div_Un); } else { _il.Emit(OpCodes.Div); } break; case ExpressionType.Multiply: if (_compiler._resolver.Options.Checked && TypeUtil.IsInteger(binaryExpression.CommonType)) { if (TypeUtil.IsUnsigned(binaryExpression.CommonType)) { _il.Emit(OpCodes.Mul_Ovf_Un); } else { _il.Emit(OpCodes.Mul_Ovf); } } else { _il.Emit(OpCodes.Mul); } break; case ExpressionType.Subtract: if (_compiler._resolver.Options.Checked && TypeUtil.IsInteger(binaryExpression.CommonType)) { if (TypeUtil.IsUnsigned(binaryExpression.CommonType)) { _il.Emit(OpCodes.Sub_Ovf_Un); } else { _il.Emit(OpCodes.Sub_Ovf); } } else { _il.Emit(OpCodes.Sub); } break; case ExpressionType.Modulo: if (TypeUtil.IsUnsigned(binaryExpression.CommonType)) { _il.Emit(OpCodes.Rem_Un); } else { _il.Emit(OpCodes.Rem); } break; default: throw new InvalidOperationException(); } }
private bool IsAllowableImplicit(Type a, Type b) { return(TypeUtil.IsInteger(a) == TypeUtil.IsInteger(b)); }
private Type ResolveExpressionType(Type left, Type right, Type commonType, ExpressionType type) { Require.NotNull(left, "left"); Require.NotNull(right, "right"); // TODO: Implicit/explicit operators and operators for the expression type. // Boolean operators. switch (type) { case ExpressionType.And: case ExpressionType.Or: case ExpressionType.Xor: case ExpressionType.AndBoth: case ExpressionType.OrBoth: if (TypeUtil.IsInteger(commonType)) { return(commonType); } else if (left != typeof(bool) || right != typeof(bool)) { throw new ExpressionsException("Invalid operand for expression type", ExpressionsExceptionType.TypeMismatch); } return(typeof(bool)); case ExpressionType.Greater: case ExpressionType.GreaterOrEquals: case ExpressionType.Less: case ExpressionType.LessOrEquals: if ( !(left.IsEnum || TypeUtil.IsNumeric(left)) || !(right.IsEnum || TypeUtil.IsNumeric(right)) ) { throw new ExpressionsException("Invalid operand for expression type", ExpressionsExceptionType.TypeMismatch); } return(typeof(bool)); case ExpressionType.Equals: case ExpressionType.NotEquals: case ExpressionType.In: case ExpressionType.LogicalAnd: case ExpressionType.LogicalOr: case ExpressionType.Compares: case ExpressionType.NotCompares: return(typeof(bool)); case ExpressionType.Add: if ( !(left == typeof(string) || right == typeof(string)) && !(TypeUtil.IsNumeric(left) && TypeUtil.IsNumeric(right)) ) { throw new ExpressionsException("Invalid operand for expression type", ExpressionsExceptionType.TypeMismatch); } return(commonType); case ExpressionType.Subtract: case ExpressionType.Multiply: case ExpressionType.Divide: case ExpressionType.Power: if (!TypeUtil.IsNumeric(left) || !TypeUtil.IsNumeric(right)) { throw new ExpressionsException("Invalid operand for expression type", ExpressionsExceptionType.TypeMismatch); } return(commonType); default: return(commonType); } }
private Type ResolveExpressionCommonType(Type left, Type right, bool allowStringConcat, bool allowBothImplicit, bool allowObjectCoercion) { Require.NotNull(left, "left"); Require.NotNull(right, "right"); // No casting required. if (left == right) { return(left); } if (allowObjectCoercion) { if (left == typeof(object)) { return(right); } if (right == typeof(object)) { return(left); } } // Special cast for adding strings. if (allowStringConcat && (left == typeof(string) || right == typeof(string))) { return(typeof(string)); } // Can we cast implicitly? var leftTable = TypeUtil.GetImplicitCastingTable(left); var rightTable = TypeUtil.GetImplicitCastingTable(right); if (leftTable != null && rightTable != null) { // See whether one of the types appears in the other. foreach (var leftType in leftTable) { if (leftType == right) { return(leftType); } } foreach (var rightType in rightTable) { if (rightType == left) { return(rightType); } } // Otherwise, find the first common type. int lowest = int.MaxValue; for (int i = 0; i < leftTable.Count; i++) { for (int j = 0; j < rightTable.Count; j++) { if (leftTable[i] == rightTable[j]) { lowest = Math.Min(lowest, j); } } } if (lowest != int.MaxValue) { if ( allowBothImplicit || (IsAllowableImplicit(left, rightTable[lowest]) && IsAllowableImplicit(right, rightTable[lowest])) ) { return(rightTable[lowest]); } } } // We can't cast implicitly. throw new ExpressionsException("Cannot resolve expression type", ExpressionsExceptionType.TypeMismatch); }
public IExpression UnaryExpression(Ast.UnaryExpression unaryExpression) { var operand = unaryExpression.Operand.Accept(this); string operatorName = null; switch (unaryExpression.Type) { case ExpressionType.Plus: operatorName = "op_UnaryPlus"; break; case ExpressionType.Minus: operatorName = "op_UnaryNegation"; break; case ExpressionType.Not: case ExpressionType.LogicalNot: operatorName = "op_Negation"; break; } if (operatorName != null) { var method = _resolver.FindOperatorMethod( operatorName, new[] { operand.Type }, null, new[] { operand.Type } ); if (method != null) { return(new Expressions.MethodCall( new TypeAccess(method.DeclaringType), method, new[] { operand } )); } } Type type; switch (unaryExpression.Type) { case ExpressionType.Plus: if (!TypeUtil.IsValidUnaryArgument(operand.Type)) { throw new ExpressionsException("Operand of plus operation must be an integer type", ExpressionsExceptionType.TypeMismatch); } type = operand.Type; break; case ExpressionType.Group: type = operand.Type; break; case ExpressionType.Minus: if (!TypeUtil.IsValidUnaryArgument(operand.Type)) { throw new ExpressionsException("Operand of minus operation must be an integer type", ExpressionsExceptionType.TypeMismatch); } // TODO: Make constants signed and handle minus on unsigned's. type = operand.Type; break; case ExpressionType.LogicalNot: if (operand.Type != typeof(bool)) { throw new ExpressionsException("Operand of not operation must be a boolean type", ExpressionsExceptionType.TypeMismatch); } type = typeof(bool); break; case ExpressionType.BitwiseNot: if (!TypeUtil.IsInteger(operand.Type)) { throw new ExpressionsException( "Cannot not bitwise not boolean types", ExpressionsExceptionType.TypeMismatch ); } type = operand.Type; break; case ExpressionType.Not: if (TypeUtil.IsInteger(operand.Type)) { type = operand.Type; } else { if (operand.Type != typeof(bool)) { throw new ExpressionsException("Operand of not operation must be a boolean type", ExpressionsExceptionType.TypeMismatch); } type = typeof(bool); } break; default: throw new InvalidOperationException(); } return(new Expressions.UnaryExpression(operand, type, unaryExpression.Type)); }
public IExpression IdentifierAccess(IdentifierAccess identifierAccess) { // First try variables. var identifiers = _resolver.DynamicExpression.ParseResult.Identifiers; for (int i = 0; i < _resolver.IdentifierTypes.Length; i++) { if ( _resolver.IdentifierTypes[i] != null && _resolver.IdentifiersEqual(identifiers[i].Name, identifierAccess.Name) ) { return(VariableAccess(_resolver.IdentifierIndexes[i], _resolver.IdentifierTypes[i])); } } // Next, we go through the owner type. if (_resolver.OwnerType != null) { var result = Resolve(new VariableAccess(_resolver.OwnerType, 0), identifierAccess.Name); if (result == null) { result = Resolve(new TypeAccess(_resolver.OwnerType), identifierAccess.Name); } if (result != null) { return(result); } } // Next, imports. Namespaces have precedence. foreach (var import in _resolver.Imports) { if ( import.Namespace != null && _resolver.IdentifiersEqual(import.Namespace, identifierAccess.Name) ) { if (import.Type != null) { return(new TypeAccess(import.Type)); } else { return(new ImportAccess(import)); } } } // Next, members of the imports. foreach (var import in _resolver.Imports) { if (import.Namespace == null) { var result = Resolve(new TypeAccess(import.Type), identifierAccess.Name); if (result != null) { return(result); } } } // Last, see whether the identifier is a built in type. var type = TypeUtil.GetBuiltInType(identifierAccess.Name, _resolver.DynamicExpression.Language); if (type != null) { return(new TypeAccess(type)); } throw new ExpressionsException( String.Format("Unresolved identifier '{0}'", identifierAccess.Name), ExpressionsExceptionType.UndefinedName ); }
public IExpression BinaryExpression(Ast.BinaryExpression binaryExpression) { // In expressions are converted to method calls. if (binaryExpression.Type == ExpressionType.In) { return(BinaryInExpression(binaryExpression)); } // We need to do this here and not in the conversion phase because // we need the return type of the method to fully bind the tree. var left = binaryExpression.Left.Accept(this); var right = binaryExpression.Right.Accept(this); string operatorName = null; switch (binaryExpression.Type) { case ExpressionType.Add: operatorName = "op_Addition"; break; case ExpressionType.Divide: operatorName = "op_Division"; break; case ExpressionType.Multiply: operatorName = "op_Multiply"; break; case ExpressionType.Subtract: operatorName = "op_Subtraction"; break; case ExpressionType.Equals: operatorName = "op_Equality"; break; case ExpressionType.NotEquals: operatorName = "op_Inequality"; break; case ExpressionType.Greater: operatorName = "op_GreaterThan"; break; case ExpressionType.GreaterOrEquals: operatorName = "op_GreaterThanOrEqual"; break; case ExpressionType.Less: operatorName = "op_LessThan"; break; case ExpressionType.LessOrEquals: operatorName = "op_LessThanOrEqual"; break; case ExpressionType.ShiftLeft: operatorName = "op_LeftShift"; break; case ExpressionType.ShiftRight: operatorName = "op_RightShift"; break; case ExpressionType.Modulo: operatorName = "op_Modulus"; break; case ExpressionType.LogicalAnd: operatorName = "op_LogicalAnd"; break; case ExpressionType.AndBoth: operatorName = "op_LogicalAnd"; break; case ExpressionType.LogicalOr: operatorName = "op_LogicalOr"; break; case ExpressionType.OrBoth: operatorName = "op_LogicalOr"; break; case ExpressionType.BitwiseAnd: operatorName = "op_BitwiseAnd"; break; case ExpressionType.BitwiseOr: operatorName = "op_BitwiseOr"; break; case ExpressionType.And: if (left.Type == typeof(bool) && right.Type == typeof(bool)) { operatorName = "op_LogicalAnd"; } else { operatorName = "op_BitwiseAnd"; } break; case ExpressionType.Or: if (left.Type == typeof(bool) && right.Type == typeof(bool)) { operatorName = "op_LogicalOr"; } else { operatorName = "op_BitwiseOr"; } break; case ExpressionType.Xor: operatorName = "op_ExclusiveOr"; break; } if (operatorName != null) { var method = _resolver.FindOperatorMethod( operatorName, new[] { left.Type, right.Type }, null, new[] { left.Type, right.Type }, new[] { left is Expressions.Constant && ((Expressions.Constant)left).Value == null, right is Expressions.Constant && ((Expressions.Constant)right).Value == null } ); if (method != null) { return(new Expressions.MethodCall( new TypeAccess(typeof(string)), method, new[] { left, right } )); } } Type commonType; switch (binaryExpression.Type) { case ExpressionType.ShiftLeft: case ExpressionType.ShiftRight: if (!TypeUtil.IsInteger(left.Type)) { throw new ExpressionsException("Left operand of shift operations must be of an integer type", ExpressionsExceptionType.TypeMismatch); } if (right.Type != typeof(int) && right.Type != typeof(byte)) { throw new ExpressionsException("Right operand of shift operations must be integer or byte type", ExpressionsExceptionType.TypeMismatch); } commonType = left.Type; break; case ExpressionType.Power: commonType = typeof(double); break; case ExpressionType.Greater: case ExpressionType.GreaterOrEquals: case ExpressionType.Less: case ExpressionType.LessOrEquals: commonType = ResolveExpressionCommonType(left.Type, right.Type, false, true, false); break; case ExpressionType.Equals: case ExpressionType.NotEquals: case ExpressionType.Compares: case ExpressionType.NotCompares: if (left.Type.IsValueType != right.Type.IsValueType) { throw new ExpressionsException("Cannot resolve expression type", ExpressionsExceptionType.TypeMismatch); } commonType = ResolveExpressionCommonType(left.Type, right.Type, false, false, true); break; default: commonType = ResolveExpressionCommonType(left.Type, right.Type, binaryExpression.Type == ExpressionType.Add, false, false); break; } var type = ResolveExpressionType(left.Type, right.Type, commonType, binaryExpression.Type); var expressionType = binaryExpression.Type; if (type != typeof(bool)) { if (expressionType == ExpressionType.AndBoth) { expressionType = ExpressionType.BitwiseAnd; } else if (expressionType == ExpressionType.OrBoth) { expressionType = ExpressionType.BitwiseOr; } } return(new Expressions.BinaryExpression(left, right, expressionType, type, commonType)); }
internal MethodInfo FindOperatorMethod(string methodName, Type[] sourceTypes, Type returnType, Type[] parameterTypes, bool[] parametersNull) { var candidates = new List <MethodInfo>(); foreach (var sourceType in sourceTypes) { foreach (var method in sourceType.GetMethods(BindingFlags.Static | BindingFlags.Public)) { if (method.Name != methodName) { continue; } var parameters = method.GetParameters(); if (parameters.Length != parameterTypes.Length) { continue; } bool match = true; bool implicitMatch = true; if (returnType != null) { match = returnType == method.ReturnType; implicitMatch = TypeUtil.CanCastImplicitely( method.ReturnType, returnType, false ); } for (int i = 0; i < parameterTypes.Length; i++) { if (parameters[i].ParameterType != parameterTypes[i]) { match = false; } if (!TypeUtil.CanCastImplicitely( parameterTypes[i], parameters[i].ParameterType, parametersNull != null && parametersNull[i] )) { implicitMatch = false; } } if (match) { return(method); } if (implicitMatch) { candidates.Add(method); } } } return(candidates.Count == 1 ? candidates[0] : null); }