mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 14:25:16 +00:00
fmt: avoid canonicalizing enum fields named @"_" to _
This can be used to escape the usual meaning of `_` to indicate a
non-exhaustive enum and create an enum tag that is a literal underscore,
so zig fmt should allow this syntax.
Before, zig fmt changes
const E = enum { @"_" };
to the semantically different
const E = enum { _ };
After, it remains the same.
This commit is contained in:
parent
ff59c45840
commit
bac3a28214
@ -3511,3 +3511,7 @@ const Token = std.zig.Token;
|
||||
const Ast = @This();
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Parse = @import("Parse.zig");
|
||||
|
||||
test {
|
||||
testing.refAllDecls(@This());
|
||||
}
|
||||
|
||||
@ -5732,6 +5732,62 @@ test "zig fmt: canonicalize symbols (asm)" {
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: don't canonicalize _ in enums" {
|
||||
try testTransform(
|
||||
\\const A = enum {
|
||||
\\ first,
|
||||
\\ second,
|
||||
\\ third,
|
||||
\\ _,
|
||||
\\};
|
||||
\\const B = enum {
|
||||
\\ @"_",
|
||||
\\ @"__",
|
||||
\\ @"___",
|
||||
\\ @"____",
|
||||
\\};
|
||||
\\const C = struct {
|
||||
\\ @"_": u8,
|
||||
\\ @"__": u8,
|
||||
\\ @"___": u8,
|
||||
\\ @"____": u8,
|
||||
\\};
|
||||
\\const D = union {
|
||||
\\ @"_": u8,
|
||||
\\ @"__": u8,
|
||||
\\ @"___": u8,
|
||||
\\ @"____": u8,
|
||||
\\};
|
||||
\\
|
||||
,
|
||||
\\const A = enum {
|
||||
\\ first,
|
||||
\\ second,
|
||||
\\ third,
|
||||
\\ _,
|
||||
\\};
|
||||
\\const B = enum {
|
||||
\\ @"_",
|
||||
\\ __,
|
||||
\\ ___,
|
||||
\\ ____,
|
||||
\\};
|
||||
\\const C = struct {
|
||||
\\ _: u8,
|
||||
\\ __: u8,
|
||||
\\ ___: u8,
|
||||
\\ ____: u8,
|
||||
\\};
|
||||
\\const D = union {
|
||||
\\ _: u8,
|
||||
\\ __: u8,
|
||||
\\ ___: u8,
|
||||
\\ ____: u8,
|
||||
\\};
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: error for missing sentinel value in sentinel slice" {
|
||||
try testError(
|
||||
\\const foo = foo[0..:];
|
||||
|
||||
@ -40,27 +40,28 @@ pub fn renderTree(buffer: *std.ArrayList(u8), tree: Ast) Error!void {
|
||||
/// Render all members in the given slice, keeping empty lines where appropriate
|
||||
fn renderMembers(gpa: Allocator, ais: *Ais, tree: Ast, members: []const Ast.Node.Index) Error!void {
|
||||
if (members.len == 0) return;
|
||||
var is_tuple = true;
|
||||
for (members) |member| {
|
||||
const container_field = tree.fullContainerField(member) orelse continue;
|
||||
if (!container_field.ast.tuple_like) {
|
||||
is_tuple = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
try renderMember(gpa, ais, tree, members[0], is_tuple, .newline);
|
||||
const container: Container = for (members) |member| {
|
||||
if (tree.fullContainerField(member)) |field| if (!field.ast.tuple_like) break .other;
|
||||
} else .tuple;
|
||||
try renderMember(gpa, ais, tree, container, members[0], .newline);
|
||||
for (members[1..]) |member| {
|
||||
try renderExtraNewline(ais, tree, member);
|
||||
try renderMember(gpa, ais, tree, member, is_tuple, .newline);
|
||||
try renderMember(gpa, ais, tree, container, member, .newline);
|
||||
}
|
||||
}
|
||||
|
||||
const Container = enum {
|
||||
@"enum",
|
||||
tuple,
|
||||
other,
|
||||
};
|
||||
|
||||
fn renderMember(
|
||||
gpa: Allocator,
|
||||
ais: *Ais,
|
||||
tree: Ast,
|
||||
container: Container,
|
||||
decl: Ast.Node.Index,
|
||||
is_tuple: bool,
|
||||
space: Space,
|
||||
) Error!void {
|
||||
const token_tags = tree.tokens.items(.tag);
|
||||
@ -180,7 +181,7 @@ fn renderMember(
|
||||
.container_field_init,
|
||||
.container_field_align,
|
||||
.container_field,
|
||||
=> return renderContainerField(gpa, ais, tree, tree.fullContainerField(decl).?, is_tuple, space),
|
||||
=> return renderContainerField(gpa, ais, tree, container, tree.fullContainerField(decl).?, space),
|
||||
|
||||
.@"comptime" => return renderExpression(gpa, ais, tree, decl, space),
|
||||
|
||||
@ -1279,19 +1280,23 @@ fn renderContainerField(
|
||||
gpa: Allocator,
|
||||
ais: *Ais,
|
||||
tree: Ast,
|
||||
container: Container,
|
||||
field_param: Ast.full.ContainerField,
|
||||
is_tuple: bool,
|
||||
space: Space,
|
||||
) Error!void {
|
||||
var field = field_param;
|
||||
if (!is_tuple) field.convertToNonTupleLike(tree.nodes);
|
||||
if (container != .tuple) field.convertToNonTupleLike(tree.nodes);
|
||||
const quote: QuoteBehavior = switch (container) {
|
||||
.@"enum" => .eagerly_unquote_except_underscore,
|
||||
.tuple, .other => .eagerly_unquote,
|
||||
};
|
||||
|
||||
if (field.comptime_token) |t| {
|
||||
try renderToken(ais, tree, t, .space); // comptime
|
||||
}
|
||||
if (field.ast.type_expr == 0 and field.ast.value_expr == 0) {
|
||||
if (field.ast.align_expr != 0) {
|
||||
try renderIdentifier(ais, tree, field.ast.main_token, .space, .eagerly_unquote); // name
|
||||
try renderIdentifier(ais, tree, field.ast.main_token, .space, quote); // name
|
||||
const lparen_token = tree.firstToken(field.ast.align_expr) - 1;
|
||||
const align_kw = lparen_token - 1;
|
||||
const rparen_token = tree.lastToken(field.ast.align_expr) + 1;
|
||||
@ -1300,11 +1305,11 @@ fn renderContainerField(
|
||||
try renderExpression(gpa, ais, tree, field.ast.align_expr, .none); // alignment
|
||||
return renderToken(ais, tree, rparen_token, .space); // )
|
||||
}
|
||||
return renderIdentifierComma(ais, tree, field.ast.main_token, space, .eagerly_unquote); // name
|
||||
return renderIdentifierComma(ais, tree, field.ast.main_token, space, quote); // name
|
||||
}
|
||||
if (field.ast.type_expr != 0 and field.ast.value_expr == 0) {
|
||||
if (!field.ast.tuple_like) {
|
||||
try renderIdentifier(ais, tree, field.ast.main_token, .none, .eagerly_unquote); // name
|
||||
try renderIdentifier(ais, tree, field.ast.main_token, .none, quote); // name
|
||||
try renderToken(ais, tree, field.ast.main_token + 1, .space); // :
|
||||
}
|
||||
|
||||
@ -1321,7 +1326,7 @@ fn renderContainerField(
|
||||
}
|
||||
}
|
||||
if (field.ast.type_expr == 0 and field.ast.value_expr != 0) {
|
||||
try renderIdentifier(ais, tree, field.ast.main_token, .space, .eagerly_unquote); // name
|
||||
try renderIdentifier(ais, tree, field.ast.main_token, .space, quote); // name
|
||||
if (field.ast.align_expr != 0) {
|
||||
const lparen_token = tree.firstToken(field.ast.align_expr) - 1;
|
||||
const align_kw = lparen_token - 1;
|
||||
@ -1335,7 +1340,7 @@ fn renderContainerField(
|
||||
return renderExpressionComma(gpa, ais, tree, field.ast.value_expr, space); // value
|
||||
}
|
||||
if (!field.ast.tuple_like) {
|
||||
try renderIdentifier(ais, tree, field.ast.main_token, .none, .eagerly_unquote); // name
|
||||
try renderIdentifier(ais, tree, field.ast.main_token, .none, quote); // name
|
||||
try renderToken(ais, tree, field.ast.main_token + 1, .space); // :
|
||||
}
|
||||
try renderExpression(gpa, ais, tree, field.ast.type_expr, .space); // type
|
||||
@ -2054,13 +2059,12 @@ fn renderContainerDecl(
|
||||
try renderToken(ais, tree, layout_token, .space);
|
||||
}
|
||||
|
||||
var is_tuple = token_tags[container_decl.ast.main_token] == .keyword_struct;
|
||||
if (is_tuple) for (container_decl.ast.members) |member| {
|
||||
const container_field = tree.fullContainerField(member) orelse continue;
|
||||
if (!container_field.ast.tuple_like) {
|
||||
is_tuple = false;
|
||||
break;
|
||||
}
|
||||
const container: Container = switch (token_tags[container_decl.ast.main_token]) {
|
||||
.keyword_enum => .@"enum",
|
||||
.keyword_struct => for (container_decl.ast.members) |member| {
|
||||
if (tree.fullContainerField(member)) |field| if (!field.ast.tuple_like) break .other;
|
||||
} else .tuple,
|
||||
else => .other,
|
||||
};
|
||||
|
||||
var lbrace: Ast.TokenIndex = undefined;
|
||||
@ -2129,7 +2133,7 @@ fn renderContainerDecl(
|
||||
// Print all the declarations on the same line.
|
||||
try renderToken(ais, tree, lbrace, .space); // lbrace
|
||||
for (container_decl.ast.members) |member| {
|
||||
try renderMember(gpa, ais, tree, member, is_tuple, .space);
|
||||
try renderMember(gpa, ais, tree, container, member, .space);
|
||||
}
|
||||
return renderToken(ais, tree, rbrace, space); // rbrace
|
||||
}
|
||||
@ -2147,9 +2151,9 @@ fn renderContainerDecl(
|
||||
.container_field_init,
|
||||
.container_field_align,
|
||||
.container_field,
|
||||
=> try renderMember(gpa, ais, tree, member, is_tuple, .comma),
|
||||
=> try renderMember(gpa, ais, tree, container, member, .comma),
|
||||
|
||||
else => try renderMember(gpa, ais, tree, member, is_tuple, .newline),
|
||||
else => try renderMember(gpa, ais, tree, container, member, .newline),
|
||||
}
|
||||
}
|
||||
ais.popIndent();
|
||||
@ -2565,6 +2569,7 @@ fn renderSpace(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, lexeme_len: us
|
||||
const QuoteBehavior = enum {
|
||||
preserve_when_shadowing,
|
||||
eagerly_unquote,
|
||||
eagerly_unquote_except_underscore,
|
||||
};
|
||||
|
||||
fn renderIdentifier(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, space: Space, quote: QuoteBehavior) Error!void {
|
||||
@ -2589,7 +2594,9 @@ fn renderIdentifier(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, space: Sp
|
||||
// Special case for _ which would incorrectly be rejected by isValidId below.
|
||||
if (contents.len == 1 and contents[0] == '_') switch (quote) {
|
||||
.eagerly_unquote => return renderQuotedIdentifier(ais, tree, token_index, space, true),
|
||||
.preserve_when_shadowing => return renderQuotedIdentifier(ais, tree, token_index, space, false),
|
||||
.eagerly_unquote_except_underscore,
|
||||
.preserve_when_shadowing,
|
||||
=> return renderQuotedIdentifier(ais, tree, token_index, space, false),
|
||||
};
|
||||
|
||||
// Scan the entire name for characters that would (after un-escaping) be illegal in a symbol,
|
||||
@ -2653,7 +2660,9 @@ fn renderIdentifier(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, space: Sp
|
||||
return renderQuotedIdentifier(ais, tree, token_index, space, false);
|
||||
}
|
||||
if (primitives.isPrimitive(buf[0..buf_i])) switch (quote) {
|
||||
.eagerly_unquote => return renderQuotedIdentifier(ais, tree, token_index, space, true),
|
||||
.eagerly_unquote,
|
||||
.eagerly_unquote_except_underscore,
|
||||
=> return renderQuotedIdentifier(ais, tree, token_index, space, true),
|
||||
.preserve_when_shadowing => return renderQuotedIdentifier(ais, tree, token_index, space, false),
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user