Browse Source

Optionally allow to treat script assert as warning

This commit allows us to treat variable use before assign errors and local variables inside of the global scope as warnings instead of asserts. This will allow for easier porting of legacy scripts. It is highly recommended use this as an aid to port scripts, but can be used in production if needbe.
Jeff Hutchinson 3 years ago
parent
commit
2e03108856

+ 7 - 3
Engine/source/console/astNodes.cpp

@@ -57,11 +57,16 @@ namespace Compiler
 using namespace Compiler;
 using namespace Compiler;
 
 
 FuncVars gEvalFuncVars;
 FuncVars gEvalFuncVars;
+FuncVars gGlobalScopeFuncVars;
 FuncVars* gFuncVars = NULL;
 FuncVars* gFuncVars = NULL;
 
 
 inline FuncVars* getFuncVars(S32 lineNumber)
 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;
    return gFuncVars;
 }
 }
 
 
@@ -1552,8 +1557,7 @@ U32 FunctionDeclStmtNode::compileStmt(CodeStream& codeStream, U32 ip)
       tbl->add(fnName, nameSpace, varName);
       tbl->add(fnName, nameSpace, varName);
    }
    }
 
 
-   // In eval mode, global func vars are allowed.
-   gFuncVars = gIsEvalCompile ? &gEvalFuncVars : NULL;
+   gFuncVars = gIsEvalCompile ? &gEvalFuncVars : &gGlobalScopeFuncVars;
 
 
    return ip;
    return ip;
 }
 }

+ 3 - 3
Engine/source/console/codeBlock.cpp

@@ -38,6 +38,7 @@ CodeBlock *    CodeBlock::smCurrentCodeBlock = NULL;
 ConsoleParser *CodeBlock::smCurrentParser = NULL;
 ConsoleParser *CodeBlock::smCurrentParser = NULL;
 
 
 extern FuncVars gEvalFuncVars;
 extern FuncVars gEvalFuncVars;
+extern FuncVars gGlobalScopeFuncVars;
 extern FuncVars* gFuncVars;
 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)
    // we are an eval compile if we don't have a file name associated (no exec)
    gIsEvalCompile = fileName == NULL;
    gIsEvalCompile = fileName == NULL;
-   // In eval mode, global func vars are allowed.
-   gFuncVars = gIsEvalCompile ? &gEvalFuncVars : NULL;
+   gFuncVars = gIsEvalCompile ? &gEvalFuncVars : &gGlobalScopeFuncVars;
 
 
    // Set up the parser.
    // Set up the parser.
    smCurrentParser = getParserForFile(fileName);
    smCurrentParser = getParserForFile(fileName);
@@ -678,7 +678,7 @@ ConsoleValue CodeBlock::compileExec(StringTableEntry fileName, const char *inStr
    codeStream.emit(OP_RETURN_VOID);
    codeStream.emit(OP_RETURN_VOID);
    codeStream.emitCodeStream(&codeSize, &code, &lineBreakPairs);
    codeStream.emitCodeStream(&codeSize, &code, &lineBreakPairs);
    
    
-   S32 localRegisterCount = gIsEvalCompile ? gEvalFuncVars.count() : 0;
+   S32 localRegisterCount = gIsEvalCompile ? gEvalFuncVars.count() : gGlobalScopeFuncVars.count();
 
 
    consoleAllocReset();
    consoleAllocReset();
 
 

+ 2 - 1
Engine/source/console/compiledEval.cpp

@@ -691,7 +691,8 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          setFrame = -1;
          setFrame = -1;
 
 
       // Do we want this code to execute using a new stack frame?
       // 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
          // argc is the local count for eval
          gEvalState.pushFrame(NULL, NULL, argc);
          gEvalState.pushFrame(NULL, NULL, argc);

+ 43 - 4
Engine/source/console/compiler.cpp

@@ -35,6 +35,13 @@
 #include "console/simBase.h"
 #include "console/simBase.h"
 
 
 extern FuncVars gEvalFuncVars;
 extern FuncVars gEvalFuncVars;
+extern FuncVars gGlobalScopeFuncVars;
+extern FuncVars *gFuncVars;
+
+namespace Con
+{
+extern bool scriptWarningsAsAsserts;
+};
 
 
 namespace Compiler
 namespace Compiler
 {
 {
@@ -124,12 +131,24 @@ namespace Compiler
       getFunctionStringTable().reset();
       getFunctionStringTable().reset();
       getIdentTable().reset();
       getIdentTable().reset();
       getFunctionVariableMappingTable().reset();
       getFunctionVariableMappingTable().reset();
-      gEvalFuncVars.clear();
+      gGlobalScopeFuncVars.clear();
+      gFuncVars = gIsEvalCompile ? &gEvalFuncVars : &gGlobalScopeFuncVars;
    }
    }
 
 
    void *consoleAlloc(U32 size) { return gConsoleAllocator.alloc(size); }
    void *consoleAlloc(U32 size) { return gConsoleAllocator.alloc(size); }
    void consoleAllocReset() { gConsoleAllocator.freeBlocks(); }
    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<StringTableEntry, Var>::iterator found = vars.find(var);
    std::unordered_map<StringTableEntry, Var>::iterator found = vars.find(var);
    if (found != vars.end())
    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;
       return found->second.reg;
    }
    }
 
 
@@ -155,7 +178,15 @@ S32 FuncVars::assign(StringTableEntry var, TypeReq currentType, S32 lineNumber,
 S32 FuncVars::lookup(StringTableEntry var, S32 lineNumber)
 S32 FuncVars::lookup(StringTableEntry var, S32 lineNumber)
 {
 {
    std::unordered_map<StringTableEntry, Var>::iterator found = vars.find(var);
    std::unordered_map<StringTableEntry, Var>::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;
    return found->second.reg;
 }
 }
 
 
@@ -163,7 +194,15 @@ TypeReq FuncVars::lookupType(StringTableEntry var, S32 lineNumber)
 {
 {
    std::unordered_map<StringTableEntry, Var>::iterator found = vars.find(var);
    std::unordered_map<StringTableEntry, Var>::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;
    return found->second.currentType;
 }
 }
 
 

+ 2 - 0
Engine/source/console/compiler.h

@@ -275,6 +275,8 @@ namespace Compiler
    void *consoleAlloc(U32 size);
    void *consoleAlloc(U32 size);
    void consoleAllocReset();
    void consoleAllocReset();
 
 
+   void scriptErrorHandler(const char* str);
+
    extern bool gSyntaxError;
    extern bool gSyntaxError;
    extern bool gIsEvalCompile;
    extern bool gIsEvalCompile;
 };
 };

+ 3 - 1
Engine/source/console/console.cpp

@@ -274,6 +274,7 @@ static Vector< String > sInstantGroupStack( __FILE__, __LINE__ );
 static DataChunker consoleLogChunker;
 static DataChunker consoleLogChunker;
 static Vector<ConsoleLogEntry> consoleLog(__FILE__, __LINE__);
 static Vector<ConsoleLogEntry> consoleLog(__FILE__, __LINE__);
 static bool consoleLogLocked;
 static bool consoleLogLocked;
+bool scriptWarningsAsAsserts = true;
 static bool logBufferEnabled=true;
 static bool logBufferEnabled=true;
 static S32 printLevel = 10;
 static S32 printLevel = 10;
 static FileStream consoleLogFile;
 static FileStream consoleLogFile;
@@ -353,7 +354,7 @@ void init()
    ConsoleConstructor::setup();
    ConsoleConstructor::setup();
 
 
    // Set up the parser(s)
    // 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.
    // Setup the console types.
    ConsoleBaseType::initialize();
    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 "
    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"
       "failures based on a missing copy object and does not report an error..\n"
       "@ingroup Console\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
    // Current script file name and root
    addVariable( "Con::File", TypeString, &gCurrentFile, "The currently executing script file.\n"
    addVariable( "Con::File", TypeString, &gCurrentFile, "The currently executing script file.\n"