ziglua icon indicating copy to clipboard operation
ziglua copied to clipboard

Support generating luadoc comments in zig build system

Open VisenDev opened this issue 1 year ago • 3 comments

(Note: I discussed this idea a few months ago in the ziglua discord, however, my original idea didn't end up working out because comptime globally mutable data had been removed from zig. )

It would be nice if ziglua could expose some functionality to the zig build system which would generate luadoc comments from zig source files (or specific zig declarations).

Basic Example:

src/api.zig

pub const Bar = struct {
   bip: usize,
   bap: bool,
};

pub fn foo(b: Bar, c: f32) ?Bar {
    //do something
}

// fn foo is later registered to lua using `autoPushFunction`

build.zig

const luadocs = try ziglua.deriveLuadocs(@import("src/api.zig"));
try ziglua.appendLuadocs(b.path("data/lua/main.lua"));

data/lua/main.lua (after zig build has been run)

--normal lua code
function doSomething() 
     local c = {['bip'] = 1, ['bap'] = false}
     local foo_result = foo(c, 1.5)
     return foo_result;
end


--ZIGLUA LUADOC BEGIN

---@class Bar
---@field bip integer
---@field bap boolean

---@return Bar|nil
---@param b Bar
---@param c number
---function foo

--ZIGLUA LUADOC END

Implementation details would adjust from here. However, this capability, combined with #93, would make lua almost as nice to use as a statically-typed compiled language (because we could now check at compile time whether our lua code is correct and whether it interfaces with our zig functions and types correctly or not)

We could also explore using lua's abstract syntax tree to place doc comments inline in the file - rather than just placing them all in a big blob at the beginning/end. (This would be helpful for function documentation). See lparser.h and luaY_parser

VisenDev avatar Sep 02 '24 16:09 VisenDev

try ziglua.appendLuadocs(b.path("data/lua/main.lua"));

So this would require some kind of build step that transforms the input lua files and outputs a new file with type information in doc comments? Seems interesting

Is there also a way in Lua to output a file that is purely types and have that be used in a project? I haven't used types in Lua very much so I'm not sure...

natecraddock avatar Sep 06 '24 03:09 natecraddock

try ziglua.appendLuadocs(b.path("data/lua/main.lua"));

So this would require some kind of build step that transforms the input lua files and outputs a new file with type information in doc comments? Seems interesting

Is there also a way in Lua to output a file that is purely types and have that be used in a project? I haven't used types in Lua very much so I'm not sure...

I believe you can create definition files https://luals.github.io/wiki/definition-files/

The problem I've had with these in the past is properly importing those files into your main lua code. Using require 'definitions.lua' lets the lsp find the definitions, but lua fails to import the file at runtime causing a crash. I need to see if there is some sort of doc-comment equivalent to require that only affects the lsp

Edit: I did figure out how to do this using ---@module which simulates a require

definitions.lua

---@meta definitions
---
---@class Vector
---@field x integer
---@field y integer

---@class Rectangle
---@field x integer
---@field y integer
---@field width integer
---@field height integer

---@class Frame
---@field subrect Rectangle[]
---@field milliseconds integer|nil

---@class Animation
---@field name string
---@field filepath string
---@field rotation_speed integer|nil
---@field origin Vector|nil
---@field frames Frame[]|nil


---@alias SubImage fun(name: string, filepath: string, x: integer, y: integer, width: integer, height: integer): Animation

init.lua

---@module "definitions.lua"

---@type SubImage
function SubImage(name, filepath, x, y, width, height)
   return {
      ['name'] = name,
      ['filepath'] = filepath,
      ['frames'] = {
         {['subrect'] = {['x'] = x, ['y'] = y, ['width'] = width, ['height'] = height},}
      },
      --['origin'] = {['x'] = width / 2, ['y'] = height},
   }
end

VisenDev avatar Sep 10 '24 21:09 VisenDev

We will have to do some consideration on the best way to implement these ideas

Desired functions

  • Function to declare a zig function that will be available to ziglua
  • Function to convert zig struct declaration into equivalent ---@class
  • Function to declare a function type signature that zig expects for lua to implement

Possible places to call these functions

  • build.zig

    • Advantage: all documentation generation happens at build time
    • Disadvantage: declaration of lua documentation happens far away from where that functionality is actually used (You may add some functionality to api.zig and forget to update build.zig to add the required functions
  • Where lua functionality is used (eg, api.zig)

    • Advantage: All lua documentation happens inline where the equivalent functionality is used
    • Disadvantage: Documentation generation would happen at runtime not build time

Possible solution - create a function in api.zig that defines all lua documentation for build.zig to call

api.zig

pub fn getLuaDefinitions(b: *std.Build) !ziglua.LuaDefinitions {
    var def = try ziglua.LuaDefinitions.init(b.allocator);
    def.defineZigType(BipBap);
    def.defineZigFunction(myZigFunction);
    def.defineExpectedLuaFunction(.{
        .name = "foo",
        .return = u8,
        .params = .{
           .{.name = "bar", .type = bool},
        },
    };
    return def;
}


// all your other code working with ziglua is also in this file

build.zig

const def = try @import("src/api.zig").getLuaDefinitions(b);
try def.overwriteFile(b.path("data/lua/definitions.lua"));

VisenDev avatar Sep 10 '24 22:09 VisenDev

Proof of concept working

test "docgen" {
    var docs = Doc.init(std.testing.allocator);
    defer docs.deinit();

    const SubType = struct { foo: i32, bar: bool };
    const TestType = struct { a: i32, b: f32, c: bool, d: SubType };
    try docs.addClass("TestType", TestType);
    try docs.printDefined();
}
Screenshot 2024-09-20 at 9 58 55 PM

VisenDev avatar Sep 21 '24 03:09 VisenDev