diff --git a/src/namedef.h b/src/namedef.h index a5abfa5a1..3966c95e7 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -732,3 +732,4 @@ xx(__decorate_internal_float__) xx(DamageFunction) xx(Length) xx(Unit) +xx(A_Jump) \ No newline at end of file diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 0e9620564..9f3a088d6 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -1148,7 +1148,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BulletAttack) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Jump) { PARAM_SELF_PROLOGUE(AActor); - PARAM_INT_DEF(maxchance); + PARAM_INT(maxchance); paramnum++; // Increment paramnum to point at the first jump target int count = numparam - paramnum; diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 04372f0ed..0a1d831d8 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -532,6 +532,17 @@ void AActor::SetOrigin(double x, double y, double z, bool moving) if (!moving) ClearInterpolation(); } +DEFINE_ACTION_FUNCTION(AActor, SetOrigin) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_BOOL(moving); + self->SetOrigin(x, y, z, moving); + return 0; +} + //=========================================================================== // // FBlockNode - allows to link actors into multiple blocks in the blockmap diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index f8fd03946..d87e601ff 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -334,7 +334,7 @@ PPrototype *FxExpression::ReturnProto() // //========================================================================== -static void EmitParameter(VMFunctionBuilder *build, FxExpression *operand, const FScriptPosition &pos) +static int EmitParameter(VMFunctionBuilder *build, FxExpression *operand, const FScriptPosition &pos) { ExpEmit where = operand->Emit(build); @@ -342,6 +342,7 @@ static void EmitParameter(VMFunctionBuilder *build, FxExpression *operand, const { pos.Message(MSG_ERROR, "Attempted to pass a non-value"); build->Emit(OP_PARAM, 0, where.RegType, where.RegNum); + return 1; } else { @@ -350,8 +351,17 @@ static void EmitParameter(VMFunctionBuilder *build, FxExpression *operand, const { regtype |= REGT_KONST; } + else if (where.RegCount == 2) + { + regtype |= REGT_MULTIREG2; + } + else if (where.RegCount == 3) + { + regtype |= REGT_MULTIREG3; + } build->Emit(OP_PARAM, 0, regtype, where.RegNum); where.Free(build); + return where.RegCount; } } @@ -5873,6 +5883,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) delete this; return nullptr; } + for (unsigned i = 0; i < ArgList->Size(); i++) { // Varargs must all have the same type as the last typed argument. A_Jump is the only function using it. @@ -5888,6 +5899,18 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) failed |= (x == nullptr); (*ArgList)[i] = x; } + int numargs = ArgList->Size() + implicit; + if ((unsigned)numargs < argtypes.Size() && argtypes[numargs] != nullptr) + { + auto flags = Function->Variants[0].ArgFlags[numargs]; + if (!(flags & VARF_Optional)) + { + ScriptPosition.Message(MSG_ERROR, "Insufficient arguments in call to %s", Function->SymbolName.GetChars()); + delete this; + return nullptr; + } + } + } if (failed) { @@ -5917,7 +5940,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) { assert((build->IsActionFunc && build->Registers[REGT_POINTER].GetMostUsed() >= NAP) || (!build->IsActionFunc && build->Registers[REGT_POINTER].GetMostUsed() >= 1)); - int count = (ArgList ? ArgList->Size() : 0); + int count = 0; (ArgList ? ArgList->Size() : 0); if (count == 1) { @@ -5928,6 +5951,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) } } + count = 0; // Emit code to pass implied parameters if (Function->Variants[0].Flags & VARF_Method) { @@ -5958,7 +5982,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) { for (unsigned i = 0; i < ArgList->Size(); ++i) { - EmitParameter(build, (*ArgList)[i], ScriptPosition); + count += EmitParameter(build, (*ArgList)[i], ScriptPosition); } } // Get a constant register for this function diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index c14a8a6e5..4eb055e6e 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -134,7 +134,9 @@ enum REGT_TYPE = 3, REGT_KONST = 4, - REGT_MULTIREG = 8, // (e.g. a vector) + REGT_MULTIREG2 = 8, + REGT_MULTIREG3 = 16, // (e.g. a vector) + REGT_MULTIREG = 24, REGT_ADDROF = 32, // used with PARAM: pass address of this register REGT_NIL = 128 // parameter was omitted diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index dd07d0100..912b95861 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -498,7 +498,11 @@ size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc) assert(opc >= 0 && opc <= 255); if (opcode == OP_PARAM) { - ParamChange(1); + int chg; + if (opb & REGT_MULTIREG2) chg = 2; + else if (opb®T_MULTIREG3) chg = 3; + else chg = 1; + ParamChange(chg); } else if (opcode == OP_CALL || opcode == OP_CALL_K || opcode == OP_TAIL || opcode == OP_TAIL_K) { diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp index c20083dcd..ea199612c 100644 --- a/src/scripting/vm/vmdisasm.cpp +++ b/src/scripting/vm/vmdisasm.cpp @@ -578,8 +578,10 @@ static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const return col+printf_wrapper(out, "s%d", regnum); case REGT_POINTER: return col+printf_wrapper(out, "a%d", regnum); - case REGT_FLOAT | REGT_MULTIREG: - return col+printf_wrapper(out, "v%d", regnum); + case REGT_FLOAT | REGT_MULTIREG2: + return col+printf_wrapper(out, "v%d.2", regnum); + case REGT_FLOAT | REGT_MULTIREG3: + return col+printf_wrapper(out, "v%d.3", regnum); case REGT_INT | REGT_KONST: return col+print_reg(out, 0, regnum, MODE_KI, 0, func); case REGT_FLOAT | REGT_KONST: diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 824cd6366..9162ca996 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -453,7 +453,7 @@ begin: } else { - switch(b & (REGT_TYPE | REGT_KONST | REGT_ADDROF)) + switch(b) { case REGT_INT: assert(C < f->NumRegD); @@ -492,40 +492,31 @@ begin: ::new(param) VMValue(konsta[C].v, konstatag[C]); break; case REGT_FLOAT: - if (b & REGT_MULTIREG) - { - assert(C < f->NumRegF - 2); - assert(f->NumParam < sfunc->MaxParam - 1); - ::new(param) VMValue(reg.f[C]); - ::new(param+1) VMValue(reg.f[C+1]); - ::new(param+2) VMValue(reg.f[C+2]); - f->NumParam += 2; - } - else - { - assert(C < f->NumRegF); - ::new(param) VMValue(reg.f[C]); - } + assert(C < f->NumRegF); + ::new(param) VMValue(reg.f[C]); + break; + case REGT_FLOAT | REGT_MULTIREG2: + assert(C < f->NumRegF - 1); + assert(f->NumParam < sfunc->MaxParam); + ::new(param) VMValue(reg.f[C]); + ::new(param + 1) VMValue(reg.f[C + 1]); + f->NumParam++; + break; + case REGT_FLOAT | REGT_MULTIREG3: + assert(C < f->NumRegF - 2); + assert(f->NumParam < sfunc->MaxParam - 1); + ::new(param) VMValue(reg.f[C]); + ::new(param + 1) VMValue(reg.f[C + 1]); + ::new(param + 2) VMValue(reg.f[C + 2]); + f->NumParam += 2; break; case REGT_FLOAT | REGT_ADDROF: assert(C < f->NumRegF); ::new(param) VMValue(®.f[C], ATAG_FREGISTER); break; case REGT_FLOAT | REGT_KONST: - if (b & REGT_MULTIREG) - { - assert(C < sfunc->NumKonstF - 2); - assert(f->NumParam < sfunc->MaxParam - 1); - ::new(param) VMValue(konstf[C]); - ::new(param+1) VMValue(konstf[C+1]); - ::new(param+2) VMValue(konstf[C+2]); - f->NumParam += 2; - } - else - { - assert(C < sfunc->NumKonstF); - ::new(param) VMValue(konstf[C]); - } + assert(C < sfunc->NumKonstF); + ::new(param) VMValue(konstf[C]); break; default: assert(0); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 294763f9b..f2644b240 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2017,6 +2017,7 @@ void ZCCCompiler::InitFunctions() SetImplicitArgs(&args, &argflags, &argnames, c->Type(), varflags); argdefaults.Resize(argnames.Size()); auto p = f->Params; + bool hasoptionals = false; if (p != nullptr) { do @@ -2043,6 +2044,7 @@ void ZCCCompiler::InitFunctions() else if (p->Default != nullptr) { flags |= VARF_Optional; + hasoptionals = true; // The simplifier is not suited to convert the constant into something usable. // All it does is reduce the expression to a constant but we still got to do proper type checking and conversion. // It will also lose important type info about enums, once these get implemented @@ -2094,6 +2096,10 @@ void ZCCCompiler::InitFunctions() } if (x != nullptr) delete x; } + else if (hasoptionals) + { + Error(p, "All arguments after the first optional one need also be optional."); + } // TBD: disallow certain types? For now, let everything pass that isn't an array. args.Push(type); argflags.Push(flags);