mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-29 07:22:07 +00:00
- give PFunction a bit more information:
* explicitly require passing the owning class when creating it. * extract self pointer class when adding a variant. * put the flags on the single variants, we can not fully rule out that they will be 100% identical, if variants ever get allowed.
This commit is contained in:
parent
091da92819
commit
db8ab1bc4a
10 changed files with 196 additions and 33 deletions
|
@ -2119,7 +2119,7 @@ static int PatchCodePtrs (int dummy)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TArray<DWORD> &args = sym->Variants[0].ArgFlags;
|
TArray<DWORD> &args = sym->Variants[0].ArgFlags;
|
||||||
if ((sym->Flags & (VARF_Method | VARF_Action)) != (VARF_Method | VARF_Action) || (args.Size() > NAP && !(args[NAP] & VARF_Optional)))
|
if ((sym->Variants[0].Flags & (VARF_Method | VARF_Action)) != (VARF_Method | VARF_Action) || (args.Size() > NAP && !(args[NAP] & VARF_Optional)))
|
||||||
{
|
{
|
||||||
Printf("Frame %d: Incompatible code pointer '%s'\n", frame, Line2);
|
Printf("Frame %d: Incompatible code pointer '%s'\n", frame, Line2);
|
||||||
sym = NULL;
|
sym = NULL;
|
||||||
|
@ -2731,7 +2731,7 @@ static bool LoadDehSupp ()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TArray<DWORD> &args = sym->Variants[0].ArgFlags;
|
TArray<DWORD> &args = sym->Variants[0].ArgFlags;
|
||||||
if ((sym->Flags & (VARF_Method|VARF_Action)) != (VARF_Method | VARF_Action) || (args.Size() > NAP && !(args[NAP] & VARF_Optional)))
|
if ((sym->Variants[0].Flags & (VARF_Method|VARF_Action)) != (VARF_Method | VARF_Action) || (args.Size() > NAP && !(args[NAP] & VARF_Optional)))
|
||||||
{
|
{
|
||||||
sc.ScriptMessage("Incompatible code pointer '%s'", sc.String);
|
sc.ScriptMessage("Incompatible code pointer '%s'", sc.String);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2475,7 +2475,7 @@ size_t PFunction::PropagateMark()
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; i < Variants.Size(); ++i)
|
for (unsigned i = 0; i < Variants.Size(); ++i)
|
||||||
{
|
{
|
||||||
//GC::Mark(Variants[i].Proto);
|
GC::Mark(Variants[i].Proto);
|
||||||
GC::Mark(Variants[i].Implementation);
|
GC::Mark(Variants[i].Implementation);
|
||||||
}
|
}
|
||||||
return Variants.Size() * sizeof(Variants[0]) + Super::PropagateMark();
|
return Variants.Size() * sizeof(Variants[0]) + Super::PropagateMark();
|
||||||
|
@ -2490,14 +2490,29 @@ size_t PFunction::PropagateMark()
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
unsigned PFunction::AddVariant(PPrototype *proto, TArray<DWORD> &argflags, TArray<FName> &argnames, VMFunction *impl)
|
unsigned PFunction::AddVariant(PPrototype *proto, TArray<DWORD> &argflags, TArray<FName> &argnames, VMFunction *impl, int flags)
|
||||||
{
|
{
|
||||||
Variant variant;
|
Variant variant;
|
||||||
|
|
||||||
|
// I do not think we really want to deal with overloading here...
|
||||||
|
assert(Variants.Size() == 0);
|
||||||
|
|
||||||
|
variant.Flags = flags;
|
||||||
variant.Proto = proto;
|
variant.Proto = proto;
|
||||||
variant.ArgFlags = argflags;
|
variant.ArgFlags = argflags;
|
||||||
variant.Implementation = impl;
|
variant.Implementation = impl;
|
||||||
if (impl != nullptr) impl->Proto = proto;
|
if (impl != nullptr) impl->Proto = proto;
|
||||||
|
|
||||||
|
// SelfClass can differ from OwningClass, but this is variant-dependent.
|
||||||
|
// Unlike the owner there can be cases where different variants can have different SelfClasses.
|
||||||
|
// (Of course only if this ever gets enabled...)
|
||||||
|
if (flags & VARF_Method)
|
||||||
|
{
|
||||||
|
assert(proto->ArgumentTypes.Size() > 0);
|
||||||
|
variant.SelfClass = dyn_cast<PClass>(proto->ArgumentTypes[0]);
|
||||||
|
assert(variant.SelfClass != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
return Variants.Push(variant);
|
return Variants.Push(variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -696,16 +696,17 @@ 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;
|
||||||
|
PClass *SelfClass;
|
||||||
};
|
};
|
||||||
TArray<Variant> Variants;
|
TArray<Variant> Variants;
|
||||||
DWORD Flags;
|
PClass *OwningClass = nullptr;
|
||||||
|
|
||||||
unsigned AddVariant(PPrototype *proto, TArray<DWORD> &argflags, TArray<FName> &argnames, VMFunction *impl);
|
unsigned AddVariant(PPrototype *proto, TArray<DWORD> &argflags, TArray<FName> &argnames, VMFunction *impl, int flags);
|
||||||
|
|
||||||
size_t PropagateMark();
|
size_t PropagateMark();
|
||||||
|
|
||||||
PFunction(FName name) : PSymbol(name), Flags(0) {}
|
PFunction(PClass *owner = nullptr, FName name = NAME_None) : PSymbol(name), OwningClass(owner) {}
|
||||||
PFunction() : PSymbol(NAME_None), Flags(0) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Meta-info for every class derived from DObject ---------------------------
|
// Meta-info for every class derived from DObject ---------------------------
|
||||||
|
|
|
@ -3898,7 +3898,7 @@ VMFunction *FxVMFunctionCall::GetDirectFunction()
|
||||||
// then it can be a "direct" function. That is, the DECORATE
|
// then it can be a "direct" function. That is, the DECORATE
|
||||||
// definition can call that function directly without wrapping
|
// definition can call that function directly without wrapping
|
||||||
// it inside VM code.
|
// it inside VM code.
|
||||||
if ((ArgList ? ArgList->Size() : 0) == 0 && (Function->Flags & VARF_Action))
|
if ((ArgList ? ArgList->Size() : 0) == 0 && (Function->Variants[0].Flags & VARF_Action))
|
||||||
{
|
{
|
||||||
return Function->Variants[0].Implementation;
|
return Function->Variants[0].Implementation;
|
||||||
}
|
}
|
||||||
|
@ -3920,8 +3920,8 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
auto argtypes = proto->ArgumentTypes;
|
auto argtypes = proto->ArgumentTypes;
|
||||||
|
|
||||||
int implicit;
|
int implicit;
|
||||||
if (Function->Flags & VARF_Action) implicit = 3;
|
if (Function->Variants[0].Flags & VARF_Action) implicit = 3;
|
||||||
else if (Function->Flags & VARF_Method) implicit = 1;
|
else if (Function->Variants[0].Flags & VARF_Method) implicit = 1;
|
||||||
else implicit = 0;
|
else implicit = 0;
|
||||||
|
|
||||||
if (ArgList != NULL)
|
if (ArgList != NULL)
|
||||||
|
@ -4014,15 +4014,15 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
|
||||||
// For ZSCRIPT 'self' is properly used for the state's owning actor, meaning we have to pass the second argument here.
|
// For ZSCRIPT 'self' is properly used for the state's owning actor, meaning we have to pass the second argument here.
|
||||||
|
|
||||||
// If both functions are non-action or both are action, there is no need for special treatment.
|
// If both functions are non-action or both are action, there is no need for special treatment.
|
||||||
if (!OwnerIsSelf || (!!(Function->Flags & VARF_Action) == build->IsActionFunc))
|
if (!OwnerIsSelf || (!!(Function->Variants[0].Flags & VARF_Action) == build->IsActionFunc))
|
||||||
{
|
{
|
||||||
// Emit code to pass implied parameters
|
// Emit code to pass implied parameters
|
||||||
if (Function->Flags & VARF_Method)
|
if (Function->Variants[0].Flags & VARF_Method)
|
||||||
{
|
{
|
||||||
build->Emit(OP_PARAM, 0, REGT_POINTER, 0);
|
build->Emit(OP_PARAM, 0, REGT_POINTER, 0);
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
if (Function->Flags & VARF_Action)
|
if (Function->Variants[0].Flags & VARF_Action)
|
||||||
{
|
{
|
||||||
static_assert(NAP == 3, "This code needs to be updated if NAP changes");
|
static_assert(NAP == 3, "This code needs to be updated if NAP changes");
|
||||||
if (build->IsActionFunc)
|
if (build->IsActionFunc)
|
||||||
|
@ -4041,17 +4041,14 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// There are two possibilities here:
|
if (build->IsActionFunc && (Function->Variants[0].Flags & VARF_Method))
|
||||||
// Calling a non-action function from an action function.
|
|
||||||
// In that case the 'stateowner' pointer needs to be used as self.
|
|
||||||
if (build->IsActionFunc && (Function->Flags & VARF_Method))
|
|
||||||
{
|
{
|
||||||
build->Emit(OP_PARAM, 0, REGT_POINTER, 1);
|
build->Emit(OP_PARAM, 0, REGT_POINTER, 0);
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
// and calling an action function from a non-action function.
|
// and calling an action function from a non-action function.
|
||||||
// This must be blocked because it lacks crucial information.
|
// This must be blocked because it lacks crucial information.
|
||||||
if (!build->IsActionFunc && (Function->Flags & VARF_Action))
|
if (!build->IsActionFunc && (Function->Variants[0].Flags & VARF_Action))
|
||||||
{
|
{
|
||||||
// This case should be eliminated in the analyzing stage.
|
// This case should be eliminated in the analyzing stage.
|
||||||
I_Error("Cannot call action function from non-action functions.");
|
I_Error("Cannot call action function from non-action functions.");
|
||||||
|
|
153
src/scripting/codegeneration/functioncalls.cpp
Normal file
153
src/scripting/codegeneration/functioncalls.cpp
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
** cg_functioncall.cpp
|
||||||
|
**
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
** Copyright 2016 Christoph Oelckers
|
||||||
|
** All rights reserved.
|
||||||
|
**
|
||||||
|
** Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions
|
||||||
|
** are met:
|
||||||
|
**
|
||||||
|
** 1. Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in the
|
||||||
|
** documentation and/or other materials provided with the distribution.
|
||||||
|
** 3. The name of the author may not be used to endorse or promote products
|
||||||
|
** derived from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "doomtype.h"
|
||||||
|
#include "codegen.h"
|
||||||
|
#include "thingdef.h"
|
||||||
|
#include "zscript/zcc_parser.h"
|
||||||
|
|
||||||
|
// just some rough concepts for now...
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FindClassMemberFunction
|
||||||
|
//
|
||||||
|
// Looks for a name in a class's
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
PFunction *FindClassMemberFunction(PClass *cls, FName name, FScriptPosition &sc)
|
||||||
|
{
|
||||||
|
PSymbolTable *symtable;
|
||||||
|
auto symbol = cls->Symbols.FindSymbolInTable(name, symtable);
|
||||||
|
auto funcsym = dyn_cast<PFunction>(symbol);
|
||||||
|
|
||||||
|
if (symbol != nullptr)
|
||||||
|
{
|
||||||
|
if (funcsym == nullptr)
|
||||||
|
{
|
||||||
|
sc.Message(MSG_ERROR, "%s is not a member function of %s", name.GetChars(), cls->TypeName.GetChars());
|
||||||
|
}
|
||||||
|
else if (funcsym->Flags & VARF_Private && symtable != &cls->Symbols)
|
||||||
|
{
|
||||||
|
sc.Message(MSG_ERROR, "%s is declared private and not accessible", symbol->SymbolName.GetChars());
|
||||||
|
}
|
||||||
|
else if (funcsym->Flags & VARF_Deprecated)
|
||||||
|
{
|
||||||
|
sc.Message(MSG_WARNING, "Call to deprecated function %s", symbol->SymbolName.GetChars());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return funcsym;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// let's save some work down the line by analyzing the type of function
|
||||||
|
// that's being called right here and create appropriate nodes.
|
||||||
|
// A simple function call expression must be immediately resolvable in
|
||||||
|
// the context it gets compiled in, if the function name cannot be
|
||||||
|
// resolved here, it will never.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FxExpression *ConvertSimpleFunctionCall(ZCC_ExprID *function, FArgumentList *args, PClass *cls, FScriptPosition &sc)
|
||||||
|
{
|
||||||
|
// Priority is as follows:
|
||||||
|
//1. member functions of the containing class.
|
||||||
|
//2. action specials.
|
||||||
|
//3. floating point operations
|
||||||
|
//4. global builtins
|
||||||
|
|
||||||
|
if (cls != nullptr)
|
||||||
|
{
|
||||||
|
// There is an action function ACS_NamedExecuteWithResult which must be ignored here for this to work.
|
||||||
|
if (function->Identifier != NAME_ACS_NamedExecuteWithResult)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
args = ConvertNodeList(fcall->Parameters);
|
||||||
|
if (args->Size() == 0)
|
||||||
|
{
|
||||||
|
delete args;
|
||||||
|
args = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FxMemberunctionCall(new FxSelf(), new FxInvoker(), func, args, sc, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FxExpression *ConvertFunctionCall(ZCC_Expression *function, FArgumentList *args, PClass *cls, FScriptPosition &sc)
|
||||||
|
{
|
||||||
|
// function names can either be
|
||||||
|
// - plain identifiers
|
||||||
|
// - class members
|
||||||
|
// - array syntax for random() calls.
|
||||||
|
|
||||||
|
switch(function->NodeType)
|
||||||
|
{
|
||||||
|
case AST_ExprID:
|
||||||
|
return ConvertSimpleFunctionCall(static_cast<ZCC_ExprID *>(function), args, cls, sc);
|
||||||
|
|
||||||
|
case AST_ExprMemberAccess:
|
||||||
|
return ConvertMemberCall(fcall);
|
||||||
|
|
||||||
|
case AST_ExprBinary:
|
||||||
|
// Array access syntax is wrapped into a ZCC_ExprBinary object.
|
||||||
|
if (fcall->Function->Operation == PEX_ArrayAccess)
|
||||||
|
{
|
||||||
|
return ConvertArrayFunctionCall(fcall);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Error(fcall, "Invalid function identifier");
|
||||||
|
return new FxNop(*fcall); // return something so that we can continue
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
assert(fcall->Function->NodeType == AST_ExprID); // of course this cannot remain. Right now nothing more complex can come along but later this will have to be decomposed into 'self' and the actual function name.
|
||||||
|
auto fname = static_cast<ZCC_ExprID *>(fcall->Function)->Identifier;
|
||||||
|
return new FxFunctionCall(nullptr, fname, ConvertNodeList(fcall->Parameters), *ast);
|
||||||
|
|
||||||
|
#endif
|
|
@ -474,9 +474,8 @@ void ParseFunctionDef(FScanner &sc, PClassActor *cls, FName funcname,
|
||||||
|
|
||||||
if (afd != NULL)
|
if (afd != NULL)
|
||||||
{
|
{
|
||||||
PFunction *sym = new PFunction(funcname);
|
PFunction *sym = new PFunction(cls, funcname);
|
||||||
sym->AddVariant(NewPrototype(rets, args), argflags, argnames, *(afd->VMPointer));
|
sym->AddVariant(NewPrototype(rets, args), argflags, argnames, *(afd->VMPointer), funcflags);
|
||||||
sym->Flags = funcflags;
|
|
||||||
if (cls->Symbols.AddSymbol(sym) == NULL)
|
if (cls->Symbols.AddSymbol(sym) == NULL)
|
||||||
{
|
{
|
||||||
delete sym;
|
delete sym;
|
||||||
|
|
|
@ -602,12 +602,12 @@ void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression
|
||||||
int pnum = 0;
|
int pnum = 0;
|
||||||
bool zeroparm;
|
bool zeroparm;
|
||||||
|
|
||||||
if (afd->Flags & VARF_Method)
|
if (afd->Variants[0].Flags & VARF_Method)
|
||||||
{
|
{
|
||||||
numparams--;
|
numparams--;
|
||||||
pnum++;
|
pnum++;
|
||||||
}
|
}
|
||||||
if (afd->Flags & VARF_Action)
|
if (afd->Variants[0].Flags & VARF_Action)
|
||||||
{
|
{
|
||||||
numparams -= 2;
|
numparams -= 2;
|
||||||
pnum += 2;
|
pnum += 2;
|
||||||
|
|
|
@ -142,9 +142,8 @@ PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, i
|
||||||
rets[0] = returntype != nullptr? returntype : TypeError; // Use TypeError as placeholder if we do not know the return type yet.
|
rets[0] = returntype != nullptr? returntype : TypeError; // Use TypeError as placeholder if we do not know the return type yet.
|
||||||
SetImplicitArgs(&args, &argflags, &argnames, containingclass, flags);
|
SetImplicitArgs(&args, &argflags, &argnames, containingclass, flags);
|
||||||
|
|
||||||
PFunction *sym = new PFunction(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);
|
sym->AddVariant(NewPrototype(rets, args), argflags, argnames, nullptr, VARF_Action|VARF_Method);
|
||||||
sym->Flags = VARF_Action;
|
|
||||||
return sym;
|
return sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -686,7 +686,7 @@ void FFunctionBuildList::Build()
|
||||||
|
|
||||||
// This needs to be fixed, so that the compile context receives the entire function symbol, including the containing class, the prototype and argument names, which will be needed to run the code generator
|
// This needs to be fixed, so that the compile context receives the entire function symbol, including the containing class, the prototype and argument names, which will be needed to run the code generator
|
||||||
// As a first step this just needs to get working so fetch the class type from the prototype's argument list.
|
// As a first step this just needs to get working so fetch the class type from the prototype's argument list.
|
||||||
auto cls = static_cast<PClass*>(item.Func->Variants[0].Proto->ArgumentTypes[!!(item.Func->Flags & VARF_Action)]);
|
auto cls = static_cast<PClass*>(item.Func->Variants[0].Proto->ArgumentTypes[!!(item.Func->Variants[0].Flags & VARF_Action)]);
|
||||||
// We don't know the return type in advance for anonymous functions.
|
// We don't know the return type in advance for anonymous functions.
|
||||||
FCompileContext ctx(cls, nullptr);
|
FCompileContext ctx(cls, nullptr);
|
||||||
item.Code = item.Code->Resolve(ctx);
|
item.Code = item.Code->Resolve(ctx);
|
||||||
|
|
|
@ -1960,9 +1960,8 @@ void ZCCCompiler::InitFunctions()
|
||||||
} while (p != f->Params);
|
} while (p != f->Params);
|
||||||
}
|
}
|
||||||
|
|
||||||
PFunction *sym = new PFunction(f->Name);
|
PFunction *sym = new PFunction(c->Type(), f->Name);
|
||||||
sym->AddVariant(NewPrototype(rets, args), argflags, argnames, afd == nullptr? nullptr : *(afd->VMPointer));
|
sym->AddVariant(NewPrototype(rets, args), argflags, argnames, afd == nullptr? nullptr : *(afd->VMPointer), varflags);
|
||||||
sym->Flags = varflags;
|
|
||||||
c->Type()->Symbols.ReplaceSymbol(sym);
|
c->Type()->Symbols.ReplaceSymbol(sym);
|
||||||
|
|
||||||
// todo: Check inheritance.
|
// todo: Check inheritance.
|
||||||
|
@ -2010,7 +2009,7 @@ FxExpression *ZCCCompiler::SetupActionFunction(PClassActor *cls, ZCC_TreeNode *a
|
||||||
PFunction *afd = dyn_cast<PFunction>(cls->Symbols.FindSymbol(id->Identifier, true));
|
PFunction *afd = dyn_cast<PFunction>(cls->Symbols.FindSymbol(id->Identifier, true));
|
||||||
if (afd != nullptr)
|
if (afd != nullptr)
|
||||||
{
|
{
|
||||||
if (fc->Parameters == nullptr && (afd->Flags & VARF_Action))
|
if (fc->Parameters == nullptr && (afd->Variants[0].Flags & VARF_Action))
|
||||||
{
|
{
|
||||||
// We can use this function directly without wrapping it in a caller.
|
// We can use this function directly without wrapping it in a caller.
|
||||||
return new FxVMFunctionCall(afd, nullptr, *af, true);
|
return new FxVMFunctionCall(afd, nullptr, *af, true);
|
||||||
|
|
Loading…
Reference in a new issue