union Token [src]
Fields
target: []const u8
target_must_resolve: []const u8
prereq: []const u8
prereq_must_resolve: []const u8
incomplete_quoted_prerequisite: IndexAndBytes
incomplete_target: IndexAndBytes
invalid_target: IndexAndChar
bad_target_escape: IndexAndChar
expected_dollar_sign: IndexAndChar
continuation_eol: IndexAndChar
incomplete_escape: IndexAndChar
expected_colon: IndexAndChar
Members
- IndexAndBytes (struct)
- IndexAndChar (struct)
- printError (Function)
- resolve (Function)
Source
pub const Token = union(enum) {
target: []const u8,
target_must_resolve: []const u8,
prereq: []const u8,
prereq_must_resolve: []const u8,
incomplete_quoted_prerequisite: IndexAndBytes,
incomplete_target: IndexAndBytes,
invalid_target: IndexAndChar,
bad_target_escape: IndexAndChar,
expected_dollar_sign: IndexAndChar,
continuation_eol: IndexAndChar,
incomplete_escape: IndexAndChar,
expected_colon: IndexAndChar,
pub const IndexAndChar = struct {
index: usize,
char: u8,
};
pub const IndexAndBytes = struct {
index: usize,
bytes: []const u8,
};
/// Resolve escapes in target or prereq. Only valid with .target_must_resolve or .prereq_must_resolve.
pub fn resolve(self: Token, writer: anytype) @TypeOf(writer).Error!void {
switch (self) {
.target_must_resolve => |bytes| {
var state: enum { start, escape, dollar } = .start;
for (bytes) |c| {
switch (state) {
.start => {
switch (c) {
'\\' => state = .escape,
'$' => state = .dollar,
else => try writer.writeByte(c),
}
},
.escape => {
switch (c) {
' ', '#', '\\' => {},
'$' => {
try writer.writeByte('\\');
state = .dollar;
continue;
},
else => try writer.writeByte('\\'),
}
try writer.writeByte(c);
state = .start;
},
.dollar => {
try writer.writeByte('$');
switch (c) {
'$' => {},
else => try writer.writeByte(c),
}
state = .start;
},
}
}
},
.prereq_must_resolve => |bytes| {
var state: enum { start, escape } = .start;
for (bytes) |c| {
switch (state) {
.start => {
switch (c) {
'\\' => state = .escape,
else => try writer.writeByte(c),
}
},
.escape => {
switch (c) {
' ' => {},
'\\' => {
try writer.writeByte(c);
continue;
},
else => try writer.writeByte('\\'),
}
try writer.writeByte(c);
state = .start;
},
}
}
},
else => unreachable,
}
}
pub fn printError(self: Token, writer: anytype) @TypeOf(writer).Error!void {
switch (self) {
.target, .target_must_resolve, .prereq, .prereq_must_resolve => unreachable, // not an error
.incomplete_quoted_prerequisite,
.incomplete_target,
=> |index_and_bytes| {
try writer.print("{s} '", .{self.errStr()});
if (self == .incomplete_target) {
const tmp = Token{ .target_must_resolve = index_and_bytes.bytes };
try tmp.resolve(writer);
} else {
try printCharValues(writer, index_and_bytes.bytes);
}
try writer.print("' at position {d}", .{index_and_bytes.index});
},
.invalid_target,
.bad_target_escape,
.expected_dollar_sign,
.continuation_eol,
.incomplete_escape,
.expected_colon,
=> |index_and_char| {
try writer.writeAll("illegal char ");
try printUnderstandableChar(writer, index_and_char.char);
try writer.print(" at position {d}: {s}", .{ index_and_char.index, self.errStr() });
},
}
}
fn errStr(self: Token) []const u8 {
return switch (self) {
.target, .target_must_resolve, .prereq, .prereq_must_resolve => unreachable, // not an error
.incomplete_quoted_prerequisite => "incomplete quoted prerequisite",
.incomplete_target => "incomplete target",
.invalid_target => "invalid target",
.bad_target_escape => "bad target escape",
.expected_dollar_sign => "expecting '$'",
.continuation_eol => "continuation expecting end-of-line",
.incomplete_escape => "incomplete escape",
.expected_colon => "expecting ':'",
};
}
}