diff --git a/src/namedef.h b/src/namedef.h index 4346844fc..2a88a64a8 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -7,7 +7,6 @@ xx(Super) xx(Object) xx(Actor) xx(Class) -xx(ClassClass) xx(Untranslated) @@ -904,3 +903,12 @@ xx(Player8) xx(PlayerChunk) xx(RestrictedToPlayerClass) xx(ForbiddenToPlayerClass) + +xx(Prototype) +xx(Void) +xx(Label) +xx(Pointer) +xx(Enum) +xx(StaticArray) +xx(DynArray) +xx(Struct) \ No newline at end of file diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 9f14f5321..b510ee45f 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -5015,7 +5015,6 @@ int DLevelScript::LineFromID(int id) bool GetVarAddrType(AActor *self, FName varname, int index, void *&addr, PType *&type, bool readonly) { PField *var = dyn_cast(self->GetClass()->FindSymbol(varname, true)); - PArray *arraytype; if (var == NULL || (!readonly && (var->Flags & VARF_Native))) { @@ -5023,9 +5022,9 @@ bool GetVarAddrType(AActor *self, FName varname, int index, void *&addr, PType * } type = var->Type; uint8_t *baddr = reinterpret_cast(self) + var->Offset; - arraytype = dyn_cast(type); - if (arraytype != NULL) + if (type->isArray()) { + PArray *arraytype = static_cast(type); // unwrap contained type type = arraytype->ElementType; // offset by index (if in bounds) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index adff18027..19cafed23 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -4803,7 +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->isScalar()) + !var->Type->isArray() || !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/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 12c92e82d..8f746f7fe 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -219,7 +219,7 @@ static PClass *FindClassType(FName name, FCompileContext &ctx) if (sym && sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) { auto type = static_cast(sym); - auto ctype = dyn_cast(type->Type); + auto ctype = PType::toClass(type->Type); if (ctype) return ctype->Descriptor; } return nullptr; @@ -227,7 +227,7 @@ static PClass *FindClassType(FName name, FCompileContext &ctx) bool isActor(PContainerType *type) { - auto cls = dyn_cast(type); + auto cls = PType::toClass(type); return cls ? cls->Descriptor->IsDescendantOf(RUNTIME_CLASS(AActor)) : false; } @@ -303,7 +303,7 @@ static bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompar // A type is always compatible to itself. if (fromtype == totype) return true; // Pointers to different types are only compatible if both point to an object and the source type is a child of the destination type. - if (source->IsA(RUNTIME_CLASS(PObjectPointer)) && dest->IsA(RUNTIME_CLASS(PObjectPointer))) + if (source->isObjectPointer() && dest->isObjectPointer()) { auto fromcls = static_cast(source)->PointedClass(); auto tocls = static_cast(dest)->PointedClass(); @@ -311,7 +311,7 @@ static bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompar return (fromcls->IsDescendantOf(tocls)); } // The same rules apply to class pointers. A child type can be assigned to a variable of a parent type. - if (source->IsA(RUNTIME_CLASS(PClassPointer)) && dest->IsA(RUNTIME_CLASS(PClassPointer))) + if (source->isClassPointer() && dest->isClassPointer()) { auto fromcls = static_cast(source)->ClassRestriction; auto tocls = static_cast(dest)->ClassRestriction; @@ -1158,7 +1158,7 @@ FxExpression *FxNameCast::Resolve(FCompileContext &ctx) CHECKRESOLVED(); SAFE_RESOLVE(basex, ctx); - if (mExplicit && basex->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer))) + if (mExplicit && basex->ValueType->isClassPointer()) { if (basex->isConstant()) { @@ -1750,7 +1750,7 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) } } } - else if (ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer))) + else if (ValueType->isClassPointer()) { FxExpression *x = new FxClassTypeCast(static_cast(ValueType), basex, Explicit); x = x->Resolve(ctx); @@ -1758,14 +1758,14 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) delete this; return x; } - /* else if (ValueType->IsKindOf(RUNTIME_CLASS(PEnum))) + /* else if (ValueType->isEnum()) { // this is not yet ready and does not get assigned to actual values. } */ - else if (ValueType->IsKindOf(RUNTIME_CLASS(PClassType))) // this should never happen because the VM doesn't handle plain class types - just pointers + else if (ValueType->isClass()) // this should never happen because the VM doesn't handle plain class types - just pointers { - if (basex->ValueType->IsKindOf(RUNTIME_CLASS(PClassType))) + if (basex->ValueType->isClass()) { // class types are only compatible if the base type is a descendant of the result type. auto fromtype = static_cast(basex->ValueType)->Descriptor; @@ -2480,13 +2480,13 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx) } else if (Base->ValueType == Right->ValueType) { - if (Base->ValueType->IsKindOf(RUNTIME_CLASS(PArray))) + if (Base->ValueType->isArray()) { ScriptPosition.Message(MSG_ERROR, "Cannot assign arrays"); delete this; return nullptr; } - if (!Base->IsVector() && Base->ValueType->IsKindOf(RUNTIME_CLASS(PStruct))) + if (!Base->IsVector() && Base->ValueType->isStruct()) { ScriptPosition.Message(MSG_ERROR, "Struct assignment not implemented yet"); delete this; @@ -3611,7 +3611,7 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx) // Special cases: Compare strings and names with names, sounds, colors, state labels and class types. // These are all types a string can be implicitly cast into, so for convenience, so they should when doing a comparison. if ((left->ValueType == TypeString || left->ValueType == TypeName) && - (right->ValueType == TypeName || right->ValueType == TypeSound || right->ValueType == TypeColor || right->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) || right->ValueType == TypeStateLabel)) + (right->ValueType == TypeName || right->ValueType == TypeSound || right->ValueType == TypeColor || right->ValueType->isClassPointer() || right->ValueType == TypeStateLabel)) { left = new FxTypeCast(left, right->ValueType, false, true); left = left->Resolve(ctx); @@ -3619,7 +3619,7 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx) ValueType = right->ValueType; } else if ((right->ValueType == TypeString || right->ValueType == TypeName) && - (left->ValueType == TypeName || left->ValueType == TypeSound || left->ValueType == TypeColor || left->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) || left->ValueType == TypeStateLabel)) + (left->ValueType == TypeName || left->ValueType == TypeSound || left->ValueType == TypeColor || left->ValueType->isClassPointer() || left->ValueType == TypeStateLabel)) { right = new FxTypeCast(right, left->ValueType, false, true); right = right->Resolve(ctx); @@ -4596,7 +4596,7 @@ FxExpression *FxTypeCheck::Resolve(FCompileContext& ctx) RESOLVE(right, ctx); ABORT(right && left); - if (left->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer))) + if (left->ValueType->isClassPointer()) { left = new FxClassTypeCast(NewClassPointer(RUNTIME_CLASS(DObject)), left, false); ClassCheck = true; @@ -5140,7 +5140,7 @@ FxExpression *FxNew::Resolve(FCompileContext &ctx) SAFE_RESOLVE(val, ctx); CallingFunction = ctx.Function; - if (!val->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer))) + if (!val->ValueType->isClassPointer()) { ScriptPosition.Message(MSG_ERROR, "Class type expected"); delete this; @@ -6126,7 +6126,7 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType * { PSymbol *sym; PSymbolTable *symtbl; - bool isclass = objtype->IsKindOf(RUNTIME_CLASS(PClassType)); + bool isclass = objtype->isClass(); if (Identifier == NAME_Default) { @@ -6180,8 +6180,8 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType * object = nullptr; return nullptr; } - auto cls_ctx = dyn_cast(classctx); - auto cls_target = dyn_cast(objtype); + auto cls_ctx = PType::toClass(classctx); + auto cls_target = PType::toClass(objtype); // [ZZ] neither PSymbol, PField or PSymbolTable have the necessary information. so we need to do the more complex check here. if (vsym->Flags & VARF_Protected) { @@ -6403,7 +6403,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) return ret; } } - else if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PStruct))) + else if (Object->ValueType->isStruct()) { auto ret = ResolveMember(ctx, ctx.Class, Object, static_cast(Object->ValueType)); delete this; @@ -6972,7 +6972,7 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) if (membervar->SymbolName == NAME_Default) { - if (!classx->ValueType->IsKindOf(RUNTIME_CLASS(PObjectPointer)) + if (!classx->ValueType->isObjectPointer() || !static_cast(classx->ValueType)->PointedClass()->IsDescendantOf(RUNTIME_CLASS(AActor))) { ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type"); @@ -7028,7 +7028,7 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) return nullptr; } } - else if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PStruct))) + else if (classx->ValueType->isStruct()) { // if this is a struct within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. if (classx->ExprType == EFX_ClassMember || classx->ExprType == EFX_StructMember || classx->ExprType == EFX_GlobalVariable || classx->ExprType == EFX_StackVariable) @@ -7237,12 +7237,11 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) } else { - arraytype = dyn_cast(Array->ValueType); - if (arraytype == nullptr) + if (!Array->ValueType->isArray()) { // Check if we got a pointer to an array. Some native data structures (like the line list in sectors) use this. PPointer *ptype = Array->ValueType->toPointer(); - if (ptype == nullptr || !ptype->PointedType->IsKindOf(RUNTIME_CLASS(PArray))) + if (ptype == nullptr || !ptype->PointedType->isArray()) { ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays."); delete this; @@ -7251,10 +7250,14 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) arraytype = static_cast(ptype->PointedType); arrayispointer = true; } + else + { + arraytype = static_cast(Array->ValueType); + } elementtype = arraytype->ElementType; } - if (Array->IsResizableArray()) + if (Array->isStaticArray()) { // if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember || Array->ExprType == EFX_GlobalVariable || Array->ExprType == EFX_StackVariable) @@ -7498,8 +7501,8 @@ static bool CheckFunctionCompatiblity(FScriptPosition &ScriptPosition, PFunction bool match = (callingself == calledself); if (!match) { - auto callingselfcls = dyn_cast(caller->Variants[0].SelfClass); - auto calledselfcls = dyn_cast(callee->Variants[0].SelfClass); + auto callingselfcls = PType::toClass(caller->Variants[0].SelfClass); + auto calledselfcls = PType::toClass(callee->Variants[0].SelfClass); match = callingselfcls != nullptr && calledselfcls != nullptr && callingselfcls->Descriptor->IsDescendantOf(calledselfcls->Descriptor); } @@ -7860,7 +7863,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) if (CheckArgSize(MethodName, ArgList, 0, 1, ScriptPosition)) { // [ZZ] allow implicit new() call to mean "create current class instance" - if (!ArgList.Size() && !ctx.Class->IsKindOf(RUNTIME_CLASS(PClassType))) + if (!ArgList.Size() && !ctx.Class->isClass()) { ScriptPosition.Message(MSG_ERROR, "Cannot use implicit new() in a struct"); delete this; @@ -7969,7 +7972,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) { cls = ccls; staticonly = true; - if (ccls->IsKindOf(RUNTIME_CLASS(PClassType))) + if (ccls->isClass()) { if (ctx.Function == nullptr) { @@ -7977,7 +7980,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) delete this; return nullptr; } - auto clstype = dyn_cast(ctx.Function->Variants[0].SelfClass); + auto clstype = PType::toClass(ctx.Function->Variants[0].SelfClass); if (clstype != nullptr) { novirtual = clstype->Descriptor->IsDescendantOf(static_cast(ccls)->Descriptor); @@ -8009,7 +8012,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) delete this; return nullptr; } - auto clstype = dyn_cast(ctx.Function->Variants[0].SelfClass); + auto clstype = PType::toClass(ctx.Function->Variants[0].SelfClass); if (clstype != nullptr) { // give the node the proper value type now that we know it's properly used. @@ -8175,7 +8178,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) delete this; return nullptr; } - if (!Self->IsResizableArray()) + if (!Self->isStaticArray()) { auto atype = Self->ValueType; if (Self->ValueType->isPointer()) atype = ValueType->toPointer()->PointedType; @@ -8210,7 +8213,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) if (MethodName == NAME_GetParentClass && - (Self->IsObject() || Self->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)))) + (Self->IsObject() || Self->ValueType->isClassPointer())) { if (ArgList.Size() > 0) { @@ -8228,7 +8231,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) cls = ptype->toContainer(); if (cls != nullptr) { - if (ptype->IsKindOf(RUNTIME_CLASS(PClassType)) && MethodName == NAME_GetClass) + if (ptype->isClass() && MethodName == NAME_GetClass) { if (ArgList.Size() > 0) { @@ -8247,7 +8250,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) return nullptr; } } - else if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PStruct))) + else if (Self->ValueType->isStruct()) { bool writable; @@ -8328,8 +8331,8 @@ isresolved: { if (!novirtual || !(afd->Variants[0].Flags & VARF_Virtual)) { - auto clstype = dyn_cast(ctx.Class); - auto ccls = dyn_cast(cls); + auto clstype = PType::toClass(ctx.Class); + auto ccls = PType::toClass(cls); if (clstype == nullptr || ccls == nullptr || !clstype->Descriptor->IsDescendantOf(ccls->Descriptor)) { ScriptPosition.Message(MSG_ERROR, "Cannot call non-static function %s::%s from here", cls->TypeName.GetChars(), MethodName.GetChars()); @@ -8820,7 +8823,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->isRealPointer() && type->toPointer()->PointedType->IsA(RUNTIME_CLASS(PStruct))) + if (type == ArgList[i]->ValueType && type->isRealPointer() && type->toPointer()->PointedType->isStruct()) { // trying to pass a struct reference as a struct reference. This must preserve the type. } @@ -9331,7 +9334,7 @@ FxExpression *FxGetParentClass::Resolve(FCompileContext &ctx) { SAFE_RESOLVE(Self, ctx); - if (!Self->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && !Self->IsObject()) + if (!Self->ValueType->isClassPointer() && !Self->IsObject()) { ScriptPosition.Message(MSG_ERROR, "GetClass() requires an object"); delete this; @@ -9402,7 +9405,7 @@ FxExpression *FxGetDefaultByType::Resolve(FCompileContext &ctx) } else { - auto cp = dyn_cast(Self->ValueType); + auto cp = PType::toClassPointer(Self->ValueType); if (cp == nullptr || !cp->ClassRestriction->IsDescendantOf(RUNTIME_CLASS(AActor))) { ScriptPosition.Message(MSG_ERROR, "GetDefaultByType() requires an actor class type"); @@ -10601,7 +10604,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) return x; } auto to = static_cast(ValueType); - if (basex->ValueType->GetClass() == RUNTIME_CLASS(PClassPointer)) + if (basex->ValueType->isClassPointer()) { auto from = static_cast(basex->ValueType); if (from->ClassRestriction->IsDescendantOf(to->ClassRestriction)) @@ -10769,7 +10772,7 @@ FxExpression *FxClassPtrCast::Resolve(FCompileContext &ctx) return x; } auto to = static_cast(ValueType); - if (basex->ValueType->GetClass() == RUNTIME_CLASS(PClassPointer)) + if (basex->ValueType->isClassPointer()) { auto from = static_cast(basex->ValueType); // Downcast is always ok. @@ -10846,7 +10849,7 @@ FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); ABORT(ctx.Class); - auto vclass = dyn_cast(ctx.Class); + auto vclass = PType::toClass(ctx.Class); assert(vclass != nullptr); auto aclass = ValidateActor(vclass->Descriptor); @@ -10925,7 +10928,7 @@ FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx) SAFE_RESOLVE(Index, ctx); } - auto vclass = dyn_cast(ctx.Class); + auto vclass = PType::toClass(ctx.Class); assert(vclass != nullptr); auto aclass = ValidateActor(vclass->Descriptor); assert(aclass != nullptr && aclass->GetStateCount() > 0); @@ -10985,7 +10988,7 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) ABORT(ctx.Class); int symlabel; - auto vclass = dyn_cast(ctx.Class); + auto vclass = PType::toClass(ctx.Class); assert(vclass != nullptr); auto clstype = ValidateActor(vclass->Descriptor); @@ -11201,7 +11204,7 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build) else { // Init arrays and structs. - if (ValueType->IsA(RUNTIME_CLASS(PStruct))) + if (ValueType->isStruct()) { auto pstr = static_cast(ValueType); if (pstr->mConstructor != nullptr) @@ -11227,7 +11230,7 @@ void FxLocalVariableDeclaration::Release(VMFunctionBuilder *build) } else { - if (ValueType->IsA(RUNTIME_CLASS(PStruct))) + if (ValueType->isStruct()) { auto pstr = static_cast(ValueType); if (pstr->mDestructor != nullptr) diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index 06047225b..aa2e06910 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -335,11 +335,11 @@ public: bool IsPointer() const { return ValueType->isPointer(); } bool IsVector() const { return ValueType == TypeVector2 || ValueType == TypeVector3; }; 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->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); } + bool IsObject() const { return ValueType->isObjectPointer(); } + bool IsArray() const { return ValueType->isArray() || (ValueType->isPointer() && ValueType->toPointer()->PointedType->isArray()); } + bool isStaticArray() const { return (ValueType->isPointer() && ValueType->toPointer()->PointedType->isStaticArray()); } // can only exist in pointer form. + bool IsDynamicArray() const { return (ValueType->isDynArray()); } + bool IsNativeStruct() const { return (ValueType->isStruct() && static_cast(ValueType)->isNative); } virtual ExpEmit Emit(VMFunctionBuilder *build); void EmitStatement(VMFunctionBuilder *build); diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index 0f06b4063..488cce89d 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -203,7 +203,7 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type) x = new FxRuntimeStateIndex(ParseExpression(sc, cls)); } } - else if (type->GetClass() == RUNTIME_CLASS(PClassPointer)) + else if (type->isClassPointer()) { // Actor name sc.SetEscape(true); sc.MustGetString(); @@ -881,7 +881,7 @@ static void DispatchScriptProperty(FScanner &sc, PProperty *prop, AActor *defaul sc.MustGetString(); *(FString*)addr = strbin1(sc.String); } - else if (f->Type->IsKindOf(RUNTIME_CLASS(PClassPointer))) + else if (f->Type->isClassPointer()) { sc.MustGetString(); @@ -892,13 +892,14 @@ static void DispatchScriptProperty(FScanner &sc, PProperty *prop, AActor *defaul else { auto cls = PClass::FindClass(sc.String); + auto cp = static_cast(f->Type); if (cls == nullptr) { - cls = static_cast(f->Type)->ClassRestriction->FindClassTentative(sc.String); + cls = cp->ClassRestriction->FindClassTentative(sc.String); } - else if (!cls->IsDescendantOf(static_cast(f->Type)->ClassRestriction)) + else if (!cls->IsDescendantOf(cp->ClassRestriction)) { - sc.ScriptMessage("class %s is not compatible with property type %s", sc.String, static_cast(f->Type)->ClassRestriction->TypeName.GetChars()); + sc.ScriptMessage("class %s is not compatible with property type %s", sc.String, cp->ClassRestriction->TypeName.GetChars()); FScriptPosition::ErrorCounter++; } *(PClass**)addr = cls; diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 19a7316bc..a76fdd5fb 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -195,8 +195,8 @@ PFunction *FindClassMemberFunction(PContainerType *selfcls, PContainerType *func if (symbol != nullptr) { - auto cls_ctx = dyn_cast(funccls); - auto cls_target = funcsym ? dyn_cast(funcsym->OwningClass) : nullptr; + auto cls_ctx = PType::toClass(funccls); + auto cls_target = funcsym ? PType::toClass(funcsym->OwningClass) : nullptr; if (funcsym == nullptr) { sc.Message(MSG_ERROR, "%s is not a member function of %s", name.GetChars(), selfcls->TypeName.GetChars()); diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 374d8a524..c948d05e3 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -446,8 +446,8 @@ int MatchString (const char *in, const char **strings) static bool PointerCheck(PType *symtype, PType *checktype) { - auto symptype = dyn_cast(symtype); - auto checkptype = dyn_cast(checktype); + auto symptype = PType::toClassPointer(symtype); + auto checkptype = PType::toClassPointer(checktype); return symptype != nullptr && checkptype != nullptr && symptype->ClassRestriction->IsDescendantOf(checkptype->ClassRestriction); } diff --git a/src/scripting/types.cpp b/src/scripting/types.cpp index ae4fe67f1..3f990b62e 100644 --- a/src/scripting/types.cpp +++ b/src/scripting/types.cpp @@ -1407,6 +1407,7 @@ PObjectPointer::PObjectPointer(PClass *cls, bool isconst) : PPointer(cls->VMType, isconst) { loadOp = OP_LO; + Flags |= TYPE_ObjectPointer; // Non-destroyed thinkers are always guaranteed to be linked into the thinker chain so we don't need the write barrier for them. if (cls && !cls->IsDescendantOf(RUNTIME_CLASS(DThinker))) storeOp = OP_SO; } @@ -1545,6 +1546,7 @@ PClassPointer::PClassPointer(PClass *restrict) else mDescriptiveName = "ClassPointer"; loadOp = OP_LP; storeOp = OP_SP; + Flags |= TYPE_ClassPointer; mVersion = restrict->VMType->mVersion; } @@ -1664,6 +1666,7 @@ PEnum::PEnum(FName name, PTypeBase *outer) { EnumName = name; Outer = outer; + Flags |= TYPE_IntNotInt; mDescriptiveName.Format("Enum<%s>", name.GetChars()); } @@ -1721,6 +1724,7 @@ PArray::PArray(PType *etype, unsigned int ecount) // also be padded to the nearest alignment. ElementSize = (etype->Size + (etype->Align - 1)) & ~(etype->Align - 1); Size = ElementSize * ecount; + Flags |= TYPE_Array; } //========================================================================== diff --git a/src/scripting/types.h b/src/scripting/types.h index df5cdb826..15442b4e1 100644 --- a/src/scripting/types.h +++ b/src/scripting/types.h @@ -4,7 +4,6 @@ #include "serializer.h" // Variable/parameter/field flags ------------------------------------------- -class PStruct; // Making all these different storage types use a common set of flags seems // like the simplest thing to do. @@ -61,20 +60,12 @@ 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; +class PClassPointer; +class PArray; +class PStruct; +class PClassType; struct ZCC_ExprConstant; class PType : public PTypeBase @@ -82,6 +73,21 @@ class PType : public PTypeBase DECLARE_ABSTRACT_CLASS(PType, PTypeBase) protected: + 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_ObjectPointer = 64, + TYPE_ClassPointer = 128, + TYPE_Array = 256, + + 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. + }; + public: PClass *TypeTableType; // The type to use for hashing into the type table unsigned int Size; // this type's size @@ -183,10 +189,21 @@ public: 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 + bool isRealPointer() const { return (Flags & (TYPE_Pointer|TYPE_ClassPointer)) == TYPE_Pointer; } // This excludes class pointers which use their PointedType differently + bool isObjectPointer() const { return !!(Flags & TYPE_ObjectPointer); } + bool isClassPointer() const { return !!(Flags & TYPE_ClassPointer); } + bool isEnum() const { return TypeTableType->TypeName == NAME_Enum; } + bool isArray() const { return !!(Flags & TYPE_Array); } + bool isStaticArray() const { return TypeTableType->TypeName == NAME_StaticArray; } + bool isDynArray() const { return TypeTableType->TypeName == NAME_DynArray; } + bool isStruct() const { return TypeTableType->TypeName == NAME_Struct; } + bool isClass() const { return TypeTableType->TypeName == FName("ClassType"); } + bool isPrototype() const { return TypeTableType->TypeName == NAME_Prototype; } PContainerType *toContainer() { return isContainer() ? (PContainerType*)this : nullptr; } PPointer *toPointer() { return isPointer() ? (PPointer*)this : nullptr; } + static PClassPointer *toClassPointer(PType *t) { return t && t->isClassPointer() ? (PClassPointer*)t : nullptr; } + static PClassType *toClass(PType *t) { return t && t->isClass() ? (PClassType*)t : nullptr; } }; // Not-really-a-type types -------------------------------------------------- @@ -493,7 +510,7 @@ public: void SetPointer(void *base, unsigned offset, TArray *special) override; protected: - PArray(); + PArray();//deleteme }; class PStaticArray : public PArray @@ -506,7 +523,7 @@ public: virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; protected: - PStaticArray(); + PStaticArray();// deleteme }; class PDynArray : public PCompoundType @@ -529,7 +546,7 @@ public: void SetPointerArray(void *base, unsigned offset, TArray *ptrofs = NULL) const override; protected: - PDynArray(); + PDynArray(); // deleteme }; class PMap : public PCompoundType @@ -544,7 +561,7 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; protected: - PMap(); + PMap(); // deleteme }; class PStruct : public PContainerType @@ -568,7 +585,7 @@ public: void SetPointer(void *base, unsigned offset, TArray *specials) override; protected: - PStruct(); + PStruct(); // deleteme }; class PPrototype : public PCompoundType @@ -584,7 +601,7 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; protected: - PPrototype(); + PPrototype(); // deleteme }; diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 4bb2a4747..f7ac47718 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1320,7 +1320,7 @@ bool ZCCCompiler::CompileFields(PContainerType *type, TArraySize != ~0u && fd->FieldSize != ~0u && thisfieldtype->Size != fd->FieldSize && fd->BitValue == 0 && - (!thisfieldtype->IsA(RUNTIME_CLASS(PStruct)) || !static_cast(thisfieldtype)->isNative)) + (!thisfieldtype->isStruct() || !static_cast(thisfieldtype)->isNative)) { Error(field, "The member variable '%s.%s' has mismatching sizes in internal and external declaration. (Internal = %d, External = %d)", type == nullptr ? "" : type->TypeName.GetChars(), FName(name->Name).GetChars(), fd->FieldSize, thisfieldtype->Size); } @@ -1652,7 +1652,7 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n return TypeError; } auto typesym = dyn_cast(sym); - if (typesym == nullptr || !typesym->Type->IsKindOf(RUNTIME_CLASS(PClassType))) + if (typesym == nullptr || !typesym->Type->isClass()) { Error(field, "%s does not represent a class type", FName(ctype->Restriction->Id).GetChars()); return TypeError; @@ -1703,15 +1703,15 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt, boo return TypeError; } - if (ptype->IsKindOf(RUNTIME_CLASS(PEnum))) + if (ptype->isEnum()) { if (!nativetype) return TypeSInt32; // hack this to an integer until we can resolve the enum mess. } - else if (ptype->IsKindOf(RUNTIME_CLASS(PClassType))) // classes cannot be instantiated at all, they always get used as references. + else if (ptype->isClass()) // classes cannot be instantiated at all, they always get used as references. { return NewPointer(ptype, type->isconst); } - else if (ptype->IsKindOf(RUNTIME_CLASS(PStruct)) && static_cast(ptype)->isNative) // native structs and classes cannot be instantiated, they always get used as reference. + else if (ptype->isStruct() && static_cast(ptype)->isNative) // native structs and classes cannot be instantiated, they always get used as reference. { if (!nativetype) return NewPointer(ptype, type->isconst); return ptype; // instantiation of native structs. Only for internal use. @@ -2035,7 +2035,7 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop { *(FString*)addr = GetStringConst(ex, ctx); } - else if (f->Type->IsKindOf(RUNTIME_CLASS(PClassPointer))) + else if (f->Type->isClassPointer()) { auto clsname = GetStringConst(ex, ctx); if (*clsname == 0 || !stricmp(clsname, "none")) @@ -2045,13 +2045,14 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop else { auto cls = PClass::FindClass(clsname); + auto cp = static_cast(f->Type); if (cls == nullptr) { - cls = static_cast(f->Type)->ClassRestriction->FindClassTentative(clsname); + cls = cp->ClassRestriction->FindClassTentative(clsname); } - else if (!cls->IsDescendantOf(static_cast(f->Type)->ClassRestriction)) + else if (!cls->IsDescendantOf(cp->ClassRestriction)) { - Error(property, "class %s is not compatible with property type %s", clsname, static_cast(f->Type)->ClassRestriction->TypeName.GetChars()); + Error(property, "class %s is not compatible with property type %s", clsname, cp->ClassRestriction->TypeName.GetChars()); } *(PClass**)addr = cls; } @@ -2495,7 +2496,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool { auto type = DetermineType(c->Type(), p, f->Name, p->Type, false, false); int flags = 0; - if ((type->IsA(RUNTIME_CLASS(PStruct)) && type != TypeVector2 && type != TypeVector3) || type->IsA(RUNTIME_CLASS(PDynArray))) + if ((type->isStruct() && type != TypeVector2 && type != TypeVector3) || type->isDynArray()) { // Structs are being passed by pointer, but unless marked 'out' that pointer must be readonly. type = NewPointer(type /*, !(p->Flags & ZCC_Out)*/); @@ -2565,7 +2566,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool break; case REGT_POINTER: - if (type->IsKindOf(RUNTIME_CLASS(PClassPointer))) + if (type->isClassPointer()) vmval[0] = (DObject*)cnst->GetValue().GetPointer(); else vmval[0] = cnst->GetValue().GetPointer(); @@ -2609,7 +2610,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool sym->AddVariant(NewPrototype(rets, args), argflags, argnames, afd == nullptr ? nullptr : *(afd->VMPointer), varflags, useflags); c->Type()->Symbols.ReplaceSymbol(sym); - auto vcls = dyn_cast(c->Type()); + auto vcls = PType::toClass(c->Type()); auto cls = vcls ? vcls->Descriptor : nullptr; PFunction *virtsym = nullptr; if (cls != nullptr && cls->ParentClass != nullptr) virtsym = dyn_cast(cls->ParentClass->VMType->Symbols.FindSymbol(FName(f->Name), true)); @@ -2656,7 +2657,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool sym->Variants[0].Implementation->VarFlags = sym->Variants[0].Flags; } - PClass *clstype = static_cast(c->Type())->Descriptor; + PClass *clstype = forclass? static_cast(c->Type())->Descriptor : nullptr; if (varflags & VARF_Virtual) { if (sym->Variants[0].Implementation == nullptr) @@ -2817,7 +2818,7 @@ FxExpression *ZCCCompiler::SetupActionFunction(PClass *cls, ZCC_TreeNode *af, in { FArgumentList argumentlist; // We can use this function directly without wrapping it in a caller. - assert(dyn_cast(afd->Variants[0].SelfClass) != nullptr); // non classes are not supposed to get here. + assert(PType::toClass(afd->Variants[0].SelfClass) != nullptr); // non classes are not supposed to get here. int comboflags = afd->Variants[0].UseFlags & StateFlags; if (comboflags == StateFlags) // the function must satisfy all the flags the state requires