@@ -904,13 +904,11 @@ pub const Lua = opaque {
904904 /// * '%d' - Insert a `Lua.Integer`, usually an `i64`, and
905905 /// * '%c' - Insert a single character represented by a number.
906906 ///
907- /// **Usage of this function is discouraged**, consider instead using Zig `std.fmt` primitives in combination with
908- /// `lua.pushString()` or `lua.pushLString()`.
909- ///
907+ /// See also: `raiseErrorFormat()`
910908 /// From: `const char *lua_pushfstring(lua_State *L, const char *fmt, ...);`
911909 /// Refer to: https://www.lua.org/manual/5.1/manual.html#lua_pushfstring
912910 /// Stack Behavior: `[-0, +1, m]`
913- pub fn pushFString (lua : * Lua , comptime format : []const u8 , args : anytype ) [:0 ]const u8 {
911+ pub fn pushFString (lua : * Lua , comptime format : [: 0 ]const u8 , args : anytype ) [:0 ]const u8 {
914912 const string : ? [* :0 ]const u8 = @call (.auto , c .lua_pushfstring , .{ asState (lua ), format .ptr } ++ args );
915913 if (string ) | s | {
916914 // NOTE: This seems dangerous. I don't really like this solution, but it doesn't look like there is any other option.
@@ -1472,10 +1470,8 @@ pub const Lua = opaque {
14721470 return 1 == c .lua_next (asState (lua ), index );
14731471 }
14741472
1475- /// Generates a Lua error. The error message (which can actually be a Lua value of any type)
1476- /// must be on the stack top. This function does a long jump and therefore never returns.
1477- ///
1478- /// Note: This function was renamed from `error` due to naming conflicts with Zig's `error` keyword.
1473+ /// Raises an error with the error message on the top of the stack. The error message may be a Lua value of any
1474+ /// type, but usually a string is best. This function does a long jump and therefore never returns.
14791475 ///
14801476 /// From: `int lua_error(lua_State *L);`
14811477 /// Refer to: https://www.lua.org/manual/5.1/manual.html#lua_error
@@ -1485,6 +1481,27 @@ pub const Lua = opaque {
14851481 unreachable ;
14861482 }
14871483
1484+ /// Raises an error with the given error message format and optional arguments. The error message follows
1485+ /// the same rules as `pushFString()` and includes the file name and line number where the error occurred,
1486+ /// if such information is available. This function does a long jump and therefore never returns.
1487+ ///
1488+ /// In the given `format` string, format specifiers are restricted to the following options:
1489+ /// * '%%' - Insert a literal '%' character in the string.
1490+ /// * '%s' - Insert a zero-terminated string,
1491+ /// * '%f' - Insert a `Lua.Number`, usually an `f64`,
1492+ /// * '%p' - Insert a pointer-width ineger formatted as hexadecimal,
1493+ /// * '%d' - Insert a `Lua.Integer`, usually an `i64`, and
1494+ /// * '%c' - Insert a single character represented by a number.
1495+ ///
1496+ /// See also: `pushFString()`
1497+ /// From: `int luaL_error(lua_State *L, const char *fmt, ...);`
1498+ /// Refer to: https://www.lua.org/manual/5.1/manual.html#luaL_error
1499+ /// Stack Behavior: `[-0, +0, v]`
1500+ pub fn raiseErrorFormat (lua : * Lua , format : [:0 ]const u8 , args : anytype ) noreturn {
1501+ _ = @call (.auto , c .luaL_error , .{ asState (lua ), format .ptr } ++ args );
1502+ unreachable ;
1503+ }
1504+
14881505 /// Represents the kinds of errors that calling a Lua function may result in.
14891506 pub const CallError = error {
14901507 /// Used when the execution of Lua code encounters an error.
@@ -2779,19 +2796,37 @@ test "c functions and closures with protectedCall" {
27792796 lua .pop (1 );
27802797}
27812798
2782- fn errorRaisingCFunction (lua : * Lua ) callconv (.c ) i32 {
2783- lua .pushLString ("error raised" );
2784- lua .raiseError ();
2799+ test "protectedCall should capture error raised by c function" {
2800+ const lua = try Lua .init (std .testing .allocator );
2801+ defer lua .deinit ();
2802+
2803+ const T = struct {
2804+ fn errorRaisingCFunction (l : * Lua ) callconv (.c ) i32 {
2805+ l .pushLString ("error raised" );
2806+ l .raiseError ();
2807+ }
2808+ };
2809+
2810+ lua .pushCFunction (T .errorRaisingCFunction );
2811+ const actual = lua .protectedCall (0 , 0 , 0 );
2812+ try std .testing .expectError (Lua .CallError .Runtime , actual );
2813+ try std .testing .expectEqualSlices (u8 , "error raised" , try lua .toLString (-1 ));
27852814}
27862815
2787- test "c functions raising error with protectedCall " {
2816+ test "protectedCall should capture formatted error raised by c function " {
27882817 const lua = try Lua .init (std .testing .allocator );
27892818 defer lua .deinit ();
27902819
2791- lua .pushCFunction (errorRaisingCFunction );
2820+ const T = struct {
2821+ fn formattedErrorRaisingCFunction (l : * Lua ) callconv (.c ) i32 {
2822+ return l .raiseErrorFormat ("%%-%s-%%,%f,%d,'%c'" , .{ "Hello" , @as (f64 , 13.3 ), @as (i32 , 42 ), @as (u8 , 'A' ) });
2823+ }
2824+ };
2825+
2826+ lua .pushCFunction (T .formattedErrorRaisingCFunction );
27922827 const actual = lua .protectedCall (0 , 0 , 0 );
27932828 try std .testing .expectError (Lua .CallError .Runtime , actual );
2794- try std .testing .expectEqualSlices (u8 , "error raised " , try lua .toLString (-1 ));
2829+ try std .testing .expectEqualSlices (u8 , "%-Hello-%,13.3,42,'A' " , try lua .toLString (-1 ));
27952830}
27962831
27972832test "openLibs doesn't effect the stack" {
0 commit comments