feature. See also
. The project being documented here (as the example) is the Zig library itself.
MacroTranslator.zigifyEscapeSequences
fn zigifyEscapeSequences(mt: *MacroTranslator, slice: []const u8) ![]const u8
File
Code
fn zigifyEscapeSequences(mt: *MacroTranslator, slice: []const u8) ![]const u8 {
var source = slice;
for (source, 0..) |c, i| {
if (c == '\"' or c == '\'') {
source = source[i..];
break;
}
}
for (source) |c| {
if (c == '\\' or c == '\t') {
break;
}
} else return source;
const bytes = try mt.t.arena.alloc(u8, source.len * 2);
var state: enum {
start,
escape,
hex,
octal,
} = .start;
var i: usize = 0;
var count: u8 = 0;
var num: u8 = 0;
for (source) |c| {
switch (state) {
.escape => {
switch (c) {
'n', 'r', 't', '\\', '\'', '\"' => {
bytes[i] = c;
},
'0'...'7' => {
count += 1;
num += c - '0';
state = .octal;
bytes[i] = 'x';
},
'x' => {
state = .hex;
bytes[i] = 'x';
},
'a' => {
bytes[i] = 'x';
i += 1;
bytes[i] = '0';
i += 1;
bytes[i] = '7';
},
'b' => {
bytes[i] = 'x';
i += 1;
bytes[i] = '0';
i += 1;
bytes[i] = '8';
},
'f' => {
bytes[i] = 'x';
i += 1;
bytes[i] = '0';
i += 1;
bytes[i] = 'C';
},
'v' => {
bytes[i] = 'x';
i += 1;
bytes[i] = '0';
i += 1;
bytes[i] = 'B';
},
'?' => {
i -= 1;
bytes[i] = '?';
},
'u', 'U' => {
try mt.fail("macro tokenizing failed: TODO unicode escape sequences", .{});
return error.ParseError;
},
else => {
try mt.fail("macro tokenizing failed: unknown escape sequence", .{});
return error.ParseError;
},
}
i += 1;
if (state == .escape)
state = .start;
},
.start => {
if (c == '\t') {
bytes[i] = '\\';
i += 1;
bytes[i] = 't';
i += 1;
continue;
}
if (c == '\\') {
state = .escape;
}
bytes[i] = c;
i += 1;
},
.hex => {
switch (c) {
'0'...'9' => {
num = std.math.mul(u8, num, 16) catch {
try mt.fail("macro tokenizing failed: hex literal overflowed", .{});
return error.ParseError;
};
num += c - '0';
},
'a'...'f' => {
num = std.math.mul(u8, num, 16) catch {
try mt.fail("macro tokenizing failed: hex literal overflowed", .{});
return error.ParseError;
};
num += c - 'a' + 10;
},
'A'...'F' => {
num = std.math.mul(u8, num, 16) catch {
try mt.fail("macro tokenizing failed: hex literal overflowed", .{});
return error.ParseError;
};
num += c - 'A' + 10;
},
else => {
i += std.fmt.printInt(bytes[i..], num, 16, .lower, .{ .fill = '0', .width = 2 });
num = 0;
if (c == '\\')
state = .escape
else
state = .start;
bytes[i] = c;
i += 1;
},
}
},
.octal => {
const accept_digit = switch (c) {
'0'...'7' => count < 3,
else => false,
};
if (accept_digit) {
count += 1;
num = std.math.mul(u8, num, 8) catch {
try mt.fail("macro tokenizing failed: octal literal overflowed", .{});
return error.ParseError;
};
num += c - '0';
} else {
i += std.fmt.printInt(bytes[i..], num, 16, .lower, .{ .fill = '0', .width = 2 });
num = 0;
count = 0;
if (c == '\\')
state = .escape
else
state = .start;
bytes[i] = c;
i += 1;
}
},
}
}
if (state == .hex or state == .octal) {
i += std.fmt.printInt(bytes[i..], num, 16, .lower, .{ .fill = '0', .width = 2 });
}
return bytes[0..i];
}