mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-06-01 09:22:17 +00:00
- implemented passing vectors as parameters. So far working for native functions.
- removed the bogus optional value from the first A_Jump argument. A quick test with an older ZDoom revealed that this was never working - and implementing it would make things a lot more complicated, especially error checking in the code generator. - fixed: The check for insufficient parameters to a function call was missing.
This commit is contained in:
parent
e94b4cc74e
commit
7209f9edd6
9 changed files with 78 additions and 37 deletions
|
@ -732,3 +732,4 @@ xx(__decorate_internal_float__)
|
||||||
xx(DamageFunction)
|
xx(DamageFunction)
|
||||||
xx(Length)
|
xx(Length)
|
||||||
xx(Unit)
|
xx(Unit)
|
||||||
|
xx(A_Jump)
|
|
@ -1148,7 +1148,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BulletAttack)
|
||||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Jump)
|
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Jump)
|
||||||
{
|
{
|
||||||
PARAM_SELF_PROLOGUE(AActor);
|
PARAM_SELF_PROLOGUE(AActor);
|
||||||
PARAM_INT_DEF(maxchance);
|
PARAM_INT(maxchance);
|
||||||
|
|
||||||
paramnum++; // Increment paramnum to point at the first jump target
|
paramnum++; // Increment paramnum to point at the first jump target
|
||||||
int count = numparam - paramnum;
|
int count = numparam - paramnum;
|
||||||
|
|
|
@ -532,6 +532,17 @@ void AActor::SetOrigin(double x, double y, double z, bool moving)
|
||||||
if (!moving) ClearInterpolation();
|
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
|
// FBlockNode - allows to link actors into multiple blocks in the blockmap
|
||||||
|
|
|
@ -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);
|
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");
|
pos.Message(MSG_ERROR, "Attempted to pass a non-value");
|
||||||
build->Emit(OP_PARAM, 0, where.RegType, where.RegNum);
|
build->Emit(OP_PARAM, 0, where.RegType, where.RegNum);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -350,8 +351,17 @@ static void EmitParameter(VMFunctionBuilder *build, FxExpression *operand, const
|
||||||
{
|
{
|
||||||
regtype |= REGT_KONST;
|
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);
|
build->Emit(OP_PARAM, 0, regtype, where.RegNum);
|
||||||
where.Free(build);
|
where.Free(build);
|
||||||
|
return where.RegCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5873,6 +5883,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
delete this;
|
delete this;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned i = 0; i < ArgList->Size(); i++)
|
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.
|
// 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);
|
failed |= (x == nullptr);
|
||||||
(*ArgList)[i] = x;
|
(*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)
|
if (failed)
|
||||||
{
|
{
|
||||||
|
@ -5917,7 +5940,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
|
||||||
{
|
{
|
||||||
assert((build->IsActionFunc && build->Registers[REGT_POINTER].GetMostUsed() >= NAP) ||
|
assert((build->IsActionFunc && build->Registers[REGT_POINTER].GetMostUsed() >= NAP) ||
|
||||||
(!build->IsActionFunc && build->Registers[REGT_POINTER].GetMostUsed() >= 1));
|
(!build->IsActionFunc && build->Registers[REGT_POINTER].GetMostUsed() >= 1));
|
||||||
int count = (ArgList ? ArgList->Size() : 0);
|
int count = 0; (ArgList ? ArgList->Size() : 0);
|
||||||
|
|
||||||
if (count == 1)
|
if (count == 1)
|
||||||
{
|
{
|
||||||
|
@ -5928,6 +5951,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
count = 0;
|
||||||
// Emit code to pass implied parameters
|
// Emit code to pass implied parameters
|
||||||
if (Function->Variants[0].Flags & VARF_Method)
|
if (Function->Variants[0].Flags & VARF_Method)
|
||||||
{
|
{
|
||||||
|
@ -5958,7 +5982,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; i < ArgList->Size(); ++i)
|
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
|
// Get a constant register for this function
|
||||||
|
|
|
@ -134,7 +134,9 @@ enum
|
||||||
REGT_TYPE = 3,
|
REGT_TYPE = 3,
|
||||||
|
|
||||||
REGT_KONST = 4,
|
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_ADDROF = 32, // used with PARAM: pass address of this register
|
||||||
|
|
||||||
REGT_NIL = 128 // parameter was omitted
|
REGT_NIL = 128 // parameter was omitted
|
||||||
|
|
|
@ -498,7 +498,11 @@ size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc)
|
||||||
assert(opc >= 0 && opc <= 255);
|
assert(opc >= 0 && opc <= 255);
|
||||||
if (opcode == OP_PARAM)
|
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)
|
else if (opcode == OP_CALL || opcode == OP_CALL_K || opcode == OP_TAIL || opcode == OP_TAIL_K)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
return col+printf_wrapper(out, "s%d", regnum);
|
||||||
case REGT_POINTER:
|
case REGT_POINTER:
|
||||||
return col+printf_wrapper(out, "a%d", regnum);
|
return col+printf_wrapper(out, "a%d", regnum);
|
||||||
case REGT_FLOAT | REGT_MULTIREG:
|
case REGT_FLOAT | REGT_MULTIREG2:
|
||||||
return col+printf_wrapper(out, "v%d", regnum);
|
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:
|
case REGT_INT | REGT_KONST:
|
||||||
return col+print_reg(out, 0, regnum, MODE_KI, 0, func);
|
return col+print_reg(out, 0, regnum, MODE_KI, 0, func);
|
||||||
case REGT_FLOAT | REGT_KONST:
|
case REGT_FLOAT | REGT_KONST:
|
||||||
|
|
|
@ -453,7 +453,7 @@ begin:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch(b & (REGT_TYPE | REGT_KONST | REGT_ADDROF))
|
switch(b)
|
||||||
{
|
{
|
||||||
case REGT_INT:
|
case REGT_INT:
|
||||||
assert(C < f->NumRegD);
|
assert(C < f->NumRegD);
|
||||||
|
@ -492,40 +492,31 @@ begin:
|
||||||
::new(param) VMValue(konsta[C].v, konstatag[C]);
|
::new(param) VMValue(konsta[C].v, konstatag[C]);
|
||||||
break;
|
break;
|
||||||
case REGT_FLOAT:
|
case REGT_FLOAT:
|
||||||
if (b & REGT_MULTIREG)
|
assert(C < f->NumRegF);
|
||||||
{
|
::new(param) VMValue(reg.f[C]);
|
||||||
assert(C < f->NumRegF - 2);
|
break;
|
||||||
assert(f->NumParam < sfunc->MaxParam - 1);
|
case REGT_FLOAT | REGT_MULTIREG2:
|
||||||
::new(param) VMValue(reg.f[C]);
|
assert(C < f->NumRegF - 1);
|
||||||
::new(param+1) VMValue(reg.f[C+1]);
|
assert(f->NumParam < sfunc->MaxParam);
|
||||||
::new(param+2) VMValue(reg.f[C+2]);
|
::new(param) VMValue(reg.f[C]);
|
||||||
f->NumParam += 2;
|
::new(param + 1) VMValue(reg.f[C + 1]);
|
||||||
}
|
f->NumParam++;
|
||||||
else
|
break;
|
||||||
{
|
case REGT_FLOAT | REGT_MULTIREG3:
|
||||||
assert(C < f->NumRegF);
|
assert(C < f->NumRegF - 2);
|
||||||
::new(param) VMValue(reg.f[C]);
|
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;
|
break;
|
||||||
case REGT_FLOAT | REGT_ADDROF:
|
case REGT_FLOAT | REGT_ADDROF:
|
||||||
assert(C < f->NumRegF);
|
assert(C < f->NumRegF);
|
||||||
::new(param) VMValue(®.f[C], ATAG_FREGISTER);
|
::new(param) VMValue(®.f[C], ATAG_FREGISTER);
|
||||||
break;
|
break;
|
||||||
case REGT_FLOAT | REGT_KONST:
|
case REGT_FLOAT | REGT_KONST:
|
||||||
if (b & REGT_MULTIREG)
|
assert(C < sfunc->NumKonstF);
|
||||||
{
|
::new(param) VMValue(konstf[C]);
|
||||||
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]);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
|
|
|
@ -2017,6 +2017,7 @@ void ZCCCompiler::InitFunctions()
|
||||||
SetImplicitArgs(&args, &argflags, &argnames, c->Type(), varflags);
|
SetImplicitArgs(&args, &argflags, &argnames, c->Type(), varflags);
|
||||||
argdefaults.Resize(argnames.Size());
|
argdefaults.Resize(argnames.Size());
|
||||||
auto p = f->Params;
|
auto p = f->Params;
|
||||||
|
bool hasoptionals = false;
|
||||||
if (p != nullptr)
|
if (p != nullptr)
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
|
@ -2043,6 +2044,7 @@ void ZCCCompiler::InitFunctions()
|
||||||
else if (p->Default != nullptr)
|
else if (p->Default != nullptr)
|
||||||
{
|
{
|
||||||
flags |= VARF_Optional;
|
flags |= VARF_Optional;
|
||||||
|
hasoptionals = true;
|
||||||
// The simplifier is not suited to convert the constant into something usable.
|
// 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.
|
// 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
|
// 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;
|
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.
|
// TBD: disallow certain types? For now, let everything pass that isn't an array.
|
||||||
args.Push(type);
|
args.Push(type);
|
||||||
argflags.Push(flags);
|
argflags.Push(flags);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue