diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp index c781bfa4619..4e7910f7cc9 100644 --- a/engines/ags/engine/ac/draw.cpp +++ b/engines/ags/engine/ac/draw.cpp @@ -1675,7 +1675,7 @@ void prepare_room_sprites() { if (_G(walkBehindMethod) == DrawAsSeparateSprite) { for (int wb = 1 /* 0 is "no area" */; - (wb < MAX_WALK_BEHINDS) && (wb < _GP(walkbehindobj).size()); ++wb) { + (wb < MAX_WALK_BEHINDS) && (wb < (int)_GP(walkbehindobj).size()); ++wb) { const auto &wbobj = _GP(walkbehindobj)[wb]; if (wbobj.Ddb) { add_to_sprite_list(wbobj.Ddb, wbobj.Pos.X, wbobj.Pos.Y, diff --git a/engines/ags/engine/debugging/debug.cpp b/engines/ags/engine/debugging/debug.cpp index 9b9076ac584..3b0644d8c32 100644 --- a/engines/ags/engine/debugging/debug.cpp +++ b/engines/ags/engine/debugging/debug.cpp @@ -315,24 +315,13 @@ void debug_script_log(const char *msg, ...) { debug_script_print_impl(full_msg, kDbgMsg_Debug); } - -String get_cur_script(int numberOfLinesOfCallStack) { - String callstack; - ccInstance *sci = ccInstance::GetCurrentInstance(); - if (sci) - callstack = sci->GetCallStack(numberOfLinesOfCallStack); - if (callstack.IsEmpty()) - callstack = cc_get_error().CallStack; - return callstack; -} - struct Breakpoint { char scriptName[80]; int lineNumber; }; bool send_message_to_editor(const char *msg, const char *errorMsg) { - String callStack = get_cur_script(25); + String callStack = cc_get_error().CallStack; if (callStack.IsEmpty()) return false; diff --git a/engines/ags/engine/debugging/debugger.h b/engines/ags/engine/debugging/debugger.h index 0929797b366..60ad55026e8 100644 --- a/engines/ags/engine/debugging/debugger.h +++ b/engines/ags/engine/debugging/debugger.h @@ -32,8 +32,6 @@ struct ScriptPosition; int check_for_messages_from_editor(); bool send_message_to_editor(const char *msg); bool send_exception_to_editor(const char *qmsg); -// Returns current script's location and callstack -AGS::Shared::String get_cur_script(int numberOfLinesOfCallStack); void check_debug_keys(); #define DBG_NOIFACE 1 diff --git a/engines/ags/engine/main/quit.cpp b/engines/ags/engine/main/quit.cpp index ae73e19bd00..77a8413ad45 100644 --- a/engines/ags/engine/main/quit.cpp +++ b/engines/ags/engine/main/quit.cpp @@ -48,6 +48,7 @@ #include "ags/engine/platform/base/ags_platform_driver.h" #include "ags/engine/platform/base/sys_main.h" #include "ags/plugins/plugin_engine.h" +#include "ags/shared/script/cc_common.h" #include "ags/engine/media/audio/audio_system.h" #include "ags/globals.h" #include "ags/ags.h" @@ -114,7 +115,7 @@ QuitReason quit_check_for_error_state(const char *&qmsg, String &alertis) { "(ACI version %s)\n\n", _G(EngineVersion).LongString.GetCStr()); } - alertis.Append(get_cur_script(5)); + alertis.Append(cc_get_error().CallStack); if (qreason != kQuit_UserAbort) alertis.Append("\nError: "); @@ -125,7 +126,7 @@ QuitReason quit_check_for_error_state(const char *&qmsg, String &alertis) { qmsg++; alertis.Format("A warning has been generated. This is not normally fatal, but you have selected " "to treat warnings as errors.\n" - "(ACI version %s)\n\n%s\n", _G(EngineVersion).LongString.GetCStr(), get_cur_script(5).GetCStr()); + "(ACI version %s)\n\n%s\n", _G(EngineVersion).LongString.GetCStr(), cc_get_error().CallStack.GetCStr()); return kQuit_GameWarning; } else { alertis.Format("An internal error has occurred. Please note down the following information.\n" diff --git a/engines/ags/engine/script/cc_instance.cpp b/engines/ags/engine/script/cc_instance.cpp index d80377b54e5..3a0217bca5e 100644 --- a/engines/ags/engine/script/cc_instance.cpp +++ b/engines/ags/engine/script/cc_instance.cpp @@ -157,6 +157,18 @@ const char *regnames[] = { "null", "sp", "mar", "ax", "bx", "cx", "op", "dx" }; const char *fixupnames[] = { "null", "fix_gldata", "fix_func", "fix_string", "fix_import", "fix_datadata", "fix_stack" }; +String cc_get_callstack(int max_lines) { + String callstack; + for (auto sci = _GP(InstThreads).crbegin(); sci != _GP(InstThreads).crend(); ++sci) { + if (callstack.IsEmpty()) + callstack.Append("in the active script:\n"); + else + callstack.Append("in the waiting script:\n"); + callstack.Append((*sci)->GetCallStack(max_lines)); + } + return callstack; +} + // Function call stack is used to temporarily store // values before passing them to script function #define MAX_FUNC_PARAMS 20 @@ -181,7 +193,7 @@ struct FunctionCallStack { ccInstance *ccInstance::GetCurrentInstance() { - return _GP(InstThreads).size() > 0 ? _GP(InstThreads).top() : nullptr; + return _GP(InstThreads).size() > 0 ? _GP(InstThreads).back() : nullptr; } ccInstance *ccInstance::CreateFromScript(PScript scri) { @@ -335,14 +347,14 @@ int ccInstance::CallScriptFunction(const char *funcname, int32_t numargs, const } PushValueToStack(RuntimeScriptValue().SetInt32(0)); // return address on stack - _GP(InstThreads).push(this); // push instance thread + _GP(InstThreads).push_back(this); // push instance thread runningInst = this; int reterr = Run(startat); // Cleanup before returning, even if error ASSERT_STACK_SIZE(numargs); PopValuesFromStack(numargs); pc = 0; - _GP(InstThreads).pop(); // pop instance thread + _GP(InstThreads).pop_back(); // pop instance thread if (reterr != 0) return reterr; @@ -1198,7 +1210,7 @@ int ccInstance::Run(int32_t curpc) { } } -String ccInstance::GetCallStack(int maxLines) { +String ccInstance::GetCallStack(int maxLines) const { String buffer = String::FromFormat("in \"%s\", line %d\n", runningInst->instanceof->GetSectionName(pc), line_number); int linesDone = 0; @@ -1212,13 +1224,13 @@ String ccInstance::GetCallStack(int maxLines) { return buffer; } -void ccInstance::GetScriptPosition(ScriptPosition &script_pos) { +void ccInstance::GetScriptPosition(ScriptPosition &script_pos) const { script_pos.Section = runningInst->instanceof->GetSectionName(pc); script_pos.Line = line_number; } // get a pointer to a variable or function exported by the script -RuntimeScriptValue ccInstance::GetSymbolAddress(const char *symname) { +RuntimeScriptValue ccInstance::GetSymbolAddress(const char *symname) const { int k; char altName[200]; snprintf(altName, sizeof(altName), "%s$", symname); @@ -1234,7 +1246,7 @@ RuntimeScriptValue ccInstance::GetSymbolAddress(const char *symname) { return rval_null; } -void ccInstance::DumpInstruction(const ScriptOperation &op) { +void ccInstance::DumpInstruction(const ScriptOperation &op) const { // line_num local var should be shared between all the instances static int line_num = 0; diff --git a/engines/ags/engine/script/cc_instance.h b/engines/ags/engine/script/cc_instance.h index 423bef9f738..3895d68ed14 100644 --- a/engines/ags/engine/script/cc_instance.h +++ b/engines/ags/engine/script/cc_instance.h @@ -159,12 +159,12 @@ public: int CallScriptFunction(const char *funcname, int32_t num_params, const RuntimeScriptValue *params); // Get the script's execution position and callstack as human-readable text - Shared::String GetCallStack(int maxLines); + Shared::String GetCallStack(int max_lines = INT_MAX) const; // Get the script's execution position - void GetScriptPosition(ScriptPosition &script_pos); + void GetScriptPosition(ScriptPosition &script_pos) const; // Get the address of an exported symbol (function or variable) in the script - RuntimeScriptValue GetSymbolAddress(const char *symname); - void DumpInstruction(const ScriptOperation &op); + RuntimeScriptValue GetSymbolAddress(const char *symname) const; + void DumpInstruction(const ScriptOperation &op) const; // Tells whether this instance is in the process of executing the byte-code bool IsBeingRun() const; diff --git a/engines/ags/engine/script/script.cpp b/engines/ags/engine/script/script.cpp index 3a89de31303..19d190e4f8e 100644 --- a/engines/ags/engine/script/script.cpp +++ b/engines/ags/engine/script/script.cpp @@ -564,7 +564,7 @@ void quit_with_script_error(const char *functionName) { quitprintf("!Error running function '%s':\n%s", functionName, error.ErrorString.GetCStr()); else quitprintf("Error running function '%s':\n%s\n\n%s", functionName, - error.ErrorString.GetCStr(), get_cur_script(5).GetCStr()); + error.ErrorString.GetCStr(), error.CallStack.GetCStr()); } int get_nivalue(InteractionCommandList *nic, int idx, int parm) { diff --git a/engines/ags/engine/script/script_engine.cpp b/engines/ags/engine/script/script_engine.cpp deleted file mode 100644 index 92478a37643..00000000000 --- a/engines/ags/engine/script/script_engine.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -//============================================================================= -// -// Script Editor run-time engine component (c) 1998 Chris Jones -// script chunk format: -// 00h 1 dword version - should be 2 -// 04h 1 dword sizeof(scriptblock) -// 08h 1 dword number of ScriptBlocks -// 0Ch n STRUCTs ScriptBlocks -// -//============================================================================= - -#include "ags/lib/std/utility.h" -#include "ags/engine/script/cc_instance.h" -#include "ags/shared/script/cc_common.h" -#include "ags/shared/util/file.h" -#include "ags/shared/util/stream.h" -#include "ags/globals.h" - -namespace AGS3 { - -namespace AGS { -namespace Shared { -class RoomStruct; -} // namespace Shared -} // namespace AGS - -using namespace AGS::Shared; - -std::pair cc_error_at_line(const char *error_msg) { - ccInstance *sci = ccInstance::GetCurrentInstance(); - if (!sci) { - return std::make_pair(String::FromFormat("Error (line %d): %s", _G(currentline), error_msg), String()); - } else { - return std::make_pair(String::FromFormat("Error: %s\n", error_msg), ccInstance::GetCurrentInstance()->GetCallStack(5)); - } -} - -String cc_error_without_line(const char *error_msg) { - return String::FromFormat("Runtime error: %s", error_msg); -} - -} // namespace AGS3 diff --git a/engines/ags/globals.cpp b/engines/ags/globals.cpp index cee427f6d65..8c835dc464f 100644 --- a/engines/ags/globals.cpp +++ b/engines/ags/globals.cpp @@ -129,7 +129,7 @@ Globals::Globals() { _animbuts = new std::vector(); // cc_instance.cpp globals - _InstThreads = new std::stack(); + _InstThreads = new std::deque(); _GlobalReturnValue = new RuntimeScriptValue(); // cc_options.cpp globals diff --git a/engines/ags/globals.h b/engines/ags/globals.h index a5aa0b1ee7a..a3f5a7082f5 100644 --- a/engines/ags/globals.h +++ b/engines/ags/globals.h @@ -25,7 +25,7 @@ #include "ags/shared/core/platform.h" #define AGS_PLATFORM_DEFINES_PSP_VARS (AGS_PLATFORM_OS_IOS || AGS_PLATFORM_OS_ANDROID) -#include "ags/lib/std/stack.h" +#include "ags/lib/std/queue.h" #include "ags/shared/ac/game_version.h" #include "ags/shared/util/stdio_compat.h" #include "ags/shared/util/string.h" @@ -369,7 +369,7 @@ public: // In AGS currently only one thread is running, others are waiting in the queue. // An example situation is repeatedly_execute_always callback running while // another instance is waiting at the blocking action or Wait(). - std::stack *_InstThreads; + std::deque *_InstThreads; // [IKM] 2012-10-21: // NOTE: This is temporary solution (*sigh*, one of many) which allows certain // exported functions return value as a RuntimeScriptValue object; diff --git a/engines/ags/lib/std/queue.h b/engines/ags/lib/std/queue.h index ead08567d02..1617c2a5b01 100644 --- a/engines/ags/lib/std/queue.h +++ b/engines/ags/lib/std/queue.h @@ -63,6 +63,80 @@ public: } }; +template +class deque { +private: + vector _intern; +public: + deque() = default; + typedef typename vector::iterator iterator; + typedef typename const vector::const_iterator const_iterator; + typedef typename vector::reverse_iterator reverse_iterator; + typedef typename const vector::const_reverse_iterator const_reverse_iterator; + + void clear() { + _intern.clear(); + } + void insert(const T &item) { + _intern.push_back(item); + } + void push_back(const T &item) { + _intern.push_back(item); + } + void push_front(const T &item) { + _intern.push_front(item); + } + void pop_back() { + _intern.pop_back(); + } + void pop_front() { + _intern.remove_at(0); + } + const T &front() const { + return _intern.front(); + } + const T &back() const { + return _intern.back(); + } + + void resize(size_t newSize) { + _intern.resize(newSize); + } + + size_t size() const { + return _intern.size(); + } + + T at(size_t idx) { + return _intern[idx]; + } + + const_iterator cbegin() { + return _intern.cbegin(); + } + const_iterator cend() { + return _intern.cend(); + } + reverse_iterator rbegin() { + return _intern.rbegin(); + } + reverse_iterator rend() { + return _intern.rend(); + } + const_reverse_iterator rbegin() const { + return _intern.rbegin(); + } + const_reverse_iterator rend() const { + return _intern.rend(); + } + const_reverse_iterator crbegin() const { + return _intern.crbegin(); + } + const_reverse_iterator crend() const { + return _intern.crend(); + } +}; + } // namespace std } // namespace AGS3 diff --git a/engines/ags/module.mk b/engines/ags/module.mk index 50ba7cc75c1..13c73481072 100644 --- a/engines/ags/module.mk +++ b/engines/ags/module.mk @@ -279,7 +279,6 @@ MODULE_OBJS = \ engine/script/runtime_script_value.o \ engine/script/script.o \ engine/script/script_api.o \ - engine/script/script_engine.o \ engine/script/script_runtime.o \ engine/script/system_imports.o \ plugins/ags_plugin.o \ diff --git a/engines/ags/shared/script/cc_common.cpp b/engines/ags/shared/script/cc_common.cpp index 054c8b20a32..3e7dfa97158 100644 --- a/engines/ags/shared/script/cc_common.cpp +++ b/engines/ags/shared/script/cc_common.cpp @@ -42,10 +42,8 @@ int ccGetOption(int optbit) { return 0; } -// Returns full script error message and callstack (if possible) -extern std::pair cc_error_at_line(const char *error_msg); -// Returns script error message without location or callstack -extern String cc_error_without_line(const char *error_msg); +// Returns current running script callstack as a human-readable text +extern String cc_get_callstack(int max_lines = INT_MAX); void cc_clear_error() { _GP(ccError) = ScriptError(); @@ -71,15 +69,12 @@ void cc_error(const char *descr, ...) { String displbuf = String::FromFormatV(descr, ap); va_end(ap); - if (_G(currentline) > 0) { - // [IKM] Implementation is project-specific - std::pair errinfo = cc_error_at_line(displbuf.GetCStr()); - _GP(ccError).ErrorString = errinfo.first; - _GP(ccError).CallStack = errinfo.second; - } else { - _GP(ccError).ErrorString = cc_error_without_line(displbuf.GetCStr()); - _GP(ccError).CallStack = ""; - } + String callstack = cc_get_callstack(); + if ((_G(currentline) > 0) && callstack.IsEmpty()) + _GP(ccError).ErrorString = String::FromFormat("Error (line %d): %s", _G(currentline), displbuf.GetCStr()); + else + _GP(ccError).ErrorString = String::FromFormat("Error: %s", displbuf.GetCStr()); + _GP(ccError).CallStack = callstack; _GP(ccError).HasError = 1; _GP(ccError).Line = _G(currentline);