- 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)); subclass = static_cast<PClassActor *>(dehtype->CreateDerivedClass(typeNameBuilder, dehtype->Size));
} }
while (subclass == nullptr); while (subclass == nullptr);
NewClassType(subclass); // This needs a VM type to work as intended.
AActor *defaults2 = GetDefaultByType (subclass); AActor *defaults2 = GetDefaultByType (subclass);
memcpy ((void *)defaults2, (void *)defaults1, sizeof(AActor)); 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); int lex = memcmp (DehSpriteMappings[mid].Sprite, sprites[self->sprite].name, 4);
if (lex == 0) if (lex == 0)
{ {
ACTION_RETURN_OBJECT(PClass::FindActor(DehSpriteMappings[mid].ClassName)); ACTION_RETURN_POINTER(PClass::FindActor(DehSpriteMappings[mid].ClassName));
} }
else if (lex < 0) else if (lex < 0)
{ {
@ -3163,6 +3164,6 @@ DEFINE_ACTION_FUNCTION(ADehackedPickup, DetermineType)
max = mid - 1; 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; FTypeTable TypeTable;
TArray<PClass *> PClass::AllClasses; TArray<PClass *> PClass::AllClasses;
TMap<FName, PClass*> PClass::ClassMap;
TArray<VMFunction**> PClass::FunctionPtrList; TArray<VMFunction**> PClass::FunctionPtrList;
bool PClass::bShutdown; bool PClass::bShutdown;
bool PClass::bVMOperational; bool PClass::bVMOperational;
@ -96,6 +97,7 @@ PStruct *TypeStringStruct;
PPointer *TypeNullPtr; PPointer *TypeNullPtr;
PPointer *TypeVoidPtr; PPointer *TypeVoidPtr;
// PRIVATE DATA DEFINITIONS ------------------------------------------------ // PRIVATE DATA DEFINITIONS ------------------------------------------------
// A harmless non-nullptr FlatPointer for classes without pointers. // A harmless non-nullptr FlatPointer for classes without pointers.
@ -1353,8 +1355,16 @@ PPointer::PPointer()
PPointer::PPointer(PType *pointsat, bool isconst) PPointer::PPointer(PType *pointsat, bool isconst)
: PBasicType(sizeof(void *), alignof(void *)), PointedType(pointsat), IsConst(isconst) : PBasicType(sizeof(void *), alignof(void *)), PointedType(pointsat), IsConst(isconst)
{ {
mDescriptiveName.Format("Pointer<%s%s>", pointsat->DescriptiveName(), isconst? "readonly " : ""); if (pointsat != nullptr)
mVersion = pointsat->mVersion; {
mDescriptiveName.Format("Pointer<%s%s>", pointsat->DescriptiveName(), isconst ? "readonly " : "");
mVersion = pointsat->mVersion;
}
else
{
mDescriptiveName = "Pointer";
mVersion = 0;
}
loadOp = OP_LP; loadOp = OP_LP;
storeOp = OP_SP; storeOp = OP_SP;
moveOp = OP_MOVEA; moveOp = OP_MOVEA;
@ -1431,7 +1441,7 @@ IMPLEMENT_CLASS(PObjectPointer, false, false)
//========================================================================== //==========================================================================
PObjectPointer::PObjectPointer(PClass *cls, bool isconst) PObjectPointer::PObjectPointer(PClass *cls, bool isconst)
: PPointer(cls, isconst) : PPointer(cls->VMType, isconst)
{ {
loadOp = OP_LO; 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. // 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) 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 = new PPointer(type, isconst);
PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PObjectPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (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);
} }
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 = new PObjectPointer(cls, isconst);
PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); TypeTable.AddType(ptype, RUNTIME_CLASS(PObjectPointer), (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);
} }
return static_cast<PPointer *>(ptype);
} }
/* PStatePointer **********************************************************/ /* PStatePointer **********************************************************/
@ -1562,13 +1576,13 @@ IMPLEMENT_CLASS(PClassPointer,false, false)
//========================================================================== //==========================================================================
PClassPointer::PClassPointer(PClass *restrict) PClassPointer::PClassPointer(PClass *restrict)
: PPointer(RUNTIME_CLASS(PClass)), ClassRestriction(restrict) : PPointer(restrict->VMType), ClassRestriction(restrict)
{ {
if (restrict) mDescriptiveName.Format("ClassPointer<%s>", restrict->TypeName.GetChars()); if (restrict) mDescriptiveName.Format("ClassPointer<%s>", restrict->TypeName.GetChars());
else mDescriptiveName = "ClassPointer"; else mDescriptiveName = "ClassPointer";
loadOp = OP_LP; loadOp = OP_LP;
storeOp = OP_SP; 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) 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 *****************************************************************/ /* 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()); key.Format("class:%s", type->TypeName.GetChars());
if (ar.BeginObject(key.GetChars())) if (ar.BeginObject(key.GetChars()))
{ {
type->Symbols.WriteFields(ar, addr); type->VMType->Symbols.WriteFields(ar, addr);
ar.EndObject(); ar.EndObject();
} }
break; break;
@ -2666,19 +2743,11 @@ bool PClass::ReadAllFields(FSerializer &ar, void *addr) const
if (type != nullptr) if (type != nullptr)
{ {
// Only read it if the type is related to this one. // Only read it if the type is related to this one.
const PClass *parent; if (IsDescendantOf(type))
for (parent = this; parent != nullptr; parent = parent->ParentClass)
{
if (parent == type)
{
break;
}
}
if (parent != nullptr)
{ {
if (ar.BeginObject(nullptr)) if (ar.BeginObject(nullptr))
{ {
readsomething |= type->Symbols.ReadFields(ar, addr, DescriptiveName()); readsomething |= type->VMType->Symbols.ReadFields(ar, addr, type->TypeName.GetChars());
ar.EndObject(); ar.EndObject();
} }
} }
@ -2738,15 +2807,6 @@ void PClass::StaticInit ()
// I'm not sure if this is really necessary to maintain any sort of sync. // I'm not sure if this is really necessary to maintain any sort of sync.
qsort(&AllClasses[0], AllClasses.Size(), sizeof(AllClasses[0]), cregcmp); 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. // This must be done before the type table is taken down.
for (auto cls : AllClasses) for (auto cls : AllClasses)
{ {
Printf("Processing %s\n", cls->TypeName.GetChars());
cls->DestroyMeta(cls->Meta); cls->DestroyMeta(cls->Meta);
} }
// Unless something went wrong, anything left here should be class and type objects only, which do not own any scripts. // 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() 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() 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); PClass::AllClasses.Push(this);
} }
@ -2882,12 +2917,6 @@ PClass::~PClass()
PClass *ClassReg::RegisterClass() PClass *ClassReg::RegisterClass()
{ {
static ClassReg *const metaclasses[] =
{
&PClass::RegistrationInfo,
&PClassActor::RegistrationInfo,
};
// Skip classes that have already been registered // Skip classes that have already been registered
if (MyClass != nullptr) if (MyClass != nullptr)
{ {
@ -2895,18 +2924,7 @@ PClass *ClassReg::RegisterClass()
} }
// Add type to list // Add type to list
PClass *cls; PClass *cls = new PClass;
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());
SetupClass(cls); SetupClass(cls);
cls->InsertIntoHash(); cls->InsertIntoHash();
@ -2934,7 +2952,7 @@ void ClassReg::SetupClass(PClass *cls)
cls->Size = SizeOf; cls->Size = SizeOf;
cls->Pointers = Pointers; cls->Pointers = Pointers;
cls->ConstructNative = ConstructNative; 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 () void PClass::InsertIntoHash ()
{ {
size_t bucket; auto k = ClassMap.CheckKey(TypeName);
PType *found; if (k != nullptr)
found = TypeTable.FindType(RUNTIME_CLASS(PClass), 0, TypeName, &bucket);
if (found != nullptr)
{ // This type has already been inserted { // This type has already been inserted
I_Error("Tried to register class '%s' more than once.\n", TypeName.GetChars()); I_Error("Tried to register class '%s' more than once.\n", TypeName.GetChars());
} }
else 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 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->bRuntimeClass = true;
newclass->ParentClass = this; newclass->ParentClass = this;
newclass->ConstructNative = ConstructNative; newclass->ConstructNative = ConstructNative;
newclass->Symbols.SetParentTable(&this->Symbols);
newclass->TypeName = name; newclass->TypeName = name;
newclass->mDescriptiveName.Format("Class<%s>", name.GetChars());
newclass->mVersion = mVersion;
newclass->MetaSize = MetaSize; 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. if (bRuntimeClass)
assert(ParentClass != nullptr); {
if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults, &PClass::SpecialInits); // 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) 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); else
for (const PField *field : Fields)
{ {
if (!(field->Flags & VARF_Native) && (field->Flags & VARF_Meta)) Printf("VM-less class %s\n", TypeName.GetChars());
{
field->Type->SetDefaultValue(Meta, unsigned(field->Offset), &MetaInits);
}
} }
} }
@ -3235,7 +3259,7 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size)
} }
else else
{ {
type = static_cast<PClass *>(GetClass()->CreateNew()); type = new PClass;
notnew = false; notnew = false;
} }
@ -3245,11 +3269,12 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size)
type->Size = size; type->Size = size;
if (size != TentativeClass) if (size != TentativeClass)
{ {
NewClassType(type);
type->InitializeDefaults(); type->InitializeDefaults();
type->Virtuals = Virtuals; type->Virtuals = Virtuals;
} }
else else
type->ObjectFlags &= OF_Transient; type->bOptional = false;
if (!notnew) if (!notnew)
{ {
@ -3270,7 +3295,7 @@ PField *PClass::AddField(FName name, PType *type, uint32_t flags)
if (!(flags & VARF_Meta)) if (!(flags & VARF_Meta))
{ {
unsigned oldsize = Size; 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. // Only initialize the defaults if they have already been created.
// For ZScript this is not the case, it will first define all fields before // 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. // Same as above, but a different data storage.
unsigned oldsize = MetaSize; 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) if (field != nullptr && !(flags & VARF_Native) && Meta != nullptr)
{ {
@ -3297,19 +3322,6 @@ PField *PClass::AddField(FName name, PType *type, uint32_t flags)
return field; 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 // PClass :: FindClassTentative
@ -3325,21 +3337,17 @@ PClass *PClass::FindClassTentative(FName name)
{ {
return nullptr; return nullptr;
} }
size_t bucket;
PType *found = TypeTable.FindType(RUNTIME_CLASS(PClass), PClass *found = FindClass(name);
/*FIXME:Outer*/0, name, &bucket); if (found != nullptr) return found;
if (found != nullptr) PClass *type = new PClass;
{
return static_cast<PClass *>(found);
}
PClass *type = static_cast<PClass *>(GetClass()->CreateNew());
DPrintf(DMSG_SPAMMY, "Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); DPrintf(DMSG_SPAMMY, "Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars());
Derive(type, name); Derive(type, name);
type->Size = TentativeClass; type->Size = TentativeClass;
TypeTable.AddType(type, RUNTIME_CLASS(PClass), 0, name, bucket);
InsertIntoHash();
return type; return type;
} }
@ -3392,7 +3400,8 @@ int PClass::FindVirtualIndex(FName name, PPrototype *proto)
PSymbol *PClass::FindSymbol(FName symname, bool searchparents) const 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, 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: protected:
TArray<FTypeAndOffset> MetaInits;
void Derive(PClass *newclass, FName name); void Derive(PClass *newclass, FName name);
void InitializeSpecials(void *addr, void *defaults, TArray<FTypeAndOffset> PClass::*Inits); void InitializeSpecials(void *addr, void *defaults, TArray<FTypeAndOffset> PClass::*Inits);
void SetSuper(); void SetSuper();
@ -602,26 +614,32 @@ public:
void InitializeDefaults(); void InitializeDefaults();
int FindVirtualIndex(FName name, PPrototype *proto); int FindVirtualIndex(FName name, PPrototype *proto);
PSymbol *FindSymbol(FName symname, bool searchparents) const; PSymbol *FindSymbol(FName symname, bool searchparents) const;
PField *AddField(FName name, PType *type, uint32_t flags);
static void StaticInit(); static void StaticInit();
static void StaticShutdown(); static void StaticShutdown();
static void StaticBootstrap(); static void StaticBootstrap();
// Per-class information ------------------------------------- // Per-class information -------------------------------------
TArray<FTypeAndOffset> SpecialInits; PClass *ParentClass = nullptr; // the class this class derives from
PClass *ParentClass; // the class this class derives from const size_t *Pointers = nullptr; // object pointers defined by this class *only*
const size_t *Pointers; // 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 *FlatPointers; // object pointers defined by this class and all its superclasses; not initialized by default const size_t *ArrayPointers = nullptr; // dynamic arrays containing object pointers.
const size_t *ArrayPointers; // dynamic arrays containing object pointers. uint8_t *Defaults = nullptr;
uint8_t *Defaults; uint8_t *Meta = nullptr; // Per-class static script data
uint8_t *Meta; // Per-class static script data unsigned Size = sizeof(DObject);
unsigned MetaSize; unsigned MetaSize = 0;
bool bRuntimeClass; // class was defined at run-time, not compile-time FName TypeName;
bool bExported; // This type has been declared in a script FName SourceLumpName;
bool bDecorateClass; // may be subject to some idiosyncracies due to DECORATE backwards compatibility 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 TArray<VMFunction*> Virtuals; // virtual function table
FName SourceLumpName; TArray<FTypeAndOffset> MetaInits;
TArray<FTypeAndOffset> SpecialInits;
TArray<PField *> Fields; TArray<PField *> Fields;
PClassType *VMType = nullptr;
void (*ConstructNative)(void *); void (*ConstructNative)(void *);
@ -631,13 +649,10 @@ public:
void InsertIntoHash(); void InsertIntoHash();
DObject *CreateNew(); DObject *CreateNew();
PClass *CreateDerivedClass(FName name, unsigned int size); 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 InitializeActorInfo();
void BuildFlatPointers(); void BuildFlatPointers();
void BuildArrayPointers(); void BuildArrayPointers();
void InitMeta();
void DestroySpecials(void *addr); void DestroySpecials(void *addr);
void DestroyMeta(void *addr); void DestroyMeta(void *addr);
const PClass *NativeClass() const; const PClass *NativeClass() const;
@ -687,6 +702,7 @@ public:
static void FindFunction(VMFunction **pptr, FName cls, FName func); static void FindFunction(VMFunction **pptr, FName cls, FName func);
PClass *FindClassTentative(FName name); PClass *FindClassTentative(FName name);
static TMap<FName, PClass*> ClassMap;
static TArray<PClass *> AllClasses; static TArray<PClass *> AllClasses;
static TArray<VMFunction**> FunctionPtrList; static TArray<VMFunction**> FunctionPtrList;
@ -719,10 +735,12 @@ PArray *NewArray(PType *type, unsigned int count);
PStaticArray *NewStaticArray(PType *type); PStaticArray *NewStaticArray(PType *type);
PDynArray *NewDynArray(PType *type); PDynArray *NewDynArray(PType *type);
PPointer *NewPointer(PType *type, bool isconst = false); PPointer *NewPointer(PType *type, bool isconst = false);
PPointer *NewPointer(PClass *type, bool isconst = false);
PClassPointer *NewClassPointer(PClass *restrict); PClassPointer *NewClassPointer(PClass *restrict);
PEnum *NewEnum(FName name, PTypeBase *outer); PEnum *NewEnum(FName name, PTypeBase *outer);
PStruct *NewStruct(FName name, PTypeBase *outer, bool native = false); PStruct *NewStruct(FName name, PTypeBase *outer, bool native = false);
PPrototype *NewPrototype(const TArray<PType *> &rettypes, const TArray<PType *> &argtypes); PPrototype *NewPrototype(const TArray<PType *> &rettypes, const TArray<PType *> &argtypes);
PClassType *NewClassType(PClass *cls);
// Built-in types ----------------------------------------------------------- // Built-in types -----------------------------------------------------------

View file

@ -75,16 +75,12 @@ void DSectorEffect::Serialize(FSerializer &arc)
DEFINE_FIELD(DSectorEffect, m_Sector) DEFINE_FIELD(DSectorEffect, m_Sector)
IMPLEMENT_CLASS(DMover, false, true) IMPLEMENT_CLASS(DMover, true, true)
IMPLEMENT_POINTERS_START(DMover) IMPLEMENT_POINTERS_START(DMover)
IMPLEMENT_POINTER(interpolation) IMPLEMENT_POINTER(interpolation)
IMPLEMENT_POINTERS_END IMPLEMENT_POINTERS_END
DMover::DMover ()
{
}
DMover::DMover (sector_t *sector) DMover::DMover (sector_t *sector)
: DSectorEffect (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) DMovingFloor::DMovingFloor (sector_t *sector)
: DMover (sector) : DMover (sector)
@ -125,11 +118,8 @@ DMovingFloor::DMovingFloor (sector_t *sector)
interpolation = sector->SetInterpolation(sector_t::FloorMove, true); 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) DMovingCeiling::DMovingCeiling (sector_t *sector, bool interpolate)
: DMover (sector) : DMover (sector)

View file

@ -25,16 +25,17 @@ protected:
class DMover : public DSectorEffect class DMover : public DSectorEffect
{ {
DECLARE_CLASS (DMover, DSectorEffect) DECLARE_ABSTRACT_CLASS (DMover, DSectorEffect)
HAS_OBJECT_POINTERS HAS_OBJECT_POINTERS
public: protected:
DMover (sector_t *sector); DMover (sector_t *sector);
void StopInterpolation(bool force = false);
protected:
TObjPtr<DInterpolation*> interpolation; TObjPtr<DInterpolation*> interpolation;
private: public:
void StopInterpolation(bool force = false);
protected: protected:
DMover (); DMover () {}
void Serialize(FSerializer &arc); void Serialize(FSerializer &arc);
void OnDestroy() override; void OnDestroy() override;
@ -42,20 +43,18 @@ protected:
class DMovingFloor : public DMover class DMovingFloor : public DMover
{ {
DECLARE_CLASS (DMovingFloor, DMover) DECLARE_ABSTRACT_CLASS (DMovingFloor, DMover)
public:
DMovingFloor (sector_t *sector);
protected: protected:
DMovingFloor (); DMovingFloor (sector_t *sector);
DMovingFloor() {}
}; };
class DMovingCeiling : public DMover class DMovingCeiling : public DMover
{ {
DECLARE_CLASS (DMovingCeiling, DMover) DECLARE_ABSTRACT_CLASS (DMovingCeiling, DMover)
public:
DMovingCeiling (sector_t *sector, bool interpolate = true);
protected: protected:
DMovingCeiling (); DMovingCeiling (sector_t *sector, bool interpolate = true);
DMovingCeiling () {}
}; };
#endif //__DSECTOREFFECT_H__ #endif //__DSECTOREFFECT_H__

View file

@ -231,8 +231,6 @@ DEFINE_ACTION_FUNCTION(AActor, GetSpriteIndex)
ACTION_RETURN_INT(GetSpriteIndex(sprt.GetChars(), false)); ACTION_RETURN_INT(GetSpriteIndex(sprt.GetChars(), false));
} }
IMPLEMENT_CLASS(PClassActor, false, false)
//========================================================================== //==========================================================================
// //
// PClassActor :: StaticInit STATIC // PClassActor :: StaticInit STATIC
@ -286,27 +284,6 @@ void PClassActor::StaticSetActorNums()
} }
} }
//==========================================================================
//
// PClassActor Constructor
//
//==========================================================================
PClassActor::PClassActor()
{
AllActorClasses.Push(this);
}
//==========================================================================
//
// PClassActor Destructor
//
//==========================================================================
PClassActor::~PClassActor()
{
}
//========================================================================== //==========================================================================
// //
// PClassActor :: SetReplacement // PClassActor :: SetReplacement

View file

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

View file

@ -639,7 +639,7 @@ static void TakeStrifeItem (player_t *player, PClassActor *itemtype, int amount)
return; return;
// Don't take the sigil. // Don't take the sigil.
if (itemtype->GetClass()->TypeName == NAME_Sigil) if (itemtype->TypeName == NAME_Sigil)
return; return;
player->mo->TakeInventory(itemtype, amount); player->mo->TakeInventory(itemtype, amount);

View file

@ -526,7 +526,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetSpawnableType)
{ {
PARAM_PROLOGUE; PARAM_PROLOGUE;
PARAM_INT(num); PARAM_INT(num);
ACTION_RETURN_OBJECT(P_GetSpawnableType(num)); ACTION_RETURN_POINTER(P_GetSpawnableType(num));
} }
struct MapinfoSpawnItem struct MapinfoSpawnItem

View file

@ -1242,7 +1242,7 @@ void APlayerPawn::CheckWeaponSwitch(PClassActor *ammotype)
DEFINE_ACTION_FUNCTION(APlayerPawn, CheckWeaponSwitch) DEFINE_ACTION_FUNCTION(APlayerPawn, CheckWeaponSwitch)
{ {
PARAM_SELF_PROLOGUE(APlayerPawn); PARAM_SELF_PROLOGUE(APlayerPawn);
PARAM_OBJECT(ammotype, PClassActor); PARAM_POINTER(ammotype, PClassActor);
self->CheckWeaponSwitch(ammotype); self->CheckWeaponSwitch(ammotype);
return 0; return 0;
} }

View file

@ -56,7 +56,7 @@
#include "w_wad.h" #include "w_wad.h"
#include "math/cmath.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; extern FRandom pr_exrandom;
FMemArena FxAlloc(65536); FMemArena FxAlloc(65536);
@ -219,15 +219,16 @@ static PClass *FindClassType(FName name, FCompileContext &ctx)
if (sym && sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) if (sym && sym->IsKindOf(RUNTIME_CLASS(PSymbolType)))
{ {
auto type = static_cast<PSymbolType*>(sym); 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; return nullptr;
} }
bool isActor(PContainerType *type) bool isActor(PContainerType *type)
{ {
auto cls = dyn_cast<PClass>(type); auto cls = dyn_cast<PClassType>(type);
return cls ? cls->IsDescendantOf(RUNTIME_CLASS(AActor)) : false; 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. // 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. // class types are only compatible if the base type is a descendant of the result type.
auto fromtype = static_cast<PClass *>(basex->ValueType); auto fromtype = static_cast<PClassType *>(basex->ValueType)->Descriptor;
auto totype = static_cast<PClass *>(ValueType); auto totype = static_cast<PClassType *>(ValueType)->Descriptor;
if (fromtype->IsDescendantOf(totype)) goto basereturn; if (fromtype->IsDescendantOf(totype)) goto basereturn;
} }
} }
@ -5148,7 +5149,7 @@ FxExpression *FxNew::Resolve(FCompileContext &ctx)
if (val->isConstant()) if (val->isConstant())
{ {
auto cls = static_cast<PClass *>(static_cast<FxConstant*>(val)->GetValue().GetPointer()); 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()); ScriptPosition.Message(MSG_ERROR, "Cannot instantiate abstract class %s", cls->TypeName.GetChars());
delete this; 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; int outerside = ctx.Function && ctx.Function->Variants.Size() ? FScopeBarrier::SideFromFlags(ctx.Function->Variants[0].Flags) : FScopeBarrier::Side_Virtual;
if (outerside == FScopeBarrier::Side_Virtual) if (outerside == FScopeBarrier::Side_Virtual)
outerside = FScopeBarrier::SideFromObjectFlags(ctx.Class->ObjectFlags); 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" 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)); 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; PSymbol *sym;
PSymbolTable *symtbl; PSymbolTable *symtbl;
bool isclass = objtype->IsKindOf(RUNTIME_CLASS(PClass)); bool isclass = objtype->IsKindOf(RUNTIME_CLASS(PClassType));
if (Identifier == NAME_Default) if (Identifier == NAME_Default)
{ {
@ -6179,8 +6180,8 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType *
object = nullptr; object = nullptr;
return nullptr; return nullptr;
} }
PClass* cls_ctx = dyn_cast<PClass>(classctx); auto cls_ctx = dyn_cast<PClassType>(classctx);
PClass* cls_target = dyn_cast<PClass>(objtype); 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. // [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) if (vsym->Flags & VARF_Protected)
{ {
@ -6194,7 +6195,7 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType *
} }
// find the class that declared this field. // find the class that declared this field.
PClass* p = cls_target; auto p = cls_target;
while (p) while (p)
{ {
if (&p->Symbols == symtbl) if (&p->Symbols == symtbl)
@ -6203,10 +6204,10 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType *
break; 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()); ScriptPosition.Message(MSG_ERROR, "Protected member %s not accessible", vsym->SymbolName.GetChars());
delete object; delete object;
@ -6358,32 +6359,29 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx)
{ {
if (ccls != nullptr) 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->IsKindOf(RUNTIME_CLASS(PSymbolConst)))
if ((sym = ccls->Symbols.FindSymbol(Identifier, true)) != nullptr)
{ {
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; delete this;
return FxConstant::MakeConstant(sym, ScriptPosition); return x->Resolve(ctx);
} }
else else
{ {
auto f = dyn_cast<PField>(sym); ScriptPosition.Message(MSG_ERROR, "Unable to access '%s.%s' in a static context\n", ccls->TypeName.GetChars(), Identifier.GetChars());
if (f != nullptr && (f->Flags & (VARF_Static | VARF_ReadOnly | VARF_Meta)) == (VARF_Static | VARF_ReadOnly)) delete this;
{ return nullptr;
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;
}
} }
} }
} }
@ -7500,9 +7498,9 @@ static bool CheckFunctionCompatiblity(FScriptPosition &ScriptPosition, PFunction
bool match = (callingself == calledself); bool match = (callingself == calledself);
if (!match) if (!match)
{ {
auto callingselfcls = dyn_cast<PClass>(caller->Variants[0].SelfClass); auto callingselfcls = dyn_cast<PClassType>(caller->Variants[0].SelfClass);
auto calledselfcls = dyn_cast<PClass>(callee->Variants[0].SelfClass); auto calledselfcls = dyn_cast<PClassType>(callee->Variants[0].SelfClass);
match = callingselfcls != nullptr && calledselfcls != nullptr && callingselfcls->IsDescendantOf(calledselfcls); match = callingselfcls != nullptr && calledselfcls != nullptr && callingselfcls->Descriptor->IsDescendantOf(calledselfcls->Descriptor);
} }
if (!match) if (!match)
@ -7613,7 +7611,6 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
} }
// [ZZ] validate call // [ZZ] validate call
PClass* cls = (PClass*)ctx.Class;
int outerflags = 0; int outerflags = 0;
if (ctx.Function) 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. // [ZZ] check this at compile time. this would work for most legit cases.
if (innerside == FScopeBarrier::Side_Virtual) if (innerside == FScopeBarrier::Side_Virtual)
{ {
innerside = FScopeBarrier::SideFromObjectFlags(cls->ObjectFlags); innerside = FScopeBarrier::SideFromObjectFlags(ctx.Class->ObjectFlags);
innerflags = FScopeBarrier::FlagsFromSide(innerside); innerflags = FScopeBarrier::FlagsFromSide(innerside);
} }
FScopeBarrier scopeBarrier(outerflags, innerflags, MethodName.GetChars()); FScopeBarrier scopeBarrier(outerflags, innerflags, MethodName.GetChars());
@ -7702,7 +7699,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
} }
PClass *cls = FindClassType(MethodName, ctx); PClass *cls = FindClassType(MethodName, ctx);
if (cls != nullptr && cls->bExported) if (cls != nullptr)
{ {
if (CheckArgSize(MethodName, ArgList, 1, 1, ScriptPosition)) if (CheckArgSize(MethodName, ArgList, 1, 1, ScriptPosition))
{ {
@ -7863,14 +7860,17 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
if (CheckArgSize(MethodName, ArgList, 0, 1, ScriptPosition)) if (CheckArgSize(MethodName, ArgList, 0, 1, ScriptPosition))
{ {
// [ZZ] allow implicit new() call to mean "create current class instance" // [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"); ScriptPosition.Message(MSG_ERROR, "Cannot use implicit new() in a struct");
delete this; delete this;
return nullptr; return nullptr;
} }
else if (!ArgList.Size()) 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]); func = new FxNew(ArgList[0]);
ArgList[0] = nullptr; ArgList[0] = nullptr;
@ -7967,40 +7967,37 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
{ {
if (ccls != nullptr) 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; if (ctx.Function == nullptr)
staticonly = true;
if (ccls->IsKindOf(RUNTIME_CLASS(PClass)))
{ {
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()); bool error;
delete this; PFunction *afd = FindClassMemberFunction(ccls, ctx.Class, MethodName, ScriptPosition, &error);
return nullptr; if ((afd->Variants[0].Flags & VARF_Method) && (afd->Variants[0].Flags & VARF_Virtual))
}
auto clstype = dyn_cast<PClass>(ctx.Function->Variants[0].SelfClass);
if (clstype != nullptr)
{
novirtual = clstype->IsDescendantOf(static_cast<PClass*>(ccls));
if (novirtual)
{ {
bool error; staticonly = false;
PFunction *afd = FindClassMemberFunction(ccls, ctx.Class, MethodName, ScriptPosition, &error); novirtual = true;
if ((afd->Variants[0].Flags & VARF_Method) && (afd->Variants[0].Flags & VARF_Virtual)) delete Self;
{ Self = new FxSelf(ScriptPosition);
staticonly = false; Self->ValueType = NewPointer(cls);
novirtual = true;
delete Self;
Self = new FxSelf(ScriptPosition);
Self->ValueType = NewPointer(cls);
}
else novirtual = false;
} }
else novirtual = false;
} }
} }
if (!novirtual) goto isresolved;
} }
if (!novirtual) goto isresolved;
} }
} }
@ -8012,11 +8009,11 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
delete this; delete this;
return nullptr; 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) if (clstype != nullptr)
{ {
// give the node the proper value type now that we know it's properly used. // 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->ValueType = NewPointer(cls);
Self->ExprType = EFX_Self; Self->ExprType = EFX_Self;
novirtual = true; // super calls are always non-virtual 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; auto ptype = static_cast<PPointer *>(Self->ValueType)->PointedType;
if (ptype->IsKindOf(RUNTIME_CLASS(PContainerType))) 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) if (ArgList.Size() > 0)
{ {
@ -8333,9 +8330,9 @@ isresolved:
{ {
if (!novirtual || !(afd->Variants[0].Flags & VARF_Virtual)) if (!novirtual || !(afd->Variants[0].Flags & VARF_Virtual))
{ {
auto clstype = dyn_cast<PClass>(ctx.Class); auto clstype = dyn_cast<PClassType>(ctx.Class);
auto ccls = dyn_cast<PClass>(cls); auto ccls = dyn_cast<PClassType>(cls);
if (clstype == nullptr || ccls == nullptr || !clstype->IsDescendantOf(ccls)) 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()); ScriptPosition.Message(MSG_ERROR, "Cannot call non-static function %s::%s from here", cls->TypeName.GetChars(), MethodName.GetChars());
delete this; delete this;
@ -9303,7 +9300,7 @@ FxExpression *FxGetClass::Resolve(FCompileContext &ctx)
delete this; delete this;
return nullptr; 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; return this;
} }
@ -10639,7 +10636,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx)
if (Explicit) cls = FindClassType(clsname, ctx); if (Explicit) cls = FindClassType(clsname, ctx);
else cls = PClass::FindClass(clsname); else cls = PClass::FindClass(clsname);
if (cls == nullptr) if (cls == nullptr || cls->VMType == nullptr)
{ {
/* lax */ /* lax */
// Since this happens in released WADs it must pass without a terminal error... :( // 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 *cls = PClass::FindClass(clsname);
const PClass *desttype = reinterpret_cast<PClass *>(param[1].a); 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. // Let the caller check this. Making this an error with a message is only taking away options from the user.
cls = nullptr; cls = nullptr;
@ -10851,7 +10848,9 @@ FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx)
{ {
CHECKRESOLVED(); CHECKRESOLVED();
ABORT(ctx.Class); 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. // 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); assert(aclass != nullptr && aclass->GetStateCount() > 0);
@ -10927,8 +10926,12 @@ FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx)
Index = new FxIntCast(Index, ctx.FromDecorate); Index = new FxIntCast(Index, ctx.FromDecorate);
SAFE_RESOLVE(Index, ctx); 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); assert(aclass != nullptr && aclass->GetStateCount() > 0);
symlabel = StateLabels.AddPointer(aclass->GetStates() + ctx.StateIndex); symlabel = StateLabels.AddPointer(aclass->GetStates() + ctx.StateIndex);
ValueType = TypeStateLabel; ValueType = TypeStateLabel;
return this; return this;
@ -10983,7 +10986,10 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx)
CHECKRESOLVED(); CHECKRESOLVED();
ABORT(ctx.Class); ABORT(ctx.Class);
int symlabel; 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) 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 // these are for vmexec.h
void FScopeBarrier::ValidateNew(PClass* cls, int outerside) 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" 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)); 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) 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)) 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)); 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) if (spc)
{ {
FCompileContext ctx(spc, cls, true); FCompileContext ctx(spc, cls->VMType, true);
data = data->Resolve(ctx); data = data->Resolve(ctx);
} }

View file

@ -69,9 +69,9 @@ EXTERN_CVAR(Bool, strictdecorate);
PClassActor *DecoDerivedClass(const FScriptPosition &sc, PClassActor *parent, FName typeName) 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)); PClassActor *type = static_cast<PClassActor *>(parent->CreateDerivedClass(typeName, parent->Size));
if (type == nullptr) if (type == nullptr)
@ -101,7 +101,8 @@ PClassActor *DecoDerivedClass(const FScriptPosition &sc, PClassActor *parent, FN
if (type != nullptr) if (type != nullptr)
{ {
// [ZZ] DECORATE classes are always play // [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; return type;
@ -1151,15 +1152,15 @@ static void ParseActor(FScanner &sc, PNamespace *ns)
switch (sc.TokenType) switch (sc.TokenType)
{ {
case TK_Const: case TK_Const:
ParseConstant (sc, &info->Symbols, info, ns); ParseConstant (sc, &info->VMType->Symbols, info, ns);
break; break;
case TK_Enum: case TK_Enum:
ParseEnum (sc, &info->Symbols, info, ns); ParseEnum (sc, &info->VMType->Symbols, info, ns);
break; break;
case TK_Var: case TK_Var:
ParseUserVariable (sc, &info->Symbols, info, ns); ParseUserVariable (sc, &info->VMType->Symbols, info, ns);
break; break;
case TK_Identifier: case TK_Identifier:

View file

@ -339,7 +339,7 @@ do_stop:
endofstate: endofstate:
if (ScriptCode != nullptr) 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); 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); int count = bag.statedef.AddStates(&state, statestring, scp);

View file

@ -195,8 +195,8 @@ PFunction *FindClassMemberFunction(PContainerType *selfcls, PContainerType *func
if (symbol != nullptr) if (symbol != nullptr)
{ {
PClass* cls_ctx = dyn_cast<PClass>(funccls); auto cls_ctx = dyn_cast<PClassType>(funccls);
PClass* cls_target = funcsym?dyn_cast<PClass>(funcsym->OwningClass):nullptr; auto cls_target = funcsym ? dyn_cast<PClassType>(funcsym->OwningClass) : nullptr;
if (funcsym == nullptr) if (funcsym == nullptr)
{ {
sc.Message(MSG_ERROR, "%s is not a member function of %s", name.GetChars(), selfcls->TypeName.GetChars()); 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. // 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()); 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()); 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 else
{ {
auto dmg = new FxReturnStatement(new FxIntCast(id, true), id->ScriptPosition); 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); 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 ParseScripts();
void ParseAllDecorate(); void ParseAllDecorate();
void SynthesizeFlagFields();
void LoadActors() void LoadActors()
{ {
@ -387,6 +388,7 @@ void LoadActors()
FScriptPosition::StrictErrors = false; FScriptPosition::StrictErrors = false;
ParseAllDecorate(); ParseAllDecorate();
SynthesizeFlagFields();
FunctionBuildList.Build(); FunctionBuildList.Build();
@ -401,7 +403,7 @@ void LoadActors()
auto ti = PClassActor::AllActorClasses[i]; auto ti = PClassActor::AllActorClasses[i];
if (ti->Size == TentativeClass) 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()); Printf(TEXTCOLOR_ORANGE "Class %s referenced but not defined\n", ti->TypeName.GetChars());
FScriptPosition::WarnCounter++; FScriptPosition::WarnCounter++;

View file

@ -67,7 +67,14 @@ static TArray<AFuncDesc> AFTable;
static TArray<FieldDesc> FieldTable; static TArray<FieldDesc> FieldTable;
extern int BackbuttonTime; extern int BackbuttonTime;
extern float BackbuttonAlpha; 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(AInventory), InventoryFlagDefs, countof(InventoryFlagDefs), 3 },
{ &RUNTIME_CLASS_CASTLESS(AWeapon), WeaponFlagDefs, countof(WeaponFlagDefs), 3 }, { &RUNTIME_CLASS_CASTLESS(AWeapon), WeaponFlagDefs, countof(WeaponFlagDefs), 3 },
{ &RUNTIME_CLASS_CASTLESS(APlayerPawn), PlayerPawnFlagDefs, countof(PlayerPawnFlagDefs), 3 }, { &RUNTIME_CLASS_CASTLESS(APlayerPawn), PlayerPawnFlagDefs, countof(PlayerPawnFlagDefs), 3 },
{ &RUNTIME_CLASS_CASTLESS(ADynamicLight),DynLightFlagDefs, countof(DynLightFlagDefs), 3 },
}; };
#define NUM_FLAG_LISTS (countof(FlagLists)) #define NUM_FLAG_LISTS (countof(FlagLists))
@ -890,29 +898,6 @@ void InitThingdef()
auto wbplayerstruct = NewStruct("WBPlayerStruct", nullptr, true); auto wbplayerstruct = NewStruct("WBPlayerStruct", nullptr, true);
wbplayerstruct->Size = sizeof(wbplayerstruct_t); wbplayerstruct->Size = sizeof(wbplayerstruct_t);
wbplayerstruct->Align = alignof(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); FAutoSegIterator probe(CRegHead, CRegTail);
@ -980,9 +965,37 @@ void InitThingdef()
FieldTable.ShrinkToFit(); FieldTable.ShrinkToFit();
qsort(&FieldTable[0], FieldTable.Size(), sizeof(FieldTable[0]), fieldcmp); 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) DEFINE_ACTION_FUNCTION(DObject, GameType)
{ {
PARAM_PROLOGUE; PARAM_PROLOGUE;

View file

@ -92,7 +92,7 @@ static PClassActor *FindClassTentative(const char *name, PClass *ancestor, bool
} }
if (cls->Size == TentativeClass && optional) 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); 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_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_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_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_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_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) #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_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_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_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_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)) { 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_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. // The above, but with an automatically increasing position index.
#define PARAM_PROLOGUE int paramnum = -1; #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()); 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()); ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars());
} }

View file

@ -51,6 +51,8 @@
#include "backend/vmbuilder.h" #include "backend/vmbuilder.h"
FSharedStringArena VMStringConstants; FSharedStringArena VMStringConstants;
bool isActor(PContainerType *type);
static int GetIntConst(FxExpression *ex, FCompileContext &ctx) static int GetIntConst(FxExpression *ex, FCompileContext &ctx)
{ {
@ -496,8 +498,8 @@ void ZCCCompiler::CreateStructTypes()
s->Outer = s->OuterDef == nullptr? nullptr : s->OuterDef->CType(); s->Outer = s->OuterDef == nullptr? nullptr : s->OuterDef->CType();
if (s->Outer) if (s->Outer)
{ {
outer = s->Outer; outer = s->Outer->VMType;
syms = &s->Outer->Symbols; syms = &s->Outer->VMType->Symbols;
} }
else else
{ {
@ -603,7 +605,7 @@ void ZCCCompiler::CreateClassTypes()
parent = RUNTIME_CLASS(DObject); 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 // The parent exists, we may create a type for this class
if (c->cls->Flags & ZCC_Native) 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()); 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; me->SourceLumpName = *c->cls->SourceName;
} }
else 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. // We will never get here if the name is a duplicate, so we can just do the assignment.
try 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); 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); auto newclass = parent->CreateDerivedClass(c->NodeName(), TentativeClass);
if (c->Type() == nullptr) if (newclass == nullptr)
{ {
Error(c->cls, "Class name %s already exists", c->NodeName().GetChars()); 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) catch (CRecoverableError &err)
{ {
Error(c->cls, "%s", err.GetMessage()); Error(c->cls, "%s", err.GetMessage());
// create a placeholder so that the compiler can continue looking for errors.
c->cls->Type = nullptr; 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) if (c->cls->Flags & ZCC_Abstract)
c->Type()->ObjectFlags |= OF_Abstract; c->Type()->ObjectFlags |= OF_Abstract;
@ -675,13 +685,13 @@ void ZCCCompiler::CreateClassTypes()
c->Type()->ObjectFlags = (c->Type()->ObjectFlags&~OF_Play) | OF_UI; c->Type()->ObjectFlags = (c->Type()->ObjectFlags&~OF_Play) | OF_UI;
if (c->cls->Flags & ZCC_Play) if (c->cls->Flags & ZCC_Play)
c->Type()->ObjectFlags = (c->Type()->ObjectFlags&~OF_UI) | OF_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)) if (c->cls->Flags & (ZCC_UIFlag | ZCC_Play))
{ {
Error(c->cls, "Can't change class scope in class %s", c->NodeName().GetChars()); 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 else
@ -689,14 +699,13 @@ void ZCCCompiler::CreateClassTypes()
c->Type()->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(c->Type()->ObjectFlags, FScopeBarrier::Side_Play); 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()); c->cls->Symbol = new PSymbolType(c->NodeName(), c->Type());
OutNamespace->Symbols.AddSymbol(c->cls->Symbol); OutNamespace->Symbols.AddSymbol(c->cls->Symbol);
Classes.Push(c); Classes.Push(c);
OrigClasses.Delete(i--); OrigClasses.Delete(i--);
donesomething = true; donesomething = true;
} }
else else if (c->cls->ParentName != nullptr)
{ {
// No base class found. Now check if something in the unprocessed classes matches. // 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. // 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()); 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. // 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()); c->cls->Symbol = new PSymbolType(c->NodeName(), c->Type());
OutNamespace->Symbols.AddSymbol(c->cls->Symbol); OutNamespace->Symbols.AddSymbol(c->cls->Symbol);
Classes.Push(c); Classes.Push(c);
@ -729,7 +738,7 @@ void ZCCCompiler::CreateClassTypes()
for (auto c : OrigClasses) for (auto c : OrigClasses)
{ {
Error(c->cls, "Class %s has circular inheritance", FName(c->NodeName()).GetChars()); 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()); c->cls->Symbol = new PSymbolType(c->NodeName(), c->Type());
OutNamespace->Symbols.AddSymbol(c->cls->Symbol); OutNamespace->Symbols.AddSymbol(c->cls->Symbol);
Classes.Push(c); 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()); 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. // We need to search the global class table here because not all children may have a scripted definition attached.
for (auto ac : PClass::AllClasses) 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. // Only set a marker here, so that we can print a better message when the actual fields get added.
HasNativeChildren.Insert(ac, true); HasNativeChildren.Insert(ac, true);
@ -1180,7 +1189,7 @@ void ZCCCompiler::CompileAllFields()
else else
type->MetaSize = 0; 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. // Remove from the list if all fields got compiled.
Classes.Delete(i--); 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()); else qualifiedname.Format("@property@%s.%s", prefix.GetChars(), name.GetChars());
fields.ShrinkToFit(); 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()); 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; return TypeError;
} }
auto typesym = dyn_cast<PSymbolType>(sym); 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()); Error(field, "%s does not represent a class type", FName(ctype->Restriction->Id).GetChars());
return TypeError; 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); 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; return TypeError;
} }
retval = NewClassPointer(static_cast<PClass *>(typesym->Type)); retval = NewClassPointer(static_cast<PClassType *>(typesym->Type)->Descriptor);
} }
break; 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. 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); return NewPointer(ptype, type->isconst);
} }
@ -1789,7 +1798,7 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper
const char * p = prop->params; const char * p = prop->params;
auto exp = property->Values; auto exp = property->Values;
FCompileContext ctx(OutNamespace, bag.Info, false); FCompileContext ctx(OutNamespace, bag.Info->VMType, false);
while (true) while (true)
{ {
FPropParam conv; FPropParam conv;
@ -1971,7 +1980,7 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop
} }
auto exp = property->Values; auto exp = property->Values;
FCompileContext ctx(OutNamespace, bag.Info, false); FCompileContext ctx(OutNamespace, bag.Info->VMType, false);
for (auto f : prop->Variables) for (auto f : prop->Variables)
{ {
void *addr; void *addr;
@ -2200,20 +2209,21 @@ void ZCCCompiler::InitDefaults()
} }
else else
{ {
auto cls = c->ClassType();
// This should never happen. // 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. // 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 else
{ {
// Copy the parent's defaults and meta data. // Copy the parent's defaults and meta data.
auto ti = static_cast<PClassActor *>(c->Type()); auto ti = static_cast<PClassActor *>(cls);
ti->InitializeDefaults(); ti->InitializeDefaults();
@ -2226,7 +2236,7 @@ void ZCCCompiler::InitDefaults()
Baggage bag; Baggage bag;
#ifdef _DEBUG #ifdef _DEBUG
bag.ClassName = c->Type()->TypeName; bag.ClassName = cls->TypeName;
#endif #endif
bag.Version = mVersion; bag.Version = mVersion;
bag.Namespace = OutNamespace; 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"); Error(f, "Action functions cannot be declared UI");
} }
// Non-Actors cannot have action functions. // 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"); 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); sym->AddVariant(NewPrototype(rets, args), argflags, argnames, afd == nullptr ? nullptr : *(afd->VMPointer), varflags, useflags);
c->Type()->Symbols.ReplaceSymbol(sym); 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; 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; unsigned vindex = ~0u;
if (virtsym != nullptr) 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; 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 (varflags & VARF_Virtual)
{ {
if (sym->Variants[0].Implementation == nullptr) if (sym->Variants[0].Implementation == nullptr)
@ -2666,7 +2677,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
else else
{ {
auto oldfunc = clstype->Virtuals[vindex]; 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) 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); 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: // The actual action function is still needed by DECORATE:
if (id->Identifier != NAME_ACS_NamedExecuteWithResult) 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 (afd != nullptr)
{ {
if (fc->Parameters == nullptr && !(afd->Variants[0].Flags & VARF_Virtual)) if (fc->Parameters == nullptr && !(afd->Variants[0].Flags & VARF_Virtual))
{ {
FArgumentList argumentlist; FArgumentList argumentlist;
// We can use this function directly without wrapping it in a caller. // We can use this function directly without wrapping it in a caller.
auto selfclass = dyn_cast<PClass>(afd->Variants[0].SelfClass); assert(dyn_cast<PClassType>(afd->Variants[0].SelfClass) != nullptr); // non classes are not supposed to get here.
assert(selfclass != nullptr); // non classes are not supposed to get here.
int comboflags = afd->Variants[0].UseFlags & StateFlags; int comboflags = afd->Variants[0].UseFlags & StateFlags;
if (comboflags == StateFlags) // the function must satisfy all the flags the state requires 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 else
{ {
flags = static_cast<PClassActor *>(c->Type())->ActorInfo()->DefaultStateUsage; flags = static_cast<PClassActor *>(c->ClassType())->ActorInfo()->DefaultStateUsage;
} }
auto st = s->Body; auto st = s->Body;
if (st != nullptr) do if (st != nullptr) do
@ -2966,7 +2976,7 @@ void ZCCCompiler::CompileStates()
if (sl->Action != nullptr) 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) if (code != nullptr)
{ {
auto funcsym = CreateAnonymousFunction(c->Type(), nullptr, state.UseFlags); 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. return new FxNop(*ast); // return something so that the compiler can continue.
} }
auto cls = PClass::FindClass(cc->ClassName); auto cls = PClass::FindClass(cc->ClassName);
if (cls == nullptr) if (cls == nullptr || cls->VMType == nullptr)
{ {
Error(cc, "Unknown class %s", FName(cc->ClassName).GetChars()); Error(cc, "Unknown class %s", FName(cc->ClassName).GetChars());
return new FxNop(*ast); // return something so that the compiler can continue. 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() 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 *ParentName;
ZCC_Identifier *Replaces; ZCC_Identifier *Replaces;
PClass *CType() { return static_cast<PClass *>(Type); } PClass *CType() { return static_cast<PClassType *>(Type)->Descriptor; }
}; };
struct ZCC_Enum : ZCC_NamedNode 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 ui float BackbuttonAlpha;
native readonly int Net_Arbitrator; native readonly int Net_Arbitrator;
native ui BaseStatusBar StatusBar; native ui BaseStatusBar StatusBar;
native readonly Weapon WP_NOCHANGE;
} }
@ -650,7 +651,21 @@ struct StringStruct native
native String Filter(); 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. // only here so that some constants and functions can be added. Not directly usable yet.
enum EFloor 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); 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 enum ECeiling
{ {
@ -749,11 +764,6 @@ struct LookExParams
State seestate; State seestate;
}; };
class SectorEffect : Thinker native
{
native protected Sector m_Sector;
}
class Lighting : SectorEffect native class Lighting : SectorEffect native
{ {
} }