zig fmt: struct and anon array initialization

This commit is contained in:
Isaac Freund 2021-02-05 13:15:42 +01:00 committed by Andrew Kelley
parent 3e960cfffe
commit 6f3b93e2e8
4 changed files with 302 additions and 247 deletions

View File

@ -212,8 +212,6 @@ pub const Tree = struct {
.Try,
.Await,
.OptionalType,
.ArrayInitDotTwo,
.ArrayInitDot,
.Switch,
.IfSimple,
.If,
@ -250,9 +248,12 @@ pub const Tree = struct {
.FnProto,
=> return main_tokens[n],
.ArrayInitDot,
.ArrayInitDotTwo,
.ArrayInitDotTwoComma,
.StructInitDot,
.StructInitDotTwo,
.StructInitDotTwoComma,
.StructInitDot,
=> return main_tokens[n] - 1,
.Catch,
@ -304,6 +305,7 @@ pub const Tree = struct {
.ArrayInitOne,
.ArrayInit,
.StructInitOne,
.StructInit,
.CallOne,
.Call,
.SwitchCaseOne,
@ -367,7 +369,6 @@ pub const Tree = struct {
.PtrTypeSentinel => unreachable, // TODO
.PtrType => unreachable, // TODO
.SliceType => unreachable, // TODO
.StructInit => unreachable, // TODO
.SwitchCaseMulti => unreachable, // TODO
.WhileSimple => unreachable, // TODO
.WhileCont => unreachable, // TODO
@ -506,6 +507,7 @@ pub const Tree = struct {
n = datas[n].rhs;
},
.ArrayInitDotTwo,
.BuiltinCallTwo,
.BlockTwo,
.StructInitDotTwo,
@ -519,7 +521,9 @@ pub const Tree = struct {
return main_tokens[n] + end_offset;
}
},
.StructInitDotTwoComma => {
.ArrayInitDotTwoComma,
.StructInitDotTwoComma,
=> {
end_offset += 2; // for the comma + rbrace
if (datas[n].rhs != 0) {
n = datas[n].rhs;
@ -590,13 +594,16 @@ pub const Tree = struct {
// require recursion due to the optional comma followed by rbrace.
// TODO follow the pattern set by StructInitDotTwoComma which will allow
// lastToken to work for all of these.
.ArrayInit => unreachable,
.ArrayInitOne => unreachable,
.ArrayInitDot => unreachable,
.StructInit => unreachable,
.StructInitOne => unreachable,
.StructInitDot => unreachable,
.ContainerFieldInit => unreachable,
.ContainerFieldAlign => unreachable,
.ContainerField => unreachable,
.ArrayInitDotTwo => unreachable, // TODO
.ArrayInitDot => unreachable, // TODO
.Switch => unreachable, // TODO
.If => unreachable, // TODO
.Continue => unreachable, // TODO
@ -606,9 +613,6 @@ pub const Tree = struct {
.Asm => unreachable, // TODO
.SliceOpen => unreachable, // TODO
.Slice => unreachable, // TODO
.ArrayInitOne => unreachable, // TODO
.ArrayInit => unreachable, // TODO
.StructInitOne => unreachable, // TODO
.SwitchCaseOne => unreachable, // TODO
.SwitchRange => unreachable, // TODO
.FnDecl => unreachable, // TODO
@ -618,7 +622,6 @@ pub const Tree = struct {
.PtrTypeSentinel => unreachable, // TODO
.PtrType => unreachable, // TODO
.SliceType => unreachable, // TODO
.StructInit => unreachable, // TODO
.SwitchCaseMulti => unreachable, // TODO
.WhileCont => unreachable, // TODO
.While => unreachable, // TODO
@ -863,6 +866,65 @@ pub const Tree = struct {
});
}
pub fn arrayInitOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) Full.ArrayInit {
assert(tree.nodes.items(.tag)[node] == .ArrayInitOne);
const data = tree.nodes.items(.data)[node];
buffer[0] = data.rhs;
const elements = if (data.rhs == 0) buffer[0..0] else buffer[0..1];
return .{
.ast = .{
.lbrace = tree.nodes.items(.main_token)[node],
.elements = elements,
.type_expr = data.lhs,
},
};
}
pub fn arrayInitDotTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) Full.ArrayInit {
assert(tree.nodes.items(.tag)[node] == .ArrayInitDotTwo or
tree.nodes.items(.tag)[node] == .ArrayInitDotTwoComma);
const data = tree.nodes.items(.data)[node];
buffer.* = .{ data.lhs, data.rhs };
const elements = if (data.rhs != 0)
buffer[0..2]
else if (data.lhs != 0)
buffer[0..1]
else
buffer[0..0];
return .{
.ast = .{
.lbrace = tree.nodes.items(.main_token)[node],
.elements = elements,
.type_expr = 0,
},
};
}
pub fn arrayInitDot(tree: Tree, node: Node.Index) Full.ArrayInit {
assert(tree.nodes.items(.tag)[node] == .ArrayInitDot);
const data = tree.nodes.items(.data)[node];
return .{
.ast = .{
.lbrace = tree.nodes.items(.main_token)[node],
.elements = tree.extra_data[data.lhs..data.rhs],
.type_expr = 0,
},
};
}
pub fn arrayInit(tree: Tree, node: Node.Index) Full.ArrayInit {
assert(tree.nodes.items(.tag)[node] == .ArrayInit);
const data = tree.nodes.items(.data)[node];
const elem_range = tree.extraData(data.rhs, Node.SubRange);
return .{
.ast = .{
.lbrace = tree.nodes.items(.main_token)[node],
.elements = tree.extra_data[elem_range.start..elem_range.end],
.type_expr = data.lhs,
},
};
}
fn fullVarDecl(tree: Tree, info: Full.VarDecl.Ast) Full.VarDecl {
const token_tags = tree.tokens.items(.tag);
var result: Full.VarDecl = .{
@ -1015,6 +1077,16 @@ pub const Full = struct {
type_expr: Node.Index,
};
};
pub const ArrayInit = struct {
ast: Ast,
pub const Ast = struct {
lbrace: TokenIndex,
elements: []const Node.Index,
type_expr: Node.Index,
};
};
};
pub const Error = union(enum) {
@ -1421,6 +1493,9 @@ pub const Node = struct {
ArrayInitOne,
/// `.{lhs, rhs}`. lhs and rhs can be omitted.
ArrayInitDotTwo,
/// Same as `ArrayInitDotTwo` except there is known to be a trailing comma
/// before the final rbrace.
ArrayInitDotTwoComma,
/// `.{a, b}`. `sub_list[lhs..rhs]`.
ArrayInitDot,
/// `lhs{a, b}`. `sub_range_list[rhs]`. lhs can be omitted which means `.{a, b}`.

View File

@ -2536,7 +2536,7 @@ const Parser = struct {
const comma_one = p.eatToken(.Comma);
if (p.eatToken(.RBrace)) |_| {
return p.addNode(.{
.tag = .ArrayInitDotTwo,
.tag = if (comma_one != null) .ArrayInitDotTwoComma else .ArrayInitDotTwo,
.main_token = lbrace,
.data = .{
.lhs = elem_init_one,
@ -2553,7 +2553,7 @@ const Parser = struct {
const comma_two = p.eatToken(.Comma);
if (p.eatToken(.RBrace)) |_| {
return p.addNode(.{
.tag = .ArrayInitDotTwo,
.tag = if (comma_one != null) .ArrayInitDotTwoComma else .ArrayInitDotTwo,
.main_token = lbrace,
.data = .{
.lhs = elem_init_one,
@ -2576,7 +2576,10 @@ const Parser = struct {
if (next == 0) break;
try init_list.append(next);
switch (p.token_tags[p.nextToken()]) {
.Comma => continue,
.Comma => {
if (p.eatToken(.RBrace)) |_| break;
continue;
},
.RBrace => break,
.Colon, .RParen, .RBracket => {
p.tok_i -= 1;

View File

@ -336,24 +336,160 @@ test "zig fmt: nosuspend block" {
// \\
// );
//}
//
//test "zig fmt: anon struct literal syntax" {
// try testCanonical(
// \\const x = .{
// \\ .a = b,
// \\ .c = d,
// \\};
// \\
// );
//}
//
//test "zig fmt: anon list literal syntax" {
// try testCanonical(
// \\const x = .{ a, b, c };
// \\
// );
//}
//
test "zig fmt: anon struct literal 1 element" {
try testCanonical(
\\const x = .{ .a = b };
\\
);
}
test "zig fmt: anon struct literal 1 element comma" {
try testCanonical(
\\const x = .{
\\ .a = b,
\\};
\\
);
}
test "zig fmt: anon struct literal 2 element" {
try testCanonical(
\\const x = .{ .a = b, .c = d };
\\
);
}
test "zig fmt: anon struct literal 2 element comma" {
try testCanonical(
\\const x = .{
\\ .a = b,
\\ .c = d,
\\};
\\
);
}
test "zig fmt: anon struct literal 3 element" {
try testCanonical(
\\const x = .{ .a = b, .c = d, .e = f };
\\
);
}
test "zig fmt: anon struct literal 3 element comma" {
try testCanonical(
\\const x = .{
\\ .a = b,
\\ .c = d,
\\ .e = f,
\\};
\\
);
}
test "zig fmt: struct literal 1 element" {
try testCanonical(
\\const x = X{ .a = b };
\\
);
}
test "zig fmt: struct literal 1 element comma" {
try testCanonical(
\\const x = X{
\\ .a = b,
\\};
\\
);
}
test "zig fmt: struct literal 2 element" {
try testCanonical(
\\const x = X{ .a = b, .c = d };
\\
);
}
test "zig fmt: struct literal 2 element comma" {
try testCanonical(
\\const x = X{
\\ .a = b,
\\ .c = d,
\\};
\\
);
}
test "zig fmt: struct literal 3 element" {
try testCanonical(
\\const x = X{ .a = b, .c = d, .e = f };
\\
);
}
test "zig fmt: struct literal 3 element comma" {
try testCanonical(
\\const x = X{
\\ .a = b,
\\ .c = d,
\\ .e = f,
\\};
\\
);
}
test "zig fmt: anon list literal 1 element" {
try testCanonical(
\\const x = .{a};
\\
);
}
test "zig fmt: anon list literal 1 element comma" {
try testCanonical(
\\const x = .{
\\ a,
\\};
\\
);
}
test "zig fmt: anon list literal 2 element" {
try testCanonical(
\\const x = .{ a, b };
\\
);
}
test "zig fmt: anon list literal 2 element comma" {
try testCanonical(
\\const x = .{
\\ a,
\\ b,
\\};
\\
);
}
test "zig fmt: anon list literal 3 element" {
try testCanonical(
\\const x = .{ a, b, c };
\\
);
}
test "zig fmt: anon list literal 3 element comma" {
try testCanonical(
\\const x = .{
\\ a,
\\ b,
\\ c,
\\};
\\
);
}
//test "zig fmt: async function" {
// try testCanonical(
// \\pub const Server = struct {

View File

@ -503,221 +503,16 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
// return renderExpression(ais, tree, slice_type.rhs, space);
//},
.ArrayInitOne => unreachable, // TODO
.ArrayInitDotTwo => unreachable, // TODO
.ArrayInitDot => unreachable, // TODO
.ArrayInit => unreachable, // TODO
//.ArrayInitializer, .ArrayInitializerDot => {
// var rtoken: ast.TokenIndex = undefined;
// var exprs: []ast.Node.Index = undefined;
// const lhs: union(enum) { dot: ast.TokenIndex, node: ast.Node.Index } = switch (base.tag) {
// .ArrayInitializerDot => blk: {
// const casted = @fieldParentPtr(ast.Node.ArrayInitializerDot, "base", base);
// rtoken = casted.rtoken;
// exprs = casted.list();
// break :blk .{ .dot = casted.dot };
// },
// .ArrayInitializer => blk: {
// const casted = @fieldParentPtr(ast.Node.ArrayInitializer, "base", base);
// rtoken = casted.rtoken;
// exprs = casted.list();
// break :blk .{ .node = casted.lhs };
// },
// else => unreachable,
// };
// const lbrace = switch (lhs) {
// .dot => |dot| tree.nextToken(dot),
// .node => |node| tree.nextToken(node.lastToken()),
// };
// switch (lhs) {
// .dot => |dot| try renderToken(ais, tree, dot, Space.None),
// .node => |node| try renderExpression(ais, tree, node, Space.None),
// }
// if (exprs.len == 0) {
// try renderToken(ais, tree, lbrace, Space.None);
// return renderToken(ais, tree, rtoken, space);
// }
// if (exprs.len == 1 and exprs[0].tag != .MultilineStringLiteral and tree.token_tags[exprs[0].*.lastToken() + 1] == .RBrace) {
// const expr = exprs[0];
// try renderToken(ais, tree, lbrace, Space.None);
// try renderExpression(ais, tree, expr, Space.None);
// return renderToken(ais, tree, rtoken, space);
// }
// // scan to find row size
// if (rowSize(tree, exprs, rtoken) != null) {
// {
// ais.pushIndentNextLine();
// defer ais.popIndent();
// try renderToken(ais, tree, lbrace, Space.Newline);
// var expr_index: usize = 0;
// while (rowSize(tree, exprs[expr_index..], rtoken)) |row_size| {
// const row_exprs = exprs[expr_index..];
// // A place to store the width of each expression and its column's maximum
// var widths = try allocator.alloc(usize, row_exprs.len + row_size);
// defer allocator.free(widths);
// mem.set(usize, widths, 0);
// var expr_newlines = try allocator.alloc(bool, row_exprs.len);
// defer allocator.free(expr_newlines);
// mem.set(bool, expr_newlines, false);
// var expr_widths = widths[0 .. widths.len - row_size];
// var column_widths = widths[widths.len - row_size ..];
// // Find next row with trailing comment (if any) to end the current section
// var section_end = sec_end: {
// var this_line_first_expr: usize = 0;
// var this_line_size = rowSize(tree, row_exprs, rtoken);
// for (row_exprs) |expr, i| {
// // Ignore comment on first line of this section
// if (i == 0 or tree.tokensOnSameLine(row_exprs[0].firstToken(), expr.lastToken())) continue;
// // Track start of line containing comment
// if (!tree.tokensOnSameLine(row_exprs[this_line_first_expr].firstToken(), expr.lastToken())) {
// this_line_first_expr = i;
// this_line_size = rowSize(tree, row_exprs[this_line_first_expr..], rtoken);
// }
// const maybe_comma = expr.lastToken() + 1;
// const maybe_comment = expr.lastToken() + 2;
// if (maybe_comment < tree.token_tags.len) {
// if (tree.token_tags[maybe_comma] == .Comma and
// tree.token_tags[maybe_comment] == .LineComment and
// tree.tokensOnSameLine(expr.lastToken(), maybe_comment))
// {
// var comment_token_loc = tree.token_locs[maybe_comment];
// const comment_is_empty = mem.trimRight(u8, tree.tokenSliceLoc(comment_token_loc), " ").len == 2;
// if (!comment_is_empty) {
// // Found row ending in comment
// break :sec_end i - this_line_size.? + 1;
// }
// }
// }
// }
// break :sec_end row_exprs.len;
// };
// expr_index += section_end;
// const section_exprs = row_exprs[0..section_end];
// // Null stream for counting the printed length of each expression
// var line_find_stream = std.io.findByteWriter('\n', std.io.null_writer);
// var counting_stream = std.io.countingWriter(line_find_stream.writer());
// var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, counting_stream.writer());
// // Calculate size of columns in current section
// var column_counter: usize = 0;
// var single_line = true;
// for (section_exprs) |expr, i| {
// if (i + 1 < section_exprs.len) {
// counting_stream.bytes_written = 0;
// line_find_stream.byte_found = false;
// try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
// const width = @intCast(usize, counting_stream.bytes_written);
// expr_widths[i] = width;
// expr_newlines[i] = line_find_stream.byte_found;
// if (!line_find_stream.byte_found) {
// const column = column_counter % row_size;
// column_widths[column] = std.math.max(column_widths[column], width);
// const expr_last_token = expr.*.lastToken() + 1;
// const next_expr = section_exprs[i + 1];
// const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, next_expr.*.firstToken());
// column_counter += 1;
// if (loc.line != 0) single_line = false;
// } else {
// single_line = false;
// column_counter = 0;
// }
// } else {
// counting_stream.bytes_written = 0;
// try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
// const width = @intCast(usize, counting_stream.bytes_written);
// expr_widths[i] = width;
// expr_newlines[i] = line_find_stream.byte_found;
// if (!line_find_stream.byte_found) {
// const column = column_counter % row_size;
// column_widths[column] = std.math.max(column_widths[column], width);
// }
// break;
// }
// }
// // Render exprs in current section
// column_counter = 0;
// var last_col_index: usize = row_size - 1;
// for (section_exprs) |expr, i| {
// if (i + 1 < section_exprs.len) {
// const next_expr = section_exprs[i + 1];
// try renderExpression(ais, tree, expr, Space.None);
// const comma = tree.nextToken(expr.*.lastToken());
// if (column_counter != last_col_index) {
// if (!expr_newlines[i] and !expr_newlines[i + 1]) {
// // Neither the current or next expression is multiline
// try renderToken(ais, tree, comma, Space.Space); // ,
// assert(column_widths[column_counter % row_size] >= expr_widths[i]);
// const padding = column_widths[column_counter % row_size] - expr_widths[i];
// try ais.writer().writeByteNTimes(' ', padding);
// column_counter += 1;
// continue;
// }
// }
// if (single_line and row_size != 1) {
// try renderToken(ais, tree, comma, Space.Space); // ,
// continue;
// }
// column_counter = 0;
// try renderToken(ais, tree, comma, Space.Newline); // ,
// try renderExtraNewline(ais, tree, next_expr);
// } else {
// const maybe_comma = tree.nextToken(expr.*.lastToken());
// if (tree.token_tags[maybe_comma] == .Comma) {
// try renderExpression(ais, tree, expr, Space.None); // ,
// try renderToken(ais, tree, maybe_comma, Space.Newline); // ,
// } else {
// try renderExpression(ais, tree, expr, Space.Comma); // ,
// }
// }
// }
// if (expr_index == exprs.len) {
// break;
// }
// }
// }
// return renderToken(ais, tree, rtoken, space);
// }
// // Single line
// try renderToken(ais, tree, lbrace, Space.Space);
// for (exprs) |expr, i| {
// if (i + 1 < exprs.len) {
// const next_expr = exprs[i + 1];
// try renderExpression(ais, tree, expr, Space.None);
// const comma = tree.nextToken(expr.*.lastToken());
// try renderToken(ais, tree, comma, Space.Space); // ,
// } else {
// try renderExpression(ais, tree, expr, Space.Space);
// }
// }
// return renderToken(ais, tree, rtoken, space);
//},
.ArrayInitOne => {
var elements: [1]ast.Node.Index = undefined;
return renderArrayInit(ais, tree, tree.arrayInitOne(&elements, node), space);
},
.ArrayInitDotTwo, .ArrayInitDotTwoComma => {
var elements: [2]ast.Node.Index = undefined;
return renderArrayInit(ais, tree, tree.arrayInitDotTwo(&elements, node), space);
},
.ArrayInitDot => return renderArrayInit(ais, tree, tree.arrayInitDot(node), space),
.ArrayInit => return renderArrayInit(ais, tree, tree.arrayInit(node), space),
.StructInitOne => {
var fields: [1]ast.Node.Index = undefined;
@ -2158,6 +1953,52 @@ fn renderStructInit(
}
}
fn renderArrayInit(
ais: *Ais,
tree: ast.Tree,
array_init: ast.Full.ArrayInit,
space: Space,
) Error!void {
const token_tags = tree.tokens.items(.tag);
if (array_init.ast.type_expr == 0) {
try renderToken(ais, tree, array_init.ast.lbrace - 1, .None); // .
} else {
try renderExpression(ais, tree, array_init.ast.type_expr, .None); // T
}
if (array_init.ast.elements.len == 0) {
try renderToken(ais, tree, array_init.ast.lbrace, .None); // lbrace
return renderToken(ais, tree, array_init.ast.lbrace + 1, space); // rbrace
}
const last_elem = array_init.ast.elements[array_init.ast.elements.len - 1];
const last_elem_token = tree.lastToken(last_elem);
if (token_tags[last_elem_token + 1] == .Comma) {
// Render one element per line.
ais.pushIndent();
try renderToken(ais, tree, array_init.ast.lbrace, .Newline);
try renderExpression(ais, tree, array_init.ast.elements[0], .Comma);
for (array_init.ast.elements[1..]) |elem| {
try renderExpressionNewlined(ais, tree, elem, .Comma);
}
ais.popIndent();
return renderToken(ais, tree, last_elem_token + 2, space); // rbrace
} else {
// Render all on one line, no trailing comma.
if (array_init.ast.elements.len == 1) {
// If there is only one element, we don't use spaces
try renderToken(ais, tree, array_init.ast.lbrace, .None);
try renderExpression(ais, tree, array_init.ast.elements[0], .None);
} else {
try renderToken(ais, tree, array_init.ast.lbrace, .Space);
for (array_init.ast.elements) |elem| {
try renderExpression(ais, tree, elem, .CommaSpace);
}
}
return renderToken(ais, tree, last_elem_token + 1, space); // rbrace
}
}
/// Render an expression, and the comma that follows it, if it is present in the source.
fn renderExpressionComma(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Space) Error!void {
const token_tags = tree.tokens.items(.tag);