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') usize(2) else 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;
}
