Commit 6f3b93e2e8
Changed files (4)
lib
lib/std/zig/ast.zig
@@ -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}`.
lib/std/zig/parse.zig
@@ -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;
lib/std/zig/parser_test.zig
@@ -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 {
lib/std/zig/render.zig
@@ -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);