diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index f9393d11f..b3a5e4297 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -466,12 +466,20 @@ public: class FxVectorValue : public FxExpression { FxExpression *xyz[3]; - bool isConst; // gets set to true if all element are const + bool isConst; // gets set to true if all element are const (used by function defaults parser) public: + + friend class ZCCCompiler; + FxVectorValue(FxExpression *x, FxExpression *y, FxExpression *z, const FScriptPosition &sc); ~FxVectorValue(); FxExpression *Resolve(FCompileContext&); + bool isConstVector(int dim) + { + if (!isConst) return false; + return dim == 2 ? xyz[2] == nullptr : xyz[2] != nullptr; + } ExpEmit Emit(VMFunctionBuilder *build); }; diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 92615461e..4109d4e79 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -643,7 +643,7 @@ public: bool Native; BYTE ImplicitArgs = 0; // either 0 for static, 1 for method or 3 for action FName Name; - TArray Defaults; + TArray DefaultArgs; class PPrototype *Proto; diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index 3f6d1cbd3..e9ac38a78 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -722,7 +722,13 @@ void FFunctionBuildList::Build() // Emit code item.Code->Emit(&buildit); buildit.MakeFunction(sfunc); - sfunc->NumArgs = item.Func->Variants[0].Proto->ArgumentTypes.Size(); + sfunc->NumArgs = 0; + // NumArgs for the VMFunction must be the amount of stack elements, which can differ from the amount of logical function arguments if vectors are in the list. + // For the VM a vector is 2 or 3 args, depending on size. + for (auto s : item.Func->Variants[0].Proto->ArgumentTypes) + { + sfunc->NumArgs += s->GetRegCount(); + } if (dump != nullptr) { diff --git a/src/scripting/vm/vmexec.cpp b/src/scripting/vm/vmexec.cpp index e2691470e..57ce48a95 100644 --- a/src/scripting/vm/vmexec.cpp +++ b/src/scripting/vm/vmexec.cpp @@ -188,14 +188,14 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam) const VMRegisters calleereg(callee); assert(calleefunc != NULL && !calleefunc->Native); - assert(numparam == calleefunc->NumArgs || ((int)calleefunc->Defaults.Size() == calleefunc->NumArgs)); + assert(numparam == calleefunc->NumArgs || ((int)calleefunc->DefaultArgs.Size() == calleefunc->NumArgs)); assert(REGT_INT == 0 && REGT_FLOAT == 1 && REGT_STRING == 2 && REGT_POINTER == 3); regd = regf = regs = rega = 0; for (int i = 0; i < calleefunc->NumArgs; ++i) { // get all actual parameters and fill the rest from the defaults. - VMValue &p = i < numparam? params[i] : calleefunc->Defaults[i]; + VMValue &p = i < numparam? params[i] : calleefunc->DefaultArgs[i]; if (p.Type < REGT_STRING) { if (p.Type == REGT_INT) diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 4b43ed815..4b16a99d1 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -544,7 +544,7 @@ begin: FillReturns(reg, f, returns, pc+1, C); if (call->Native) { - numret = static_cast(call)->NativeCall(stack, reg.param + f->NumParam - B, call->Defaults, B, returns, C); + numret = static_cast(call)->NativeCall(stack, reg.param + f->NumParam - B, call->DefaultArgs, B, returns, C); } else { @@ -588,7 +588,7 @@ begin: if (call->Native) { - return static_cast(call)->NativeCall(stack, reg.param + f->NumParam - B, call->Defaults, B, ret, numret); + return static_cast(call)->NativeCall(stack, reg.param + f->NumParam - B, call->DefaultArgs, B, ret, numret); } else { // FIXME: Not a true tail call diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index bf2159fa1..c54b585e9 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -415,7 +415,7 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur { if (func->Native) { - return static_cast(func)->NativeCall(this, params, func->Defaults, numparams, results, numresults); + return static_cast(func)->NativeCall(this, params, func->DefaultArgs, numparams, results, numresults); } else { diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 6c83b5a99..78a448f7c 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2022,7 +2022,8 @@ void ZCCCompiler::InitFunctions() { do { - VMValue vmval; // default is REGT_NIL which means 'no default value' here. + int elementcount = 1; + VMValue vmval[3]; // default is REGT_NIL which means 'no default value' here. if (p->Type != nullptr) { auto type = DetermineType(c->Type(), p, f->Name, p->Type, false, false); @@ -2036,6 +2037,14 @@ void ZCCCompiler::InitFunctions() { type = NewPointer(type); } + else if (type == TypeVector2) + { + elementcount = 2; + } + else if (type == TypeVector3) + { + elementcount = 3; + } } if (type->GetRegType() == REGT_NIL && type != TypeVector2 && type != TypeVector3) { @@ -2055,7 +2064,21 @@ void ZCCCompiler::InitFunctions() if (x != nullptr) { - if (!x->isConstant()) + // Vectors need special treatment because they use more than one entry in the Defaults and do not report as actual constants + if (type == TypeVector2 && x->ExprType == EFX_VectorValue && static_cast(x)->isConstVector(2)) + { + auto vx = static_cast(x); + vmval[0] = static_cast(vx->xyz[0])->GetValue().GetFloat(); + vmval[1] = static_cast(vx->xyz[1])->GetValue().GetFloat(); + } + else if (type == TypeVector3 && x->ExprType == EFX_VectorValue && static_cast(x)->isConstVector(3)) + { + auto vx = static_cast(x); + vmval[0] = static_cast(vx->xyz[0])->GetValue().GetFloat(); + vmval[1] = static_cast(vx->xyz[1])->GetValue().GetFloat(); + vmval[2] = static_cast(vx->xyz[2])->GetValue().GetFloat(); + } + else if (!x->isConstant()) { Error(p, "Default parameter %s is not constant in %s", FName(p->Name).GetChars(), FName(f->Name).GetChars()); } @@ -2070,22 +2093,22 @@ void ZCCCompiler::InitFunctions() switch (type->GetRegType()) { case REGT_INT: - vmval = cnst->GetValue().GetInt(); + vmval[0] = cnst->GetValue().GetInt(); break; case REGT_FLOAT: - vmval = cnst->GetValue().GetFloat(); + vmval[0] = cnst->GetValue().GetFloat(); break; case REGT_POINTER: if (type->IsKindOf(RUNTIME_CLASS(PClassPointer))) - vmval = (DObject*)cnst->GetValue().GetPointer(); + vmval[0] = (DObject*)cnst->GetValue().GetPointer(); else - vmval = cnst->GetValue().GetPointer(); + vmval[0] = cnst->GetValue().GetPointer(); break; case REGT_STRING: - vmval = cnst->GetValue().GetString(); + vmval[0] = cnst->GetValue().GetString(); break; default: @@ -2112,7 +2135,7 @@ void ZCCCompiler::InitFunctions() argflags.Push(0); argnames.Push(NAME_None); } - argdefaults.Push(vmval); + for(int i=0;i(p->SiblingNext); } while (p != f->Params); } @@ -2131,7 +2154,7 @@ void ZCCCompiler::InitFunctions() } if (sym->Variants[0].Implementation != nullptr && hasdefault) // do not copy empty default lists, they only waste space and processing time. { - sym->Variants[0].Implementation->Defaults = std::move(argdefaults); + sym->Variants[0].Implementation->DefaultArgs = std::move(argdefaults); } // todo: Check inheritance. }