MemberFromPointerExpression
using CLanguage.Compiler;
using CLanguage.Interpreter;
using CLanguage.Types;
using System;
using System.Linq;
using System.Runtime.CompilerServices;
namespace CLanguage.Syntax
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public class MemberFromPointerExpression : Expression
{
public Expression Left { get; set; }
public string MemberName { get; set; }
public override bool CanEmitPointer => true;
public MemberFromPointerExpression(Expression left, string memberName)
{
Left = left;
MemberName = memberName;
}
public override CType GetEvaluatedCType(EmitContext ec)
{
CType evaluatedCType = Left.GetEvaluatedCType(ec);
CPointerType cPointerType = evaluatedCType as CPointerType;
if (cPointerType != null) {
CStructType cStructType = cPointerType.InnerType as CStructType;
if (cStructType != null) {
CStructMember cStructMember = cStructType.Members.FirstOrDefault((CStructMember x) => x.Name == MemberName);
if (cStructMember == null) {
ec.Report.Error(1061, "'{1}' not found in '{0}'", cStructType.Name, MemberName);
return CBasicType.SignedInt;
}
return cStructMember.MemberType;
}
}
if (cPointerType != null) {
ec.Report.Error(1061, "'{1}' not found in '{0}'", cPointerType, MemberName);
return CBasicType.SignedInt;
}
ec.Report.Error(1061, "-> cannot be used with '{0}'", evaluatedCType);
return CBasicType.SignedInt;
}
protected override void DoEmit(EmitContext ec)
{
CType evaluatedCType = Left.GetEvaluatedCType(ec);
CPointerType cPointerType = evaluatedCType as CPointerType;
if (cPointerType != null) {
CStructType cStructType = cPointerType.InnerType as CStructType;
if (cStructType != null) {
CStructMember cStructMember = cStructType.Members.FirstOrDefault((CStructMember x) => x.Name == MemberName);
if (cStructMember == null)
ec.Report.Error(1061, "'{1}' not found in '{0}'", cStructType.Name, MemberName);
else {
CStructMethod cStructMethod = cStructMember as CStructMethod;
if (cStructMethod != null && cStructMember.MemberType is CFunctionType) {
ResolvedVariable resolvedVariable = ec.ResolveMethodFunction(cStructType, cStructMethod);
if (resolvedVariable != null) {
Left.Emit(ec);
ec.Emit(OpCode.LoadConstant, Value.Pointer(resolvedVariable.Address));
}
} else {
Left.Emit(ec);
ec.Emit(OpCode.LoadConstant, Value.Pointer(cStructType.GetFieldValueOffset(cStructMember, ec)));
ec.Emit(OpCode.OffsetPointer);
ec.Emit(OpCode.LoadPointer);
}
}
return;
}
}
throw new NotSupportedException("Cannot read '" + MemberName + "' on " + evaluatedCType?.GetType().Name);
}
protected override void DoEmitPointer(EmitContext ec)
{
CType evaluatedCType = Left.GetEvaluatedCType(ec);
CPointerType cPointerType = evaluatedCType as CPointerType;
if (cPointerType != null) {
CStructType cStructType = cPointerType.InnerType as CStructType;
if (cStructType != null) {
CStructMember cStructMember = cStructType.Members.FirstOrDefault((CStructMember x) => x.Name == MemberName);
if (cStructMember == null)
ec.Report.Error(1061, "'{1}' not found in '{0}'", cStructType.Name, MemberName);
else if (cStructMember is CStructMethod && cStructMember.MemberType is CFunctionType) {
ec.Report.Error(1656, "Cannot assign to '{0}'", MemberName);
} else {
Left.Emit(ec);
ec.Emit(OpCode.LoadConstant, Value.Pointer(cStructType.GetFieldValueOffset(cStructMember, ec)));
ec.Emit(OpCode.OffsetPointer);
}
return;
}
}
throw new NotSupportedException("Cannot write '" + MemberName + "' on " + evaluatedCType?.GetType().Name);
}
public override string ToString()
{
return $"{Left}""{MemberName}";
}
}
}