- tested and fixed FxLocalVariableDeclaration.

- create proper variable data from the function prototype instead of assuming that there's just 3 pointers.
- added a printable name to VMScriptFunction for error output during gameplay in case something goes wrong.
This commit is contained in:
Christoph Oelckers 2016-10-20 16:55:12 +02:00
parent 2fd4fa9660
commit 24394dfc92
7 changed files with 40 additions and 35 deletions

View file

@ -2545,7 +2545,8 @@ unsigned PFunction::AddVariant(PPrototype *proto, TArray<DWORD> &argflags, TArra
variant.Flags = flags;
variant.Proto = proto;
variant.ArgFlags = argflags;
variant.ArgFlags = std::move(argflags);
variant.ArgNames = std::move(argnames);
variant.Implementation = impl;
if (impl != nullptr) impl->Proto = proto;

View file

@ -5074,7 +5074,6 @@ VMFunction *FxSequence::GetDirectFunction()
FxExpression *FxCompoundStatement::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
auto outer = ctx.Block;
Outer = ctx.Block;
ctx.Block = this;
@ -5105,10 +5104,12 @@ ExpEmit FxCompoundStatement::Emit(VMFunctionBuilder *build)
// FxCompoundStatement :: FindLocalVariable
//
// Looks for a variable name in any of the containing compound statements
// This does a simple linear search on each block's variables.
// The lists here normally don't get large enough to justify something more complex.
//
//==========================================================================
FxLocalVariableDeclaration *FxCompoundStatement::FindLocalVariable(FName name)
FxLocalVariableDeclaration *FxCompoundStatement::FindLocalVariable(FName name, FCompileContext &ctx)
{
auto block = this;
while (block != nullptr)
@ -5122,6 +5123,14 @@ FxLocalVariableDeclaration *FxCompoundStatement::FindLocalVariable(FName name)
}
block = block->Outer;
}
// finally check the context for function arguments
for (auto arg : ctx.FunctionArgs)
{
if (arg->Name == name)
{
return arg;
}
}
return nullptr;
}

View file

@ -64,6 +64,7 @@ class FxJumpStatement;
struct FScriptPosition;
class FxLoopStatement;
class FxCompoundStatement;
class FxLocalVariableDeclaration;
struct FCompileContext
{
@ -73,6 +74,7 @@ struct FCompileContext
PFunction *Function; // The function that is currently being compiled (or nullptr for constant evaluation.)
PClass *Class; // The type of the owning class.
bool FromDecorate;
TDeletingArray<FxLocalVariableDeclaration *> FunctionArgs;
FCompileContext(PFunction *func, PPrototype *ret, bool fromdecorate);
FCompileContext(PClass *cls); // only to be used to resolve constants!
@ -191,8 +193,7 @@ struct ExpVal
struct ExpEmit
{
ExpEmit() : RegNum(0), RegType(REGT_NIL), Konst(false), Fixed(false), Final(false) {}
ExpEmit(int reg, int type) : RegNum(reg), RegType(type), Konst(false), Fixed(false), Final(false) {}
ExpEmit(int reg, int type, bool konst) : RegNum(reg), RegType(type), Konst(konst), Fixed(false), Final(false) {}
ExpEmit(int reg, int type, bool konst = false, bool fixed = false) : RegNum(reg), RegType(type), Konst(konst), Fixed(fixed), Final(false) {}
ExpEmit(VMFunctionBuilder *build, int type);
void Free(VMFunctionBuilder *build);
void Reuse(VMFunctionBuilder *build);
@ -1122,7 +1123,7 @@ public:
FxCompoundStatement(const FScriptPosition &pos) : FxSequence(pos) {}
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
FxLocalVariableDeclaration *FindLocalVariable(FName name);
FxLocalVariableDeclaration *FindLocalVariable(FName name, FCompileContext &ctx);
bool CheckLocalVariable(FName name);
};
@ -1384,9 +1385,9 @@ class FxLocalVariableDeclaration : public FxExpression
FName Name;
FxExpression *Init;
public:
int RegNum = -1;
public:
FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, const FScriptPosition &p);
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);

View file

@ -789,6 +789,7 @@ public:
VM_UBYTE NumKonstA;
VM_UHALF MaxParam; // Maximum number of parameters this function has on the stack at once
VM_UBYTE NumArgs; // Number of arguments this function takes
FString PrintableName; // so that the VM can print meaningful info if something in this function goes wrong.
};
class VMFrameStack

View file

@ -663,7 +663,7 @@ VMFunction *FFunctionBuildList::AddFunction(PFunction *functype, FxExpression *c
Item it;
it.Func = functype;
it.Code = code;
it.DumpName = name;
it.PrintableName = name;
it.Function = new VMScriptFunction;
it.Proto = nullptr;
it.FromDecorate = fromdecorate;
@ -684,39 +684,45 @@ void FFunctionBuildList::Build()
{
assert(item.Code != NULL);
// 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.
// We don't know the return type in advance for anonymous functions.
FCompileContext ctx(item.Func, nullptr, item.FromDecorate);
FCompileContext ctx(item.Func, item.Func->SymbolName == NAME_None ? nullptr : item.Func->Variants[0].Proto, item.FromDecorate);
// Allocate registers for the function's arguments and create local variable nodes before starting to resolve it.
VMFunctionBuilder buildit(true);
for(unsigned i=0;i<item.Func->Variants[0].Proto->ArgumentTypes.Size();i++)
{
auto type = item.Func->Variants[0].Proto->ArgumentTypes[i];
auto name = item.Func->Variants[0].ArgNames[i];
// this won't get resolved and won't get emitted. This is only needed so that the code generator can retrieve the necessary info to do its work.
auto local = new FxLocalVariableDeclaration(type, name, nullptr, FScriptPosition());
local->RegNum = buildit.Registers[type->GetRegType()].Get(1);
ctx.FunctionArgs.Push(local);
}
item.Code = item.Code->Resolve(ctx);
item.Proto = ctx.ReturnProto;
// Make sure resolving it didn't obliterate it.
if (item.Code != nullptr)
{
VMFunctionBuilder buildit(true);
assert(item.Proto != nullptr);
auto numargs = item.Func->Variants[0].Proto->ArgumentTypes.Size();
// Generate prototype for this anonymous function
// Fixme: This later needs to do proper allocation for the function's entire argument list, once non-anonymous functions can be done.
buildit.Registers[REGT_POINTER].Get(numargs);
VMScriptFunction *sfunc = item.Function;
// create a new prototype from the now known return type and the argument list of the function's template prototype.
item.Function->Proto = NewPrototype(item.Proto->ReturnTypes, item.Func->Variants[0].Proto->ArgumentTypes);
sfunc->Proto = NewPrototype(item.Proto->ReturnTypes, item.Func->Variants[0].Proto->ArgumentTypes);
// Emit code
item.Code->Emit(&buildit);
buildit.MakeFunction(item.Function);
item.Function->NumArgs = numargs;
buildit.MakeFunction(sfunc);
sfunc->NumArgs = item.Func->Variants[0].Proto->ArgumentTypes.Size();
if (dump != nullptr)
{
DumpFunction(dump, sfunc, item.DumpName.GetChars(), (int)item.DumpName.Len());
DumpFunction(dump, sfunc, item.PrintableName.GetChars(), (int)item.PrintableName.Len());
codesize += sfunc->CodeSize;
}
sfunc->PrintableName = item.PrintableName;
}
delete item.Code;
}

View file

@ -105,7 +105,7 @@ class FFunctionBuildList
FxExpression *Code = nullptr;
PPrototype *Proto = nullptr;
VMScriptFunction *Function = nullptr;
FString DumpName;
FString PrintableName;
bool FromDecorate;
};

View file

@ -2078,19 +2078,6 @@ FxExpression *ZCCCompiler::SetupActionFunction(PClassActor *cls, ZCC_TreeNode *a
}
ConvertClass = cls;
return ConvertAST(af);
//Error(af, "Complex action functions not supported yet.");
//return nullptr;
/*
bool hasfinalret;
tcall->Code = ParseActions(sc, state, statestring, bag, hasfinalret);
if (!hasfinalret && tcall->Code != nullptr)
{
static_cast<FxCompoundStatement *>(tcall->Code)->Add(new FxReturnStatement(nullptr, sc));
}
*/
}
//==========================================================================