Skip to content

Lygaen/lua.zig

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LUA.ZIG

Brainmade mark

License Zig

A thin wrapper over Lua 5.5, providing all the goodies of it ! The zig version is the one on the master branch.

Lua Wrapper

To link / get a module of the Lua Wrapper, one can do the following :

$ zig fetch --save=lua.zig https://codeberg.org/mathieu_cayeux/lua.zig

And in your build.zig.zon:

const lua_zig = b.dependency("lua.zig");
YOUR_MODULE.addImport("lua-zig", lua_zig.module("lua.zig"));

If you want solely the C API :

YOUR_MODULE.addImport("lua-c", lua_zig.module("lua.c"));

Then, you can check out the examples/ folder. An overview of the API is :

// functions can take a struct as
// an argument !
fn functor(value: struct {
    internal: u32
}) u32 {
    std.log.debug("functor({})", .{value});

    return value.internal * value.internal;
}

const LUA_PROGRAM =
    \\function multiply(x, y)
    \\    local z = x * y
    \\    z = functor({ internal = z })
    \\    return z
    \\end
;

pub fn main(init: std.process.Init) !void {
    var state: lua.Lua = try .init(init.gpa, .{});
    defer state.deinit();
    defer {
        if (state.diag.hasErr()) {
            std.log.err("{}: {s}", .{ state.diag.err.?, state.diag.message });
        }
    }

    try state.setGlobal("functor", functor);

    const reader = std.Io.Reader.fixed(LUA_PROGRAM);
    try state.loadFromReader(reader);
    // The program must be ran once to load symbols
    try state.run();

    // Return value (here `u32`) can be a struct, string, etc.
    // If it is a string or a struct containing one, don't forget to call
    // state.free(#) on it !
    const ret = try state.call("multiply", .{ 2, 3 }, u32);

    std.log.debug("functor(2 * 3) = {}", .{ret});
}

Generate the Lua C Library

Now, the build.zig can be used to generate an exact copy of official repo's Lua libraries ! In particular, it will create a one-to-one equivalent of what would be generated by make :

PREFIX/
  include/*
  lib/*
  man/man1/*
  bin/*

To generate the above, do :

$ git clone https://codeberg.org/mathieu_cayeux/lua.zig
$ cd lua.zig
$ zig build install -Dskip-zig

Note that skip-zig will skip any TranslateC steps, module creation etc. It should be used only if you want to create a standard Lua library.

You can also add the option skip-lua-exes which will skip creating the bin and man/man1 folder as well as what it contains, namely the lua and luac executables and their manpages.

$ zig build install -Dskip-zig -Dskip-lua-exes
$ file zig-out/bin/
zig-out/bin/: cannot open `zig-out/bin/' (No such file or directory)

Limitations

The build toolchain uses the Translate C API to generate the bindings. This is equivalent on older zig build to doing a @cImport, but the latter will be removed on later versions.

Note that because lua makes heavy use of macros to make inline calls of functions, some translated call will not work, namely because of #164 which is a current bug that doesn't coerce NULL (the macro) to a pointer's null.

As such, some of the following code will get a compile-time error :

const my_str = lua.lua_tostring(L, -1);

will get :

// ERROR: error: expected type '[*c]usize', found '?*anyopaque'
pub inline fn lua_tostring(L: anytype, i: anytype) @TypeOf(lua_tolstring(L, i, NULL));
//                                                                             ^~~~
// -- snip --
// note: generic function instantiated here
const my_str = lua.lua_tostring(new_state, -1);

The fix is as follows :

const my_str = lua.lua_tostring(new_state, -1);
// TO
const my_str = lua.lua_tolstring(new_state, -1, null);

aka. copying what is after the @TypeOf in the declaration and swapping the values NULL to null where applicable.

License

I'm using MIT.