mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-05-30 16:40:58 +00:00
- actually evaluate the default parameters and store them in the VMFunction.
- disabled the assert in PType::GetRegType. This assert blocks any use to check for types that are incompatible with function parameters. - pass the default parameter constants to the native functions. At the moment this is not used yet. - use the function defaults to complete argument lists to script functions. - fixed all default values that got flagged by the expression evaluator as non-constant. Most were state labels and colors which were defaulted to "". The proper value is null for states and 0 for colors. - also replaced all "" defaults for names with "none".
This commit is contained in:
parent
d32d52c0b9
commit
66b1f36e56
12 changed files with 152 additions and 62 deletions
|
@ -96,7 +96,7 @@ FCompileContext::FCompileContext(PFunction *fnc, PPrototype *ret, bool fromdecor
|
|||
if (fnc != nullptr) Class = fnc->OwningClass;
|
||||
}
|
||||
|
||||
FCompileContext::FCompileContext(PClass *cls) : ReturnProto(nullptr), Function(nullptr), Class(cls), FromDecorate(true) // only used by DECORATE constants.
|
||||
FCompileContext::FCompileContext(PClass *cls, bool fromdecorate) : ReturnProto(nullptr), Function(nullptr), Class(cls), FromDecorate(fromdecorate)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -3745,7 +3745,7 @@ FxExpression *FxRandom::Resolve(FCompileContext &ctx)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int DecoRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret)
|
||||
int DecoRandom(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
{
|
||||
assert(numparam >= 1 && numparam <= 3);
|
||||
FRandom *rng = reinterpret_cast<FRandom *>(param[0].a);
|
||||
|
@ -3995,7 +3995,7 @@ FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScri
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int DecoFRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret)
|
||||
int DecoFRandom(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
{
|
||||
assert(numparam == 1 || numparam == 3);
|
||||
FRandom *rng = reinterpret_cast<FRandom *>(param[0].a);
|
||||
|
@ -5255,7 +5255,7 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int DecoCallLineSpecial(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret)
|
||||
int DecoCallLineSpecial(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
{
|
||||
assert(numparam > 2 && numparam < 8);
|
||||
assert(param[0].Type == REGT_INT);
|
||||
|
@ -6702,7 +6702,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int DecoNameToClass(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret)
|
||||
int DecoNameToClass(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
{
|
||||
assert(numparam == 2);
|
||||
assert(numret == 1);
|
||||
|
@ -6842,7 +6842,7 @@ static bool VerifyJumpTarget(AActor *stateowner, FStateParamInfo *stateinfo, int
|
|||
return false;
|
||||
}
|
||||
|
||||
static int DecoHandleRuntimeState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret)
|
||||
static int DecoHandleRuntimeState(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_OBJECT(stateowner, AActor);
|
||||
|
@ -7008,7 +7008,7 @@ static int DoFindState(VMFrameStack *stack, VMValue *param, int numparam, VMRetu
|
|||
}
|
||||
|
||||
// Find a state with any number of dots in its name.
|
||||
int BuiltinFindMultiNameState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret)
|
||||
int BuiltinFindMultiNameState(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
{
|
||||
assert(numparam > 1);
|
||||
assert(numret == 1);
|
||||
|
@ -7024,7 +7024,7 @@ int BuiltinFindMultiNameState(VMFrameStack *stack, VMValue *param, int numparam,
|
|||
}
|
||||
|
||||
// Find a state without any dots in its name.
|
||||
int BuiltinFindSingleNameState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret)
|
||||
int BuiltinFindSingleNameState(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
{
|
||||
assert(numparam == 2);
|
||||
assert(numret == 1);
|
||||
|
|
|
@ -77,7 +77,7 @@ struct FCompileContext
|
|||
TDeletingArray<FxLocalVariableDeclaration *> FunctionArgs;
|
||||
|
||||
FCompileContext(PFunction *func, PPrototype *ret, bool fromdecorate);
|
||||
FCompileContext(PClass *cls); // only to be used to resolve constants!
|
||||
FCompileContext(PClass *cls, bool fromdecorate); // only to be used to resolve constants!
|
||||
|
||||
PSymbol *FindInClass(FName identifier, PSymbolTable *&symt);
|
||||
PSymbol *FindInSelfClass(FName identifier, PSymbolTable *&symt);
|
||||
|
|
|
@ -87,7 +87,7 @@ FxExpression *ParseExpression (FScanner &sc, PClassActor *cls, bool mustresolve)
|
|||
|
||||
if (mustresolve)
|
||||
{
|
||||
FCompileContext ctx(cls);
|
||||
FCompileContext ctx(cls, true);
|
||||
data = data->Resolve(ctx);
|
||||
}
|
||||
|
||||
|
|
|
@ -667,8 +667,8 @@ void InitThingdef()
|
|||
symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Vel.X)));
|
||||
symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Vel.Y)));
|
||||
symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Vel.Z)));
|
||||
symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Scale.X)));
|
||||
symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native|VARF_ReadOnly|VARF_Deprecated, myoffsetof(AActor, Scale.Y)));
|
||||
symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native|VARF_Deprecated, myoffsetof(AActor, Scale.X)));
|
||||
symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native|VARF_Deprecated, myoffsetof(AActor, Scale.Y)));
|
||||
symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor, Score)));
|
||||
symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor, accuracy)));
|
||||
symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor, stamina)));
|
||||
|
|
|
@ -173,20 +173,6 @@ enum EVMAbortException
|
|||
X_BAD_SELF,
|
||||
};
|
||||
|
||||
class VMFunction : public DObject
|
||||
{
|
||||
DECLARE_ABSTRACT_CLASS(VMFunction, DObject);
|
||||
HAS_OBJECT_POINTERS;
|
||||
public:
|
||||
bool Native;
|
||||
BYTE ImplicitArgs = 0; // either 0 for static, 1 for method or 3 for action
|
||||
FName Name;
|
||||
|
||||
class PPrototype *Proto;
|
||||
|
||||
VMFunction(FName name = NAME_None) : Native(false), ImplicitArgs(0), Name(name), Proto(NULL) {}
|
||||
};
|
||||
|
||||
enum EVMOpMode
|
||||
{
|
||||
MODE_ASHIFT = 0,
|
||||
|
@ -642,6 +628,21 @@ do_double: if (inexact)
|
|||
}
|
||||
};
|
||||
|
||||
class VMFunction : public DObject
|
||||
{
|
||||
DECLARE_ABSTRACT_CLASS(VMFunction, DObject);
|
||||
HAS_OBJECT_POINTERS;
|
||||
public:
|
||||
bool Native;
|
||||
BYTE ImplicitArgs = 0; // either 0 for static, 1 for method or 3 for action
|
||||
FName Name;
|
||||
TArray<VMValue> Defaults;
|
||||
|
||||
class PPrototype *Proto;
|
||||
|
||||
VMFunction(FName name = NAME_None) : Native(false), ImplicitArgs(0), Name(name), Proto(NULL) {}
|
||||
};
|
||||
|
||||
// VM frame layout:
|
||||
// VMFrame header
|
||||
// parameter stack - 16 byte boundary, 16 bytes each
|
||||
|
@ -829,7 +830,7 @@ class VMNativeFunction : public VMFunction
|
|||
{
|
||||
DECLARE_CLASS(VMNativeFunction, VMFunction);
|
||||
public:
|
||||
typedef int (*NativeCallType)(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret);
|
||||
typedef int (*NativeCallType)(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret);
|
||||
|
||||
VMNativeFunction() : NativeCall(NULL) { Native = true; }
|
||||
VMNativeFunction(NativeCallType call) : NativeCall(call) { Native = true; }
|
||||
|
@ -900,8 +901,8 @@ void VMDumpConstants(FILE *out, const VMScriptFunction *func);
|
|||
void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func);
|
||||
|
||||
// Use this in the prototype for a native function.
|
||||
#define VM_ARGS VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret
|
||||
#define VM_ARGS_NAMES stack, param, numparam, ret, numret
|
||||
#define VM_ARGS VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret
|
||||
#define VM_ARGS_NAMES stack, param, defaultparam, numparam, ret, numret
|
||||
|
||||
// Use these to collect the parameters in a native function.
|
||||
// variable name <x> at position <p>
|
||||
|
@ -924,6 +925,16 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
|
|||
// PARAM_INT_OPT(0,myint) { myint = 55; }
|
||||
// Just make sure to fill it in when using these macros, because the compiler isn't likely
|
||||
// to give useful error messages if you don't.
|
||||
#define PARAM_EXISTS ((p) < numparam && param[p].Type != REGT_NIL)
|
||||
#define ASSERTINT(p) assert((p).Type == REGT_INT)
|
||||
#define ASSERTFLOAT(p) assert((p).Type == REGT_FLOAT)
|
||||
#define ASSERTSTRING(p) assert((p).Type == REGT_STRING)
|
||||
#define ASSERTOBJECT(p) assert((p).Type == REGT_POINTER && (p).atag == ATAG_OBJECT)
|
||||
#define ASSERTPOINTER(p) assert((p).Type == REGT_POINTER && (p).atag == ATAG_GENERIC)
|
||||
#define ASSERTSTATE(p) assert((p).Type == REGT_POINTER && ((p).atag == ATAG_GENERIC || (p).atag == ATAG_STATE))
|
||||
|
||||
#define PARAM_INT_DEF_AT(p,x) int x; if (PARAM_EXISTS) { ASSERTINT(param[p]); x = param[p].i; } else { ASSERTINT(defaultparam[p]); x = defaultparam[p].i; }
|
||||
|
||||
#define PARAM_INT_OPT_AT(p,x) int x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = param[p].i; } else
|
||||
#define PARAM_BOOL_OPT_AT(p,x) bool x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = !!param[p].i; } else
|
||||
#define PARAM_NAME_OPT_AT(p,x) FName x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = ENamedName(param[p].i); } else
|
||||
|
@ -954,6 +965,20 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
|
|||
#define PARAM_OBJECT(x,type) ++paramnum; PARAM_OBJECT_AT(paramnum,x,type)
|
||||
#define PARAM_CLASS(x,base) ++paramnum; PARAM_CLASS_AT(paramnum,x,base)
|
||||
|
||||
#define PARAM_INT_DEF(x) ++paramnum; PARAM_INT_DEF_AT(paramnum,x)
|
||||
#define PARAM_BOOL_DEF(x) ++paramnum; PARAM_BOOL_DEF_AT(paramnum,x)
|
||||
#define PARAM_NAME_DEF(x) ++paramnum; PARAM_NAME_DEF_AT(paramnum,x)
|
||||
#define PARAM_SOUND_DEF(x) ++paramnum; PARAM_SOUND_DEF_AT(paramnum,x)
|
||||
#define PARAM_COLOR_DEF(x) ++paramnum; PARAM_COLOR_DEF_AT(paramnum,x)
|
||||
#define PARAM_FLOAT_DEF(x) ++paramnum; PARAM_FLOAT_DEF_AT(paramnum,x)
|
||||
#define PARAM_ANGLE_DEF(x) ++paramnum; PARAM_ANGLE_DEF_AT(paramnum,x)
|
||||
#define PARAM_STRING_DEF(x) ++paramnum; PARAM_STRING_DEF_AT(paramnum,x)
|
||||
#define PARAM_STATE_DEF(x) ++paramnum; PARAM_STATE_DEF_AT(paramnum,x)
|
||||
#define PARAM_STATEINFO_DEF(x) ++paramnum; PARAM_STATEINFO_DEF_AT(paramnum,x)
|
||||
#define PARAM_POINTER_DEF(x,type) ++paramnum; PARAM_POINTER_DEF_AT(paramnum,x,type)
|
||||
#define PARAM_OBJECT_DEF(x,type) ++paramnum; PARAM_OBJECT_DEF_AT(paramnum,x,type)
|
||||
#define PARAM_CLASS_DEF(x,base) ++paramnum; PARAM_CLASS_DEF_AT(paramnum,x,base)
|
||||
|
||||
#define PARAM_INT_OPT(x) ++paramnum; PARAM_INT_OPT_AT(paramnum,x)
|
||||
#define PARAM_BOOL_OPT(x) ++paramnum; PARAM_BOOL_OPT_AT(paramnum,x)
|
||||
#define PARAM_NAME_OPT(x) ++paramnum; PARAM_NAME_OPT_AT(paramnum,x)
|
||||
|
@ -968,7 +993,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
|
|||
#define PARAM_OBJECT_OPT(x,type) ++paramnum; PARAM_OBJECT_OPT_AT(paramnum,x,type)
|
||||
#define PARAM_CLASS_OPT(x,base) ++paramnum; PARAM_CLASS_OPT_AT(paramnum,x,base)
|
||||
|
||||
typedef int(*actionf_p)(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/
|
||||
typedef int(*actionf_p)(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/
|
||||
|
||||
struct AFuncDesc
|
||||
{
|
||||
|
|
|
@ -188,13 +188,14 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam)
|
|||
const VMRegisters calleereg(callee);
|
||||
|
||||
assert(calleefunc != NULL && !calleefunc->Native);
|
||||
assert(numparam == calleefunc->NumArgs);
|
||||
assert(numparam == calleefunc->NumArgs || ((int)calleefunc->Defaults.Size() == numparam));
|
||||
assert(REGT_INT == 0 && REGT_FLOAT == 1 && REGT_STRING == 2 && REGT_POINTER == 3);
|
||||
|
||||
regd = regf = regs = rega = 0;
|
||||
for (int i = 0; i < numparam; ++i)
|
||||
for (int i = 0; i < calleefunc->NumArgs; ++i)
|
||||
{
|
||||
VMValue &p = params[i];
|
||||
// get all actual parameters and fill the rest from the defaults.
|
||||
VMValue &p = i < numparam? params[i] : calleefunc->Defaults[i];
|
||||
if (p.Type < REGT_STRING)
|
||||
{
|
||||
if (p.Type == REGT_INT)
|
||||
|
|
|
@ -506,7 +506,7 @@ begin:
|
|||
FillReturns(reg, f, returns, pc+1, C);
|
||||
if (call->Native)
|
||||
{
|
||||
numret = static_cast<VMNativeFunction *>(call)->NativeCall(stack, reg.param + f->NumParam - B, B, returns, C);
|
||||
numret = static_cast<VMNativeFunction *>(call)->NativeCall(stack, reg.param + f->NumParam - B, call->Defaults, B, returns, C);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -550,7 +550,7 @@ begin:
|
|||
|
||||
if (call->Native)
|
||||
{
|
||||
return static_cast<VMNativeFunction *>(call)->NativeCall(stack, reg.param + f->NumParam - B, B, ret, numret);
|
||||
return static_cast<VMNativeFunction *>(call)->NativeCall(stack, reg.param + f->NumParam - B, call->Defaults, B, ret, numret);
|
||||
}
|
||||
else
|
||||
{ // FIXME: Not a true tail call
|
||||
|
|
|
@ -415,7 +415,7 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur
|
|||
{
|
||||
if (func->Native)
|
||||
{
|
||||
return static_cast<VMNativeFunction *>(func)->NativeCall(this, params, numparams, results, numresults);
|
||||
return static_cast<VMNativeFunction *>(func)->NativeCall(this, params, func->Defaults, numparams, results, numresults);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1952,6 +1952,7 @@ void ZCCCompiler::InitFunctions()
|
|||
TArray<PType *> rets(1);
|
||||
TArray<PType *> args;
|
||||
TArray<uint32_t> argflags;
|
||||
TArray<VMValue> argdefaults;
|
||||
TArray<FName> argnames;
|
||||
|
||||
for (auto c : Classes)
|
||||
|
@ -1961,6 +1962,7 @@ void ZCCCompiler::InitFunctions()
|
|||
rets.Clear();
|
||||
args.Clear();
|
||||
argflags.Clear();
|
||||
bool hasdefault = false;
|
||||
// For the time being, let's not allow overloading. This may be reconsidered later but really just adds an unnecessary amount of complexity here.
|
||||
if (AddTreeNode(f->Name, f, &c->TreeNodes, false))
|
||||
{
|
||||
|
@ -2018,36 +2020,96 @@ void ZCCCompiler::InitFunctions()
|
|||
}
|
||||
}
|
||||
SetImplicitArgs(&args, &argflags, &argnames, c->Type(), varflags);
|
||||
argdefaults.Resize(argnames.Size());
|
||||
auto p = f->Params;
|
||||
if (p != nullptr)
|
||||
{
|
||||
do
|
||||
{
|
||||
VMValue vmval; // 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);
|
||||
int flags = 0;
|
||||
if (p->Flags & ZCC_In) flags |= VARF_In;
|
||||
if (p->Flags & ZCC_Out) flags |= VARF_Out;
|
||||
if (p->Default != nullptr)
|
||||
if ((type->IsA(RUNTIME_CLASS(PStruct))) || (flags & VARF_Out))
|
||||
{
|
||||
auto val = Simplify(p->Default, &c->Type()->Symbols, true);
|
||||
flags |= VARF_Optional;
|
||||
if (val->Operation != PEX_ConstValue)
|
||||
// 'out' parameters and all structs except vectors are passed by reference
|
||||
if ((flags & VARF_Out) || (type != TypeVector2 && type != TypeVector3))
|
||||
{
|
||||
Error(c->cls, "Default parameter %s is not constant in %s", FName(p->Name).GetChars(), FName(f->Name).GetChars());
|
||||
type = NewPointer(type);
|
||||
}
|
||||
// Todo: Store and handle the default value (native functions will discard it anyway but for scripted ones this should be done decently.)
|
||||
}
|
||||
if (type->GetRegType() == REGT_NIL && type != TypeVector2 && type != TypeVector3)
|
||||
{
|
||||
Error(p, "Invalid type %s for function parameter", type->DescriptiveName());
|
||||
}
|
||||
else if (p->Default != nullptr)
|
||||
{
|
||||
flags |= VARF_Optional;
|
||||
// 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
|
||||
// The code generator can do this properly for us.
|
||||
FxExpression *x = new FxTypeCast(ConvertNode(p->Default), type, false);
|
||||
FCompileContext ctx(c->Type(), false);
|
||||
x = x->Resolve(ctx);
|
||||
|
||||
if (x != nullptr)
|
||||
{
|
||||
if (!x->isConstant())
|
||||
{
|
||||
Error(p, "Default parameter %s is not constant in %s", FName(p->Name).GetChars(), FName(f->Name).GetChars());
|
||||
}
|
||||
else if (x->ValueType != type)
|
||||
{
|
||||
Error(p, "Default parameter %s could not be converted to target type %s", FName(p->Name).GetChars(), c->Type()->TypeName.GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto cnst = static_cast<FxConstant *>(x);
|
||||
hasdefault = true;
|
||||
switch (type->GetRegType())
|
||||
{
|
||||
case REGT_INT:
|
||||
vmval = cnst->GetValue().GetInt();
|
||||
break;
|
||||
|
||||
case REGT_FLOAT:
|
||||
vmval = cnst->GetValue().GetFloat();
|
||||
break;
|
||||
|
||||
case REGT_POINTER:
|
||||
if (type->IsKindOf(RUNTIME_CLASS(PClassPointer)))
|
||||
vmval = (DObject*)cnst->GetValue().GetPointer();
|
||||
else
|
||||
vmval = cnst->GetValue().GetPointer();
|
||||
break;
|
||||
|
||||
case REGT_STRING:
|
||||
vmval = cnst->GetValue().GetString();
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0 && "no valid type for constant");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (x != nullptr) delete x;
|
||||
}
|
||||
// TBD: disallow certain types? For now, let everything pass that isn't an array.
|
||||
args.Push(type);
|
||||
argflags.Push(flags);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Push(nullptr);
|
||||
argflags.Push(0);
|
||||
}
|
||||
argdefaults.Push(vmval);
|
||||
p = static_cast<decltype(p)>(p->SiblingNext);
|
||||
} while (p != f->Params);
|
||||
}
|
||||
|
@ -2064,9 +2126,11 @@ void ZCCCompiler::InitFunctions()
|
|||
sym->Variants[0].Implementation = FunctionBuildList.AddFunction(sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
// todo: Check inheritance.
|
||||
// todo: Process function bodies.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue