BinaryExpression
using CLanguage.Compiler;
using CLanguage.Interpreter;
using CLanguage.Types;
using System;
using System.Runtime.CompilerServices;
namespace CLanguage.Syntax
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public class BinaryExpression : Expression
{
public Expression Left { get; set; }
public Binop Op { get; set; }
public Expression Right { get; set; }
public BinaryExpression(Expression left, Binop op, Expression right)
{
if (left == null)
throw new ArgumentNullException("left");
if (right == null)
throw new ArgumentNullException("right");
Left = left;
Op = op;
Right = right;
}
protected override void DoEmit(EmitContext ec)
{
Expression left = Left;
Expression right = Right;
Binop op = Op;
CType arithmeticType = Expression.GetArithmeticType(left, right, op.ToString(), ec);
Left.Emit(ec);
ec.EmitCast(Left.GetEvaluatedCType(ec), arithmeticType);
Right.Emit(ec);
ec.EmitCast(Right.GetEvaluatedCType(ec), arithmeticType);
int instructionOffset = ec.GetInstructionOffset(arithmeticType);
op = Op;
switch (op) {
case Binop.Add:
ec.Emit((OpCode)(18 + instructionOffset));
break;
case Binop.Subtract:
ec.Emit((OpCode)(28 + instructionOffset));
break;
case Binop.Multiply:
ec.Emit((OpCode)(38 + instructionOffset));
break;
case Binop.Divide:
ec.Emit((OpCode)(48 + instructionOffset));
break;
case Binop.Mod:
ec.Emit((OpCode)(78 + instructionOffset));
break;
case Binop.BinaryAnd:
ec.Emit((OpCode)(118 + instructionOffset));
break;
case Binop.BinaryOr:
ec.Emit((OpCode)(128 + instructionOffset));
break;
case Binop.BinaryXor:
ec.Emit((OpCode)(138 + instructionOffset));
break;
case Binop.ShiftLeft:
ec.Emit((OpCode)(58 + instructionOffset));
break;
case Binop.ShiftRight:
ec.Emit((OpCode)(68 + instructionOffset));
break;
default:
throw new NotSupportedException("Unsupported binary operator '" + Op.ToString() + "'");
}
}
public override CType GetEvaluatedCType(EmitContext ec)
{
return Expression.GetArithmeticType(Left, Right, Op.ToString(), ec);
}
public override string ToString()
{
return $"""{Left}""{Op}""{Right}""";
}
public override Value EvalConstant(EmitContext ec)
{
CType evaluatedCType = Left.GetEvaluatedCType(ec);
CType evaluatedCType2 = Right.GetEvaluatedCType(ec);
if (evaluatedCType.IsIntegral && evaluatedCType2.IsIntegral) {
int num = (int)Left.EvalConstant(ec);
int num2 = (int)Right.EvalConstant(ec);
switch (Op) {
case Binop.Add:
return num + num2;
case Binop.Subtract:
return num - num2;
case Binop.Multiply:
return num * num2;
case Binop.Divide:
return num / num2;
case Binop.Mod:
return num % num2;
case Binop.BinaryAnd:
return num & num2;
case Binop.BinaryOr:
return num | num2;
case Binop.BinaryXor:
return num ^ num2;
case Binop.ShiftLeft:
return num << num2;
case Binop.ShiftRight:
return num >> num2;
default:
throw new NotSupportedException("Unsupported binary operator '" + Op.ToString() + "'");
}
}
return base.EvalConstant(ec);
}
}
}