UnaryExpression
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 UnaryExpression : Expression
{
public Unop Op { get; set; }
public Expression Right { get; set; }
public UnaryExpression(Unop op, Expression right)
{
Op = op;
Right = right;
}
public override CType GetEvaluatedCType(EmitContext ec)
{
if (Op != Unop.Not)
return Expression.GetPromotedType(Right, Op.ToString(), ec);
return CBasicType.SignedInt;
}
protected override void DoEmit(EmitContext ec)
{
switch (Op) {
case Unop.PreIncrement:
new AssignExpression(Right, new BinaryExpression(Right, Binop.Add, ConstantExpression.One)).Emit(ec);
break;
case Unop.PreDecrement:
new AssignExpression(Right, new BinaryExpression(Right, Binop.Add, ConstantExpression.NegativeOne)).Emit(ec);
break;
case Unop.PostIncrement:
Right.Emit(ec);
new AssignExpression(Right, new BinaryExpression(Right, Binop.Add, ConstantExpression.One)).Emit(ec);
ec.Emit(OpCode.Pop);
break;
case Unop.PostDecrement:
Right.Emit(ec);
new AssignExpression(Right, new BinaryExpression(Right, Binop.Add, ConstantExpression.NegativeOne)).Emit(ec);
ec.Emit(OpCode.Pop);
break;
default: {
CBasicType cBasicType = (CBasicType)GetEvaluatedCType(ec);
Right.Emit(ec);
ec.EmitCast(Right.GetEvaluatedCType(ec), cBasicType);
int instructionOffset = ec.GetInstructionOffset(cBasicType);
switch (Op) {
case Unop.None:
break;
case Unop.Negate:
ec.Emit((OpCode)(168 + instructionOffset));
break;
case Unop.Not:
ec.Emit((OpCode)(148 + instructionOffset));
break;
case Unop.BinaryComplement:
ec.Emit((OpCode)(158 + instructionOffset));
break;
default:
throw new NotSupportedException("Unsupported unary operator '" + Op.ToString() + "'");
}
break;
}
}
}
public override string ToString()
{
return $"""{Op}""{Right}""";
}
public override Value EvalConstant(EmitContext ec)
{
if (Right.GetEvaluatedCType(ec).IsIntegral) {
int num = (int)Right.EvalConstant(ec);
switch (Op) {
case Unop.None:
return num;
case Unop.Not:
return (num == 0) ? 1 : 0;
case Unop.Negate:
return -num;
case Unop.BinaryComplement:
return ~num;
case Unop.PreIncrement:
return num + 1;
case Unop.PreDecrement:
return num - 1;
case Unop.PostIncrement:
return num;
case Unop.PostDecrement:
return num;
default:
throw new NotSupportedException("Unsupported unary operator '" + Op.ToString() + "'");
}
}
return base.EvalConstant(ec);
}
}
}