mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-27 14:22:13 +00:00
- pass the current function to the compile context instead of just the containing class.
This commit is contained in:
parent
db8ab1bc4a
commit
cbb990a79e
7 changed files with 101 additions and 48 deletions
|
@ -2509,7 +2509,9 @@ unsigned PFunction::AddVariant(PPrototype *proto, TArray<DWORD> &argflags, TArra
|
||||||
if (flags & VARF_Method)
|
if (flags & VARF_Method)
|
||||||
{
|
{
|
||||||
assert(proto->ArgumentTypes.Size() > 0);
|
assert(proto->ArgumentTypes.Size() > 0);
|
||||||
variant.SelfClass = dyn_cast<PClass>(proto->ArgumentTypes[0]);
|
auto selftypeptr = dyn_cast<PPointer>(proto->ArgumentTypes[0]);
|
||||||
|
assert(selftypeptr != nullptr);
|
||||||
|
variant.SelfClass = dyn_cast<PClass>(selftypeptr->PointedType);
|
||||||
assert(variant.SelfClass != nullptr);
|
assert(variant.SelfClass != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ enum
|
||||||
VARF_In = (1<<10),
|
VARF_In = (1<<10),
|
||||||
VARF_Out = (1<<11),
|
VARF_Out = (1<<11),
|
||||||
VARF_Implicit = (1<<12), // implicitly created parameters (i.e. do not compare when checking function signatures)
|
VARF_Implicit = (1<<12), // implicitly created parameters (i.e. do not compare when checking function signatures)
|
||||||
|
VARF_Static = (1<<13), // static class data (by necessity read only.)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Symbol information -------------------------------------------------------
|
// Symbol information -------------------------------------------------------
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
#include "thingdef.h"
|
#include "thingdef.h"
|
||||||
#include "p_lnspec.h"
|
#include "p_lnspec.h"
|
||||||
#include "doomstat.h"
|
#include "doomstat.h"
|
||||||
#include "thingdef_exp.h"
|
#include "codegen.h"
|
||||||
#include "m_fixed.h"
|
#include "m_fixed.h"
|
||||||
#include "vmbuilder.h"
|
#include "vmbuilder.h"
|
||||||
#include "v_text.h"
|
#include "v_text.h"
|
||||||
|
@ -91,13 +91,25 @@ static const FLOP FxFlops[] =
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
FCompileContext::FCompileContext(PClass *cls, PPrototype *ret) : Class(cls), ReturnProto(ret)
|
FCompileContext::FCompileContext(PFunction *fnc, PPrototype *ret) : ReturnProto(ret), Function(fnc), Class(nullptr)
|
||||||
|
{
|
||||||
|
if (fnc != nullptr) Class = fnc->OwningClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
FCompileContext::FCompileContext(PClass *cls) : ReturnProto(nullptr), Function(nullptr), Class(cls)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PSymbol *FCompileContext::FindInClass(FName identifier)
|
PSymbol *FCompileContext::FindInClass(FName identifier, PSymbolTable *&symt)
|
||||||
{
|
{
|
||||||
return Class ? Class->Symbols.FindSymbol(identifier, true) : nullptr;
|
return Class != nullptr? Class->Symbols.FindSymbolInTable(identifier, symt) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
PSymbol *FCompileContext::FindInSelfClass(FName identifier, PSymbolTable *&symt)
|
||||||
|
{
|
||||||
|
// If we have no self we cannot retrieve any values from it.
|
||||||
|
if (Function == nullptr || Function->Variants[0].SelfClass == nullptr) return nullptr;
|
||||||
|
return Function->Variants[0].SelfClass->Symbols.FindSymbolInTable(identifier, symt);
|
||||||
}
|
}
|
||||||
PSymbol *FCompileContext::FindGlobal(FName identifier)
|
PSymbol *FCompileContext::FindGlobal(FName identifier)
|
||||||
{
|
{
|
||||||
|
@ -3178,15 +3190,16 @@ FxIdentifier::FxIdentifier(FName name, const FScriptPosition &pos)
|
||||||
FxExpression *FxIdentifier::Resolve(FCompileContext& ctx)
|
FxExpression *FxIdentifier::Resolve(FCompileContext& ctx)
|
||||||
{
|
{
|
||||||
PSymbol * sym;
|
PSymbol * sym;
|
||||||
FxExpression *newex = NULL;
|
FxExpression *newex = nullptr;
|
||||||
//FBaseCVar * cv = NULL;
|
|
||||||
//FString s;
|
|
||||||
int num;
|
int num;
|
||||||
//const PClass *Class;
|
|
||||||
|
|
||||||
CHECKRESOLVED();
|
CHECKRESOLVED();
|
||||||
|
|
||||||
|
// Ugh, the horror. Constants need to be taken from the owning class, but members from the self class to catch invalid accesses here...
|
||||||
|
|
||||||
// see if the current class (if valid) defines something with this name.
|
// see if the current class (if valid) defines something with this name.
|
||||||
if ((sym = ctx.FindInClass(Identifier)) != NULL)
|
PSymbolTable *symtbl;
|
||||||
|
if ((sym = ctx.FindInClass(Identifier, symtbl)) != nullptr)
|
||||||
{
|
{
|
||||||
if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst)))
|
if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst)))
|
||||||
{
|
{
|
||||||
|
@ -3195,15 +3208,64 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx)
|
||||||
}
|
}
|
||||||
else if (sym->IsKindOf(RUNTIME_CLASS(PField)))
|
else if (sym->IsKindOf(RUNTIME_CLASS(PField)))
|
||||||
{
|
{
|
||||||
|
ABORT(ctx.Function); // only valid when resolving a function.
|
||||||
PField *vsym = static_cast<PField*>(sym);
|
PField *vsym = static_cast<PField*>(sym);
|
||||||
ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as member variable, index %d\n", Identifier.GetChars(), vsym->Offset);
|
|
||||||
newex = new FxClassMember((new FxSelf(ScriptPosition))->Resolve(ctx), vsym, ScriptPosition);
|
// We have 4 cases to consider here:
|
||||||
|
// 1. The symbol is a static/meta member (not implemented yet) which is always accessible.
|
||||||
|
// 2. This is a static function
|
||||||
|
// 3. This is an action function with a restricted self pointer
|
||||||
|
// 4. This is a normal member or unrestricted action function.
|
||||||
|
if (vsym->Flags & VARF_Deprecated)
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_WARNING, "Accessing deprecated member variable %s", vsym->SymbolName.GetChars());
|
||||||
|
}
|
||||||
|
if ((vsym->Flags & VARF_Private) && symtbl != &ctx.Class->Symbols)
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Private member %s not accessible", vsym->SymbolName.GetChars());
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vsym->Flags & VARF_Static)
|
||||||
|
{
|
||||||
|
// todo. For now these cannot be defined so let's just exit.
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.Function->Variants[0].SelfClass == nullptr)
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Unable to access class member from static function");
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ctx.Function->Variants[0].SelfClass != ctx.Class)
|
||||||
|
{
|
||||||
|
// Check if the restricted class can access it.
|
||||||
|
PSymbol *sym2;
|
||||||
|
if ((sym2 = ctx.FindInSelfClass(Identifier, symtbl)) != nullptr)
|
||||||
|
{
|
||||||
|
if (sym != sym2)
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Member variable of %s not accessible through restricted self pointer", ctx.Class->TypeName.GetChars());
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as member variable, index %d\n", Identifier.GetChars(), vsym->Offset);
|
||||||
|
newex = new FxClassMember((new FxSelf(ScriptPosition))->Resolve(ctx), vsym, ScriptPosition);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_ERROR, "Invalid member identifier '%s'\n", Identifier.GetChars());
|
ScriptPosition.Message(MSG_ERROR, "Invalid member identifier '%s'\n", Identifier.GetChars());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// now check the global identifiers.
|
// now check the global identifiers.
|
||||||
else if ((sym = ctx.FindGlobal(Identifier)) != NULL)
|
else if ((sym = ctx.FindGlobal(Identifier)) != NULL)
|
||||||
{
|
{
|
||||||
|
@ -3217,23 +3279,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx)
|
||||||
ScriptPosition.Message(MSG_ERROR, "Invalid global identifier '%s'\n", Identifier.GetChars());
|
ScriptPosition.Message(MSG_ERROR, "Invalid global identifier '%s'\n", Identifier.GetChars());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
else if ((Class = PClass::FindClass(Identifier)))
|
|
||||||
{
|
|
||||||
pos.Message(MSG_DEBUGLOG, "Resolving name '%s' as class name\n", Identifier.GetChars());
|
|
||||||
newex = new FxClassType(Class, ScriptPosition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// also check for CVars
|
|
||||||
/*
|
|
||||||
else if ((cv = FindCVar(Identifier, NULL)) != NULL)
|
|
||||||
{
|
|
||||||
CLOG(CL_RESOLVE, LPrintf("Resolving name '%s' as cvar\n", Identifier.GetChars()));
|
|
||||||
newex = new FxCVar(cv, ScriptPosition);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// and line specials
|
// and line specials
|
||||||
else if ((num = P_FindLineSpecial(Identifier, NULL, NULL)))
|
else if ((num = P_FindLineSpecial(Identifier, NULL, NULL)))
|
||||||
{
|
{
|
||||||
|
@ -3270,15 +3316,13 @@ FxSelf::FxSelf(const FScriptPosition &pos)
|
||||||
FxExpression *FxSelf::Resolve(FCompileContext& ctx)
|
FxExpression *FxSelf::Resolve(FCompileContext& ctx)
|
||||||
{
|
{
|
||||||
CHECKRESOLVED();
|
CHECKRESOLVED();
|
||||||
if (!ctx.Class)
|
if (ctx.Function == nullptr || ctx.Function->Variants[0].SelfClass == nullptr)
|
||||||
{
|
{
|
||||||
// can't really happen with DECORATE's expression evaluator.
|
|
||||||
ScriptPosition.Message(MSG_ERROR, "self used outside of a member function");
|
ScriptPosition.Message(MSG_ERROR, "self used outside of a member function");
|
||||||
delete this;
|
delete this;
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
ValueType = ctx.Class;
|
ValueType = NewPointer(ctx.Function->Variants[0].SelfClass);
|
||||||
ValueType = NewPointer(RUNTIME_CLASS(DObject));
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3614,8 +3658,10 @@ FxFunctionCall::~FxFunctionCall()
|
||||||
|
|
||||||
FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
|
FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
{
|
{
|
||||||
// This part is mostly a kludge, it really needs to get the class type from Self.
|
ABORT(ctx.Class);
|
||||||
|
|
||||||
PFunction *afd = dyn_cast<PFunction>(ctx.Class->Symbols.FindSymbol(MethodName, true));
|
PFunction *afd = dyn_cast<PFunction>(ctx.Class->Symbols.FindSymbol(MethodName, true));
|
||||||
|
// Todo: More checks are needed here to make it work as expected.
|
||||||
if (afd != nullptr)
|
if (afd != nullptr)
|
||||||
{
|
{
|
||||||
auto x = new FxVMFunctionCall(afd, ArgList, ScriptPosition, false);
|
auto x = new FxVMFunctionCall(afd, ArgList, ScriptPosition, false);
|
||||||
|
@ -5172,9 +5218,9 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx)
|
||||||
delete this;
|
delete this;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (!scope->IsDescendantOf(ctx.Class))
|
else if (!scope->IsAncestorOf(ctx.Class))
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(),ctx.Class->TypeName.GetChars());
|
ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(), ctx.Class->TypeName.GetChars());
|
||||||
delete this;
|
delete this;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,11 +67,14 @@ struct FCompileContext
|
||||||
{
|
{
|
||||||
TArray<FxJumpStatement *> Jumps;
|
TArray<FxJumpStatement *> Jumps;
|
||||||
PPrototype *ReturnProto;
|
PPrototype *ReturnProto;
|
||||||
PClass *Class;
|
PFunction *Function; // The function that is currently being compiled (or nullptr for constant evaluation.)
|
||||||
|
PClass *Class; // The type of the owning class.
|
||||||
|
|
||||||
FCompileContext(PClass *cls = nullptr, PPrototype *ret = nullptr);
|
FCompileContext(PFunction *func = nullptr, PPrototype *ret = nullptr);
|
||||||
|
FCompileContext(PClass *cls); // only to be used to resolve constants!
|
||||||
|
|
||||||
PSymbol *FindInClass(FName identifier);
|
PSymbol *FindInClass(FName identifier, PSymbolTable *&symt);
|
||||||
|
PSymbol *FindInSelfClass(FName identifier, PSymbolTable *&symt);
|
||||||
PSymbol *FindGlobal(FName identifier);
|
PSymbol *FindGlobal(FName identifier);
|
||||||
|
|
||||||
void HandleJumps(int token, FxExpression *handler);
|
void HandleJumps(int token, FxExpression *handler);
|
||||||
|
|
|
@ -89,7 +89,7 @@ void SetImplicitArgs(TArray<PType *> *args, TArray<DWORD> *argflags, TArray<FNam
|
||||||
if (funcflags & VARF_Method)
|
if (funcflags & VARF_Method)
|
||||||
{
|
{
|
||||||
// implied self pointer
|
// implied self pointer
|
||||||
if (args != nullptr) args->Push(cls);
|
if (args != nullptr) args->Push(NewPointer(cls));
|
||||||
if (argflags != nullptr) argflags->Push(VARF_Implicit);
|
if (argflags != nullptr) argflags->Push(VARF_Implicit);
|
||||||
if (argnames != nullptr) argnames->Push(NAME_self);
|
if (argnames != nullptr) argnames->Push(NAME_self);
|
||||||
}
|
}
|
||||||
|
@ -101,11 +101,11 @@ void SetImplicitArgs(TArray<PType *> *args, TArray<DWORD> *argflags, TArray<FNam
|
||||||
// Special treatment for weapons and CustomInventorys: 'self' is not the defining class but the actual user of the item, so this pointer must be of type 'Actor'
|
// Special treatment for weapons and CustomInventorys: 'self' is not the defining class but the actual user of the item, so this pointer must be of type 'Actor'
|
||||||
if (cls->IsDescendantOf(RUNTIME_CLASS(AStateProvider)))
|
if (cls->IsDescendantOf(RUNTIME_CLASS(AStateProvider)))
|
||||||
{
|
{
|
||||||
args->Insert(0, RUNTIME_CLASS(AActor)); // this must go in before the real pointer to the containing class.
|
args->Insert(0, NewPointer(RUNTIME_CLASS(AActor))); // this must go in before the real pointer to the containing class.
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
args->Push(cls);
|
args->Push(NewPointer(cls));
|
||||||
}
|
}
|
||||||
args->Push(TypeState/*Info*/); // fixme: TypeState is not the correct type here!!!
|
args->Push(TypeState/*Info*/); // fixme: TypeState is not the correct type here!!!
|
||||||
}
|
}
|
||||||
|
|
|
@ -686,9 +686,8 @@ 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->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(item.Func, nullptr);
|
||||||
item.Code = item.Code->Resolve(ctx);
|
item.Code = item.Code->Resolve(ctx);
|
||||||
item.Proto = ctx.ReturnProto;
|
item.Proto = ctx.ReturnProto;
|
||||||
|
|
||||||
|
@ -715,10 +714,7 @@ void FFunctionBuildList::Build()
|
||||||
|
|
||||||
if (dump != nullptr)
|
if (dump != nullptr)
|
||||||
{
|
{
|
||||||
char label[64];
|
DumpFunction(dump, sfunc, item.DumpName.GetChars(), (int)item.DumpName.Len());
|
||||||
int labellen = mysnprintf(label, countof(label), item.DumpName,
|
|
||||||
cls->TypeName.GetChars());
|
|
||||||
DumpFunction(dump, sfunc, label, labellen);
|
|
||||||
codesize += sfunc->CodeSize;
|
codesize += sfunc->CodeSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1888,6 +1888,11 @@ void ZCCCompiler::InitFunctions()
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
auto type = DetermineType(c->Type(), f, f->Name, t, false);
|
auto type = DetermineType(c->Type(), f, f->Name, t, false);
|
||||||
|
if (type->IsKindOf(RUNTIME_CLASS(PStruct)))
|
||||||
|
{
|
||||||
|
// structs and classes only get passed by pointer.
|
||||||
|
type = NewPointer(type);
|
||||||
|
}
|
||||||
// TBD: disallow certain types? For now, let everything pass that isn't an array.
|
// TBD: disallow certain types? For now, let everything pass that isn't an array.
|
||||||
rets.Push(type);
|
rets.Push(type);
|
||||||
t = static_cast<decltype(t)>(t->SiblingNext);
|
t = static_cast<decltype(t)>(t->SiblingNext);
|
||||||
|
|
Loading…
Reference in a new issue