- added some syntactic help to the ZScript parser to allow defining the arrays with native structs on the script side instead of having to define them internally.

This commit is contained in:
Christoph Oelckers 2017-03-13 12:48:25 +01:00
parent fc8b697e33
commit 5fd86cf98c
16 changed files with 106 additions and 58 deletions

View file

@ -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 **************************************************************/

View file

@ -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);

View file

@ -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)

View file

@ -7147,7 +7147,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
{
PDynArray *darraytype = static_cast<PDynArray*>(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

View file

@ -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<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)); }
bool IsArray() const { return ValueType->IsKindOf(RUNTIME_CLASS(PArray)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PArray))); }
bool IsResizableArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PResizableArray))); } // can only exist in pointer form.
bool IsResizableArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(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);

View file

@ -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);

View file

@ -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)

View file

@ -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();

View file

@ -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);

View file

@ -1204,7 +1204,8 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &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<ZCC_VarDeclarator*>(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;
}

View file

@ -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);

View file

@ -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);

View file

@ -139,6 +139,7 @@ enum EZCCBuiltinType
ZCC_Sound,
ZCC_UserType,
ZCC_NativeType,
ZCC_Let,
ZCC_NUM_BUILT_IN_TYPES

View file

@ -341,7 +341,7 @@ class ThinkerIterator : Object native
}
class ActorIterator : Object native
{
{
native static ActorIterator Create(int tid, class<Actor> 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;

View file

@ -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<line_t *> Lines; // this is defined internally to avoid exposing some overly complicated type to the parser
native readonly Array<Line> lines;
native readonly @secplane floorplane;
native readonly @secplane ceilingplane;
native readonly Sector heightsec;
native uint bottommap, midmap, topmap;

View file

@ -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;