diff --git a/src/app_console/app_console.cpp b/src/app_console/app_console.cpp index 2d16b60b..7347f130 100644 --- a/src/app_console/app_console.cpp +++ b/src/app_console/app_console.cpp @@ -43,6 +43,7 @@ #include "service_locator.hpp" #include "system_events.hpp" #include "track.hpp" +#include "ui_events.hpp" namespace console { @@ -326,6 +327,25 @@ void RegisterHeaps() { esp_console_cmd_register(&cmd); } +int CmdStacks(int argc, char** argv) { + static const std::pmr::string usage = "usage: stacks"; + if (argc != 1) { + std::cout << usage << std::endl; + return 1; + } + events::Ui().Dispatch(ui::DumpLuaStack{}); + return 0; +} + +void RegisterStacks() { + esp_console_cmd_t cmd{.command = "stacks", + .help = "prints contents of each lua stack", + .hint = NULL, + .func = &CmdStacks, + .argtable = NULL}; + esp_console_cmd_register(&cmd); +} + #if CONFIG_HEAP_TRACING static heap_trace_record_t* sTraceRecords = nullptr; static bool sIsTracking = false; @@ -630,6 +650,7 @@ auto AppConsole::RegisterExtraComponents() -> void { RegisterTasks(); RegisterHeaps(); + RegisterStacks(); #if CONFIG_HEAP_TRACING RegisterAllocs(); diff --git a/src/lua/include/lua_thread.hpp b/src/lua/include/lua_thread.hpp index c85ccb91..d10dba3a 100644 --- a/src/lua/include/lua_thread.hpp +++ b/src/lua/include/lua_thread.hpp @@ -30,6 +30,8 @@ class LuaThread { auto RunScript(const std::string& path) -> bool; auto RunString(const std::string& path) -> bool; + auto DumpStack() -> void; + auto bridge() -> Bridge& { return *bridge_; } auto state() -> lua_State* { return state_; } diff --git a/src/lua/lua_thread.cpp b/src/lua/lua_thread.cpp index dc588144..b94b70ab 100644 --- a/src/lua/lua_thread.cpp +++ b/src/lua/lua_thread.cpp @@ -6,8 +6,11 @@ #include "lua_thread.hpp" +#include #include +#include "lauxlib.h" +#include "lua.h" #include "lua.hpp" #include "font/lv_font_loader.h" @@ -123,6 +126,61 @@ auto LuaThread::RunString(const std::string& script) -> bool { return true; } +auto LuaThread::DumpStack() -> void { + int top = lua_gettop(state_); + std::cout << "stack size: " << top << std::endl; + for (size_t i = 1; i <= top; i++) { + std::cout << "[" << i << "]\t" << luaL_typename(state_, i); + switch (lua_type(state_, i)) { + case LUA_TNUMBER: + std::cout << "\t("; + if (lua_isinteger(state_, i)) { + std::cout << lua_tointeger(state_, i); + } else { + std::cout << lua_tonumber(state_, i); + } + std::cout << ")"; + break; + case LUA_TSTRING: + std::cout << "\t('" << lua_tostring(state_, i) << "')"; + break; + case LUA_TBOOLEAN: + std::cout << "\t(" << lua_toboolean(state_, i) << ")"; + break; + case LUA_TNIL: + // Value is implied. + break; + case LUA_TTABLE: + lua_pushnil(state_); + while (lua_next(state_, i) != 0) { + // Keys + std::cout << std::endl << "\t\t" << luaL_typename(state_, -2); + if (lua_type(state_, -2) == LUA_TSTRING) { + std::cout << "\t(" << lua_tostring(state_, -2) << ")"; + } else if (lua_type(state_, -2) == LUA_TNUMBER) { + std::cout << "\t(" << lua_tonumber(state_, -2) << ")"; + } + + // Values + std::cout << "\t\t" << luaL_typename(state_, -1); + if (lua_type(state_, -1) == LUA_TSTRING) { + std::cout << "\t(" << lua_tostring(state_, -1) << ")"; + } else if (lua_type(state_, -1) == LUA_TNUMBER) { + std::cout << "\t(" << lua_tonumber(state_, -1) << ")"; + } + // Pop the value; we don't care about it. Leave the key on the stack + // for the next call to lua_next. + lua_pop(state_, 1); + } + break; + default: + std::cout << "\t(" << lua_topointer(state_, i) << ")"; + break; + } + std::cout << std::endl; + } +} + static int msg_handler(lua_State* L) { if (!lua_isstring(L, 1)) { return 1; diff --git a/src/lua/property.cpp b/src/lua/property.cpp index 33600ee8..5357ccc5 100644 --- a/src/lua/property.cpp +++ b/src/lua/property.cpp @@ -113,6 +113,9 @@ PropertyBindings::PropertyBindings(lua_State& s) { // Add our binding funcs (get, set, bind) to the metatable. luaL_setfuncs(&s, kPropertyBindingFuncs, 0); + // We've finished setting up the metatable, so pop it. + lua_pop(&s, 1); + // Create a weak table in the registry to hold live bindings. lua_pushstring(&s, kBindingsTable); lua_newtable(&s); // bindings = {} @@ -368,6 +371,7 @@ auto Property::Update(const LuaValue& v) -> void { PushValue(*b.first); // push the argument CallProtected(b.first, 1, 0); // invoke the closure + lua_pop(b.first, 1); // pop the bindings table } } diff --git a/src/ui/include/ui_events.hpp b/src/ui/include/ui_events.hpp index 07b18dea..5c033b0c 100644 --- a/src/ui/include/ui_events.hpp +++ b/src/ui/include/ui_events.hpp @@ -28,6 +28,8 @@ struct OnLuaError : tinyfsm::Event { std::string message; }; +struct DumpLuaStack : tinyfsm::Event {}; + namespace internal { struct ControlSchemeChanged : tinyfsm::Event {}; diff --git a/src/ui/include/ui_fsm.hpp b/src/ui/include/ui_fsm.hpp index 583a00a5..9de1169b 100644 --- a/src/ui/include/ui_fsm.hpp +++ b/src/ui/include/ui_fsm.hpp @@ -51,6 +51,7 @@ class UiState : public tinyfsm::Fsm { void react(const tinyfsm::Event& ev) {} virtual void react(const OnLuaError&) {} + virtual void react(const DumpLuaStack&) {} virtual void react(const internal::BackPressed&) {} virtual void react(const system_fsm::BootComplete&) {} virtual void react(const system_fsm::StorageMounted&) {} @@ -148,6 +149,7 @@ class Lua : public UiState { void exit() override; void react(const OnLuaError&) override; + void react(const DumpLuaStack&) override; void react(const internal::BackPressed&) override; using UiState::react; diff --git a/src/ui/ui_fsm.cpp b/src/ui/ui_fsm.cpp index 7f94abc5..e532e693 100644 --- a/src/ui/ui_fsm.cpp +++ b/src/ui/ui_fsm.cpp @@ -541,6 +541,10 @@ void Lua::react(const OnLuaError& err) { ESP_LOGE("lua", "%s", err.message.c_str()); } +void Lua::react(const DumpLuaStack& ev) { + sLua->DumpStack(); +} + void Lua::react(const internal::BackPressed& ev) { PopLuaScreen(sLua->state()); }