private void ExtendedConvertToType(Type fromType, Type toType, bool allowExplicit) { try { // See whether we can find a constructor on target type. var constructor = _resolver.ResolveMethodGroup( toType.GetConstructors(_resolver.Options.AccessBindingFlags | BindingFlags.CreateInstance), new[] { fromType }, new[] { false } ); if (constructor != null) { ILUtil.EmitNew(_il, (ConstructorInfo)constructor); return; } // See whether we have an implicit cast. var castMethod = _resolver.FindOperatorMethod( "op_Implicit", new[] { fromType, toType }, toType, new[] { fromType } ); if (castMethod == null && allowExplicit) { castMethod = _resolver.FindOperatorMethod( "op_Explicit", new[] { fromType, toType }, toType, new[] { fromType } ); } if (castMethod != null) { var parameterType = castMethod.GetParameters()[0].ParameterType; if (fromType != parameterType) { ILUtil.EmitConvertToType(_il, fromType, parameterType, _resolver.Options.Checked); } _il.Emit(OpCodes.Call, castMethod); if (toType != castMethod.ReturnType) { ILUtil.EmitConvertToType(_il, castMethod.ReturnType, toType, _resolver.Options.Checked); } return; } // Let ILUtill handle it. ILUtil.EmitConvertToType(_il, fromType, toType, _resolver.Options.Checked); } catch (Exception ex) { throw new ExpressionsException( "Invalid explicit cast", ExpressionsExceptionType.InvalidExplicitCast, ex ); } }
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 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)); }