protected virtual void EmitBinaryOperator(MethodContext method, Compiler compiler, ExpressionContext left, ExpressionContext right, Parse.BinaryExpression expression)
{
var leftType = left.Type.GetNative(compiler.Emitter);
var rightType = right.Type.GetNative(compiler.Emitter);
left.EmitGet(method);
right.EmitGet(method);
switch (expression.Operator)
{
case Parse.Operator.Addition:
if (!CallClassOp(method, "op_Addition", leftType, rightType))
method.IL.Emit(OpCodes.Add);
break;
case Parse.Operator.Subtract:
if (!CallClassOp(method, "op_Subtraction", leftType, rightType))
method.IL.Emit(OpCodes.Sub);
break;
case Parse.Operator.Multiply:
if (!CallClassOp(method, "op_Multiply", leftType, rightType))
method.IL.Emit(OpCodes.Mul);
break;
case Parse.Operator.Modulo:
if (!CallClassOp(method, "op_Modulus", leftType, rightType))
method.IL.Emit(OpCodes.Rem);
break;
case Parse.Operator.Divide:
if (!CallClassOp(method, "op_Division", leftType, rightType))
method.IL.Emit(OpCodes.Div);
break;
case Parse.Operator.Power:
var mathPower = typeof(System.Math).GetMethod("Pow", new[] { left.Type.GetNative(compiler.Emitter), right.Type.GetNative(compiler.Emitter) });
if (mathPower == null)
throw new NotSupportedException();
method.IL.EmitCall(OpCodes.Call, mathPower, null);
break;
case Parse.Operator.BitwiseAnd:
if (!CallClassOp(method, "op_BitwiseOr", leftType, rightType))
method.IL.Emit(OpCodes.And);
break;
case Parse.Operator.BitwiseOr:
if (!CallClassOp(method, "op_Addition", leftType, rightType))
method.IL.Emit(OpCodes.Or);
break;
case Parse.Operator.BitwiseXor:
case Parse.Operator.Xor:
if (!CallClassOp(method, "op_ExclusiveOr", leftType, rightType))
method.IL.Emit(OpCodes.Xor);
break;
case Parse.Operator.ShiftLeft:
if (!CallClassOp(method, "op_LeftShift", leftType, rightType))
method.IL.Emit(OpCodes.Shl);
break;
case Parse.Operator.ShiftRight:
if (!CallClassOp(method, "op_RightShift", leftType, rightType))
method.IL.Emit(OpCodes.Shr);
break;
case Parse.Operator.Equal:
if (!CallClassOp(method, "op_Equality", leftType, rightType))
method.IL.Emit(OpCodes.Ceq);
break;
case Parse.Operator.NotEqual:
if (!CallClassOp(method, "op_Inequality", leftType, rightType))
{
method.IL.Emit(OpCodes.Ceq);
method.IL.Emit(OpCodes.Ldc_I4_0);
method.IL.Emit(OpCodes.Ceq);
}
break;
case Parse.Operator.InclusiveGreater:
if (!CallClassOp(method, "op_GreaterThanOrEqual", leftType, rightType))
{
method.IL.Emit(OpCodes.Clt);
method.IL.Emit(OpCodes.Ldc_I4_0);
method.IL.Emit(OpCodes.Ceq);
}
break;
case Parse.Operator.InclusiveLess:
if (!CallClassOp(method, "op_LessThanOrEqual", leftType, rightType))
{
method.IL.Emit(OpCodes.Cgt);
method.IL.Emit(OpCodes.Ldc_I4_0);
method.IL.Emit(OpCodes.Ceq);
}
break;
case Parse.Operator.Greater:
if (!CallClassOp(method, "op_GreaterThan", leftType, rightType))
method.IL.Emit(OpCodes.Cgt);
break;
case Parse.Operator.Less:
if (!CallClassOp(method, "op_LessThan", leftType, rightType))
method.IL.Emit(OpCodes.Clt);
break;
default: throw NotSupported(expression);
}
}