Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Luals docgen #99

Merged
merged 33 commits into from
Sep 27, 2024
Merged

Luals docgen #99

merged 33 commits into from
Sep 27, 2024

Conversation

VisenDev
Copy link
Contributor

Closes #94

I did figure out how to implement this via a custom build step.

At the moment, only defining zig structs are supported (though I'd like to support functions as well)

@natecraddock
Copy link
Owner

Excellent work! I'll take a look at this soon

@VisenDev
Copy link
Contributor Author

Output from the example in build.zig

---@meta

--- This is an autogenerated file,
--- Do not modify

---@class Foo
---@field far MyEnum
---@field near SubType

---@class SubType
---@field foo integer
---@field bar boolean
---@field bip MyEnum
---@field bap MyEnum[]?

---@class TestType
---@field a integer
---@field b number
---@field c boolean
---@field d SubType
---@field e Bippity[]

---@alias MyEnum
---|' "asdf" '
---|' "fdsa" '
---|' "qwer" '
---|' "rewq" '

---@class Bippity
---@field A integer?
---@field B lightuserdata
---@field C string
---@field D lightuserdata?

@VisenDev
Copy link
Contributor Author

There does seem to be a problem with this approach unfortunately. See https://discord.com/channels/605571803288698900/1288525615468646521/1288525615468646521

Maybe we will need to compile a specific "generate definitions.lua executable" and then run it inside build.zig, instead of having build.zig do this directly

@natecraddock
Copy link
Owner

Maybe we will need to compile a specific "generate definitions.lua executable" and then run it inside build.zig, instead of having build.zig do this directly

This would be doable. For luajit we already compile a tiny version of lua and run that in the build process

As the number of files for this grows, maybe it would be nice to move all the complex logic for this in a build/ directory?

@VisenDev
Copy link
Contributor Author

This is the approach I am trying now

const std = @import("std");
const ziglua = @import("ziglua");

pub fn main() !void {
    const T = struct { foo: i32 };
    const MyEnum = enum { asdf, fdsa, qwer, rewq };
    const SubType = struct { foo: i32, bar: bool, bip: MyEnum, bap: ?[]MyEnum };
    const Bippity = struct { A: ?i32, B: *bool, C: []const u8, D: ?*SubType };
    const TestType = struct { a: i32, b: f32, c: bool, d: SubType, e: [10]Bippity };
    const Foo = struct { far: MyEnum, near: SubType };

    const to_define: []const ziglua.DefineEntry = &.{
        .{ .type = TestType, .name = "TestType" },
        .{ .type = Foo, .name = "Foo" },
        .{ .type = T, .name = "T" },
    };
    const output = std.mem.sliceTo(std.os.argv[1], 0);
    try ziglua.define(output, to_define);
}

build.zig

    const def_exe = b.addExecutable(.{
        .root_source_file = b.path("examples/define-exe.zig"),
        .name = "def",
        .target = target,
    });
    def_exe.root_module.addImport("ziglua", ziglua);
    var run_def_exe = b.addRunArtifact(def_exe);
    run_def_exe.addArg(b.path("definitions.lua").getPath(b));

    const define_step = b.step("define", "Generate definitions.lua file");
    define_step.dependOn(&run_def_exe.step);

@VisenDev
Copy link
Contributor Author

Hmm I'm getting a very strange error testing this in my own codebase

robertb@artixlinux ~/z/ziggity (master)> zig build define
defining: animation.Animation
defining: Animation
 - adding field: texture
defining: struct_Texture
 - adding field: id
 - adding field: width
 - adding field: height
 - adding field: mipmaps
 - adding field: format
finished defining: struct_Texture
 - adding field: filepath
 - adding field: name
 - adding field: loop
 - adding field: origin
defining: struct_Vector2
 - adding field: x
 - adding field: y
finished defining: struct_Vector2
 - adding field: frames
defining: AnimationFrame
 - adding field: subrect
defining: struct_Rectangle
 - adding field: x
 - adding field: y
 - adding field: width
 - adding field: height
finished defining: struct_Rectangle
 - adding field: milliseconds
finished defining: AnimationFrame
finished defining: Animation
finished defining: animation.Animation
defining: keybindings.Key
defining: Key
 - adding field: name
 - adding field: char
 - adding field: shift
 - adding field: control
 - adding field: mode
General protection exception (no address available)
/usr/lib/zig/std/mem/Allocator.zig:92:30: 0x107878b in resize__anon_9784 (define)
    return self.vtable.resize(self.ptr, buf, log2_buf_align, new_len, ret_addr);
                             ^
/usr/lib/zig/std/array_list.zig:454:38: 0x10426fa in ensureTotalCapacityPrecise (define)
            if (self.allocator.resize(old_memory, new_capacity)) {
                                     ^
/usr/lib/zig/std/array_list.zig:434:51: 0x107653d in ensureTotalCapacity (define)
            return self.ensureTotalCapacityPrecise(better_capacity);
                                                  ^
/usr/lib/zig/std/array_list.zig:468:44: 0x1041dda in ensureUnusedCapacity (define)
            return self.ensureTotalCapacity(try addOrOom(self.items.len, additional_count));
                                           ^
/usr/lib/zig/std/array_list.zig:305:42: 0x1035ab6 in appendSlice (define)
            try self.ensureUnusedCapacity(items.len);
                                         ^
/home/robertb/.cache/zig/p/12206920befce7e3da4bdcbfe5b2e6369d484884edb2ce3da70d1410b46f3f62bd9a/src/define.zig:150:33: 0x103d80a in addType__anon_4500 (define)
            try text.appendSlice(name);
                                ^
/home/robertb/.cache/zig/p/12206920befce7e3da4bdcbfe5b2e6369d484884edb2ce3da70d1410b46f3f62bd9a/src/define.zig:96:16: 0x103d992 in addClassField__anon_4498 (define)
    try addType(alloc, database, text, field.type);
               ^
/home/robertb/.cache/zig/p/12206920befce7e3da4bdcbfe5b2e6369d484884edb2ce3da70d1410b46f3f62bd9a/src/define.zig:107:26: 0x103dcc4 in addClassFields__anon_4497 (define)
        try addClassField(alloc, database, text, fields[0]);
                         ^
/home/robertb/.cache/zig/p/12206920befce7e3da4bdcbfe5b2e6369d484884edb2ce3da70d1410b46f3f62bd9a/src/define.zig:108:27: 0x103dd56 in addClassFields__anon_4494 (define)
        try addClassFields(alloc, database, text, fields[1..fields.len]);
                          ^
/home/robertb/.cache/zig/p/12206920befce7e3da4bdcbfe5b2e6369d484884edb2ce3da70d1410b46f3f62bd9a/src/define.zig:108:27: 0x103ddd6 in addClassFields__anon_4491 (define)
        try addClassFields(alloc, database, text, fields[1..fields.len]);
                          ^
/home/robertb/.cache/zig/p/12206920befce7e3da4bdcbfe5b2e6369d484884edb2ce3da70d1410b46f3f62bd9a/src/define.zig:108:27: 0x103de56 in addClassFields__anon_4487 (define)
        try addClassFields(alloc, database, text, fields[1..fields.len]);
                          ^
/home/robertb/.cache/zig/p/12206920befce7e3da4bdcbfe5b2e6369d484884edb2ce3da70d1410b46f3f62bd9a/src/define.zig:108:27: 0x103ded6 in addClassFields__anon_4486 (define)
        try addClassFields(alloc, database, text, fields[1..fields.len]);
                          ^
/home/robertb/.cache/zig/p/12206920befce7e3da4bdcbfe5b2e6369d484884edb2ce3da70d1410b46f3f62bd9a/src/define.zig:80:27: 0x103e112 in addClass__anon_4484 (define)
        try addClassFields(alloc, database, text, @typeInfo(T).Struct.fields);
                          ^
/home/robertb/.cache/zig/p/12206920befce7e3da4bdcbfe5b2e6369d484884edb2ce3da70d1410b46f3f62bd9a/src/define.zig:21:21: 0x103e2a5 in define__anon_2370 (define)
        try addClass(alloc, &database, def.name, def.type);
                    ^
/home/robertb/zig/ziggity/src/define_exe.zig:12:22: 0x103f7af in main (define)
    try ziglua.define(std.heap.c_allocator, path, to_define);
                     ^
/usr/lib/zig/std/start.zig:524:37: 0x103fcce in main (define)
            const result = root.main() catch |err| {
                                    ^
???:?:?: 0x75588619dd6d in ??? (libc.so.6)
Unwind information for `libc.so.6:0x75588619dd6d` was not available, trace may be incomplete

define
└─ run define failure
error: the following command terminated unexpectedly:
/home/robertb/zig/ziggity/.zig-cache/o/d239e0747f4d06f2f534eb4e45dd958a/define /home/robertb/zig/ziggity/definitions.lua
Build Summary: 24/26 steps succeeded; 1 failed (disable with --summary none)
define transitive failure
└─ run define failure
error: the following build command failed with exit code 1:
/home/robertb/zig/ziggity/.zig-cache/o/6d9cf93a67f25f45113095678177e53e/build /usr/bin/zig /home/robertb/zig/ziggity /home/robertb/zig/ziggity/.zig-cache /home/robertb/.cache/zig --seed 0xa08be77d -Z52efd68346586418 define

@VisenDev VisenDev marked this pull request as draft September 25, 2024 19:00
@VisenDev
Copy link
Contributor Author

Changing the allocator to a raw_c_allocator is giving me a double free error.

So somehow, multiple Arraylists are being defined with the same memory. This is very strange

@VisenDev VisenDev marked this pull request as ready for review September 25, 2024 20:04
@VisenDev
Copy link
Contributor Author

Okay I think I fixed the bug

@VisenDev
Copy link
Contributor Author

VisenDev commented Sep 25, 2024

Output from real world usage in a project of mine. Finally think I implemented it in a way that works. I've had an unusual amount of esoteric memory bugs working on this.

---@meta

--- This is an autogenerated file,
--- Do not modify

---@class Animation
---@field texture struct_Texture | nil
---@field filepath string
---@field name string
---@field loop boolean
---@field origin struct_Vector2
---@field frames AnimationFrame[]

---@class struct_Texture
---@field id integer
---@field width integer
---@field height integer
---@field mipmaps integer
---@field format integer

---@class struct_Vector2
---@field x number
---@field y number

---@class AnimationFrame
---@field subrect struct_Rectangle
---@field milliseconds number

---@class struct_Rectangle
---@field x number
---@field y number
---@field width number
---@field height number

---@class Key
---@field name string
---@field char integer
---@field shift boolean
---@field control boolean
---@field mode KeyMode

---@alias KeyMode
---|' "insert" '
---|' "normal" '

---@class RenderOptions
---@field rotation_radians number
---@field tint struct_Color
---@field flipped boolean
---@field render_style RenderOptions__enum_3471
---@field vertical_scale number
---@field horizontal_scale number
---@field width_override number | nil
---@field height_override number | nil

---@class struct_Color
---@field r integer
---@field g integer
---@field b integer
---@field a integer

---@alias RenderOptions__enum_3471
---|' "scaled_to_grid" '
---|' "actual" '
const std = @import("std");
const ziglua = @import("ziglua");
const anime = @import("animation.zig");
const key = @import("keybindings.zig");

pub fn main() !void {
    const path = std.mem.sliceTo(std.os.argv[1], 0);
    try ziglua.define(std.heap.raw_c_allocator, path, &.{ anime.Animation, key.Key, anime.RenderOptions });
}

@natecraddock
Copy link
Owner

Let me make sure I understand the flow here

Someone makes a file like examples/define-exe.zig in their project. And then they add a build step to generate an output .lua file when that file is run?

@VisenDev
Copy link
Contributor Author

Let me make sure I understand the flow here

Someone makes a file like examples/define-exe.zig in their project. And then they add a build step to generate an output .lua file when that file is run?

Yes, running this file will generate the definitions.lua file. It is necessary to create a separate executable for this because certain types might require certain dependencies to be provided during compilation.

For example, I needed to define some types that had a raylib dependency, I couldn't use a build.zig directly for this because zig didn't know how to find those dependencies when build.zig itself was compiled. Thus, we create an executable specifically for generating these definitions. This executable can then be provided any necessary dependencies for compilation.

You can look at my project here to see this in practice. You can look at build.zig to see the build steps, src/define_exe.zig to see the code to produce the definitions, and data/lua/definitions.lua to see the output definitions

@natecraddock
Copy link
Owner

You can look at my project here to see this in practice. You can look at build.zig to see the build steps, src/define_exe.zig to see the code to produce the definitions, and data/lua/definitions.lua to see the output definitions

Perfect thank you!

build.zig Outdated Show resolved Hide resolved
@natecraddock
Copy link
Owner

Thanks for working on this and for all the things you have implemented for ziglua :)

@natecraddock natecraddock merged commit f28836c into natecraddock:main Sep 27, 2024
3 checks passed
@VisenDev
Copy link
Contributor Author

Thanks for working on this and for all the things you have implemented for ziglua :)

Of course! Its things I was going to implement in my own code anyways, so i figured I might as well contribute it to the library so others can use it as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support generating luadoc comments in zig build system
2 participants