mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-10 14:51:40 +00:00
Add final and sealed as class options
This commit is contained in:
parent
42df40941c
commit
5e96dbc981
7 changed files with 55 additions and 9 deletions
|
@ -204,6 +204,7 @@ std2:
|
||||||
'stop' { RET(TK_Stop); }
|
'stop' { RET(TK_Stop); }
|
||||||
'null' { RET(TK_Null); }
|
'null' { RET(TK_Null); }
|
||||||
'nullptr' { RET(ParseVersion >= MakeVersion(4, 9, 0)? TK_Null : TK_Identifier); }
|
'nullptr' { RET(ParseVersion >= MakeVersion(4, 9, 0)? TK_Null : TK_Identifier); }
|
||||||
|
'sealed' { RET(ParseVersion >= MakeVersion(4, 12, 0)? TK_Sealed : TK_Identifier); }
|
||||||
|
|
||||||
'is' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Is : TK_Identifier); }
|
'is' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Is : TK_Identifier); }
|
||||||
'replaces' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Replaces : TK_Identifier); }
|
'replaces' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Replaces : TK_Identifier); }
|
||||||
|
|
|
@ -122,6 +122,7 @@ xx(TK_Null, "'null'")
|
||||||
xx(TK_Global, "'global'")
|
xx(TK_Global, "'global'")
|
||||||
xx(TK_Stop, "'stop'")
|
xx(TK_Stop, "'stop'")
|
||||||
xx(TK_Include, "'include'")
|
xx(TK_Include, "'include'")
|
||||||
|
xx(TK_Sealed, "'sealed'")
|
||||||
|
|
||||||
xx(TK_Is, "'is'")
|
xx(TK_Is, "'is'")
|
||||||
xx(TK_Replaces, "'replaces'")
|
xx(TK_Replaces, "'replaces'")
|
||||||
|
|
|
@ -66,11 +66,14 @@ public:
|
||||||
bool bRuntimeClass = false; // class was defined at run-time, not compile-time
|
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 bDecorateClass = false; // may be subject to some idiosyncracies due to DECORATE backwards compatibility
|
||||||
bool bAbstract = false;
|
bool bAbstract = false;
|
||||||
|
bool bSealed = false;
|
||||||
|
bool bFinal = false;
|
||||||
bool bOptional = false;
|
bool bOptional = false;
|
||||||
TArray<VMFunction*> Virtuals; // virtual function table
|
TArray<VMFunction*> Virtuals; // virtual function table
|
||||||
TArray<FTypeAndOffset> MetaInits;
|
TArray<FTypeAndOffset> MetaInits;
|
||||||
TArray<FTypeAndOffset> SpecialInits;
|
TArray<FTypeAndOffset> SpecialInits;
|
||||||
TArray<PField *> Fields;
|
TArray<PField *> Fields;
|
||||||
|
TArray<FName> SealedRestriction;
|
||||||
PClassType *VMType = nullptr;
|
PClassType *VMType = nullptr;
|
||||||
|
|
||||||
void (*ConstructNative)(void *);
|
void (*ConstructNative)(void *);
|
||||||
|
|
|
@ -78,6 +78,7 @@ static void SetNodeLine(ZCC_TreeNode *name, int line)
|
||||||
struct ClassFlagsBlock {
|
struct ClassFlagsBlock {
|
||||||
VM_UWORD Flags;
|
VM_UWORD Flags;
|
||||||
ZCC_Identifier *Replaces;
|
ZCC_Identifier *Replaces;
|
||||||
|
ZCC_Identifier *Sealed;
|
||||||
VersionInfo Version;
|
VersionInfo Version;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -242,6 +243,7 @@ class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C).
|
||||||
head->ParentName = B;
|
head->ParentName = B;
|
||||||
head->Flags = C.Flags;
|
head->Flags = C.Flags;
|
||||||
head->Replaces = C.Replaces;
|
head->Replaces = C.Replaces;
|
||||||
|
head->Sealed = C.Sealed;
|
||||||
head->Version = C.Version;
|
head->Version = C.Version;
|
||||||
head->Type = nullptr;
|
head->Type = nullptr;
|
||||||
head->Symbol = nullptr;
|
head->Symbol = nullptr;
|
||||||
|
@ -253,13 +255,15 @@ class_ancestry(X) ::= . { X = NULL; }
|
||||||
class_ancestry(X) ::= COLON dottable_id(A). { X = A; /*X-overwrites-A*/ }
|
class_ancestry(X) ::= COLON dottable_id(A). { X = A; /*X-overwrites-A*/ }
|
||||||
|
|
||||||
%type class_flags{ClassFlagsBlock}
|
%type class_flags{ClassFlagsBlock}
|
||||||
class_flags(X) ::= . { X.Flags = 0; X.Replaces = NULL; X.Version = {0,0}; }
|
class_flags(X) ::= . { X.Flags = 0; X.Replaces = NULL; X.Version = {0,0}; X.Sealed = NULL; }
|
||||||
class_flags(X) ::= class_flags(A) ABSTRACT. { X.Flags = A.Flags | ZCC_Abstract; X.Replaces = A.Replaces; }
|
class_flags(X) ::= class_flags(A) ABSTRACT. { X.Flags = A.Flags | ZCC_Abstract; X.Replaces = A.Replaces; X.Version = A.Version; X.Sealed = A.Sealed; }
|
||||||
class_flags(X) ::= class_flags(A) NATIVE. { X.Flags = A.Flags | ZCC_Native; X.Replaces = A.Replaces; }
|
class_flags(X) ::= class_flags(A) FINAL. { X.Flags = A.Flags | ZCC_Final; X.Replaces = A.Replaces; X.Version = A.Version; X.Sealed = A.Sealed;}
|
||||||
class_flags(X) ::= class_flags(A) UI. { X.Flags = A.Flags | ZCC_UIFlag; X.Replaces = A.Replaces; }
|
class_flags(X) ::= class_flags(A) NATIVE. { X.Flags = A.Flags | ZCC_Native; X.Replaces = A.Replaces; X.Version = A.Version; X.Sealed = A.Sealed; }
|
||||||
class_flags(X) ::= class_flags(A) PLAY. { X.Flags = A.Flags | ZCC_Play; X.Replaces = A.Replaces; }
|
class_flags(X) ::= class_flags(A) UI. { X.Flags = A.Flags | ZCC_UIFlag; X.Replaces = A.Replaces; X.Version = A.Version; X.Sealed = A.Sealed; }
|
||||||
class_flags(X) ::= class_flags(A) REPLACES dottable_id(B). { X.Flags = A.Flags; X.Replaces = B; }
|
class_flags(X) ::= class_flags(A) PLAY. { X.Flags = A.Flags | ZCC_Play; X.Replaces = A.Replaces; X.Version = A.Version; X.Sealed = A.Sealed; }
|
||||||
class_flags(X) ::= class_flags(A) VERSION LPAREN STRCONST(C) RPAREN. { X.Flags = A.Flags | ZCC_Version; X.Replaces = A.Replaces; X.Version = C.String->GetChars(); }
|
class_flags(X) ::= class_flags(A) REPLACES dottable_id(B). { X.Flags = A.Flags; X.Replaces = B; X.Version = A.Version; X.Sealed = A.Sealed; }
|
||||||
|
class_flags(X) ::= class_flags(A) VERSION LPAREN STRCONST(C) RPAREN. { X.Flags = A.Flags | ZCC_Version; X.Replaces = A.Replaces; X.Version = C.String->GetChars(); X.Sealed = A.Sealed; }
|
||||||
|
class_flags(X) ::= class_flags(A) SEALED LPAREN states_opt(B) RPAREN. { X.Flags = A.Flags | ZCC_Sealed; X.Replaces = A.Replaces; X.Version = A.Version; X.Sealed = B; }
|
||||||
|
|
||||||
/*----- Dottable Identifier -----*/
|
/*----- Dottable Identifier -----*/
|
||||||
// This can be either a single identifier or two identifiers connected by a .
|
// This can be either a single identifier or two identifiers connected by a .
|
||||||
|
|
|
@ -792,8 +792,14 @@ void ZCCCompiler::CreateClassTypes()
|
||||||
PClass *parent;
|
PClass *parent;
|
||||||
auto ParentName = c->cls->ParentName;
|
auto ParentName = c->cls->ParentName;
|
||||||
|
|
||||||
if (ParentName != nullptr && ParentName->SiblingNext == ParentName) parent = PClass::FindClass(ParentName->Id);
|
if (ParentName != nullptr && ParentName->SiblingNext == ParentName)
|
||||||
else if (ParentName == nullptr) parent = RUNTIME_CLASS(DObject);
|
{
|
||||||
|
parent = PClass::FindClass(ParentName->Id);
|
||||||
|
}
|
||||||
|
else if (ParentName == nullptr)
|
||||||
|
{
|
||||||
|
parent = RUNTIME_CLASS(DObject);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The parent is a dotted name which the type system currently does not handle.
|
// The parent is a dotted name which the type system currently does not handle.
|
||||||
|
@ -813,6 +819,15 @@ void ZCCCompiler::CreateClassTypes()
|
||||||
|
|
||||||
if (parent != nullptr && (parent->VMType != nullptr || c->NodeName() == NAME_Object))
|
if (parent != nullptr && (parent->VMType != nullptr || c->NodeName() == NAME_Object))
|
||||||
{
|
{
|
||||||
|
if(parent->bFinal)
|
||||||
|
{
|
||||||
|
Error(c->cls, "Class '%s' cannot extend final class '%s'", FName(c->NodeName()).GetChars(), parent->TypeName.GetChars());
|
||||||
|
}
|
||||||
|
else if(parent->bSealed && !parent->SealedRestriction.Contains(c->NodeName()))
|
||||||
|
{
|
||||||
|
Error(c->cls, "Class '%s' cannot extend sealed class '%s'", FName(c->NodeName()).GetChars(), parent->TypeName.GetChars());
|
||||||
|
}
|
||||||
|
|
||||||
// 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)
|
||||||
{
|
{
|
||||||
|
@ -874,6 +889,25 @@ void ZCCCompiler::CreateClassTypes()
|
||||||
{
|
{
|
||||||
c->Type()->mVersion = c->cls->Version;
|
c->Type()->mVersion = c->cls->Version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (c->cls->Flags & ZCC_Final)
|
||||||
|
{
|
||||||
|
c->ClassType()->bFinal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->cls->Flags & ZCC_Sealed)
|
||||||
|
{
|
||||||
|
PClass * ccls = c->ClassType();
|
||||||
|
ccls->bSealed = true;
|
||||||
|
ZCC_Identifier * it = c->cls->Sealed;
|
||||||
|
if(it) do
|
||||||
|
{
|
||||||
|
ccls->SealedRestriction.Push(FName(it->Id));
|
||||||
|
it = (ZCC_Identifier*) it->SiblingNext;
|
||||||
|
}
|
||||||
|
while(it != c->cls->Sealed);
|
||||||
|
}
|
||||||
//
|
//
|
||||||
if (mVersion >= MakeVersion(2, 4, 0))
|
if (mVersion >= MakeVersion(2, 4, 0))
|
||||||
{
|
{
|
||||||
|
|
|
@ -232,6 +232,7 @@ static void InitTokenMap()
|
||||||
TOKENDEF (TK_Out, ZCC_OUT);
|
TOKENDEF (TK_Out, ZCC_OUT);
|
||||||
TOKENDEF (TK_Super, ZCC_SUPER);
|
TOKENDEF (TK_Super, ZCC_SUPER);
|
||||||
TOKENDEF (TK_Null, ZCC_NULLPTR);
|
TOKENDEF (TK_Null, ZCC_NULLPTR);
|
||||||
|
TOKENDEF (TK_Sealed, ZCC_SEALED);
|
||||||
TOKENDEF ('~', ZCC_TILDE);
|
TOKENDEF ('~', ZCC_TILDE);
|
||||||
TOKENDEF ('!', ZCC_BANG);
|
TOKENDEF ('!', ZCC_BANG);
|
||||||
TOKENDEF (TK_SizeOf, ZCC_SIZEOF);
|
TOKENDEF (TK_SizeOf, ZCC_SIZEOF);
|
||||||
|
|
|
@ -64,6 +64,7 @@ enum
|
||||||
ZCC_VirtualScope = 1 << 20,
|
ZCC_VirtualScope = 1 << 20,
|
||||||
ZCC_Version = 1 << 21,
|
ZCC_Version = 1 << 21,
|
||||||
ZCC_Internal = 1 << 22,
|
ZCC_Internal = 1 << 22,
|
||||||
|
ZCC_Sealed = 1 << 23,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function parameter modifiers
|
// Function parameter modifiers
|
||||||
|
@ -251,6 +252,7 @@ struct ZCC_Class : ZCC_Struct
|
||||||
{
|
{
|
||||||
ZCC_Identifier *ParentName;
|
ZCC_Identifier *ParentName;
|
||||||
ZCC_Identifier *Replaces;
|
ZCC_Identifier *Replaces;
|
||||||
|
ZCC_Identifier *Sealed;
|
||||||
|
|
||||||
PClass *CType() { return static_cast<PClassType *>(Type)->Descriptor; }
|
PClass *CType() { return static_cast<PClassType *>(Type)->Descriptor; }
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue