diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 818543e89..ee1e03912 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1806,7 +1806,7 @@ PArray *NewArray(PType *type, unsigned int count) /* PArray *****************************************************************/ -IMPLEMENT_CLASS(PResizableArray, false, false) +IMPLEMENT_CLASS(PStaticArray, false, false) //========================================================================== // @@ -1814,7 +1814,7 @@ IMPLEMENT_CLASS(PResizableArray, false, false) // //========================================================================== -PResizableArray::PResizableArray() +PStaticArray::PStaticArray() { mDescriptiveName = "ResizableArray"; } @@ -1825,7 +1825,7 @@ PResizableArray::PResizableArray() // //========================================================================== -PResizableArray::PResizableArray(PType *etype) +PStaticArray::PStaticArray(PType *etype) : PArray(etype, 0) { mDescriptiveName.Format("ResizableArray<%s>", etype->DescriptiveName()); @@ -1837,7 +1837,7 @@ PResizableArray::PResizableArray(PType *etype) // //========================================================================== -bool PResizableArray::IsMatch(intptr_t id1, intptr_t id2) const +bool PStaticArray::IsMatch(intptr_t id1, intptr_t id2) const { const PType *elemtype = (const PType *)id1; unsigned int count = (unsigned int)(intptr_t)id2; @@ -1851,7 +1851,7 @@ bool PResizableArray::IsMatch(intptr_t id1, intptr_t id2) const // //========================================================================== -void PResizableArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +void PStaticArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const { id1 = (intptr_t)ElementType; id2 = 0; @@ -1859,23 +1859,23 @@ void PResizableArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const //========================================================================== // -// NewResizableArray +// NewStaticArray // // Returns a PArray for the given type and size, making sure not to create // duplicates. // //========================================================================== -PResizableArray *NewResizableArray(PType *type) +PStaticArray *NewStaticArray(PType *type) { size_t bucket; - PType *atype = TypeTable.FindType(RUNTIME_CLASS(PResizableArray), (intptr_t)type, 0, &bucket); + PType *atype = TypeTable.FindType(RUNTIME_CLASS(PStaticArray), (intptr_t)type, 0, &bucket); if (atype == nullptr) { - atype = new PResizableArray(type); - TypeTable.AddType(atype, RUNTIME_CLASS(PResizableArray), (intptr_t)type, 0, bucket); + atype = new PStaticArray(type); + TypeTable.AddType(atype, RUNTIME_CLASS(PStaticArray), (intptr_t)type, 0, bucket); } - return (PResizableArray *)atype; + return (PStaticArray *)atype; } /* PDynArray **************************************************************/ diff --git a/src/dobjtype.h b/src/dobjtype.h index c3ced5a63..854a809de 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -468,17 +468,17 @@ protected: PArray(); }; -class PResizableArray : public PArray +class PStaticArray : public PArray { - DECLARE_CLASS(PResizableArray, PArray); + DECLARE_CLASS(PStaticArray, PArray); public: - PResizableArray(PType *etype); + PStaticArray(PType *etype); virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; protected: - PResizableArray(); + PStaticArray(); }; class PDynArray : public PCompoundType @@ -706,7 +706,7 @@ extern FTypeTable TypeTable; // Returns a type from the TypeTable. Will create one if it isn't present. PMap *NewMap(PType *keytype, PType *valuetype); PArray *NewArray(PType *type, unsigned int count); -PResizableArray *NewResizableArray(PType *type); +PStaticArray *NewStaticArray(PType *type); PDynArray *NewDynArray(PType *type); PPointer *NewPointer(PType *type, bool isconst = false); PClassPointer *NewClassPointer(PClass *restrict); diff --git a/src/g_level.cpp b/src/g_level.cpp index f2ca8aea1..e1f77b624 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1902,6 +1902,11 @@ void FLevelLocals::AddScroller (int secnum) // //========================================================================== +DEFINE_FIELD(FLevelLocals, sectors) +DEFINE_FIELD(FLevelLocals, lines) +DEFINE_FIELD(FLevelLocals, sides) +DEFINE_FIELD(FLevelLocals, vertexes) +DEFINE_FIELD(FLevelLocals, sectorPortals) DEFINE_FIELD(FLevelLocals, time) DEFINE_FIELD(FLevelLocals, maptime) DEFINE_FIELD(FLevelLocals, totaltime) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 0ea6517da..74e04d429 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -7147,7 +7147,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) { PDynArray *darraytype = static_cast(Array->ValueType); elementtype = darraytype->ElementType; - Array->ValueType = NewPointer(NewResizableArray(elementtype)); // change type so that this can use the code for resizable arrays unchanged. + Array->ValueType = NewPointer(NewStaticArray(elementtype)); // change type so that this can use the code for resizable arrays unchanged. arrayispointer = true; } else diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index 0861ee4ed..a75ea5b02 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -335,7 +335,7 @@ public: bool IsBoolCompat() const { return ValueType->GetRegCount() == 1 && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT || ValueType->GetRegType() == REGT_POINTER); } bool IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && ValueType != TypeNullPtr && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)); } bool IsArray() const { return ValueType->IsKindOf(RUNTIME_CLASS(PArray)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PArray))); } - bool IsResizableArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PResizableArray))); } // can only exist in pointer form. + bool IsResizableArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PStaticArray))); } // can only exist in pointer form. bool IsDynamicArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PDynArray))); } virtual ExpEmit Emit(VMFunctionBuilder *build); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index c90cc17e8..db2abf597 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -853,16 +853,6 @@ void InitThingdef() } ); - // set up the lines array in the sector struct. This is a bit messy because the type system is not prepared to handle a pointer to an array of pointers to a native struct even remotely well... - // As a result, the size has to be set to something large and arbritrary because it can change between maps. This will need some serious improvement when things get cleaned up. - sectorstruct->AddNativeField("lines", NewPointer(NewResizableArray(NewPointer(linestruct, false)), false), myoffsetof(sector_t, Lines), VARF_Native); - - sectorstruct->AddNativeField("ceilingplane", secplanestruct, myoffsetof(sector_t, ceilingplane), VARF_Native | VARF_ReadOnly); - sectorstruct->AddNativeField("floorplane", secplanestruct, myoffsetof(sector_t, floorplane), VARF_Native | VARF_ReadOnly); - - - - // expose the global validcount variable. PField *vcf = new PField("validcount", TypeSInt32, VARF_Native | VARF_Static, (intptr_t)&validcount); Namespaces.GlobalNamespace->Symbols.AddSymbol(vcf); @@ -876,27 +866,19 @@ void InitThingdef() PField *levelf = new PField("level", lstruct, VARF_Native | VARF_Static, (intptr_t)&level); Namespaces.GlobalNamespace->Symbols.AddSymbol(levelf); - // Add the game data arrays to LevelLocals. - lstruct->AddNativeField("sectors", NewPointer(NewResizableArray(sectorstruct), false), myoffsetof(FLevelLocals, sectors), VARF_Native); - lstruct->AddNativeField("lines", NewPointer(NewResizableArray(linestruct), false), myoffsetof(FLevelLocals, lines), VARF_Native); - lstruct->AddNativeField("sides", NewPointer(NewResizableArray(sidestruct), false), myoffsetof(FLevelLocals, sides), VARF_Native); - lstruct->AddNativeField("vertexes", NewPointer(NewResizableArray(vertstruct), false), myoffsetof(FLevelLocals, vertexes), VARF_Native|VARF_ReadOnly); - lstruct->AddNativeField("sectorportals", NewPointer(NewResizableArray(sectorportalstruct), false), myoffsetof(FLevelLocals, sectorPortals), VARF_Native); - - - auto aact = NewPointer(NewResizableArray(NewClassPointer(RUNTIME_CLASS(AActor))), true); + auto aact = NewPointer(NewStaticArray(NewClassPointer(RUNTIME_CLASS(AActor))), true); PField *aacf = new PField("AllActorClasses", aact, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&PClassActor::AllActorClasses); Namespaces.GlobalNamespace->Symbols.AddSymbol(aacf); - auto plrcls = NewPointer(NewResizableArray(playerclassstruct), false); + auto plrcls = NewPointer(NewStaticArray(playerclassstruct), false); PField *plrclsf = new PField("PlayerClasses", plrcls, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&PlayerClasses); Namespaces.GlobalNamespace->Symbols.AddSymbol(plrclsf); - auto plrskn = NewPointer(NewResizableArray(playerskinstruct), false); + auto plrskn = NewPointer(NewStaticArray(playerskinstruct), false); PField *plrsknf = new PField("PlayerSkins", plrskn, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&Skins); Namespaces.GlobalNamespace->Symbols.AddSymbol(plrsknf); - auto teamst = NewPointer(NewResizableArray(teamstruct), false); + auto teamst = NewPointer(NewStaticArray(teamstruct), false); PField *teamf = new PField("Teams", teamst, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&Teams); Namespaces.GlobalNamespace->Symbols.AddSymbol(teamf); @@ -921,9 +903,6 @@ void InitThingdef() PField *fieldptr = new PField("players", parray, VARF_Native | VARF_Static, (intptr_t)&players); Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); - pstruct->AddNativeField("weapons", NewNativeStruct("WeaponSlots", nullptr), myoffsetof(player_t, weapons), VARF_Native); - - parray = NewArray(TypeBool, MAXPLAYERS); fieldptr = new PField("playeringame", parray, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&playeringame); Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 8a26a7d3f..df5d8a398 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -1099,7 +1099,7 @@ struct FieldDesc { const char *ClassName; const char *FieldName; - unsigned FieldOffset; + intptr_t FieldOffset; unsigned FieldSize; int BitValue; }; @@ -1169,6 +1169,12 @@ struct AFuncDesc extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \ MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname; +#define DEFINE_GLOBAL(name) \ + static const FieldDesc VMGlobal_##name = { nullptr, #name, (intptr_t)&name, (unsigned)sizeof(name), 0 }; \ + extern FieldDesc const *const VMGlobal_##name##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMGlobal_##name##_HookPtr GCC_FSEG = &VMGlobal_##name; + + class AActor; #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) diff --git a/src/scripting/zscript/ast.cpp b/src/scripting/zscript/ast.cpp index 63a098498..c410f4fc1 100644 --- a/src/scripting/zscript/ast.cpp +++ b/src/scripting/zscript/ast.cpp @@ -482,8 +482,9 @@ static void PrintBasicType(FLispString &out, ZCC_TreeNode *node) out.Open("basic-type"); PrintNodes(out, tnode->ArraySize); PrintBuiltInType(out, tnode->Type); - if (tnode->Type == ZCC_UserType) + if (tnode->Type == ZCC_UserType || tnode->Type == ZCC_NativeType) { + if (tnode->Type == ZCC_NativeType) out.Add("@", 1); PrintNodes(out, tnode->UserType, false); } out.Close(); diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index 58d87557a..8fe863dea 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -764,6 +764,18 @@ type_name(X) ::= IDENTIFIER(A). /* User-defined type (struct, enum, or class) id->Id = A.Name(); X = type; } + +type_name(X) ::= ATSIGN IDENTIFIER(A). +{ + NEW_AST_NODE(BasicType, type, A); + NEW_AST_NODE(Identifier, id, A); + type->Type = ZCC_NativeType; + type->UserType = id; + type->isconst = false; + id->Id = A.Name(); + X = type; +} + type_name(X) ::= READONLY LT IDENTIFIER(A) GT. { NEW_AST_NODE(BasicType, type, A); @@ -775,6 +787,17 @@ type_name(X) ::= READONLY LT IDENTIFIER(A) GT. X = type; } +type_name(X) ::= READONLY LT ATSIGN IDENTIFIER(A) GT. +{ + NEW_AST_NODE(BasicType, type, A); + NEW_AST_NODE(Identifier, id, A); + type->Type = ZCC_NativeType; + type->UserType = id; + type->isconst = true; + id->Id = A.Name(); + X = type; +} + type_name(X) ::= DOT dottable_id(A). { NEW_AST_NODE(BasicType, type, A); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index f18c3230f..6202be534 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1204,7 +1204,8 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel { Error(field, "The member variable '%s.%s' has not been exported from the executable.", type->TypeName.GetChars(), FName(name->Name).GetChars()); } - else if (thisfieldtype->Size != fd->FieldSize && fd->BitValue == 0) + // For native structs a size check cannot be done because they normally have no size. But for a native reference they are still fine. + else if (thisfieldtype->Size != ~0u && thisfieldtype->Size != fd->FieldSize && fd->BitValue == 0 && !thisfieldtype->IsA(RUNTIME_CLASS(PNativeStruct))) { Error(field, "The member variable '%s.%s' has mismatching sizes in internal and external declaration. (Internal = %d, External = %d)", type->TypeName.GetChars(), FName(name->Name).GetChars(), fd->FieldSize, thisfieldtype->Size); } @@ -1424,6 +1425,16 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n retval = TypeAuto; break; + case ZCC_NativeType: + + // Creating an instance of a native struct is only allowed for internal definitions of native variables. + if (Wads.GetLumpFile(Lump) != 0 || !formember) + { + Error(field, "%s: @ not allowed for user scripts", name.GetChars()); + } + retval = ResolveUserType(btype, &outertype->Symbols, true); + break; + case ZCC_UserType: // statelabel et.al. are not tokens - there really is no need to, it works just as well as an identifier. Maybe the same should be done for some other types, too? switch (btype->UserType->Id) @@ -1445,7 +1456,7 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n break; default: - retval = ResolveUserType(btype, &outertype->Symbols); + retval = ResolveUserType(btype, &outertype->Symbols, false); break; } break; @@ -1473,7 +1484,18 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n auto ftype = DetermineType(outertype, field, name, atype->ElementType, false, true); if (ftype->GetRegType() == REGT_NIL || ftype->GetRegCount() > 1) { - Error(field, "%s: Base type for dynamic array types nust be integral, but got %s", name.GetChars(), ftype->DescriptiveName()); + if (field->NodeType == AST_VarDeclarator && (static_cast(field)->Flags & ZCC_Native) && Wads.GetLumpFile(Lump) == 0) + { + // the internal definitions may declare native arrays to complex types. + // As long as they can be mapped to a static array type the VM can handle them, in a limited but sufficient fashion. + retval = NewPointer(NewStaticArray(ftype), false); + retval->Size = ~0u; // don't check for a size match, it's likely to fail anyway. + retval->Align = ~0u; + } + else + { + Error(field, "%s: Base type for dynamic array types nust be integral, but got %s", name.GetChars(), ftype->DescriptiveName()); + } } else { @@ -1537,7 +1559,7 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n // //========================================================================== -PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt) +PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt, bool nativetype) { // Check the symbol table for the identifier. PSymbol *sym = symt->FindSymbol(type->UserType->Id, true); @@ -1554,15 +1576,16 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt) if (ptype->IsKindOf(RUNTIME_CLASS(PEnum))) { - return TypeSInt32; // hack this to an integer until we can resolve the enum mess. + if (!nativetype) return TypeSInt32; // hack this to an integer until we can resolve the enum mess. } if (ptype->IsKindOf(RUNTIME_CLASS(PNativeStruct))) // native structs and classes cannot be instantiated, they always get used as reference. { - return NewPointer(ptype, type->isconst); + if (!nativetype) return NewPointer(ptype, type->isconst); + if (!ptype->IsKindOf(RUNTIME_CLASS(PClass))) return ptype; // instantiation of native structs. Only for internal use. } - return ptype; + if (!nativetype) return ptype; } - Error(type, "Unable to resolve %s as type.", FName(type->UserType->Id).GetChars()); + Error(type, "Unable to resolve %s%s as type.", nativetype? "@" : "", FName(type->UserType->Id).GetChars()); return TypeError; } diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index 3bc9aa178..8fe4ca36f 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -109,7 +109,7 @@ private: FString FlagsToString(uint32_t flags); PType *DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes, bool formember); PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PStruct *cls); - PType *ResolveUserType(ZCC_BasicType *type, PSymbolTable *sym); + PType *ResolveUserType(ZCC_BasicType *type, PSymbolTable *sym, bool nativetype); void InitDefaults(); void ProcessDefaultFlag(PClassActor *cls, ZCC_FlagStmt *flg); diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index c4f86eff1..1f0cb0242 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -92,6 +92,7 @@ static void InitTokenMap() TOKENDEF (TK_XorEq, ZCC_XOREQ); TOKENDEF ('?', ZCC_QUESTION); TOKENDEF (':', ZCC_COLON); + TOKENDEF ('@', ZCC_ATSIGN); TOKENDEF (TK_OrOr, ZCC_OROR); TOKENDEF (TK_AndAnd, ZCC_ANDAND); TOKENDEF (TK_Eq, ZCC_EQEQ); diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index 49384b522..29c6ec20c 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -139,6 +139,7 @@ enum EZCCBuiltinType ZCC_Sound, ZCC_UserType, + ZCC_NativeType, ZCC_Let, ZCC_NUM_BUILT_IN_TYPES diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 19667cf8a..3b08b8170 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -341,7 +341,7 @@ class ThinkerIterator : Object native } class ActorIterator : Object native -{ +{ native static ActorIterator Create(int tid, class type = "Actor"); native Actor Next(); native void Reinit(); @@ -396,6 +396,12 @@ struct LevelLocals native //UDMF_Thing // not implemented }; + native Array<@Sector> Sectors; + native Array<@Line> Lines; + native Array<@Side> Sides; + native readonly Array<@Vertex> Vertexes; + native Array<@SectorPortal> SectorPortals; + native readonly int time; native readonly int maptime; native readonly int totaltime; diff --git a/wadsrc/static/zscript/mapdata.txt b/wadsrc/static/zscript/mapdata.txt index d38d8417d..9ebed3818 100644 --- a/wadsrc/static/zscript/mapdata.txt +++ b/wadsrc/static/zscript/mapdata.txt @@ -201,7 +201,7 @@ struct SecSpecial play struct Sector native play { - //secplane_t floorplane, ceilingplane; // defined internally + //FDynamicColormap *ColorMap; native Actor SoundTarget; @@ -245,8 +245,11 @@ struct Sector native play native int prevsec; native int nextsec; - //TStaticPointedArray Lines; // this is defined internally to avoid exposing some overly complicated type to the parser + native readonly Array lines; + native readonly @secplane floorplane; + native readonly @secplane ceilingplane; + native readonly Sector heightsec; native uint bottommap, midmap, topmap; diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index d18b0bde4..038e62a9d 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -326,7 +326,7 @@ struct PlayerInfo native play // this is what internally is known as player_t native Actor ConversationPC; native double ConversationNPCAngle; native bool ConversationFaceTalker; - //native WeaponSlots weapons; <- defined internally + native @WeaponSlots weapons; /* these are not doable yet ticcmd_t cmd;