From 1c84c8fd3154c79179f5f13949696f5ecb5fb81f Mon Sep 17 00:00:00 2001 From: Nathan Craddock Date: Wed, 6 May 2026 08:38:19 -0600 Subject: [PATCH] Remove errors from functions that return LuaType These functions mapped LuaType.nil to a Zig error. When the returned type is inspected, nil is still one of the possible values, even though in the case of an error that is not possible. I think it makes more sense to not return errors for these functions. --- src/lib.zig | 59 +++++++++++++++----------------- src/tests.zig | 94 +++++++++++++++++++++++++-------------------------- 2 files changed, 74 insertions(+), 79 deletions(-) diff --git a/src/lib.zig b/src/lib.zig index dd6ace5..daffbb8 100644 --- a/src/lib.zig +++ b/src/lib.zig @@ -1257,15 +1257,13 @@ pub const Lua = opaque { /// Pushes onto the stack the value of the global name. Returns the type of that value. /// - /// Returns an error if the global does not exist (is nil) - /// /// * Pops from Stack: `0` /// * Pushes to Stack: `1` /// * Lua Runtime Errors: `any` /// /// See https://www.lua.org/manual/5.4/manual.html#lua_getglobal - pub fn getGlobal(lua: *Lua, name: [:0]const u8) !LuaType { - const lua_type: LuaType = blk: { + pub fn getGlobal(lua: *Lua, name: [:0]const u8) LuaType { + return blk: { switch (lang) { .lua53, .lua54, .lua55, .luau => break :blk @enumFromInt(c.lua_getglobal(@as(*LuaState, @ptrCast(lua)), name.ptr)), else => { @@ -1274,9 +1272,6 @@ pub const Lua = opaque { }, } }; - - if (lua_type == .nil) return error.LuaError; - return lua_type; } /// Pushes onto the stack the value `t[i]` where `t` is the value at the given `index` @@ -1299,15 +1294,12 @@ pub const Lua = opaque { c.lua_getuservalue(@ptrCast(lua), index); } - // TODO: should all versions of getUserValue possibly fail? fn getUserValue53(lua: *Lua, index: i32) LuaType { return @enumFromInt(c.lua_getuservalue(@ptrCast(lua), index)); } - fn getUserValue54(lua: *Lua, index: i32, n: i32) !LuaType { - const val_type: LuaType = @enumFromInt(c.lua_getiuservalue(@ptrCast(lua), index, n)); - if (val_type == .none) return error.LuaError; - return val_type; + fn getUserValue54(lua: *Lua, index: i32, n: i32) LuaType { + return @enumFromInt(c.lua_getiuservalue(@ptrCast(lua), index, n)); } /// Pushes onto the stack the nth user value associated with the full userdata at the given index @@ -3773,12 +3765,9 @@ pub const Lua = opaque { /// * Pushes to Stack: `(0|1)` /// * Lua Runtime Errors: `memory` /// - /// TODO: possibly return an error if nil /// See https://www.lua.org/manual/5.4/manual.html#luaL_getmetafield - pub fn getMetaField(lua: *Lua, obj: i32, field: [:0]const u8) !LuaType { - const val_type: LuaType = @enumFromInt(c.luaL_getmetafield(@ptrCast(lua), obj, field.ptr)); - if (val_type == .nil) return error.LuaError; - return val_type; + pub fn getMetaField(lua: *Lua, obj: i32, field: [:0]const u8) LuaType { + return @enumFromInt(c.luaL_getmetafield(@ptrCast(lua), obj, field.ptr)); } /// Pushes onto the stack the metatable associated with the name tname in the @@ -4839,12 +4828,15 @@ pub const Lua = opaque { defer lua.pop(1); for (0..arr_len) |i| { - if (lua.getMetaField(-1, "__index")) |_| { - lua.pushValue(-2); - lua.pushInteger(@intCast(i + 1)); - lua.call(.{ .args = 1, .results = 1 }); - } else |_| { - _ = lua.rawGetIndex(-1, @intCast(i + 1)); + switch (lua.getMetaField(-1, "__index")) { + .nil => { + _ = lua.rawGetIndex(-1, @intCast(i + 1)); + }, + else => { + lua.pushValue(-2); + lua.pushInteger(@intCast(i + 1)); + lua.call(.{ .args = 1, .results = 1 }); + }, } defer lua.pop(1); result[i] = try lua.toAny(child, -1); @@ -4979,12 +4971,15 @@ pub const Lua = opaque { defer lua.pop(1); inline for (info.fields, 0..) |field, i| { - if (lua.getMetaField(-1, "__index")) |_| { - lua.pushValue(-2); - lua.pushInteger(@intCast(i + 1)); - lua.call(.{ .args = 1, .results = 1 }); - } else |_| { - _ = lua.rawGetIndex(-1, @intCast(i + 1)); + switch (lua.getMetaField(-1, "__index")) { + .nil => { + _ = lua.rawGetIndex(-1, @intCast(i + 1)); + }, + else => { + lua.pushValue(-2); + lua.pushInteger(@intCast(i + 1)); + lua.call(.{ .args = 1, .results = 1 }); + }, } defer lua.pop(1); result[i] = try lua.toAnyInternal(field.type, a, allow_alloc, -1); @@ -5047,7 +5042,7 @@ pub const Lua = opaque { /// Calls a function and pushes its return value to the top of the stack fn autoCallAndPush(lua: *Lua, comptime ReturnType: type, func_name: [:0]const u8, args: anytype) !void { - if (try lua.getGlobal(func_name) != LuaType.function) return error.LuaInvalidFunctionName; + if (lua.getGlobal(func_name) != .function) return error.LuaInvalidFunctionName; inline for (args) |arg| { try lua.pushAny(arg); @@ -5132,14 +5127,14 @@ pub const Lua = opaque { ///get any lua global pub fn get(lua: *Lua, comptime ReturnType: type, name: [:0]const u8) !ReturnType { - _ = try lua.getGlobal(name); + _ = lua.getGlobal(name); return try lua.toAny(ReturnType, -1); } /// get any lua global /// can allocate memory pub fn getAlloc(lua: *Lua, comptime ReturnType: type, name: [:0]const u8) !Parsed(ReturnType) { - _ = try lua.getGlobal(name); + _ = lua.getGlobal(name); return try lua.toAnyAlloc(ReturnType, -1); } diff --git a/src/tests.zig b/src/tests.zig index 0328ea2..22918a7 100644 --- a/src/tests.zig +++ b/src/tests.zig @@ -327,7 +327,7 @@ test "executing string contents" { try lua.loadString("a = f(2)"); try lua.protectedCall(.{}); - try expectEqual(.number, try lua.getGlobal("a")); + try expectEqual(.number, lua.getGlobal("a")); try expectEqual(12, try lua.toInteger(1)); try expectError(if (zlua.lang == .luau) error.InvalidBytecode else error.LuaSyntax, lua.loadString("bad syntax")); @@ -439,7 +439,7 @@ test "calling a function" { lua.register("zigadd", zlua.wrap(add)); - _ = try lua.getGlobal("zigadd"); + _ = lua.getGlobal("zigadd"); lua.pushInteger(10); lua.pushInteger(32); @@ -607,7 +607,7 @@ test "function registration" { lua.registerFns("testlib", &funcs); // testlib.add(1, 2) - _ = try lua.getGlobal("testlib"); + _ = lua.getGlobal("testlib"); _ = lua.getField(-1, "add"); lua.pushInteger(1); lua.pushInteger(2); @@ -757,7 +757,7 @@ test "table access" { defer lua.deinit(); try lua.doString("a = { [1] = 'first', key = 'value', ['other one'] = 1234 }"); - _ = try lua.getGlobal("a"); + _ = lua.getGlobal("a"); if (zlua.lang == .lua53 or zlua.lang == .lua54 or zlua.lang == .lua55) { try expectEqual(.string, lua.rawGetIndex(1, 1)); @@ -798,14 +798,14 @@ test "table access" { lua.setMetatable(1); try lua.getMetatable(1); - _ = try lua.getMetaField(1, "__len"); - try expectError(error.LuaError, lua.getMetaField(1, "__index")); + _ = lua.getMetaField(1, "__len"); + try expectEqual(.nil, lua.getMetaField(1, "__index")); lua.pushBoolean(true); lua.setField(1, "bool"); try lua.doString("b = a.bool"); - try expectEqual(.boolean, try lua.getGlobal("b")); + try expectEqual(.boolean, lua.getGlobal("b")); try expect(lua.toBoolean(-1)); // create array [1, 2, 3, 4, 5] @@ -871,7 +871,7 @@ test "dump and load" { // store a function in a global try lua.doString("f = function(x) return function(n) return n + x end end"); // put the function on the stack - _ = try lua.getGlobal("f"); + _ = lua.getGlobal("f"); const writer = struct { fn inner(l: *Lua, buf: []const u8, data: *anyopaque) bool { @@ -975,13 +975,13 @@ test "userdata and uservalues" { _ = lua.pushStringZ("test string"); try lua.setUserValue(1, 2); - try expectEqual(.number, try lua.getUserValue(1, 1)); + try expectEqual(.number, lua.getUserValue(1, 1)); try expectEqual(1234.56, try lua.toNumber(-1)); - try expectEqual(.string, try lua.getUserValue(1, 2)); + try expectEqual(.string, lua.getUserValue(1, 2)); try expectEqualStrings("test string", try lua.toString(-1)); try expectError(error.OutOfBounds, lua.setUserValue(1, 3)); - try expectError(error.LuaError, lua.getUserValue(1, 3)); + try expectEqual(.none, lua.getUserValue(1, 3)); } } @@ -1009,7 +1009,7 @@ test "upvalues" { // call the function repeatedly, each time ensuring the result increases by one var expected: i32 = 1; while (expected <= 10) : (expected += 1) { - _ = try lua.getGlobal("counter"); + _ = lua.getGlobal("counter"); lua.call(.{ .results = 1 }); try expectEqual(expected, try lua.toInteger(-1)); lua.pop(1); @@ -1021,7 +1021,7 @@ test "table traversal" { defer lua.deinit(); try lua.doString("t = { key = 'value', second = true, third = 1 }"); - _ = try lua.getGlobal("t"); + _ = lua.getGlobal("t"); lua.pushNil(); @@ -1077,21 +1077,21 @@ test "closing vars" { ); lua.newTable(); - _ = try lua.getGlobal("mt"); + _ = lua.getGlobal("mt"); lua.setMetatable(-2); lua.toClose(-1); lua.closeSlot(-1); lua.pop(1); lua.newTable(); - _ = try lua.getGlobal("mt"); + _ = lua.getGlobal("mt"); lua.setMetatable(-2); lua.toClose(-1); lua.closeSlot(-1); lua.pop(1); // this should have incremented "closed_vars" to 2 - _ = try lua.getGlobal("closed_vars"); + _ = lua.getGlobal("closed_vars"); try expectEqual(2, try lua.toNumber(-1)); } @@ -1252,7 +1252,7 @@ test "resuming" { \\ return "done" \\end ); - _ = try thread.getGlobal("counter"); + _ = thread.getGlobal("counter"); var num_results: i32 = 0; var i: i32 = 1; @@ -1442,7 +1442,7 @@ test "get global fail" { const lua: *Lua = try .init(testing.allocator); defer lua.deinit(); - try expectError(error.LuaError, lua.getGlobal("foo")); + try expectEqual(.nil, lua.getGlobal("foo")); } test "globalSub" { @@ -1466,7 +1466,7 @@ test "loadBuffer" { } else _ = try lua.loadBuffer("global = 10", "chunkname", .text); try lua.protectedCall(.{ .args = 0, .results = zlua.mult_return }); - _ = try lua.getGlobal("global"); + _ = lua.getGlobal("global"); try expectEqual(10, try lua.toInteger(-1)); } @@ -1489,7 +1489,7 @@ test "where" { \\ret = whereFn() ); - _ = try lua.getGlobal("ret"); + _ = lua.getGlobal("ret"); try expectEqualStrings("[string \"...\"]:2: ", try lua.toString(-1)); } @@ -1548,7 +1548,7 @@ test "metatables" { } // set the len metamethod to the function f - _ = try lua.getGlobal("f"); + _ = lua.getGlobal("f"); lua.setField(1, "__len"); lua.newTable(); @@ -1618,7 +1618,7 @@ test "traceback" { lua.setGlobal("tracebackFn"); try lua.doString("res = tracebackFn()"); - _ = try lua.getGlobal("res"); + _ = lua.getGlobal("res"); if (zlua.lang == .luau) { try expectEqualStrings("\n[string \"...\"]:1\n", try lua.toString(-1)); } else { @@ -1637,7 +1637,7 @@ test "getSubtable" { \\ b = {}, \\} ); - _ = try lua.getGlobal("a"); + _ = lua.getGlobal("a"); // get the subtable a.b _ = lua.getSubtable(-1, "b"); @@ -1771,13 +1771,13 @@ test "function environments" { lua.pushInteger(10); lua.setGlobal("x"); - _ = try lua.getGlobal("test"); + _ = lua.getGlobal("test"); try lua.protectedCall(.{ .results = 1 }); try testing.expectEqual(10, lua.toInteger(1)); lua.pop(1); // now set the functions table to have a different value of x - _ = try lua.getGlobal("test"); + _ = lua.getGlobal("test"); lua.newTable(); lua.pushInteger(20); lua.setField(2, "x"); @@ -1787,7 +1787,7 @@ test "function environments" { try testing.expectEqual(20, lua.toInteger(1)); lua.pop(1); - _ = try lua.getGlobal("test"); + _ = lua.getGlobal("test"); lua.getFnEnvironment(1); _ = lua.getField(2, "x"); try testing.expectEqual(20, lua.toInteger(3)); @@ -1818,7 +1818,7 @@ test "debug interface" { \\ return x + y \\end ); - _ = try lua.getGlobal("f"); + _ = lua.getGlobal("f"); var info: DebugInfo = undefined; lua.getInfo(.{ @@ -1877,7 +1877,7 @@ test "debug interface" { try expectEqual(zlua.wrap(hook), lua.getHook()); try expectEqual(zlua.HookMask{ .call = true, .line = true, .ret = true }, lua.getHookMask()); - _ = try lua.getGlobal("f"); + _ = lua.getGlobal("f"); lua.pushNumber(3); try lua.protectedCall(.{ .args = 1, .results = 1 }); } @@ -1895,7 +1895,7 @@ test "debug interface Lua 5.1 and Luau" { \\ return x + y \\end ); - _ = try lua.getGlobal("f"); + _ = lua.getGlobal("f"); var info: DebugInfo = undefined; @@ -1967,7 +1967,7 @@ test "debug interface Lua 5.1 and Luau" { try expectEqual(@as(?zlua.CHookFn, zlua.wrap(hook)), lua.getHook()); try expectEqual(zlua.HookMask{ .call = true, .line = true, .ret = true }, lua.getHookMask()); - _ = try lua.getGlobal("f"); + _ = lua.getGlobal("f"); lua.pushNumber(3); try lua.protectedCall(.{ .args = 1, .results = 1 }); } @@ -1984,7 +1984,7 @@ test "debug upvalues" { \\end \\addone = f(1) ); - _ = try lua.getGlobal("addone"); + _ = lua.getGlobal("addone"); // index doesn't exist try expectError(error.OutOfBounds, lua.getUpvalue(1, 2)); @@ -2014,8 +2014,8 @@ test "debug upvalues" { \\addthree = f(3) ); - _ = try lua.getGlobal("addone"); - _ = try lua.getGlobal("addthree"); + _ = lua.getGlobal("addone"); + _ = lua.getGlobal("addthree"); // now addone and addthree share the same upvalue lua.upvalueJoin(-2, 1, -1, 1); @@ -2199,7 +2199,7 @@ test "luau vectors" { \\ return vector(c.x, c.y, c.z) \\end ); - _ = try lua.getGlobal("test"); + _ = lua.getGlobal("test"); try lua.protectedCall(.{ .results = 1 }); var v = try lua.toVector(-1); try testing.expectEqualSlices(f32, &[3]f32{ 10, 14, 18 }, v[0..3]); @@ -2403,9 +2403,9 @@ test "toAny" { //void try lua.doString("value = {}\nvalue_err = {a = 5}"); - _ = try lua.getGlobal("value"); + _ = lua.getGlobal("value"); try testing.expectEqual(void{}, try lua.toAny(void, -1)); - _ = try lua.getGlobal("value_err"); + _ = lua.getGlobal("value_err"); try testing.expectError(error.LuaVoidTableIsNotEmpty, lua.toAny(void, -1)); } @@ -2419,7 +2419,7 @@ test "toAny struct" { bizz: []const u8 = "hi", }; try lua.doString("value = {[\"foo\"] = 10, [\"bar\"] = false}"); - const lua_type = try lua.getGlobal("value"); + const lua_type = lua.getGlobal("value"); try testing.expect(lua_type == .table); const my_struct = try lua.toAny(MyType, 1); try testing.expect(std.meta.eql( @@ -2469,7 +2469,7 @@ test "toAny tuple from struct" { \\ } ); - const lua_type = try lua.getGlobal("value"); + const lua_type = lua.getGlobal("value"); try testing.expect(lua_type == .table); const my_struct = try lua.toAny(MyType, 1); try testing.expect(std.meta.eql( @@ -2503,7 +2503,7 @@ test "toAny from struct with fromLua" { \\ } ); - const lua_type = try lua.getGlobal("value"); + const lua_type = lua.getGlobal("value"); try testing.expect(lua_type == .table); const my_struct = try lua.toAny(MyType, 1); try testing.expect(std.meta.eql( @@ -2536,7 +2536,7 @@ test "toAny mutable string in struct" { bar: bool, }; try lua.doString("value = {[\"name\"] = \"hi\", [\"sentinel\"] = \"ss\", [\"bar\"] = false}"); - const lua_type = try lua.getGlobal("value"); + const lua_type = lua.getGlobal("value"); try testing.expect(lua_type == .table); const parsed = try lua.toAnyAlloc(MyType, 1); defer parsed.deinit(); @@ -2574,7 +2574,7 @@ test "toAny struct recursive" { \\} ); - _ = try lua.getGlobal("value"); + _ = lua.getGlobal("value"); const my_struct = try lua.toAny(MyType, -1); try testing.expectEqualDeep(MyType{}, my_struct); } @@ -2602,15 +2602,15 @@ test "toAny tagged union" { \\} ); - _ = try lua.getGlobal("value0"); + _ = lua.getGlobal("value0"); const my_struct0 = try lua.toAny(MyType, -1); try testing.expectEqualDeep(MyType{ .c = "Hello, world!" }, my_struct0); - _ = try lua.getGlobal("value1"); + _ = lua.getGlobal("value1"); const my_struct1 = try lua.toAny(MyType, -1); try testing.expectEqualDeep(MyType{ .d = .{ .t0 = 5.0, .t1 = -3.0 } }, my_struct1); - _ = try lua.getGlobal("value2"); + _ = lua.getGlobal("value2"); const my_struct2 = try lua.toAny(MyType, -1); try testing.expectEqualDeep(MyType{ .a = 1000 }, my_struct2); } @@ -2623,7 +2623,7 @@ test "toAny slice" { \\list = {1, 2, 3, 4, 5} ; try lua.doString(program); - _ = try lua.getGlobal("list"); + _ = lua.getGlobal("list"); const sliced = try lua.toAnyAlloc([]u32, -1); defer sliced.deinit(); @@ -2641,7 +2641,7 @@ test "toAny array" { \\array= {1, 2, nil, 4, 5} ; try lua.doString(program); - _ = try lua.getGlobal("array"); + _ = lua.getGlobal("array"); const array = try lua.toAny([5]?u32, -1); try testing.expectEqual(arr, array); } @@ -2655,7 +2655,7 @@ test "toAny vector" { \\vector= {true, false, false, true} ; try lua.doString(program); - _ = try lua.getGlobal("vector"); + _ = lua.getGlobal("vector"); const vector = try lua.toAny(@Vector(4, bool), -1); try testing.expectEqual(vec, vector); }