- implemented the 'is' operator (i.e. class type check.)

This commit is contained in:
Christoph Oelckers 2016-10-30 01:05:56 +02:00
parent 78a18acf46
commit ac1c022911
4 changed files with 158 additions and 33 deletions

View File

@ -673,13 +673,14 @@ xx(PlayerClass)
xx(Wi_NoAutostartMap) xx(Wi_NoAutostartMap)
// Decorate compatibility functions // Decorate compatibility functions
xx(DecoRandom) xx(BuiltinTypeCheck)
xx(DecoFRandom) xx(BuiltinRandom)
xx(DecoCallLineSpecial) xx(BuiltinFRandom)
xx(DecoNameToClass) xx(BuiltinCallLineSpecial)
xx(BuiltinNameToClass)
xx(BuiltinFindMultiNameState) xx(BuiltinFindMultiNameState)
xx(BuiltinFindSingleNameState) xx(BuiltinFindSingleNameState)
xx(DecoHandleRuntimeState) xx(BuiltinHandleRuntimeState)
xx(Damage) xx(Damage)
// basic type names // basic type names

View File

@ -203,23 +203,24 @@ void ExpEmit::Reuse(VMFunctionBuilder *build)
//========================================================================== //==========================================================================
// //
// FindDecorateBuiltinFunction // FindBuiltinFunction
// //
// Returns the symbol for a decorate utility function. If not found, create // 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) if (sym == NULL)
{ {
PSymbolVMFunction *symfunc = new PSymbolVMFunction(funcname); PSymbolVMFunction *symfunc = new PSymbolVMFunction(funcname);
VMNativeFunction *calldec = new VMNativeFunction(func, funcname); VMNativeFunction *calldec = new VMNativeFunction(func, funcname);
symfunc->Function = calldec; symfunc->Function = calldec;
sym = symfunc; sym = symfunc;
RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); Builtins.AddSymbol(sym);
} }
return sym; return sym;
} }
@ -3615,9 +3616,6 @@ FxExpression *FxDotCross::Resolve(FCompileContext& ctx)
ExpEmit FxDotCross::Emit(VMFunctionBuilder *build) 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 to(build, ValueType->GetRegType(), ValueType->GetRegCount());
ExpEmit op1 = left->Emit(build); ExpEmit op1 = left->Emit(build);
ExpEmit op2 = right->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) FxConditional::FxConditional(FxExpression *c, FxExpression *t, FxExpression *f)
: FxExpression(EFX_Conditional, c->ScriptPosition) : 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); assert(numparam >= 1 && numparam <= 3);
FRandom *rng = reinterpret_cast<FRandom *>(param[0].a); FRandom *rng = reinterpret_cast<FRandom *>(param[0].a);
@ -4309,7 +4409,7 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build)
{ {
// Call DecoRandom to generate a random number. // Call DecoRandom to generate a random number.
VMFunction *callfunc; VMFunction *callfunc;
PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoRandom, DecoRandom); PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom);
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != NULL); assert(((PSymbolVMFunction *)sym)->Function != NULL);
@ -4428,9 +4528,9 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build)
assert(choices.Size() > 0); assert(choices.Size() > 0);
// Call DecoRandom to generate a random number. // Call BuiltinRandom to generate a random number.
VMFunction *callfunc; VMFunction *callfunc;
PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoRandom, DecoRandom); PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom);
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != NULL); 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); assert(numparam == 1 || numparam == 3);
FRandom *rng = reinterpret_cast<FRandom *>(param[0].a); 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) 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; VMFunction *callfunc;
PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoFRandom, DecoFRandom); PSymbol *sym = FindBuiltinFunction(NAME_BuiltinFRandom, BuiltinFRandom);
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != NULL); assert(((PSymbolVMFunction *)sym)->Function != NULL);
@ -4647,9 +4747,9 @@ FxExpression *FxRandom2::Resolve(FCompileContext &ctx)
ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) 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; VMFunction *callfunc;
PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoRandom, DecoRandom); PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom);
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != NULL); 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(numparam > 2 && numparam < 8);
assert(param[0].Type == REGT_INT); 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; VMFunction *callfunc;
PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoCallLineSpecial, DecoCallLineSpecial); PSymbol *sym = FindBuiltinFunction(NAME_BuiltinCallLineSpecial, BuiltinCallLineSpecial);
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != NULL); 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(numparam == 2);
assert(numret == 1); 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, clsname.RegType, clsname.RegNum);
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(const_cast<PClass *>(desttype), ATAG_OBJECT)); 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; VMFunction *callfunc;
PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoNameToClass, DecoNameToClass); PSymbol *sym = FindBuiltinFunction(NAME_BuiltinNameToClass, BuiltinNameToClass);
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != NULL); assert(((PSymbolVMFunction *)sym)->Function != NULL);
@ -7487,7 +7587,7 @@ static bool VerifyJumpTarget(AActor *stateowner, FStateParamInfo *stateinfo, int
return false; 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_PROLOGUE;
PARAM_OBJECT(stateowner, AActor); PARAM_OBJECT(stateowner, AActor);
@ -7522,7 +7622,7 @@ ExpEmit FxRuntimeStateIndex::Emit(VMFunctionBuilder *build)
VMFunction *callfunc; VMFunction *callfunc;
PSymbol *sym; PSymbol *sym;
sym = FindDecorateBuiltinFunction(NAME_DecoHandleRuntimeState, DecoHandleRuntimeState); sym = FindBuiltinFunction(NAME_BuiltinHandleRuntimeState, BuiltinHandleRuntimeState);
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != nullptr); assert(((PSymbolVMFunction *)sym)->Function != nullptr);
callfunc = ((PSymbolVMFunction *)sym)->Function; callfunc = ((PSymbolVMFunction *)sym)->Function;
@ -7702,11 +7802,11 @@ ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build)
if (names.Size() == 1) if (names.Size() == 1)
{ {
sym = FindDecorateBuiltinFunction(NAME_BuiltinFindSingleNameState, BuiltinFindSingleNameState); sym = FindBuiltinFunction(NAME_BuiltinFindSingleNameState, BuiltinFindSingleNameState);
} }
else else
{ {
sym = FindDecorateBuiltinFunction(NAME_BuiltinFindMultiNameState, BuiltinFindMultiNameState); sym = FindBuiltinFunction(NAME_BuiltinFindMultiNameState, BuiltinFindMultiNameState);
} }
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));

View File

@ -267,6 +267,7 @@ enum EFxType
EFX_CaseStatement, EFX_CaseStatement,
EFX_VectorInitializer, EFX_VectorInitializer,
EFX_VectorBuiltin, EFX_VectorBuiltin,
EFX_TypeCheck,
EFX_COUNT EFX_COUNT
}; };
@ -929,6 +930,27 @@ public:
ExpEmit Emit(VMFunctionBuilder *build); 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 // FxConditional

View File

@ -2690,9 +2690,11 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
case PEX_DotProduct: case PEX_DotProduct:
return new FxDotCross(tok, left, right); 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. // todo: These do not have representations in DECORATE and no implementation exists yet.
case PEX_Concat: case PEX_Concat:
case PEX_Is:
default: default:
I_Error("Binary operator %d not implemented yet", op); I_Error("Binary operator %d not implemented yet", op);