From f99ac8b28b00728efea7ad7ee063335d63d7b997 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 5 Oct 2020 19:15:08 +0200 Subject: [PATCH] - allow struct extensions in zscript. This is mainly for splitting the Doom specific content off the main definitions for easier reuse. --- src/common/scripting/frontend/zcc-parse.lemon | 12 +++++++ src/common/scripting/frontend/zcc_compile.cpp | 34 +++++++++++++++++-- wadsrc/static/zscript.txt | 1 + wadsrc/static/zscript/base.zs | 22 ------------ wadsrc/static/zscript/doombase.zs | 24 +++++++++++++ wadsrc/static/zscript/ui/menu/optionmenu.zs | 2 +- 6 files changed, 70 insertions(+), 25 deletions(-) create mode 100644 wadsrc/static/zscript/doombase.zs diff --git a/src/common/scripting/frontend/zcc-parse.lemon b/src/common/scripting/frontend/zcc-parse.lemon index 9bf5932cf..79e52d831 100644 --- a/src/common/scripting/frontend/zcc-parse.lemon +++ b/src/common/scripting/frontend/zcc-parse.lemon @@ -234,6 +234,7 @@ class_head(X) ::= EXTEND CLASS(T) IDENTIFIER(A). X = head; } + class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C). { NEW_AST_NODE(Class,head,T); @@ -394,6 +395,17 @@ struct_def(X) ::= STRUCT(T) IDENTIFIER(A) struct_flags(S) LBRACE opt_struct_body X = def; } +struct_def(X) ::= EXTEND STRUCT(T) IDENTIFIER(A) LBRACE opt_struct_body(B) RBRACE opt_semicolon. +{ + NEW_AST_NODE(Struct,def,T); + def->NodeName = A.Name(); + def->Body = B; + def->Type = nullptr; + def->Symbol = nullptr; + def->Flags = ZCC_Extension; + X = def; +} + %type struct_flags{ClassFlagsBlock} struct_flags(X) ::= . { X.Flags = 0; X.Version = {0, 0}; } struct_flags(X) ::= struct_flags(A) UI. { X.Flags = A.Flags | ZCC_UIFlag; } diff --git a/src/common/scripting/frontend/zcc_compile.cpp b/src/common/scripting/frontend/zcc_compile.cpp index a4908e7bc..ac22942fd 100644 --- a/src/common/scripting/frontend/zcc_compile.cpp +++ b/src/common/scripting/frontend/zcc_compile.cpp @@ -377,8 +377,30 @@ void ZCCCompiler::ProcessMixin(ZCC_MixinDef *cnode, PSymbolTreeNode *treenode) void ZCCCompiler::ProcessStruct(ZCC_Struct *cnode, PSymbolTreeNode *treenode, ZCC_Class *outer) { - Structs.Push(new ZCC_StructWork(static_cast(cnode), treenode, outer)); - ZCC_StructWork *cls = Structs.Last(); + ZCC_StructWork* cls = nullptr; + + // If this is a struct extension, put the new node directly into the existing class. + if (cnode->Flags == ZCC_Extension) + { + for (auto strct : Structs) + { + if (strct->NodeName() == cnode->NodeName) + { + cls = strct; + break; + } + } + if (cls == nullptr) + { + Error(cnode, "Struct %s cannot be found in the current translation unit.", FName(cnode->NodeName).GetChars()); + return; + } + } + else + { + Structs.Push(new ZCC_StructWork(static_cast(cnode), treenode, outer)); + cls = Structs.Last(); + } auto node = cnode->Body; PSymbolTreeNode *childnode; @@ -494,7 +516,15 @@ ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols, ProcessClass(static_cast(node), tnode); break; } + goto common; case AST_Struct: + if (static_cast(node)->Flags == ZCC_Extension) + { + ProcessStruct(static_cast(node), tnode, nullptr); + break; + } + + common: case AST_ConstantDef: case AST_Enum: if ((tnode = AddTreeNode(static_cast(node)->NodeName, node, GlobalTreeNodes))) diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 5311aa291..6b1480c89 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -1,5 +1,6 @@ version "4.5" #include "zscript/base.zs" +#include "zscript/doombase.zs" #include "zscript/sounddata.zs" #include "zscript/mapdata.zs" #include "zscript/dynarrays.zs" diff --git a/wadsrc/static/zscript/base.zs b/wadsrc/static/zscript/base.zs index f99609a8f..8f2a61910 100644 --- a/wadsrc/static/zscript/base.zs +++ b/wadsrc/static/zscript/base.zs @@ -2,22 +2,13 @@ struct _ native // These are the global variables, the struct is only here to avoid extending the parser for this. { native readonly Array AllClasses; - native readonly Array > AllActorClasses; - native readonly Array<@PlayerClass> PlayerClasses; - native readonly Array<@PlayerSkin> PlayerSkins; - native readonly Array<@Team> Teams; - native int validcount; native readonly bool multiplayer; native @KeyBindings Bindings; native @KeyBindings AutomapBindings; - native play @DehInfo deh; native readonly @GameInfoStruct gameinfo; native readonly ui bool netgame; - - native readonly bool automapactive; native readonly uint gameaction; native readonly int gamestate; - native readonly TextureID skyflatnum; native readonly Font smallfont; native readonly Font smallfont2; native readonly Font bigfont; @@ -38,27 +29,14 @@ struct _ native // These are the global variables, the struct is only here to av native readonly int CleanHeight_1; native ui int menuactive; native readonly @FOptionMenuSettings OptionMenuSettings; - native readonly int gametic; native readonly bool demoplayback; native ui int BackbuttonTime; native ui float BackbuttonAlpha; - native readonly int Net_Arbitrator; - native ui BaseStatusBar StatusBar; - native readonly Weapon WP_NOCHANGE; - deprecated("3.8", "Use Actor.isFrozen() or Level.isFrozen() instead") native readonly bool globalfreeze; - native int LocalViewPitch; native readonly @MusPlayingInfo musplaying; native readonly bool generic_ui; native readonly int GameTicRate; native MenuCustomize menuCustomizer; - -// sandbox state in multi-level setups: - - native play @PlayerInfo players[MAXPLAYERS]; - native readonly bool playeringame[MAXPLAYERS]; native readonly int consoleplayer; - native play LevelLocals Level; - } struct MusPlayingInfo native diff --git a/wadsrc/static/zscript/doombase.zs b/wadsrc/static/zscript/doombase.zs new file mode 100644 index 000000000..4d59b2d54 --- /dev/null +++ b/wadsrc/static/zscript/doombase.zs @@ -0,0 +1,24 @@ + +extend struct _ +{ + native readonly Array > AllActorClasses; + native readonly Array<@PlayerClass> PlayerClasses; + native readonly Array<@PlayerSkin> PlayerSkins; + native readonly Array<@Team> Teams; + native int validcount; + native play @DehInfo deh; + native readonly bool automapactive; + native readonly TextureID skyflatnum; + native readonly int gametic; + native readonly int Net_Arbitrator; + native ui BaseStatusBar StatusBar; + native readonly Weapon WP_NOCHANGE; + deprecated("3.8", "Use Actor.isFrozen() or Level.isFrozen() instead") native readonly bool globalfreeze; + native int LocalViewPitch; + + // sandbox state in multi-level setups: + native play @PlayerInfo players[MAXPLAYERS]; + native readonly bool playeringame[MAXPLAYERS]; + native play LevelLocals Level; + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/ui/menu/optionmenu.zs b/wadsrc/static/zscript/ui/menu/optionmenu.zs index 38fa33c1b..ac136338a 100644 --- a/wadsrc/static/zscript/ui/menu/optionmenu.zs +++ b/wadsrc/static/zscript/ui/menu/optionmenu.zs @@ -235,7 +235,7 @@ class OptionMenu : Menu if (mDesc.mSelectedItem < 0) { // Figure out how many lines of text fit on the menu - int y = mDesc.mPosition; + int y = mDesc.mPosition; if (y <= 0) {