Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse array of type T #9

Merged
merged 2 commits into from
Aug 29, 2024
Merged
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: 0 additions & 2 deletions resources/tutorial.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
---
# An employee record
name: Martin D'vloper
job: Developer
skill: Elite
Expand Down
99 changes: 84 additions & 15 deletions src/root.zig
Original file line number Diff line number Diff line change
Expand Up @@ -125,17 +125,17 @@ pub fn Ymlz(comptime Destination: type) type {
if (typeInfo.Pointer.size == .Slice and typeInfo.Pointer.child == u8) {
@field(destination, field.name) = try self.parseStringExpression(raw_line, depth);
} else if (typeInfo.Pointer.size == .Slice and (typeInfo.Pointer.child == []const u8 or typeInfo.Pointer.child == []u8)) {
@field(destination, field.name) = try self.parseStringArrayExpression(typeInfo.Pointer.child, depth + 1);
} else if (typeInfo.Pointer.size == .Slice and @typeInfo(typeInfo.Pointer.child) != .Pointer) {
@field(destination, field.name) = try self.parseArrayExpression(typeInfo.Pointer.child, depth + 1);
} else {
std.debug.print("Type info: {any}\n", .{@typeInfo([]const u8)});
@panic("unexpected type recieved - " ++ @typeName(field.type) ++ "\n");
}
},
.Struct => {
@field(destination, field.name) = try self.parse(field.type, depth + 1);
},
else => {
std.debug.print("Type info: {any}\n", .{@typeInfo([]const u8)});
@panic("unexpected type recieved - " ++ @typeName(field.type) ++ "\n");
},
}
Expand Down Expand Up @@ -207,6 +207,34 @@ pub fn Ymlz(comptime Destination: type) type {
return false;
}

fn revert(self: *Self, len: usize) !void {
const file = self.file orelse return error.NoFileFound;
// We stumbled on new field, so we rewind this advancement and return our parsed type.
// - 2 -> For some reason we need to go back twice + the length of the sentence for the '\n'
self.seeked -= len + 1;
try file.seekTo(self.seeked);
}

fn parseStringArrayExpression(self: *Self, comptime T: type, depth: usize) ![]T {
var list = std.ArrayList(T).init(self.allocator);
defer list.deinit();

while (true) {
const raw_value_line = try self.readLine() orelse break;

if (self.isNewExpression(raw_value_line, depth)) {
try self.revert(raw_value_line.len);
break;
}

const result = try self.parseStringExpression(raw_value_line, depth);

try list.append(result);
}

return try list.toOwnedSlice();
}

fn parseArrayExpression(self: *Self, comptime T: type, depth: usize) ![]T {
var list = std.ArrayList(T).init(self.allocator);
defer list.deinit();
Expand All @@ -215,18 +243,13 @@ pub fn Ymlz(comptime Destination: type) type {
const raw_value_line = try self.readLine() orelse break;

if (self.isNewExpression(raw_value_line, depth)) {
const file = self.file orelse return error.NoFileFound;
// We stumbled on new field, so we rewind this advancement and return our parsed type.
// - 2 -> For some reason we need to go back twice + the length of the sentence for the '\n'
self.seeked -= raw_value_line.len + 1;
try file.seekTo(self.seeked);
try self.revert(raw_value_line.len);
break;
}

// for now only arrays of strings
const value = try self.parseStringExpression(raw_value_line, depth);
const result = try self.parse(T, depth + 1);

try list.append(value);
try list.append(result);
}

return try list.toOwnedSlice();
Expand Down Expand Up @@ -255,11 +278,7 @@ pub fn Ymlz(comptime Destination: type) type {
const raw_value_line = try self.readLine() orelse break;

if (self.isNewExpression(raw_value_line, depth)) {
const file = self.file orelse return error.NoFileFound;
// We stumbled on new field, so we rewind this advancement and return our parsed type.
// - 2 -> For some reason we need to go back twice + the length of the sentence for the '\n'
self.seeked -= raw_value_line.len + 1;
try file.seekTo(self.seeked);
try self.revert(raw_value_line.len);
if (preserve_new_line)
_ = list.pop();
break;
Expand Down Expand Up @@ -529,3 +548,53 @@ test "should be able to ignore single quotes and double quotes" {
try expect(std.mem.containsAtLeast(u8, result.two, 1, "trying to see if it will break"));
try expect(std.mem.containsAtLeast(u8, result.three, 1, "hello world"));
}

test "should be able to parse arrays of T" {
const Tutorial = struct {
name: []const u8,
type: []const u8,
born: u64,
};

const Experiment = struct {
name: []const u8,
job: []const u8,
skill: []const u8,
employed: bool,
foods: [][]const u8,
languages: struct {
perl: []const u8,
python: []const u8,
pascal: []const u8,
},
education: []const u8,
tutorial: []Tutorial,
};

const yml_file_location = try std.fs.cwd().realpathAlloc(
std.testing.allocator,
"./resources/tutorial.yml",
);
defer std.testing.allocator.free(yml_file_location);

var ymlz = try Ymlz(Experiment).init(std.testing.allocator);
const result = try ymlz.load(yml_file_location);
defer ymlz.deinit(result);

try expect(std.mem.eql(u8, result.name, "Martin D'vloper"));
try expect(std.mem.eql(u8, result.job, "Developer"));
try expect(std.mem.eql(u8, result.foods[0], "Apple"));
try expect(std.mem.eql(u8, result.foods[3], "Mango"));

try expect(std.mem.eql(u8, result.tutorial[0].name, "YAML Ain't Markup Language"));
try expect(std.mem.eql(u8, result.tutorial[0].type, "awesome"));
try expect(result.tutorial[0].born == 2001);

try expect(std.mem.eql(u8, result.tutorial[1].name, "JavaScript Object Notation"));
try expect(std.mem.eql(u8, result.tutorial[1].type, "great"));
try expect(result.tutorial[1].born == 2001);

try expect(std.mem.eql(u8, result.tutorial[2].name, "Extensible Markup Language"));
try expect(std.mem.eql(u8, result.tutorial[2].type, "good"));
try expect(result.tutorial[2].born == 1996);
}