From b2d944974e336830dda358ed69a0dd8b43d5ab1c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 13 Apr 2017 12:47:41 +0200 Subject: [PATCH] - first stage of simplifying the type system. Let's use inline checkers in PType instead of constantly having to do clumsy IsKindOf checks etc. Once complete this also means that the types can be taken out of the class hierarchy, freeing up some common names. --- src/dobjtype.cpp | 13 +--- src/dobjtype.h | 1 - src/info.cpp | 6 +- src/menu/menudef.cpp | 8 +-- src/p_acs.cpp | 15 +++-- src/p_actionfunctions.cpp | 5 +- src/p_setup.cpp | 2 +- src/scripting/backend/codegen.cpp | 76 +++++++++++------------ src/scripting/backend/codegen.h | 12 ++-- src/scripting/decorate/thingdef_parse.cpp | 6 +- src/scripting/symbols.cpp | 8 +-- src/scripting/types.cpp | 48 +++++++------- src/scripting/types.h | 47 +++++++++++--- src/scripting/zscript/ast.cpp | 2 +- src/scripting/zscript/zcc-parse.lemon | 8 +-- src/scripting/zscript/zcc_compile.cpp | 34 +++++----- 16 files changed, 153 insertions(+), 138 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 117180d75..0ae2b4771 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -205,7 +205,6 @@ void PClass::StaticInit () { atterm (StaticShutdown); - StaticBootstrap(); Namespaces.GlobalNamespace = Namespaces.NewNamespace(0); FAutoSegIterator probe(CRegHead, CRegTail); @@ -265,6 +264,7 @@ void PClass::StaticShutdown () ClassDataAllocator.FreeAllBlocks(); AllClasses.Clear(); PClassActor::AllActorClasses.Clear(); + ClassMap.Clear(); FAutoSegIterator probe(CRegHead, CRegTail); @@ -276,16 +276,6 @@ void PClass::StaticShutdown () } -//========================================================================== -// -// PClass :: StaticBootstrap STATIC -// -//========================================================================== - -void PClass::StaticBootstrap() -{ -} - //========================================================================== // // PClass Constructor @@ -363,7 +353,6 @@ void ClassReg::SetupClass(PClass *cls) cls->Size = SizeOf; cls->Pointers = Pointers; cls->ConstructNative = ConstructNative; - //cls->mDescriptiveName.Format("Class<%s>", cls->TypeName.GetChars()); } //========================================================================== diff --git a/src/dobjtype.h b/src/dobjtype.h index 24cd43451..b98f3e7b5 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -52,7 +52,6 @@ public: static void StaticInit(); static void StaticShutdown(); - static void StaticBootstrap(); // Per-class information ------------------------------------- PClass *ParentClass = nullptr; // the class this class derives from diff --git a/src/info.cpp b/src/info.cpp index c6072afca..aa0eac170 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -75,12 +75,12 @@ cycle_t ActionCycles; // //========================================================================== -class PActorInfo : public PBasicType +class PActorInfo : public PCompoundType { - DECLARE_CLASS(PActorInfo, PBasicType); + DECLARE_CLASS(PActorInfo, PCompoundType); public: PActorInfo() - :PBasicType(sizeof(FActorInfo), alignof(FActorInfo)) + :PCompoundType(sizeof(FActorInfo), alignof(FActorInfo)) { } diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 5a2f18974..8c80325c0 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -424,7 +424,7 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc) } params.Push(f.GetIndex()); } - else if (args[i]->IsKindOf(RUNTIME_CLASS(PInt))) + else if (args[i]->isIntCompatible()) { char *endp; int v = (int)strtoll(sc.String, &endp, 0); @@ -441,7 +441,7 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc) if (args[i] == TypeBool) v = !!v; params.Push(v); } - else if (args[i]->IsKindOf(RUNTIME_CLASS(PFloat))) + else if (args[i]->isFloat()) { char *endp; double v = strtod(sc.String, &endp); @@ -775,7 +775,7 @@ static void ParseOptionMenuBody(FScanner &sc, DOptionMenuDescriptor *desc) { params.Push(V_GetColor(nullptr, sc)); } - else if (args[i]->IsKindOf(RUNTIME_CLASS(PInt))) + else if (args[i]->isIntCompatible()) { char *endp; int v = (int)strtoll(sc.String, &endp, 0); @@ -794,7 +794,7 @@ static void ParseOptionMenuBody(FScanner &sc, DOptionMenuDescriptor *desc) if (args[i] == TypeBool) v = !!v; params.Push(v); } - else if (args[i]->IsKindOf(RUNTIME_CLASS(PFloat))) + else if (args[i]->isFloat()) { char *endp; double v = strtod(sc.String, &endp); diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 55dfdd8e6..9f14f5321 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -5040,12 +5040,11 @@ bool GetVarAddrType(AActor *self, FName varname, int index, void *&addr, PType * return false; } addr = baddr; - // We don't want Int subclasses like Name or Color to be accessible, - // but we do want to support Float subclasses like Fixed. - if (!type->IsA(RUNTIME_CLASS(PInt)) && !type->IsKindOf(RUNTIME_CLASS(PFloat))) + // We don't want Int subclasses like Name or Color to be accessible here. + if (!type->isInt() && !type->isFloat()) { // For reading, we also support Name and String types. - if (readonly && (type->IsA(RUNTIME_CLASS(PName)) || type->IsA(RUNTIME_CLASS(PString)))) + if (readonly && (type == TypeName || type == TypeString)) { return true; } @@ -5061,7 +5060,7 @@ static void SetUserVariable(AActor *self, FName varname, int index, int value) if (GetVarAddrType(self, varname, index, addr, type, false)) { - if (!type->IsKindOf(RUNTIME_CLASS(PFloat))) + if (!type->isFloat()) { type->SetValue(addr, value); } @@ -5079,15 +5078,15 @@ static int GetUserVariable(AActor *self, FName varname, int index) if (GetVarAddrType(self, varname, index, addr, type, true)) { - if (type->IsKindOf(RUNTIME_CLASS(PFloat))) + if (type->isFloat()) { return DoubleToACS(type->GetValueFloat(addr)); } - else if (type->IsA(RUNTIME_CLASS(PName))) + else if (type == TypeName) { return GlobalACSStrings.AddString(FName(ENamedName(type->GetValueInt(addr))).GetChars()); } - else if (type->IsA(RUNTIME_CLASS(PString))) + else if (type == TypeString) { return GlobalACSStrings.AddString(*(FString *)addr); } diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 030bdae51..adff18027 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -4753,7 +4753,7 @@ static PField *GetVar(DObject *self, FName varname) { PField *var = dyn_cast(self->GetClass()->FindSymbol(varname, true)); - if (var == NULL || (var->Flags & (VARF_Native | VARF_Private | VARF_Protected | VARF_Static)) || !var->Type->IsKindOf(RUNTIME_CLASS(PBasicType))) + if (var == NULL || (var->Flags & (VARF_Native | VARF_Private | VARF_Protected | VARF_Static)) || !var->Type->isScalar()) { Printf("%s is not a user variable in class %s\n", varname.GetChars(), self->GetClass()->TypeName.GetChars()); @@ -4803,8 +4803,7 @@ static PField *GetArrayVar(DObject *self, FName varname, int pos) PField *var = dyn_cast(self->GetClass()->FindSymbol(varname, true)); if (var == NULL || (var->Flags & (VARF_Native | VARF_Private | VARF_Protected | VARF_Static)) || - !var->Type->IsKindOf(RUNTIME_CLASS(PArray)) || - !static_cast(var->Type)->ElementType->IsKindOf(RUNTIME_CLASS(PBasicType))) + !var->Type->IsKindOf(RUNTIME_CLASS(PArray)) || !static_cast(var->Type)->ElementType->isScalar()) { Printf("%s is not a user array in class %s\n", varname.GetChars(), self->GetClass()->TypeName.GetChars()); diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 08cb7123c..341caab7b 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1621,7 +1621,7 @@ static void SetMapThingUserData(AActor *actor, unsigned udi) udi++; - if (var == NULL || (var->Flags & (VARF_Native|VARF_Private|VARF_Protected|VARF_Static)) || !var->Type->IsKindOf(RUNTIME_CLASS(PBasicType))) + if (var == NULL || (var->Flags & (VARF_Native|VARF_Private|VARF_Protected|VARF_Static)) || !var->Type->isScalar()) { DPrintf(DMSG_WARNING, "%s is not a user variable in class %s\n", varname.GetChars(), actor->GetClass()->TypeName.GetChars()); diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 0c47493ea..12c92e82d 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -207,7 +207,7 @@ static PContainerType *FindContainerType(FName name, FCompileContext &ctx) if (sym && sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) { auto type = static_cast(sym); - return dyn_cast(type->Type); + return type->Type->toContainer(); } return nullptr; } @@ -292,10 +292,10 @@ static PSymbol *FindBuiltinFunction(FName funcname, VMNativeFunction::NativeCall static bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompare = false) { - if (dest->IsKindOf(RUNTIME_CLASS(PPointer)) && source->IsKindOf(RUNTIME_CLASS(PPointer))) + if (dest->isPointer() && source->isPointer()) { - auto fromtype = static_cast(source); - auto totype = static_cast(dest); + auto fromtype = source->toPointer(); + auto totype = dest->toPointer(); // null pointers can be assigned to everything, everything can be assigned to void pointers. if (fromtype == nullptr || totype == TypeVoidPtr) return true; // when comparing const-ness does not matter. @@ -557,11 +557,11 @@ FxExpression *FxConstant::MakeConstant(PSymbol *sym, const FScriptPosition &pos) PSymbolConstNumeric *csym = dyn_cast(sym); if (csym != nullptr) { - if (csym->ValueType->IsA(RUNTIME_CLASS(PInt))) + if (csym->ValueType->isInt()) { x = new FxConstant(csym->Value, pos); } - else if (csym->ValueType->IsA(RUNTIME_CLASS(PFloat))) + else if (csym->ValueType->isFloat()) { x = new FxConstant(csym->Float, pos); } @@ -1356,7 +1356,7 @@ FxExpression *FxColorCast::Resolve(FCompileContext &ctx) CHECKRESOLVED(); SAFE_RESOLVE(basex, ctx); - if (basex->ValueType == TypeColor || basex->ValueType->GetClass() == RUNTIME_CLASS(PInt)) + if (basex->ValueType == TypeColor || basex->ValueType->isInt()) { FxExpression *x = basex; x->ValueType = TypeColor; @@ -1445,7 +1445,7 @@ FxExpression *FxSoundCast::Resolve(FCompileContext &ctx) CHECKRESOLVED(); SAFE_RESOLVE(basex, ctx); - if (basex->ValueType == TypeSound || basex->ValueType->GetClass() == RUNTIME_CLASS(PInt)) + if (basex->ValueType == TypeSound || basex->ValueType->isInt()) { FxExpression *x = basex; x->ValueType = TypeSound; @@ -1617,7 +1617,7 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) // don't go through the entire list if the types are the same. goto basereturn; } - else if (basex->ValueType == TypeNullPtr && (ValueType == TypeState || ValueType->IsKindOf(RUNTIME_CLASS(PPointer)))) + else if (basex->ValueType == TypeNullPtr && ValueType->isPointer()) { goto basereturn; } @@ -1629,7 +1629,7 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) delete this; return x; } - else if (ValueType->IsA(RUNTIME_CLASS(PInt))) + else if (ValueType->isInt()) { // This is only for casting to actual ints. Subtypes representing an int will be handled elsewhere. FxExpression *x = new FxIntCast(basex, NoWarn, Explicit); @@ -1773,7 +1773,7 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) if (fromtype->IsDescendantOf(totype)) goto basereturn; } } - else if (basex->IsNativeStruct() && ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType == basex->ValueType) + else if (basex->IsNativeStruct() && ValueType->isRealPointer() && ValueType->toPointer()->PointedType == basex->ValueType) { bool writable; basex->RequestAddress(ctx, &writable); @@ -2494,7 +2494,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx) } // Both types are the same so this is ok. } - else if (Right->IsNativeStruct() && Base->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(Base->ValueType)->PointedType == Right->ValueType) + else if (Right->IsNativeStruct() && Base->ValueType->isRealPointer() && Base->ValueType->toPointer()->PointedType == Right->ValueType) { // allow conversion of native structs to pointers of the same type. This is necessary to assign elements from global arrays like players, sectors, etc. to local pointers. // For all other types this is not needed. Structs are not assignable and classes can only exist as references. @@ -3649,12 +3649,12 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx) goto error; } } - else if (left->IsPointer() && static_cast(left->ValueType)->PointedType == right->ValueType) + else if (left->IsPointer() && left->ValueType->toPointer()->PointedType == right->ValueType) { bool writable; if (!right->RequestAddress(ctx, &writable)) goto error; } - else if (right->IsPointer() && static_cast(right->ValueType)->PointedType == left->ValueType) + else if (right->IsPointer() && right->ValueType->toPointer()->PointedType == left->ValueType) { bool writable; if (!left->RequestAddress(ctx, &writable)) goto error; @@ -4684,7 +4684,7 @@ FxExpression *FxDynamicCast::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); SAFE_RESOLVE(expr, ctx); - bool constflag = expr->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(expr->ValueType)->IsConst; + bool constflag = expr->ValueType->isPointer() && expr->ValueType->toPointer()->IsConst; if (constflag) { // readonly pointers are normally only used for class defaults which lack type information to be cast properly, so we have to error out here. @@ -6342,7 +6342,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) auto sn = static_cast(sym); VMValue vmv; - if (sn->ValueType->IsKindOf(RUNTIME_CLASS(PInt))) vmv = sn->Value; + if (sn->ValueType->isIntCompatible()) vmv = sn->Value; else vmv = sn->Float; auto x = new FxConstant(sn->ValueType, vmv, ScriptPosition); delete this; @@ -6393,10 +6393,10 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) { Object->ValueType = TypeColorStruct; } - if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) + if (Object->ValueType->isRealPointer()) { - auto ptype = static_cast(Object->ValueType)->PointedType; - if (ptype->IsKindOf(RUNTIME_CLASS(PContainerType))) + auto ptype = Object->ValueType->toPointer()->PointedType; + if (ptype->isContainer()) { auto ret = ResolveMember(ctx, ctx.Class, Object, static_cast(ptype)); delete this; @@ -6603,8 +6603,8 @@ FxExpression *FxClassDefaults::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); SAFE_RESOLVE(obj, ctx); - assert(obj->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))); - ValueType = NewPointer(static_cast(obj->ValueType)->PointedType, true); + assert(obj->ValueType->isRealPointer()); + ValueType = NewPointer(obj->ValueType->toPointer()->PointedType, true); return this; } @@ -6938,7 +6938,7 @@ bool FxStructMember::RequestAddress(FCompileContext &ctx, bool *writable) { // [ZZ] original check. bool bWritable = (AddressWritable && !ctx.CheckWritable(membervar->Flags) && - (!classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) || !static_cast(classx->ValueType)->IsConst)); + (!classx->ValueType->isPointer() || !classx->ValueType->toPointer()->IsConst)); // [ZZ] implement write barrier between different scopes if (bWritable) { @@ -7018,10 +7018,10 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) return x->Resolve(ctx); } - if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) + if (classx->ValueType->isPointer()) { - PPointer *ptrtype = dyn_cast(classx->ValueType); - if (ptrtype == nullptr || !ptrtype->PointedType->IsKindOf(RUNTIME_CLASS(PContainerType))) + PPointer *ptrtype = classx->ValueType->toPointer(); + if (ptrtype == nullptr || !ptrtype->PointedType->isContainer()) { ScriptPosition.Message(MSG_ERROR, "Member variable requires a struct or class object"); delete this; @@ -7241,7 +7241,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) if (arraytype == nullptr) { // Check if we got a pointer to an array. Some native data structures (like the line list in sectors) use this. - PPointer *ptype = dyn_cast(Array->ValueType); + PPointer *ptype = Array->ValueType->toPointer(); if (ptype == nullptr || !ptype->PointedType->IsKindOf(RUNTIME_CLASS(PArray))) { ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays."); @@ -7316,7 +7316,7 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) if (arrayispointer) { - arraytype = static_cast(static_cast(Array->ValueType)->PointedType); + arraytype = static_cast(Array->ValueType->toPointer()->PointedType); } else { @@ -8150,7 +8150,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) member->membervar = newfield; } } - else if (a->IsPointer() && Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) + else if (a->IsPointer() && Self->ValueType->isPointer()) { // the only case which must be checked up front is for pointer arrays receiving a new element. // Since there is only one native backing class it uses a neutral void pointer as its argument, @@ -8178,7 +8178,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) if (!Self->IsResizableArray()) { auto atype = Self->ValueType; - if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) atype = static_cast(ValueType)->PointedType; + if (Self->ValueType->isPointer()) atype = ValueType->toPointer()->PointedType; auto size = static_cast(atype)->ElementCount; auto x = new FxConstant(size, ScriptPosition); delete this; @@ -8222,10 +8222,11 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) return x->Resolve(ctx); } - if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !Self->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer))) + if (Self->ValueType->isRealPointer()) { - auto ptype = static_cast(Self->ValueType)->PointedType; - if (ptype->IsKindOf(RUNTIME_CLASS(PContainerType))) + auto ptype = Self->ValueType->toPointer()->PointedType; + cls = ptype->toContainer(); + if (cls != nullptr) { if (ptype->IsKindOf(RUNTIME_CLASS(PClassType)) && MethodName == NAME_GetClass) { @@ -8238,9 +8239,6 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) auto x = new FxGetClass(Self); return x->Resolve(ctx); } - - - cls = static_cast(ptype); } else { @@ -8759,7 +8757,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) // If this is a reference argument, the pointer type must be undone because the code below expects the pointed type as value type. if (argflags[i + k + implicit] & VARF_Ref) { - assert(ntype->IsKindOf(RUNTIME_CLASS(PPointer))); + assert(ntype->isPointer()); ntype = TypeNullPtr; // the default of a reference type can only be a null pointer } if (ntype->GetRegCount() == 1) @@ -8822,7 +8820,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) ArgList[i] = ArgList[i]->Resolve(ctx); // nust be resolved before the address is requested. if (ArgList[i] != nullptr && ArgList[i]->ValueType != TypeNullPtr) { - if (type == ArgList[i]->ValueType && type->IsA(RUNTIME_CLASS(PPointer)) && static_cast(type)->PointedType->IsA(RUNTIME_CLASS(PStruct))) + if (type == ArgList[i]->ValueType && type->isRealPointer() && type->toPointer()->PointedType->IsA(RUNTIME_CLASS(PStruct))) { // trying to pass a struct reference as a struct reference. This must preserve the type. } @@ -8937,7 +8935,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) if (innerside == FScopeBarrier::Side_Virtual) { - auto selfside = FScopeBarrier::SideFromObjectFlags(static_cast(Self->ValueType)->PointedType->ObjectFlags); + auto selfside = FScopeBarrier::SideFromObjectFlags(Self->ValueType->toPointer()->PointedType->ObjectFlags); int outerside = FScopeBarrier::SideFromFlags(CallingFunction->Variants[0].Flags); if (outerside == FScopeBarrier::Side_Virtual) @@ -9300,7 +9298,7 @@ FxExpression *FxGetClass::Resolve(FCompileContext &ctx) delete this; return nullptr; } - ValueType = NewClassPointer(static_cast(static_cast(Self->ValueType)->PointedType)->Descriptor); + ValueType = NewClassPointer(static_cast(Self->ValueType->toPointer()->PointedType)->Descriptor); return this; } diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index 1f6c8baca..06047225b 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -330,14 +330,14 @@ public: virtual bool CheckReturn() { return false; } virtual int GetBitValue() { return -1; } bool IsNumeric() const { return ValueType->isNumeric(); } - bool IsFloat() const { return ValueType->GetRegType() == REGT_FLOAT && ValueType->GetRegCount() == 1; } - bool IsInteger() const { return ValueType->isNumeric() && (ValueType->GetRegType() == REGT_INT); } - bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; } + bool IsFloat() const { return ValueType->isFloat(); } + bool IsInteger() const { return ValueType->isNumeric() && ValueType->isIntCompatible(); } + bool IsPointer() const { return ValueType->isPointer(); } bool IsVector() const { return ValueType == TypeVector2 || ValueType == TypeVector3; }; - bool IsBoolCompat() const { return ValueType->GetRegCount() == 1 && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT || ValueType->GetRegType() == REGT_POINTER); } + bool IsBoolCompat() const { return ValueType->isScalar(); } bool IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PObjectPointer)); } - 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(PStaticArray))); } // can only exist in pointer form. + bool IsArray() const { return ValueType->IsKindOf(RUNTIME_CLASS(PArray)) || (ValueType->isPointer() && ValueType->toPointer()->PointedType->IsKindOf(RUNTIME_CLASS(PArray))); } + bool IsResizableArray() const { return (ValueType->isPointer() && ValueType->toPointer()->PointedType->IsKindOf(RUNTIME_CLASS(PStaticArray))); } // can only exist in pointer form. bool IsDynamicArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PDynArray))); } bool IsNativeStruct() const { return (ValueType->IsA(RUNTIME_CLASS(PStruct)) && static_cast(ValueType)->isNative); } diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index 4758aaa23..0f06b4063 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -866,17 +866,17 @@ static void DispatchScriptProperty(FScanner &sc, PProperty *prop, AActor *defaul if (sc.CheckNumber()) *(int*)addr = sc.Number; else *(PalEntry*)addr = V_GetColor(nullptr, sc); } - else if (f->Type->IsKindOf(RUNTIME_CLASS(PInt))) + else if (f->Type->isIntCompatible()) { sc.MustGetNumber(); static_cast(f->Type)->SetValue(addr, sc.Number); } - else if (f->Type->IsKindOf(RUNTIME_CLASS(PFloat))) + else if (f->Type->isFloat()) { sc.MustGetFloat(); static_cast(f->Type)->SetValue(addr, sc.Float); } - else if (f->Type->IsKindOf(RUNTIME_CLASS(PString))) + else if (f->Type == TypeString) { sc.MustGetString(); *(FString*)addr = strbin1(sc.String); diff --git a/src/scripting/symbols.cpp b/src/scripting/symbols.cpp index 098ecaaa5..bb720875e 100644 --- a/src/scripting/symbols.cpp +++ b/src/scripting/symbols.cpp @@ -104,9 +104,9 @@ unsigned PFunction::AddVariant(PPrototype *proto, TArray &argflags, TA if (flags & VARF_Method) { assert(proto->ArgumentTypes.Size() > 0); - auto selftypeptr = dyn_cast(proto->ArgumentTypes[0]); + auto selftypeptr = proto->ArgumentTypes[0]->toPointer(); assert(selftypeptr != nullptr); - variant.SelfClass = dyn_cast(selftypeptr->PointedType); + variant.SelfClass = selftypeptr->PointedType->toContainer(); assert(variant.SelfClass != nullptr); } else @@ -155,7 +155,7 @@ PField::PField(FName name, PType *type, uint32_t flags, size_t offset, int bitva unsigned val = bitvalue; while ((val >>= 1)) BitValue++; - if (type->IsA(RUNTIME_CLASS(PInt)) && unsigned(BitValue) < 8u * type->Size) + if (type->isInt() && unsigned(BitValue) < 8u * type->Size) { // map to the single bytes in the actual variable. The internal bit instructions operate on 8 bit values. #ifndef __BIG_ENDIAN__ @@ -582,7 +582,7 @@ void RemoveUnusedSymbols() { for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext) { - if (ty->IsKindOf(RUNTIME_CLASS(PContainerType))) + if (ty->isContainer()) { auto it = ty->Symbols.GetIterator(); PSymbolTable::MapType::Pair *pair; diff --git a/src/scripting/types.cpp b/src/scripting/types.cpp index b445ad884..ae4fe67f1 100644 --- a/src/scripting/types.cpp +++ b/src/scripting/types.cpp @@ -377,16 +377,6 @@ void PType::StaticInit() IMPLEMENT_CLASS(PBasicType, true, false) -//========================================================================== -// -// PBasicType Default Constructor -// -//========================================================================== - -PBasicType::PBasicType() -{ -} - //========================================================================== // // PBasicType Parameterized Constructor @@ -397,12 +387,25 @@ PBasicType::PBasicType(unsigned int size, unsigned int align) : PType(size, align) { mDescriptiveName = "BasicType"; + Flags |= TYPE_Scalar; } /* PCompoundType **********************************************************/ IMPLEMENT_CLASS(PCompoundType, true, false) +//========================================================================== +// +// PBasicType Parameterized Constructor +// +//========================================================================== + +PCompoundType::PCompoundType(unsigned int size, unsigned int align) + : PType(size, align) +{ + mDescriptiveName = "CompoundType"; +} + /* PContainerType *************************************************************/ IMPLEMENT_CLASS(PContainerType, true, false) @@ -462,6 +465,7 @@ PInt::PInt(unsigned int size, bool unsign, bool compatible) : PBasicType(size, size), Unsigned(unsign), IntCompatible(compatible) { mDescriptiveName.Format("%cInt%d", unsign? 'U':'S', size); + Flags |= TYPE_Int; MemberOnly = (size < 4); if (!unsign) @@ -713,26 +717,13 @@ PBool::PBool() { mDescriptiveName = "Bool"; MemberOnly = false; + Flags |= TYPE_IntNotInt; } /* PFloat *****************************************************************/ IMPLEMENT_CLASS(PFloat, false, false) -//========================================================================== -// -// PFloat Default Constructor -// -//========================================================================== - -PFloat::PFloat() -: PBasicType(8, 8) -{ - mDescriptiveName = "Float"; - SetDoubleSymbols(); - SetOps(); -} - //========================================================================== // // PFloat Parameterized Constructor @@ -743,6 +734,7 @@ PFloat::PFloat(unsigned int size) : PBasicType(size, size) { mDescriptiveName.Format("Float%d", size); + Flags |= TYPE_Float; if (size == 8) { #ifdef __i386__ @@ -1085,6 +1077,7 @@ PName::PName() : PInt(sizeof(FName), true, false) { mDescriptiveName = "Name"; + Flags |= TYPE_IntNotInt; assert(sizeof(FName) == alignof(FName)); } @@ -1134,6 +1127,7 @@ IMPLEMENT_CLASS(PSpriteID, false, false) PSpriteID::PSpriteID() : PInt(sizeof(int), true, true) { + Flags |= TYPE_IntNotInt; mDescriptiveName = "SpriteID"; } @@ -1177,6 +1171,7 @@ PTextureID::PTextureID() : PInt(sizeof(FTextureID), true, false) { mDescriptiveName = "TextureID"; + Flags |= TYPE_IntNotInt; assert(sizeof(FTextureID) == alignof(FTextureID)); } @@ -1220,6 +1215,7 @@ PSound::PSound() : PInt(sizeof(FSoundID), true) { mDescriptiveName = "Sound"; + Flags |= TYPE_IntNotInt; assert(sizeof(FSoundID) == alignof(FSoundID)); } @@ -1270,6 +1266,7 @@ PColor::PColor() : PInt(sizeof(PalEntry), true) { mDescriptiveName = "Color"; + Flags |= TYPE_IntNotInt; assert(sizeof(PalEntry) == alignof(PalEntry)); } @@ -1286,6 +1283,7 @@ IMPLEMENT_CLASS(PStateLabel, false, false) PStateLabel::PStateLabel() : PInt(sizeof(int), false, false) { + Flags |= TYPE_IntNotInt; mDescriptiveName = "StateLabel"; } @@ -1307,6 +1305,7 @@ PPointer::PPointer() storeOp = OP_SP; moveOp = OP_MOVEA; RegType = REGT_POINTER; + Flags |= TYPE_Pointer; } //========================================================================== @@ -1332,6 +1331,7 @@ PPointer::PPointer(PType *pointsat, bool isconst) storeOp = OP_SP; moveOp = OP_MOVEA; RegType = REGT_POINTER; + Flags |= TYPE_Pointer; } //========================================================================== diff --git a/src/scripting/types.h b/src/scripting/types.h index 3c233c617..df5cdb826 100644 --- a/src/scripting/types.h +++ b/src/scripting/types.h @@ -61,6 +61,21 @@ enum // Map * * // Prototype *+ *+ +enum ETypeFlags +{ + TYPE_Scalar = 1, + TYPE_Container = 2, + TYPE_Int = 4, + TYPE_IntNotInt = 8, // catch-all for subtypes that are not being checked by type directly. + TYPE_Float = 16, + TYPE_Pointer = 32, + + TYPE_IntCompatible = TYPE_Int | TYPE_IntNotInt, // must be the combination of all flags that are subtypes of int and can be cast to an int. +}; + +class PContainerType; +class PPointer; + struct ZCC_ExprConstant; class PType : public PTypeBase { @@ -71,6 +86,7 @@ public: PClass *TypeTableType; // The type to use for hashing into the type table unsigned int Size; // this type's size unsigned int Align; // this type's preferred alignment + unsigned int Flags = 0; // What is this type? PType *HashNext; // next type in this type table PSymbolTable Symbols; bool MemberOnly = false; // type may only be used as a struct/class member but not as a local variable or function argument. @@ -160,6 +176,17 @@ public: const char *DescriptiveName() const; static void StaticInit(); + + bool isScalar() const { return !!(Flags & TYPE_Scalar); } + bool isContainer() const { return !!(Flags & TYPE_Container); } + bool isInt() const { return (Flags & TYPE_IntCompatible) == TYPE_Int; } + bool isIntCompatible() const { return !!(Flags & TYPE_IntCompatible); } + bool isFloat() const { return !!(Flags & TYPE_Float); } + bool isPointer() const { return !!(Flags & TYPE_Pointer); } + bool isRealPointer() const { return !!(Flags & TYPE_Pointer); } // This excludes class pointers which use their PointedType differently + + PContainerType *toContainer() { return isContainer() ? (PContainerType*)this : nullptr; } + PPointer *toPointer() { return isPointer() ? (PPointer*)this : nullptr; } }; // Not-really-a-type types -------------------------------------------------- @@ -183,14 +210,15 @@ public: class PBasicType : public PType { DECLARE_ABSTRACT_CLASS(PBasicType, PType); -public: - PBasicType(); - PBasicType(unsigned int size, unsigned int align); +protected: + PBasicType(unsigned int size = 1, unsigned int align = 1); }; class PCompoundType : public PType { DECLARE_ABSTRACT_CLASS(PCompoundType, PType); +protected: + PCompoundType(unsigned int size = 1, unsigned int align = 1); }; class PContainerType : public PCompoundType @@ -200,11 +228,15 @@ public: PTypeBase *Outer; // object this type is contained within FName TypeName; // this type's name - PContainerType() : Outer(NULL) { - mDescriptiveName = "NamedType"; + PContainerType() : Outer(NULL) + { + mDescriptiveName = "ContainerType"; + Flags |= TYPE_Container; } - PContainerType(FName name, PTypeBase *outer) : Outer(outer), TypeName(name) { + PContainerType(FName name, PTypeBase *outer) : Outer(outer), TypeName(name) + { mDescriptiveName = name.GetChars(); + Flags |= TYPE_Container; } virtual bool IsMatch(intptr_t id1, intptr_t id2) const; @@ -252,7 +284,7 @@ class PFloat : public PBasicType { DECLARE_CLASS(PFloat, PBasicType); public: - PFloat(unsigned int size); + PFloat(unsigned int size = 8); void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; @@ -263,7 +295,6 @@ public: virtual double GetValueFloat(void *addr) const; virtual bool isNumeric() override { return true; } protected: - PFloat(); void SetOps(); private: struct SymbolInitF diff --git a/src/scripting/zscript/ast.cpp b/src/scripting/zscript/ast.cpp index d886c8db2..463364f99 100644 --- a/src/scripting/zscript/ast.cpp +++ b/src/scripting/zscript/ast.cpp @@ -593,7 +593,7 @@ static void PrintExprConstant(FLispString &out, ZCC_TreeNode *node) { out.AddName(ENamedName(enode->IntVal)); } - else if (enode->Type->IsKindOf(RUNTIME_CLASS(PInt))) + else if (enode->Type->isIntCompatible()) { out.AddInt(enode->IntVal, static_cast(enode->Type)->Unsigned); } diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index cf7eb4566..923c40eef 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -403,7 +403,7 @@ enum_def(X) ::= ENUM(T) IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRAC // Compute implicit values by adding one to the preceding value. assert(prev->Value != NULL); // If the preceding node is a constant, then we can do this now. - if (prev->Value->Operation == PEX_ConstValue && prev->Value->Type->IsA(RUNTIME_CLASS(PInt))) + if (prev->Value->Operation == PEX_ConstValue && prev->Value->Type->isInt()) { NEW_INTCONST_NODE(cval, prev->Value->Type, static_cast(prev->Value)->IntVal + 1, node); node->Value = cval; @@ -1256,9 +1256,9 @@ unary_expr(X) ::= primary(X). unary_expr(X) ::= SUB unary_expr(A). [UNARY] { ZCC_ExprConstant *con = static_cast(A); - if (A->Operation == PEX_ConstValue && (con->Type->IsA(RUNTIME_CLASS(PInt)) || con->Type->IsA(RUNTIME_CLASS(PFloat)))) + if (A->Operation == PEX_ConstValue && (con->Type->isInt() || con->Type->isFloat())) { // For constants, manipulate the child node directly, and don't create a new node. - if (con->Type->IsA(RUNTIME_CLASS(PInt))) + if (con->Type->isInt()) { con->IntVal = -con->IntVal; } @@ -1280,7 +1280,7 @@ unary_expr(X) ::= ADD unary_expr(A). [UNARY] // it so we can type check that it is being applied to something numeric. // But we can do that right now for constant numerals. ZCC_ExprConstant *con = static_cast(A); - if (A->Operation != PEX_ConstValue || (!con->Type->IsA(RUNTIME_CLASS(PInt)) && !con->Type->IsA(RUNTIME_CLASS(PFloat)))) + if (A->Operation != PEX_ConstValue || (!con->Type->isInt() && !con->Type->isFloat())) { UNARY_EXPR(A,PEX_AntiNegate); X = expr1; diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 1e4acc9b1..4bb2a4747 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -873,13 +873,13 @@ void ZCCCompiler::AddConstant(ZCC_ConstantWork &constant) { def->Symbol = new PSymbolConstString(def->NodeName, *(cval->StringVal)); } - else if (cval->Type->IsA(RUNTIME_CLASS(PInt))) + else if (cval->Type->isInt()) { // How do we get an Enum type in here without screwing everything up??? //auto type = def->Type != nullptr ? def->Type : cval->Type; def->Symbol = new PSymbolConstNumeric(def->NodeName, cval->Type, cval->IntVal); } - else if (cval->Type->IsA(RUNTIME_CLASS(PFloat))) + else if (cval->Type->isFloat()) { if (def->Type != nullptr) { @@ -899,13 +899,13 @@ void ZCCCompiler::AddConstant(ZCC_ConstantWork &constant) { def->Symbol = new PSymbolConstString(def->NodeName, c.GetString()); } - else if (c.Type->IsA(RUNTIME_CLASS(PInt))) + else if (c.Type->isInt()) { // How do we get an Enum type in here without screwing everything up??? //auto type = def->Type != nullptr ? def->Type : cval->Type; def->Symbol = new PSymbolConstNumeric(def->NodeName, c.Type, c.GetInt()); } - else if (c.Type->IsA(RUNTIME_CLASS(PFloat))) + else if (c.Type->isFloat()) { if (def->Type != nullptr) { @@ -974,7 +974,7 @@ void ZCCCompiler::CompileArrays(ZCC_StructWork *work) FArgumentList values; // Don't use narrow typea for casting. - if (ctype->IsA(RUNTIME_CLASS(PInt))) ctype = static_cast(ztype)->Unsigned ? TypeUInt32 : TypeSInt32; + if (ctype->isInt()) ctype = static_cast(ztype)->Unsigned ? TypeUInt32 : TypeSInt32; else if (ctype == TypeFloat32) ctype = TypeFloat64; ConvertNodeList(values, sas->Values); @@ -1077,13 +1077,13 @@ ZCC_ExprConstant *ZCCCompiler::NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expres if (val->Type != TypeError) { assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); - if (sym->ValueType->IsKindOf(RUNTIME_CLASS(PInt))) + if (sym->ValueType->isIntCompatible()) { val->IntVal = static_cast(sym)->Value; } else { - assert(sym->ValueType->IsKindOf(RUNTIME_CLASS(PFloat))); + assert(sym->ValueType->isFloat()); val->DoubleVal = static_cast(sym)->Float; } } @@ -1752,7 +1752,7 @@ PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, ex = ex->Resolve(ctx); if (ex == nullptr) return TypeError; - if (!ex->isConstant() || !ex->ValueType->IsA(RUNTIME_CLASS(PInt))) + if (!ex->isConstant() || !ex->ValueType->isInt()) { Error(arraysize, "Array index must be an integer constant"); return TypeError; @@ -2023,15 +2023,15 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop { *(PalEntry*)addr = V_GetColor(nullptr, GetStringConst(ex, ctx), &ex->ScriptPosition); } - else if (f->Type->IsKindOf(RUNTIME_CLASS(PInt))) + else if (f->Type->isIntCompatible()) { static_cast(f->Type)->SetValue(addr, GetIntConst(ex, ctx)); } - else if (f->Type->IsKindOf(RUNTIME_CLASS(PFloat))) + else if (f->Type->isFloat()) { static_cast(f->Type)->SetValue(addr, GetFloatConst(ex, ctx)); } - else if (f->Type->IsKindOf(RUNTIME_CLASS(PString))) + else if (f->Type == TypeString) { *(FString*)addr = GetStringConst(ex, ctx); } @@ -2304,7 +2304,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool do { auto type = DetermineType(c->Type(), f, f->Name, t, false, false); - if (type->IsKindOf(RUNTIME_CLASS(PContainerType)) && type != TypeVector2 && type != TypeVector3) + if (type->isContainer() && type != TypeVector2 && type != TypeVector3) { // structs and classes only get passed by pointer. type = NewPointer(type); @@ -3228,23 +3228,23 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) case AST_ExprConstant: { auto cnst = static_cast(ast); - if (cnst->Type->IsA(RUNTIME_CLASS(PName))) + if (cnst->Type == TypeName) { return new FxConstant(FName(ENamedName(cnst->IntVal)), *ast); } - else if (cnst->Type->IsA(RUNTIME_CLASS(PInt))) + else if (cnst->Type->isInt()) { return new FxConstant(cnst->IntVal, *ast); } - else if (cnst->Type->IsA(RUNTIME_CLASS(PBool))) + else if (cnst->Type == TypeBool) { return new FxConstant(!!cnst->IntVal, *ast); } - else if (cnst->Type->IsA(RUNTIME_CLASS(PFloat))) + else if (cnst->Type->isFloat()) { return new FxConstant(cnst->DoubleVal, *ast); } - else if (cnst->Type->IsA(RUNTIME_CLASS(PString))) + else if (cnst->Type == TypeString) { return new FxConstant(*cnst->StringVal, *ast); }