From fc9e304189f296b1aeece5e85183f1646cf6b8ae Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 Apr 2017 22:46:49 +0200 Subject: [PATCH] - separated class descriptors from VM types. Combining these two groups of data has been the cause of many hard to detect errors because it allowed liberal casting between types that are used for completely different things. --- src/d_dehacked.cpp | 7 +- src/dobjtype.cpp | 285 +++++++++++---------- src/dobjtype.h | 56 ++-- src/dsectoreffect.cpp | 16 +- src/dsectoreffect.h | 27 +- src/info.cpp | 23 -- src/info.h | 1 - src/p_conversation.cpp | 2 +- src/p_things.cpp | 2 +- src/p_user.cpp | 2 +- src/scripting/backend/codegen.cpp | 168 ++++++------ src/scripting/backend/scopebarrier.cpp | 4 +- src/scripting/decorate/thingdef_exp.cpp | 2 +- src/scripting/decorate/thingdef_parse.cpp | 13 +- src/scripting/decorate/thingdef_states.cpp | 2 +- src/scripting/thingdef.cpp | 12 +- src/scripting/thingdef_data.cpp | 63 +++-- src/scripting/thingdef_properties.cpp | 2 +- src/scripting/vm/vm.h | 8 +- src/scripting/vm/vmexec.h | 2 +- src/scripting/zscript/zcc_compile.cpp | 96 +++---- src/scripting/zscript/zcc_compile.h | 2 +- src/scripting/zscript/zcc_parser.h | 2 +- wadsrc/static/zscript/base.txt | 24 +- 24 files changed, 428 insertions(+), 393 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 31a5ec784..2b7f6999a 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -3034,7 +3034,8 @@ void FinishDehPatch () subclass = static_cast(dehtype->CreateDerivedClass(typeNameBuilder, dehtype->Size)); } while (subclass == nullptr); - + NewClassType(subclass); // This needs a VM type to work as intended. + AActor *defaults2 = GetDefaultByType (subclass); memcpy ((void *)defaults2, (void *)defaults1, sizeof(AActor)); @@ -3152,7 +3153,7 @@ DEFINE_ACTION_FUNCTION(ADehackedPickup, DetermineType) int lex = memcmp (DehSpriteMappings[mid].Sprite, sprites[self->sprite].name, 4); if (lex == 0) { - ACTION_RETURN_OBJECT(PClass::FindActor(DehSpriteMappings[mid].ClassName)); + ACTION_RETURN_POINTER(PClass::FindActor(DehSpriteMappings[mid].ClassName)); } else if (lex < 0) { @@ -3163,6 +3164,6 @@ DEFINE_ACTION_FUNCTION(ADehackedPickup, DetermineType) max = mid - 1; } } - ACTION_RETURN_OBJECT(nullptr); + ACTION_RETURN_POINTER(nullptr); } diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 68b300871..c1d36b3db 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -68,6 +68,7 @@ FMemArena ClassDataAllocator(32768); // use this for all static class data that FTypeTable TypeTable; TArray PClass::AllClasses; +TMap PClass::ClassMap; TArray PClass::FunctionPtrList; bool PClass::bShutdown; bool PClass::bVMOperational; @@ -96,6 +97,7 @@ PStruct *TypeStringStruct; PPointer *TypeNullPtr; PPointer *TypeVoidPtr; + // PRIVATE DATA DEFINITIONS ------------------------------------------------ // A harmless non-nullptr FlatPointer for classes without pointers. @@ -1353,8 +1355,16 @@ PPointer::PPointer() PPointer::PPointer(PType *pointsat, bool isconst) : PBasicType(sizeof(void *), alignof(void *)), PointedType(pointsat), IsConst(isconst) { - mDescriptiveName.Format("Pointer<%s%s>", pointsat->DescriptiveName(), isconst? "readonly " : ""); - mVersion = pointsat->mVersion; + if (pointsat != nullptr) + { + mDescriptiveName.Format("Pointer<%s%s>", pointsat->DescriptiveName(), isconst ? "readonly " : ""); + mVersion = pointsat->mVersion; + } + else + { + mDescriptiveName = "Pointer"; + mVersion = 0; + } loadOp = OP_LP; storeOp = OP_SP; moveOp = OP_MOVEA; @@ -1431,7 +1441,7 @@ IMPLEMENT_CLASS(PObjectPointer, false, false) //========================================================================== PObjectPointer::PObjectPointer(PClass *cls, bool isconst) - : PPointer(cls, isconst) + : PPointer(cls->VMType, isconst) { loadOp = OP_LO; // Non-destroyed thinkers are always guaranteed to be linked into the thinker chain so we don't need the write barrier for them. @@ -1484,28 +1494,32 @@ bool PObjectPointer::ReadValue(FSerializer &ar, const char *key, void *addr) con PPointer *NewPointer(PType *type, bool isconst) { - if (type->IsKindOf(RUNTIME_CLASS(PClass))) + auto cp = dyn_cast(type); + if (cp) return NewPointer(cp->Descriptor, isconst); + + size_t bucket; + PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); + if (ptype == nullptr) { - size_t bucket; - PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PObjectPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); - if (ptype == nullptr) - { - ptype = new PObjectPointer(static_cast(type), isconst); - TypeTable.AddType(ptype, RUNTIME_CLASS(PObjectPointer), (intptr_t)type, isconst ? 1 : 0, bucket); - } - return static_cast(ptype); + ptype = new PPointer(type, isconst); + TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, bucket); } - else + return static_cast(ptype); +} + +PPointer *NewPointer(PClass *cls, bool isconst) +{ + assert(cls->VMType != nullptr); + + auto type = cls->VMType; + size_t bucket; + PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PObjectPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); + if (ptype == nullptr) { - size_t bucket; - PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); - if (ptype == nullptr) - { - ptype = new PPointer(type, isconst); - TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, bucket); - } - return static_cast(ptype); + ptype = new PObjectPointer(cls, isconst); + TypeTable.AddType(ptype, RUNTIME_CLASS(PObjectPointer), (intptr_t)type, isconst ? 1 : 0, bucket); } + return static_cast(ptype); } /* PStatePointer **********************************************************/ @@ -1562,13 +1576,13 @@ IMPLEMENT_CLASS(PClassPointer,false, false) //========================================================================== PClassPointer::PClassPointer(PClass *restrict) -: PPointer(RUNTIME_CLASS(PClass)), ClassRestriction(restrict) +: PPointer(restrict->VMType), ClassRestriction(restrict) { if (restrict) mDescriptiveName.Format("ClassPointer<%s>", restrict->TypeName.GetChars()); else mDescriptiveName = "ClassPointer"; loadOp = OP_LP; storeOp = OP_SP; - mVersion = restrict->mVersion; + mVersion = restrict->VMType->mVersion; } //========================================================================== @@ -1614,7 +1628,6 @@ bool PClassPointer::isCompatible(PType *type) void PClassPointer::SetPointer(void *base, unsigned offset, TArray *special) { - // Class pointers do not get added to FlatPointers because they are released from the GC. } //========================================================================== @@ -2590,7 +2603,71 @@ PPrototype *NewPrototype(const TArray &rettypes, const TArray /* PClass *****************************************************************/ -IMPLEMENT_CLASS(PClass, false, false) +IMPLEMENT_CLASS(PClassType, false, false) + +//========================================================================== +// +// +// +//========================================================================== + +PClassType::PClassType(PClass *cls) +{ + assert(cls->VMType == nullptr); + Descriptor = cls; + TypeName = cls->TypeName; + if (cls->ParentClass != nullptr) + { + ParentType = cls->ParentClass->VMType; + assert(ParentType != nullptr); + Symbols.SetParentTable(&ParentType->Symbols); + } + cls->VMType = this; + mDescriptiveName.Format("Class<%s>", cls->TypeName.GetChars()); +} + +//========================================================================== +// +// PClass :: AddField +// +//========================================================================== + +PField *PClassType::AddField(FName name, PType *type, uint32_t flags) +{ + return Descriptor->AddField(name, type, flags); +} + +//========================================================================== +// +// PClass :: AddNativeField +// +//========================================================================== + +PField *PClassType::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue) +{ + auto field = Symbols.AddNativeField(name, type, address, flags, bitvalue); + if (field != nullptr) Descriptor->Fields.Push(field); + return field; +} + +//========================================================================== +// +// +// +//========================================================================== + +PClassType *NewClassType(PClass *cls) +{ + size_t bucket; + PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PClassType), 0, (intptr_t)cls->TypeName, &bucket); + if (ptype == nullptr) + { + ptype = new PClassType(cls); + TypeTable.AddType(ptype, RUNTIME_CLASS(PClassType), 0, (intptr_t)cls->TypeName, bucket); + } + return static_cast(ptype); +} + //========================================================================== // @@ -2619,7 +2696,7 @@ static void RecurseWriteFields(const PClass *type, FSerializer &ar, const void * key.Format("class:%s", type->TypeName.GetChars()); if (ar.BeginObject(key.GetChars())) { - type->Symbols.WriteFields(ar, addr); + type->VMType->Symbols.WriteFields(ar, addr); ar.EndObject(); } break; @@ -2666,19 +2743,11 @@ bool PClass::ReadAllFields(FSerializer &ar, void *addr) const if (type != nullptr) { // Only read it if the type is related to this one. - const PClass *parent; - for (parent = this; parent != nullptr; parent = parent->ParentClass) - { - if (parent == type) - { - break; - } - } - if (parent != nullptr) + if (IsDescendantOf(type)) { if (ar.BeginObject(nullptr)) { - readsomething |= type->Symbols.ReadFields(ar, addr, DescriptiveName()); + readsomething |= type->VMType->Symbols.ReadFields(ar, addr, type->TypeName.GetChars()); ar.EndObject(); } } @@ -2738,15 +2807,6 @@ void PClass::StaticInit () // I'm not sure if this is really necessary to maintain any sort of sync. qsort(&AllClasses[0], AllClasses.Size(), sizeof(AllClasses[0]), cregcmp); - // Set all symbol table relations here so that they are valid right from the start. - for (auto c : AllClasses) - { - if (c->ParentClass != nullptr) - { - c->Symbols.SetParentTable(&c->ParentClass->Symbols); - } - } - } //========================================================================== @@ -2785,7 +2845,6 @@ void PClass::StaticShutdown () // This must be done before the type table is taken down. for (auto cls : AllClasses) { - Printf("Processing %s\n", cls->TypeName.GetChars()); cls->DestroyMeta(cls->Meta); } // Unless something went wrong, anything left here should be class and type objects only, which do not own any scripts. @@ -2814,16 +2873,6 @@ void PClass::StaticShutdown () void PClass::StaticBootstrap() { - PClass *cls = new PClass; - PClass::RegistrationInfo.SetupClass(cls); - - // The PClassClass constructor initialized these to nullptr, because the - // PClass metadata had not been created yet. Now it has, so we know what - // they should be and can insert them into the type table successfully. - cls->InsertIntoHash(); - - // Create parent objects before we go so that these definitions are complete. - cls->ParentClass = PClass::RegistrationInfo.ParentType->RegisterClass(); } //========================================================================== @@ -2834,20 +2883,6 @@ void PClass::StaticBootstrap() PClass::PClass() { - Size = sizeof(DObject); - ParentClass = nullptr; - Pointers = nullptr; - FlatPointers = nullptr; - ArrayPointers = nullptr; - HashNext = nullptr; - Defaults = nullptr; - bRuntimeClass = false; - bExported = false; - bDecorateClass = false; - ConstructNative = nullptr; - Meta = nullptr; - mDescriptiveName = "Class"; - PClass::AllClasses.Push(this); } @@ -2882,12 +2917,6 @@ PClass::~PClass() PClass *ClassReg::RegisterClass() { - static ClassReg *const metaclasses[] = - { - &PClass::RegistrationInfo, - &PClassActor::RegistrationInfo, - }; - // Skip classes that have already been registered if (MyClass != nullptr) { @@ -2895,18 +2924,7 @@ PClass *ClassReg::RegisterClass() } // Add type to list - PClass *cls; - - if (MetaClassNum >= countof(metaclasses)) - { - assert(0 && "Class registry has an invalid meta class identifier"); - } - - if (metaclasses[MetaClassNum]->MyClass == nullptr) - { // Make sure the meta class is already registered before registering this one - metaclasses[MetaClassNum]->RegisterClass(); - } - cls = static_cast(metaclasses[MetaClassNum]->MyClass->CreateNew()); + PClass *cls = new PClass; SetupClass(cls); cls->InsertIntoHash(); @@ -2934,7 +2952,7 @@ void ClassReg::SetupClass(PClass *cls) cls->Size = SizeOf; cls->Pointers = Pointers; cls->ConstructNative = ConstructNative; - cls->mDescriptiveName.Format("Class<%s>", cls->TypeName.GetChars()); + //cls->mDescriptiveName.Format("Class<%s>", cls->TypeName.GetChars()); } //========================================================================== @@ -2947,17 +2965,18 @@ void ClassReg::SetupClass(PClass *cls) void PClass::InsertIntoHash () { - size_t bucket; - PType *found; - - found = TypeTable.FindType(RUNTIME_CLASS(PClass), 0, TypeName, &bucket); - if (found != nullptr) + auto k = ClassMap.CheckKey(TypeName); + if (k != nullptr) { // This type has already been inserted I_Error("Tried to register class '%s' more than once.\n", TypeName.GetChars()); } else { - TypeTable.AddType(this, RUNTIME_CLASS(PClass), 0, TypeName, bucket); + ClassMap[TypeName] = this; + } + if (IsDescendantOf(RUNTIME_CLASS(AActor))) + { + PClassActor::AllActorClasses.Push(static_cast(this)); } } @@ -2995,7 +3014,8 @@ PClass *PClass::FindClass (FName zaname) { return nullptr; } - return static_cast(TypeTable.FindType(RUNTIME_CLASS(PClass), 0, zaname, nullptr)); + auto k = ClassMap.CheckKey(zaname); + return k ? *k : nullptr; } //========================================================================== @@ -3104,10 +3124,7 @@ void PClass::Derive(PClass *newclass, FName name) newclass->bRuntimeClass = true; newclass->ParentClass = this; newclass->ConstructNative = ConstructNative; - newclass->Symbols.SetParentTable(&this->Symbols); newclass->TypeName = name; - newclass->mDescriptiveName.Format("Class<%s>", name.GetChars()); - newclass->mVersion = mVersion; newclass->MetaSize = MetaSize; } @@ -3175,26 +3192,33 @@ void PClass::InitializeDefaults() } } - if (bRuntimeClass) + if (VMType != nullptr) // purely internal classes have no symbol table { - // Copy parent values from the parent defaults. - assert(ParentClass != nullptr); - if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults, &PClass::SpecialInits); + if (bRuntimeClass) + { + // Copy parent values from the parent defaults. + assert(ParentClass != nullptr); + if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults, &PClass::SpecialInits); + for (const PField *field : Fields) + { + if (!(field->Flags & VARF_Native) && !(field->Flags & VARF_Meta)) + { + field->Type->SetDefaultValue(Defaults, unsigned(field->Offset), &SpecialInits); + } + } + } + if (Meta != nullptr) ParentClass->InitializeSpecials(Meta, ParentClass->Meta, &PClass::MetaInits); for (const PField *field : Fields) { - if (!(field->Flags & VARF_Native) && !(field->Flags & VARF_Meta)) + if (!(field->Flags & VARF_Native) && (field->Flags & VARF_Meta)) { - field->Type->SetDefaultValue(Defaults, unsigned(field->Offset), &SpecialInits); + field->Type->SetDefaultValue(Meta, unsigned(field->Offset), &MetaInits); } } } - if (Meta != nullptr) ParentClass->InitializeSpecials(Meta, ParentClass->Meta, &PClass::MetaInits); - for (const PField *field : Fields) + else { - if (!(field->Flags & VARF_Native) && (field->Flags & VARF_Meta)) - { - field->Type->SetDefaultValue(Meta, unsigned(field->Offset), &MetaInits); - } + Printf("VM-less class %s\n", TypeName.GetChars()); } } @@ -3235,7 +3259,7 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) } else { - type = static_cast(GetClass()->CreateNew()); + type = new PClass; notnew = false; } @@ -3245,11 +3269,12 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) type->Size = size; if (size != TentativeClass) { + NewClassType(type); type->InitializeDefaults(); type->Virtuals = Virtuals; } else - type->ObjectFlags &= OF_Transient; + type->bOptional = false; if (!notnew) { @@ -3270,7 +3295,7 @@ PField *PClass::AddField(FName name, PType *type, uint32_t flags) if (!(flags & VARF_Meta)) { unsigned oldsize = Size; - field = Symbols.AddField(name, type, flags, Size); + field = VMType->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 @@ -3285,7 +3310,7 @@ PField *PClass::AddField(FName name, PType *type, uint32_t flags) { // Same as above, but a different data storage. unsigned oldsize = MetaSize; - field = Symbols.AddField(name, type, flags, MetaSize); + field = VMType->Symbols.AddField(name, type, flags, MetaSize); if (field != nullptr && !(flags & VARF_Native) && Meta != nullptr) { @@ -3297,19 +3322,6 @@ PField *PClass::AddField(FName name, PType *type, uint32_t flags) return field; } -//========================================================================== -// -// PClass :: AddNativeField -// -//========================================================================== - -PField *PClass::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue) -{ - auto field = Symbols.AddNativeField(name, type, address, flags, bitvalue); - if (field != nullptr) Fields.Push(field); - return field; -} - //========================================================================== // // PClass :: FindClassTentative @@ -3325,21 +3337,17 @@ PClass *PClass::FindClassTentative(FName name) { return nullptr; } - size_t bucket; - PType *found = TypeTable.FindType(RUNTIME_CLASS(PClass), - /*FIXME:Outer*/0, name, &bucket); + PClass *found = FindClass(name); + if (found != nullptr) return found; - if (found != nullptr) - { - return static_cast(found); - } - PClass *type = static_cast(GetClass()->CreateNew()); + PClass *type = new PClass; DPrintf(DMSG_SPAMMY, "Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); Derive(type, name); type->Size = TentativeClass; - TypeTable.AddType(type, RUNTIME_CLASS(PClass), 0, name, bucket); + + InsertIntoHash(); return type; } @@ -3392,7 +3400,8 @@ int PClass::FindVirtualIndex(FName name, PPrototype *proto) PSymbol *PClass::FindSymbol(FName symname, bool searchparents) const { - return Symbols.FindSymbol(symname, searchparents); + if (VMType == nullptr) return nullptr; + return VMType->Symbols.FindSymbol(symname, searchparents); } //========================================================================== diff --git a/src/dobjtype.h b/src/dobjtype.h index 823c43e2a..dfb362a81 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -587,12 +587,24 @@ enum TentativeClass = UINT_MAX, }; -class PClass : public PContainerType +class PClassType : public PContainerType +{ + DECLARE_CLASS(PClassType, PContainerType); + +private: + +public: + PClass *Descriptor; + PClassType *ParentType; + + PClassType(PClass *cls = nullptr); + 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; +}; + +class PClass { - 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(); @@ -602,26 +614,32 @@ public: void InitializeDefaults(); int FindVirtualIndex(FName name, PPrototype *proto); PSymbol *FindSymbol(FName symname, bool searchparents) const; + PField *AddField(FName name, PType *type, uint32_t flags); static void StaticInit(); static void StaticShutdown(); static void StaticBootstrap(); // Per-class information ------------------------------------- - TArray SpecialInits; - PClass *ParentClass; // the class this class derives from - const size_t *Pointers; // object pointers defined by this class *only* - const size_t *FlatPointers; // object pointers defined by this class and all its superclasses; not initialized by default - const size_t *ArrayPointers; // dynamic arrays containing object pointers. - uint8_t *Defaults; - uint8_t *Meta; // Per-class static script data - unsigned MetaSize; - bool bRuntimeClass; // class was defined at run-time, not compile-time - bool bExported; // This type has been declared in a script - bool bDecorateClass; // may be subject to some idiosyncracies due to DECORATE backwards compatibility + PClass *ParentClass = nullptr; // the class this class derives from + const size_t *Pointers = nullptr; // object pointers defined by this class *only* + const size_t *FlatPointers = nullptr; // object pointers defined by this class and all its superclasses; not initialized by default + const size_t *ArrayPointers = nullptr; // dynamic arrays containing object pointers. + uint8_t *Defaults = nullptr; + uint8_t *Meta = nullptr; // Per-class static script data + unsigned Size = sizeof(DObject); + unsigned MetaSize = 0; + FName TypeName; + FName SourceLumpName; + bool bRuntimeClass = false; // class was defined at run-time, not compile-time + bool bDecorateClass = false; // may be subject to some idiosyncracies due to DECORATE backwards compatibility + bool bAbstract = false; + bool bOptional = false; TArray Virtuals; // virtual function table - FName SourceLumpName; + TArray MetaInits; + TArray SpecialInits; TArray Fields; + PClassType *VMType = nullptr; void (*ConstructNative)(void *); @@ -631,13 +649,10 @@ public: void InsertIntoHash(); 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(); - void InitMeta(); void DestroySpecials(void *addr); void DestroyMeta(void *addr); const PClass *NativeClass() const; @@ -687,6 +702,7 @@ public: static void FindFunction(VMFunction **pptr, FName cls, FName func); PClass *FindClassTentative(FName name); + static TMap ClassMap; static TArray AllClasses; static TArray FunctionPtrList; @@ -719,10 +735,12 @@ PArray *NewArray(PType *type, unsigned int count); PStaticArray *NewStaticArray(PType *type); PDynArray *NewDynArray(PType *type); PPointer *NewPointer(PType *type, bool isconst = false); +PPointer *NewPointer(PClass *type, bool isconst = false); PClassPointer *NewClassPointer(PClass *restrict); PEnum *NewEnum(FName name, PTypeBase *outer); PStruct *NewStruct(FName name, PTypeBase *outer, bool native = false); PPrototype *NewPrototype(const TArray &rettypes, const TArray &argtypes); +PClassType *NewClassType(PClass *cls); // Built-in types ----------------------------------------------------------- diff --git a/src/dsectoreffect.cpp b/src/dsectoreffect.cpp index e02af8ccf..ec257a310 100644 --- a/src/dsectoreffect.cpp +++ b/src/dsectoreffect.cpp @@ -75,16 +75,12 @@ void DSectorEffect::Serialize(FSerializer &arc) DEFINE_FIELD(DSectorEffect, m_Sector) -IMPLEMENT_CLASS(DMover, false, true) +IMPLEMENT_CLASS(DMover, true, true) IMPLEMENT_POINTERS_START(DMover) IMPLEMENT_POINTER(interpolation) IMPLEMENT_POINTERS_END -DMover::DMover () -{ -} - DMover::DMover (sector_t *sector) : DSectorEffect (sector) { @@ -112,11 +108,8 @@ void DMover::StopInterpolation(bool force) } } -IMPLEMENT_CLASS(DMovingFloor, false, false) +IMPLEMENT_CLASS(DMovingFloor, true, false) -DMovingFloor::DMovingFloor () -{ -} DMovingFloor::DMovingFloor (sector_t *sector) : DMover (sector) @@ -125,11 +118,8 @@ DMovingFloor::DMovingFloor (sector_t *sector) interpolation = sector->SetInterpolation(sector_t::FloorMove, true); } -IMPLEMENT_CLASS(DMovingCeiling, false, false) +IMPLEMENT_CLASS(DMovingCeiling, true, false) -DMovingCeiling::DMovingCeiling () -{ -} DMovingCeiling::DMovingCeiling (sector_t *sector, bool interpolate) : DMover (sector) diff --git a/src/dsectoreffect.h b/src/dsectoreffect.h index bdd2aa713..e583a85cd 100644 --- a/src/dsectoreffect.h +++ b/src/dsectoreffect.h @@ -25,16 +25,17 @@ protected: class DMover : public DSectorEffect { - DECLARE_CLASS (DMover, DSectorEffect) + DECLARE_ABSTRACT_CLASS (DMover, DSectorEffect) HAS_OBJECT_POINTERS -public: +protected: DMover (sector_t *sector); - void StopInterpolation(bool force = false); -protected: + TObjPtr interpolation; -private: +public: + void StopInterpolation(bool force = false); + protected: - DMover (); + DMover () {} void Serialize(FSerializer &arc); void OnDestroy() override; @@ -42,20 +43,18 @@ protected: class DMovingFloor : public DMover { - DECLARE_CLASS (DMovingFloor, DMover) -public: - DMovingFloor (sector_t *sector); + DECLARE_ABSTRACT_CLASS (DMovingFloor, DMover) protected: - DMovingFloor (); + DMovingFloor (sector_t *sector); + DMovingFloor() {} }; class DMovingCeiling : public DMover { - DECLARE_CLASS (DMovingCeiling, DMover) -public: - DMovingCeiling (sector_t *sector, bool interpolate = true); + DECLARE_ABSTRACT_CLASS (DMovingCeiling, DMover) protected: - DMovingCeiling (); + DMovingCeiling (sector_t *sector, bool interpolate = true); + DMovingCeiling () {} }; #endif //__DSECTOREFFECT_H__ diff --git a/src/info.cpp b/src/info.cpp index 4c3777af4..7f677bf3a 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -231,8 +231,6 @@ DEFINE_ACTION_FUNCTION(AActor, GetSpriteIndex) ACTION_RETURN_INT(GetSpriteIndex(sprt.GetChars(), false)); } -IMPLEMENT_CLASS(PClassActor, false, false) - //========================================================================== // // PClassActor :: StaticInit STATIC @@ -286,27 +284,6 @@ void PClassActor::StaticSetActorNums() } } -//========================================================================== -// -// PClassActor Constructor -// -//========================================================================== - -PClassActor::PClassActor() -{ - AllActorClasses.Push(this); -} - -//========================================================================== -// -// PClassActor Destructor -// -//========================================================================== - -PClassActor::~PClassActor() -{ -} - //========================================================================== // // PClassActor :: SetReplacement diff --git a/src/info.h b/src/info.h index 907b9a3b2..01a1a3f47 100644 --- a/src/info.h +++ b/src/info.h @@ -288,7 +288,6 @@ struct FActorInfo class PClassActor : public PClass { - DECLARE_CLASS(PClassActor, PClass); protected: public: static void StaticInit (); diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 0e734479a..08399fe49 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -639,7 +639,7 @@ static void TakeStrifeItem (player_t *player, PClassActor *itemtype, int amount) return; // Don't take the sigil. - if (itemtype->GetClass()->TypeName == NAME_Sigil) + if (itemtype->TypeName == NAME_Sigil) return; player->mo->TakeInventory(itemtype, amount); diff --git a/src/p_things.cpp b/src/p_things.cpp index da6f56cac..ac105f4ee 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -526,7 +526,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetSpawnableType) { PARAM_PROLOGUE; PARAM_INT(num); - ACTION_RETURN_OBJECT(P_GetSpawnableType(num)); + ACTION_RETURN_POINTER(P_GetSpawnableType(num)); } struct MapinfoSpawnItem diff --git a/src/p_user.cpp b/src/p_user.cpp index 2a4f000e8..f1f1b31f2 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1242,7 +1242,7 @@ void APlayerPawn::CheckWeaponSwitch(PClassActor *ammotype) DEFINE_ACTION_FUNCTION(APlayerPawn, CheckWeaponSwitch) { PARAM_SELF_PROLOGUE(APlayerPawn); - PARAM_OBJECT(ammotype, PClassActor); + PARAM_POINTER(ammotype, PClassActor); self->CheckWeaponSwitch(ammotype); return 0; } diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index f54ccf1f8..7d731eb5f 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -56,7 +56,7 @@ #include "w_wad.h" #include "math/cmath.h" -inline PClass *PObjectPointer::PointedClass() const { return static_cast(PointedType); } +inline PClass *PObjectPointer::PointedClass() const { return static_cast(PointedType)->Descriptor; } extern FRandom pr_exrandom; FMemArena FxAlloc(65536); @@ -219,15 +219,16 @@ static PClass *FindClassType(FName name, FCompileContext &ctx) if (sym && sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) { auto type = static_cast(sym); - return dyn_cast(type->Type); + auto ctype = dyn_cast(type->Type); + if (ctype) return ctype->Descriptor; } return nullptr; } bool isActor(PContainerType *type) { - auto cls = dyn_cast(type); - return cls ? cls->IsDescendantOf(RUNTIME_CLASS(AActor)) : false; + auto cls = dyn_cast(type); + return cls ? cls->Descriptor->IsDescendantOf(RUNTIME_CLASS(AActor)) : false; } //========================================================================== @@ -1762,13 +1763,13 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) // this is not yet ready and does not get assigned to actual values. } */ - else if (ValueType->IsKindOf(RUNTIME_CLASS(PClass))) // this should never happen because the VM doesn't handle plain class types - just pointers + else if (ValueType->IsKindOf(RUNTIME_CLASS(PClassType))) // this should never happen because the VM doesn't handle plain class types - just pointers { - if (basex->ValueType->IsKindOf(RUNTIME_CLASS(PClass))) + if (basex->ValueType->IsKindOf(RUNTIME_CLASS(PClassType))) { // class types are only compatible if the base type is a descendant of the result type. - auto fromtype = static_cast(basex->ValueType); - auto totype = static_cast(ValueType); + auto fromtype = static_cast(basex->ValueType)->Descriptor; + auto totype = static_cast(ValueType)->Descriptor; if (fromtype->IsDescendantOf(totype)) goto basereturn; } } @@ -5148,7 +5149,7 @@ FxExpression *FxNew::Resolve(FCompileContext &ctx) if (val->isConstant()) { auto cls = static_cast(static_cast(val)->GetValue().GetPointer()); - if (cls->ObjectFlags & OF_Abstract) + if (cls->bAbstract) { ScriptPosition.Message(MSG_ERROR, "Cannot instantiate abstract class %s", cls->TypeName.GetChars()); delete this; @@ -5159,7 +5160,7 @@ FxExpression *FxNew::Resolve(FCompileContext &ctx) int outerside = ctx.Function && ctx.Function->Variants.Size() ? FScopeBarrier::SideFromFlags(ctx.Function->Variants[0].Flags) : FScopeBarrier::Side_Virtual; if (outerside == FScopeBarrier::Side_Virtual) outerside = FScopeBarrier::SideFromObjectFlags(ctx.Class->ObjectFlags); - int innerside = FScopeBarrier::SideFromObjectFlags(cls->ObjectFlags); + int innerside = FScopeBarrier::SideFromObjectFlags(cls->VMType->ObjectFlags); if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) // "cannot construct ui class ... from data context" { ScriptPosition.Message(MSG_ERROR, "Cannot construct %s class %s from %s context", FScopeBarrier::StringFromSide(innerside), cls->TypeName.GetChars(), FScopeBarrier::StringFromSide(outerside)); @@ -6125,7 +6126,7 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType * { PSymbol *sym; PSymbolTable *symtbl; - bool isclass = objtype->IsKindOf(RUNTIME_CLASS(PClass)); + bool isclass = objtype->IsKindOf(RUNTIME_CLASS(PClassType)); if (Identifier == NAME_Default) { @@ -6179,8 +6180,8 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType * object = nullptr; return nullptr; } - PClass* cls_ctx = dyn_cast(classctx); - PClass* cls_target = dyn_cast(objtype); + auto cls_ctx = dyn_cast(classctx); + auto cls_target = dyn_cast(objtype); // [ZZ] neither PSymbol, PField or PSymbolTable have the necessary information. so we need to do the more complex check here. if (vsym->Flags & VARF_Protected) { @@ -6194,7 +6195,7 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType * } // find the class that declared this field. - PClass* p = cls_target; + auto p = cls_target; while (p) { if (&p->Symbols == symtbl) @@ -6203,10 +6204,10 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType * break; } - p = p->ParentClass; + p = p->ParentType; } - if (!cls_ctx->IsDescendantOf(cls_target)) + if (!cls_ctx->Descriptor->IsDescendantOf(cls_target->Descriptor)) { ScriptPosition.Message(MSG_ERROR, "Protected member %s not accessible", vsym->SymbolName.GetChars()); delete object; @@ -6358,32 +6359,29 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) { if (ccls != nullptr) { - if (!ccls->IsKindOf(RUNTIME_CLASS(PClass)) || static_cast(ccls)->bExported) + PSymbol *sym; + if ((sym = ccls->Symbols.FindSymbol(Identifier, true)) != nullptr) { - PSymbol *sym; - if ((sym = ccls->Symbols.FindSymbol(Identifier, true)) != nullptr) + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) { - if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) + ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s.%s' as constant\n", ccls->TypeName.GetChars(), Identifier.GetChars()); + delete this; + return FxConstant::MakeConstant(sym, ScriptPosition); + } + else + { + auto f = dyn_cast(sym); + if (f != nullptr && (f->Flags & (VARF_Static | VARF_ReadOnly | VARF_Meta)) == (VARF_Static | VARF_ReadOnly)) { - ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s.%s' as constant\n", ccls->TypeName.GetChars(), Identifier.GetChars()); + auto x = new FxGlobalVariable(f, ScriptPosition); delete this; - return FxConstant::MakeConstant(sym, ScriptPosition); + return x->Resolve(ctx); } else { - auto f = dyn_cast(sym); - if (f != nullptr && (f->Flags & (VARF_Static | VARF_ReadOnly | VARF_Meta)) == (VARF_Static | VARF_ReadOnly)) - { - auto x = new FxGlobalVariable(f, ScriptPosition); - delete this; - return x->Resolve(ctx); - } - else - { - ScriptPosition.Message(MSG_ERROR, "Unable to access '%s.%s' in a static context\n", ccls->TypeName.GetChars(), Identifier.GetChars()); - delete this; - return nullptr; - } + ScriptPosition.Message(MSG_ERROR, "Unable to access '%s.%s' in a static context\n", ccls->TypeName.GetChars(), Identifier.GetChars()); + delete this; + return nullptr; } } } @@ -7500,9 +7498,9 @@ static bool CheckFunctionCompatiblity(FScriptPosition &ScriptPosition, PFunction bool match = (callingself == calledself); if (!match) { - auto callingselfcls = dyn_cast(caller->Variants[0].SelfClass); - auto calledselfcls = dyn_cast(callee->Variants[0].SelfClass); - match = callingselfcls != nullptr && calledselfcls != nullptr && callingselfcls->IsDescendantOf(calledselfcls); + auto callingselfcls = dyn_cast(caller->Variants[0].SelfClass); + auto calledselfcls = dyn_cast(callee->Variants[0].SelfClass); + match = callingselfcls != nullptr && calledselfcls != nullptr && callingselfcls->Descriptor->IsDescendantOf(calledselfcls->Descriptor); } if (!match) @@ -7613,7 +7611,6 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) } // [ZZ] validate call - PClass* cls = (PClass*)ctx.Class; int outerflags = 0; if (ctx.Function) { @@ -7626,7 +7623,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) // [ZZ] check this at compile time. this would work for most legit cases. if (innerside == FScopeBarrier::Side_Virtual) { - innerside = FScopeBarrier::SideFromObjectFlags(cls->ObjectFlags); + innerside = FScopeBarrier::SideFromObjectFlags(ctx.Class->ObjectFlags); innerflags = FScopeBarrier::FlagsFromSide(innerside); } FScopeBarrier scopeBarrier(outerflags, innerflags, MethodName.GetChars()); @@ -7702,7 +7699,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) } PClass *cls = FindClassType(MethodName, ctx); - if (cls != nullptr && cls->bExported) + if (cls != nullptr) { if (CheckArgSize(MethodName, ArgList, 1, 1, ScriptPosition)) { @@ -7863,14 +7860,17 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) if (CheckArgSize(MethodName, ArgList, 0, 1, ScriptPosition)) { // [ZZ] allow implicit new() call to mean "create current class instance" - if (!ArgList.Size() && !ctx.Class->IsKindOf(RUNTIME_CLASS(PClass))) + if (!ArgList.Size() && !ctx.Class->IsKindOf(RUNTIME_CLASS(PClassType))) { ScriptPosition.Message(MSG_ERROR, "Cannot use implicit new() in a struct"); delete this; return nullptr; } else if (!ArgList.Size()) - ArgList.Push(new FxConstant((PClass*)ctx.Class, NewClassPointer((PClass*)ctx.Class), ScriptPosition)); + { + auto cls = static_cast(ctx.Class)->Descriptor; + ArgList.Push(new FxConstant(cls, NewClassPointer(cls), ScriptPosition)); + } func = new FxNew(ArgList[0]); ArgList[0] = nullptr; @@ -7967,40 +7967,37 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) { if (ccls != nullptr) { - if (!ccls->IsKindOf(RUNTIME_CLASS(PClass)) || static_cast(ccls)->bExported) + cls = ccls; + staticonly = true; + if (ccls->IsKindOf(RUNTIME_CLASS(PClassType))) { - cls = ccls; - staticonly = true; - if (ccls->IsKindOf(RUNTIME_CLASS(PClass))) + if (ctx.Function == nullptr) { - if (ctx.Function == nullptr) + ScriptPosition.Message(MSG_ERROR, "Unable to call %s from constant declaration", MethodName.GetChars()); + delete this; + return nullptr; + } + auto clstype = dyn_cast(ctx.Function->Variants[0].SelfClass); + if (clstype != nullptr) + { + novirtual = clstype->Descriptor->IsDescendantOf(static_cast(ccls)->Descriptor); + if (novirtual) { - ScriptPosition.Message(MSG_ERROR, "Unable to call %s from constant declaration", MethodName.GetChars()); - delete this; - return nullptr; - } - auto clstype = dyn_cast(ctx.Function->Variants[0].SelfClass); - if (clstype != nullptr) - { - novirtual = clstype->IsDescendantOf(static_cast(ccls)); - if (novirtual) + bool error; + PFunction *afd = FindClassMemberFunction(ccls, ctx.Class, MethodName, ScriptPosition, &error); + if ((afd->Variants[0].Flags & VARF_Method) && (afd->Variants[0].Flags & VARF_Virtual)) { - bool error; - PFunction *afd = FindClassMemberFunction(ccls, ctx.Class, MethodName, ScriptPosition, &error); - if ((afd->Variants[0].Flags & VARF_Method) && (afd->Variants[0].Flags & VARF_Virtual)) - { - staticonly = false; - novirtual = true; - delete Self; - Self = new FxSelf(ScriptPosition); - Self->ValueType = NewPointer(cls); - } - else novirtual = false; + staticonly = false; + novirtual = true; + delete Self; + Self = new FxSelf(ScriptPosition); + Self->ValueType = NewPointer(cls); } + else novirtual = false; } } - if (!novirtual) goto isresolved; } + if (!novirtual) goto isresolved; } } @@ -8012,11 +8009,11 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) delete this; return nullptr; } - auto clstype = dyn_cast(ctx.Function->Variants[0].SelfClass); + auto clstype = dyn_cast(ctx.Function->Variants[0].SelfClass); if (clstype != nullptr) { // give the node the proper value type now that we know it's properly used. - cls = clstype->ParentClass; + cls = clstype->ParentType; Self->ValueType = NewPointer(cls); Self->ExprType = EFX_Self; novirtual = true; // super calls are always non-virtual @@ -8230,7 +8227,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) auto ptype = static_cast(Self->ValueType)->PointedType; if (ptype->IsKindOf(RUNTIME_CLASS(PContainerType))) { - if (ptype->IsKindOf(RUNTIME_CLASS(PClass)) && MethodName == NAME_GetClass) + if (ptype->IsKindOf(RUNTIME_CLASS(PClassType)) && MethodName == NAME_GetClass) { if (ArgList.Size() > 0) { @@ -8333,9 +8330,9 @@ isresolved: { if (!novirtual || !(afd->Variants[0].Flags & VARF_Virtual)) { - auto clstype = dyn_cast(ctx.Class); - auto ccls = dyn_cast(cls); - if (clstype == nullptr || ccls == nullptr || !clstype->IsDescendantOf(ccls)) + auto clstype = dyn_cast(ctx.Class); + auto ccls = dyn_cast(cls); + if (clstype == nullptr || ccls == nullptr || !clstype->Descriptor->IsDescendantOf(ccls->Descriptor)) { ScriptPosition.Message(MSG_ERROR, "Cannot call non-static function %s::%s from here", cls->TypeName.GetChars(), MethodName.GetChars()); delete this; @@ -9303,7 +9300,7 @@ FxExpression *FxGetClass::Resolve(FCompileContext &ctx) delete this; return nullptr; } - ValueType = NewClassPointer(static_cast(static_cast(Self->ValueType)->PointedType)); + ValueType = NewClassPointer(static_cast(static_cast(Self->ValueType)->PointedType)->Descriptor); return this; } @@ -10639,7 +10636,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) if (Explicit) cls = FindClassType(clsname, ctx); else cls = PClass::FindClass(clsname); - if (cls == nullptr) + if (cls == nullptr || cls->VMType == nullptr) { /* lax */ // Since this happens in released WADs it must pass without a terminal error... :( @@ -10694,7 +10691,7 @@ int BuiltinNameToClass(VMValue *param, TArray &defaultparam, int numpar const PClass *cls = PClass::FindClass(clsname); const PClass *desttype = reinterpret_cast(param[1].a); - if (!cls->IsDescendantOf(desttype)) + if (cls->VMType == nullptr || !cls->IsDescendantOf(desttype)) { // Let the caller check this. Making this an error with a message is only taking away options from the user. cls = nullptr; @@ -10851,7 +10848,9 @@ FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); ABORT(ctx.Class); - auto aclass = dyn_cast(ctx.Class); + auto vclass = dyn_cast(ctx.Class); + assert(vclass != nullptr); + auto aclass = ValidateActor(vclass->Descriptor); // This expression type can only be used from actors, for everything else it has already produced a compile error. assert(aclass != nullptr && aclass->GetStateCount() > 0); @@ -10927,8 +10926,12 @@ FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx) Index = new FxIntCast(Index, ctx.FromDecorate); SAFE_RESOLVE(Index, ctx); } - auto aclass = dyn_cast(ctx.Class); + + auto vclass = dyn_cast(ctx.Class); + assert(vclass != nullptr); + auto aclass = ValidateActor(vclass->Descriptor); assert(aclass != nullptr && aclass->GetStateCount() > 0); + symlabel = StateLabels.AddPointer(aclass->GetStates() + ctx.StateIndex); ValueType = TypeStateLabel; return this; @@ -10983,7 +10986,10 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) CHECKRESOLVED(); ABORT(ctx.Class); int symlabel; - auto clstype = dyn_cast(ctx.Class); + + auto vclass = dyn_cast(ctx.Class); + assert(vclass != nullptr); + auto clstype = ValidateActor(vclass->Descriptor); if (names[0] == NAME_None) { diff --git a/src/scripting/backend/scopebarrier.cpp b/src/scripting/backend/scopebarrier.cpp index 29caa2457..f227e0240 100644 --- a/src/scripting/backend/scopebarrier.cpp +++ b/src/scripting/backend/scopebarrier.cpp @@ -175,14 +175,14 @@ void FScopeBarrier::AddFlags(int flags1, int flags2, const char* name) // these are for vmexec.h void FScopeBarrier::ValidateNew(PClass* cls, int outerside) { - int innerside = FScopeBarrier::SideFromObjectFlags(cls->ObjectFlags); + int innerside = FScopeBarrier::SideFromObjectFlags(cls->VMType->ObjectFlags); if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) // "cannot construct ui class ... from data context" ThrowAbortException(X_OTHER, "Cannot construct %s class %s from %s context", FScopeBarrier::StringFromSide(innerside), cls->TypeName.GetChars(), FScopeBarrier::StringFromSide(outerside)); } void FScopeBarrier::ValidateCall(PClass* selftype, VMFunction *calledfunc, int outerside) { - int innerside = FScopeBarrier::SideFromObjectFlags(selftype->ObjectFlags); + int innerside = FScopeBarrier::SideFromObjectFlags(selftype->VMType->ObjectFlags); if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) ThrowAbortException(X_OTHER, "Cannot call %s function %s from %s context", FScopeBarrier::StringFromSide(innerside), calledfunc->PrintableName.GetChars(), FScopeBarrier::StringFromSide(outerside)); } \ No newline at end of file diff --git a/src/scripting/decorate/thingdef_exp.cpp b/src/scripting/decorate/thingdef_exp.cpp index 56aaf25df..d3acae632 100644 --- a/src/scripting/decorate/thingdef_exp.cpp +++ b/src/scripting/decorate/thingdef_exp.cpp @@ -88,7 +88,7 @@ FxExpression *ParseExpression (FScanner &sc, PClassActor *cls, PNamespace *spc) if (spc) { - FCompileContext ctx(spc, cls, true); + FCompileContext ctx(spc, cls->VMType, true); data = data->Resolve(ctx); } diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index ea1c50ee4..4758aaa23 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -69,9 +69,9 @@ EXTERN_CVAR(Bool, strictdecorate); PClassActor *DecoDerivedClass(const FScriptPosition &sc, PClassActor *parent, FName typeName) { - if (parent->mVersion > MakeVersion(2, 0)) + if (parent->VMType->mVersion > MakeVersion(2, 0)) { - sc.Message(MSG_ERROR, "Parent class %s of %s not accessible to DECORATE", parent->GetClass()->TypeName.GetChars(), typeName.GetChars()); + sc.Message(MSG_ERROR, "Parent class %s of %s not accessible to DECORATE", parent->TypeName.GetChars(), typeName.GetChars()); } PClassActor *type = static_cast(parent->CreateDerivedClass(typeName, parent->Size)); if (type == nullptr) @@ -101,7 +101,8 @@ PClassActor *DecoDerivedClass(const FScriptPosition &sc, PClassActor *parent, FN if (type != nullptr) { // [ZZ] DECORATE classes are always play - type->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(type->ObjectFlags, FScopeBarrier::Side_Play); + auto vmtype = type->VMType; + vmtype->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(vmtype->ObjectFlags, FScopeBarrier::Side_Play); } return type; @@ -1151,15 +1152,15 @@ static void ParseActor(FScanner &sc, PNamespace *ns) switch (sc.TokenType) { case TK_Const: - ParseConstant (sc, &info->Symbols, info, ns); + ParseConstant (sc, &info->VMType->Symbols, info, ns); break; case TK_Enum: - ParseEnum (sc, &info->Symbols, info, ns); + ParseEnum (sc, &info->VMType->Symbols, info, ns); break; case TK_Var: - ParseUserVariable (sc, &info->Symbols, info, ns); + ParseUserVariable (sc, &info->VMType->Symbols, info, ns); break; case TK_Identifier: diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index 3aa4c5afb..a5f48aa6c 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -339,7 +339,7 @@ do_stop: endofstate: if (ScriptCode != nullptr) { - auto funcsym = CreateAnonymousFunction(actor, nullptr, state.UseFlags); + auto funcsym = CreateAnonymousFunction(actor->VMType, nullptr, state.UseFlags); state.ActionFunc = FunctionBuildList.AddFunction(bag.Namespace, bag.Version, funcsym, ScriptCode, FStringf("%s.StateFunction.%d", actor->TypeName.GetChars(), bag.statedef.GetStateCount()), true, bag.statedef.GetStateCount(), int(statestring.Len()), sc.LumpNum); } int count = bag.statedef.AddStates(&state, statestring, scp); diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 4eb0098dd..14fd21886 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -195,8 +195,8 @@ PFunction *FindClassMemberFunction(PContainerType *selfcls, PContainerType *func if (symbol != nullptr) { - PClass* cls_ctx = dyn_cast(funccls); - PClass* cls_target = funcsym?dyn_cast(funcsym->OwningClass):nullptr; + auto cls_ctx = dyn_cast(funccls); + auto cls_target = funcsym ? dyn_cast(funcsym->OwningClass) : nullptr; if (funcsym == nullptr) { sc.Message(MSG_ERROR, "%s is not a member function of %s", name.GetChars(), selfcls->TypeName.GetChars()); @@ -206,7 +206,7 @@ PFunction *FindClassMemberFunction(PContainerType *selfcls, PContainerType *func // private access is only allowed if the symbol table belongs to the class in which the current function is being defined. sc.Message(MSG_ERROR, "%s is declared private and not accessible", symbol->SymbolName.GetChars()); } - else if ((funcsym->Variants[0].Flags & VARF_Protected) && symtable != &funccls->Symbols && (!cls_ctx || !cls_target || !cls_ctx->IsDescendantOf((PClass*)cls_target))) + else if ((funcsym->Variants[0].Flags & VARF_Protected) && symtable != &funccls->Symbols && (!cls_ctx || !cls_target || !cls_ctx->Descriptor->IsDescendantOf(cls_target->Descriptor))) { sc.Message(MSG_ERROR, "%s is declared protected and not accessible", symbol->SymbolName.GetChars()); } @@ -236,7 +236,7 @@ void CreateDamageFunction(PNamespace *OutNamespace, const VersionInfo &ver, PCla else { auto dmg = new FxReturnStatement(new FxIntCast(id, true), id->ScriptPosition); - auto funcsym = CreateAnonymousFunction(info, TypeSInt32, 0); + auto funcsym = CreateAnonymousFunction(info->VMType, TypeSInt32, 0); defaults->DamageFunc = FunctionBuildList.AddFunction(OutNamespace, ver, funcsym, dmg, FStringf("%s.DamageFunction", info->TypeName.GetChars()), fromDecorate, -1, 0, lumpnum); } } @@ -373,6 +373,7 @@ static void CheckStates(PClassActor *obj) //========================================================================== void ParseScripts(); void ParseAllDecorate(); +void SynthesizeFlagFields(); void LoadActors() { @@ -387,6 +388,7 @@ void LoadActors() FScriptPosition::StrictErrors = false; ParseAllDecorate(); + SynthesizeFlagFields(); FunctionBuildList.Build(); @@ -401,7 +403,7 @@ void LoadActors() auto ti = PClassActor::AllActorClasses[i]; if (ti->Size == TentativeClass) { - if (ti->ObjectFlags & OF_Transient) + if (ti->bOptional) { Printf(TEXTCOLOR_ORANGE "Class %s referenced but not defined\n", ti->TypeName.GetChars()); FScriptPosition::WarnCounter++; diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index fe3a35933..5bbeb9296 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -67,7 +67,14 @@ static TArray AFTable; static TArray FieldTable; extern int BackbuttonTime; extern float BackbuttonAlpha; -static AWeapon *wpnochg; + +// Argh. It sucks when bad hacks need to be supported. WP_NOCHANGE is just a bogus pointer but is used everywhere as a special flag. +// It cannot be defined as constant because constants can either be numbers or strings but nothing else, so the only 'solution' +// is to create a static variable from it that points to an otherwise unused object and reference that in the script. Yuck!!! +// This must point to a valid DObject derived object so that the garbage collector can deal with it. +// The global VM types are the most convenient options here because they get created before the compiler is started and they +// are not exposed in other ways to scripts - and they do not change unless the engine is shut down. +DEFINE_GLOBAL_NAMED(TypeSInt32, wp_nochange); //========================================================================== // @@ -505,6 +512,7 @@ static const struct FFlagList { const PClass * const *Type; FFlagDef *Defs; int { &RUNTIME_CLASS_CASTLESS(AInventory), InventoryFlagDefs, countof(InventoryFlagDefs), 3 }, { &RUNTIME_CLASS_CASTLESS(AWeapon), WeaponFlagDefs, countof(WeaponFlagDefs), 3 }, { &RUNTIME_CLASS_CASTLESS(APlayerPawn), PlayerPawnFlagDefs, countof(PlayerPawnFlagDefs), 3 }, + { &RUNTIME_CLASS_CASTLESS(ADynamicLight),DynLightFlagDefs, countof(DynLightFlagDefs), 3 }, }; #define NUM_FLAG_LISTS (countof(FlagLists)) @@ -890,29 +898,6 @@ void InitThingdef() auto wbplayerstruct = NewStruct("WBPlayerStruct", nullptr, true); wbplayerstruct->Size = sizeof(wbplayerstruct_t); wbplayerstruct->Align = alignof(wbplayerstruct_t); - - - // Argh. It sucks when bad hacks need to be supported. WP_NOCHANGE is just a bogus pointer but it used everywhere as a special flag. - // It cannot be defined as constant because constants can either be numbers or strings but nothing else, so the only 'solution' - // is to create a static variable from it and reference that in the script. Yuck!!! - wpnochg = WP_NOCHANGE; - PField *fieldptr = new PField("WP_NOCHANGE", NewPointer(RUNTIME_CLASS(AWeapon), false), VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&wpnochg); - Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); - - // synthesize a symbol for each flag from the flag name tables to avoid redundant declaration of them. - for (auto &fl : FlagLists) - { - if (fl.Use & 2) - { - for(int i=0;i 0) // skip the deprecated entries in this list - { - const_cast(*fl.Type)->AddNativeField(FStringf("b%s", fl.Defs[i].name), (fl.Defs[i].fieldsize == 4 ? TypeSInt32 : TypeSInt16), fl.Defs[i].structoffset, fl.Defs[i].varflags, fl.Defs[i].flagbit); - } - } - } - } FAutoSegIterator probe(CRegHead, CRegTail); @@ -980,9 +965,37 @@ void InitThingdef() FieldTable.ShrinkToFit(); qsort(&FieldTable[0], FieldTable.Size(), sizeof(FieldTable[0]), fieldcmp); } - } +void SynthesizeFlagFields() +{ + // These are needed for inserting the flag symbols + /* + NewClassType(RUNTIME_CLASS(DObject)); + NewClassType(RUNTIME_CLASS(DThinker)); + NewClassType(RUNTIME_CLASS(AActor)); + NewClassType(RUNTIME_CLASS(AInventory)); + NewClassType(RUNTIME_CLASS(AStateProvider)); + NewClassType(RUNTIME_CLASS(AWeapon)); + NewClassType(RUNTIME_CLASS(APlayerPawn)); + NewClassType(RUNTIME_CLASS(ADynamicLight)); + */ + // synthesize a symbol for each flag from the flag name tables to avoid redundant declaration of them. + for (auto &fl : FlagLists) + { + auto cls = const_cast(*fl.Type); + if (fl.Use & 2) + { + for (int i = 0; i < fl.NumDefs; i++) + { + if (fl.Defs[i].structoffset > 0) // skip the deprecated entries in this list + { + cls->VMType->AddNativeField(FStringf("b%s", fl.Defs[i].name), (fl.Defs[i].fieldsize == 4 ? TypeSInt32 : TypeSInt16), fl.Defs[i].structoffset, fl.Defs[i].varflags, fl.Defs[i].flagbit); + } + } + } + } +} DEFINE_ACTION_FUNCTION(DObject, GameType) { PARAM_PROLOGUE; diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 0d363c2be..0084c319c 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -92,7 +92,7 @@ static PClassActor *FindClassTentative(const char *name, PClass *ancestor, bool } if (cls->Size == TentativeClass && optional) { - cls->ObjectFlags |= OF_Transient; // since this flag has no meaning in class types, let's use it for marking the type optional. + cls->bOptional = true; } return static_cast(cls); } diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index a0103c83d..d05e33a5f 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -834,10 +834,10 @@ bool AssertObject(void * ob); #define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a; #define PARAM_POINTERTYPE_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type x = (type )param[p].a; #define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && AssertObject(param[p].a)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); -#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && AssertObject(param[p].a)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); +#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); #define PARAM_POINTER_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x); #define PARAM_OBJECT_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (AssertObject(param[p].a))); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); -#define PARAM_CLASS_NOT_NULL_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (AssertObject(param[p].a))); base::MetaClass *x = (base::MetaClass *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); +#define PARAM_CLASS_NOT_NULL_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); base::MetaClass *x = (base::MetaClass *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); #define PARAM_EXISTS(p) ((p) < numparam) @@ -853,8 +853,8 @@ bool AssertObject(void * ob); #define PARAM_STATE_ACTION_DEF_AT(p,x) FState *x; if (PARAM_EXISTS(p)) { ASSERTINT(param[p]); x = (FState*)StateLabels.GetState(param[p].i, stateowner->GetClass()); } else { ASSERTINT(defaultparam[p]); x = (FState*)StateLabels.GetState(defaultparam[p].i, stateowner->GetClass()); } #define PARAM_POINTER_DEF_AT(p,x,t) t *x; if (PARAM_EXISTS(p)) { ASSERTPOINTER(param[p]); x = (t*)param[p].a; } else { ASSERTPOINTER(defaultparam[p]); x = (t*)defaultparam[p].a; } #define PARAM_OBJECT_DEF_AT(p,x,t) t *x; if (PARAM_EXISTS(p)) { ASSERTOBJECT(param[p]); x = (t*)param[p].a; } else { ASSERTOBJECT(defaultparam[p]); x = (t*)defaultparam[p].a; } -#define PARAM_CLASS_DEF_AT(p,x,t) t::MetaClass *x; if (PARAM_EXISTS(p)) { ASSERTOBJECT(param[p]); x = (t::MetaClass*)param[p].a; } else { ASSERTOBJECT(defaultparam[p]); x = (t::MetaClass*)defaultparam[p].a; } -#define PARAM_CLASS_DEF_NOT_NULL_AT(p,x,t) t::MetaClass *x; if (PARAM_EXISTS(p)) { ASSERTOBJECT(param[p]); x = (t::MetaClass*)PARAM_NULLCHECK(param[p].a, #x); } else { ASSERTOBJECT(defaultparam[p]); x = (t::MetaClass*)PARAM_NULLCHECK(defaultparam[p].a, #x); } +#define PARAM_CLASS_DEF_AT(p,x,t) t::MetaClass *x; if (PARAM_EXISTS(p)) { x = (t::MetaClass*)param[p].a; } else { ASSERTPOINTER(defaultparam[p]); x = (t::MetaClass*)defaultparam[p].a; } +#define PARAM_CLASS_DEF_NOT_NULL_AT(p,x,t) t::MetaClass *x; if (PARAM_EXISTS(p)) { x = (t::MetaClass*)PARAM_NULLCHECK(param[p].a, #x); } else { x = (t::MetaClass*)PARAM_NULLCHECK(defaultparam[p].a, #x); } // The above, but with an automatically increasing position index. #define PARAM_PROLOGUE int paramnum = -1; diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index adb0480de..a62627cc4 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -791,7 +791,7 @@ static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret) { ThrowAbortException(X_OTHER, "Class %s requires native construction", cls->TypeName.GetChars()); } - if (cls->ObjectFlags & OF_Abstract) + if (cls->bAbstract) { ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars()); } diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 9ebed3c6b..677b5f11e 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -51,6 +51,8 @@ #include "backend/vmbuilder.h" FSharedStringArena VMStringConstants; +bool isActor(PContainerType *type); + static int GetIntConst(FxExpression *ex, FCompileContext &ctx) { @@ -496,8 +498,8 @@ void ZCCCompiler::CreateStructTypes() s->Outer = s->OuterDef == nullptr? nullptr : s->OuterDef->CType(); if (s->Outer) { - outer = s->Outer; - syms = &s->Outer->Symbols; + outer = s->Outer->VMType; + syms = &s->Outer->VMType->Symbols; } else { @@ -603,7 +605,7 @@ void ZCCCompiler::CreateClassTypes() parent = RUNTIME_CLASS(DObject); } - if (parent != nullptr) + if (parent != nullptr && (parent->VMType != nullptr || c->NodeName() == NAME_Object)) { // The parent exists, we may create a type for this class if (c->cls->Flags & ZCC_Native) @@ -624,7 +626,7 @@ void ZCCCompiler::CreateClassTypes() { DPrintf(DMSG_SPAMMY, "Registered %s as native with parent %s\n", me->TypeName.GetChars(), parent->TypeName.GetChars()); } - c->cls->Type = me; + c->cls->Type = NewClassType(me); me->SourceLumpName = *c->cls->SourceName; } else @@ -632,25 +634,33 @@ void ZCCCompiler::CreateClassTypes() // We will never get here if the name is a duplicate, so we can just do the assignment. try { - if (parent->mVersion > mVersion) + if (parent->VMType->mVersion > mVersion) { Error(c->cls, "Parent class %s of %s not accessible to ZScript version %d.%d.%d", parent->TypeName.GetChars(), c->NodeName().GetChars(), mVersion.major, mVersion.minor, mVersion.revision); } - c->cls->Type = parent->CreateDerivedClass(c->NodeName(), TentativeClass); - if (c->Type() == nullptr) + auto newclass = parent->CreateDerivedClass(c->NodeName(), TentativeClass); + if (newclass == nullptr) { 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->ClassType()->ParentClass->TypeName.GetChars()); + else + { + c->cls->Type = NewClassType(newclass); + DPrintf(DMSG_SPAMMY, "Created class %s with parent %s\n", c->Type()->TypeName.GetChars(), c->ClassType()->ParentClass->TypeName.GetChars()); + } } catch (CRecoverableError &err) { Error(c->cls, "%s", err.GetMessage()); - // create a placeholder so that the compiler can continue looking for errors. c->cls->Type = nullptr; } } - if (c->Type() == nullptr) c->cls->Type = parent->FindClassTentative(c->NodeName()); + if (c->Type() == nullptr) + { + // create a placeholder so that the compiler can continue looking for errors. + c->cls->Type = NewClassType(parent->FindClassTentative(c->NodeName())); + } + if (c->cls->Flags & ZCC_Abstract) c->Type()->ObjectFlags |= OF_Abstract; @@ -675,13 +685,13 @@ void ZCCCompiler::CreateClassTypes() c->Type()->ObjectFlags = (c->Type()->ObjectFlags&~OF_Play) | OF_UI; if (c->cls->Flags & ZCC_Play) c->Type()->ObjectFlags = (c->Type()->ObjectFlags&~OF_UI) | OF_Play; - if (parent->ObjectFlags & (OF_UI | OF_Play)) // parent is either ui or play + if (parent->VMType->ObjectFlags & (OF_UI | OF_Play)) // parent is either ui or play { if (c->cls->Flags & (ZCC_UIFlag | ZCC_Play)) { Error(c->cls, "Can't change class scope in class %s", c->NodeName().GetChars()); } - c->Type()->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(c->Type()->ObjectFlags, FScopeBarrier::SideFromObjectFlags(parent->ObjectFlags)); + c->Type()->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(c->Type()->ObjectFlags, FScopeBarrier::SideFromObjectFlags(parent->VMType->ObjectFlags)); } } else @@ -689,14 +699,13 @@ void ZCCCompiler::CreateClassTypes() c->Type()->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(c->Type()->ObjectFlags, FScopeBarrier::Side_Play); } - 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); OrigClasses.Delete(i--); donesomething = true; } - else + else if (c->cls->ParentName != nullptr) { // No base class found. Now check if something in the unprocessed classes matches. // If not, print an error. If something is found let's retry again in the next iteration. @@ -713,7 +722,7 @@ void ZCCCompiler::CreateClassTypes() { Error(c->cls, "Class %s has unknown base class %s", c->NodeName().GetChars(), FName(c->cls->ParentName->Id).GetChars()); // create a placeholder so that the compiler can continue looking for errors. - c->cls->Type = RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName()); + c->cls->Type = NewClassType(RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName())); c->cls->Symbol = new PSymbolType(c->NodeName(), c->Type()); OutNamespace->Symbols.AddSymbol(c->cls->Symbol); Classes.Push(c); @@ -729,7 +738,7 @@ void ZCCCompiler::CreateClassTypes() for (auto c : OrigClasses) { Error(c->cls, "Class %s has circular inheritance", FName(c->NodeName()).GetChars()); - c->cls->Type = RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName()); + c->cls->Type = NewClassType(RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName())); c->cls->Symbol = new PSymbolType(c->NodeName(), c->Type()); OutNamespace->Symbols.AddSymbol(c->cls->Symbol); Classes.Push(c); @@ -753,7 +762,7 @@ void ZCCCompiler::CreateClassTypes() } } - if (cd->cls->Replaces != nullptr && !static_cast(cd->Type())->SetReplacement(cd->cls->Replaces->Id)) + if (cd->cls->Replaces != nullptr && !static_cast(cd->ClassType())->SetReplacement(cd->cls->Replaces->Id)) { Warn(cd->cls, "Replaced type '%s' not found for %s", FName(cd->cls->Replaces->Id).GetChars(), cd->Type()->TypeName.GetChars()); } @@ -1131,7 +1140,7 @@ void ZCCCompiler::CompileAllFields() // We need to search the global class table here because not all children may have a scripted definition attached. for (auto ac : PClass::AllClasses) { - if (ac->ParentClass == c->Type() && ac->Size != TentativeClass) + if (ac->ParentClass != nullptr && ac->ParentClass->VMType == c->Type() && ac->Size != TentativeClass) { // Only set a marker here, so that we can print a better message when the actual fields get added. HasNativeChildren.Insert(ac, true); @@ -1180,7 +1189,7 @@ void ZCCCompiler::CompileAllFields() else type->MetaSize = 0; - if (CompileFields(type, Classes[i]->Fields, nullptr, &Classes[i]->TreeNodes, false, !!HasNativeChildren.CheckKey(type))) + if (CompileFields(type->VMType, Classes[i]->Fields, nullptr, &Classes[i]->TreeNodes, false, !!HasNativeChildren.CheckKey(type))) { // Remove from the list if all fields got compiled. Classes.Delete(i--); @@ -1423,7 +1432,7 @@ bool ZCCCompiler::CompileProperties(PClass *type, TArray &Proper else qualifiedname.Format("@property@%s.%s", prefix.GetChars(), name.GetChars()); fields.ShrinkToFit(); - if (!type->Symbols.AddSymbol(new PProperty(qualifiedname, fields))) + if (!type->VMType->Symbols.AddSymbol(new PProperty(qualifiedname, fields))) { Error(id, "Unable to add property %s to class %s", FName(p->NodeName).GetChars(), type->TypeName.GetChars()); } @@ -1648,7 +1657,7 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n return TypeError; } auto typesym = dyn_cast(sym); - if (typesym == nullptr || !typesym->Type->IsKindOf(RUNTIME_CLASS(PClass))) + if (typesym == nullptr || !typesym->Type->IsKindOf(RUNTIME_CLASS(PClassType))) { Error(field, "%s does not represent a class type", FName(ctype->Restriction->Id).GetChars()); return TypeError; @@ -1658,7 +1667,7 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n Error(field, "Class %s not accessible to ZScript version %d.%d.%d", FName(ctype->Restriction->Id).GetChars(), mVersion.major, mVersion.minor, mVersion.revision); return TypeError; } - retval = NewClassPointer(static_cast(typesym->Type)); + retval = NewClassPointer(static_cast(typesym->Type)->Descriptor); } break; } @@ -1703,7 +1712,7 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt, boo { if (!nativetype) return TypeSInt32; // hack this to an integer until we can resolve the enum mess. } - else if (ptype->IsKindOf(RUNTIME_CLASS(PClass))) // classes cannot be instantiated at all, they always get used as references. + else if (ptype->IsKindOf(RUNTIME_CLASS(PClassType))) // classes cannot be instantiated at all, they always get used as references. { return NewPointer(ptype, type->isconst); } @@ -1789,7 +1798,7 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper const char * p = prop->params; auto exp = property->Values; - FCompileContext ctx(OutNamespace, bag.Info, false); + FCompileContext ctx(OutNamespace, bag.Info->VMType, false); while (true) { FPropParam conv; @@ -1971,7 +1980,7 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop } auto exp = property->Values; - FCompileContext ctx(OutNamespace, bag.Info, false); + FCompileContext ctx(OutNamespace, bag.Info->VMType, false); for (auto f : prop->Variables) { void *addr; @@ -2200,20 +2209,21 @@ void ZCCCompiler::InitDefaults() } else { + auto cls = c->ClassType(); // This should never happen. - if (c->ClassType()->Defaults != nullptr) + if (cls->Defaults != nullptr) { - Error(c->cls, "%s already has defaults", c->Type()->TypeName.GetChars()); + Error(c->cls, "%s already has defaults", cls->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->ClassType()->ParentClass->Defaults == nullptr && c->ClassType() != RUNTIME_CLASS(AActor)) + else if (cls->ParentClass->Defaults == nullptr && cls != RUNTIME_CLASS(AActor)) { - Error(c->cls, "Parent class %s of %s is not initialized", c->ClassType()->ParentClass->TypeName.GetChars(), c->ClassType()->TypeName.GetChars()); + Error(c->cls, "Parent class %s of %s is not initialized", cls->ParentClass->TypeName.GetChars(), cls->TypeName.GetChars()); } else { // Copy the parent's defaults and meta data. - auto ti = static_cast(c->Type()); + auto ti = static_cast(cls); ti->InitializeDefaults(); @@ -2226,7 +2236,7 @@ void ZCCCompiler::InitDefaults() Baggage bag; #ifdef _DEBUG - bag.ClassName = c->Type()->TypeName; + bag.ClassName = cls->TypeName; #endif bag.Version = mVersion; bag.Namespace = OutNamespace; @@ -2390,7 +2400,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool Error(f, "Action functions cannot be declared UI"); } // Non-Actors cannot have action functions. - if (!c->Type()->IsKindOf(RUNTIME_CLASS(PClassActor))) + if (!isActor(c->Type())) { Error(f, "'Action' can only be used in child classes of Actor"); } @@ -2598,9 +2608,10 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool sym->AddVariant(NewPrototype(rets, args), argflags, argnames, afd == nullptr ? nullptr : *(afd->VMPointer), varflags, useflags); c->Type()->Symbols.ReplaceSymbol(sym); - auto cls = dyn_cast(c->Type()); + auto vcls = dyn_cast(c->Type()); + auto cls = vcls ? vcls->Descriptor : nullptr; PFunction *virtsym = nullptr; - if (cls != nullptr && cls->ParentClass != nullptr) virtsym = dyn_cast(cls->ParentClass->Symbols.FindSymbol(FName(f->Name), true)); + if (cls != nullptr && cls->ParentClass != nullptr) virtsym = dyn_cast(cls->ParentClass->VMType->Symbols.FindSymbol(FName(f->Name), true)); unsigned vindex = ~0u; if (virtsym != nullptr) { @@ -2644,7 +2655,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool sym->Variants[0].Implementation->VarFlags = sym->Variants[0].Flags; } - PClass *clstype = static_cast(c->Type()); + PClass *clstype = static_cast(c->Type())->Descriptor; if (varflags & VARF_Virtual) { if (sym->Variants[0].Implementation == nullptr) @@ -2666,7 +2677,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool else { auto oldfunc = clstype->Virtuals[vindex]; - auto parentfunc = dyn_cast(clstype->ParentClass->Symbols.FindSymbol(sym->SymbolName, true)); + auto parentfunc = dyn_cast(clstype->ParentClass->VMType->Symbols.FindSymbol(sym->SymbolName, true)); if (parentfunc && parentfunc->mVersion > mVersion) { Error(f, "Attempt to override function %s which is incompatible with version %d.%d.%d", FName(f->Name).GetChars(), mVersion.major, mVersion.minor, mVersion.revision); @@ -2798,15 +2809,14 @@ FxExpression *ZCCCompiler::SetupActionFunction(PClass *cls, ZCC_TreeNode *af, in // The actual action function is still needed by DECORATE: if (id->Identifier != NAME_ACS_NamedExecuteWithResult) { - PFunction *afd = dyn_cast(cls->Symbols.FindSymbol(id->Identifier, true)); + PFunction *afd = dyn_cast(cls->VMType->Symbols.FindSymbol(id->Identifier, true)); if (afd != nullptr) { if (fc->Parameters == nullptr && !(afd->Variants[0].Flags & VARF_Virtual)) { FArgumentList argumentlist; // We can use this function directly without wrapping it in a caller. - auto selfclass = dyn_cast(afd->Variants[0].SelfClass); - assert(selfclass != nullptr); // non classes are not supposed to get here. + assert(dyn_cast(afd->Variants[0].SelfClass) != nullptr); // non classes are not supposed to get here. int comboflags = afd->Variants[0].UseFlags & StateFlags; if (comboflags == StateFlags) // the function must satisfy all the flags the state requires @@ -2831,7 +2841,7 @@ FxExpression *ZCCCompiler::SetupActionFunction(PClass *cls, ZCC_TreeNode *af, in } } } - return ConvertAST(cls, af); + return ConvertAST(cls->VMType, af); } //========================================================================== @@ -2889,7 +2899,7 @@ void ZCCCompiler::CompileStates() } else { - flags = static_cast(c->Type())->ActorInfo()->DefaultStateUsage; + flags = static_cast(c->ClassType())->ActorInfo()->DefaultStateUsage; } auto st = s->Body; if (st != nullptr) do @@ -2966,7 +2976,7 @@ void ZCCCompiler::CompileStates() if (sl->Action != nullptr) { - auto code = SetupActionFunction(static_cast(c->Type()), sl->Action, state.UseFlags); + auto code = SetupActionFunction(static_cast(c->ClassType()), sl->Action, state.UseFlags); if (code != nullptr) { auto funcsym = CreateAnonymousFunction(c->Type(), nullptr, state.UseFlags); @@ -3176,7 +3186,7 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) return new FxNop(*ast); // return something so that the compiler can continue. } auto cls = PClass::FindClass(cc->ClassName); - if (cls == nullptr) + if (cls == nullptr || cls->VMType == nullptr) { Error(cc, "Unknown class %s", FName(cc->ClassName).GetChars()); return new FxNop(*ast); // return something so that the compiler can continue. diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index acfbc6b15..baa5c89f6 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -66,7 +66,7 @@ struct ZCC_ClassWork : public ZCC_StructWork PClass *ClassType() { - return static_cast(strct->Type); + return static_cast(strct->Type)->Descriptor; } }; diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index 22742ac56..b55fd153b 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -209,7 +209,7 @@ struct ZCC_Class : ZCC_Struct ZCC_Identifier *ParentName; ZCC_Identifier *Replaces; - PClass *CType() { return static_cast(Type); } + PClass *CType() { return static_cast(Type)->Descriptor; } }; struct ZCC_Enum : ZCC_NamedNode diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 0f1195cbf..9defba9de 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -41,6 +41,7 @@ struct _ native // These are the global variables, the struct is only here to av native ui float BackbuttonAlpha; native readonly int Net_Arbitrator; native ui BaseStatusBar StatusBar; + native readonly Weapon WP_NOCHANGE; } @@ -650,7 +651,21 @@ struct StringStruct native native String Filter(); } -class Floor : Thinker native +class SectorEffect : Thinker native +{ + native protected Sector m_Sector; +} + +class Mover : SectorEffect native +{} + +class MovingFloor : Mover native +{} + +class MovingCeiling : Mover native +{} + +class Floor : MovingFloor native { // only here so that some constants and functions can be added. Not directly usable yet. enum EFloor @@ -695,7 +710,7 @@ class Floor : Thinker native native static bool CreateFloor(sector sec, EFloor floortype, line ln, double speed, double height = 0, int crush = -1, int change = 0, bool crushmode = false, bool hereticlower = false); } -class Ceiling : Thinker native +class Ceiling : MovingCeiling native { enum ECeiling { @@ -749,11 +764,6 @@ struct LookExParams State seestate; }; -class SectorEffect : Thinker native -{ - native protected Sector m_Sector; -} - class Lighting : SectorEffect native { }