mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-25 05:21:02 +00:00
- added handling for structs. When defined inside classes or other structs the double member access will be merged, so there is no performance hit by using structs to group data.
This commit is contained in:
parent
3f1673f34f
commit
808188ff18
3 changed files with 145 additions and 36 deletions
|
@ -4226,14 +4226,15 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx)
|
||||||
PSymbolTable *symtbl;
|
PSymbolTable *symtbl;
|
||||||
auto ptype = static_cast<PPointer *>(Object->ValueType)->PointedType;
|
auto ptype = static_cast<PPointer *>(Object->ValueType)->PointedType;
|
||||||
|
|
||||||
if (ptype->IsKindOf(RUNTIME_CLASS(PClass)))
|
if (ptype->IsKindOf(RUNTIME_CLASS(PStruct))) // PClass is a child class of PStruct so this covers both.
|
||||||
{
|
{
|
||||||
PClass *cls = static_cast<PClass *>(ptype);
|
PStruct *cls = static_cast<PStruct *>(ptype);
|
||||||
|
bool isclass = cls->IsKindOf(RUNTIME_CLASS(PClass));
|
||||||
if ((sym = cls->Symbols.FindSymbolInTable(Identifier, symtbl)) != nullptr)
|
if ((sym = cls->Symbols.FindSymbolInTable(Identifier, symtbl)) != nullptr)
|
||||||
{
|
{
|
||||||
if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst)))
|
if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst)))
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as class constant\n", Identifier.GetChars());
|
ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as %s constant\n", Identifier.GetChars(), isclass? "class" : "struct");
|
||||||
newex = FxConstant::MakeConstant(sym, ScriptPosition);
|
newex = FxConstant::MakeConstant(sym, ScriptPosition);
|
||||||
}
|
}
|
||||||
else if (sym->IsKindOf(RUNTIME_CLASS(PField)))
|
else if (sym->IsKindOf(RUNTIME_CLASS(PField)))
|
||||||
|
@ -4263,7 +4264,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx)
|
||||||
delete this;
|
delete this;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto x = new FxClassMember(Object, vsym, ScriptPosition);
|
auto x = isclass? new FxClassMember(Object, vsym, ScriptPosition) : new FxStructMember(Object, vsym, ScriptPosition);
|
||||||
delete this;
|
delete this;
|
||||||
return x->Resolve(ctx);
|
return x->Resolve(ctx);
|
||||||
}
|
}
|
||||||
|
@ -4281,14 +4282,41 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (ptype->IsA(RUNTIME_CLASS(PStruct)))
|
|
||||||
{
|
|
||||||
// todo
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (Object->ValueType->IsA(RUNTIME_CLASS(PStruct)))
|
else if (Object->ValueType->IsA(RUNTIME_CLASS(PStruct)))
|
||||||
{
|
{
|
||||||
// todo
|
if ((sym = Object->ValueType->Symbols.FindSymbol(Identifier, false)) != nullptr)
|
||||||
|
{
|
||||||
|
if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst)))
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as struct constant\n", Identifier.GetChars());
|
||||||
|
newex = FxConstant::MakeConstant(sym, ScriptPosition);
|
||||||
|
}
|
||||||
|
else if (sym->IsKindOf(RUNTIME_CLASS(PField)))
|
||||||
|
{
|
||||||
|
PField *vsym = static_cast<PField*>(sym);
|
||||||
|
|
||||||
|
if (vsym->Flags & VARF_Deprecated)
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_WARNING, "Accessing deprecated member variable %s", vsym->SymbolName.GetChars());
|
||||||
|
}
|
||||||
|
auto x = new FxStructMember(Object, vsym, ScriptPosition);
|
||||||
|
delete this;
|
||||||
|
return x->Resolve(ctx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Invalid member identifier '%s'\n", Identifier.GetChars());
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Unknown identifier '%s'", Identifier.GetChars());
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptPosition.Message(MSG_ERROR, "Left side of %s is not a struct or class", Identifier.GetChars());
|
ScriptPosition.Message(MSG_ERROR, "Left side of %s is not a struct or class", Identifier.GetChars());
|
||||||
|
@ -4381,13 +4409,13 @@ ExpEmit FxSelf::Emit(VMFunctionBuilder *build)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
FxClassMember::FxClassMember(FxExpression *x, PField* mem, const FScriptPosition &pos)
|
FxStructMember::FxStructMember(FxExpression *x, PField* mem, const FScriptPosition &pos)
|
||||||
: FxExpression(EFX_ClassMember, pos)
|
: FxExpression(EFX_StructMember, pos)
|
||||||
{
|
{
|
||||||
classx = x;
|
classx = x;
|
||||||
membervar = mem;
|
membervar = mem;
|
||||||
AddressRequested = false;
|
AddressRequested = false;
|
||||||
//if (classx->IsDefaultObject()) Readonly=true;
|
AddressWritable = true; // must be true unless classx tells us otherwise if requested.
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -4396,7 +4424,7 @@ FxClassMember::FxClassMember(FxExpression *x, PField* mem, const FScriptPosition
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
FxClassMember::~FxClassMember()
|
FxStructMember::~FxStructMember()
|
||||||
{
|
{
|
||||||
SAFE_DELETE(classx);
|
SAFE_DELETE(classx);
|
||||||
}
|
}
|
||||||
|
@ -4407,10 +4435,10 @@ FxClassMember::~FxClassMember()
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
bool FxClassMember::RequestAddress(bool *writable)
|
bool FxStructMember::RequestAddress(bool *writable)
|
||||||
{
|
{
|
||||||
AddressRequested = true;
|
AddressRequested = true;
|
||||||
if (writable != nullptr) *writable = !(membervar->Flags & VARF_ReadOnly);
|
if (writable != nullptr) *writable = AddressWritable && !(membervar->Flags & VARF_ReadOnly);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4420,23 +4448,50 @@ bool FxClassMember::RequestAddress(bool *writable)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
FxExpression *FxClassMember::Resolve(FCompileContext &ctx)
|
FxExpression *FxStructMember::Resolve(FCompileContext &ctx)
|
||||||
{
|
{
|
||||||
CHECKRESOLVED();
|
CHECKRESOLVED();
|
||||||
SAFE_RESOLVE(classx, ctx);
|
SAFE_RESOLVE(classx, ctx);
|
||||||
|
|
||||||
PPointer *ptrtype = dyn_cast<PPointer>(classx->ValueType);
|
if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)))
|
||||||
if (ptrtype == NULL || !ptrtype->IsKindOf(RUNTIME_CLASS(DObject)))
|
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_ERROR, "Member variable requires a class or object");
|
PPointer *ptrtype = dyn_cast<PPointer>(classx->ValueType);
|
||||||
delete this;
|
if (ptrtype == nullptr || !ptrtype->PointedType->IsA(RUNTIME_CLASS(PStruct)))
|
||||||
return NULL;
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Member variable requires a struct");
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (classx->ValueType->IsA(RUNTIME_CLASS(PStruct)))
|
||||||
|
{
|
||||||
|
// if this is a struct within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset.
|
||||||
|
if (classx->ExprType == EFX_ClassMember || classx->ExprType == EFX_StructMember)
|
||||||
|
{
|
||||||
|
auto parentfield = static_cast<FxStructMember *>(classx)->membervar;
|
||||||
|
// PFields are garbage collected so this will be automatically taken care of later.
|
||||||
|
auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset);
|
||||||
|
static_cast<FxStructMember *>(classx)->membervar = newfield;
|
||||||
|
classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
|
||||||
|
auto x = classx->Resolve(ctx);
|
||||||
|
classx = nullptr;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!(classx->RequestAddress(&AddressWritable)))
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "unable to dereference left side of %s", membervar->SymbolName.GetChars());
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ValueType = membervar->Type;
|
ValueType = membervar->Type;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpEmit FxClassMember::Emit(VMFunctionBuilder *build)
|
ExpEmit FxStructMember::Emit(VMFunctionBuilder *build)
|
||||||
{
|
{
|
||||||
ExpEmit obj = classx->Emit(build);
|
ExpEmit obj = classx->Emit(build);
|
||||||
assert(obj.RegType == REGT_POINTER);
|
assert(obj.RegType == REGT_POINTER);
|
||||||
|
@ -4473,6 +4528,41 @@ ExpEmit FxClassMember::Emit(VMFunctionBuilder *build)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FxClassMember::FxClassMember(FxExpression *x, PField* mem, const FScriptPosition &pos)
|
||||||
|
: FxStructMember(x, mem, pos)
|
||||||
|
{
|
||||||
|
ExprType = EFX_ClassMember;
|
||||||
|
//if (classx->IsDefaultObject()) Readonly=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FxExpression *FxClassMember::Resolve(FCompileContext &ctx)
|
||||||
|
{
|
||||||
|
CHECKRESOLVED();
|
||||||
|
SAFE_RESOLVE(classx, ctx);
|
||||||
|
|
||||||
|
PPointer *ptrtype = dyn_cast<PPointer>(classx->ValueType);
|
||||||
|
if (ptrtype == NULL || !ptrtype->PointedType->IsKindOf(RUNTIME_CLASS(PClass)))
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Member variable requires a class or object");
|
||||||
|
delete this;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ValueType = membervar->Type;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
|
@ -237,6 +237,7 @@ enum EFxType
|
||||||
EFX_FRandom,
|
EFX_FRandom,
|
||||||
EFX_Random2,
|
EFX_Random2,
|
||||||
EFX_ClassMember,
|
EFX_ClassMember,
|
||||||
|
EFX_StructMember,
|
||||||
EFX_LocalVariable,
|
EFX_LocalVariable,
|
||||||
EFX_Self,
|
EFX_Self,
|
||||||
EFX_ArrayElement,
|
EFX_ArrayElement,
|
||||||
|
@ -1037,20 +1038,35 @@ public:
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
class FxClassMember : public FxExpression
|
class FxStructMember : public FxExpression
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FxExpression *classx;
|
FxExpression *classx;
|
||||||
PField *membervar;
|
PField *membervar;
|
||||||
bool AddressRequested;
|
bool AddressRequested;
|
||||||
|
bool AddressWritable;
|
||||||
|
|
||||||
FxClassMember(FxExpression*, PField*, const FScriptPosition&);
|
FxStructMember(FxExpression*, PField*, const FScriptPosition&);
|
||||||
~FxClassMember();
|
~FxStructMember();
|
||||||
FxExpression *Resolve(FCompileContext&);
|
FxExpression *Resolve(FCompileContext&);
|
||||||
bool RequestAddress(bool *writable);
|
bool RequestAddress(bool *writable);
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxClassMember
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
class FxClassMember : public FxStructMember
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
FxClassMember(FxExpression*, PField*, const FScriptPosition&);
|
||||||
|
FxExpression *Resolve(FCompileContext&);
|
||||||
|
};
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FxLocalVariable
|
// FxLocalVariable
|
||||||
|
|
|
@ -650,17 +650,17 @@ void InitThingdef()
|
||||||
symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, tid)));
|
symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, tid)));
|
||||||
symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, TIDtoHate)));
|
symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, TIDtoHate)));
|
||||||
symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, waterlevel)));
|
symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, waterlevel)));
|
||||||
symt.AddSymbol(new PField(NAME_X, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.X))); // must remain read-only!
|
symt.AddSymbol(new PField(NAME_X, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, __Pos.X))); // must remain read-only!
|
||||||
symt.AddSymbol(new PField(NAME_Y, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Y))); // must remain read-only!
|
symt.AddSymbol(new PField(NAME_Y, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, __Pos.Y))); // must remain read-only!
|
||||||
symt.AddSymbol(new PField(NAME_Z, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Z))); // must remain read-only!
|
symt.AddSymbol(new PField(NAME_Z, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, __Pos.Z))); // must remain read-only!
|
||||||
symt.AddSymbol(new PField(NAME_VelX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X)));
|
symt.AddSymbol(new PField(NAME_VelX, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Vel.X)));
|
||||||
symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y)));
|
symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Vel.Y)));
|
||||||
symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z)));
|
symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Vel.Z)));
|
||||||
symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X)));
|
symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Vel.X)));
|
||||||
symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y)));
|
symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Vel.Y)));
|
||||||
symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z)));
|
symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Vel.Z)));
|
||||||
symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.X)));
|
symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Scale.X)));
|
||||||
symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.Y)));
|
symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Scale.Y)));
|
||||||
symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor, Score)));
|
symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor, Score)));
|
||||||
symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor, accuracy)));
|
symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor, accuracy)));
|
||||||
symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor, stamina)));
|
symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor, stamina)));
|
||||||
|
@ -677,6 +677,9 @@ void InitThingdef()
|
||||||
symt.AddSymbol(new PField(NAME_VisibleEndAngle, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleEndAngle)));
|
symt.AddSymbol(new PField(NAME_VisibleEndAngle, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleEndAngle)));
|
||||||
symt.AddSymbol(new PField(NAME_VisibleEndPitch, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleEndPitch)));
|
symt.AddSymbol(new PField(NAME_VisibleEndPitch, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleEndPitch)));
|
||||||
symt.AddSymbol(new PField("AttackSound", TypeSound, VARF_Native, myoffsetof(AActor, AttackSound)));
|
symt.AddSymbol(new PField("AttackSound", TypeSound, VARF_Native, myoffsetof(AActor, AttackSound)));
|
||||||
|
symt.AddSymbol(new PField("Pos", TypeVector3, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos)));
|
||||||
|
symt.AddSymbol(new PField("Vel", TypeVector3, VARF_Native, myoffsetof(AActor, Vel)));
|
||||||
|
symt.AddSymbol(new PField("Scale", TypeVector2, VARF_Native, myoffsetof(AActor, Scale)));
|
||||||
symt.AddSymbol(new PField(NAME_Target, TypeActor, VARF_Native, myoffsetof(AActor, target)));
|
symt.AddSymbol(new PField(NAME_Target, TypeActor, VARF_Native, myoffsetof(AActor, target)));
|
||||||
symt.AddSymbol(new PField(NAME_Master, TypeActor, VARF_Native, myoffsetof(AActor, master)));
|
symt.AddSymbol(new PField(NAME_Master, TypeActor, VARF_Native, myoffsetof(AActor, master)));
|
||||||
symt.AddSymbol(new PField(NAME_Tracer, TypeActor, VARF_Native, myoffsetof(AActor, tracer)));
|
symt.AddSymbol(new PField(NAME_Tracer, TypeActor, VARF_Native, myoffsetof(AActor, tracer)));
|
||||||
|
|
Loading…
Reference in a new issue