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 { }