From d6a3937107a64d088f8361027b97dbf63bb6c0c1 Mon Sep 17 00:00:00 2001 From: Sandu Liviu Catalin Date: Sun, 16 Jun 2019 02:12:51 +0300 Subject: [PATCH] Include code line in debug. Includes the line of code that causes a syntax error. Few other minor fixes. --- bin/sqmod.ini | 2 + source/Base/ScriptSrc.cpp | 32 ++++++++++------ source/Base/ScriptSrc.hpp | 2 +- source/Core.cpp | 78 ++++++++++++++++++++++++++++++++++----- source/Core.hpp | 27 ++++++++++++++ 5 files changed, 119 insertions(+), 22 deletions(-) diff --git a/bin/sqmod.ini b/bin/sqmod.ini index 61627de9..b890acce 100644 --- a/bin/sqmod.ini +++ b/bin/sqmod.ini @@ -6,6 +6,8 @@ StackSize=2048 ErrorHandling=true # Allow the plug-in to load even if no scripts were loaded EmptyInit=false +# Include code in debug information +Debugging=true # Logging options [Log] diff --git a/source/Base/ScriptSrc.cpp b/source/Base/ScriptSrc.cpp index 0e0ad54f..1e55edf5 100644 --- a/source/Base/ScriptSrc.cpp +++ b/source/Base/ScriptSrc.cpp @@ -87,43 +87,51 @@ void ScriptSrc::Process() FileHandle fp(mPath.c_str()); // First 2 bytes of the file will tell if this is a compiled script std::uint16_t tag; - // Read the first 2 bytes of the file and determine the file type - if (std::fread(&tag, 1, 2, fp) != 2 || tag == SQ_BYTECODE_STREAM_TAG) - { - return; // Probably an empty file or compiled script - } // Go to the end of the file std::fseek(fp, 0, SEEK_END); // Calculate buffer size from beginning to current position const LongI length = std::ftell(fp); // Go back to the beginning std::fseek(fp, 0, SEEK_SET); + // Read the first 2 bytes of the file and determine the file type + if ((length >= 2) && (std::fread(&tag, 1, 2, fp) != 2 || tag == SQ_BYTECODE_STREAM_TAG)) + { + return; // Probably an empty file or compiled script + } // Allocate enough space to hold the file data mData.resize(length, 0); // Read the file contents into allocated data std::fread(&mData[0], 1, length, fp); // Where the last line ended - unsigned line = 0; + size_t line_start = 0, line_end = 0; // Process the file data and locate new lines for (String::const_iterator itr = mData.cbegin(); itr != mData.cend();) { // Is this a Unix style line ending? if (*itr == '\n') { + // Extract the line length + line_end = std::distance(mData.cbegin(), itr); // Store the beginning of the line - mLine.push_back(line); + mLine.emplace_back(line_start, line_end); // Advance to the next line - line = std::distance(mData.cbegin(), ++itr); + line_start = line_end+1; + // The line end character was not included + ++itr; } // Is this a Windows style line ending? else if (*itr == '\r') { if (*(++itr) == '\n') { + // Extract the line length + line_end = std::distance(mData.cbegin(), itr)-1; // Store the beginning of the line - mLine.push_back(line); + mLine.emplace_back(line_start, line_end); // Advance to the next line - line = std::distance(mData.cbegin(), ++itr); + line_start = line_end+2; + // The line end character was not included + ++itr; } } else @@ -132,9 +140,9 @@ void ScriptSrc::Process() } } // Should we add the last line as well? - if (line) + if (mData.size() - line_start > 0) { - mLine.push_back(line); + mLine.emplace_back(line_start, mData.size()); } // Specify that this script contains line information mInfo = true; diff --git a/source/Base/ScriptSrc.hpp b/source/Base/ScriptSrc.hpp index 0fd7d592..5b45529b 100644 --- a/source/Base/ScriptSrc.hpp +++ b/source/Base/ScriptSrc.hpp @@ -22,7 +22,7 @@ class ScriptSrc public: // -------------------------------------------------------------------------------------------- - typedef std::vector< Uint32 > Line; + typedef std::vector< std::pair< Uint32, Uint32 > > Line; // -------------------------------------------------------------------------------------------- Script mExec; // Reference to the script object. diff --git a/source/Core.cpp b/source/Core.cpp index 8d44c40b..f1aac5b9 100644 --- a/source/Core.cpp +++ b/source/Core.cpp @@ -51,8 +51,6 @@ extern void TerminateTasks(); extern void TerminateRoutines(); extern void TerminateCommands(); extern void TerminateSignals(); -extern void MgInitialize(); -extern void MgTerminate(); // ------------------------------------------------------------------------------------------------ extern Buffer GetRealFilePath(CSStr path); @@ -275,7 +273,7 @@ bool Core::Initialize() // Configure error handling ErrorHandling::Enable(conf.GetBoolValue("Squirrel", "ErrorHandling", true)); // See if debugging options should be enabled - m_Debugging = conf.GetBoolValue("Squirrel", "Debugging", false); + m_Debugging = conf.GetBoolValue("Squirrel", "Debugging", m_Debugging); // Prevent common null objects from using dead virtual machines NullArray() = Array(); @@ -374,9 +372,6 @@ bool Core::Initialize() InitializeRoutines(); InitializeTasks(); - // Initialize the Mongoose library - //MgInitialize(); - // Initialization successful return true; } @@ -541,8 +536,6 @@ void Core::Terminate(bool shutdown) // Tell modules to do their monkey business _Func->SendPluginCommand(SQMOD_RELEASED_CMD, ""); } - // Terminate the Mongoose manager - //MgTerminate(); OutputMessage("Squirrel plug-in was successfully terminated"); } @@ -594,6 +587,38 @@ void Core::SetOption(CSStr name, CSStr value) m_Options[name] = value; } +// ------------------------------------------------------------------------------------------------ +Core::Scripts::iterator Core::FindScript(const CSStr src) +{ + // Iterate over loaded scripts + for (Scripts::iterator itr = m_Scripts.begin(); itr != m_Scripts.end(); ++itr) + { + // Is this script the source we're looking for? + if (itr->mPath.compare(0, String::npos, src) == 0) + { + return itr; + } + } + // Not found! + return m_Scripts.end(); +} + +// ------------------------------------------------------------------------------------------------ +Core::Scripts::iterator Core::FindPendingScript(const CSStr src) +{ + // Iterate over loaded scripts + for (Scripts::iterator itr = m_PendingScripts.begin(); itr != m_PendingScripts.end(); ++itr) + { + // Is this script the source we're looking for? + if (itr->mPath.compare(0, String::npos, src) == 0) + { + return itr; + } + } + // Not found! + return m_PendingScripts.end(); +} + // ------------------------------------------------------------------------------------------------ bool Core::LoadScript(CSStr filepath, bool delay) { @@ -852,7 +877,42 @@ SQInteger Core::RuntimeErrorHandler(HSQUIRRELVM vm) // ------------------------------------------------------------------------------------------------ void Core::CompilerErrorHandler(HSQUIRRELVM /*vm*/, CSStr desc, CSStr src, SQInteger line, SQInteger column) { - LogFtl("Message: %s\n[\n=>Location: %s\n=>Line: %" PRINT_INT_FMT "\n=>Column: %" PRINT_INT_FMT "\n]", desc, src, line, column); + // Should we include code in output? (we count lines from 0, squirrel counts from 1) + if ((line <= 0) || !Core::Get().IsDebugging() || !Core::Get().CompilerErrorHandlerEx(desc, src, --line, column)) { + LogFtl("Message: %s\n[\n=>Location: %s\n=>Line: %" PRINT_INT_FMT "\n=>Column: %" PRINT_INT_FMT "\n]", desc, src, line, column); + } +} + +// ------------------------------------------------------------------------------------------------ +bool Core::CompilerErrorHandlerEx(CSStr desc, CSStr src, SQInteger line, SQInteger column) +{ + // Find the script we're looking for + Scripts::iterator script = FindScript(src); + // Found anything? + if (script == m_Scripts.end()) + { + return false; // No such script! + } + // Have debug information? + else if (!(script->mInfo)) + { + return false; // Nothing to show! + } + // Is this line outside the range that we have? + else if (script->mLine.size() < line) + { + return false; // No such line! + } + // Grab the line we're looking for + ScriptSrc::Line::iterator itr = script->mLine.begin() + line; + // Grab the code from that line + String code = script->mData.substr(itr->first, itr->second - itr->first); + // Trim whitespace from the beginning of the code code + code.erase(0, code.find_first_not_of(" \t\n\r\f\v")); + // Display the error message with the code included + LogFtl("Message: %s\n[\n=>Location: %s\n=>Line: %" PRINT_SZ_FMT "\n=>Column: %" PRINT_INT_FMT "\n=>Code: %s\n]", desc, src, ++line, column, code.c_str()); + // We displayed the information + return true; } } // Namespace:: SqMod diff --git a/source/Core.hpp b/source/Core.hpp index 38b968af..90efc180 100644 --- a/source/Core.hpp +++ b/source/Core.hpp @@ -831,6 +831,32 @@ public: */ void SetOption(CSStr name, CSStr value); + /* -------------------------------------------------------------------------------------------- + * Retrieve the script source associated with a certain path in the scripts list. + */ + Scripts::iterator FindScript(const CSStr src); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the script source associated with a certain path in the pending scripts list. + */ + Scripts::iterator FindPendingScript(const CSStr src); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the scripts list. Should not be modified directly! Information purposes only. + */ + Scripts & GetScripts() + { + return m_Scripts; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the pending scripts list. Should not be modified directly! Information purposes only. + */ + Scripts & GetPendingScripts() + { + return m_PendingScripts; + } + /* -------------------------------------------------------------------------------------------- * Retrieve the virtual machine. */ @@ -958,6 +984,7 @@ protected: static SQInteger RuntimeErrorHandler(HSQUIRRELVM vm); static void CompilerErrorHandler(HSQUIRRELVM vm, CSStr desc, CSStr src, SQInteger line, SQInteger column); + bool CompilerErrorHandlerEx(CSStr desc, CSStr src, SQInteger line, SQInteger column); /* -------------------------------------------------------------------------------------------- * Entity scanners.