How to parse build.zig.zon with new ZON parser in std

It seems like build runner uses custom parser to parse build.zig.zon so there are no examples of it.
Problem is in build.zig.zon using keys for names of dependencies (here example)

.dependencies = .{
    .example = .{
        .url = "https://example.com/foo.tar.gz",
        ....

but im not sure if this is possible in zon. Here is my current attempt. It works if build.zig.zon has no dependencies at all.

const BuildZigZon = struct {
    name: []const u8,
    version: []const u8,
    dependencies: []const Dependency,
    paths: []const []const u8,

    const Dependency = struct {
        []const u8,
        struct {
            url: []const u8 = "",
            hash: []const u8 = "",
            path: []const u8 = "",
            lazy: bool = false,
        },
    };
};

fn openBuildZigZon(arena: std.mem.Allocator, dir: std.fs.Dir, path: []const u8) !BuildZigZon {
    const content = try dir.readFileAllocOptions(arena, path, 1000 * 1000 * 1000, null, 1, 0);

    var status: std.zon.parse.Status = .{};
    const result = std.zon.parse.fromSlice(BuildZigZon, arena, content, &status, .{}) catch |e| {
        std.log.err("path {s} {}", .{ path, status });
        return e;
    };

    return result;
}

Why I need it?
I want to create loc like utility but it also counts lines in dependencies

Solved by just parsing manualy.

const BuildZigZon = struct {
    name: ?[]const u8 = null,
    version: ?[]const u8 = null,
    dependencies: std.StringArrayHashMapUnmanaged(Dependency) = .empty,

    const Dependency = struct {
        url: []const u8 = "",
        hash: []const u8 = "",
        path: []const u8 = "",
        lazy: bool = false,
    };
};

fn openBuildZigZon(arena: std.mem.Allocator, dir: std.fs.Dir, path: []const u8) !BuildZigZon {
    const content = try dir.readFileAllocOptions(arena, path, 1000 * 1000 * 1000, null, 1, 0);

    const ast = try std.zig.Ast.parse(arena, content, .zon);
    const zoir = try std.zig.ZonGen.generate(arena, ast, .{ .parse_str_lits = true });

    const root = std.zig.Zoir.Node.Index.root.get(zoir);
    const root_struct = if (root == .struct_literal) root.struct_literal else return error.Parse;

    var result: BuildZigZon = .{};

    for (root_struct.names, 0..root_struct.vals.len) |name_node, index| {
        const value = root_struct.vals.at(@intCast(index));
        const name = name_node.get(zoir);

        if (std.mem.eql(u8, name, "name")) {
            result.name = try arena.dupe(u8, value.get(zoir).string_literal);
        }

        if (std.mem.eql(u8, name, "version")) {
            result.version = try arena.dupe(u8, value.get(zoir).string_literal);
        }

        if (std.mem.eql(u8, name, "dependencies")) dep: {
            switch (value.get(zoir)) {
                .struct_literal => |sl| {
                    for (sl.names, 0..sl.vals.len) |dep_name, dep_index| {
                        const node = sl.vals.at(@intCast(dep_index));
                        const dep_body = try std.zon.parse.fromZoirNode(BuildZigZon.Dependency, arena, ast, zoir, node, null, .{});

                        try result.dependencies.put(arena, try arena.dupe(u8, dep_name.get(zoir)), dep_body);
                    }
                },
                .empty_literal => {
                    break :dep;
                },
                else => return error.Parse,
            }
        }
    }

    return result;
}

Yay now we can count lines with dependencies

build.zig - 34
 raylib-zig - /home/andrewkraevskii/.cache/zig/p/122058d3ea6318efb819d0bffba630afd1a459fa3a99b4bfe4b680a937d5de04d2fc
info: entered inner print
 lib/raymath.zig - 446
 lib/rlgl-ext.zig - 158
 lib/raygui-ext.zig - 59
 lib/raygui.zig - 578
 lib/rlgl.zig - 713
 lib/raylib-ext.zig - 581
 lib/raylib.zig - 3261
 lib/raymath-ext.zig - 145
 build.zig - 308
 emcc.zig - 97
  raylib - /home/andrewkraevskii/.cache/zig/p/1220d93782859726c2c46a05450615b7edfc82b7319daac50cbc7c3345d660b022d7
info: entered inner print
  build.zig - 332
   xcode_frameworks - /home/andrewkraevskii/.cache/zig/p/12208da4dfcd9b53fb367375fb612ec73f38e53015f1ce6ae6d6e8437a637078e170
   emsdk - /home/andrewkraevskii/.cache/zig/p/1220e8fe9509f0843e5e22326300ca415c27afbfbba3992f3c3184d71613540b5564
  raygui - /home/andrewkraevskii/.cache/zig/p/122062b24f031e68f0d11c91dfc32aed5baf06caf26ed3c80ea1802f9e788ef1c358
info: entered inner print
src/main.zig - 632
total lines 7344
1 Like

I will make sure @import("build.zig.zon") directly in build.zig works. This was certainly my original intent.

10 Likes