Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions src/codegen/gen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ fn createFile(
const rel_to_proto = if (well_known_types.isWellKnownImport(file_path))
try allocator.dupe(u8, file_path)
else
try std.fs.path.relativePosix(allocator, proto_root, file_path);
// TODO(jae): Test this change of having to add "cwd"
try std.fs.path.relativePosix(allocator, ".", proto_root, file_path);
defer allocator.free(rel_to_proto);

// Generate output path
Expand Down Expand Up @@ -101,13 +102,14 @@ fn createFile(
/// Error: GeneratorError variants for different failure modes
/// OutOfMemory if allocation fails
pub fn generateProtobuf(
io: std.Io,
allocator: std.mem.Allocator,
proto_root: []const u8,
target_root: []const u8,
project_root: []const u8,
ignore_masks: ?[]const []const u8,
) !void {
var parsed = try gremlin_parser.parse(allocator, proto_root, ignore_masks);
var parsed = try gremlin_parser.parse(io, allocator, proto_root, ignore_masks);
defer parsed.deinit();

// Create ZigFile instances
Expand All @@ -134,7 +136,7 @@ pub fn generateProtobuf(
try resolveReferences(&files);

// Generate code for each file
try generateCode(allocator, &files);
try generateCode(io, allocator, &files);
}

/// Resolves cross-file references between all generated files.
Expand All @@ -158,10 +160,10 @@ fn resolveReferences(files: *std.ArrayList(ZigFile)) !void {
/// Parameters:
/// - allocator: Memory allocator for file operations
/// - files: List of ZigFile instances to generate code for
fn generateCode(allocator: std.mem.Allocator, files: *std.ArrayList(ZigFile)) !void {
fn generateCode(io: std.Io, allocator: std.mem.Allocator, files: *std.ArrayList(ZigFile)) !void {
for (files.items) |*file| {
var out_file = try FileOutput.init(allocator, file.out_path);
try file.write(&out_file);
try out_file.close();
try out_file.close(io);
}
}
9 changes: 5 additions & 4 deletions src/codegen/gen/enum.zig
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,10 @@ pub const ZigEnum = struct {
///
/// Returns: A newly allocated string containing the Zig enum code
pub fn createEnumDef(self: *const ZigEnum, allocator: std.mem.Allocator) ![]const u8 {
var buffer = try std.ArrayList(u8).initCapacity(allocator, 1024);
errdefer buffer.deinit(allocator);
var writer = buffer.writer(allocator);
const buffer = try allocator.alloc(u8, 32 * 1024);
defer allocator.free(buffer);

var writer = std.Io.Writer.fixed(buffer);

try writer.print("pub const {s} = enum(i32) {{\n", .{self.const_name});

Expand All @@ -126,7 +127,7 @@ pub const ZigEnum = struct {
}

try writer.writeAll("};\n");
return buffer.toOwnedSlice(allocator);
return allocator.dupe(u8, writer.buffered());
}

/// Frees all resources associated with this enum definition.
Expand Down
6 changes: 5 additions & 1 deletion src/codegen/gen/fields/bytes.zig
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ fn formatStringLiteral(allocator: std.mem.Allocator, str: []const u8) ![]const u
'"' => try result.appendSlice(allocator, "\\\""),

// All other characters are converted to hex for consistent representation
else => try std.fmt.format(result.writer(allocator), "\\x{X:0>2}", .{c}),
else => {
var buf: [32]u8 = undefined;
const hex = try std.fmt.bufPrint(&buf, "\\x{X:0>2}", .{c});
try result.appendSlice(allocator, hex);
},
}
}
try result.appendSlice(allocator, "\"");
Expand Down
6 changes: 4 additions & 2 deletions src/codegen/gen/import.zig
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,17 @@ pub fn importResolve(
const rel_to_proto = if (well_known_types.isWellKnownImport(import_path))
try allocator.dupe(u8, import_path)
else
try std.fs.path.relativePosix(allocator, proto_root, import_path);
// TODO(jae): Test this change of having to add "cwd"
try std.fs.path.relativePosix(allocator, ".", proto_root, import_path);
defer allocator.free(rel_to_proto);

// Generate output path in target directory
const out_path = try paths.outputPath(allocator, rel_to_proto, target_root);
defer allocator.free(out_path);

// Get path relative to project root
const rel_to_project = try std.fs.path.relativePosix(allocator, project_root, out_path);
// TODO(jae): Test this change of having to add "cwd"
const rel_to_project = try std.fs.path.relativePosix(allocator, ".", project_root, out_path);
defer allocator.free(rel_to_project);

// Generate import alias from filename
Expand Down
19 changes: 13 additions & 6 deletions src/codegen/gen/output.zig
Original file line number Diff line number Diff line change
Expand Up @@ -91,17 +91,17 @@ pub const FileOutput = struct {
/// Collapses consecutive newlines into single newlines.
///
/// Returns: Error if file operations fail
pub fn close(self: *FileOutput) !void {
pub fn close(self: *FileOutput, io: std.Io) !void {
// Ensure directory exists
const dir_path = std.fs.path.dirname(self.path) orelse return error.InvalidPath;
try std.fs.cwd().makePath(dir_path);
try std.Io.Dir.cwd().createDirPath(io, dir_path);

// Create or truncate output file
const file = try std.fs.cwd().createFile(self.path, .{
const file = try std.Io.Dir.cwd().createFile(io, self.path, .{
.truncate = true,
.read = false,
});
defer file.close();
defer file.close(io);

// Collapse consecutive newlines into single newlines
var processed = try std.ArrayList(u8).initCapacity(self.allocator, self.content.items.len);
Expand All @@ -128,13 +128,20 @@ pub const FileOutput = struct {
trimmed_len -= 1;
}

var file_buf: [4096]u8 = undefined;
var file_out = file.writer(io, &file_buf);
var file_writer = &file_out.interface;

// Write content up to the last non-newline character
if (trimmed_len > 0) {
try file.writeAll(processed.items[0..trimmed_len]);
try file_writer.writeAll(processed.items[0..trimmed_len]);
}

// Always add exactly one newline at the end
try file.writeAll("\n");
try file_writer.writeAll("\n");

// Flush the writer
try file_writer.flush();

// Free the content buffer
self.content.deinit(self.allocator);
Expand Down
15 changes: 8 additions & 7 deletions src/parser/entries/buffer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ pub const ParserBuffer = struct {

/// Initialize a ParserBuffer by reading the entire contents of a file
/// Caller owns the memory and must call deinit()
pub fn initFile(allocator: std.mem.Allocator, path: []const u8) !ParserBuffer {
var file = try std.fs.openFileAbsolute(path, .{ .mode = .read_only });
defer file.close();

const buf = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
pub fn initFile(io: std.Io, allocator: std.mem.Allocator, path: []const u8) !ParserBuffer {
var file = try std.Io.Dir.openFileAbsolute(io, path, .{ .mode = .read_only });
defer file.close(io);
var file_reader = file.reader(io, &.{});
const buf = try file_reader.interface.allocRemaining(allocator, .unlimited);
return ParserBuffer{ .buf = buf, .allocator = allocator };
}

Expand Down Expand Up @@ -254,9 +254,10 @@ test "large comment" {

test "file read" {
var path_buffer: [std.fs.max_path_bytes]u8 = undefined;
const path = try std.fs.realpath("test_data/google/proto3.proto", &path_buffer);
const path_len = try std.Io.Dir.cwd().realPathFile(std.testing.io, "test_data/google/proto3.proto", &path_buffer);
const path = path_buffer[0..path_len];

var buf = try ParserBuffer.initFile(std.testing.allocator, path);
var buf = try ParserBuffer.initFile(std.testing.io, std.testing.allocator, path);
try std.testing.expect(buf.buf.len > 0);
buf.deinit();
}
Expand Down
18 changes: 7 additions & 11 deletions src/parser/fs/paths.zig
Original file line number Diff line number Diff line change
Expand Up @@ -52,26 +52,26 @@ fn matchGlob(path: []const u8, pattern: []const u8) bool {
return pattern_idx == pattern.len and path_idx == path.len;
}

pub fn findProtoFiles(allocator: std.mem.Allocator, basePath: []const u8, ignore_masks: ?[]const []const u8) !std.ArrayList([]const u8) {
var dir = try std.fs.cwd().openDir(basePath, .{ .iterate = true });
defer dir.close();
pub fn findProtoFiles(io: std.Io, allocator: std.mem.Allocator, basePath: []const u8, ignore_masks: ?[]const []const u8) !std.ArrayList([:0]const u8) {
var dir = try std.Io.Dir.cwd().openDir(io, basePath, .{ .iterate = true });
defer dir.close(io);

var walker = try dir.walk(allocator);
defer walker.deinit();

var paths = try std.ArrayList([]const u8).initCapacity(allocator, 128);
var paths = try std.ArrayList([:0]const u8).initCapacity(allocator, 128);
errdefer {
for (paths.items) |path| {
allocator.free(path);
}
paths.deinit(allocator);
}

while (try walker.next()) |entry| {
while (try walker.next(io)) |entry| {
if (matchesAnyMask(entry.path, ignore_masks)) continue;

if (entry.kind == .file and std.mem.eql(u8, std.fs.path.extension(entry.basename), ".proto")) {
const path = try dir.realpathAlloc(allocator, entry.path);
const path = try dir.realPathFileAlloc(io, entry.path, allocator);
try paths.append(allocator, path);
}
}
Expand Down Expand Up @@ -176,10 +176,7 @@ pub fn findRoot(
}

test "walk" {
var path_buffer: [std.fs.max_path_bytes]u8 = undefined;
const path = try std.fs.realpath(".", &path_buffer);

var entries = try findProtoFiles(std.testing.allocator, path, null);
var entries = try findProtoFiles(std.testing.io, std.testing.allocator, ".", null);
defer {
for (entries.items) |entry| {
std.testing.allocator.free(entry);
Expand All @@ -190,7 +187,6 @@ test "walk" {
try std.testing.expect(entries.items.len > 0);
for (entries.items) |entry| {
try std.testing.expect(entry.len > 0);
try std.testing.expectStringStartsWith(entry, path);
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/parser/parser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ fn printError(allocator: std.mem.Allocator, path: []const u8, err: Error, buf: *
/// Parse protocol buffer files starting from the given base path
/// Returns a ParseResult containing all parsed files and their buffers
/// Caller owns the returned ParseResult and must call deinit() on it
pub fn parse(allocator: std.mem.Allocator, base_path: []const u8, ignore_masks: ?[]const []const u8) !ParseResult {
var proto_files = try paths.findProtoFiles(allocator, base_path, ignore_masks);
pub fn parse(io: std.Io, allocator: std.mem.Allocator, base_path: []const u8, ignore_masks: ?[]const []const u8) !ParseResult {
var proto_files = try paths.findProtoFiles(io, allocator, base_path, ignore_masks);
defer {
for (proto_files.items) |file| {
allocator.free(file);
Expand All @@ -107,7 +107,7 @@ pub fn parse(allocator: std.mem.Allocator, base_path: []const u8, ignore_masks:
}

const root = if (!std.fs.path.isAbsolute(base_path))
try std.fs.cwd().realpathAlloc(allocator, base_path)
try std.Io.Dir.cwd().realPathFileAlloc(io, base_path, allocator)
else
try allocator.dupe(u8, base_path);
defer allocator.free(root);
Expand All @@ -131,7 +131,7 @@ pub fn parse(allocator: std.mem.Allocator, base_path: []const u8, ignore_masks:

// Process each proto file
for (proto_files.items) |file_path| {
var buffer = try ParserBuffer.initFile(allocator, file_path);
var buffer = try ParserBuffer.initFile(io, allocator, file_path);
errdefer buffer.deinit();

var result = ProtoFile.parse(allocator, &buffer);
Expand Down
3 changes: 2 additions & 1 deletion step.zig
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,11 @@ fn make(step: *std.Build.Step, _: std.Build.Step.MakeOptions) !void {
const target_path = try ps.gen_output.getPath3(b, step).toString(b.allocator);
const build_path = b.build_root.path orelse @panic("build path unknown");

const proto_path_resolved = try std.Build.Cache.Directory.cwd().handle.realpathAlloc(b.allocator, proto_path);
const proto_path_resolved = try std.Build.Cache.Directory.cwd().handle.realPathFileAlloc(b.graph.io, proto_path, b.allocator);
defer b.allocator.free(proto_path_resolved);

generateProtobuf(
b.graph.io,
b.allocator,
proto_path_resolved,
target_path,
Expand Down