VariableExpression
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 VariableExpression : Expression
{
public string VariableName { get; set; }
public override bool CanEmitPointer => true;
public VariableExpression(string val, Location loc, Location endLoc)
{
VariableName = val;
base.Location = loc;
base.EndLocation = endLoc;
}
public override CType GetEvaluatedCType(EmitContext ec)
{
return ec.ResolveVariable(this, null).VariableType;
}
protected override void DoEmit(EmitContext ec)
{
ResolvedVariable resolvedVariable = ec.ResolveVariable(this, null);
if (resolvedVariable != null) {
VariableScope scope;
if (resolvedVariable.Scope == VariableScope.Function)
ec.Emit(OpCode.LoadConstant, Value.Pointer(resolvedVariable.Address));
else if (resolvedVariable.VariableType is CBasicType || resolvedVariable.VariableType is CPointerType || resolvedVariable.VariableType is CEnumType) {
if (resolvedVariable.Scope == VariableScope.Arg)
ec.Emit(OpCode.LoadArg, resolvedVariable.Address);
else if (resolvedVariable.Scope == VariableScope.Global) {
ec.Emit(OpCode.LoadGlobal, resolvedVariable.Address);
} else if (resolvedVariable.Scope == VariableScope.Local) {
ec.Emit(OpCode.LoadLocal, resolvedVariable.Address);
} else {
if (resolvedVariable.Scope != VariableScope.Constant) {
scope = resolvedVariable.Scope;
throw new NotSupportedException("Cannot evaluate variable scope '" + scope.ToString() + "'");
}
ec.Emit(OpCode.LoadConstant, resolvedVariable.Constant);
}
} else {
if (!(resolvedVariable.VariableType is CArrayType))
throw new NotSupportedException("Cannot evaluate variable type '" + resolvedVariable.VariableType?.ToString() + "'");
if (resolvedVariable.Scope == VariableScope.Arg) {
ec.Emit(OpCode.LoadConstant, Value.Pointer(resolvedVariable.Address));
ec.Emit(OpCode.LoadFramePointer);
ec.Emit(OpCode.OffsetPointer);
} else if (resolvedVariable.Scope == VariableScope.Global) {
ec.Emit(OpCode.LoadConstant, Value.Pointer(resolvedVariable.Address));
} else {
if (resolvedVariable.Scope != VariableScope.Local) {
scope = resolvedVariable.Scope;
throw new NotSupportedException("Cannot evaluate array variable scope '" + scope.ToString() + "'");
}
ec.Emit(OpCode.LoadConstant, Value.Pointer(resolvedVariable.Address));
ec.Emit(OpCode.LoadFramePointer);
ec.Emit(OpCode.OffsetPointer);
}
}
} else
ec.Emit(OpCode.LoadConstant, 0);
}
protected override void DoEmitPointer(EmitContext ec)
{
ResolvedVariable resolvedVariable = ec.ResolveVariable(this, null);
if (resolvedVariable != null)
resolvedVariable.EmitPointer(ec);
else
ec.Emit(OpCode.LoadConstant, 0);
}
public override string ToString()
{
return VariableName.ToString();
}
public override Value EvalConstant(EmitContext ec)
{
ResolvedVariable resolvedVariable = ec.ResolveVariable(this, null);
if (resolvedVariable != null && resolvedVariable.Scope == VariableScope.Constant)
return resolvedVariable.Constant;
return base.EvalConstant(ec);
}
}
}