diff options
-rw-r--r-- | src/lane.cpp | 42 | ||||
-rw-r--r-- | src/lane.h | 9 |
2 files changed, 28 insertions, 23 deletions
diff --git a/src/lane.cpp b/src/lane.cpp index d6c9960..10060ad 100644 --- a/src/lane.cpp +++ b/src/lane.cpp | |||
@@ -499,7 +499,7 @@ namespace { | |||
499 | // xxh64 of string "kStackTraceRegKey" generated at https://www.pelock.com/products/hash-calculator | 499 | // xxh64 of string "kStackTraceRegKey" generated at https://www.pelock.com/products/hash-calculator |
500 | static constexpr RegistryUniqueKey kStackTraceRegKey{ 0x3F327747CACAA904ull }; | 500 | static constexpr RegistryUniqueKey kStackTraceRegKey{ 0x3F327747CACAA904ull }; |
501 | 501 | ||
502 | [[nodiscard]] static int lane_error(lua_State* L_) | 502 | int Lane::LuaErrorHandler(lua_State* L_) |
503 | { | 503 | { |
504 | // error message (any type) | 504 | // error message (any type) |
505 | STACK_CHECK_START_ABS(L_, 1); // L_: some_error | 505 | STACK_CHECK_START_ABS(L_, 1); // L_: some_error |
@@ -510,7 +510,7 @@ static constexpr RegistryUniqueKey kStackTraceRegKey{ 0x3F327747CACAA904ull }; | |||
510 | return 1; // just pass on | 510 | return 1; // just pass on |
511 | } | 511 | } |
512 | 512 | ||
513 | STACK_GROW(L_, 3); | 513 | STACK_GROW(L_, 4); // lua_setfield consumes a stack slot, so we have to account for it |
514 | bool const _extended{ kExtendedStackTraceRegKey.readBoolValue(L_) }; | 514 | bool const _extended{ kExtendedStackTraceRegKey.readBoolValue(L_) }; |
515 | STACK_CHECK(L_, 1); | 515 | STACK_CHECK(L_, 1); |
516 | 516 | ||
@@ -537,19 +537,19 @@ static constexpr RegistryUniqueKey kStackTraceRegKey{ 0x3F327747CACAA904ull }; | |||
537 | lua_newtable(L_); // L_: some_error {} {} | 537 | lua_newtable(L_); // L_: some_error {} {} |
538 | 538 | ||
539 | lua_pushstring(L_, _ar.source); // L_: some_error {} {} source | 539 | lua_pushstring(L_, _ar.source); // L_: some_error {} {} source |
540 | lua_setfield(L_, -2, "source"); // L_: some_error {} {} | 540 | luaG_setfield(L_, -2, std::string_view{ "source" }); // L_: some_error {} {} |
541 | 541 | ||
542 | lua_pushinteger(L_, _ar.currentline); // L_: some_error {} {} currentline | 542 | lua_pushinteger(L_, _ar.currentline); // L_: some_error {} {} currentline |
543 | lua_setfield(L_, -2, "currentline"); // L_: some_error {} {} | 543 | luaG_setfield(L_, -2, std::string_view{ "currentline" }); // L_: some_error {} {} |
544 | 544 | ||
545 | lua_pushstring(L_, _ar.name); // L_: some_error {} {} name | 545 | lua_pushstring(L_, _ar.name ? _ar.name : "<?>"); // L_: some_error {} {} name |
546 | lua_setfield(L_, -2, "name"); // L_: some_error {} {} | 546 | luaG_setfield(L_, -2, std::string_view{ "name" }); // L_: some_error {} {} |
547 | 547 | ||
548 | lua_pushstring(L_, _ar.namewhat); // L_: some_error {} {} namewhat | 548 | lua_pushstring(L_, _ar.namewhat); // L_: some_error {} {} namewhat |
549 | lua_setfield(L_, -2, "namewhat"); // L_: some_error {} {} | 549 | luaG_setfield(L_, -2, std::string_view{ "namewhat" }); // L_: some_error {} {} |
550 | 550 | ||
551 | lua_pushstring(L_, _ar.what); // L_: some_error {} {} what | 551 | lua_pushstring(L_, _ar.what); // L_: some_error {} {} what |
552 | lua_setfield(L_, -2, "what"); // L_: some_error {} {} | 552 | luaG_setfield(L_, -2, std::string_view{ "what" }); // L_: some_error {} {} |
553 | } else if (_ar.currentline > 0) { | 553 | } else if (_ar.currentline > 0) { |
554 | luaG_pushstring(L_, "%s:%d", _ar.short_src, _ar.currentline); // L_: some_error {} "blah:blah" | 554 | luaG_pushstring(L_, "%s:%d", _ar.short_src, _ar.currentline); // L_: some_error {} "blah:blah" |
555 | } else { | 555 | } else { |
@@ -630,7 +630,7 @@ static void push_stack_trace(lua_State* L_, Lane::ErrorTraceLevel errorTraceLeve | |||
630 | STACK_GROW(L_, 5); | 630 | STACK_GROW(L_, 5); |
631 | 631 | ||
632 | int const _finalizers_index{ lua_gettop(L_) }; | 632 | int const _finalizers_index{ lua_gettop(L_) }; |
633 | int const _err_handler_index{ (errorTraceLevel_ != Lane::Minimal) ? (lua_pushcfunction(L_, lane_error), lua_gettop(L_)) : 0 }; | 633 | int const _err_handler_index{ (errorTraceLevel_ != Lane::Minimal) ? (lua_pushcfunction(L_, Lane::LuaErrorHandler), lua_gettop(L_)) : 0 }; |
634 | 634 | ||
635 | LuaError _rc{ LuaError::OK }; | 635 | LuaError _rc{ LuaError::OK }; |
636 | for (int _n = static_cast<int>(lua_rawlen(L_, _finalizers_index)); _n > 0; --_n) { | 636 | for (int _n = static_cast<int>(lua_rawlen(L_, _finalizers_index)); _n > 0; --_n) { |
@@ -763,7 +763,7 @@ static void lane_main(Lane* const lane_) | |||
763 | LuaError _rc{ LuaError::ERRRUN }; | 763 | LuaError _rc{ LuaError::ERRRUN }; |
764 | if (lane_->status == Lane::Pending) { // nothing wrong happened during preparation, we can work | 764 | if (lane_->status == Lane::Pending) { // nothing wrong happened during preparation, we can work |
765 | // At this point, the lane function and arguments are on the stack, possibly preceded by the error handler | 765 | // At this point, the lane function and arguments are on the stack, possibly preceded by the error handler |
766 | int const _errorHandlerCount{ lane_->errorTraceLevel == Lane::Minimal ? 0 : 1}; | 766 | int const _errorHandlerCount{ lane_->errorHandlerCount() }; |
767 | int _nargs{ lua_gettop(_L) - 1 - _errorHandlerCount }; | 767 | int _nargs{ lua_gettop(_L) - 1 - _errorHandlerCount }; |
768 | { | 768 | { |
769 | std::unique_lock _guard{ lane_->doneMutex }; | 769 | std::unique_lock _guard{ lane_->doneMutex }; |
@@ -777,7 +777,7 @@ static void lane_main(Lane* const lane_) | |||
777 | // S and L are different: we run as a coroutine in Lua thread L created in state S | 777 | // S and L are different: we run as a coroutine in Lua thread L created in state S |
778 | do { | 778 | do { |
779 | int _nresults{}; | 779 | int _nresults{}; |
780 | _rc = luaG_resume(_L, nullptr, _nargs, &_nresults); // L: eh? retvals|err | 780 | _rc = luaG_resume(_L, nullptr, _nargs, &_nresults); // L: eh? retvals|err... |
781 | if (_rc == LuaError::YIELD) { | 781 | if (_rc == LuaError::YIELD) { |
782 | // change our status to suspended, and wait until someone wants us to resume | 782 | // change our status to suspended, and wait until someone wants us to resume |
783 | std::unique_lock _guard{ lane_->doneMutex }; | 783 | std::unique_lock _guard{ lane_->doneMutex }; |
@@ -794,6 +794,15 @@ static void lane_main(Lane* const lane_) | |||
794 | _nargs = lua_gettop(_L); | 794 | _nargs = lua_gettop(_L); |
795 | } | 795 | } |
796 | } while (_rc == LuaError::YIELD); | 796 | } while (_rc == LuaError::YIELD); |
797 | if (_rc != LuaError::OK) { // : err... | ||
798 | // for some reason, in my tests with Lua 5.4, when the coroutine raises an error, I have 3 copies of it on the stack | ||
799 | // or false + the error message when running Lua 5.1 | ||
800 | // since the rest of our code wants only the error message, let us keep only the latter. | ||
801 | lua_replace(_L, 1); // L: err... | ||
802 | lua_settop(_L, 1); // L: err | ||
803 | // now we build the stack trace table if the error trace level requests it | ||
804 | std::ignore = Lane::LuaErrorHandler(_L); // L: err | ||
805 | } | ||
797 | } | 806 | } |
798 | 807 | ||
799 | if (_errorHandlerCount) { | 808 | if (_errorHandlerCount) { |
@@ -1098,17 +1107,6 @@ void Lane::PushMetatable(lua_State* L_) | |||
1098 | 1107 | ||
1099 | // ################################################################################################# | 1108 | // ################################################################################################# |
1100 | 1109 | ||
1101 | [[nodiscard]] int Lane::pushErrorHandler() const | ||
1102 | { | ||
1103 | if (errorTraceLevel != ErrorTraceLevel::Minimal) { | ||
1104 | lua_pushcfunction(L, lane_error); | ||
1105 | return 1; | ||
1106 | } | ||
1107 | return 0; | ||
1108 | } | ||
1109 | |||
1110 | // ################################################################################################# | ||
1111 | |||
1112 | void Lane::pushStatusString(lua_State* L_) const | 1110 | void Lane::pushStatusString(lua_State* L_) const |
1113 | { | 1111 | { |
1114 | std::string_view const _str{ threadStatusString() }; | 1112 | std::string_view const _str{ threadStatusString() }; |
@@ -158,12 +158,19 @@ class Lane | |||
158 | lua_close(_L); // this collects our coroutine thread at the same time | 158 | lua_close(_L); // this collects our coroutine thread at the same time |
159 | } | 159 | } |
160 | [[nodiscard]] std::string_view errorTraceLevelString() const; | 160 | [[nodiscard]] std::string_view errorTraceLevelString() const; |
161 | [[nodiscard]] int errorHandlerCount() const noexcept | ||
162 | { | ||
163 | // don't push a error handler when in coroutine mode, as the first lua_resume wants only the function and its arguments on the stack | ||
164 | return ((errorTraceLevel == Lane::Minimal) || isCoroutine()) ? 0 : 1; | ||
165 | } | ||
166 | [[nodiscard]] bool isCoroutine() const noexcept { return S != L; } | ||
161 | [[nodiscard]] std::string_view getDebugName() const | 167 | [[nodiscard]] std::string_view getDebugName() const |
162 | { | 168 | { |
163 | std::lock_guard<std::mutex> _guard{ debugNameMutex }; | 169 | std::lock_guard<std::mutex> _guard{ debugNameMutex }; |
164 | return debugName; | 170 | return debugName; |
165 | } | 171 | } |
166 | [[nodiscard]] int pushErrorHandler() const; | 172 | static int LuaErrorHandler(lua_State* L_); |
173 | [[nodiscard]] int pushErrorHandler() const noexcept { return (errorHandlerCount() == 0) ? 0 : (lua_pushcfunction(L, LuaErrorHandler), 1); } | ||
167 | [[nodiscard]] std::string_view pushErrorTraceLevel(lua_State* L_) const; | 174 | [[nodiscard]] std::string_view pushErrorTraceLevel(lua_State* L_) const; |
168 | static void PushMetatable(lua_State* L_); | 175 | static void PushMetatable(lua_State* L_); |
169 | void pushStatusString(lua_State* L_) const; | 176 | void pushStatusString(lua_State* L_) const; |