diff --git a/doc/langref/ambiguous_precedence_mul_bitand.zig b/doc/langref/ambiguous_precedence_mul_bitand.zig index 66f1f5a1a4535148a5377dc3e335dc9e1d498147..af3c28cc6c04729e2fd1cec8084c2a1b9afb8ae3 100644 --- a/doc/langref/ambiguous_precedence_mul_bitand.zig +++ b/doc/langref/ambiguous_precedence_mul_bitand.zig @@ -8,4 +8,4 @@ test "ambiguous precedence" { _ = x & y *% z; } -// obj=ambiguous operator precedence with operators … & … *% …; use parentheses to disambiguate \ No newline at end of file +// obj=ambiguous operator precedence with operators ... & ... *% ...; use parentheses to disambiguate \ No newline at end of file diff --git a/doc/langref/ambiguous_precedence_orelse_ne.zig b/doc/langref/ambiguous_precedence_orelse_ne.zig index 922886e24ba36b0f5e522269cf6eca593137122c..b7be5d0c9bdff108e37183365fbcaa59705bb61a 100644 --- a/doc/langref/ambiguous_precedence_orelse_ne.zig +++ b/doc/langref/ambiguous_precedence_orelse_ne.zig @@ -15,4 +15,4 @@ test "ambiguous precedence" { _ = makeBool(x) orelse y != z; } -// obj=ambiguous operator precedence with operators … orelse … != …; use parentheses to disambiguate \ No newline at end of file +// obj=ambiguous operator precedence with operators ... orelse ... != ...; use parentheses to disambiguate \ No newline at end of file diff --git a/doc/langref/ambiguous_precedence_shift_sub.zig b/doc/langref/ambiguous_precedence_shift_sub.zig index b5f7d8a679154bc66af1451224f62fac2f489c91..2410aa950cfcc25060f6d8d341129983f8fd51e3 100644 --- a/doc/langref/ambiguous_precedence_shift_sub.zig +++ b/doc/langref/ambiguous_precedence_shift_sub.zig @@ -7,4 +7,4 @@ test "ambiguous precedence" { _ = x << y - 1; } -// obj=ambiguous operator precedence with operators … << … - …; use parentheses to disambiguate \ No newline at end of file +// obj=ambiguous operator precedence with operators ... << ... - ...; use parentheses to disambiguate \ No newline at end of file diff --git a/doc/langref/nonchaining_sibling_operators.zig b/doc/langref/nonchaining_sibling_operators.zig index 9716a956b1580dd214df68aa6619f55996e52ac8..9873620d783801578cdb5560a0541992be28ab4b 100644 --- a/doc/langref/nonchaining_sibling_operators.zig +++ b/doc/langref/nonchaining_sibling_operators.zig @@ -2,4 +2,4 @@ fn foo(x: anytype, y: anytype, z: anytype) void { _ = x << y << z; } -// obj=repetition of non-chainable operators … << … << …; use parentheses to disambiguate \ No newline at end of file +// obj=repetition of non-chainable operators ... << ... << ...; use parentheses to disambiguate \ No newline at end of file diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig index 14a16e1730564aa7add9e659dc81a76175b5a95c..e5426856cd9aad238ae5dc0b43340a7f44c1a744 100644 --- a/lib/std/zig/Ast.zig +++ b/lib/std/zig/Ast.zig @@ -556,7 +556,7 @@ pub fn renderError(tree: Ast, parse_error: Error, w: *Writer) Writer.Error!void return w.writeAll("use 'var' or 'const' to declare variable"); }, .ambiguous_operator_precedence => { - return w.print("ambiguous operator precedence with operators … {s} … {s} …; use parentheses to disambiguate", .{ + return w.print("ambiguous operator precedence with operators ... {s} ... {s} ...; use parentheses to disambiguate", .{ tree.tokenTag(parse_error.token - @as(u32, @intCast(parse_error.extra.offset))).lexeme().?, tree.tokenTag(parse_error.token).lexeme().?, }); @@ -565,19 +565,19 @@ pub fn renderError(tree: Ast, parse_error: Error, w: *Writer) Writer.Error!void return w.writeAll("previous ambiguous operator here"); }, .illegal_chained_operators => { - return w.print("repetition of non-chainable operators … {s} … {s} …; use parentheses to disambiguate", .{ + return w.print("repetition of non-chainable operators ... {s} ... {s} ...; use parentheses to disambiguate", .{ tree.tokenTag(parse_error.token - @as(u32, @intCast(parse_error.extra.offset))).lexeme().?, tree.tokenTag(parse_error.token).lexeme().?, }); }, .hint_operator_precedence_left => { - return w.print("did you mean `(… {s} …) {s} …` ?", .{ + return w.print("previously evaluated as `(... {s} ...) {s} ...`", .{ tree.tokenTag(parse_error.token - @as(u32, @intCast(parse_error.extra.offset))).lexeme().?, tree.tokenTag(parse_error.token).lexeme().?, }); }, .hint_operator_precedence_right => { - return w.print("did you mean `… {s} (… {s} …)` ?", .{ + return w.print("previously evaluated as `... {s} (... {s} ...)`", .{ tree.tokenTag(parse_error.token - @as(u32, @intCast(parse_error.extra.offset))).lexeme().?, tree.tokenTag(parse_error.token).lexeme().?, }); diff --git a/lib/std/zig/Parse.zig b/lib/std/zig/Parse.zig index 64e5c398dded4cdeb52a29ba48ae78735e5b75b6..95f3c1603ddad89c898f9f90c9c819959812bac8 100644 --- a/lib/std/zig/Parse.zig +++ b/lib/std/zig/Parse.zig @@ -1552,34 +1552,47 @@ const PrecClass = struct { root, - /// For this to work correctly we require that all subgroups are strictly adjacent - /// Major groups are defined by the first text before an underscore - const Major: type = b: { - var major_names: []const []const u8 = &.{}; - for (std.meta.fieldNames(Group)) |fieldname| { - var major_name: []const u8 = fieldname[0..]; - for (fieldname, 0..) |c, i| { - if (c == '_') { - major_name = fieldname[0..i]; - break; - } - } - if (major_names.len == 0 or !std.mem.eql(u8, major_name, major_names[major_names.len - 1])) { - major_names = major_names ++ &[1][]const u8{major_name}; - } - } - - const IntType = std.math.IntFittingRange(0, major_names.len - 1); - var values: [major_names.len]IntType = undefined; - for (0..major_names.len) |i| values[i] = i; - - break :b @Enum( - IntType, - .exhaustive, - major_names, - &values, - ); + const Major = enum { + top, + arithmetic, + bitwise, + comparison, + bool, + recovery, + root, }; + + fn getMajor(group: Group) Major { + return switch (group) { + .top, + => .top, + + .arithmetic_product_chainable, + .arithmetic_mod_nonchainable, + .arithmetic_sum, + => .arithmetic, + + .bitwise_shift, + .bitwise_and, + .bitwise_xor, + .bitwise_or, + => .bitwise, + + .comparison, + => .comparison, + + .bool_and, + .bool_or, + => .bool, + + .recovery_orelse, + .recovery_catch, + => .recovery, + + .root, + => .root, + }; + } }; pub const start: PrecClass = .{ .group = .root }; @@ -1598,29 +1611,22 @@ const PrecClass = struct { fn setMajorRelation(prec_array: *PrecedenceArray, major_a: Group.Major, rel: Rel, major_b: Group.Major) void { for (std.meta.fieldNames(Group), 0..) |fieldname_i, i| { - if (!std.mem.startsWith(u8, fieldname_i, @tagName(major_a))) continue; + if (@field(Group, fieldname_i).getMajor() != major_a) continue; for (std.meta.fieldNames(Group), 0..) |fieldname_j, j| { - if (!std.mem.startsWith(u8, fieldname_j, @tagName(major_b))) continue; + if (@field(Group, fieldname_j).getMajor() != major_b) continue; - prec_array.*[i][j] = rel; - prec_array.*[j][i] = rel.inverted(); + prec_array[i][j] = rel; + prec_array[j][i] = rel.inverted(); } } } fn setMinorRelation(prec_array: *PrecedenceArray, minor_a: Group, rel: Rel, minor_b: Group) void { - prec_array.*[@backingInt(minor_a)][@backingInt(minor_b)] = rel; - prec_array.*[@backingInt(minor_b)][@backingInt(minor_a)] = rel.inverted(); + prec_array[@backingInt(minor_a)][@backingInt(minor_b)] = rel; + prec_array[@backingInt(minor_b)][@backingInt(minor_a)] = rel.inverted(); } - /// Arithmetic_* > Comparison - /// Bitwise_* > Comparison - /// Comparison > Bool_* > Root - /// Recovery > Root - /// - /// *_Product > *_Sum - /// /// order[y][x] --> y cmp x const precedence_ordering = b: { @setEvalBranchQuota(20_000); @@ -1646,7 +1652,7 @@ const PrecClass = struct { setMinorRelation(&order, .arithmetic_mod_nonchainable, .gt, .arithmetic_sum); setMinorRelation(&order, .arithmetic_product_chainable, .gt, .arithmetic_sum); - computeTransativeOrdering(&order); + computeTransitiveOrdering(&order); break :b order; }; @@ -1658,7 +1664,7 @@ const PrecClass = struct { /// == != < > <= >= /// and /// or - const v16_precedence_ordering = b: { + const v0_16_precedence_ordering = b: { @setEvalBranchQuota(20_000); var order: PrecedenceArray = @splat(@splat(null)); @@ -1685,7 +1691,7 @@ const PrecClass = struct { setMinorRelation(&order, .bool_or, .gt, .root); - computeTransativeOrdering(&order); + computeTransitiveOrdering(&order); for (order) |row| { for (row) |item| { if (item == null) @compileError("Null entry in old precedence ordering which had none."); @@ -1698,11 +1704,11 @@ const PrecClass = struct { return PrecClass.precedence_ordering[@backingInt(lhs.group)][@backingInt(rhs.group)]; } - pub fn v16_cmp(lhs: PrecClass, rhs: PrecClass) Rel { - return PrecClass.v16_precedence_ordering[@backingInt(lhs.group)][@backingInt(rhs.group)].?; + pub fn v0_16_cmp(lhs: PrecClass, rhs: PrecClass) Rel { + return PrecClass.v0_16_precedence_ordering[@backingInt(lhs.group)][@backingInt(rhs.group)].?; } - fn computeTransativeOrdering(order: *PrecedenceArray) void { + fn computeTransitiveOrdering(order: *PrecedenceArray) void { for (0..Group.num_distinct) |i| for (0..Group.num_distinct) |j| for (0..Group.num_distinct) |k| { if (order[i][j] == null or order[j][k] == null) continue; // X < Y < Z ==> X < Z X > Y > Z ==> X > Z @@ -1766,23 +1772,6 @@ const operTable = std.enums.directEnumArrayDefault(Token.Tag, OperInfo, .{ .prec // zig fmt: on }); -fn comptimePrecedenceFromNodeTag(comptime tag: Node.Tag) PrecClass { - for (operTable) |data| { - if (data.tag == tag) return data.prec; - } - return .{ .group = .top, .assoc = .left }; -} - -pub fn precedenceFromNodeTag(tag: Node.Tag) PrecClass { - return switch (tag) { - inline else => |ct_tag| comptimePrecedenceFromNodeTag(ct_tag), - }; -} - -pub fn newPrecedenceBetween(left_tok: Node.Tag, right_tok: Node.Tag) ?PrecClass.Rel { - return precedenceFromNodeTag(left_tok).cmp(precedenceFromNodeTag(right_tok)); -} - fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32) Error!?Node.Index { var node = try p.parsePrefixExpr() orelse return null; @@ -1793,10 +1782,9 @@ fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32 const info = operTable[@backingInt(tok_tag)]; const rel = info.prec.cmp(min_exc_prec) orelse b: { - // This issues warnings if the relation is null, which it never is in 0.16.0 const prev_op_tok_tag = p.tokenTag(prev_operator_token); const prev_op_info = operTable[@backingInt(prev_op_tok_tag)]; - const v16_rel = prev_op_info.prec.v16_cmp(info.prec); + const v0_16_rel = prev_op_info.prec.v0_16_cmp(info.prec); try p.warnMsg(.{ .tag = .ambiguous_operator_precedence, .is_note = false, @@ -1810,7 +1798,7 @@ fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32 .is_note = true, .token = prev_operator_token, }); - if (v16_rel == .gt or v16_rel == .eq) { + if (v0_16_rel == .gt or v0_16_rel == .eq) { try p.warnMsg(.{ .tag = .hint_operator_precedence_left, .is_note = true, @@ -1830,7 +1818,7 @@ fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32 }); } // Use the old precedence rules to construct the tree to ease automatic fixups - break :b info.prec.v16_cmp(min_exc_prec); + break :b info.prec.v0_16_cmp(min_exc_prec); }; if (rel == .lt) { @@ -1838,7 +1826,6 @@ fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32 } if (min_exc_prec.group == info.prec.group and min_exc_prec.assoc == .none and info.prec.assoc == .none) { - //Special cased check to maintain the old more helpful error for chained comparisons. if (info.prec.group == .comparison) { try p.warn(.chained_comparison_operators); } else {