From afd9347087eb62e5c996247ab2da8291d7449ed3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 16 Oct 2016 19:42:22 +0200 Subject: [PATCH] - changed order of script files to match the old DECORATE list for easy comparison of the disassembly. - added a descriptive name to all types for error messages. - added a generic type cast node to the code generator. - added a few more cast operations to the 'cast' VM instruction. - extended FxClassTypeCast to handle all possible input that can be cast to a class pointer, not just names. --- src/dobjtype.cpp | 47 ++ src/dobjtype.h | 11 +- src/scripting/codegeneration/codegen.cpp | 545 +++++++++++++++++++++- src/scripting/codegeneration/codegen.h | 74 ++- src/scripting/decorate/thingdef_parse.cpp | 2 +- src/scripting/vm/vm.h | 6 + src/scripting/vm/vmdisasm.cpp | 6 + src/scripting/vm/vmexec.cpp | 2 + src/scripting/vm/vmexec.h | 33 ++ src/scripting/zscript/zcc_compile.cpp | 6 +- wadsrc/static/zscript.txt | 6 +- 11 files changed, 723 insertions(+), 15 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index b023a2693..3d42059ca 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -199,6 +199,7 @@ END_POINTERS PType::PType() : Size(0), Align(1), HashNext(NULL) { + mDescriptiveName = "Type"; } //========================================================================== @@ -210,6 +211,7 @@ PType::PType() PType::PType(unsigned int size, unsigned int align) : Size(size), Align(align), HashNext(NULL) { + mDescriptiveName = "Type"; } //========================================================================== @@ -533,6 +535,17 @@ void PType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const id2 = 0; } +//========================================================================== +// +// PType :: GetTypeIDs +// +//========================================================================== + +const char *PType::DescriptiveName() const +{ + return mDescriptiveName.GetChars(); +} + //========================================================================== // // PType :: StaticInit STATIC @@ -649,6 +662,7 @@ PBasicType::PBasicType() PBasicType::PBasicType(unsigned int size, unsigned int align) : PType(size, align) { + mDescriptiveName = "BasicType"; } /* PCompoundType **********************************************************/ @@ -714,6 +728,7 @@ IMPLEMENT_CLASS(PInt) PInt::PInt() : PBasicType(4, 4), Unsigned(false) { + mDescriptiveName = "SInt32"; Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Min, this, -0x7FFFFFFF - 1)); Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Max, this, 0x7FFFFFFF)); } @@ -727,6 +742,8 @@ PInt::PInt() PInt::PInt(unsigned int size, bool unsign) : PBasicType(size, size), Unsigned(unsign) { + mDescriptiveName.Format("%cInt%d", unsign? 'U':'S', size); + MemberOnly = (size < 4); if (!unsign) { @@ -981,6 +998,8 @@ IMPLEMENT_CLASS(PBool) PBool::PBool() : PInt(sizeof(bool), true) { + mDescriptiveName = "Bool"; + MemberOnly = false; // Override the default max set by PInt's constructor PSymbolConstNumeric *maxsym = static_cast(Symbols.FindSymbol(NAME_Max, false)); assert(maxsym != NULL && maxsym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); @@ -1000,6 +1019,7 @@ IMPLEMENT_CLASS(PFloat) PFloat::PFloat() : PBasicType(8, 8) { + mDescriptiveName = "Float"; SetDoubleSymbols(); } @@ -1012,6 +1032,7 @@ PFloat::PFloat() PFloat::PFloat(unsigned int size) : PBasicType(size, size) { + mDescriptiveName.Format("Float%d", size); if (size == 8) { SetDoubleSymbols(); @@ -1274,6 +1295,7 @@ IMPLEMENT_CLASS(PString) PString::PString() : PBasicType(sizeof(FString), __alignof(FString)) { + mDescriptiveName = "String"; } //========================================================================== @@ -1376,6 +1398,7 @@ IMPLEMENT_CLASS(PName) PName::PName() : PInt(sizeof(FName), true) { + mDescriptiveName = "Name"; assert(sizeof(FName) == __alignof(FName)); } @@ -1425,6 +1448,7 @@ IMPLEMENT_CLASS(PSound) PSound::PSound() : PInt(sizeof(FSoundID), true) { + mDescriptiveName = "Sound"; assert(sizeof(FSoundID) == __alignof(FSoundID)); } @@ -1474,6 +1498,7 @@ IMPLEMENT_CLASS(PColor) PColor::PColor() : PInt(sizeof(PalEntry), true) { + mDescriptiveName = "Color"; assert(sizeof(PalEntry) == __alignof(PalEntry)); } @@ -1490,6 +1515,7 @@ IMPLEMENT_CLASS(PStatePointer) PStatePointer::PStatePointer() : PBasicType(sizeof(FState *), __alignof(FState *)) { + mDescriptiveName = "State"; } //========================================================================== @@ -1564,6 +1590,7 @@ END_POINTERS PPointer::PPointer() : PBasicType(sizeof(void *), __alignof(void *)), PointedType(NULL) { + mDescriptiveName = "Pointer"; } //========================================================================== @@ -1575,6 +1602,7 @@ PPointer::PPointer() PPointer::PPointer(PType *pointsat) : PBasicType(sizeof(void *), __alignof(void *)), PointedType(pointsat) { + mDescriptiveName.Format("Pointer<%s>", pointsat->DescriptiveName()); } //========================================================================== @@ -1708,6 +1736,7 @@ END_POINTERS PClassPointer::PClassPointer() : PPointer(RUNTIME_CLASS(PClass)), ClassRestriction(NULL) { + mDescriptiveName = "ClassPointer"; } //========================================================================== @@ -1719,6 +1748,7 @@ PClassPointer::PClassPointer() PClassPointer::PClassPointer(PClass *restrict) : PPointer(RUNTIME_CLASS(PClass)), ClassRestriction(restrict) { + mDescriptiveName.Format("ClassPointer<%s>", restrict->TypeName.GetChars()); } //========================================================================== @@ -1784,6 +1814,7 @@ END_POINTERS PEnum::PEnum() : ValueType(NULL) { + mDescriptiveName = "Enum"; } //========================================================================== @@ -1795,6 +1826,7 @@ PEnum::PEnum() PEnum::PEnum(FName name, PTypeBase *outer) : PNamedType(name, outer), ValueType(NULL) { + mDescriptiveName.Format("Enum<%s>", name.GetChars()); } //========================================================================== @@ -1833,6 +1865,7 @@ END_POINTERS PArray::PArray() : ElementType(NULL), ElementCount(0) { + mDescriptiveName = "Array"; } //========================================================================== @@ -1844,6 +1877,8 @@ PArray::PArray() PArray::PArray(PType *etype, unsigned int ecount) : ElementType(etype), ElementCount(ecount) { + mDescriptiveName.Format("Array<%s>[%d]", etype->DescriptiveName(), ecount); + Align = etype->Align; // Since we are concatenating elements together, the element size should // also be padded to the nearest alignment. @@ -1975,6 +2010,7 @@ IMPLEMENT_CLASS(PVector) PVector::PVector() : PArray(TypeFloat32, 3) { + mDescriptiveName = "Vector"; } //========================================================================== @@ -1986,6 +2022,7 @@ PVector::PVector() PVector::PVector(unsigned int size) : PArray(TypeFloat32, size) { + mDescriptiveName.Format("Vector<%d>", size); assert(size >= 2 && size <= 4); } @@ -2025,6 +2062,7 @@ END_POINTERS PDynArray::PDynArray() : ElementType(NULL) { + mDescriptiveName = "DynArray"; Size = sizeof(FArray); Align = __alignof(FArray); } @@ -2038,6 +2076,7 @@ PDynArray::PDynArray() PDynArray::PDynArray(PType *etype) : ElementType(etype) { + mDescriptiveName.Format("DynArray<%s>", etype->DescriptiveName()); Size = sizeof(FArray); Align = __alignof(FArray); } @@ -2105,6 +2144,7 @@ END_POINTERS PMap::PMap() : KeyType(NULL), ValueType(NULL) { + mDescriptiveName = "Map"; Size = sizeof(FMap); Align = __alignof(FMap); } @@ -2118,6 +2158,7 @@ PMap::PMap() PMap::PMap(PType *keytype, PType *valtype) : KeyType(keytype), ValueType(valtype) { + mDescriptiveName.Format("Map<%s, %s>", keytype->DescriptiveName(), valtype->DescriptiveName()); Size = sizeof(FMap); Align = __alignof(FMap); } @@ -2181,6 +2222,7 @@ IMPLEMENT_CLASS(PStruct) PStruct::PStruct() { + mDescriptiveName = "Struct"; } //========================================================================== @@ -2192,6 +2234,7 @@ PStruct::PStruct() PStruct::PStruct(FName name, PTypeBase *outer) : PNamedType(name, outer) { + mDescriptiveName.Format("Struct<%s>", name.GetChars()); } //========================================================================== @@ -2804,6 +2847,7 @@ PClass::PClass() Defaults = NULL; bRuntimeClass = false; ConstructNative = NULL; + mDescriptiveName = "Class"; PClass::AllClasses.Push(this); } @@ -2896,6 +2940,7 @@ void ClassReg::SetupClass(PClass *cls) cls->Size = SizeOf; cls->Pointers = Pointers; cls->ConstructNative = ConstructNative; + cls->mDescriptiveName.Format("Class<%s>", cls->TypeName.GetChars()); } //========================================================================== @@ -3108,6 +3153,7 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) type->TypeName = name; type->Size = size; type->bRuntimeClass = true; + type->mDescriptiveName.Format("Class<%s>", name.GetChars()); Derive(type); DeriveData(type); if (!notnew) @@ -3185,6 +3231,7 @@ PClass *PClass::FindClassTentative(FName name, bool fatal) type->ConstructNative = ConstructNative; type->Size = TentativeClass; type->bRuntimeClass = true; + type->mDescriptiveName.Format("Class<%s>", name.GetChars()); type->Symbols.SetParentTable(&Symbols); TypeTable.AddType(type, RUNTIME_CLASS(PClass), (intptr_t)type->Outer, name, bucket); return type; diff --git a/src/dobjtype.h b/src/dobjtype.h index 885e1ea0e..fd6e078ea 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -222,6 +222,7 @@ public: 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. + FString mDescriptiveName; PType(); PType(unsigned int size, unsigned int align); @@ -285,6 +286,8 @@ public: // Get the type IDs used by IsMatch virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + const char *DescriptiveName() const; + size_t PropagateMark(); static void StaticInit(); @@ -377,8 +380,12 @@ public: PTypeBase *Outer; // object this type is contained within FName TypeName; // this type's name - PNamedType() : Outer(NULL) {} - PNamedType(FName name, PTypeBase *outer) : Outer(outer), TypeName(name) {} + PNamedType() : Outer(NULL) { + mDescriptiveName = "NamedType"; + } + PNamedType(FName name, PTypeBase *outer) : Outer(outer), TypeName(name) { + mDescriptiveName = name.GetChars(); + } virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 91153f3ac..9b8a87eed 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -595,9 +595,9 @@ ExpEmit FxIntCast::Emit(VMFunctionBuilder *build) //========================================================================== FxFloatCast::FxFloatCast(FxExpression *x) -: FxExpression(x->ScriptPosition) + : FxExpression(x->ScriptPosition) { - basex=x; + basex = x; ValueType = TypeFloat64; } @@ -685,6 +685,519 @@ ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build) // //========================================================================== +FxNameCast::FxNameCast(FxExpression *x) + : FxExpression(x->ScriptPosition) +{ + basex = x; + ValueType = TypeName; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxNameCast::~FxNameCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxNameCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + if (basex->ValueType == TypeName) + { + FxExpression *x = basex; + basex = NULL; + delete this; + return x; + } + else if (basex->ValueType == TypeString) + { + if (basex->isConstant()) + { + ExpVal constval = static_cast(basex)->GetValue(); + FxExpression *x = new FxConstant(constval.GetName(), ScriptPosition); + delete this; + return x; + } + return this; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Cannot convert to name"); + delete this; + return NULL; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxNameCast::Emit(VMFunctionBuilder *build) +{ + ExpEmit from = basex->Emit(build); + assert(!from.Konst); + assert(basex->ValueType == TypeString); + from.Free(build); + ExpEmit to(build, REGT_INT); + build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_S2N); + return to; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxStringCast::FxStringCast(FxExpression *x) + : FxExpression(x->ScriptPosition) +{ + basex = x; + ValueType = TypeString; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxStringCast::~FxStringCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxStringCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + if (basex->ValueType == TypeString) + { + FxExpression *x = basex; + basex = NULL; + delete this; + return x; + } + else if (basex->ValueType == TypeName) + { + if (basex->isConstant()) + { + ExpVal constval = static_cast(basex)->GetValue(); + FxExpression *x = new FxConstant(constval.GetString(), ScriptPosition); + delete this; + return x; + } + return this; + } + else if (basex->ValueType == TypeSound) + { + if (basex->isConstant()) + { + ExpVal constval = static_cast(basex)->GetValue(); + FxExpression *x = new FxConstant(S_sfx[constval.GetInt()].name, ScriptPosition); + delete this; + return x; + } + return this; + } + // although it could be done, let's not convert colors back to strings. + else + { + ScriptPosition.Message(MSG_ERROR, "Cannot convert to string"); + delete this; + return NULL; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxStringCast::Emit(VMFunctionBuilder *build) +{ + ExpEmit from = basex->Emit(build); + assert(!from.Konst); + + from.Free(build); + ExpEmit to(build, REGT_STRING); + if (ValueType == TypeName) + { + build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_N2S); + } + else if (ValueType == TypeSound) + { + build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_So2S); + } + return to; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxColorCast::FxColorCast(FxExpression *x) + : FxExpression(x->ScriptPosition) +{ + basex = x; + ValueType = TypeColor; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxColorCast::~FxColorCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxColorCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + if (basex->ValueType == TypeColor || basex->ValueType->GetClass() == RUNTIME_CLASS(PInt)) + { + FxExpression *x = basex; + x->ValueType = TypeColor; + basex = NULL; + delete this; + return x; + } + else if (basex->ValueType == TypeString) + { + if (basex->isConstant()) + { + ExpVal constval = static_cast(basex)->GetValue(); + FxExpression *x = new FxConstant(V_GetColor(nullptr, constval.GetString()), ScriptPosition); + delete this; + return x; + } + return this; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Cannot convert to color"); + delete this; + return NULL; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxColorCast::Emit(VMFunctionBuilder *build) +{ + ExpEmit from = basex->Emit(build); + assert(!from.Konst); + assert(basex->ValueType == TypeString); + from.Free(build); + ExpEmit to(build, REGT_INT); + build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_S2Co); + return to; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxSoundCast::FxSoundCast(FxExpression *x) + : FxExpression(x->ScriptPosition) +{ + basex = x; + ValueType = TypeSound; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxSoundCast::~FxSoundCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxSoundCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + if (basex->ValueType == TypeSound || basex->ValueType->GetClass() == RUNTIME_CLASS(PInt)) + { + FxExpression *x = basex; + x->ValueType = TypeSound; + basex = NULL; + delete this; + return x; + } + else if (basex->ValueType == TypeString) + { + if (basex->isConstant()) + { + ExpVal constval = static_cast(basex)->GetValue(); + FxExpression *x = new FxConstant(FSoundID(constval.GetString()), ScriptPosition); + delete this; + return x; + } + return this; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Cannot convert to sound"); + delete this; + return NULL; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxSoundCast::Emit(VMFunctionBuilder *build) +{ + ExpEmit from = basex->Emit(build); + assert(!from.Konst); + assert(basex->ValueType == TypeString); + from.Free(build); + ExpEmit to(build, REGT_INT); + build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_S2So); + return to; +} + +//========================================================================== +// +// generic type cast operator +// +//========================================================================== + +FxTypeCast::FxTypeCast(FxExpression *x, PType *type, bool nowarn) + : FxExpression(x->ScriptPosition) +{ + basex = x; + ValueType = type; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxTypeCast::~FxTypeCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + // first deal with the simple types + if (ValueType == TypeError || basex->ValueType == TypeError) + { + delete this; + return nullptr; + } + else if (ValueType == TypeVoid) // this should never happen + { + goto errormsg; + } + else if (basex->ValueType == TypeVoid) + { + goto errormsg; + } + else if (basex->ValueType == ValueType) + { + // don't go through the entire list if the types are the same. + goto basereturn; + } + else if (ValueType->GetRegType() == REGT_FLOAT) + { + FxExpression *x = new FxFloatCast(basex); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + else if (ValueType->IsA(RUNTIME_CLASS(PInt))) + { + // This is only for casting to actual ints. Subtypes representing an int will be handled elsewhere. + FxExpression *x = new FxIntCast(basex, NoWarn); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + else if (ValueType == TypeBool) + { + FxExpression *x = new FxBoolCast(basex); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + else if (ValueType == TypeString) + { + FxExpression *x = new FxStringCast(basex); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + else if (ValueType == TypeName) + { + FxExpression *x = new FxNameCast(basex); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + else if (ValueType == TypeSound) + { + FxExpression *x = new FxSoundCast(basex); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + else if (ValueType == TypeColor) + { + FxExpression *x = new FxColorCast(basex); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + else if (ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer))) + { + FxExpression *x = new FxClassTypeCast(static_cast(ValueType), basex); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + /* else if (ValueType->IsKindOf(RUNTIME_CLASS(PEnum))) + { + // this is not yet ready and does not get assigned to actual values. + } + */ + else if (ValueType->IsKindOf(RUNTIME_CLASS(PClass))) // this should never happen because the VM doesn't handle plain class types - just pointers + { + if (basex->ValueType->IsKindOf(RUNTIME_CLASS(PClass))) + { + // class types are only compatible if the base type is a descendant of the result type. + auto fromtype = static_cast(basex->ValueType); + auto totype = static_cast(ValueType); + if (fromtype->IsDescendantOf(totype)) goto basereturn; + } + } + else if (ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) + { + // 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 (basex->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) + { + auto fromtype = static_cast(basex->ValueType); + auto totype = static_cast(ValueType); + if (fromtype->PointedType->IsKindOf(RUNTIME_CLASS(PClass)) && totype->PointedType->IsKindOf(RUNTIME_CLASS(PClass))) + { + + auto fromcls = static_cast(fromtype->PointedType); + auto tocls = static_cast(totype->PointedType); + if (fromcls->IsDescendantOf(tocls)) goto basereturn; + } + } + } + // todo: pointers to class objects. + // All other types are only compatible to themselves and have already been handled above by the equality check. + // Anything that falls through here is not compatible and must print an error. + +errormsg: + ScriptPosition.Message(MSG_ERROR, "Cannot convert %s to %s", basex->ValueType->DescriptiveName(), ValueType->DescriptiveName()); + delete this; + return nullptr; + +basereturn: + auto x = basex; + basex = nullptr; + delete this; + return x; + +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxTypeCast::Emit(VMFunctionBuilder *build) +{ + assert(false); + // This should never be reached + return ExpEmit(); +} + +//========================================================================== +// +// +// +//========================================================================== + FxPlusSign::FxPlusSign(FxExpression *operand) : FxExpression(operand->ScriptPosition) { @@ -5030,10 +5543,11 @@ VMFunction *FxReturnStatement::GetDirectFunction() // //========================================================================== -FxClassTypeCast::FxClassTypeCast(PClass *dtype, FxExpression *x) +FxClassTypeCast::FxClassTypeCast(PClassPointer *dtype, FxExpression *x) : FxExpression(x->ScriptPosition) { - desttype = dtype; + ValueType = dtype; + desttype = dtype->ClassRestriction; basex=x; } @@ -5058,8 +5572,25 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); SAFE_RESOLVE(basex, ctx); + + if (basex->ValueType->GetClass() == RUNTIME_CLASS(PClassPointer)) + { + auto to = static_cast(ValueType); + auto from = static_cast(basex->ValueType); + if (from->ClassRestriction->IsDescendantOf(to->ClassRestriction)) + { + basex->ValueType = to; + auto x = basex; + basex = nullptr; + delete this; + return x; + } + ScriptPosition.Message(MSG_ERROR, "Cannot convert from %s to %s: Incompatible class types", from->ClassRestriction->TypeName.GetChars(), to->ClassRestriction->TypeName.GetChars()); + delete this; + return nullptr; + } - if (basex->ValueType != TypeName) + if (basex->ValueType != TypeName && basex->ValueType != TypeString) { ScriptPosition.Message(MSG_ERROR, "Cannot convert to class type"); delete this; @@ -5097,6 +5628,10 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) delete this; return x; } + if (basex->ValueType == TypeString) + { + basex = new FxNameCast(basex); + } return this; } diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 213fe388a..7d6465e75 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -411,6 +411,78 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +class FxNameCast : public FxExpression +{ + FxExpression *basex; + +public: + + FxNameCast(FxExpression *x); + ~FxNameCast(); + FxExpression *Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder *build); +}; + +class FxStringCast : public FxExpression +{ + FxExpression *basex; + +public: + + FxStringCast(FxExpression *x); + ~FxStringCast(); + FxExpression *Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder *build); +}; + +class FxColorCast : public FxExpression +{ + FxExpression *basex; + +public: + + FxColorCast(FxExpression *x); + ~FxColorCast(); + FxExpression *Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder *build); +}; + +class FxSoundCast : public FxExpression +{ + FxExpression *basex; + +public: + + FxSoundCast(FxExpression *x); + ~FxSoundCast(); + FxExpression *Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// FxTypeCast +// +//========================================================================== + +class FxTypeCast : public FxExpression +{ + FxExpression *basex; + bool NoWarn; + +public: + + FxTypeCast(FxExpression *x, PType *type, bool nowarn); + ~FxTypeCast(); + FxExpression *Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxSign @@ -1130,7 +1202,7 @@ class FxClassTypeCast : public FxExpression public: - FxClassTypeCast(PClass *dtype, FxExpression *x); + FxClassTypeCast(PClassPointer *dtype, FxExpression *x); ~FxClassTypeCast(); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index 534c74d18..f416d6103 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -207,7 +207,7 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c sc.SetEscape(true); sc.MustGetString(); sc.SetEscape(false); - x = new FxClassTypeCast(static_cast(type)->ClassRestriction, new FxConstant(FName(sc.String), sc)); + x = new FxClassTypeCast(static_cast(type), new FxConstant(FName(sc.String), sc)); } else { diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 69e5b81b3..425eba531 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -116,6 +116,12 @@ enum CAST_P2S, CAST_S2I, CAST_S2F, + CAST_S2N, + CAST_N2S, + CAST_S2Co, + CAST_S2So, + CAST_Co2S, + CAST_So2S, }; // Register types for VMParam diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp index 0b84cf8c0..563f89f28 100644 --- a/src/scripting/vm/vmdisasm.cpp +++ b/src/scripting/vm/vmdisasm.cpp @@ -379,6 +379,9 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction case CAST_I2F: mode = MODE_AF | MODE_BI | MODE_CUNUSED; break; + case CAST_Co2S: + case CAST_So2S: + case CAST_N2S: case CAST_I2S: mode = MODE_AS | MODE_BI | MODE_CUNUSED; break; @@ -391,6 +394,9 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction case CAST_P2S: mode = MODE_AS | MODE_BP | MODE_CUNUSED; break; + case CAST_S2Co: + case CAST_S2So: + case CAST_S2N: case CAST_S2I: mode = MODE_AI | MODE_BS | MODE_CUNUSED; break; diff --git a/src/scripting/vm/vmexec.cpp b/src/scripting/vm/vmexec.cpp index 651090c6b..b1393382a 100644 --- a/src/scripting/vm/vmexec.cpp +++ b/src/scripting/vm/vmexec.cpp @@ -32,6 +32,8 @@ */ #include +#include +#include #include "vm.h" #include "xs_Float.h" #include "math/cmath.h" diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index adf2986c5..1d1764c6e 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -1466,6 +1466,39 @@ static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int c reg.f[a] = reg.s[b].ToDouble(); break; + case CAST_S2N: + ASSERTD(a); ASSERTS(b); + reg.d[a] = FName(reg.s[b]); + break; + + case CAST_N2S: + { + ASSERTS(a); ASSERTD(b); + FName name = FName(ENamedName(reg.d[b])); + reg.s[a] = name.IsValidName() ? name.GetChars() : ""; + break; + } + + case CAST_S2Co: + ASSERTD(a); ASSERTS(b); + reg.d[a] = V_GetColor(NULL, reg.s[b]); + break; + + case CAST_Co2S: + ASSERTS(a); ASSERTD(b); + reg.s[a].Format("%02x %02x %02x", PalEntry(reg.d[b]).r, PalEntry(reg.d[b]).g, PalEntry(reg.d[b]).b); + break; + + case CAST_S2So: + ASSERTD(a); ASSERTS(b); + reg.d[a] = FSoundID(reg.s[b]); + break; + + case CAST_So2S: + ASSERTS(a); ASSERTD(b); + reg.s[a] = S_sfx[reg.d[b]].name; + break; + default: assert(0); } diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index f6d23a99b..1992587c8 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -885,7 +885,7 @@ ZCC_Expression *ZCCCompiler::SimplifyFunctionCall(ZCC_ExprFuncCall *callop, PSym if (routelen < 0) { ///FIXME: Need real type names - Error(callop, "Cannot convert type 1 to type 2"); + Error(callop, "Cannot convert %s to %s", parm->Value->Type->DescriptiveName(), dest->DescriptiveName()); callop->ToErrorNode(); } else @@ -1341,7 +1341,7 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n //return TypeFloat32; case ZCC_Float64: retval = TypeFloat64; - return; + break; case ZCC_String: retval = TypeString; @@ -1433,7 +1433,7 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n } if (retval != TypeError && retval->MemberOnly && !formember) { - Error(field, "Invalid type"); // fixme: Types need a descriptive name that can be output here. + Error(field, "Invalid type %s", retval->DescriptiveName()); // fixme: Types need a descriptive name that can be output here. return TypeError; } return retval; diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 73bb467d8..a349d7ed5 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -7,9 +7,7 @@ zscript/shared/morph.txt zscript/shared/botstuff.txt zscript/shared/sharedmisc.txt zscript/shared/blood.txt -zscript/shared/ice.txt zscript/shared/debris.txt -zscript/shared/specialspot.txt zscript/shared/decal.txt zscript/shared/splashes.txt zscript/shared/pickups.txt @@ -18,6 +16,7 @@ zscript/shared/spark.txt zscript/shared/soundsequence.txt zscript/shared/soundenvironment.txt zscript/shared/bridge.txt +zscript/shared/specialspot.txt zscript/shared/teleport.txt zscript/shared/camera.txt zscript/shared/movingcamera.txt @@ -28,6 +27,7 @@ zscript/shared/hatetarget.txt zscript/shared/secrettrigger.txt zscript/shared/setcolor.txt zscript/shared/sectoraction.txt +zscript/shared/ice.txt zscript/shared/dog.txt zscript/doom/doomplayer.txt @@ -59,5 +59,5 @@ zscript/doom/doomweapons.txt zscript/doom/stealthmonsters.txt zscript/doom/scriptedmarine.txt -//zscript/test1.txt +zscript/heretic/beast.txt