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
2 changes: 1 addition & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
.name = .gremlin,
.version = "0.1.0",
.fingerprint = 0x52f178c9d53d6b13,
.minimum_zig_version = "0.15.2",
.minimum_zig_version = "0.16.0",

.paths = .{""},
}
136 changes: 68 additions & 68 deletions integration-test/benchmark.zig
Original file line number Diff line number Diff line change
Expand Up @@ -128,48 +128,48 @@ fn updateGoldenMessage(msg: *unittest.TestAllTypes, repeated_storage: []?unittes
fn createDeepNested() benchmark.DeepNested {
const items_level1 = [_]?benchmark.Level1{
benchmark.Level1{
.id = 11,
.title = "item1_top_level",
.score = 2.34,
.nested = benchmark.Level2{
.id = 110,
.description = "nested_in_top_item1",
.payload = "some payload data",
.nested = benchmark.Level3{
.id = 1100,
.name = "deeply_nested_top_item1",
.id = 11,
.title = "item1_top_level",
.score = 2.34,
.nested = benchmark.Level2{
.id = 110,
.description = "nested_in_top_item1",
.payload = "some payload data",
.nested = benchmark.Level3{
.id = 1100,
.name = "deeply_nested_top_item1",
},
},
},
},
benchmark.Level1{
.id = 12,
.title = "item2_top_level",
.score = 3.45,
.nested = benchmark.Level2{
.id = 120,
.description = "nested_in_top_item2",
.payload = "more payload data here",
},
.id = 12,
.title = "item2_top_level",
.score = 3.45,
.nested = benchmark.Level2{
.id = 120,
.description = "nested_in_top_item2",
.payload = "more payload data here",
},
},
benchmark.Level1{
.id = 13,
.title = "item3_top_level",
.score = 4.56,
.id = 13,
.title = "item3_top_level",
.score = 4.56,
},
benchmark.Level1{
.id = 14,
.title = "item4_top_level",
.score = 5.67,
.nested = benchmark.Level2{
.id = 140,
.description = "nested_in_top_item4",
.payload = "final payload data",
},
.id = 14,
.title = "item4_top_level",
.score = 5.67,
.nested = benchmark.Level2{
.id = 140,
.description = "nested_in_top_item4",
.payload = "final payload data",
},
},
benchmark.Level1{
.id = 15,
.title = "item5_top_level",
.score = 6.78,
.id = 15,
.title = "item5_top_level",
.score = 6.78,
},
};

Expand All @@ -193,23 +193,23 @@ fn createDeepNested() benchmark.DeepNested {

const items_level3 = [_]?benchmark.Level3{
benchmark.Level3{
.id = 31,
.name = "item1_nested",
.nested = benchmark.Level4{
.value = 310,
.data = "nested_item1_data",
.numbers = &[_]i32{ 1, 2, 3, 4, 5 },
},
.id = 31,
.name = "item1_nested",
.nested = benchmark.Level4{
.value = 310,
.data = "nested_item1_data",
.numbers = &[_]i32{ 1, 2, 3, 4, 5 },
},
.items = &sub_items1,
},
benchmark.Level3{
.id = 32,
.name = "item2_nested",
.nested = benchmark.Level4{
.value = 320,
.data = "nested_item2_data",
.numbers = &[_]i32{ 6, 7, 8, 9, 10 },
},
.id = 32,
.name = "item2_nested",
.nested = benchmark.Level4{
.value = 320,
.data = "nested_item2_data",
.numbers = &[_]i32{ 6, 7, 8, 9, 10 },
},
.items = &sub_items2,
},
benchmark.Level3{
Expand All @@ -234,32 +234,32 @@ fn createDeepNested() benchmark.DeepNested {

const items_level2 = [_]?benchmark.Level2{
benchmark.Level2{
.id = 21,
.description = "item1_level2_with_payload",
.payload = "payload for item 1",
.nested = benchmark.Level3{
.id = 210,
.name = "nested_in_item1",
.nested = benchmark.Level4{
.value = 2100,
.data = "deep_nested",
.numbers = &[_]i32{ 100, 200, 300 },
.id = 21,
.description = "item1_level2_with_payload",
.payload = "payload for item 1",
.nested = benchmark.Level3{
.id = 210,
.name = "nested_in_item1",
.nested = benchmark.Level4{
.value = 2100,
.data = "deep_nested",
.numbers = &[_]i32{ 100, 200, 300 },
},
},
},
},
benchmark.Level2{
.id = 22,
.description = "item2_level2_with_payload",
.payload = "payload for item 2 with more data",
.nested = benchmark.Level3{
.id = 220,
.name = "nested_in_item2",
},
.id = 22,
.description = "item2_level2_with_payload",
.payload = "payload for item 2 with more data",
.nested = benchmark.Level3{
.id = 220,
.name = "nested_in_item2",
},
},
benchmark.Level2{
.id = 23,
.description = "item3_level2_with_payload",
.payload = "payload for item 3",
.id = 23,
.description = "item3_level2_with_payload",
.payload = "payload for item 3",
},
benchmark.Level2{
.id = 24,
Expand Down
11 changes: 6 additions & 5 deletions src/codegen/gen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ 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);
try std.fs.path.relativePosix(allocator, "/", proto_root, file_path);
defer allocator.free(rel_to_proto);

// Generate output path
Expand Down Expand Up @@ -99,11 +99,12 @@ fn createFile(
/// OutOfMemory if allocation fails
pub fn generateProtobuf(
allocator: std.mem.Allocator,
io: std.Io,
proto_root: []const u8,
target_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(allocator, io, proto_root, ignore_masks);
defer parsed.deinit();

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

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

/// Resolves cross-file references between all generated files.
Expand All @@ -153,10 +154,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(allocator: std.mem.Allocator, io: std.Io, 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);
}
}
8 changes: 4 additions & 4 deletions src/codegen/gen/enum.zig
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,9 @@ 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);
var aw = try std.Io.Writer.Allocating.initCapacity(allocator, 1024);
errdefer aw.deinit();
const writer = &aw.writer;

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

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

try writer.writeAll("};\n");
return buffer.toOwnedSlice(allocator);
return aw.toOwnedSlice();
}

/// 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 => {
const hex = try std.fmt.allocPrint(allocator, "\\x{X:0>2}", .{c});
defer allocator.free(hex);
try result.appendSlice(allocator, hex);
},
}
}
try result.appendSlice(allocator, "\"");
Expand Down
6 changes: 3 additions & 3 deletions src/codegen/gen/import.zig
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ pub fn importResolve(
const imported_file_rel_path_from_proto_root = if (well_known_types.isWellKnownImport(import_path_in_proto_file))
try allocator.dupe(u8, import_path_in_proto_file)
else
try std.fs.path.relativePosix(allocator, proto_root, import_path_in_proto_file);
try std.fs.path.relativePosix(allocator, "/", proto_root, import_path_in_proto_file);
defer allocator.free(imported_file_rel_path_from_proto_root);

// Generate output path for the imported file
Expand All @@ -154,7 +154,7 @@ pub fn importResolve(
} else {
// Different directory - compute path relative to the importing file's output location
// First, get the output path for the current file (the one doing the importing)
const current_file_rel_to_proto_root = try std.fs.path.relativePosix(allocator, proto_root, proto_file_path);
const current_file_rel_to_proto_root = try std.fs.path.relativePosix(allocator, "/", proto_root, proto_file_path);
defer allocator.free(current_file_rel_to_proto_root);

const current_file_out_path = try paths.outputPath(allocator, current_file_rel_to_proto_root, target_root);
Expand All @@ -164,7 +164,7 @@ pub fn importResolve(
const current_out_dir = std.fs.path.dirname(current_file_out_path) orelse ".";

// Compute relative path from current file's directory to imported file
const rel_import_path = try std.fs.path.relativePosix(allocator, current_out_dir, out_path);
const rel_import_path = try std.fs.path.relativePosix(allocator, "/", current_out_dir, out_path);
defer allocator.free(rel_import_path);

return try ZigImport.init(allocator, src, name, rel_import_path);
Expand Down
13 changes: 6 additions & 7 deletions src/codegen/gen/output.zig
Original file line number Diff line number Diff line change
Expand Up @@ -91,17 +91,16 @@ 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, .{
var 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 Down Expand Up @@ -130,11 +129,11 @@ pub const FileOutput = struct {

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

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

// Free the content buffer
self.content.deinit(self.allocator);
Expand Down
7 changes: 4 additions & 3 deletions src/gremlin/types.zig
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@ pub const SizedBool = Sized(bool);
pub const SizedBytes = Sized([]const u8);

/// Protocol buffer encoding/decoding errors
pub const Error = error{ InvalidVarInt, // Invalid variable integer encoding
pub const Error = error{
InvalidVarInt, // Invalid variable integer encoding
InvalidTag, // Invalid field tag
InvalidData, // Data doesn't match expected format
OutOfMemory // Memory allocation failed
};
OutOfMemory, // Memory allocation failed
};
14 changes: 6 additions & 8 deletions src/parser/entries/buffer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,8 @@ 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(allocator: std.mem.Allocator, io: std.Io, path: []const u8) !ParserBuffer {
const buf = try std.Io.Dir.cwd().readFileAlloc(io, path, allocator, .unlimited);
return ParserBuffer{ .buf = buf, .allocator = allocator };
}

Expand Down Expand Up @@ -253,10 +250,11 @@ 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);
var path_buffer: [std.Io.Dir.max_path_bytes]u8 = undefined;
const n = try std.Io.Dir.cwd().realPathFile(std.testing.io, "test_data/google/proto3.proto", &path_buffer);
const path = path_buffer[0..n];

var buf = try ParserBuffer.initFile(std.testing.allocator, path);
var buf = try ParserBuffer.initFile(std.testing.allocator, std.testing.io, path);
try std.testing.expect(buf.buf.len > 0);
buf.deinit();
}
Expand Down
2 changes: 1 addition & 1 deletion src/parser/entries/service.zig
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ test "service parsing" {

// Test case 3: Service with nested braces
{
var buf = ParserBuffer{ .buf =
var buf = ParserBuffer{ .buf =
\\service Test {
\\ rpc Method1 (Request) { option deprecated = true; }
\\ rpc Method2 (Request) returns (Response) { option idempotency_level = "NO_SIDE_EFFECTS"; }
Expand Down
Loading