public static object InvokeBinaryOperator(string operatorName, object lhs, object rhs)
{
Type lhsType = lhs.GetType();
Type rhsType = rhs.GetType();
TypeCode lhsTypeCode = Type.GetTypeCode(lhsType);
TypeCode rhsTypeCode = Type.GetTypeCode(rhsType);
if (IsNumeric(lhsTypeCode) && IsNumeric(rhsTypeCode))
{
// HACK: optimization to get to the correct operators faster
// is it worthy?
switch (((int)operatorName[3] << 8) + (int)operatorName[operatorName.Length - 1])
{
case ((int)'A' << 8) + (int)'n': // op_Addition
return op_Addition(lhs, lhsTypeCode, rhs, rhsTypeCode);
case ((int)'S' << 8) + (int)'n': // op_Subtraction
return op_Subtraction(lhs, lhsTypeCode, rhs, rhsTypeCode);
case ((int)'M' << 8) + (int)'y': // op_Multiply
return op_Multiply(lhs, lhsTypeCode, rhs, rhsTypeCode);
case ((int)'D' << 8) + (int)'n': // op_Division
return op_Division(lhs, lhsTypeCode, rhs, rhsTypeCode);
case ((int)'M' << 8) + (int)'s': // op_Modulus
return op_Modulus(lhs, lhsTypeCode, rhs, rhsTypeCode);
case ((int)'E' << 8) + (int)'n': // op_Exponentiation
return op_Exponentiation(lhs, lhsTypeCode, rhs, rhsTypeCode);
case ((int)'L' << 8) + (int)'n': // op_LessThan
return op_LessThan(lhs, lhsTypeCode, rhs, rhsTypeCode);
case ((int)'L' << 8) + (int)'l': // op_LessThanOrEqual
return op_LessThanOrEqual(lhs, lhsTypeCode, rhs, rhsTypeCode);
case ((int)'G' << 8) + (int)'n': // op_GreaterThan
return op_GreaterThan(lhs, lhsTypeCode, rhs, rhsTypeCode);
case ((int)'G' << 8) + (int)'l': // op_GreaterThanOrEqual
return op_GreaterThanOrEqual(lhs, lhsTypeCode, rhs, rhsTypeCode);
case ((int)'B' << 8) + (int)'r': // op_BitwiseOr
return op_BitwiseOr(lhs, lhsTypeCode, rhs, rhsTypeCode);
case ((int)'B' << 8) + (int)'d': // op_BitwiseAnd
return op_BitwiseAnd(lhs, lhsTypeCode, rhs, rhsTypeCode);
case ((int)'E' << 8) + (int)'r': // op_ExclusiveOr
return op_ExclusiveOr(lhs, lhsTypeCode, rhs, rhsTypeCode);
case ((int)'S' << 8) + (int)'t': // op_ShiftLeft/Right
return operatorName[8] == 'L' ?
op_ShiftLeft(lhs, lhsTypeCode, rhs, rhsTypeCode) :
op_ShiftRight(lhs, lhsTypeCode, rhs, rhsTypeCode);
case ((int)'M' << 8) + (int)'h': // op_Match
case ((int)'N' << 8) + (int)'h': // op_NotMatch
case ((int)'M' << 8) + (int)'r': // op_Member
case ((int)'N' << 8) + (int)'r': // op_NotMember
default:
throw new MissingMethodException(MissingOperatorMessageFor(operatorName, lhsType, rhsType));
}
}
else
{
var args = new object[] { lhs, rhs };
var duck = lhs as IQuackFu;
if (null != duck)
return duck.QuackInvoke(operatorName, args);
duck = rhs as IQuackFu;
if (null != duck)
return duck.QuackInvoke(operatorName, args);
try
{
// TODO: first resolve the right method on either
// lhs and rhs
// and then cache the final information
return Invoke(lhsType, operatorName, args);
}
catch (MissingMethodException x)
{
try
{
return Invoke(rhsType, operatorName, args);
}
catch (MissingMethodException)
{
try
{
return InvokeRuntimeServicesOperator(operatorName, args);
}
catch (MissingMethodException)
{
}
}
throw new MissingMethodException(MissingOperatorMessageFor(operatorName, lhsType, rhsType), x); // always throw the original exception
}
}
}