From 96631e88082aa4b5d9645214a275f73daa4dab62 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 Apr 2017 17:21:13 +0200 Subject: [PATCH] - make PClass not inherit from PStruct. Having these two types related can cause problems with detection in the compiler because for some parts they need quite different handling. Common handling for the fields has been moved into PSymbolTable but overall redundancy was quite minor as both types share surprisingly little functionality. --- src/dobjtype.cpp | 208 ++++++++------------------ src/dobjtype.h | 26 ++-- src/scripting/backend/codegen.cpp | 34 ++--- src/scripting/backend/codegen.h | 6 +- src/scripting/symbols.cpp | 78 +++++++++- src/scripting/symbols.h | 10 +- src/scripting/thingdef.cpp | 6 +- src/scripting/thingdef.h | 10 +- src/scripting/thingdef_data.cpp | 4 +- src/scripting/zscript/zcc_compile.cpp | 54 ++++--- src/scripting/zscript/zcc_compile.h | 20 +-- src/scripting/zscript/zcc_parser.h | 2 +- 12 files changed, 221 insertions(+), 237 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 98274328e0..b9ad1e57d1 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -438,17 +438,17 @@ PBasicType::PBasicType(unsigned int size, unsigned int align) IMPLEMENT_CLASS(PCompoundType, true, false) -/* PNamedType *************************************************************/ +/* PContainerType *************************************************************/ -IMPLEMENT_CLASS(PNamedType, true, false) +IMPLEMENT_CLASS(PContainerType, true, false) //========================================================================== // -// PNamedType :: IsMatch +// PContainerType :: IsMatch // //========================================================================== -bool PNamedType::IsMatch(intptr_t id1, intptr_t id2) const +bool PContainerType::IsMatch(intptr_t id1, intptr_t id2) const { const DObject *outer = (const DObject *)id1; FName name = (ENamedName)(intptr_t)id2; @@ -458,11 +458,11 @@ bool PNamedType::IsMatch(intptr_t id1, intptr_t id2) const //========================================================================== // -// PNamedType :: GetTypeIDs +// PContainerType :: GetTypeIDs // //========================================================================== -void PNamedType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +void PContainerType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const { id1 = (intptr_t)Outer; id2 = TypeName; @@ -2280,6 +2280,25 @@ PMap *NewMap(PType *keytype, PType *valuetype) IMPLEMENT_CLASS(PStruct, false, false) +//========================================================================== +// +// WriteFields +// +//========================================================================== + +static void WriteFields(FSerializer &ar, const void *addr, const TArray &fields) +{ + for (unsigned i = 0; i < fields.Size(); ++i) + { + const PField *field = fields[i]; + // Skip fields without or with native serialization + if (!(field->Flags & (VARF_Transient | VARF_Meta))) + { + field->Type->WriteValue(ar, field->SymbolName.GetChars(), (const uint8_t *)addr + field->Offset); + } + } +} + //========================================================================== // // PStruct - Default Constructor @@ -2299,7 +2318,7 @@ PStruct::PStruct() //========================================================================== PStruct::PStruct(FName name, PTypeBase *outer, bool isnative) -: PNamedType(name, outer) +: PContainerType(name, outer) { mDescriptiveName.Format("%sStruct<%s>", isnative? "Native" : "", name.GetChars()); Size = 0; @@ -2365,72 +2384,13 @@ bool PStruct::ReadValue(FSerializer &ar, const char *key, void *addr) const { if (ar.BeginObject(key)) { - bool ret = ReadFields(ar, addr); + bool ret = Symbols.ReadFields(ar, addr, DescriptiveName()); ar.EndObject(); return ret; } return false; } -//========================================================================== -// -// PStruct :: WriteFields STATIC -// -//========================================================================== - -void PStruct::WriteFields(FSerializer &ar, const void *addr, const TArray &fields) -{ - for (unsigned i = 0; i < fields.Size(); ++i) - { - const PField *field = fields[i]; - // Skip fields without or with native serialization - if (!(field->Flags & (VARF_Transient|VARF_Meta))) - { - field->Type->WriteValue(ar, field->SymbolName.GetChars(), (const uint8_t *)addr + field->Offset); - } - } -} - -//========================================================================== -// -// PStruct :: ReadFields -// -//========================================================================== - -bool PStruct::ReadFields(FSerializer &ar, void *addr) const -{ - bool readsomething = false; - bool foundsomething = false; - const char *label; - while ((label = ar.GetKey())) - { - foundsomething = true; - - const PSymbol *sym = Symbols.FindSymbol(FName(label, true), true); - if (sym == nullptr) - { - DPrintf(DMSG_ERROR, "Cannot find field %s in %s\n", - label, TypeName.GetChars()); - } - else if (!sym->IsKindOf(RUNTIME_CLASS(PField))) - { - DPrintf(DMSG_ERROR, "Symbol %s in %s is not a field\n", - label, TypeName.GetChars()); - } - else if ((static_cast(sym)->Flags & (VARF_Transient | VARF_Meta))) - { - DPrintf(DMSG_ERROR, "Symbol %s in %s is not a serializable field\n", - label, TypeName.GetChars()); - } - else - { - readsomething |= static_cast(sym)->Type->ReadValue(ar, nullptr, - (uint8_t *)addr + static_cast(sym)->Offset); - } - } - return readsomething || !foundsomething; -} - //========================================================================== // // PStruct :: AddField @@ -2442,25 +2402,8 @@ bool PStruct::ReadFields(FSerializer &ar, void *addr) const PField *PStruct::AddField(FName name, PType *type, uint32_t flags) { - PField *field = new PField(name, type, flags); - - // The new field is added to the end of this struct, alignment permitting. - field->Offset = (Size + (type->Align - 1)) & ~(type->Align - 1); - - // Enlarge this struct to enclose the new field. - Size = unsigned(field->Offset + type->Size); - - // This struct's alignment is the same as the largest alignment of any of - // its fields. - Align = MAX(Align, type->Align); - - if (Symbols.AddSymbol(field) == nullptr) - { // name is already in use - field->Destroy(); - return nullptr; - } - Fields.Push(field); - + auto field = Symbols.AddField(name, type, flags, Size, &Align); + if (field != nullptr) Fields.Push(field); return field; } @@ -2699,7 +2642,7 @@ static void RecurseWriteFields(const PClass *type, FSerializer &ar, const void * key.Format("class:%s", type->TypeName.GetChars()); if (ar.BeginObject(key.GetChars())) { - PStruct::WriteFields(ar, addr, type->Fields); + WriteFields(ar, addr, type->Fields); ar.EndObject(); } break; @@ -2708,15 +2651,6 @@ static void RecurseWriteFields(const PClass *type, FSerializer &ar, const void * } } -void PClass::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - if (ar.BeginObject(key)) - { - RecurseWriteFields(this, ar, addr); - ar.EndObject(); - } -} - // Same as WriteValue, but does not create a new object in the serializer // This is so that user variables do not contain unnecessary subblocks. void PClass::WriteAllFields(FSerializer &ar, const void *addr) const @@ -2726,21 +2660,10 @@ void PClass::WriteAllFields(FSerializer &ar, const void *addr) const //========================================================================== // -// PClass :: ReadValue +// PClass :: ReadAllFields // //========================================================================== -bool PClass::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - if (ar.BeginObject(key)) - { - bool ret = ReadAllFields(ar, addr); - ar.EndObject(); - return ret; - } - return true; -} - bool PClass::ReadAllFields(FSerializer &ar, void *addr) const { bool readsomething = false; @@ -2778,7 +2701,7 @@ bool PClass::ReadAllFields(FSerializer &ar, void *addr) const { if (ar.BeginObject(nullptr)) { - readsomething |= type->ReadFields(ar, addr); + readsomething |= type->Symbols.ReadFields(ar, addr, DescriptiveName()); ar.EndObject(); } } @@ -3358,39 +3281,6 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) return type; } -//========================================================================== -// -// PStruct :: AddField -// -// Appends a new metadata field to the end of a struct. Returns either the new field -// or nullptr if a symbol by that name already exists. -// -//========================================================================== - -PField *PClass::AddMetaField(FName name, PType *type, uint32_t flags) -{ - PField *field = new PField(name, type, flags); - - // The new field is added to the end of this struct, alignment permitting. - field->Offset = (MetaSize + (type->Align - 1)) & ~(type->Align - 1); - - // Enlarge this struct to enclose the new field. - MetaSize = unsigned(field->Offset + type->Size); - - // This struct's alignment is the same as the largest alignment of any of - // its fields. - Align = MAX(Align, type->Align); - - if (Symbols.AddSymbol(field) == nullptr) - { // name is already in use - field->Destroy(); - return nullptr; - } - Fields.Push(field); - - return field; -} - //========================================================================== // // PClass :: AddField @@ -3399,10 +3289,11 @@ PField *PClass::AddMetaField(FName name, PType *type, uint32_t flags) PField *PClass::AddField(FName name, PType *type, uint32_t flags) { + PField *field; if (!(flags & VARF_Meta)) { unsigned oldsize = Size; - PField *field = Super::AddField(name, type, flags); + field = Symbols.AddField(name, type, flags, Size); // Only initialize the defaults if they have already been created. // For ZScript this is not the case, it will first define all fields before @@ -3412,23 +3303,42 @@ PField *PClass::AddField(FName name, PType *type, uint32_t flags) Defaults = (uint8_t *)M_Realloc(Defaults, Size); memset(Defaults + oldsize, 0, Size - oldsize); } - return field; } else { + // Same as above, but a different data storage. unsigned oldsize = MetaSize; - PField *field = AddMetaField(name, type, flags); + field = Symbols.AddField(name, type, flags, MetaSize); - // Only initialize the defaults if they have already been created. - // For ZScript this is not the case, it will first define all fields before - // setting up any defaults for any class. if (field != nullptr && !(flags & VARF_Native) && Meta != nullptr) { Meta = (uint8_t *)M_Realloc(Meta, MetaSize); memset(Meta + oldsize, 0, MetaSize - oldsize); } - return field; } + if (field != nullptr) Fields.Push(field); + return field; +} + +//========================================================================== +// +// PClass :: AddNativeField +// +// This looks the same as the struct version but that will change later. +// +//========================================================================== + +PField *PClass::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue) +{ + PField *field = new PField(name, type, flags | VARF_Native | VARF_Transient, address, bitvalue); + + if (Symbols.AddSymbol(field) == nullptr) + { // name is already in use + field->Destroy(); + return nullptr; + } + Fields.Push(field); + return field; } //========================================================================== diff --git a/src/dobjtype.h b/src/dobjtype.h index bc5a6bcfd1..0b776e5035 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -216,22 +216,24 @@ class PCompoundType : public PType DECLARE_ABSTRACT_CLASS(PCompoundType, PType); }; -class PNamedType : public PCompoundType +class PContainerType : public PCompoundType { - DECLARE_ABSTRACT_CLASS(PNamedType, PCompoundType); + DECLARE_ABSTRACT_CLASS(PContainerType, PCompoundType); public: PTypeBase *Outer; // object this type is contained within FName TypeName; // this type's name - PNamedType() : Outer(NULL) { + PContainerType() : Outer(NULL) { mDescriptiveName = "NamedType"; } - PNamedType(FName name, PTypeBase *outer) : Outer(outer), TypeName(name) { + PContainerType(FName name, PTypeBase *outer) : Outer(outer), TypeName(name) { mDescriptiveName = name.GetChars(); } virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + virtual PField *AddField(FName name, PType *type, uint32_t flags = 0) = 0; + virtual PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) = 0; }; // Basic types -------------------------------------------------------------- @@ -537,9 +539,9 @@ protected: PMap(); }; -class PStruct : public PNamedType +class PStruct : public PContainerType { - DECLARE_CLASS(PStruct, PNamedType); + DECLARE_CLASS(PStruct, PContainerType); public: PStruct(FName name, PTypeBase *outer, bool isnative = false); @@ -558,8 +560,6 @@ public: void SetDefaultValue(void *base, unsigned offset, TArray *specials) override; void SetPointer(void *base, unsigned offset, TArray *specials) override; - static void WriteFields(FSerializer &ar, const void *addr, const TArray &fields); - bool ReadFields(FSerializer &ar, void *addr) const; protected: PStruct(); }; @@ -588,20 +588,17 @@ enum TentativeClass = UINT_MAX, }; -class PClass : public PStruct +class PClass : public PContainerType { - DECLARE_CLASS(PClass, PStruct); + DECLARE_CLASS(PClass, PContainerType); // We unravel _WITH_META here just as we did for PType. protected: TArray MetaInits; void Derive(PClass *newclass, FName name); void InitializeSpecials(void *addr, void *defaults, TArray PClass::*Inits); void SetSuper(); - PField *AddMetaField(FName name, PType *type, uint32_t flags); public: - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; void WriteAllFields(FSerializer &ar, const void *addr) const; - bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; bool ReadAllFields(FSerializer &ar, void *addr) const; void InitializeDefaults(); int FindVirtualIndex(FName name, PPrototype *proto); @@ -625,6 +622,7 @@ public: bool bDecorateClass; // may be subject to some idiosyncracies due to DECORATE backwards compatibility TArray Virtuals; // virtual function table FName SourceLumpName; + TArray Fields; void (*ConstructNative)(void *); @@ -635,6 +633,8 @@ public: DObject *CreateNew(); PClass *CreateDerivedClass(FName name, unsigned int size); PField *AddField(FName name, PType *type, uint32_t flags=0) override; + PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) override; + void InitializeActorInfo(); void BuildFlatPointers(); void BuildArrayPointers(); diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 26e15fe142..f54ccf1f83 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -114,7 +114,7 @@ FCompileContext::FCompileContext(PNamespace *cg, PFunction *fnc, PPrototype *ret if (fnc != nullptr) Class = fnc->OwningClass; } -FCompileContext::FCompileContext(PNamespace *cg, PStruct *cls, bool fromdecorate) +FCompileContext::FCompileContext(PNamespace *cg, PContainerType *cls, bool fromdecorate) : ReturnProto(nullptr), Function(nullptr), Class(cls), FromDecorate(fromdecorate), StateIndex(-1), StateCount(0), Lump(-1), CurGlobals(cg) { } @@ -200,14 +200,14 @@ FxLocalVariableDeclaration *FCompileContext::FindLocalVariable(FName name) } } -static PStruct *FindStructType(FName name, FCompileContext &ctx) +static PContainerType *FindContainerType(FName name, FCompileContext &ctx) { auto sym = ctx.Class->Symbols.FindSymbol(name, true); if (sym == nullptr) sym = ctx.CurGlobals->Symbols.FindSymbol(name, true); if (sym && sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) { auto type = static_cast(sym); - return dyn_cast(type->Type); + return dyn_cast(type->Type); } return nullptr; } @@ -224,7 +224,7 @@ static PClass *FindClassType(FName name, FCompileContext &ctx) return nullptr; } -bool isActor(PStruct *type) +bool isActor(PContainerType *type) { auto cls = dyn_cast(type); return cls ? cls->IsDescendantOf(RUNTIME_CLASS(AActor)) : false; @@ -6121,7 +6121,7 @@ foundit: // //========================================================================== -FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PStruct *classctx, FxExpression *&object, PStruct *objtype) +FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType *classctx, FxExpression *&object, PContainerType *objtype) { PSymbol *sym; PSymbolTable *symtbl; @@ -6269,7 +6269,7 @@ FxMemberIdentifier::~FxMemberIdentifier() FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) { - PStruct *ccls = nullptr; + PContainerType *ccls = nullptr; CHECKRESOLVED(); if (Object->ExprType == EFX_Identifier) @@ -6277,7 +6277,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) auto id = static_cast(Object)->Identifier; // If the left side is a class name for a static member function call it needs to be resolved manually // because the resulting value type would cause problems in nearly every other place where identifiers are being used. - ccls = FindStructType(id, ctx); + ccls = FindContainerType(id, ctx); if (ccls != nullptr) { static_cast(Object)->noglobal = true; @@ -6398,9 +6398,9 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) { auto ptype = static_cast(Object->ValueType)->PointedType; - if (ptype->IsKindOf(RUNTIME_CLASS(PStruct))) + if (ptype->IsKindOf(RUNTIME_CLASS(PContainerType))) { - auto ret = ResolveMember(ctx, ctx.Class, Object, static_cast(ptype)); + auto ret = ResolveMember(ctx, ctx.Class, Object, static_cast(ptype)); delete this; return ret; } @@ -7023,7 +7023,7 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) { PPointer *ptrtype = dyn_cast(classx->ValueType); - if (ptrtype == nullptr || !ptrtype->PointedType->IsKindOf(RUNTIME_CLASS(PStruct))) + if (ptrtype == nullptr || !ptrtype->PointedType->IsKindOf(RUNTIME_CLASS(PContainerType))) { ScriptPosition.Message(MSG_ERROR, "Member variable requires a struct or class object"); delete this; @@ -7925,12 +7925,12 @@ FxMemberFunctionCall::~FxMemberFunctionCall() FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) { - PStruct *cls; + PContainerType *cls = nullptr; bool staticonly = false; bool novirtual = false; bool isreadonly = false; - PStruct *ccls = nullptr; + PContainerType *ccls = nullptr; if (ctx.Class == nullptr) { @@ -7957,7 +7957,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) // because the resulting value type would cause problems in nearly every other place where identifiers are being used. // [ZZ] substitute ccls for String internal type. if (id == NAME_String) ccls = TypeStringStruct; - else ccls = FindStructType(id, ctx); + else ccls = FindContainerType(id, ctx); if (ccls != nullptr) static_cast(Self)->noglobal = true; } @@ -8228,7 +8228,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !Self->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer))) { auto ptype = static_cast(Self->ValueType)->PointedType; - if (ptype->IsKindOf(RUNTIME_CLASS(PStruct))) + if (ptype->IsKindOf(RUNTIME_CLASS(PContainerType))) { if (ptype->IsKindOf(RUNTIME_CLASS(PClass)) && MethodName == NAME_GetClass) { @@ -8243,7 +8243,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) } - cls = static_cast(ptype); + cls = static_cast(ptype); } else { @@ -8825,9 +8825,9 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) ArgList[i] = ArgList[i]->Resolve(ctx); // nust be resolved before the address is requested. if (ArgList[i] != nullptr && ArgList[i]->ValueType != TypeNullPtr) { - if (type == ArgList[i]->ValueType && type->IsA(RUNTIME_CLASS(PPointer)) && static_cast(type)->IsA(RUNTIME_CLASS(PStruct))) + if (type == ArgList[i]->ValueType && type->IsA(RUNTIME_CLASS(PPointer)) && static_cast(type)->PointedType->IsA(RUNTIME_CLASS(PStruct))) { - // trying to pass a struct reference as a struct refg + // trying to pass a struct reference as a struct reference. This must preserve the type. } else { diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index a6aef75235..35831c958f 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -78,7 +78,7 @@ struct FCompileContext FxCompoundStatement *Block = nullptr; PPrototype *ReturnProto; PFunction *Function; // The function that is currently being compiled (or nullptr for constant evaluation.) - PStruct *Class; // The type of the owning class. + PContainerType *Class; // The type of the owning class. bool FromDecorate; // DECORATE must silence some warnings and demote some errors. int StateIndex; // index in actor's state table for anonymous functions, otherwise -1 (not used by DECORATE which pre-resolves state indices) int StateCount; // amount of states an anoymous function is being used on (must be 1 for state indices to be allowed.) @@ -90,7 +90,7 @@ struct FCompileContext FString VersionString; FCompileContext(PNamespace *spc, PFunction *func, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump, const VersionInfo &ver); - FCompileContext(PNamespace *spc, PStruct *cls, bool fromdecorate); // only to be used to resolve constants! + FCompileContext(PNamespace *spc, PContainerType *cls, bool fromdecorate); // only to be used to resolve constants! PSymbol *FindInClass(FName identifier, PSymbolTable *&symt); PSymbol *FindInSelfClass(FName identifier, PSymbolTable *&symt); @@ -373,7 +373,7 @@ public: FxIdentifier(FName i, const FScriptPosition &p); FxExpression *Resolve(FCompileContext&); - FxExpression *ResolveMember(FCompileContext&, PStruct*, FxExpression*&, PStruct*); + FxExpression *ResolveMember(FCompileContext&, PContainerType*, FxExpression*&, PContainerType*); }; diff --git a/src/scripting/symbols.cpp b/src/scripting/symbols.cpp index 41ca4a1a87..8b641ac55b 100644 --- a/src/scripting/symbols.cpp +++ b/src/scripting/symbols.cpp @@ -36,6 +36,8 @@ #include #include "dobject.h" #include "i_system.h" +#include "templates.h" +#include "serializer.h" // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -102,7 +104,7 @@ unsigned PFunction::AddVariant(PPrototype *proto, TArray &argflags, TA assert(proto->ArgumentTypes.Size() > 0); auto selftypeptr = dyn_cast(proto->ArgumentTypes[0]); assert(selftypeptr != nullptr); - variant.SelfClass = dyn_cast(selftypeptr->PointedType); + variant.SelfClass = dyn_cast(selftypeptr->PointedType); assert(variant.SelfClass != nullptr); } else @@ -238,6 +240,78 @@ PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) // //========================================================================== +PField *PSymbolTable::AddField(FName name, PType *type, uint32_t flags, unsigned &Size, unsigned *Align) +{ + PField *field = new PField(name, type, flags); + + // The new field is added to the end of this struct, alignment permitting. + field->Offset = (Size + (type->Align - 1)) & ~(type->Align - 1); + + // Enlarge this struct to enclose the new field. + Size = unsigned(field->Offset + type->Size); + + // This struct's alignment is the same as the largest alignment of any of + // its fields. + if (Align != nullptr) + { + *Align = MAX(*Align, type->Align); + } + + if (AddSymbol(field) == nullptr) + { // name is already in use + field->Destroy(); + return nullptr; + } + return field; +} + +//========================================================================== +// +// PClass :: ReadFields +// +// This will need some changes later. +//========================================================================== + +bool PSymbolTable::ReadFields(FSerializer &ar, void *addr, const char *TypeName) const +{ + bool readsomething = false; + bool foundsomething = false; + const char *label; + while ((label = ar.GetKey())) + { + foundsomething = true; + + const PSymbol *sym = FindSymbol(FName(label, true), false); + if (sym == nullptr) + { + DPrintf(DMSG_ERROR, "Cannot find field %s in %s\n", + label, TypeName); + } + else if (!sym->IsKindOf(RUNTIME_CLASS(PField))) + { + DPrintf(DMSG_ERROR, "Symbol %s in %s is not a field\n", + label, TypeName); + } + else if ((static_cast(sym)->Flags & (VARF_Transient | VARF_Meta))) + { + DPrintf(DMSG_ERROR, "Symbol %s in %s is not a serializable field\n", + label, TypeName); + } + else + { + readsomething |= static_cast(sym)->Type->ReadValue(ar, nullptr, + (uint8_t *)addr + static_cast(sym)->Offset); + } + } + return readsomething || !foundsomething; +} + +//========================================================================== +// +// +// +//========================================================================== + void PSymbolTable::RemoveSymbol(PSymbol *sym) { auto mysym = Symbols.CheckKey(sym->SymbolName); @@ -387,7 +461,7 @@ void RemoveUnusedSymbols() { for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext) { - if (ty->IsKindOf(RUNTIME_CLASS(PStruct))) + if (ty->IsKindOf(RUNTIME_CLASS(PContainerType))) { auto it = ty->Symbols.GetIterator(); PSymbolTable::MapType::Pair *pair; diff --git a/src/scripting/symbols.h b/src/scripting/symbols.h index 648462168c..f21ec749ea 100644 --- a/src/scripting/symbols.h +++ b/src/scripting/symbols.h @@ -10,7 +10,7 @@ class VMFunction; class PType; class PPrototype; struct ZCC_TreeNode; -class PStruct; +class PContainerType; // Symbol information ------------------------------------------------------- @@ -175,15 +175,15 @@ public: TArray ArgNames; // we need the names to access them later when the function gets compiled. uint32_t Flags; int UseFlags; - PStruct *SelfClass; + PContainerType *SelfClass; }; TArray Variants; - PStruct *OwningClass = nullptr; + PContainerType *OwningClass = nullptr; unsigned AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags, int useflags); int GetImplicitArgs(); - PFunction(PStruct *owner = nullptr, FName name = NAME_None) : PSymbol(name), OwningClass(owner) {} + PFunction(PContainerType *owner = nullptr, FName name = NAME_None) : PSymbol(name), OwningClass(owner) {} }; // A symbol table ----------------------------------------------------------- @@ -215,6 +215,8 @@ struct PSymbolTable // a symbol with the same name is already in the table. This symbol is // not copied and will be freed when the symbol table is destroyed. PSymbol *AddSymbol (PSymbol *sym); + PField *AddField(FName name, PType *type, uint32_t flags, unsigned &Size, unsigned *Align = nullptr); + bool ReadFields(FSerializer &ar, void *addr, const char *TypeName) const; // Similar to AddSymbol but always succeeds. Returns the symbol that used // to be in the table with this name, if any. diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 0fbac19b9a..4eb0098ddc 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -101,7 +101,7 @@ FScriptPosition & GetStateSource(FState *state) // //========================================================================== -void SetImplicitArgs(TArray *args, TArray *argflags, TArray *argnames, PStruct *cls, uint32_t funcflags, int useflags) +void SetImplicitArgs(TArray *args, TArray *argflags, TArray *argnames, PContainerType *cls, uint32_t funcflags, int useflags) { // Must be called before adding any other arguments. assert(args == nullptr || args->Size() == 0); @@ -154,7 +154,7 @@ void SetImplicitArgs(TArray *args, TArray *argflags, TArray rets(1); TArray args; @@ -184,7 +184,7 @@ PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, i // //========================================================================== -PFunction *FindClassMemberFunction(PStruct *selfcls, PStruct *funccls, FName name, FScriptPosition &sc, bool *error) +PFunction *FindClassMemberFunction(PContainerType *selfcls, PContainerType *funccls, FName name, FScriptPosition &sc, bool *error) { // Skip ACS_NamedExecuteWithResult. Anything calling this should use the builtin instead. if (name == NAME_ACS_NamedExecuteWithResult) return nullptr; diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index 7517283cfd..d727623b4b 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -148,8 +148,8 @@ inline void ResetBaggage (Baggage *bag, PClassActor *stateclass) // //========================================================================== -AFuncDesc *FindFunction(PStruct *cls, const char * string); -FieldDesc *FindField(PStruct *cls, const char * string); +AFuncDesc *FindFunction(PContainerType *cls, const char * string); +FieldDesc *FindField(PContainerType *cls, const char * string); FxExpression *ParseExpression(FScanner &sc, PClassActor *cls, PNamespace *resolvenspc = nullptr); @@ -159,9 +159,9 @@ void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray *args, TArray *argflags, TArray *argnames, PStruct *cls, uint32_t funcflags, int useflags); -PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, int flags); -PFunction *FindClassMemberFunction(PStruct *cls, PStruct *funccls, FName name, FScriptPosition &sc, bool *error); +void SetImplicitArgs(TArray *args, TArray *argflags, TArray *argnames, PContainerType *cls, uint32_t funcflags, int useflags); +PFunction *CreateAnonymousFunction(PContainerType *containingclass, PType *returntype, int flags); +PFunction *FindClassMemberFunction(PContainerType *cls, PContainerType *funccls, FName name, FScriptPosition &sc, bool *error); void CreateDamageFunction(PNamespace *ns, const VersionInfo &ver, PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum); //========================================================================== diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index c145fd0f55..fe3a359338 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -667,7 +667,7 @@ static int CompareClassNames(const Desc& a, const Desc& b) // //========================================================================== -AFuncDesc *FindFunction(PStruct *cls, const char * string) +AFuncDesc *FindFunction(PContainerType *cls, const char * string) { int min = 0, max = AFTable.Size() - 1; @@ -698,7 +698,7 @@ AFuncDesc *FindFunction(PStruct *cls, const char * string) // //========================================================================== -FieldDesc *FindField(PStruct *cls, const char * string) +FieldDesc *FindField(PContainerType *cls, const char * string) { int min = 0, max = FieldTable.Size() - 1; const char * cname = cls ? cls->TypeName.GetChars() : ""; diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 50eb2c3966..9ebed3c6b9 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -75,7 +75,7 @@ const char * ZCCCompiler::GetStringConst(FxExpression *ex, FCompileContext &ctx) return AST.Strings.Alloc(static_cast(ex)->GetValue().GetString())->GetChars(); } -int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PStruct *cls) +int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PContainerType *cls) { FCompileContext ctx(OutNamespace, cls, false); FxExpression *ex = new FxIntCast(ConvertNode(node), false); @@ -89,7 +89,7 @@ int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PStruct *cls) return static_cast(ex)->GetValue().GetInt(); } -FString ZCCCompiler::StringConstFromNode(ZCC_TreeNode *node, PStruct *cls) +FString ZCCCompiler::StringConstFromNode(ZCC_TreeNode *node, PContainerType *cls) { FCompileContext ctx(OutNamespace, cls, false); FxExpression *ex = new FxStringCast(ConvertNode(node)); @@ -641,7 +641,7 @@ void ZCCCompiler::CreateClassTypes() { Error(c->cls, "Class name %s already exists", c->NodeName().GetChars()); } - else DPrintf(DMSG_SPAMMY, "Created class %s with parent %s\n", c->Type()->TypeName.GetChars(), c->Type()->ParentClass->TypeName.GetChars()); + else DPrintf(DMSG_SPAMMY, "Created class %s with parent %s\n", c->Type()->TypeName.GetChars(), c->ClassType()->ParentClass->TypeName.GetChars()); } catch (CRecoverableError &err) { @@ -689,7 +689,7 @@ void ZCCCompiler::CreateClassTypes() c->Type()->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(c->Type()->ObjectFlags, FScopeBarrier::Side_Play); } - c->Type()->bExported = true; // this class is accessible to script side type casts. (The reason for this flag is that types like PInt need to be skipped.) + c->ClassType()->bExported = true; // this class is accessible to script side type casts. (The reason for this flag is that types like PInt need to be skipped.) c->cls->Symbol = new PSymbolType(c->NodeName(), c->Type()); OutNamespace->Symbols.AddSymbol(c->cls->Symbol); Classes.Push(c); @@ -746,7 +746,7 @@ void ZCCCompiler::CreateClassTypes() // Link the tree node tables. We only can do this after we know the class relations. for (auto cc : Classes) { - if (cc->Type() == cd->Type()->ParentClass) + if (cc->ClassType() == cd->ClassType()->ParentClass) { cd->TreeNodes.SetParentTable(&cc->TreeNodes); break; @@ -769,7 +769,7 @@ void ZCCCompiler::CreateClassTypes() // //========================================================================== -void ZCCCompiler::CopyConstants(TArray &dest, TArray &Constants, PStruct *cls, PSymbolTable *ot) +void ZCCCompiler::CopyConstants(TArray &dest, TArray &Constants, PContainerType *cls, PSymbolTable *ot) { for (auto c : Constants) { @@ -1155,7 +1155,7 @@ void ZCCCompiler::CompileAllFields() } for (unsigned i = 0; i < Classes.Size(); i++) { - auto type = Classes[i]->Type(); + auto type = Classes[i]->ClassType(); if (type->Size == TentativeClass) { @@ -1167,7 +1167,7 @@ void ZCCCompiler::CompileAllFields() else { // Inherit the size of the parent class - type->Size = Classes[i]->Type()->ParentClass->Size; + type->Size = Classes[i]->ClassType()->ParentClass->Size; } } if (type->TypeName == NAME_Actor) @@ -1175,8 +1175,8 @@ void ZCCCompiler::CompileAllFields() assert(type->MetaSize == 0); AddActorInfo(type); // AActor needs the actor info manually added to its meta data before adding any scripted fields. } - else if (Classes[i]->Type()->ParentClass) - type->MetaSize = Classes[i]->Type()->ParentClass->MetaSize; + else if (Classes[i]->ClassType()->ParentClass) + type->MetaSize = Classes[i]->ClassType()->ParentClass->MetaSize; else type->MetaSize = 0; @@ -1207,7 +1207,7 @@ void ZCCCompiler::CompileAllFields() // //========================================================================== -bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren) +bool ZCCCompiler::CompileFields(PContainerType *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren) { while (Fields.Size() > 0) { @@ -1372,7 +1372,7 @@ void ZCCCompiler::CompileAllProperties() for (auto c : Classes) { if (c->Properties.Size() > 0) - CompileProperties(c->Type(), c->Properties, c->Type()->TypeName); + CompileProperties(c->ClassType(), c->Properties, c->Type()->TypeName); } } @@ -1727,7 +1727,7 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt, boo // //========================================================================== -PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PStruct *cls) +PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PContainerType *cls) { TArray indices; @@ -2189,28 +2189,26 @@ void ZCCCompiler::InitDefaults() for (auto c : Classes) { // This may be removed if the conditions change, but right now only subclasses of Actor can define a Default block. - if (!c->Type()->IsDescendantOf(RUNTIME_CLASS(AActor))) + if (!c->ClassType()->IsDescendantOf(RUNTIME_CLASS(AActor))) { if (c->Defaults.Size()) Error(c->cls, "%s: Non-actor classes may not have defaults", c->Type()->TypeName.GetChars()); - if (c->Type()->ParentClass) + if (c->ClassType()->ParentClass) { - auto ti = static_cast(c->Type()); - FString mename = ti->TypeName.GetChars(); - + auto ti = static_cast(c->ClassType()); ti->InitializeDefaults(); } } else { // This should never happen. - if (c->Type()->Defaults != nullptr) + if (c->ClassType()->Defaults != nullptr) { Error(c->cls, "%s already has defaults", c->Type()->TypeName.GetChars()); } // This can only occur if a native parent is not initialized. In all other cases the sorting of the class list should prevent this from ever happening. - else if (c->Type()->ParentClass->Defaults == nullptr && c->Type() != RUNTIME_CLASS(AActor)) + else if (c->ClassType()->ParentClass->Defaults == nullptr && c->ClassType() != RUNTIME_CLASS(AActor)) { - Error(c->cls, "Parent class %s of %s is not initialized", c->Type()->ParentClass->TypeName.GetChars(), c->Type()->TypeName.GetChars()); + Error(c->cls, "Parent class %s of %s is not initialized", c->ClassType()->ParentClass->TypeName.GetChars(), c->ClassType()->TypeName.GetChars()); } else { @@ -2295,7 +2293,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool do { auto type = DetermineType(c->Type(), f, f->Name, t, false, false); - if (type->IsKindOf(RUNTIME_CLASS(PStruct)) && type != TypeVector2 && type != TypeVector3) + if (type->IsKindOf(RUNTIME_CLASS(PContainerType)) && type != TypeVector2 && type != TypeVector3) { // structs and classes only get passed by pointer. type = NewPointer(type); @@ -2749,9 +2747,9 @@ void ZCCCompiler::InitFunctions() for (auto c : Classes) { // cannot be done earlier because it requires the parent class to be processed by this code, too. - if (c->Type()->ParentClass != nullptr) + if (c->ClassType()->ParentClass != nullptr) { - c->Type()->Virtuals = c->Type()->ParentClass->Virtuals; + c->ClassType()->Virtuals = c->ClassType()->ParentClass->Virtuals; } for (auto f : c->Functions) { @@ -2847,7 +2845,7 @@ void ZCCCompiler::CompileStates() for (auto c : Classes) { - if (!c->Type()->IsDescendantOf(RUNTIME_CLASS(AActor))) + if (!c->ClassType()->IsDescendantOf(RUNTIME_CLASS(AActor))) { if (c->States.Size()) Error(c->cls, "%s: States can only be defined for actors.", c->Type()->TypeName.GetChars()); continue; @@ -2855,7 +2853,7 @@ void ZCCCompiler::CompileStates() FString statename; // The state builder wants the label as one complete string, not separated into tokens. FStateDefinitions statedef; - statedef.MakeStateDefines(ValidateActor(c->Type()->ParentClass)); + statedef.MakeStateDefines(ValidateActor(c->ClassType()->ParentClass)); int numframes = 0; for (auto s : c->States) @@ -3050,7 +3048,7 @@ void ZCCCompiler::CompileStates() } try { - GetDefaultByType(c->Type())->Finalize(statedef); + GetDefaultByType(c->ClassType())->Finalize(statedef); } catch (CRecoverableError &err) { @@ -3065,7 +3063,7 @@ void ZCCCompiler::CompileStates() // //========================================================================== -FxExpression *ZCCCompiler::ConvertAST(PStruct *cls, ZCC_TreeNode *ast) +FxExpression *ZCCCompiler::ConvertAST(PContainerType *cls, ZCC_TreeNode *ast) { ConvertClass = cls; // there are two possibilities here: either a single function call or a compound statement. For a compound statement we also need to check if the last thing added was a return. diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index 9d54f925b7..acfbc6b159 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -41,7 +41,7 @@ struct ZCC_StructWork return strct->NodeName; } - PStruct *Type() + PContainerType *Type() { return strct->Type; } @@ -64,7 +64,7 @@ struct ZCC_ClassWork : public ZCC_StructWork Outer = nullptr; } - PClass *Type() + PClass *ClassType() { return static_cast(strct->Type); } @@ -79,7 +79,7 @@ struct ZCC_PropertyWork struct ZCC_ConstantWork { ZCC_ConstantDef *node; - PStruct *cls; + PContainerType *cls; PSymbolTable *Outputtable; ExpVal constval; }; @@ -94,25 +94,25 @@ public: private: const char * GetStringConst(FxExpression *ex, FCompileContext &ctx); - int IntConstFromNode(ZCC_TreeNode *node, PStruct *cls); - FString StringConstFromNode(ZCC_TreeNode *node, PStruct *cls); + int IntConstFromNode(ZCC_TreeNode *node, PContainerType *cls); + FString StringConstFromNode(ZCC_TreeNode *node, PContainerType *cls); void ProcessClass(ZCC_Class *node, PSymbolTreeNode *tnode); void ProcessStruct(ZCC_Struct *node, PSymbolTreeNode *tnode, ZCC_Class *outer); void CreateStructTypes(); void CreateClassTypes(); - void CopyConstants(TArray &dest, TArray &Constants, PStruct *cls, PSymbolTable *ot); + void CopyConstants(TArray &dest, TArray &Constants, PContainerType *cls, PSymbolTable *ot); void CompileAllConstants(); void AddConstant(ZCC_ConstantWork &constant); bool CompileConstant(ZCC_ConstantWork *def); void CompileArrays(ZCC_StructWork *work); void CompileAllFields(); - bool CompileFields(PStruct *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren = false); + bool CompileFields(PContainerType *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren = false); void CompileAllProperties(); bool CompileProperties(PClass *type, TArray &Properties, FName prefix); FString FlagsToString(uint32_t flags); PType *DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes, bool formember); - PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PStruct *cls); + PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PContainerType *cls); PType *ResolveUserType(ZCC_BasicType *type, PSymbolTable *sym, bool nativetype); void InitDefaults(); @@ -143,12 +143,12 @@ private: void Error(ZCC_TreeNode *node, const char *msg, ...) GCCPRINTF(3,4); void MessageV(ZCC_TreeNode *node, const char *txtcolor, const char *msg, va_list argptr); - FxExpression *ConvertAST(PStruct *cclass, ZCC_TreeNode *ast); + FxExpression *ConvertAST(PContainerType *cclass, ZCC_TreeNode *ast); FxExpression *ConvertNode(ZCC_TreeNode *node); FArgumentList &ConvertNodeList(FArgumentList &, ZCC_TreeNode *head); DObject *Outer; - PStruct *ConvertClass; // class type to be used when resoving symbols while converting an AST + PContainerType *ConvertClass; // class type to be used when resoving symbols while converting an AST PSymbolTable *GlobalTreeNodes; PNamespace *OutNamespace; ZCC_AST &AST; diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index 29c6ec20cb..22742ac560 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -195,7 +195,7 @@ struct ZCC_Struct : ZCC_NamedNode { VM_UWORD Flags; ZCC_TreeNode *Body; - PStruct *Type; + PContainerType *Type; VersionInfo Version; };