AssignExpression
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 AssignExpression : Expression
{
public Expression Left { get; set; }
public Expression Right { get; set; }
public AssignExpression(Expression left, Expression right)
{
Left = left;
Right = right;
}
public override CType GetEvaluatedCType(EmitContext ec)
{
return Left.GetEvaluatedCType(ec);
}
private void DoEmitStructureAssignment(StructureExpression sexpr, EmitContext ec)
{
CArrayType cArrayType = GetEvaluatedCType(ec) as CArrayType;
if (cArrayType != null) {
int numValues = cArrayType.ElementType.NumValues;
int count = sexpr.Items.Count;
for (int i = 0; i < count; i++) {
sexpr.Items[i].Expression.Emit(ec);
Left.EmitPointer(ec);
ec.Emit(OpCode.LoadConstant, i * numValues);
ec.Emit(OpCode.OffsetPointer);
ec.Emit(OpCode.StorePointer);
}
Left.EmitPointer(ec);
return;
}
throw new NotSupportedException($"""{GetEvaluatedCType(ec)}""");
}
protected override void DoEmit(EmitContext ec)
{
StructureExpression structureExpression = Right as StructureExpression;
if (structureExpression != null)
DoEmitStructureAssignment(structureExpression, ec);
else {
Right.Emit(ec);
VariableExpression variableExpression = Left as VariableExpression;
if (variableExpression != null) {
ec.EmitCast(Right.GetEvaluatedCType(ec), Left.GetEvaluatedCType(ec));
ec.Emit(OpCode.Dup);
ResolvedVariable resolvedVariable = ec.ResolveVariable(variableExpression, null);
if (resolvedVariable.Scope == VariableScope.Global)
ec.Emit(OpCode.StoreGlobal, resolvedVariable.Address);
else if (resolvedVariable.Scope == VariableScope.Local) {
ec.Emit(OpCode.StoreLocal, resolvedVariable.Address);
} else if (resolvedVariable.Scope == VariableScope.Arg) {
ec.Emit(OpCode.StoreArg, resolvedVariable.Address);
} else {
if (resolvedVariable.Scope != VariableScope.Function)
throw new NotSupportedException("Assigning to scope '" + resolvedVariable.Scope.ToString() + "'");
ec.Emit(OpCode.Pop);
ec.Report.Error(1656, "Cannot assign to `" + variableExpression.VariableName + "` because it is a function");
}
} else if (Left.CanEmitPointer) {
ec.EmitCast(Right.GetEvaluatedCType(ec), Left.GetEvaluatedCType(ec));
ec.Emit(OpCode.Dup);
Left.EmitPointer(ec);
ec.Emit(OpCode.StorePointer);
} else {
ec.Report.Error(131, "The left-hand side of an assignment must be a variable or an addressable memory location");
}
}
}
public override string ToString()
{
return $"{Left}""{Right}";
}
}
}