From 4e64ae96929a6b806dea6f0769a408112970141b Mon Sep 17 00:00:00 2001 From: rpkak Date: Fri, 14 Mar 2025 12:18:10 +0100 Subject: [PATCH] DepTokenizer: allow space between target and colon --- lib/std/Build/Cache/DepTokenizer.zig | 64 ++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/lib/std/Build/Cache/DepTokenizer.zig b/lib/std/Build/Cache/DepTokenizer.zig index ccd7f82fdf0a..a1e64c006d99 100644 --- a/lib/std/Build/Cache/DepTokenizer.zig +++ b/lib/std/Build/Cache/DepTokenizer.zig @@ -25,7 +25,7 @@ pub fn next(self: *Tokenizer) ?Token { }, }, .target => switch (char) { - '\t', '\n', '\r', ' ' => { + '\n', '\r' => { return errorIllegalChar(.invalid_target, self.index, char); }, '$' => { @@ -40,6 +40,15 @@ pub fn next(self: *Tokenizer) ?Token { self.state = .target_colon; self.index += 1; }, + '\t', ' ' => { + self.state = .target_space; + + const bytes = self.bytes[start..self.index]; + std.debug.assert(bytes.len != 0); + self.index += 1; + + return finishTarget(must_resolve, bytes); + }, else => { self.index += 1; }, @@ -110,6 +119,19 @@ pub fn next(self: *Tokenizer) ?Token { self.state = .target; }, }, + .target_space => switch (char) { + '\t', ' ' => { + // silently ignore additional horizontal whitespace + self.index += 1; + }, + ':' => { + self.state = .rhs; + self.index += 1; + }, + else => { + return errorIllegalChar(.expected_colon, self.index, char); + }, + }, .rhs => switch (char) { '\t', ' ' => { // silently ignore horizontal whitespace @@ -256,6 +278,10 @@ pub fn next(self: *Tokenizer) ?Token { self.state = .lhs; return null; }, + .target_space => { + const idx = self.index - 1; + return errorIllegalChar(.expected_colon, idx, self.bytes[idx]); + }, .prereq_quote => { return errorPosition(.incomplete_quoted_prerequisite, start, self.bytes[start..]); }, @@ -299,6 +325,7 @@ const State = enum { target_dollar_sign, target_colon, target_colon_reverse_solidus, + target_space, rhs, rhs_continuation, rhs_continuation_linefeed, @@ -322,6 +349,7 @@ pub const Token = union(enum) { expected_dollar_sign: IndexAndChar, continuation_eol: IndexAndChar, incomplete_escape: IndexAndChar, + expected_colon: IndexAndChar, pub const IndexAndChar = struct { index: usize, @@ -420,6 +448,7 @@ pub const Token = union(enum) { .expected_dollar_sign, .continuation_eol, .incomplete_escape, + .expected_colon, => |index_and_char| { try writer.writeAll("illegal char "); try printUnderstandableChar(writer, index_and_char.char); @@ -438,6 +467,7 @@ pub const Token = union(enum) { .expected_dollar_sign => "expecting '$'", .continuation_eol => "continuation expecting end-of-line", .incomplete_escape => "incomplete escape", + .expected_colon => "expecting ':'", }; } }; @@ -545,6 +575,16 @@ test "empty target linefeeds + hspace + continuations" { , expect); } +test "empty target + hspace + colon" { + const expect = "target = {foo.o}"; + + try depTokenizer("foo.o :", expect); + try depTokenizer("foo.o\t\t\t:", expect); + try depTokenizer("foo.o \t \t :", expect); + try depTokenizer("\r\nfoo.o :", expect); + try depTokenizer(" foo.o :", expect); +} + test "prereq" { const expect = \\target = {foo.o} @@ -923,9 +963,6 @@ test "error illegal char at position - expecting dollar_sign" { } test "error illegal char at position - invalid target" { - try depTokenizer("foo\t.o", - \\ERROR: illegal char \x09 at position 3: invalid target - ); try depTokenizer("foo\n.o", \\ERROR: illegal char \x0A at position 3: invalid target ); @@ -963,6 +1000,25 @@ test "error prereq - continuation expecting end-of-line" { ); } +test "error illegal char at position - expecting colon" { + try depTokenizer("foo\t.o:", + \\target = {foo} + \\ERROR: illegal char '.' at position 4: expecting ':' + ); + try depTokenizer("foo .o:", + \\target = {foo} + \\ERROR: illegal char '.' at position 4: expecting ':' + ); + try depTokenizer("foo \n.o:", + \\target = {foo} + \\ERROR: illegal char \x0A at position 4: expecting ':' + ); + try depTokenizer("foo.o\t\n:", + \\target = {foo.o} + \\ERROR: illegal char \x0A at position 6: expecting ':' + ); +} + // - tokenize input, emit textual representation, and compare to expect fn depTokenizer(input: []const u8, expect: []const u8) !void { var arena_allocator = std.heap.ArenaAllocator.init(std.testing.allocator);