Skip to content

Commit

Permalink
First pass at stringify
Browse files Browse the repository at this point in the history
  • Loading branch information
MasonRemaley committed Dec 25, 2023
1 parent cc3b9f2 commit 47776f9
Show file tree
Hide file tree
Showing 7 changed files with 2,185 additions and 194 deletions.
140 changes: 140 additions & 0 deletions lib/std/zig/string_literal.zig
Original file line number Diff line number Diff line change
Expand Up @@ -298,3 +298,143 @@ test "parse" {
try expect(eql(u8, "foo", try parseAlloc(alloc, "\"f\x6f\x6f\"")));
try expect(eql(u8, "f💯", try parseAlloc(alloc, "\"f\u{1f4af}\"")));
}

/// Parses one line at a time of a multiline Zig string literal to a std.io.Writer type. Does not append a null terminator.
pub fn MultilineParser(comptime Writer: type) type {
return struct {
writer: Writer,
first_line: bool,

pub fn init(writer: Writer) @This() {
return .{
.writer = writer,
.first_line = true,
};
}

/// Parse one line of a multiline string, writing the result to the writer prepending a newline if necessary.
///
/// Asserts bytes begins with "\\". The line may be terminated with '\n' or "\r\n", but may not contain any interior newlines.
/// contain any interior newlines.
pub fn line(self: *@This(), bytes: []const u8) Writer.Error!void {
assert(bytes.len >= 2 and bytes[0] == '\\' and bytes[1] == '\\');
if (self.first_line) {
self.first_line = false;
} else {
try self.writer.writeByte('\n');
}
const carriage_return_ending: usize = if (bytes[bytes.len - 2] == '\r') 2 else if (bytes[bytes.len - 1] == '\n') 1 else 0;
const line_bytes = bytes[2 .. bytes.len - carriage_return_ending];
try self.writer.writeAll(line_bytes);
}
};
}

pub fn multilineParser(writer: anytype) MultilineParser(@TypeOf(writer)) {
return MultilineParser(@TypeOf(writer)).init(writer);
}

test "parse multiline" {
// Varying newlines
{
{
var parsed = std.ArrayList(u8).init(std.testing.allocator);
defer parsed.deinit();
const writer = parsed.writer();
var parser = multilineParser(writer);
try parser.line("\\\\foo");
try std.testing.expectEqualStrings("foo", parsed.items);
try parser.line("\\\\bar");
try std.testing.expectEqualStrings("foo\nbar", parsed.items);
}

{
var parsed = std.ArrayList(u8).init(std.testing.allocator);
defer parsed.deinit();
const writer = parsed.writer();
var parser = multilineParser(writer);
try parser.line("\\\\foo");
try std.testing.expectEqualStrings("foo", parsed.items);
try parser.line("\\\\bar\n");
try std.testing.expectEqualStrings("foo\nbar", parsed.items);
}

{
var parsed = std.ArrayList(u8).init(std.testing.allocator);
defer parsed.deinit();
const writer = parsed.writer();
var parser = multilineParser(writer);
try parser.line("\\\\foo");
try std.testing.expectEqualStrings("foo", parsed.items);
try parser.line("\\\\bar\r\n");
try std.testing.expectEqualStrings("foo\nbar", parsed.items);
}

{
var parsed = std.ArrayList(u8).init(std.testing.allocator);
defer parsed.deinit();
const writer = parsed.writer();
var parser = multilineParser(writer);
try parser.line("\\\\foo\n");
try std.testing.expectEqualStrings("foo", parsed.items);
try parser.line("\\\\bar");
try std.testing.expectEqualStrings("foo\nbar", parsed.items);
}

{
var parsed = std.ArrayList(u8).init(std.testing.allocator);
defer parsed.deinit();
const writer = parsed.writer();
var parser = multilineParser(writer);
try parser.line("\\\\foo\r\n");
try std.testing.expectEqualStrings("foo", parsed.items);
try parser.line("\\\\bar");
try std.testing.expectEqualStrings("foo\nbar", parsed.items);
}
}

// Empty lines
{
{
var parsed = std.ArrayList(u8).init(std.testing.allocator);
defer parsed.deinit();
const writer = parsed.writer();
var parser = multilineParser(writer);
try parser.line("\\\\");
try std.testing.expectEqualStrings("", parsed.items);
try parser.line("\\\\");
try std.testing.expectEqualStrings("\n", parsed.items);
try parser.line("\\\\foo");
try std.testing.expectEqualStrings("\n\nfoo", parsed.items);
try parser.line("\\\\bar");
try std.testing.expectEqualStrings("\n\nfoo\nbar", parsed.items);
}

{
var parsed = std.ArrayList(u8).init(std.testing.allocator);
defer parsed.deinit();
const writer = parsed.writer();
var parser = multilineParser(writer);
try parser.line("\\\\foo");
try std.testing.expectEqualStrings("foo", parsed.items);
try parser.line("\\\\");
try std.testing.expectEqualStrings("foo\n", parsed.items);
try parser.line("\\\\bar");
try std.testing.expectEqualStrings("foo\n\nbar", parsed.items);
try parser.line("\\\\");
try std.testing.expectEqualStrings("foo\n\nbar\n", parsed.items);
}
}

// No escapes
{
var parsed = std.ArrayList(u8).init(std.testing.allocator);
defer parsed.deinit();
const writer = parsed.writer();
var parser = multilineParser(writer);
try parser.line("\\\\no \\n escape");
try std.testing.expectEqualStrings("no \\n escape", parsed.items);
try parser.line("\\\\still no \\n escape");
try std.testing.expectEqualStrings("no \\n escape\nstill no \\n escape", parsed.items);
}
}

0 comments on commit 47776f9

Please sign in to comment.