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 f61ad34bb..d89a89576 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 caeb18f8c..cc9968ae3 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 69927883c..19d331301 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 a37b7449b..12ce01273 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 eeeba6295..fc34fd2d7 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 ed85ab6b3..8389975ef 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 7d4edf78a..bc7857630 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 503ef7e9e..ca8c3f3cb 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 5144a1bd0..502b8d0cf 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);