zig/lib/std/zig/parse_string_literal.zig
2019-11-08 15:57:24 -05:00

77 lines
2.2 KiB
Zig

const std = @import("../std.zig");
const assert = std.debug.assert;
const State = enum {
Start,
Backslash,
};
pub const ParseStringLiteralError = error{
OutOfMemory,
/// When this is returned, index will be the position of the character.
InvalidCharacter,
};
/// caller owns returned memory
pub fn parseStringLiteral(
allocator: *std.mem.Allocator,
bytes: []const u8,
bad_index: *usize, // populated if error.InvalidCharacter is returned
) ParseStringLiteralError![]u8 {
const first_index = if (bytes[0] == 'c') @as(usize, 2) else @as(usize, 1);
assert(bytes[bytes.len - 1] == '"');
var list = std.ArrayList(u8).init(allocator);
errdefer list.deinit();
const slice = bytes[first_index..];
try list.ensureCapacity(slice.len - 1);
var state = State.Start;
for (slice) |b, index| {
switch (state) {
State.Start => switch (b) {
'\\' => state = State.Backslash,
'\n' => {
bad_index.* = index;
return error.InvalidCharacter;
},
'"' => return list.toOwnedSlice(),
else => try list.append(b),
},
State.Backslash => switch (b) {
'x' => @panic("TODO"),
'u' => @panic("TODO"),
'U' => @panic("TODO"),
'n' => {
try list.append('\n');
state = State.Start;
},
'r' => {
try list.append('\r');
state = State.Start;
},
'\\' => {
try list.append('\\');
state = State.Start;
},
't' => {
try list.append('\t');
state = State.Start;
},
'"' => {
try list.append('"');
state = State.Start;
},
else => {
bad_index.* = index;
return error.InvalidCharacter;
},
},
else => unreachable,
}
}
unreachable;
}