@@ -2784,6 +2784,23 @@ pub const Lua = opaque {
27842784 return 0 != c .lua_getinfo (asState (lua ), what .ptr , @ptrCast (info ));
27852785 }
27862786
2787+ /// Get information about the interpreter runtime stack. This function fills parts of a `DebugInfo` structure
2788+ /// with an identification of the activation record of the function executing at a given level. This function should
2789+ /// be called before calls to `getInfo()` when inspecting the call stack.
2790+ ///
2791+ /// Level 0 is the current running function, whereas level 1 is the function that has called the current running
2792+ /// function, and so on.
2793+ ///
2794+ /// Returns true when there are no errors, returns false otherwise. This function will return false when called
2795+ /// with a level greater than the stack depth, returns false.
2796+ ///
2797+ /// From: `int lua_getstack(lua_State *L, int level, lua_Debug *ar);`
2798+ /// Refer to: https://www.lua.org/manual/5.1/manual.html#lua_getstack
2799+ /// Stack Behavior: `[-0, +0, -]`
2800+ pub fn getStack (lua : * Lua , level : i32 , info : * Lua.DebugInfo ) bool {
2801+ return 0 != c .lua_getstack (asState (lua ), level , @ptrCast (info ));
2802+ }
2803+
27872804 /// Represents the different kinds of functions that can be inspected by `getInfo()`. This enumerates the possible
27882805 /// values that `getInfo()` will set in the `what` field when inspecting a function.
27892806 pub const FunctionKind = enum {
@@ -5474,3 +5491,48 @@ test "getInfoFunction() can pretty printed" {
54745491 \\
54755492 , actual [45.. ]);
54765493}
5494+
5495+ test "getStack() can be used to inspect the call stack" {
5496+ const lua = try Lua .init (std .testing .allocator );
5497+ defer lua .deinit ();
5498+
5499+ const T = struct {
5500+ fn errorCallback (l : * Lua ) callconv (.c ) i32 {
5501+ var info : Lua.DebugInfo = .{};
5502+ if (! l .getStack (1 , & info ) or ! l .getInfo ("nSlufL" , & info )) {
5503+ return l .raiseErrorFormat ("unreachable" , .{});
5504+ }
5505+
5506+ std .testing .expectEqualStrings ("bar\x00 " , info .name .? [0.. 4]) catch unreachable ;
5507+ std .testing .expectEqualStrings ("global\x00 " , info .namewhat .? [0.. 7]) catch unreachable ;
5508+ std .testing .expectEqualStrings ("Lua\x00 " , info .what .? [0.. 4]) catch unreachable ;
5509+ std .testing .expectEqualStrings ("[string \" function bar()...\" ]\x00 " , info .short_src [0.. 29]) catch unreachable ;
5510+ std .testing .expectEqual (2 , info .currentline ) catch unreachable ;
5511+ std .testing .expectEqual (0 , info .nups ) catch unreachable ;
5512+ std .testing .expectEqual (1 , info .linedefined ) catch unreachable ;
5513+ std .testing .expectEqual (3 , info .lastlinedefined ) catch unreachable ;
5514+
5515+ l .pushString (info .name .? );
5516+ return 1 ;
5517+ }
5518+ };
5519+
5520+ lua .pushCFunction (T .errorCallback );
5521+ const expected_source =
5522+ \\function bar()
5523+ \\ return error("this error invokes the errorCallback above")
5524+ \\end
5525+ \\function foo()
5526+ \\ bar()
5527+ \\end
5528+ ;
5529+ try lua .doString (expected_source );
5530+
5531+ try std .testing .expectEqual (Lua .Type .function , lua .getGlobal ("foo" ));
5532+ try std .testing .expectError (Lua .ProtectedCallError .Runtime , lua .callProtected (0 , Lua .MultipleReturn , 1 ));
5533+
5534+ try std .testing .expectEqual (2 , lua .getTop ());
5535+ try std .testing .expect (lua .isFunction (1 ));
5536+ try std .testing .expect (lua .isString (2 ));
5537+ try std .testing .expectEqualStrings ("bar" , try lua .toLString (-1 ));
5538+ }
0 commit comments