static BinaryOperatorEasyOut() { const OperandType ERR = OperandType.Error; const OperandType OBJ = OperandType.Object; const OperandType INT = OperandType.Int; const OperandType UIN = OperandType.UInt; const OperandType LNG = OperandType.Long; const OperandType ULG = OperandType.ULong; const OperandType FLT = OperandType.Float; const OperandType DBL = OperandType.Double; const OperandType DEC = OperandType.Decimal; const OperandType BOL = OperandType.Bool; // Overload resolution for Y * / - % < > <= >= X OperandType[,] arithmetic = { // bool chr i08 i16 i32 i64 u08 u16 u32 u64 r32 r64 dec /* bool */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, /* chr */ { ERR, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, FLT, DBL, DEC }, /* i08 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, FLT, DBL, DEC }, /* i16 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, FLT, DBL, DEC }, /* i32 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, FLT, DBL, DEC }, /* i64 */ { ERR, LNG, LNG, LNG, LNG, LNG, LNG, LNG, LNG, ERR, FLT, DBL, DEC }, /* u08 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, FLT, DBL, DEC }, /* u16 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, FLT, DBL, DEC }, /* u32 */ { ERR, UIN, LNG, LNG, LNG, LNG, UIN, UIN, UIN, ULG, FLT, DBL, DEC }, /* u64 */ { ERR, ULG, ERR, ERR, ERR, ERR, ULG, ULG, ULG, ULG, FLT, DBL, DEC }, /* r32 */ { ERR, FLT, FLT, FLT, FLT, FLT, FLT, FLT, FLT, FLT, FLT, DBL, ERR }, /* r64 */ { ERR, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, ERR }, /* dec */ { ERR, DEC, DEC, DEC, DEC, DEC, DEC, DEC, DEC, DEC, ERR, ERR, DEC }, }; // Overload resolution for Y + X OperandType[,] addition = { // bool chr i08 i16 i32 i64 u08 u16 u32 u64 r32 r64 dec /* bool */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, /* chr */ { ERR, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, FLT, DBL, DEC }, /* i08 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, FLT, DBL, DEC }, /* i16 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, FLT, DBL, DEC }, /* i32 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, FLT, DBL, DEC }, /* i64 */ { ERR, LNG, LNG, LNG, LNG, LNG, LNG, LNG, LNG, ERR, FLT, DBL, DEC }, /* u08 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, FLT, DBL, DEC }, /* u16 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, FLT, DBL, DEC }, /* u32 */ { ERR, UIN, LNG, LNG, LNG, LNG, UIN, UIN, UIN, ULG, FLT, DBL, DEC }, /* u64 */ { ERR, ULG, ERR, ERR, ERR, ERR, ULG, ULG, ULG, ULG, FLT, DBL, DEC }, /* r32 */ { ERR, FLT, FLT, FLT, FLT, FLT, FLT, FLT, FLT, FLT, FLT, DBL, ERR }, /* r64 */ { ERR, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, ERR }, /* dec */ { ERR, DEC, DEC, DEC, DEC, DEC, DEC, DEC, DEC, DEC, ERR, ERR, DEC }, }; // Overload resolution for Y << >> X OperandType[,] shift = { // bool chr i08 i16 i32 i64 u08 u16 u32 u64 r32 r64 dec /* bool */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, /* chr */ { ERR, INT, INT, INT, INT, ERR, INT, INT, ERR, ERR, ERR, ERR, ERR }, /* i08 */ { ERR, INT, INT, INT, INT, ERR, INT, INT, ERR, ERR, ERR, ERR, ERR }, /* i16 */ { ERR, INT, INT, INT, INT, ERR, INT, INT, ERR, ERR, ERR, ERR, ERR }, /* i32 */ { ERR, INT, INT, INT, INT, ERR, INT, INT, ERR, ERR, ERR, ERR, ERR }, /* i64 */ { ERR, LNG, LNG, LNG, LNG, ERR, LNG, LNG, ERR, ERR, ERR, ERR, ERR }, /* u08 */ { ERR, INT, INT, INT, INT, ERR, INT, INT, ERR, ERR, ERR, ERR, ERR }, /* u16 */ { ERR, INT, INT, INT, INT, ERR, INT, INT, ERR, ERR, ERR, ERR, ERR }, /* u32 */ { ERR, UIN, UIN, UIN, UIN, ERR, UIN, UIN, ERR, ERR, ERR, ERR, ERR }, /* u64 */ { ERR, ULG, ULG, ULG, ULG, ERR, ULG, ULG, ERR, ERR, ERR, ERR, ERR }, /* r32 */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, /* r64 */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, /* dec */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, }; // Overload resolution for Y == != X // Note that these are the overload resolution rules; overload resolution might pick an invalid operator. // For example, overload resolution on object == decimal chooses the object/object overload, which then // is not legal because decimal must be a reference type. But we don't know to give that error *until* // overload resolution has chosen the reference equality operator. OperandType[,] equality = { // bool chr i08 i16 i32 i64 u08 u16 u32 u64 r32 r64 dec /* bool */ { BOL, OBJ, OBJ, OBJ, OBJ, OBJ, OBJ, OBJ, OBJ, OBJ, OBJ, OBJ, OBJ }, /* chr */ { OBJ, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, FLT, DBL, DEC }, /* i08 */ { OBJ, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, FLT, DBL, DEC }, /* i16 */ { OBJ, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, FLT, DBL, DEC }, /* i32 */ { OBJ, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, FLT, DBL, DEC }, /* i64 */ { OBJ, LNG, LNG, LNG, LNG, LNG, LNG, LNG, LNG, ERR, FLT, DBL, DEC }, /* u08 */ { OBJ, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, FLT, DBL, DEC }, /* u16 */ { OBJ, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, FLT, DBL, DEC }, /* u32 */ { OBJ, UIN, LNG, LNG, LNG, LNG, UIN, UIN, UIN, ULG, FLT, DBL, DEC }, /* u64 */ { OBJ, ULG, ERR, ERR, ERR, ERR, ULG, ULG, ULG, ULG, FLT, DBL, DEC }, /* r32 */ { OBJ, FLT, FLT, FLT, FLT, FLT, FLT, FLT, FLT, FLT, FLT, DBL, OBJ }, /* r64 */ { OBJ, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, OBJ }, /* dec */ { OBJ, DEC, DEC, DEC, DEC, DEC, DEC, DEC, DEC, DEC, OBJ, OBJ, DEC }, }; // Overload resolution for Y | & ^ || && X OperandType[,] logical = { // bool chr i08 i16 i32 i64 u08 u16 u32 u64 r32 r64 dec /* bool */ { BOL, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, /* chr */ { ERR, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, ERR, ERR, ERR }, /* i08 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, ERR, ERR, ERR }, /* i16 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, ERR, ERR, ERR }, /* i32 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, ERR, ERR, ERR }, /* i64 */ { ERR, LNG, LNG, LNG, LNG, LNG, LNG, LNG, LNG, ERR, ERR, ERR, ERR }, /* u08 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, ERR, ERR, ERR }, /* u16 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, ERR, ERR, ERR }, /* u32 */ { ERR, UIN, LNG, LNG, LNG, LNG, UIN, UIN, UIN, ULG, ERR, ERR, ERR }, /* u64 */ { ERR, ULG, ERR, ERR, ERR, ERR, ULG, ULG, ULG, ULG, ERR, ERR, ERR }, /* r32 */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, /* r64 */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, /* dec */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, }; var ops = (BinaryOperatorKind[])Enum.GetValues(typeof(BinaryOperatorKind)); s_binOp = new BinaryOperatorSymbol[ops.Length][, ]; s_binOp[(int)BinaryOperatorKind.Error] = new BinaryOperatorSymbol[28, 28]; for (int i = 0; i < 28; i++) { for (int j = 0; j < 28; j++) { s_binOp[(int)BinaryOperatorKind.Error][i, j] = BinaryOperatorSymbol.Create(BinaryOperatorKind.Error, OperandType.Error); } } for (int i = ((int)BinaryOperatorKind.Error) + 1; i < ops.Length; i++) { s_binOp[i] = s_binOp[(int)BinaryOperatorKind.Error]; } Func <BinaryOperatorKind, OperandType[, ], BinaryOperatorSymbol[, ]> expandTable = (k, x) => { var res = new BinaryOperatorSymbol[28, 28]; for (int i = 0; i < 13; i++) { for (int j = 0; j < 13; j++) { var t = x[i, j]; var nt = OperandTypeHelper.IsNullable(t + OperandTypeHelper.NullableDelta) ? t + OperandTypeHelper.NullableDelta : t; res[i + 2, j + 2] = BinaryOperatorSymbol.Create(k, t); res[i + 2 + 13, j + 2] = BinaryOperatorSymbol.Create(k, nt); res[i + 2, j + 2 + 13] = BinaryOperatorSymbol.Create(k, nt); res[i + 2 + 13, j + 2 + 13] = BinaryOperatorSymbol.Create(k, nt); } } bool eq = k == BinaryOperatorKind.Equal || k == BinaryOperatorKind.NotEqual || k == BinaryOperatorKind.ExactEqual; bool add = k == BinaryOperatorKind.Addition; var op_o = eq ? BinaryOperatorSymbol.Create(k, OperandType.Object) : BinaryOperatorSymbol.Create(BinaryOperatorKind.Error, OperandType.Error); var op_ss = (eq || add) ? BinaryOperatorSymbol.Create(k, OperandType.String) : op_o; var op_so = (eq || add) ? BinaryOperatorSymbol.Create(k, OperandType.StringAndObject) : op_o; var op_os = (eq || add) ? BinaryOperatorSymbol.Create(k, OperandType.ObjectAndString) : op_o; for (int i = 0; i < 28; i++) { if (i == 1) { // str res[1, 1] = op_ss; } else { // obj res[0, i] = op_o; res[i, 0] = op_o; // str res[1, i] = op_so; res[i, 1] = op_os; } } return(res); }; var tables = new[] { arithmetic, addition, shift, equality, logical }; Func <BinaryOperatorKind, int> tableIndex = k => { if (k == BinaryOperatorKind.Multiplication || k == BinaryOperatorKind.Subtraction || k == BinaryOperatorKind.Division || k == BinaryOperatorKind.Remainder || k == BinaryOperatorKind.Exponent) { return(0); } if (k == BinaryOperatorKind.Addition) { return(1); } if (k == BinaryOperatorKind.LeftShift || k == BinaryOperatorKind.RightShift) { return(2); } if (k == BinaryOperatorKind.Equal || k == BinaryOperatorKind.NotEqual || k == BinaryOperatorKind.ExactEqual) { return(3); } if (k == BinaryOperatorKind.GreaterThan || k == BinaryOperatorKind.LessThan || k == BinaryOperatorKind.GreaterThanOrEqual || k == BinaryOperatorKind.LessThanOrEqual || k == BinaryOperatorKind.And || k == BinaryOperatorKind.Xor || k == BinaryOperatorKind.Or) { return(4); } if (k == BinaryOperatorKind.Substr || k == BinaryOperatorKind.DefaultValue) { return(-1); } return(-1); }; for (int i = ((int)BinaryOperatorKind.Error) + 1; i < ops.Length; i++) { var k = (BinaryOperatorKind)i; var ti = tableIndex(k); if (ti >= 0) { s_binOp[i] = expandTable(k, tables[ti]); } } }
internal static BinaryOperatorSymbol UserDefinedBinaryOperator(BinaryOperatorKind kind, ref Expr left, ref Expr right, BindOptions options) { MethodSymbol mop = null; ConversionSymbol lconv = null; ConversionSymbol rconv = null; bool hasUsual = left.Datatype.NativeType == NativeType.Usual || right.Datatype.NativeType == NativeType.Usual; if (options.HasFlag(BindOptions.AllowInexactComparisons)) { bool hasString = left.Datatype.NativeType == NativeType.String || right.Datatype.NativeType == NativeType.String; bool bothStrings = left.Datatype.NativeType == NativeType.String && right.Datatype.NativeType == NativeType.String; switch (kind) { case BinaryOperatorKind.Equal: if (bothStrings) { ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.XSharp_RT_Functions___StringEquals), ref mop, ref lconv, ref rconv, options); } else if (hasString) { ResolveBinaryOperator(left, right, Compilation.Get(NativeType.Usual).Lookup(OperatorNames.__UsualInExactEquals), ref mop, ref lconv, ref rconv, options); } break; case BinaryOperatorKind.NotEqual: if (bothStrings) { ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.XSharp_RT_Functions___StringNotEquals), ref mop, ref lconv, ref rconv, options); } else if (hasString) { ResolveBinaryOperator(left, right, Compilation.Get(NativeType.Usual).Lookup(OperatorNames.__UsualInExactNotEquals), ref mop, ref lconv, ref rconv, options); } break; case BinaryOperatorKind.GreaterThan: case BinaryOperatorKind.LessThan: case BinaryOperatorKind.GreaterThanOrEqual: case BinaryOperatorKind.LessThanOrEqual: if (bothStrings) { ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.XSharp_RT_Functions___StringCompare), ref mop, ref lconv, ref rconv, options); } break; } } else { switch (kind) { case BinaryOperatorKind.Equal: case BinaryOperatorKind.NotEqual: case BinaryOperatorKind.GreaterThan: case BinaryOperatorKind.LessThan: case BinaryOperatorKind.GreaterThanOrEqual: case BinaryOperatorKind.LessThanOrEqual: if (left.Datatype.NativeType == NativeType.String && right.Datatype.NativeType == NativeType.String) { ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.System_String_CompareOrdinal), ref mop, ref lconv, ref rconv, options); } break; } } if (mop == null) { var name = BinaryOperatorSymbol.OperatorName(kind); if (name != null) { ResolveBinaryOperator(left, right, left.Datatype.Lookup(name), ref mop, ref lconv, ref rconv, options | BindOptions.Special); ResolveBinaryOperator(left, right, right.Datatype.Lookup(name), ref mop, ref lconv, ref rconv, options | BindOptions.Special); } } if (mop == null && kind == BinaryOperatorKind.Exponent) { ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.XSharp_RT_Functions_POW), ref mop, ref lconv, ref rconv, options); if (hasUsual) { ResolveBinaryOperator(left, right, left.Datatype.Lookup(OperatorNames.__UsualExponent), ref mop, ref lconv, ref rconv, options); ResolveBinaryOperator(left, right, right.Datatype.Lookup(OperatorNames.__UsualExponent), ref mop, ref lconv, ref rconv, options); } } if (mop != null) { var op = BinaryOperatorSymbol.Create(kind, mop, lconv, rconv); ApplyBinaryOperator(ref left, ref right, op); return(op); } return(null); }