From a2116fc7bf682cb67d3c9c675930743fd83072ff Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 23 Oct 2016 12:57:21 +0200 Subject: [PATCH] - 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. --- src/p_mobj.cpp | 9 ++++++++ src/sc_man_scanner.re | 2 +- src/sc_man_tokens.h | 2 +- src/scripting/vm/vm.h | 1 + src/scripting/zscript/zcc-parse.lemon | 12 +++++++++++ src/scripting/zscript/zcc_compile.cpp | 31 +++++++++++++++++++++++++-- src/scripting/zscript/zcc_parser.cpp | 1 + src/scripting/zscript/zcc_parser.h | 1 + wadsrc/static/zscript/actor.txt | 7 ++++-- 9 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f61ad34bb7..d89a89576c 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -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); } +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) { if (source == NULL) diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index caeb18f8cc..cc9968ae3f 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -151,7 +151,7 @@ std2: 'transient' { RET(TK_Transient); } 'final' { RET(TK_Final); } 'throws' { RET(TK_Throws); } - 'extends' { RET(TK_Extends); } + 'extend' { RET(TK_Extend); } 'public' { RET(TK_Public); } 'protected' { RET(TK_Protected); } 'private' { RET(TK_Private); } diff --git a/src/sc_man_tokens.h b/src/sc_man_tokens.h index 69927883cb..19d3313019 100644 --- a/src/sc_man_tokens.h +++ b/src/sc_man_tokens.h @@ -89,7 +89,7 @@ xx(TK_Transient, "'transient'") xx(TK_Volatile, "'volatile'") xx(TK_Final, "'final'") xx(TK_Throws, "'throws'") -xx(TK_Extends, "'extends'") +xx(TK_Extend, "'extend'") xx(TK_Public, "'public'") xx(TK_Protected, "'protected'") xx(TK_Private, "'private'") diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index a37b7449b6..12ce012736 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -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_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_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) diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index eeeba6295a..fc34fd2d76 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -171,6 +171,18 @@ class_definition(X) ::= class_head(A) class_body(B). 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). { NEW_AST_NODE(Class,head,T); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index ed85ab6b32..8389975efa 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -61,8 +61,29 @@ void ZCCCompiler::ProcessClass(ZCC_Class *cnode, PSymbolTreeNode *treenode) { - Classes.Push(new ZCC_ClassWork(static_cast(cnode), treenode)); - auto cls = Classes.Last(); + ZCC_ClassWork *cls = nullptr; + // 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(cnode), treenode)); + cls = Classes.Last(); + } auto node = cnode->Body; PSymbolTreeNode *childnode; @@ -220,6 +241,12 @@ ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols, switch (node->NodeType) { case AST_Class: + // a class extension should not check the tree node symbols. + if (static_cast(node)->Flags == ZCC_Extension) + { + ProcessClass(static_cast(node), tnode); + break; + } case AST_Struct: case AST_ConstantDef: case AST_Enum: diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 7d4edf78a3..bc78576306 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -198,6 +198,7 @@ static void InitTokenMap() TOKENDEF (TK_Offset, ZCC_OFFSET); TOKENDEF (TK_CanRaise, ZCC_CANRAISE); TOKENDEF (TK_Light, ZCC_LIGHT); + TOKENDEF (TK_Extend, ZCC_EXTEND); ZCC_InitOperators(); ZCC_InitConversions(); diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index 503ef7e9e3..ca8c3f3cbf 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -32,6 +32,7 @@ enum ZCC_ReadOnly = 1 << 9, ZCC_FuncConst = 1 << 10, ZCC_Abstract = 1 << 11, + ZCC_Extension = 1 << 12, }; // Function parameter modifiers diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 5144a1bd09..502b8d0cfa 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -47,6 +47,9 @@ class Actor : Thinker native } // Functions + native Actor P_SpawnMissile(Actor dest, class type, Actor owner = null); + + // DECORATE compatible functions native bool CheckClass(class checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); native bool IsPointerEqual(int ptr_select1, int ptr_select2); native int CountInv(class itemtype, int ptr_select = AAPTR_DEFAULT); @@ -112,8 +115,8 @@ class Actor : Thinker native native void A_BetaSkullAttack(); native void A_Metal(); native void A_SpidRefire(); - native void A_BabyMetal(); - native void A_BspiAttack(); + //native void A_BabyMetal(); + //native void A_BspiAttack(); native void A_Hoof(); native void A_CyberAttack(); native void A_PainAttack(class spawntype = "LostSoul", float angle = 0, int flags = 0, int limit = -1);