| ... | @@ -61,10 +61,12 @@ const ErrorMsg = union(enum) { | ... | @@ -61,10 +61,12 @@ const ErrorMsg = union(enum) { |
| 61 | // this is a workaround for stage1 compiler bug I ran into when making it ?u32 | 61 | // this is a workaround for stage1 compiler bug I ran into when making it ?u32 |
| 62 | column: u32, | 62 | column: u32, |
| 63 | kind: Kind, | 63 | kind: Kind, |
| | 64 | count: u32, |
| 64 | }, | 65 | }, |
| 65 | plain: struct { | 66 | plain: struct { |
| 66 | msg: []const u8, | 67 | msg: []const u8, |
| 67 | kind: Kind, | 68 | kind: Kind, |
| | 69 | count: u32, |
| 68 | }, | 70 | }, |
| 69 | | 71 | |
| 70 | const Kind = enum { | 72 | const Kind = enum { |
| ... | @@ -81,12 +83,14 @@ const ErrorMsg = union(enum) { | ... | @@ -81,12 +83,14 @@ const ErrorMsg = union(enum) { |
| 81 | .line = @intCast(u32, src.line), | 83 | .line = @intCast(u32, src.line), |
| 82 | .column = @intCast(u32, src.column), | 84 | .column = @intCast(u32, src.column), |
| 83 | .kind = kind, | 85 | .kind = kind, |
| | 86 | .count = src.count, |
| 84 | }, | 87 | }, |
| 85 | }, | 88 | }, |
| 86 | .plain => |plain| return .{ | 89 | .plain => |plain| return .{ |
| 87 | .plain = .{ | 90 | .plain = .{ |
| 88 | .msg = plain.msg, | 91 | .msg = plain.msg, |
| 89 | .kind = kind, | 92 | .kind = kind, |
| | 93 | .count = plain.count, |
| 90 | }, | 94 | }, |
| 91 | }, | 95 | }, |
| 92 | } | 96 | } |
| ... | @@ -118,10 +122,16 @@ const ErrorMsg = union(enum) { | ... | @@ -118,10 +122,16 @@ const ErrorMsg = union(enum) { |
| 118 | try writer.writeAll("?: "); | 122 | try writer.writeAll("?: "); |
| 119 | } | 123 | } |
| 120 | } | 124 | } |
| 121 | return writer.print("{s}: {s}", .{ @tagName(src.kind), src.msg }); | 125 | try writer.print("{s}: {s}", .{ @tagName(src.kind), src.msg }); |
| | 126 | if (src.count != 1) { |
| | 127 | try writer.print(" ({d} times)", .{src.count}); |
| | 128 | } |
| 122 | }, | 129 | }, |
| 123 | .plain => |plain| { | 130 | .plain => |plain| { |
| 124 | return writer.print("{s}: {s}", .{ @tagName(plain.kind), plain.msg }); | 131 | try writer.print("{s}: {s}", .{ @tagName(plain.kind), plain.msg }); |
| | 132 | if (plain.count != 1) { |
| | 133 | try writer.print(" ({d} times)", .{plain.count}); |
| | 134 | } |
| 125 | }, | 135 | }, |
| 126 | } | 136 | } |
| 127 | } | 137 | } |
| ... | @@ -647,12 +657,20 @@ pub const TestContext = struct { | ... | @@ -647,12 +657,20 @@ pub const TestContext = struct { |
| 647 | for (errors) |err_msg_line, i| { | 657 | for (errors) |err_msg_line, i| { |
| 648 | if (std.mem.startsWith(u8, err_msg_line, "error: ")) { | 658 | if (std.mem.startsWith(u8, err_msg_line, "error: ")) { |
| 649 | array[i] = .{ | 659 | array[i] = .{ |
| 650 | .plain = .{ .msg = err_msg_line["error: ".len..], .kind = .@"error" }, | 660 | .plain = .{ |
| | 661 | .msg = err_msg_line["error: ".len..], |
| | 662 | .kind = .@"error", |
| | 663 | .count = 1, |
| | 664 | }, |
| 651 | }; | 665 | }; |
| 652 | continue; | 666 | continue; |
| 653 | } else if (std.mem.startsWith(u8, err_msg_line, "note: ")) { | 667 | } else if (std.mem.startsWith(u8, err_msg_line, "note: ")) { |
| 654 | array[i] = .{ | 668 | array[i] = .{ |
| 655 | .plain = .{ .msg = err_msg_line["note: ".len..], .kind = .note }, | 669 | .plain = .{ |
| | 670 | .msg = err_msg_line["note: ".len..], |
| | 671 | .kind = .note, |
| | 672 | .count = 1, |
| | 673 | }, |
| 656 | }; | 674 | }; |
| 657 | continue; | 675 | continue; |
| 658 | } | 676 | } |
| ... | @@ -662,7 +680,7 @@ pub const TestContext = struct { | ... | @@ -662,7 +680,7 @@ pub const TestContext = struct { |
| 662 | const line_text = it.next() orelse @panic("missing line"); | 680 | const line_text = it.next() orelse @panic("missing line"); |
| 663 | const col_text = it.next() orelse @panic("missing column"); | 681 | const col_text = it.next() orelse @panic("missing column"); |
| 664 | const kind_text = it.next() orelse @panic("missing 'error'/'note'"); | 682 | const kind_text = it.next() orelse @panic("missing 'error'/'note'"); |
| 665 | const msg = it.rest()[1..]; // skip over the space at end of "error: " | 683 | var msg = it.rest()[1..]; // skip over the space at end of "error: " |
| 666 | | 684 | |
| 667 | const line: ?u32 = if (std.mem.eql(u8, line_text, "?")) | 685 | const line: ?u32 = if (std.mem.eql(u8, line_text, "?")) |
| 668 | null | 686 | null |
| ... | @@ -695,6 +713,14 @@ pub const TestContext = struct { | ... | @@ -695,6 +713,14 @@ pub const TestContext = struct { |
| 695 | break :blk n - 1; | 713 | break :blk n - 1; |
| 696 | } else std.math.maxInt(u32); | 714 | } else std.math.maxInt(u32); |
| 697 | | 715 | |
| | 716 | const suffix = " times)"; |
| | 717 | const count = if (std.mem.endsWith(u8, msg, suffix)) count: { |
| | 718 | const lparen = std.mem.lastIndexOfScalar(u8, msg, '(').?; |
| | 719 | const count = std.fmt.parseInt(u32, msg[lparen + 1 .. msg.len - suffix.len], 10) catch @panic("bad error note count number"); |
| | 720 | msg = msg[0 .. lparen - 1]; |
| | 721 | break :count count; |
| | 722 | } else 1; |
| | 723 | |
| 698 | array[i] = .{ | 724 | array[i] = .{ |
| 699 | .src = .{ | 725 | .src = .{ |
| 700 | .src_path = src_path, | 726 | .src_path = src_path, |
| ... | @@ -702,6 +728,7 @@ pub const TestContext = struct { | ... | @@ -702,6 +728,7 @@ pub const TestContext = struct { |
| 702 | .line = line_0based, | 728 | .line = line_0based, |
| 703 | .column = column_0based, | 729 | .column = column_0based, |
| 704 | .kind = kind, | 730 | .kind = kind, |
| | 731 | .count = count, |
| 705 | }, | 732 | }, |
| 706 | }; | 733 | }; |
| 707 | } | 734 | } |
| ... | @@ -1606,7 +1633,8 @@ pub const TestContext = struct { | ... | @@ -1606,7 +1633,8 @@ pub const TestContext = struct { |
| 1606 | (case_msg.src.column == std.math.maxInt(u32) or | 1633 | (case_msg.src.column == std.math.maxInt(u32) or |
| 1607 | actual_msg.column == case_msg.src.column) and | 1634 | actual_msg.column == case_msg.src.column) and |
| 1608 | std.mem.eql(u8, expected_msg, actual_msg.msg) and | 1635 | std.mem.eql(u8, expected_msg, actual_msg.msg) and |
| 1609 | case_msg.src.kind == .@"error") | 1636 | case_msg.src.kind == .@"error" and |
| | 1637 | actual_msg.count == case_msg.src.count) |
| 1610 | { | 1638 | { |
| 1611 | handled_errors[i] = true; | 1639 | handled_errors[i] = true; |
| 1612 | break; | 1640 | break; |
| ... | @@ -1616,7 +1644,8 @@ pub const TestContext = struct { | ... | @@ -1616,7 +1644,8 @@ pub const TestContext = struct { |
| 1616 | if (ex_tag != .plain) continue; | 1644 | if (ex_tag != .plain) continue; |
| 1617 | | 1645 | |
| 1618 | if (std.mem.eql(u8, case_msg.plain.msg, plain.msg) and | 1646 | if (std.mem.eql(u8, case_msg.plain.msg, plain.msg) and |
| 1619 | case_msg.plain.kind == .@"error") | 1647 | case_msg.plain.kind == .@"error" and |
| | 1648 | case_msg.plain.count == plain.count) |
| 1620 | { | 1649 | { |
| 1621 | handled_errors[i] = true; | 1650 | handled_errors[i] = true; |
| 1622 | break; | 1651 | break; |