mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 23:02:08 +00:00
- implemented named arguments.
- fixed flag CVAR access. As it turned out, OP_LBIT is a bit messy to set up properly when accessing integers that may or may not be big endian, so it now uses a shift and bit masking to do its work. - used the SpawnPlayerMissile call in A_FireBFG to test named arguments.
This commit is contained in:
parent
7d8143224e
commit
e7f6bae83e
4 changed files with 119 additions and 5 deletions
|
@ -6054,9 +6054,14 @@ ExpEmit FxCVar::Emit(VMFunctionBuilder *build)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CVAR_DummyBool:
|
case CVAR_DummyBool:
|
||||||
build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast<FFlagCVar *>(CVar)->ValueVar.Value, ATAG_GENERIC));
|
{
|
||||||
build->Emit(OP_LBIT, dest.RegNum, addr.RegNum, static_cast<FFlagCVar *>(CVar)->BitNum);
|
auto cv = static_cast<FFlagCVar *>(CVar);
|
||||||
|
build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&cv->ValueVar.Value, ATAG_GENERIC));
|
||||||
|
build->Emit(OP_LW, dest.RegNum, addr.RegNum, nul);
|
||||||
|
build->Emit(OP_SRL_RI, dest.RegNum, dest.RegNum, cv->BitNum);
|
||||||
|
build->Emit(OP_AND_RK, dest.RegNum, dest.RegNum, build->GetConstantInt(1));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case CVAR_DummyInt:
|
case CVAR_DummyInt:
|
||||||
{
|
{
|
||||||
|
@ -7408,7 +7413,9 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
auto proto = Function->Variants[0].Proto;
|
auto proto = Function->Variants[0].Proto;
|
||||||
auto &argtypes = proto->ArgumentTypes;
|
auto &argtypes = proto->ArgumentTypes;
|
||||||
|
auto &argnames = Function->Variants[0].ArgNames;
|
||||||
auto &argflags = Function->Variants[0].ArgFlags;
|
auto &argflags = Function->Variants[0].ArgFlags;
|
||||||
|
auto &defaults = Function->Variants[0].Implementation->DefaultArgs;
|
||||||
|
|
||||||
int implicit = Function->GetImplicitArgs();
|
int implicit = Function->GetImplicitArgs();
|
||||||
|
|
||||||
|
@ -7446,6 +7453,67 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
}
|
}
|
||||||
assert(type != nullptr);
|
assert(type != nullptr);
|
||||||
|
|
||||||
|
if (ArgList[i]->ExprType == EFX_NamedNode)
|
||||||
|
{
|
||||||
|
if (!(flag & VARF_Optional))
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument here - not all required arguments have been passed.");
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (foundvarargs)
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument in the varargs part of the parameter list.");
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
unsigned j;
|
||||||
|
bool done = false;
|
||||||
|
FName name = static_cast<FxNamedNode *>(ArgList[i])->name;
|
||||||
|
for (j = 0; j < argnames.Size() - implicit; j++)
|
||||||
|
{
|
||||||
|
if (argnames[j + implicit] == name)
|
||||||
|
{
|
||||||
|
if (j < i)
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Named argument %s comes before current position in argument list.", name.GetChars());
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
// copy the original argument into the list
|
||||||
|
auto old = static_cast<FxNamedNode *>(ArgList[i]);
|
||||||
|
ArgList[i] = old->value;
|
||||||
|
old->value = nullptr;
|
||||||
|
delete old;
|
||||||
|
// now fill the gap with constants created from the default list so that we got a full list of arguments.
|
||||||
|
int insert = j - i;
|
||||||
|
for (int k = 0; k < insert; k++)
|
||||||
|
{
|
||||||
|
auto ntype = argtypes[i + k + implicit];
|
||||||
|
// If this is a reference argument, the pointer type must be undone because the code below expects the pointed type as value type.
|
||||||
|
if (argflags[i + k + implicit] & VARF_Ref)
|
||||||
|
{
|
||||||
|
assert(ntype->IsKindOf(RUNTIME_CLASS(PPointer)));
|
||||||
|
ntype = TypeNullPtr; // the default of a reference type can only be a null pointer
|
||||||
|
}
|
||||||
|
auto x = new FxConstant(ntype, defaults[i + k + implicit], ScriptPosition);
|
||||||
|
ArgList.Insert(i + k, x);
|
||||||
|
}
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!done)
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Named argument %s not found.", name.GetChars());
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
// re-get the proper info for the inserted node.
|
||||||
|
type = argtypes[i + implicit];
|
||||||
|
flag = argflags[i + implicit];
|
||||||
|
}
|
||||||
|
|
||||||
FxExpression *x;
|
FxExpression *x;
|
||||||
if (!(flag & VARF_Ref))
|
if (!(flag & VARF_Ref))
|
||||||
{
|
{
|
||||||
|
|
|
@ -285,6 +285,7 @@ enum EFxType
|
||||||
EFX_StaticArray,
|
EFX_StaticArray,
|
||||||
EFX_StaticArrayVariable,
|
EFX_StaticArrayVariable,
|
||||||
EFX_CVar,
|
EFX_CVar,
|
||||||
|
EFX_NamedNode,
|
||||||
EFX_COUNT
|
EFX_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -472,6 +473,31 @@ public:
|
||||||
ValueType = value.Type = TypeNullPtr;
|
ValueType = value.Type = TypeNullPtr;
|
||||||
isresolved = true;
|
isresolved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FxConstant(PType *type, VMValue &vmval, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos)
|
||||||
|
{
|
||||||
|
ValueType = value.Type = type;
|
||||||
|
isresolved = true;
|
||||||
|
switch (vmval.Type)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case REGT_INT:
|
||||||
|
value.Int = vmval.i;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REGT_FLOAT:
|
||||||
|
value.Float = vmval.f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REGT_STRING:
|
||||||
|
value = ExpVal(vmval.s());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REGT_POINTER:
|
||||||
|
value.pointer = vmval.a;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static FxExpression *MakeConstant(PSymbol *sym, const FScriptPosition &pos);
|
static FxExpression *MakeConstant(PSymbol *sym, const FScriptPosition &pos);
|
||||||
|
|
||||||
|
@ -1912,5 +1938,24 @@ public:
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FxNamedNode : public FxExpression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FName name;
|
||||||
|
FxExpression *value;
|
||||||
|
FxNamedNode(FName n, FxExpression *x, const FScriptPosition &pos)
|
||||||
|
: FxExpression(EFX_NamedNode, pos), name(n), value(x)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FxExpression *Resolve(FCompileContext&)
|
||||||
|
{
|
||||||
|
// This should never reach the backend in a supported context,
|
||||||
|
// it's just needed to extend argument lists with the skipped parameters and needs to be resolved by the parent node.
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Named arguments not supported here");
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2845,8 +2845,9 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
|
||||||
case AST_FuncParm:
|
case AST_FuncParm:
|
||||||
{
|
{
|
||||||
auto fparm = static_cast<ZCC_FuncParm *>(ast);
|
auto fparm = static_cast<ZCC_FuncParm *>(ast);
|
||||||
// ignore the label for now, that's stuff for far later, when a bit more here is working.
|
auto node = ConvertNode(fparm->Value);
|
||||||
return ConvertNode(fparm->Value);
|
if (fparm->Label != NAME_None) node = new FxNamedNode(fparm->Label, node, *ast);
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AST_ExprID:
|
case AST_ExprID:
|
||||||
|
|
|
@ -81,7 +81,7 @@ extend class StateProvider
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpawnPlayerMissile("BFGBall", angle, 0, 0, 0, null, false, sv_nobfgaim);
|
SpawnPlayerMissile("BFGBall", angle, nofreeaim:sv_nobfgaim);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue