const std = @import("std"); // Minimal Node definition for the DAG format (no App variant for kernels) const Node = union(enum(u8)) { leaf, stem: struct { child: u32 }, fork: struct { left: u32, right: u32 }, }; fn parseLine(line: []const u8) !Node { var it = std.mem.splitScalar(u8, std.mem.trim(u8, line, " \t\n\r"), ' '); const tag = it.next() orelse return error.EmptyLine; if (std.mem.eql(u8, tag, "leaf")) { return .leaf; } else if (std.mem.eql(u8, tag, "stem")) { const child_str = it.next() orelse return error.MissingChild; const child = try std.fmt.parseInt(u32, child_str, 10); return .{ .stem = .{ .child = child } }; } else if (std.mem.eql(u8, tag, "fork")) { const left_str = it.next() orelse return error.MissingLeft; const right_str = it.next() orelse return error.MissingRight; const left = try std.fmt.parseInt(u32, left_str, 10); const right = try std.fmt.parseInt(u32, right_str, 10); return .{ .fork = .{ .left = left, .right = right } }; } else { return error.UnknownTag; } } pub fn main(init: std.process.Init) !void { const gpa = init.gpa; const io = init.io; const args = try init.minimal.args.toSlice(init.arena.allocator()); if (args.len != 3) { std.debug.print("Usage: gen_kernel \n", .{}); std.process.exit(1); } const input_path = args[1]; const output_path = args[2]; const source = try std.Io.Dir.cwd().readFileAlloc(io, input_path, gpa, .limited(10 * 1024 * 1024)); defer gpa.free(source); var nodes = std.ArrayList(Node).empty; defer nodes.deinit(gpa); var it = std.mem.splitScalar(u8, source, '\n'); const root_line = it.next() orelse return error.EmptyFile; const root = try std.fmt.parseInt(u32, std.mem.trim(u8, root_line, " \t\n\r"), 10); while (it.next()) |line| { const trimmed = std.mem.trim(u8, line, " \t\n\r"); if (trimmed.len == 0) continue; const node = try parseLine(trimmed); try nodes.append(gpa, node); } const file = try std.Io.Dir.cwd().createFile(io, output_path, .{}); defer file.close(io); var buf: [4096]u8 = undefined; var writer = file.writer(io, &buf); try writer.interface.writeAll("// Auto-generated from "); try writer.interface.writeAll(input_path); try writer.interface.writeAll("\n// Do not edit manually.\n\n"); try writer.interface.writeAll("pub const NodeTag = enum(u8) { leaf = 0, stem = 1, fork = 2 };\n\n"); try writer.interface.writeAll("pub const Node = union(NodeTag) {\n"); try writer.interface.writeAll(" leaf,\n"); try writer.interface.writeAll(" stem: struct { child: u32 },\n"); try writer.interface.writeAll(" fork: struct { left: u32, right: u32 },\n"); try writer.interface.writeAll("};\n\n"); try writer.interface.print("pub const kernel_root: u32 = {d};\n\n", .{root}); try writer.interface.writeAll("pub const kernel_nodes = [_]Node{\n"); for (nodes.items) |node| { switch (node) { .leaf => try writer.interface.writeAll(" .leaf,\n"), .stem => |s| try writer.interface.print(" .{{ .stem = .{{ .child = {d} }} }},\n", .{s.child}), .fork => |f| try writer.interface.print(" .{{ .fork = .{{ .left = {d}, .right = {d} }} }},\n", .{f.left, f.right}), } } try writer.interface.writeAll("};\n"); try writer.flush(); std.debug.print("Generated {d} kernel nodes, root={d} -> {s}\n", .{ nodes.items.len, root, output_path }); }