diff --git a/Engine/source/console/astNodes.cpp b/Engine/source/console/astNodes.cpp index c34c4b38d..0c69fbc5c 100644 --- a/Engine/source/console/astNodes.cpp +++ b/Engine/source/console/astNodes.cpp @@ -57,11 +57,16 @@ namespace Compiler using namespace Compiler; FuncVars gEvalFuncVars; +FuncVars gGlobalScopeFuncVars; FuncVars* gFuncVars = NULL; inline FuncVars* getFuncVars(S32 lineNumber) { - AssertISV(gFuncVars, avar("Attemping to use local variable in global scope. File: %s Line: %d", CodeBlock::smCurrentParser->getCurrentFile(), lineNumber)); + if (gFuncVars == &gGlobalScopeFuncVars) + { + const char* str = avar("Attemping to use local variable in global scope. File: %s Line: %d", CodeBlock::smCurrentParser->getCurrentFile(), lineNumber); + scriptErrorHandler(str); + } return gFuncVars; } @@ -1552,8 +1557,7 @@ U32 FunctionDeclStmtNode::compileStmt(CodeStream& codeStream, U32 ip) tbl->add(fnName, nameSpace, varName); } - // In eval mode, global func vars are allowed. - gFuncVars = gIsEvalCompile ? &gEvalFuncVars : NULL; + gFuncVars = gIsEvalCompile ? &gEvalFuncVars : &gGlobalScopeFuncVars; return ip; } diff --git a/Engine/source/console/codeBlock.cpp b/Engine/source/console/codeBlock.cpp index f03ec25f6..46b40d441 100644 --- a/Engine/source/console/codeBlock.cpp +++ b/Engine/source/console/codeBlock.cpp @@ -38,6 +38,7 @@ CodeBlock * CodeBlock::smCurrentCodeBlock = NULL; ConsoleParser *CodeBlock::smCurrentParser = NULL; extern FuncVars gEvalFuncVars; +extern FuncVars gGlobalScopeFuncVars; extern FuncVars* gFuncVars; //------------------------------------------------------------------------- @@ -637,8 +638,7 @@ ConsoleValue CodeBlock::compileExec(StringTableEntry fileName, const char *inStr // 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; + gFuncVars = gIsEvalCompile ? &gEvalFuncVars : &gGlobalScopeFuncVars; // Set up the parser. smCurrentParser = getParserForFile(fileName); @@ -678,7 +678,7 @@ ConsoleValue CodeBlock::compileExec(StringTableEntry fileName, const char *inStr codeStream.emit(OP_RETURN_VOID); codeStream.emitCodeStream(&codeSize, &code, &lineBreakPairs); - S32 localRegisterCount = gIsEvalCompile ? gEvalFuncVars.count() : 0; + S32 localRegisterCount = gIsEvalCompile ? gEvalFuncVars.count() : gGlobalScopeFuncVars.count(); consoleAllocReset(); diff --git a/Engine/source/console/compiledEval.cpp b/Engine/source/console/compiledEval.cpp index e9862c7ee..126cf4b01 100644 --- a/Engine/source/console/compiledEval.cpp +++ b/Engine/source/console/compiledEval.cpp @@ -691,7 +691,8 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa setFrame = -1; // Do we want this code to execute using a new stack frame? - if (setFrame < 0) + // compiling a file will force setFrame to 0, forcing us to get a new frame. + if (setFrame <= 0) { // argc is the local count for eval gEvalState.pushFrame(NULL, NULL, argc); diff --git a/Engine/source/console/compiler.cpp b/Engine/source/console/compiler.cpp index 13839feda..f898b8984 100644 --- a/Engine/source/console/compiler.cpp +++ b/Engine/source/console/compiler.cpp @@ -35,6 +35,13 @@ #include "console/simBase.h" extern FuncVars gEvalFuncVars; +extern FuncVars gGlobalScopeFuncVars; +extern FuncVars *gFuncVars; + +namespace Con +{ +extern bool scriptWarningsAsAsserts; +}; namespace Compiler { @@ -124,12 +131,24 @@ namespace Compiler getFunctionStringTable().reset(); getIdentTable().reset(); getFunctionVariableMappingTable().reset(); - gEvalFuncVars.clear(); + gGlobalScopeFuncVars.clear(); + gFuncVars = gIsEvalCompile ? &gEvalFuncVars : &gGlobalScopeFuncVars; } void *consoleAlloc(U32 size) { return gConsoleAllocator.alloc(size); } void consoleAllocReset() { gConsoleAllocator.freeBlocks(); } + void scriptErrorHandler(const char* str) + { + if (Con::scriptWarningsAsAsserts) + { + AssertISV(false, str); + } + else + { + Con::warnf(ConsoleLogEntry::Type::Script, "%s", str); + } + } } //------------------------------------------------------------------------- @@ -141,7 +160,11 @@ S32 FuncVars::assign(StringTableEntry var, TypeReq currentType, S32 lineNumber, 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)); + if (found->second.isConstant) + { + const char* str = avar("Script Warning: Reassigning variable %s when it is a constant. File: %s Line : %d", var, CodeBlock::smCurrentParser->getCurrentFile(), lineNumber); + scriptErrorHandler(str); + } return found->second.reg; } @@ -155,7 +178,15 @@ S32 FuncVars::assign(StringTableEntry var, TypeReq currentType, S32 lineNumber, 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)); + + if (found == vars.end()) + { + const char* str = avar("Script Warning: Variable %s referenced before used when compiling script. File: %s Line: %d", var, CodeBlock::smCurrentParser->getCurrentFile(), lineNumber); + scriptErrorHandler(str); + + return assign(var, TypeReqString, lineNumber, false); + } + return found->second.reg; } @@ -163,7 +194,15 @@ 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)); + if (found == vars.end()) + { + const char* str = avar("Script Warning: Variable %s referenced before used when compiling script. File: %s Line: %d", var, CodeBlock::smCurrentParser->getCurrentFile(), lineNumber); + scriptErrorHandler(str); + + assign(var, TypeReqString, lineNumber, false); + return vars.find(var)->second.currentType; + } + return found->second.currentType; } diff --git a/Engine/source/console/compiler.h b/Engine/source/console/compiler.h index 24067257f..612923939 100644 --- a/Engine/source/console/compiler.h +++ b/Engine/source/console/compiler.h @@ -275,6 +275,8 @@ namespace Compiler void *consoleAlloc(U32 size); void consoleAllocReset(); + void scriptErrorHandler(const char* str); + extern bool gSyntaxError; extern bool gIsEvalCompile; }; diff --git a/Engine/source/console/console.cpp b/Engine/source/console/console.cpp index 14e75f0f8..59fca1874 100644 --- a/Engine/source/console/console.cpp +++ b/Engine/source/console/console.cpp @@ -274,6 +274,7 @@ static Vector< String > sInstantGroupStack( __FILE__, __LINE__ ); static DataChunker consoleLogChunker; static Vector consoleLog(__FILE__, __LINE__); static bool consoleLogLocked; +bool scriptWarningsAsAsserts = true; static bool logBufferEnabled=true; static S32 printLevel = 10; static FileStream consoleLogFile; @@ -353,7 +354,7 @@ void init() ConsoleConstructor::setup(); // Set up the parser(s) - CON_ADD_PARSER(CMD, TORQUE_SCRIPT_EXTENSION, true); // TorqueScript + CON_ADD_PARSER(CMD, (char*)TORQUE_SCRIPT_EXTENSION, true); // TorqueScript // Setup the console types. ConsoleBaseType::initialize(); @@ -377,6 +378,7 @@ void init() addVariable("Con::objectCopyFailures", TypeS32, &gObjectCopyFailures, "If greater than zero then it counts the number of object creation " "failures based on a missing copy object and does not report an error..\n" "@ingroup Console\n"); + addVariable("Con::scriptWarningsAsAsserts", TypeBool, &scriptWarningsAsAsserts, "If true, script warnings (outside of syntax errors) will be treated as fatal asserts."); // Current script file name and root addVariable( "Con::File", TypeString, &gCurrentFile, "The currently executing script file.\n"