- scriptified cht_Give and cht_Take and made them virtual function of PlayerPawn so that this can be better configured for mods that want other options in here.

- improved the class pointer to string cast to print the actual type it describes and not the class pointer's own type.
- fixed: The 'is' operator created non-working code when checking the inheritance of a class pointer, it only worked for objects.
This commit is contained in:
Christoph Oelckers 2017-01-17 17:31:54 +01:00
commit 14f2c39e58
21 changed files with 559 additions and 461 deletions

View file

@ -4362,9 +4362,8 @@ ExpEmit FxDotCross::Emit(VMFunctionBuilder *build)
FxTypeCheck::FxTypeCheck(FxExpression *l, FxExpression *r)
: FxExpression(EFX_TypeCheck, l->ScriptPosition)
{
left = new FxTypeCast(l, NewPointer(RUNTIME_CLASS(DObject)), false);
right = new FxClassTypeCast(NewClassPointer(RUNTIME_CLASS(DObject)), r);
EmitTail = false;
left = l;
right = r;
ValueType = TypeBool;
}
@ -4389,9 +4388,27 @@ FxTypeCheck::~FxTypeCheck()
FxExpression *FxTypeCheck::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
// This must resolve the cast separately so that it can set the proper type for class descriptors.
RESOLVE(left, ctx);
RESOLVE(right, ctx);
ABORT(right && left);
if (left->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)))
{
left = new FxClassTypeCast(NewClassPointer(RUNTIME_CLASS(DObject)), left);
ClassCheck = true;
}
else
{
left = new FxTypeCast(left, NewPointer(RUNTIME_CLASS(DObject)), false);
ClassCheck = false;
}
right = new FxClassTypeCast(NewClassPointer(RUNTIME_CLASS(DObject)), right);
RESOLVE(left, ctx);
RESOLVE(right, ctx);
ABORT(right && left);
return this;
}
@ -4408,7 +4425,8 @@ ExpEmit FxTypeCheck::EmitCommon(VMFunctionBuilder *build)
castee.Free(build);
casttype.Free(build);
ExpEmit ares(build, REGT_POINTER);
build->Emit(casttype.Konst ? OP_DYNCAST_K : OP_DYNCAST_R, ares.RegNum, castee.RegNum, casttype.RegNum);
if (!ClassCheck) build->Emit(casttype.Konst ? OP_DYNCAST_K : OP_DYNCAST_R, ares.RegNum, castee.RegNum, casttype.RegNum);
else build->Emit(casttype.Konst ? OP_DYNCASTC_K : OP_DYNCASTC_R, ares.RegNum, castee.RegNum, casttype.RegNum);
return ares;
}

View file

@ -1086,7 +1086,7 @@ class FxTypeCheck : public FxExpression
public:
FxExpression *left;
FxExpression *right;
bool EmitTail;
bool ClassCheck;
FxTypeCheck(FxExpression*, FxExpression*);
~FxTypeCheck();

View file

@ -788,6 +788,11 @@ void InitThingdef()
PField *dehf = new PField("deh", dstruct, VARF_Native | VARF_Static, (intptr_t)&deh);
GlobalSymbols.AddSymbol(dehf);
// set up a variable for the global gameinfo data
PStruct *gistruct = NewNativeStruct("GameInfoStruct", nullptr);
PField *gi = new PField("gameinfo", gistruct, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&gameinfo);
GlobalSymbols.AddSymbol(gi);
// set up a variable for the global players array.
PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr);
pstruct->Size = sizeof(player_t);
@ -796,6 +801,9 @@ void InitThingdef()
PField *playerf = new PField("players", parray, VARF_Native | VARF_Static, (intptr_t)&players);
GlobalSymbols.AddSymbol(playerf);
pstruct->AddNativeField("weapons", NewNativeStruct("WeaponSlots", nullptr), myoffsetof(player_t, weapons), VARF_Native);
parray = NewArray(TypeBool, MAXPLAYERS);
playerf = new PField("playeringame", parray, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&playeringame);
GlobalSymbols.AddSymbol(playerf);

View file

@ -401,7 +401,7 @@ begin:
OP(MOVEA):
{
ASSERTA(a); ASSERTA(B);
int b = B;
b = B;
reg.a[a] = reg.a[b];
reg.atag[a] = reg.atag[b];
NEXTOP;
@ -409,7 +409,7 @@ begin:
OP(MOVEV2):
{
ASSERTF(a); ASSERTF(B);
int b = B;
b = B;
reg.f[a] = reg.f[b];
reg.f[a + 1] = reg.f[b + 1];
NEXTOP;
@ -417,7 +417,7 @@ begin:
OP(MOVEV3):
{
ASSERTF(a); ASSERTF(B);
int b = B;
b = B;
reg.f[a] = reg.f[b];
reg.f[a + 1] = reg.f[b + 1];
reg.f[a + 2] = reg.f[b + 2];
@ -435,6 +435,18 @@ begin:
reg.a[a] = (reg.a[b] && ((DObject*)(reg.a[b]))->IsKindOf((PClass*)(konsta[C].o))) ? reg.a[b] : nullptr;
reg.atag[a] = ATAG_OBJECT;
NEXTOP;
OP(DYNCASTC_R) :
ASSERTA(a); ASSERTA(B); ASSERTA(C);
b = B;
reg.a[a] = (reg.a[b] && ((PClass*)(reg.a[b]))->IsDescendantOf((PClass*)(reg.a[C]))) ? reg.a[b] : nullptr;
reg.atag[a] = ATAG_OBJECT;
NEXTOP;
OP(DYNCASTC_K) :
ASSERTA(a); ASSERTA(B); ASSERTKA(C);
b = B;
reg.a[a] = (reg.a[b] && ((PClass*)(reg.a[b]))->IsDescendantOf((PClass*)(konsta[C].o))) ? reg.a[b] : nullptr;
reg.atag[a] = ATAG_OBJECT;
NEXTOP;
OP(CAST):
if (C == CAST_I2F)
{
@ -1746,9 +1758,21 @@ static void DoCast(const VMRegisters &reg, const VMFrame *f, int a, int b, int c
break;
case CAST_P2S:
{
ASSERTS(a); ASSERTA(b);
reg.s[a].Format("%s<%p>", reg.atag[b] == ATAG_OBJECT ? (reg.a[b] == nullptr? "Object" : ((DObject*)reg.a[b])->GetClass()->TypeName.GetChars() ) : "Pointer", reg.a[b]);
break;
if (reg.a[b] == nullptr) reg.s[a] = "null";
else if (reg.atag[b] == ATAG_OBJECT)
{
auto op = static_cast<DObject*>(reg.a[b]);
if (op->IsKindOf(RUNTIME_CLASS(PClass))) reg.s[a].Format("Class<%s>", static_cast<PClass*>(op)->TypeName.GetChars());
else reg.s[a].Format("Object<%p>", ((DObject*)reg.a[b])->GetClass()->TypeName.GetChars());
}
else
{
reg.s[a].Format("%s<%p>", "Pointer", reg.a[b]);
}
break;
}
case CAST_S2I:
ASSERTD(a); ASSERTS(b);

View file

@ -86,6 +86,8 @@ xx(CAST, cast, CAST, NOP, 0, 0), // xA = xB, conversion specified by C
xx(CASTB, castb, CAST, NOP, 0, 0), // xA = !!xB, type specified by C
xx(DYNCAST_R, dyncast, RPRPRP, NOP, 0, 0), // aA = dyn_cast<aC>(aB);
xx(DYNCAST_K, dyncast, RPRPKP, NOP, 0, 0), // aA = dyn_cast<aKC>(aB);
xx(DYNCASTC_R, dyncastc, RPRPRP, NOP, 0, 0), // aA = dyn_cast<aC>(aB); for class types
xx(DYNCASTC_K, dyncastc, RPRPKP, NOP, 0, 0), // aA = dyn_cast<aKC>(aB);
// Control flow.
xx(TEST, test, RII16, NOP, 0, 0), // if (dA != BC) then pc++