mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-28 23:11:58 +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(Length)
|
||||
xx(Unit)
|
||||
xx(A_Jump)
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue