- 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.
This commit is contained in:
Christoph Oelckers 2017-04-12 22:46:49 +02:00
parent afd6743965
commit fc9e304189
24 changed files with 428 additions and 393 deletions

View file

@ -3034,7 +3034,8 @@ void FinishDehPatch ()
subclass = static_cast<PClassActor *>(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);
}

View file

@ -68,6 +68,7 @@ FMemArena ClassDataAllocator(32768); // use this for all static class data that
FTypeTable TypeTable;
TArray<PClass *> PClass::AllClasses;
TMap<FName, PClass*> PClass::ClassMap;
TArray<VMFunction**> 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<PClassType>(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<PClass*>(type), isconst);
TypeTable.AddType(ptype, RUNTIME_CLASS(PObjectPointer), (intptr_t)type, isconst ? 1 : 0, bucket);
}
return static_cast<PPointer *>(ptype);
ptype = new PPointer(type, isconst);
TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, bucket);
}
else
return static_cast<PPointer *>(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<PPointer *>(ptype);
ptype = new PObjectPointer(cls, isconst);
TypeTable.AddType(ptype, RUNTIME_CLASS(PObjectPointer), (intptr_t)type, isconst ? 1 : 0, bucket);
}
return static_cast<PPointer *>(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<size_t> *special)
{
// Class pointers do not get added to FlatPointers because they are released from the GC.
}
//==========================================================================
@ -2590,7 +2603,71 @@ PPrototype *NewPrototype(const TArray<PType *> &rettypes, const TArray<PType *>
/* 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<PClassType *>(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<PClass *>(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<PClassActor*>(this));
}
}
@ -2995,7 +3014,8 @@ PClass *PClass::FindClass (FName zaname)
{
return nullptr;
}
return static_cast<PClass *>(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<PClass *>(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<PClass *>(found);
}
PClass *type = static_cast<PClass *>(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);
}
//==========================================================================

View file

@ -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<FTypeAndOffset> MetaInits;
void Derive(PClass *newclass, FName name);
void InitializeSpecials(void *addr, void *defaults, TArray<FTypeAndOffset> 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<FTypeAndOffset> 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<VMFunction*> Virtuals; // virtual function table
FName SourceLumpName;
TArray<FTypeAndOffset> MetaInits;
TArray<FTypeAndOffset> SpecialInits;
TArray<PField *> 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<FName, PClass*> ClassMap;
static TArray<PClass *> AllClasses;
static TArray<VMFunction**> 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<PType *> &rettypes, const TArray<PType *> &argtypes);
PClassType *NewClassType(PClass *cls);
// Built-in types -----------------------------------------------------------

View file

@ -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)

View file

@ -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<DInterpolation*> 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__

View file

@ -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

View file

@ -288,7 +288,6 @@ struct FActorInfo
class PClassActor : public PClass
{
DECLARE_CLASS(PClassActor, PClass);
protected:
public:
static void StaticInit ();

View file

@ -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);

View file

@ -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

View file

@ -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;
}

View file

@ -56,7 +56,7 @@
#include "w_wad.h"
#include "math/cmath.h"
inline PClass *PObjectPointer::PointedClass() const { return static_cast<PClass*>(PointedType); }
inline PClass *PObjectPointer::PointedClass() const { return static_cast<PClassType*>(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<PSymbolType*>(sym);
return dyn_cast<PClass>(type->Type);
auto ctype = dyn_cast<PClassType>(type->Type);
if (ctype) return ctype->Descriptor;
}
return nullptr;
}
bool isActor(PContainerType *type)
{
auto cls = dyn_cast<PClass>(type);
return cls ? cls->IsDescendantOf(RUNTIME_CLASS(AActor)) : false;
auto cls = dyn_cast<PClassType>(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<PClass *>(basex->ValueType);
auto totype = static_cast<PClass *>(ValueType);
auto fromtype = static_cast<PClassType *>(basex->ValueType)->Descriptor;
auto totype = static_cast<PClassType *>(ValueType)->Descriptor;
if (fromtype->IsDescendantOf(totype)) goto basereturn;
}
}
@ -5148,7 +5149,7 @@ FxExpression *FxNew::Resolve(FCompileContext &ctx)
if (val->isConstant())
{
auto cls = static_cast<PClass *>(static_cast<FxConstant*>(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<PClass>(classctx);
PClass* cls_target = dyn_cast<PClass>(objtype);
auto cls_ctx = dyn_cast<PClassType>(classctx);
auto cls_target = dyn_cast<PClassType>(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<PClass *>(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<PField>(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<PField>(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<PClass>(caller->Variants[0].SelfClass);
auto calledselfcls = dyn_cast<PClass>(callee->Variants[0].SelfClass);
match = callingselfcls != nullptr && calledselfcls != nullptr && callingselfcls->IsDescendantOf(calledselfcls);
auto callingselfcls = dyn_cast<PClassType>(caller->Variants[0].SelfClass);
auto calledselfcls = dyn_cast<PClassType>(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<PClassType*>(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<PClass *>(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<PClassType>(ctx.Function->Variants[0].SelfClass);
if (clstype != nullptr)
{
novirtual = clstype->Descriptor->IsDescendantOf(static_cast<PClassType*>(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<PClass>(ctx.Function->Variants[0].SelfClass);
if (clstype != nullptr)
{
novirtual = clstype->IsDescendantOf(static_cast<PClass*>(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<PClass>(ctx.Function->Variants[0].SelfClass);
auto clstype = dyn_cast<PClassType>(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<PPointer *>(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<PClass>(ctx.Class);
auto ccls = dyn_cast<PClass>(cls);
if (clstype == nullptr || ccls == nullptr || !clstype->IsDescendantOf(ccls))
auto clstype = dyn_cast<PClassType>(ctx.Class);
auto ccls = dyn_cast<PClassType>(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<PClass*>(static_cast<PPointer*>(Self->ValueType)->PointedType));
ValueType = NewClassPointer(static_cast<PClassType*>(static_cast<PPointer*>(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<VMValue> &defaultparam, int numpar
const PClass *cls = PClass::FindClass(clsname);
const PClass *desttype = reinterpret_cast<PClass *>(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<PClassActor>(ctx.Class);
auto vclass = dyn_cast<PClassType>(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<PClassActor>(ctx.Class);
auto vclass = dyn_cast<PClassType>(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<PClassActor>(ctx.Class);
auto vclass = dyn_cast<PClassType>(ctx.Class);
assert(vclass != nullptr);
auto clstype = ValidateActor(vclass->Descriptor);
if (names[0] == NAME_None)
{

View file

@ -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));
}

View file

@ -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);
}

View file

@ -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<PClassActor *>(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:

View file

@ -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);

View file

@ -195,8 +195,8 @@ PFunction *FindClassMemberFunction(PContainerType *selfcls, PContainerType *func
if (symbol != nullptr)
{
PClass* cls_ctx = dyn_cast<PClass>(funccls);
PClass* cls_target = funcsym?dyn_cast<PClass>(funcsym->OwningClass):nullptr;
auto cls_ctx = dyn_cast<PClassType>(funccls);
auto cls_target = funcsym ? dyn_cast<PClassType>(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++;

View file

@ -67,7 +67,14 @@ static TArray<AFuncDesc> AFTable;
static TArray<FieldDesc> 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<fl.NumDefs;i++)
{
if (fl.Defs[i].structoffset > 0) // skip the deprecated entries in this list
{
const_cast<PClass*>(*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<PClass*>(*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;

View file

@ -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<PClassActor *>(cls);
}

View file

@ -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;

View file

@ -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());
}

View file

@ -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<PClassActor *>(cd->Type())->SetReplacement(cd->cls->Replaces->Id))
if (cd->cls->Replaces != nullptr && !static_cast<PClassActor *>(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<ZCC_Property *> &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<PSymbolType>(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<PClass *>(typesym->Type));
retval = NewClassPointer(static_cast<PClassType *>(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<PClassActor *>(c->Type());
auto ti = static_cast<PClassActor *>(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<PClass>(c->Type());
auto vcls = dyn_cast<PClassType>(c->Type());
auto cls = vcls ? vcls->Descriptor : nullptr;
PFunction *virtsym = nullptr;
if (cls != nullptr && cls->ParentClass != nullptr) virtsym = dyn_cast<PFunction>(cls->ParentClass->Symbols.FindSymbol(FName(f->Name), true));
if (cls != nullptr && cls->ParentClass != nullptr) virtsym = dyn_cast<PFunction>(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<PClass *>(c->Type());
PClass *clstype = static_cast<PClassType *>(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<PFunction>(clstype->ParentClass->Symbols.FindSymbol(sym->SymbolName, true));
auto parentfunc = dyn_cast<PFunction>(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<PFunction>(cls->Symbols.FindSymbol(id->Identifier, true));
PFunction *afd = dyn_cast<PFunction>(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<PClass>(afd->Variants[0].SelfClass);
assert(selfclass != nullptr); // non classes are not supposed to get here.
assert(dyn_cast<PClassType>(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<PClassActor *>(c->Type())->ActorInfo()->DefaultStateUsage;
flags = static_cast<PClassActor *>(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<PClassActor *>(c->Type()), sl->Action, state.UseFlags);
auto code = SetupActionFunction(static_cast<PClassActor *>(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.

View file

@ -66,7 +66,7 @@ struct ZCC_ClassWork : public ZCC_StructWork
PClass *ClassType()
{
return static_cast<PClass *>(strct->Type);
return static_cast<PClassType *>(strct->Type)->Descriptor;
}
};

View file

@ -209,7 +209,7 @@ struct ZCC_Class : ZCC_Struct
ZCC_Identifier *ParentName;
ZCC_Identifier *Replaces;
PClass *CType() { return static_cast<PClass *>(Type); }
PClass *CType() { return static_cast<PClassType *>(Type)->Descriptor; }
};
struct ZCC_Enum : ZCC_NamedNode

View file

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