mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2025-01-18 22:51:39 +00:00
- implemented usage restrictions for action functions.
This commit is contained in:
parent
1d006b37c3
commit
a2e17c0ab5
8 changed files with 189 additions and 58 deletions
|
@ -2489,7 +2489,7 @@ size_t PFunction::PropagateMark()
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
unsigned PFunction::AddVariant(PPrototype *proto, TArray<DWORD> &argflags, TArray<FName> &argnames, VMFunction *impl, int flags)
|
unsigned PFunction::AddVariant(PPrototype *proto, TArray<DWORD> &argflags, TArray<FName> &argnames, VMFunction *impl, int flags, int useflags)
|
||||||
{
|
{
|
||||||
Variant variant;
|
Variant variant;
|
||||||
|
|
||||||
|
@ -2497,6 +2497,7 @@ unsigned PFunction::AddVariant(PPrototype *proto, TArray<DWORD> &argflags, TArra
|
||||||
assert(Variants.Size() == 0);
|
assert(Variants.Size() == 0);
|
||||||
|
|
||||||
variant.Flags = flags;
|
variant.Flags = flags;
|
||||||
|
variant.UseFlags = useflags;
|
||||||
variant.Proto = proto;
|
variant.Proto = proto;
|
||||||
variant.ArgFlags = std::move(argflags);
|
variant.ArgFlags = std::move(argflags);
|
||||||
variant.ArgNames = std::move(argnames);
|
variant.ArgNames = std::move(argnames);
|
||||||
|
|
|
@ -724,13 +724,14 @@ public:
|
||||||
VMFunction *Implementation;
|
VMFunction *Implementation;
|
||||||
TArray<DWORD> ArgFlags; // Should be the same length as Proto->ArgumentTypes
|
TArray<DWORD> ArgFlags; // Should be the same length as Proto->ArgumentTypes
|
||||||
TArray<FName> ArgNames; // we need the names to access them later when the function gets compiled.
|
TArray<FName> ArgNames; // we need the names to access them later when the function gets compiled.
|
||||||
DWORD Flags;
|
uint32_t Flags;
|
||||||
|
int UseFlags;
|
||||||
PClass *SelfClass;
|
PClass *SelfClass;
|
||||||
};
|
};
|
||||||
TArray<Variant> Variants;
|
TArray<Variant> Variants;
|
||||||
PClass *OwningClass = nullptr;
|
PClass *OwningClass = nullptr;
|
||||||
|
|
||||||
unsigned AddVariant(PPrototype *proto, TArray<DWORD> &argflags, TArray<FName> &argnames, VMFunction *impl, int flags);
|
unsigned AddVariant(PPrototype *proto, TArray<DWORD> &argflags, TArray<FName> &argnames, VMFunction *impl, int flags, int useflags);
|
||||||
int GetImplicitArgs()
|
int GetImplicitArgs()
|
||||||
{
|
{
|
||||||
if (Variants[0].Flags & VARF_Action) return 3;
|
if (Variants[0].Flags & VARF_Action) return 3;
|
||||||
|
|
|
@ -5931,6 +5931,42 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Checks if a function may be called from the current context.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
static bool CheckFunctionCompatiblity(FScriptPosition &ScriptPosition, PFunction *caller, PFunction *callee)
|
||||||
|
{
|
||||||
|
if (callee->Variants[0].Flags & VARF_Method)
|
||||||
|
{
|
||||||
|
// The called function must support all usage modes of the current function. It may support more, but must not support less.
|
||||||
|
if ((callee->Variants[0].UseFlags & caller->Variants[0].UseFlags) != caller->Variants[0].UseFlags)
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Function %s incompatible with current context\n", callee->SymbolName.GetChars());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(caller->Variants[0].Flags & VARF_Method))
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Call to non-static function %s from a static context", callee->SymbolName.GetChars());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto callingself = caller->Variants[0].SelfClass;
|
||||||
|
auto calledself = callee->Variants[0].SelfClass;
|
||||||
|
if (!callingself->IsDescendantOf(calledself))
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Call to member function %s with incompatible self pointer.", callee->SymbolName.GetChars());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
@ -6008,39 +6044,15 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
|
|
||||||
PFunction *afd = FindClassMemberFunction(ctx.Class, ctx.Class, MethodName, ScriptPosition, &error);
|
PFunction *afd = FindClassMemberFunction(ctx.Class, ctx.Class, MethodName, ScriptPosition, &error);
|
||||||
|
|
||||||
// Action functions in state providers need special treatment because self is of type Actor here.
|
|
||||||
if (afd != nullptr && ctx.Class->IsDescendantOf(RUNTIME_CLASS(AStateProvider)) && (ctx.Function->Variants[0].Flags & VARF_Action))
|
|
||||||
{
|
|
||||||
// Only accept static and action functions from the current class. Calling a member function will require explicit use of 'invoker'.
|
|
||||||
if ((afd->Variants[0].Flags & (VARF_Method|VARF_Action)) == VARF_Method)
|
|
||||||
{
|
|
||||||
// Everything else that may be used here must pass the selfclass check, i.e. it must be reachable from Actor.
|
|
||||||
// Note that FuncClass is still the current item because for symbol privacy checks this is relevant.
|
|
||||||
afd = FindClassMemberFunction(ctx.Function->Variants[0].SelfClass, ctx.Class, MethodName, ScriptPosition, &error);
|
|
||||||
if (afd == nullptr)
|
|
||||||
{
|
|
||||||
ScriptPosition.Message(MSG_ERROR, "Unable to call non-action function %s from here. Please use 'invoker.%s' to call it.", MethodName.GetChars(), MethodName.GetChars());
|
|
||||||
delete this;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
delete this;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (afd != nullptr)
|
if (afd != nullptr)
|
||||||
{
|
{
|
||||||
if (ctx.Function->Variants[0].Flags & VARF_Static && !(afd->Variants[0].Flags & VARF_Static))
|
if (!CheckFunctionCompatiblity(ScriptPosition, ctx.Function, afd))
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_ERROR, "Call to non-static function %s from a static context", MethodName.GetChars());
|
|
||||||
delete this;
|
delete this;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto self = !(afd->Variants[0].Flags & VARF_Static)? new FxSelf(ScriptPosition) : nullptr;
|
|
||||||
|
auto self = (afd->Variants[0].Flags & VARF_Method)? new FxSelf(ScriptPosition) : nullptr;
|
||||||
auto x = new FxVMFunctionCall(self, afd, ArgList, ScriptPosition, false);
|
auto x = new FxVMFunctionCall(self, afd, ArgList, ScriptPosition, false);
|
||||||
delete this;
|
delete this;
|
||||||
return x->Resolve(ctx);
|
return x->Resolve(ctx);
|
||||||
|
@ -6338,6 +6350,7 @@ isresolved:
|
||||||
delete this;
|
delete this;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (staticonly && (afd->Variants[0].Flags & VARF_Method))
|
if (staticonly && (afd->Variants[0].Flags & VARF_Method))
|
||||||
{
|
{
|
||||||
if (!ctx.Class->IsDescendantOf(cls))
|
if (!ctx.Class->IsDescendantOf(cls))
|
||||||
|
@ -6355,6 +6368,28 @@ isresolved:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (afd->Variants[0].Flags & VARF_Method)
|
||||||
|
{
|
||||||
|
if (Self->ExprType == EFX_Self)
|
||||||
|
{
|
||||||
|
if (!CheckFunctionCompatiblity(ScriptPosition, ctx.Function, afd))
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Functions with no Actor usage may not be called through a pointer because they will lose their context.
|
||||||
|
if (!(afd->Variants[0].UseFlags & SUF_ACTOR))
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Function %s cannot be used with a non-self object\n", afd->SymbolName.GetChars());
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// do not pass the self pointer to static functions.
|
// do not pass the self pointer to static functions.
|
||||||
auto self = (afd->Variants[0].Flags & VARF_Method) ? Self : nullptr;
|
auto self = (afd->Variants[0].Flags & VARF_Method) ? Self : nullptr;
|
||||||
auto x = new FxVMFunctionCall(self, afd, ArgList, ScriptPosition, staticonly|novirtual);
|
auto x = new FxVMFunctionCall(self, afd, ArgList, ScriptPosition, staticonly|novirtual);
|
||||||
|
|
|
@ -170,7 +170,7 @@ PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, i
|
||||||
SetImplicitArgs(&args, &argflags, &argnames, containingclass, fflags, flags);
|
SetImplicitArgs(&args, &argflags, &argnames, containingclass, fflags, flags);
|
||||||
|
|
||||||
PFunction *sym = new PFunction(containingclass, NAME_None); // anonymous functions do not have names.
|
PFunction *sym = new PFunction(containingclass, NAME_None); // anonymous functions do not have names.
|
||||||
sym->AddVariant(NewPrototype(rets, args), argflags, argnames, nullptr, fflags);
|
sym->AddVariant(NewPrototype(rets, args), argflags, argnames, nullptr, fflags, flags);
|
||||||
return sym;
|
return sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -820,6 +820,7 @@ static void PrintFuncDeclarator(FLispString &out, ZCC_TreeNode *node)
|
||||||
out.Break();
|
out.Break();
|
||||||
out.Open("func-declarator");
|
out.Open("func-declarator");
|
||||||
out.AddHex(dnode->Flags);
|
out.AddHex(dnode->Flags);
|
||||||
|
PrintNodes(out, dnode->UseFlags);
|
||||||
PrintNodes(out, dnode->Type);
|
PrintNodes(out, dnode->Type);
|
||||||
out.AddName(dnode->Name);
|
out.AddName(dnode->Name);
|
||||||
PrintNodes(out, dnode->Params);
|
PrintNodes(out, dnode->Params);
|
||||||
|
@ -827,6 +828,16 @@ static void PrintFuncDeclarator(FLispString &out, ZCC_TreeNode *node)
|
||||||
out.Close();
|
out.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void PrintDeclFlags(FLispString &out, ZCC_TreeNode *node)
|
||||||
|
{
|
||||||
|
auto dnode = (ZCC_DeclFlags *)node;
|
||||||
|
out.Break();
|
||||||
|
out.Open("decl-flags");
|
||||||
|
out.AddHex(dnode->Flags);
|
||||||
|
PrintNodes(out, dnode->Id);
|
||||||
|
out.Close();
|
||||||
|
}
|
||||||
|
|
||||||
static void PrintFlagStmt(FLispString &out, ZCC_TreeNode *node)
|
static void PrintFlagStmt(FLispString &out, ZCC_TreeNode *node)
|
||||||
{
|
{
|
||||||
auto dnode = (ZCC_FlagStmt *)node;
|
auto dnode = (ZCC_FlagStmt *)node;
|
||||||
|
@ -901,6 +912,7 @@ void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode *
|
||||||
PrintFlagStmt,
|
PrintFlagStmt,
|
||||||
PrintPropertyStmt,
|
PrintPropertyStmt,
|
||||||
PrintVectorInitializer,
|
PrintVectorInitializer,
|
||||||
|
PrintDeclFlags,
|
||||||
};
|
};
|
||||||
|
|
||||||
FString ZCC_PrintAST(ZCC_TreeNode *root)
|
FString ZCC_PrintAST(ZCC_TreeNode *root)
|
||||||
|
|
|
@ -814,20 +814,21 @@ declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C).
|
||||||
}
|
}
|
||||||
else if (C.FuncName != NAME_None)
|
else if (C.FuncName != NAME_None)
|
||||||
{ // A function
|
{ // A function
|
||||||
NEW_AST_NODE(FuncDeclarator, decl, A.SourceLoc);
|
NEW_AST_NODE(FuncDeclarator, decl, A == nullptr? C.SourceLoc : A->SourceLoc);
|
||||||
decl->Type = B;
|
decl->Type = B;
|
||||||
decl->Params = C.FuncParams;
|
decl->Params = C.FuncParams;
|
||||||
decl->Name = C.FuncName;
|
decl->Name = C.FuncName;
|
||||||
decl->Flags = A.Int | C.FuncFlags;
|
decl->UseFlags = A == nullptr? nullptr : A->Id;
|
||||||
|
decl->Flags = (A == nullptr? 0 : A->Flags) | C.FuncFlags;
|
||||||
decl->Body = C.FuncBody;
|
decl->Body = C.FuncBody;
|
||||||
X = decl;
|
X = decl;
|
||||||
}
|
}
|
||||||
else if (B != NULL && B->SiblingNext == B)
|
else if (B != NULL && B->SiblingNext == B)
|
||||||
{ // A variable
|
{ // A variable
|
||||||
NEW_AST_NODE(VarDeclarator, decl, A.SourceLoc);
|
NEW_AST_NODE(VarDeclarator, decl, A == nullptr? B->SourceLoc : A->SourceLoc);
|
||||||
decl->Type = B;
|
decl->Type = B;
|
||||||
decl->Names = C.VarNames;
|
decl->Names = C.VarNames;
|
||||||
decl->Flags = A.Int;
|
decl->Flags = (A == nullptr? 0 : A->Flags);
|
||||||
X = decl;
|
X = decl;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -845,10 +846,10 @@ declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C).
|
||||||
}
|
}
|
||||||
declarator_no_fun(X) ::= decl_flags(A) type(B) variable_list(C) SEMICOLON.
|
declarator_no_fun(X) ::= decl_flags(A) type(B) variable_list(C) SEMICOLON.
|
||||||
{
|
{
|
||||||
NEW_AST_NODE(VarDeclarator, decl, A.SourceLoc ? A.SourceLoc : B->SourceLoc);
|
NEW_AST_NODE(VarDeclarator, decl, A != nullptr? A->SourceLoc : B->SourceLoc);
|
||||||
decl->Type = B;
|
decl->Type = B;
|
||||||
decl->Names = C;
|
decl->Names = C;
|
||||||
decl->Flags = A.Int;
|
decl->Flags = A == nullptr? 0 : A->Flags;
|
||||||
X = decl;
|
X = decl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -916,19 +917,52 @@ variable_list(X) ::= variable_list(A) COMMA variable_name(B).
|
||||||
X = A; /*X-overwrites-A*/
|
X = A; /*X-overwrites-A*/
|
||||||
}
|
}
|
||||||
|
|
||||||
decl_flags(X) ::= . { X.Int = 0; X.SourceLoc = 0; }
|
%type decl_flags { ZCC_DeclFlags * }
|
||||||
decl_flags(X) ::= decl_flags(A) NATIVE(T). { X.Int = A.Int | ZCC_Native; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
|
decl_flags(X) ::= . { X = NULL; }
|
||||||
decl_flags(X) ::= decl_flags(A) STATIC(T). { X.Int = A.Int | ZCC_Static; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
|
decl_flags(X) ::= decl_flags(F) decl_flag(A).
|
||||||
decl_flags(X) ::= decl_flags(A) PRIVATE(T). { X.Int = A.Int | ZCC_Private; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
|
{
|
||||||
decl_flags(X) ::= decl_flags(A) PROTECTED(T). { X.Int = A.Int | ZCC_Protected; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
|
if (F == nullptr)
|
||||||
decl_flags(X) ::= decl_flags(A) LATENT(T). { X.Int = A.Int | ZCC_Latent; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
|
{
|
||||||
decl_flags(X) ::= decl_flags(A) FINAL(T). { X.Int = A.Int | ZCC_Final; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
|
NEW_AST_NODE(DeclFlags,nil_f,A);
|
||||||
decl_flags(X) ::= decl_flags(A) META(T). { X.Int = A.Int | ZCC_Meta; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
|
X = nil_f;
|
||||||
decl_flags(X) ::= decl_flags(A) ACTION(T). { X.Int = A.Int | ZCC_Action; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
|
X->Id = nullptr;
|
||||||
decl_flags(X) ::= decl_flags(A) READONLY(T). { X.Int = A.Int | ZCC_ReadOnly; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
|
X->Flags = A.Int;
|
||||||
decl_flags(X) ::= decl_flags(A) DEPRECATED(T). { X.Int = A.Int | ZCC_Deprecated; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
|
}
|
||||||
decl_flags(X) ::= decl_flags(A) VIRTUAL(T). { X.Int = A.Int | ZCC_Virtual; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
|
else
|
||||||
decl_flags(X) ::= decl_flags(A) OVERRIDE(T). { X.Int = A.Int | ZCC_Override; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
|
{
|
||||||
|
X = F;
|
||||||
|
X->Flags |= A.Int;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
decl_flags(X) ::= decl_flags(F) ACTION(B) states_opts(A).
|
||||||
|
{
|
||||||
|
if (F == nullptr)
|
||||||
|
{
|
||||||
|
NEW_AST_NODE(DeclFlags,nil_f,B.SourceLoc);
|
||||||
|
X = nil_f;
|
||||||
|
X->Flags = ZCC_Action;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
X = F;
|
||||||
|
X->Flags |= ZCC_Action;
|
||||||
|
}
|
||||||
|
X->Id = A;
|
||||||
|
}
|
||||||
|
|
||||||
|
decl_flag(X) ::= NATIVE(T). { X.Int = ZCC_Native; X.SourceLoc = T.SourceLoc; }
|
||||||
|
decl_flag(X) ::= STATIC(T). { X.Int = ZCC_Static; X.SourceLoc = T.SourceLoc; }
|
||||||
|
decl_flag(X) ::= PRIVATE(T). { X.Int = ZCC_Private; X.SourceLoc = T.SourceLoc; }
|
||||||
|
decl_flag(X) ::= PROTECTED(T). { X.Int = ZCC_Protected; X.SourceLoc = T.SourceLoc; }
|
||||||
|
decl_flag(X) ::= LATENT(T). { X.Int = ZCC_Latent; X.SourceLoc = T.SourceLoc; }
|
||||||
|
decl_flag(X) ::= FINAL(T). { X.Int = ZCC_Final; X.SourceLoc = T.SourceLoc; }
|
||||||
|
decl_flag(X) ::= META(T). { X.Int = ZCC_Meta; X.SourceLoc = T.SourceLoc; }
|
||||||
|
decl_flag(X) ::= READONLY(T). { X.Int = ZCC_ReadOnly; X.SourceLoc = T.SourceLoc; }
|
||||||
|
decl_flag(X) ::= DEPRECATED(T). { X.Int = ZCC_Deprecated; X.SourceLoc = T.SourceLoc; }
|
||||||
|
decl_flag(X) ::= VIRTUAL(T). { X.Int = ZCC_Virtual; X.SourceLoc = T.SourceLoc; }
|
||||||
|
decl_flag(X) ::= OVERRIDE(T). { X.Int = ZCC_Override; X.SourceLoc = T.SourceLoc; }
|
||||||
|
|
||||||
func_const(X) ::= . { X.Int = 0; X.SourceLoc = stat->sc->GetMessageLine(); }
|
func_const(X) ::= . { X.Int = 0; X.SourceLoc = stat->sc->GetMessageLine(); }
|
||||||
func_const(X) ::= CONST(T). { X.Int = ZCC_FuncConst; X.SourceLoc = T.SourceLoc; }
|
func_const(X) ::= CONST(T). { X.Int = ZCC_FuncConst; X.SourceLoc = T.SourceLoc; }
|
||||||
|
@ -979,9 +1013,9 @@ func_param(X) ::= func_param_flags(A) type(B) IDENTIFIER(C) EQ expr(D).
|
||||||
}
|
}
|
||||||
|
|
||||||
func_param_flags(X) ::= . { X.Int = 0; X.SourceLoc = 0; }
|
func_param_flags(X) ::= . { X.Int = 0; X.SourceLoc = 0; }
|
||||||
func_param_flags(X) ::= func_param_flags(A) IN(T). { X.Int = A.Int | ZCC_In; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
|
func_param_flags(X) ::= func_param_flags(A) IN(T). { X.Int = A.Int | ZCC_In; X.SourceLoc = T.SourceLoc; }
|
||||||
func_param_flags(X) ::= func_param_flags(A) OUT(T). { X.Int = A.Int | ZCC_Out; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
|
func_param_flags(X) ::= func_param_flags(A) OUT(T). { X.Int = A.Int | ZCC_Out; X.SourceLoc = T.SourceLoc; }
|
||||||
func_param_flags(X) ::= func_param_flags(A) OPTIONAL(T). { X.Int = A.Int | ZCC_Optional; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
|
func_param_flags(X) ::= func_param_flags(A) OPTIONAL(T). { X.Int = A.Int | ZCC_Optional; X.SourceLoc = T.SourceLoc; }
|
||||||
|
|
||||||
/************ Expressions ************/
|
/************ Expressions ************/
|
||||||
|
|
||||||
|
|
|
@ -2051,6 +2051,35 @@ void ZCCCompiler::InitFunctions()
|
||||||
uint32_t varflags = VARF_Method;
|
uint32_t varflags = VARF_Method;
|
||||||
int implicitargs = 1;
|
int implicitargs = 1;
|
||||||
AFuncDesc *afd = nullptr;
|
AFuncDesc *afd = nullptr;
|
||||||
|
int useflags = SUF_ACTOR | SUF_OVERLAY | SUF_WEAPON | SUF_ITEM;
|
||||||
|
if (f->UseFlags != nullptr)
|
||||||
|
{
|
||||||
|
useflags = 0;
|
||||||
|
auto p = f->UseFlags;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
switch (p->Id)
|
||||||
|
{
|
||||||
|
case NAME_Actor:
|
||||||
|
useflags |= SUF_ACTOR;
|
||||||
|
break;
|
||||||
|
case NAME_Overlay:
|
||||||
|
useflags |= SUF_OVERLAY;
|
||||||
|
break;
|
||||||
|
case NAME_Weapon:
|
||||||
|
useflags |= SUF_WEAPON;
|
||||||
|
break;
|
||||||
|
case NAME_Item:
|
||||||
|
useflags |= SUF_ITEM;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Error(p, "Unknown Action qualifier %s", FName(p->Id).GetChars());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = static_cast<decltype(p)>(p->SiblingNext);
|
||||||
|
} while (p != f->UseFlags);
|
||||||
|
}
|
||||||
|
|
||||||
// map to implementation flags.
|
// map to implementation flags.
|
||||||
if (f->Flags & ZCC_Private) varflags |= VARF_Private;
|
if (f->Flags & ZCC_Private) varflags |= VARF_Private;
|
||||||
|
@ -2058,9 +2087,22 @@ void ZCCCompiler::InitFunctions()
|
||||||
if (f->Flags & ZCC_Deprecated) varflags |= VARF_Deprecated;
|
if (f->Flags & ZCC_Deprecated) varflags |= VARF_Deprecated;
|
||||||
if (f->Flags & ZCC_Virtual) varflags |= VARF_Virtual;
|
if (f->Flags & ZCC_Virtual) varflags |= VARF_Virtual;
|
||||||
if (f->Flags & ZCC_Override) varflags |= VARF_Override;
|
if (f->Flags & ZCC_Override) varflags |= VARF_Override;
|
||||||
if (f->Flags & ZCC_Action) varflags |= VARF_Action|VARF_Final, implicitargs = 3; // Action implies Final.
|
if (f->Flags & ZCC_Action)
|
||||||
|
{
|
||||||
|
varflags |= VARF_Final; // Action implies Final.
|
||||||
|
if (useflags & (SUF_OVERLAY | SUF_WEAPON | SUF_ITEM))
|
||||||
|
{
|
||||||
|
varflags |= VARF_Action;
|
||||||
|
implicitargs = 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
implicitargs = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (f->Flags & ZCC_Static) varflags = (varflags & ~VARF_Method) | VARF_Final, implicitargs = 0; // Static implies Final.
|
if (f->Flags & ZCC_Static) varflags = (varflags & ~VARF_Method) | VARF_Final, implicitargs = 0; // Static implies Final.
|
||||||
|
|
||||||
|
|
||||||
if (varflags & VARF_Override) varflags &= ~VARF_Virtual; // allow 'virtual override'.
|
if (varflags & VARF_Override) varflags &= ~VARF_Virtual; // allow 'virtual override'.
|
||||||
// Only one of these flags may be used.
|
// Only one of these flags may be used.
|
||||||
static int exclude[] = { ZCC_Virtual, ZCC_Override, ZCC_Action, ZCC_Static };
|
static int exclude[] = { ZCC_Virtual, ZCC_Override, ZCC_Action, ZCC_Static };
|
||||||
|
@ -2096,9 +2138,7 @@ void ZCCCompiler::InitFunctions()
|
||||||
(*afd->VMPointer)->ImplicitArgs = BYTE(implicitargs);
|
(*afd->VMPointer)->ImplicitArgs = BYTE(implicitargs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Todo: parse these values from the definition
|
SetImplicitArgs(&args, &argflags, &argnames, c->Type(), varflags, useflags);
|
||||||
int tempuseflags = (varflags & VARF_Action) ? SUF_WEAPON | SUF_ITEM | SUF_OVERLAY | SUF_ACTOR : SUF_ACTOR;
|
|
||||||
SetImplicitArgs(&args, &argflags, &argnames, c->Type(), varflags, tempuseflags);
|
|
||||||
argdefaults.Resize(argnames.Size());
|
argdefaults.Resize(argnames.Size());
|
||||||
auto p = f->Params;
|
auto p = f->Params;
|
||||||
bool hasoptionals = false;
|
bool hasoptionals = false;
|
||||||
|
@ -2225,7 +2265,7 @@ void ZCCCompiler::InitFunctions()
|
||||||
}
|
}
|
||||||
|
|
||||||
PFunction *sym = new PFunction(c->Type(), f->Name);
|
PFunction *sym = new PFunction(c->Type(), f->Name);
|
||||||
sym->AddVariant(NewPrototype(rets, args), argflags, argnames, afd == nullptr? nullptr : *(afd->VMPointer), varflags);
|
sym->AddVariant(NewPrototype(rets, args), argflags, argnames, afd == nullptr? nullptr : *(afd->VMPointer), varflags, useflags);
|
||||||
c->Type()->Symbols.ReplaceSymbol(sym);
|
c->Type()->Symbols.ReplaceSymbol(sym);
|
||||||
|
|
||||||
if (!(f->Flags & ZCC_Native))
|
if (!(f->Flags & ZCC_Native))
|
||||||
|
|
|
@ -101,6 +101,7 @@ enum EZCCTreeNodeType
|
||||||
AST_FlagStmt,
|
AST_FlagStmt,
|
||||||
AST_PropertyStmt,
|
AST_PropertyStmt,
|
||||||
AST_VectorValue,
|
AST_VectorValue,
|
||||||
|
AST_DeclFlags,
|
||||||
|
|
||||||
NUM_AST_NODE_TYPES
|
NUM_AST_NODE_TYPES
|
||||||
};
|
};
|
||||||
|
@ -473,6 +474,12 @@ struct ZCC_FuncParamDecl : ZCC_TreeNode
|
||||||
int Flags;
|
int Flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ZCC_DeclFlags : ZCC_TreeNode
|
||||||
|
{
|
||||||
|
ZCC_Identifier *Id;
|
||||||
|
int Flags;
|
||||||
|
};
|
||||||
|
|
||||||
struct ZCC_ConstantDef : ZCC_NamedNode
|
struct ZCC_ConstantDef : ZCC_NamedNode
|
||||||
{
|
{
|
||||||
ZCC_Expression *Value;
|
ZCC_Expression *Value;
|
||||||
|
@ -498,6 +505,7 @@ struct ZCC_FuncDeclarator : ZCC_Declarator
|
||||||
ZCC_FuncParamDecl *Params;
|
ZCC_FuncParamDecl *Params;
|
||||||
ENamedName Name;
|
ENamedName Name;
|
||||||
ZCC_Statement *Body;
|
ZCC_Statement *Body;
|
||||||
|
ZCC_Identifier *UseFlags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ZCC_Default : ZCC_CompoundStmt
|
struct ZCC_Default : ZCC_CompoundStmt
|
||||||
|
|
Loading…
Reference in a new issue