- created an export for P_SpawnMissile so that I can do some tests with functions.

- allow class extensions.

These are separate blocks in different files that get concatenated to one class body for processing. The reason is to allow spreading the many functions in Actor over multiple files, so that they remain manageable. For example, all the Doom action functions should be in their respective files, but their symbols need to be in Actor. To extend a class, both files need to be in the same translation unit, so it won't allow user-side extension of internal classes.
This commit is contained in:
Christoph Oelckers 2016-10-23 12:57:21 +02:00
parent f9cd2c9af7
commit a2116fc7bf
9 changed files with 60 additions and 6 deletions

View file

@ -5824,6 +5824,15 @@ AActor *P_SpawnMissile (AActor *source, AActor *dest, PClassActor *type, AActor
return P_SpawnMissileXYZ (source->PosPlusZ(32 + source->GetBobOffset()), source, dest, type, true, owner); return P_SpawnMissileXYZ (source->PosPlusZ(32 + source->GetBobOffset()), source, dest, type, true, owner);
} }
DEFINE_ACTION_FUNCTION(AActor, P_SpawnMissile)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(dest, AActor);
PARAM_CLASS(type, AActor);
PARAM_OBJECT_OPT(owner, AActor) { owner = self; }
ACTION_RETURN_OBJECT(P_SpawnMissile(self, dest, type, owner));
}
AActor *P_SpawnMissileZ (AActor *source, double z, AActor *dest, PClassActor *type) AActor *P_SpawnMissileZ (AActor *source, double z, AActor *dest, PClassActor *type)
{ {
if (source == NULL) if (source == NULL)

View file

@ -151,7 +151,7 @@ std2:
'transient' { RET(TK_Transient); } 'transient' { RET(TK_Transient); }
'final' { RET(TK_Final); } 'final' { RET(TK_Final); }
'throws' { RET(TK_Throws); } 'throws' { RET(TK_Throws); }
'extends' { RET(TK_Extends); } 'extend' { RET(TK_Extend); }
'public' { RET(TK_Public); } 'public' { RET(TK_Public); }
'protected' { RET(TK_Protected); } 'protected' { RET(TK_Protected); }
'private' { RET(TK_Private); } 'private' { RET(TK_Private); }

View file

@ -89,7 +89,7 @@ xx(TK_Transient, "'transient'")
xx(TK_Volatile, "'volatile'") xx(TK_Volatile, "'volatile'")
xx(TK_Final, "'final'") xx(TK_Final, "'final'")
xx(TK_Throws, "'throws'") xx(TK_Throws, "'throws'")
xx(TK_Extends, "'extends'") xx(TK_Extend, "'extend'")
xx(TK_Public, "'public'") xx(TK_Public, "'public'")
xx(TK_Protected, "'protected'") xx(TK_Protected, "'protected'")
xx(TK_Private, "'private'") xx(TK_Private, "'private'")

View file

@ -1013,6 +1013,7 @@ struct AFuncDesc
#define ACTION_RETURN_STATE(v) do { FState *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_STATE); return 1; } return 0; } while(0) #define ACTION_RETURN_STATE(v) do { FState *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_STATE); return 1; } return 0; } while(0)
#define ACTION_RETURN_OBJECT(v) do { auto state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_OBJECT); return 1; } return 0; } while(0)
#define ACTION_RETURN_FLOAT(v) do { double u = v; if (numret > 0) { assert(ret != nullptr); ret->SetFloat(u); return 1; } return 0; } while(0) #define ACTION_RETURN_FLOAT(v) do { double u = v; if (numret > 0) { assert(ret != nullptr); ret->SetFloat(u); return 1; } return 0; } while(0)
#define ACTION_RETURN_INT(v) do { int u = v; if (numret > 0) { assert(ret != NULL); ret->SetInt(u); return 1; } return 0; } while(0) #define ACTION_RETURN_INT(v) do { int u = v; if (numret > 0) { assert(ret != NULL); ret->SetInt(u); return 1; } return 0; } while(0)
#define ACTION_RETURN_BOOL(v) ACTION_RETURN_INT(v) #define ACTION_RETURN_BOOL(v) ACTION_RETURN_INT(v)

View file

@ -171,6 +171,18 @@ class_definition(X) ::= class_head(A) class_body(B).
X = A; /*X-overwrites-A*/ X = A; /*X-overwrites-A*/
} }
class_head(X) ::= EXTEND CLASS(T) IDENTIFIER(A).
{
NEW_AST_NODE(Class,head,T);
head->NodeName = A.Name();
head->ParentName = nullptr;
head->Flags = ZCC_Extension;
head->Replaces = nullptr;
head->Type = nullptr;
head->Symbol = nullptr;
X = head;
}
class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C). class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C).
{ {
NEW_AST_NODE(Class,head,T); NEW_AST_NODE(Class,head,T);

View file

@ -61,8 +61,29 @@
void ZCCCompiler::ProcessClass(ZCC_Class *cnode, PSymbolTreeNode *treenode) void ZCCCompiler::ProcessClass(ZCC_Class *cnode, PSymbolTreeNode *treenode)
{ {
Classes.Push(new ZCC_ClassWork(static_cast<ZCC_Class *>(cnode), treenode)); ZCC_ClassWork *cls = nullptr;
auto cls = Classes.Last(); // If this is a class extension, put the new node directly into the existing class.
if (cnode->Flags == ZCC_Extension)
{
for (auto clss : Classes)
{
if (clss->NodeName() == cnode->NodeName)
{
cls = clss;
break;
}
}
if (cls == nullptr)
{
Error(cnode, "Class %s cannot be found in the current translation unit.");
return;
}
}
else
{
Classes.Push(new ZCC_ClassWork(static_cast<ZCC_Class *>(cnode), treenode));
cls = Classes.Last();
}
auto node = cnode->Body; auto node = cnode->Body;
PSymbolTreeNode *childnode; PSymbolTreeNode *childnode;
@ -220,6 +241,12 @@ ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols,
switch (node->NodeType) switch (node->NodeType)
{ {
case AST_Class: case AST_Class:
// a class extension should not check the tree node symbols.
if (static_cast<ZCC_Class *>(node)->Flags == ZCC_Extension)
{
ProcessClass(static_cast<ZCC_Class *>(node), tnode);
break;
}
case AST_Struct: case AST_Struct:
case AST_ConstantDef: case AST_ConstantDef:
case AST_Enum: case AST_Enum:

View file

@ -198,6 +198,7 @@ static void InitTokenMap()
TOKENDEF (TK_Offset, ZCC_OFFSET); TOKENDEF (TK_Offset, ZCC_OFFSET);
TOKENDEF (TK_CanRaise, ZCC_CANRAISE); TOKENDEF (TK_CanRaise, ZCC_CANRAISE);
TOKENDEF (TK_Light, ZCC_LIGHT); TOKENDEF (TK_Light, ZCC_LIGHT);
TOKENDEF (TK_Extend, ZCC_EXTEND);
ZCC_InitOperators(); ZCC_InitOperators();
ZCC_InitConversions(); ZCC_InitConversions();

View file

@ -32,6 +32,7 @@ enum
ZCC_ReadOnly = 1 << 9, ZCC_ReadOnly = 1 << 9,
ZCC_FuncConst = 1 << 10, ZCC_FuncConst = 1 << 10,
ZCC_Abstract = 1 << 11, ZCC_Abstract = 1 << 11,
ZCC_Extension = 1 << 12,
}; };
// Function parameter modifiers // Function parameter modifiers

View file

@ -47,6 +47,9 @@ class Actor : Thinker native
} }
// Functions // Functions
native Actor P_SpawnMissile(Actor dest, class<Actor> type, Actor owner = null);
// DECORATE compatible functions
native bool CheckClass(class<Actor> checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); native bool CheckClass(class<Actor> checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false);
native bool IsPointerEqual(int ptr_select1, int ptr_select2); native bool IsPointerEqual(int ptr_select1, int ptr_select2);
native int CountInv(class<Inventory> itemtype, int ptr_select = AAPTR_DEFAULT); native int CountInv(class<Inventory> itemtype, int ptr_select = AAPTR_DEFAULT);
@ -112,8 +115,8 @@ class Actor : Thinker native
native void A_BetaSkullAttack(); native void A_BetaSkullAttack();
native void A_Metal(); native void A_Metal();
native void A_SpidRefire(); native void A_SpidRefire();
native void A_BabyMetal(); //native void A_BabyMetal();
native void A_BspiAttack(); //native void A_BspiAttack();
native void A_Hoof(); native void A_Hoof();
native void A_CyberAttack(); native void A_CyberAttack();
native void A_PainAttack(class<Actor> spawntype = "LostSoul", float angle = 0, int flags = 0, int limit = -1); native void A_PainAttack(class<Actor> spawntype = "LostSoul", float angle = 0, int flags = 0, int limit = -1);