Skip to content

Commit 32bbc5d

Browse files
committed
Set assert handler from Zig
Signed-off-by: Maksym Pavlenko <pavlenko.maksym@gmail.com>
1 parent e8ec8a3 commit 32bbc5d

File tree

6 files changed

+98
-0
lines changed

6 files changed

+98
-0
lines changed

build.zig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,15 @@ pub fn build(b: *std.Build) !void {
170170
.optimize = optimize,
171171
});
172172

173+
// Add C wrapper
174+
mod.addCSourceFile(.{
175+
.file = b.path("src/handler.cpp"),
176+
.flags = flags,
177+
});
178+
mod.addIncludePath(b.path("luau/VM/include"));
179+
mod.addIncludePath(b.path("luau/Common/include"));
180+
mod.addIncludePath(b.path("src"));
181+
173182
mod.linkLibrary(luau_vm);
174183

175184
// TODO: Make these optional
@@ -205,6 +214,15 @@ pub fn build(b: *std.Build) !void {
205214
}),
206215
});
207216

217+
// Add C wrapper
218+
unit_tests.root_module.addCSourceFile(.{
219+
.file = b.path("src/handler.cpp"),
220+
.flags = flags,
221+
});
222+
unit_tests.root_module.addIncludePath(b.path("luau/VM/include"));
223+
unit_tests.root_module.addIncludePath(b.path("luau/Common/include"));
224+
unit_tests.root_module.addIncludePath(b.path("src"));
225+
208226
// See https://zig.news/squeek502/code-coverage-for-zig-1dk1
209227
if (opts.cover) {
210228
unit_tests.setExecCmd(&[_]?[]const u8{

src/assert.zig

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const c = @cImport({
2+
@cInclude("handler.h");
3+
});
4+
5+
/// Assert handler function type for Luau VM assertions.
6+
pub const AssertHandler = c.Luau_AssertHandler;
7+
8+
/// Set a custom assert handler for Luau VM assertions.
9+
///
10+
/// The handler is called when a Luau VM assertion fails, allowing custom error
11+
/// handling and debugging. The handler receives information about the failed assertion
12+
/// including expression, file, line number, and function name.
13+
///
14+
/// Parameters:
15+
/// - handler: Function pointer with signature (expr, file, line, func) -> c_int
16+
/// Returns 0 to abort, non-zero to continue execution
17+
pub inline fn setAssertHandler(handler: AssertHandler) void {
18+
c.luau_set_assert_handler(handler);
19+
}

src/handler.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include "handler.h"
2+
#include "Luau/Common.h"
3+
4+
void luau_set_assert_handler(Luau_AssertHandler handler) {
5+
Luau::assertHandler() = handler;
6+
}

src/handler.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#pragma once
2+
3+
typedef int (*Luau_AssertHandler)(const char* expression, const char* file, int line, const char* function);
4+
5+
#ifdef __cplusplus
6+
extern "C" {
7+
#endif
8+
9+
void luau_set_assert_handler(Luau_AssertHandler handler);
10+
11+
#ifdef __cplusplus
12+
}
13+
#endif

src/lua.zig

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ pub const Compiler = @import("compile.zig").Compiler;
4848
const userdata = @import("userdata.zig");
4949
const stack = @import("stack.zig");
5050
const alloc = @import("alloc.zig").alloc;
51+
const assert = @import("assert.zig");
5152

5253
/// High-level Lua wrapper and main library entry point.
5354
/// Provides an idiomatic Zig interface with automatic type conversions for the Luau scripting language.
@@ -65,6 +66,9 @@ pub const Lua = struct {
6566
Compile,
6667
};
6768

69+
/// Assert handler function type for Luau VM assertions.
70+
pub const AssertHandler = assert.AssertHandler;
71+
6872
/// Initialize a new Lua state with optional custom allocator.
6973
///
7074
/// Creates a new Luau virtual machine instance. Pass `null` to use Luau's built-in
@@ -939,6 +943,27 @@ pub const Lua = struct {
939943

940944
return list.toOwnedSlice();
941945
}
946+
947+
/// Set a custom assert handler for Luau VM assertions.
948+
///
949+
/// The assert handler is called when a Luau VM assertion fails, allowing custom error
950+
/// handling and debugging. The handler receives information about the failed assertion
951+
/// including expression, file, line number, and function name.
952+
///
953+
/// Example:
954+
/// ```zig
955+
/// fn myAssertHandler(expr: [*c]const u8, file: [*c]const u8, line: c_int, func: [*c]const u8) callconv(.C) c_int {
956+
/// std.debug.print("Assertion failed: {s} at {s}:{} in {s}\n", .{expr, file, line, func});
957+
/// return 0; // Return 0 to abort
958+
/// }
959+
///
960+
/// Lua.setAssertHandler(myAssertHandler);
961+
/// ```
962+
///
963+
/// Note: The handler function must have C calling convention and return 0 to abort or non-zero to continue.
964+
pub inline fn setAssertHandler(handler: AssertHandler) void {
965+
assert.setAssertHandler(handler);
966+
}
942967
};
943968

944969
const expect = std.testing.expect;

src/tests.zig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,3 +524,20 @@ test "checkArg userdata support" {
524524

525525
try expectEq(lua.top(), 0);
526526
}
527+
528+
fn testAssertHandler(expr: [*c]const u8, file: [*c]const u8, line: c_int, func: [*c]const u8) callconv(.C) c_int {
529+
_ = expr;
530+
_ = file;
531+
_ = line;
532+
_ = func;
533+
return 1; // Continue execution
534+
}
535+
536+
test "assert handler" {
537+
const lua = try Lua.init(&std.testing.allocator);
538+
defer lua.deinit();
539+
540+
// Verify the API works by setting and resetting the handler
541+
Lua.setAssertHandler(testAssertHandler);
542+
Lua.setAssertHandler(null);
543+
}

0 commit comments

Comments
 (0)