From 2d50f52cf135fd8e6ebed638767dd60fd34d01c0 Mon Sep 17 00:00:00 2001 From: Jeff Hutchinson Date: Mon, 20 Sep 2021 21:00:33 -0400 Subject: [PATCH] Allow local variables to be used in eval. --- Engine/source/console/astNodes.cpp | 55 ++------------------------ Engine/source/console/codeBlock.cpp | 15 ++++++- Engine/source/console/compiledEval.cpp | 3 +- Engine/source/console/compiler.cpp | 42 ++++++++++++++++++++ Engine/source/console/compiler.h | 29 ++++++++++++++ 5 files changed, 90 insertions(+), 54 deletions(-) diff --git a/Engine/source/console/astNodes.cpp b/Engine/source/console/astNodes.cpp index 091f6cf1c..aaca1ea06 100644 --- a/Engine/source/console/astNodes.cpp +++ b/Engine/source/console/astNodes.cpp @@ -56,57 +56,7 @@ namespace Compiler using namespace Compiler; -class FuncVars -{ - struct Var - { - S32 reg; - TypeReq currentType; - StringTableEntry name; - bool isConstant; - }; - -public: - S32 assign(StringTableEntry var, TypeReq currentType, S32 lineNumber, bool isConstant = false) - { - std::unordered_map::iterator found = vars.find(var); - if (found != vars.end()) - { - AssertISV(!found->second.isConstant, avar("Reassigning variable %s when it is a constant. File: %s Line : %d", var, CodeBlock::smCurrentParser->getCurrentFile(), lineNumber)); - return found->second.reg; - } - - S32 id = counter++; - vars[var] = { id, currentType, var, isConstant }; - variableNameMap[id] = var; - - return id; - } - - S32 lookup(StringTableEntry var, S32 lineNumber) - { - std::unordered_map::iterator found = vars.find(var); - AssertISV(found != vars.end(), avar("Variable %s referenced before used when compiling script. File: %s Line: %d", var, CodeBlock::smCurrentParser->getCurrentFile(), lineNumber)); - return found->second.reg; - } - - TypeReq lookupType(StringTableEntry var, S32 lineNumber) - { - std::unordered_map::iterator found = vars.find(var); - - AssertISV(found != vars.end(), avar("Variable %s referenced before used when compiling script. File: %s Line: %d", var, CodeBlock::smCurrentParser->getCurrentFile(), lineNumber)); - return found->second.currentType; - } - - inline S32 count() { return counter; } - - std::unordered_map variableNameMap; - -private: - std::unordered_map vars; - S32 counter = 0; -}; - +FuncVars gEvalFuncVars; FuncVars* gFuncVars = NULL; inline FuncVars* getFuncVars(S32 lineNumber) @@ -1602,7 +1552,8 @@ U32 FunctionDeclStmtNode::compileStmt(CodeStream& codeStream, U32 ip) tbl->add(fnName, nameSpace, varName); } - gFuncVars = NULL; + // In eval mode, global func vars are allowed. + gFuncVars = gIsEvalCompile ? &gEvalFuncVars : NULL; return ip; } diff --git a/Engine/source/console/codeBlock.cpp b/Engine/source/console/codeBlock.cpp index 1d1ad7593..f03ec25f6 100644 --- a/Engine/source/console/codeBlock.cpp +++ b/Engine/source/console/codeBlock.cpp @@ -37,6 +37,9 @@ CodeBlock * CodeBlock::smCodeBlockList = NULL; CodeBlock * CodeBlock::smCurrentCodeBlock = NULL; ConsoleParser *CodeBlock::smCurrentParser = NULL; +extern FuncVars gEvalFuncVars; +extern FuncVars* gFuncVars; + //------------------------------------------------------------------------- CodeBlock::CodeBlock() @@ -491,6 +494,8 @@ bool CodeBlock::compile(const char *codeFileName, StringTableEntry fileName, con chompUTF8BOM(inScript, &script); gSyntaxError = false; + gIsEvalCompile = false; + gFuncVars = NULL; consoleAllocReset(); @@ -629,6 +634,11 @@ ConsoleValue CodeBlock::compileExec(StringTableEntry fileName, const char *inStr addToCodeList(); gStatementList = NULL; + + // we are an eval compile if we don't have a file name associated (no exec) + gIsEvalCompile = fileName == NULL; + // In eval mode, global func vars are allowed. + gFuncVars = gIsEvalCompile ? &gEvalFuncVars : NULL; // Set up the parser. smCurrentParser = getParserForFile(fileName); @@ -667,6 +677,8 @@ ConsoleValue CodeBlock::compileExec(StringTableEntry fileName, const char *inStr codeStream.emit(OP_RETURN_VOID); codeStream.emitCodeStream(&codeSize, &code, &lineBreakPairs); + + S32 localRegisterCount = gIsEvalCompile ? gEvalFuncVars.count() : 0; consoleAllocReset(); @@ -683,7 +695,8 @@ ConsoleValue CodeBlock::compileExec(StringTableEntry fileName, const char *inStr if (lastIp + 1 != codeSize) Con::warnf(ConsoleLogEntry::General, "precompile size mismatch, precompile: %d compile: %d", codeSize, lastIp); - return std::move(exec(0, fileName, NULL, 0, 0, noCalls, NULL, setFrame)); + // repurpose argc as local register counter for global state + return std::move(exec(0, fileName, NULL, localRegisterCount, 0, noCalls, NULL, setFrame)); } //------------------------------------------------------------------------- diff --git a/Engine/source/console/compiledEval.cpp b/Engine/source/console/compiledEval.cpp index 561e1f04a..360c13c90 100644 --- a/Engine/source/console/compiledEval.cpp +++ b/Engine/source/console/compiledEval.cpp @@ -693,7 +693,8 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa // Do we want this code to execute using a new stack frame? if (setFrame < 0) { - gEvalState.pushFrame(NULL, NULL, 0); + // argc is the local count for eval + gEvalState.pushFrame(NULL, NULL, argc); gCallStack.pushFrame(0); popFrame = true; } diff --git a/Engine/source/console/compiler.cpp b/Engine/source/console/compiler.cpp index 1ab6e7b22..13839feda 100644 --- a/Engine/source/console/compiler.cpp +++ b/Engine/source/console/compiler.cpp @@ -34,6 +34,8 @@ #include "console/simBase.h" +extern FuncVars gEvalFuncVars; + namespace Compiler { @@ -86,6 +88,7 @@ namespace Compiler //------------------------------------------------------------ bool gSyntaxError = false; + bool gIsEvalCompile = false; //------------------------------------------------------------ @@ -121,6 +124,7 @@ namespace Compiler getFunctionStringTable().reset(); getIdentTable().reset(); getFunctionVariableMappingTable().reset(); + gEvalFuncVars.clear(); } void *consoleAlloc(U32 size) { return gConsoleAllocator.alloc(size); } @@ -132,6 +136,44 @@ namespace Compiler using namespace Compiler; +S32 FuncVars::assign(StringTableEntry var, TypeReq currentType, S32 lineNumber, bool isConstant) +{ + std::unordered_map::iterator found = vars.find(var); + if (found != vars.end()) + { + AssertISV(!found->second.isConstant, avar("Reassigning variable %s when it is a constant. File: %s Line : %d", var, CodeBlock::smCurrentParser->getCurrentFile(), lineNumber)); + return found->second.reg; + } + + S32 id = counter++; + vars[var] = { id, currentType, var, isConstant }; + variableNameMap[id] = var; + + return id; +} + +S32 FuncVars::lookup(StringTableEntry var, S32 lineNumber) +{ + std::unordered_map::iterator found = vars.find(var); + AssertISV(found != vars.end(), avar("Variable %s referenced before used when compiling script. File: %s Line: %d", var, CodeBlock::smCurrentParser->getCurrentFile(), lineNumber)); + return found->second.reg; +} + +TypeReq FuncVars::lookupType(StringTableEntry var, S32 lineNumber) +{ + std::unordered_map::iterator found = vars.find(var); + + AssertISV(found != vars.end(), avar("Variable %s referenced before used when compiling script. File: %s Line: %d", var, CodeBlock::smCurrentParser->getCurrentFile(), lineNumber)); + return found->second.currentType; +} + +void FuncVars::clear() +{ + vars.clear(); + variableNameMap.clear(); + counter = 0; +} + //------------------------------------------------------------------------- diff --git a/Engine/source/console/compiler.h b/Engine/source/console/compiler.h index 117576a61..24067257f 100644 --- a/Engine/source/console/compiler.h +++ b/Engine/source/console/compiler.h @@ -276,6 +276,35 @@ namespace Compiler void consoleAllocReset(); extern bool gSyntaxError; + extern bool gIsEvalCompile; +}; + +class FuncVars +{ + struct Var + { + S32 reg; + TypeReq currentType; + StringTableEntry name; + bool isConstant; + }; + +public: + S32 assign(StringTableEntry var, TypeReq currentType, S32 lineNumber, bool isConstant = false); + + S32 lookup(StringTableEntry var, S32 lineNumber); + + TypeReq lookupType(StringTableEntry var, S32 lineNumber); + + inline S32 count() { return counter; } + + std::unordered_map variableNameMap; + + void clear(); + +private: + std::unordered_map vars; + S32 counter = 0; }; /// Utility class to emit and patch bytecode