From 24394dfc924b17abc0581e2d6c022be42d1a6c0d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 20 Oct 2016 16:55:12 +0200 Subject: [PATCH] - 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. --- src/dobjtype.cpp | 3 ++- src/scripting/codegeneration/codegen.cpp | 13 +++++++-- src/scripting/codegeneration/codegen.h | 9 ++++--- src/scripting/vm/vm.h | 1 + src/scripting/vm/vmbuilder.cpp | 34 ++++++++++++++---------- src/scripting/vm/vmbuilder.h | 2 +- src/scripting/zscript/zcc_compile.cpp | 13 --------- 7 files changed, 40 insertions(+), 35 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 317694e20..f25e592f2 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2545,7 +2545,8 @@ unsigned PFunction::AddVariant(PPrototype *proto, TArray &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; diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 4554a830b..9b6248c88 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -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; } diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index eeabf891e..c16c45f42 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -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 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); diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 425eba531..8cd63f3e5 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -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 diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index 7e946a17c..5e5ce85db 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -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;iVariants[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; } diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/vm/vmbuilder.h index c5ca868e0..dcaae7251 100644 --- a/src/scripting/vm/vmbuilder.h +++ b/src/scripting/vm/vmbuilder.h @@ -105,7 +105,7 @@ class FFunctionBuildList FxExpression *Code = nullptr; PPrototype *Proto = nullptr; VMScriptFunction *Function = nullptr; - FString DumpName; + FString PrintableName; bool FromDecorate; }; diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 33830d135..88486d9c3 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -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(tcall->Code)->Add(new FxReturnStatement(nullptr, sc)); - } - */ - } //==========================================================================