mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 15:21:51 +00:00
- implemented the 'is' operator (i.e. class type check.)
This commit is contained in:
parent
78a18acf46
commit
ac1c022911
4 changed files with 158 additions and 33 deletions
|
@ -673,13 +673,14 @@ xx(PlayerClass)
|
|||
xx(Wi_NoAutostartMap)
|
||||
|
||||
// Decorate compatibility functions
|
||||
xx(DecoRandom)
|
||||
xx(DecoFRandom)
|
||||
xx(DecoCallLineSpecial)
|
||||
xx(DecoNameToClass)
|
||||
xx(BuiltinTypeCheck)
|
||||
xx(BuiltinRandom)
|
||||
xx(BuiltinFRandom)
|
||||
xx(BuiltinCallLineSpecial)
|
||||
xx(BuiltinNameToClass)
|
||||
xx(BuiltinFindMultiNameState)
|
||||
xx(BuiltinFindSingleNameState)
|
||||
xx(DecoHandleRuntimeState)
|
||||
xx(BuiltinHandleRuntimeState)
|
||||
xx(Damage)
|
||||
|
||||
// basic type names
|
||||
|
|
|
@ -203,23 +203,24 @@ void ExpEmit::Reuse(VMFunctionBuilder *build)
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
// FindDecorateBuiltinFunction
|
||||
// FindBuiltinFunction
|
||||
//
|
||||
// Returns the symbol for a decorate utility function. If not found, create
|
||||
// it and install it in Actor.
|
||||
// it and install it a local symbol table.
|
||||
//
|
||||
//==========================================================================
|
||||
static PSymbolTable Builtins;
|
||||
|
||||
static PSymbol *FindDecorateBuiltinFunction(FName funcname, VMNativeFunction::NativeCallType func)
|
||||
static PSymbol *FindBuiltinFunction(FName funcname, VMNativeFunction::NativeCallType func)
|
||||
{
|
||||
PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(funcname, false);
|
||||
PSymbol *sym = Builtins.FindSymbol(funcname, false);
|
||||
if (sym == NULL)
|
||||
{
|
||||
PSymbolVMFunction *symfunc = new PSymbolVMFunction(funcname);
|
||||
VMNativeFunction *calldec = new VMNativeFunction(func, funcname);
|
||||
symfunc->Function = calldec;
|
||||
sym = symfunc;
|
||||
RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym);
|
||||
Builtins.AddSymbol(sym);
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
@ -3615,9 +3616,6 @@ FxExpression *FxDotCross::Resolve(FCompileContext& ctx)
|
|||
|
||||
ExpEmit FxDotCross::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
// This is not the "right" way to do these, but it works for now.
|
||||
// (Problem: No information sharing is done between nodes to reduce the
|
||||
// code size if you have something like a1 && a2 && a3 && ... && an.)
|
||||
ExpEmit to(build, ValueType->GetRegType(), ValueType->GetRegCount());
|
||||
ExpEmit op1 = left->Emit(build);
|
||||
ExpEmit op2 = right->Emit(build);
|
||||
|
@ -3634,6 +3632,108 @@ 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;
|
||||
ValueType = TypeBool;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxTypeCheck::~FxTypeCheck()
|
||||
{
|
||||
SAFE_DELETE(left);
|
||||
SAFE_DELETE(right);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxExpression *FxTypeCheck::Resolve(FCompileContext& ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
RESOLVE(left, ctx);
|
||||
RESOLVE(right, ctx);
|
||||
ABORT(right && left);
|
||||
return this;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PPrototype *FxTypeCheck::ReturnProto()
|
||||
{
|
||||
EmitTail = true;
|
||||
return FxExpression::ReturnProto();
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int BuiltinTypeCheck(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
{
|
||||
assert(numparam == 2);
|
||||
PARAM_POINTER_AT(0, obj, DObject);
|
||||
PARAM_CLASS_AT(1, cls, DObject);
|
||||
ACTION_RETURN_BOOL(obj->IsKindOf(cls));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
ExpEmit FxTypeCheck::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
ExpEmit out(build, REGT_INT);
|
||||
EmitParameter(build, left, ScriptPosition);
|
||||
EmitParameter(build, right, ScriptPosition);
|
||||
|
||||
|
||||
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinTypeCheck, BuiltinTypeCheck);
|
||||
|
||||
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
||||
assert(((PSymbolVMFunction *)sym)->Function != NULL);
|
||||
auto callfunc = ((PSymbolVMFunction *)sym)->Function;
|
||||
|
||||
int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K);
|
||||
build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1);
|
||||
|
||||
if (EmitTail)
|
||||
{
|
||||
ExpEmit call;
|
||||
call.Final = true;
|
||||
return call;
|
||||
}
|
||||
|
||||
build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum);
|
||||
return out;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxConditional::FxConditional(FxExpression *c, FxExpression *t, FxExpression *f)
|
||||
: FxExpression(EFX_Conditional, c->ScriptPosition)
|
||||
{
|
||||
|
@ -4278,7 +4378,7 @@ FxExpression *FxRandom::Resolve(FCompileContext &ctx)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int DecoRandom(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
int BuiltinRandom(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
{
|
||||
assert(numparam >= 1 && numparam <= 3);
|
||||
FRandom *rng = reinterpret_cast<FRandom *>(param[0].a);
|
||||
|
@ -4309,7 +4409,7 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build)
|
|||
{
|
||||
// Call DecoRandom to generate a random number.
|
||||
VMFunction *callfunc;
|
||||
PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoRandom, DecoRandom);
|
||||
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom);
|
||||
|
||||
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
||||
assert(((PSymbolVMFunction *)sym)->Function != NULL);
|
||||
|
@ -4428,9 +4528,9 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build)
|
|||
|
||||
assert(choices.Size() > 0);
|
||||
|
||||
// Call DecoRandom to generate a random number.
|
||||
// Call BuiltinRandom to generate a random number.
|
||||
VMFunction *callfunc;
|
||||
PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoRandom, DecoRandom);
|
||||
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom);
|
||||
|
||||
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
||||
assert(((PSymbolVMFunction *)sym)->Function != NULL);
|
||||
|
@ -4528,7 +4628,7 @@ FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScri
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int DecoFRandom(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
int BuiltinFRandom(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
{
|
||||
assert(numparam == 1 || numparam == 3);
|
||||
FRandom *rng = reinterpret_cast<FRandom *>(param[0].a);
|
||||
|
@ -4553,9 +4653,9 @@ int DecoFRandom(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultpar
|
|||
|
||||
ExpEmit FxFRandom::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
// Call the DecoFRandom function to generate a floating point random number..
|
||||
// Call the BuiltinFRandom function to generate a floating point random number..
|
||||
VMFunction *callfunc;
|
||||
PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoFRandom, DecoFRandom);
|
||||
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinFRandom, BuiltinFRandom);
|
||||
|
||||
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
||||
assert(((PSymbolVMFunction *)sym)->Function != NULL);
|
||||
|
@ -4647,9 +4747,9 @@ FxExpression *FxRandom2::Resolve(FCompileContext &ctx)
|
|||
|
||||
ExpEmit FxRandom2::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
// Call the DecoRandom function to generate the random number.
|
||||
// Call the BuiltinRandom function to generate the random number.
|
||||
VMFunction *callfunc;
|
||||
PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoRandom, DecoRandom);
|
||||
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom);
|
||||
|
||||
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
||||
assert(((PSymbolVMFunction *)sym)->Function != NULL);
|
||||
|
@ -5836,7 +5936,7 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int DecoCallLineSpecial(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
int BuiltinCallLineSpecial(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
{
|
||||
assert(numparam > 2 && numparam < 8);
|
||||
assert(param[0].Type == REGT_INT);
|
||||
|
@ -5885,9 +5985,9 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
|
|||
}
|
||||
}
|
||||
}
|
||||
// Call the DecoCallLineSpecial function to perform the desired special.
|
||||
// Call the BuiltinCallLineSpecial function to perform the desired special.
|
||||
VMFunction *callfunc;
|
||||
PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoCallLineSpecial, DecoCallLineSpecial);
|
||||
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinCallLineSpecial, BuiltinCallLineSpecial);
|
||||
|
||||
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
||||
assert(((PSymbolVMFunction *)sym)->Function != NULL);
|
||||
|
@ -7347,7 +7447,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int DecoNameToClass(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
int BuiltinNameToClass(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
{
|
||||
assert(numparam == 2);
|
||||
assert(numret == 1);
|
||||
|
@ -7380,9 +7480,9 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build)
|
|||
build->Emit(OP_PARAM, 0, clsname.RegType, clsname.RegNum);
|
||||
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(const_cast<PClass *>(desttype), ATAG_OBJECT));
|
||||
|
||||
// Call the DecoNameToClass function to convert from 'name' to class.
|
||||
// Call the BuiltinNameToClass function to convert from 'name' to class.
|
||||
VMFunction *callfunc;
|
||||
PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoNameToClass, DecoNameToClass);
|
||||
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinNameToClass, BuiltinNameToClass);
|
||||
|
||||
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
||||
assert(((PSymbolVMFunction *)sym)->Function != NULL);
|
||||
|
@ -7487,7 +7587,7 @@ static bool VerifyJumpTarget(AActor *stateowner, FStateParamInfo *stateinfo, int
|
|||
return false;
|
||||
}
|
||||
|
||||
static int DecoHandleRuntimeState(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
static int BuiltinHandleRuntimeState(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_OBJECT(stateowner, AActor);
|
||||
|
@ -7522,7 +7622,7 @@ ExpEmit FxRuntimeStateIndex::Emit(VMFunctionBuilder *build)
|
|||
VMFunction *callfunc;
|
||||
PSymbol *sym;
|
||||
|
||||
sym = FindDecorateBuiltinFunction(NAME_DecoHandleRuntimeState, DecoHandleRuntimeState);
|
||||
sym = FindBuiltinFunction(NAME_BuiltinHandleRuntimeState, BuiltinHandleRuntimeState);
|
||||
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
||||
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
|
||||
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
||||
|
@ -7702,11 +7802,11 @@ ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build)
|
|||
|
||||
if (names.Size() == 1)
|
||||
{
|
||||
sym = FindDecorateBuiltinFunction(NAME_BuiltinFindSingleNameState, BuiltinFindSingleNameState);
|
||||
sym = FindBuiltinFunction(NAME_BuiltinFindSingleNameState, BuiltinFindSingleNameState);
|
||||
}
|
||||
else
|
||||
{
|
||||
sym = FindDecorateBuiltinFunction(NAME_BuiltinFindMultiNameState, BuiltinFindMultiNameState);
|
||||
sym = FindBuiltinFunction(NAME_BuiltinFindMultiNameState, BuiltinFindMultiNameState);
|
||||
}
|
||||
|
||||
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
||||
|
|
|
@ -267,6 +267,7 @@ enum EFxType
|
|||
EFX_CaseStatement,
|
||||
EFX_VectorInitializer,
|
||||
EFX_VectorBuiltin,
|
||||
EFX_TypeCheck,
|
||||
EFX_COUNT
|
||||
};
|
||||
|
||||
|
@ -929,6 +930,27 @@ public:
|
|||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxBinaryLogical
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxTypeCheck : public FxExpression
|
||||
{
|
||||
public:
|
||||
FxExpression *left;
|
||||
FxExpression *right;
|
||||
bool EmitTail;
|
||||
|
||||
FxTypeCheck(FxExpression*, FxExpression*);
|
||||
~FxTypeCheck();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
PPrototype *ReturnProto();
|
||||
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxConditional
|
||||
|
|
|
@ -2690,9 +2690,11 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
|
|||
case PEX_DotProduct:
|
||||
return new FxDotCross(tok, left, right);
|
||||
|
||||
case PEX_Is:
|
||||
return new FxTypeCheck(left, right);
|
||||
|
||||
// todo: These do not have representations in DECORATE and no implementation exists yet.
|
||||
case PEX_Concat:
|
||||
case PEX_Is:
|
||||
|
||||
default:
|
||||
I_Error("Binary operator %d not implemented yet", op);
|
||||
|
|
Loading…
Reference in a new issue