diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index 483ae26956..1780cc4f8d 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -255,6 +255,7 @@ pub const Tree = struct { => return main_tokens[n] - end_offset, .ArrayInitDot, + .ArrayInitDotComma, .ArrayInitDotTwo, .ArrayInitDotTwoComma, .StructInitDot, @@ -311,7 +312,9 @@ pub const Tree = struct { .Deref, .ArrayAccess, .ArrayInitOne, + .ArrayInitOneComma, .ArrayInit, + .ArrayInitComma, .StructInitOne, .StructInit, .CallOne, @@ -604,6 +607,13 @@ pub const Tree = struct { const extra = tree.extraData(datas[n].rhs, Node.Asm); return extra.rparen + end_offset; }, + .ArrayInit => { + const elements = tree.extraData(datas[n].rhs, Node.SubRange); + assert(elements.end - elements.start > 0); + end_offset += 1; // for the rbrace + n = tree.extra_data[elements.end - 1]; // last element + }, + .ArrayInitComma, .ContainerDeclArgComma, .SwitchComma, => { @@ -612,6 +622,7 @@ pub const Tree = struct { end_offset += 2; // for the comma + rbrace n = tree.extra_data[members.end - 1]; // last parameter }, + .ArrayInitDot, .Block, .ContainerDecl, .TaggedUnion, @@ -621,6 +632,7 @@ pub const Tree = struct { end_offset += 1; // for the rbrace n = tree.extra_data[datas[n].rhs - 1]; // last statement }, + .ArrayInitDotComma, .BlockSemicolon, .ContainerDeclComma, .TaggedUnionComma, @@ -772,7 +784,16 @@ pub const Tree = struct { } }, - .SliceOpen, .CallOneComma, .AsyncCallOneComma => { + .ArrayInitOne => { + end_offset += 1; // rbrace + n = datas[n].rhs; + assert(n != 0); + }, + .SliceOpen, + .CallOneComma, + .AsyncCallOneComma, + .ArrayInitOneComma, + => { end_offset += 2; // ellipsis2 + rbracket, or comma + rparen n = datas[n].rhs; assert(n != 0); @@ -912,9 +933,6 @@ 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, // TODO - .ArrayInitOne => unreachable, // TODO - .ArrayInitDot => unreachable, // TODO .StructInit => unreachable, // TODO .StructInitOne => unreachable, // TODO .StructInitDot => unreachable, // TODO @@ -1151,7 +1169,8 @@ 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); + assert(tree.nodes.items(.tag)[node] == .ArrayInitOne or + tree.nodes.items(.tag)[node] == .ArrayInitOneComma); const data = tree.nodes.items(.data)[node]; buffer[0] = data.rhs; const elements = if (data.rhs == 0) buffer[0..0] else buffer[0..1]; @@ -1185,7 +1204,8 @@ pub const Tree = struct { } pub fn arrayInitDot(tree: Tree, node: Node.Index) full.ArrayInit { - assert(tree.nodes.items(.tag)[node] == .ArrayInitDot); + assert(tree.nodes.items(.tag)[node] == .ArrayInitDot or + tree.nodes.items(.tag)[node] == .ArrayInitDotComma); const data = tree.nodes.items(.data)[node]; return .{ .ast = .{ @@ -1197,7 +1217,8 @@ pub const Tree = struct { } pub fn arrayInit(tree: Tree, node: Node.Index) full.ArrayInit { - assert(tree.nodes.items(.tag)[node] == .ArrayInit); + assert(tree.nodes.items(.tag)[node] == .ArrayInit or + tree.nodes.items(.tag)[node] == .ArrayInitComma); const data = tree.nodes.items(.data)[node]; const elem_range = tree.extraData(data.rhs, Node.SubRange); return .{ @@ -2436,6 +2457,8 @@ pub const Node = struct { ArrayAccess, /// `lhs{rhs}`. rhs can be omitted. ArrayInitOne, + /// `lhs{rhs,}`. rhs can *not* be omitted + ArrayInitOneComma, /// `.{lhs, rhs}`. lhs and rhs can be omitted. ArrayInitDotTwo, /// Same as `ArrayInitDotTwo` except there is known to be a trailing comma @@ -2443,8 +2466,14 @@ pub const Node = struct { ArrayInitDotTwoComma, /// `.{a, b}`. `sub_list[lhs..rhs]`. ArrayInitDot, + /// Same as `ArrayInitDot` except there is known to be a trailing comma + /// before the final rbrace. + ArrayInitDotComma, /// `lhs{a, b}`. `sub_range_list[rhs]`. lhs can be omitted which means `.{a, b}`. ArrayInit, + /// Same as `ArrayInit` except there is known to be a trailing comma + /// before the final rbrace. + ArrayInitComma, /// `lhs{.a = rhs}`. rhs can be omitted making it empty. /// main_token is the lbrace. StructInitOne, diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index 4571ece0e8..9c07ad320a 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -2205,9 +2205,10 @@ const Parser = struct { } const elem_init = try p.expectExpr(); + const comma_one = p.eatToken(.Comma); if (p.eatToken(.RBrace)) |_| { return p.addNode(.{ - .tag = .ArrayInitOne, + .tag = if (comma_one != null) .ArrayInitOneComma else .ArrayInitOne, .main_token = lbrace, .data = .{ .lhs = lhs, @@ -2215,21 +2216,30 @@ const Parser = struct { }, }); } + if (comma_one == null) { + try p.warn(.{ + .ExpectedToken = .{ .token = p.tok_i, .expected_id = .Comma }, + }); + } var init_list = std.ArrayList(Node.Index).init(p.gpa); defer init_list.deinit(); try init_list.append(elem_init); - while (p.eatToken(.Comma)) |_| { - const next = try p.parseExpr(); - if (next == 0) break; + var trailing_comma = true; + var next = try p.parseExpr(); + while (next != 0) : (next = try p.parseExpr()) { try init_list.append(next); + if (p.eatToken(.Comma) == null) { + trailing_comma = false; + break; + } } _ = try p.expectToken(.RBrace); const span = try p.listToSpan(init_list.items); return p.addNode(.{ - .tag = .ArrayInit, + .tag = if (trailing_comma) .ArrayInitComma else .ArrayInit, .main_token = lbrace, .data = .{ .lhs = lhs, @@ -2805,7 +2815,7 @@ const Parser = struct { const comma_two = p.eatToken(.Comma); if (p.eatToken(.RBrace)) |_| { return p.addNode(.{ - .tag = if (comma_one != null) .ArrayInitDotTwoComma else .ArrayInitDotTwo, + .tag = if (comma_two != null) .ArrayInitDotTwoComma else .ArrayInitDotTwo, .main_token = lbrace, .data = .{ .lhs = elem_init_one, @@ -2855,7 +2865,7 @@ const Parser = struct { } const span = try p.listToSpan(init_list.items); return p.addNode(.{ - .tag = .ArrayInitDot, + .tag = if (p.token_tags[p.tok_i - 2] == .Comma) .ArrayInitDotComma else .ArrayInitDot, .main_token = lbrace, .data = .{ .lhs = span.start, diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 9eb7ecadba..3b0afff9a7 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -568,109 +568,135 @@ test "zig fmt: struct literal 3 element comma" { test "zig fmt: anon list literal 1 element" { try testCanonical( - \\const x = .{a}; + \\test { + \\ const x = .{a}; + \\} \\ ); } test "zig fmt: anon list literal 1 element comma" { try testCanonical( - \\const x = .{ - \\ a, - \\}; + \\test { + \\ const x = .{ + \\ a, + \\ }; + \\} \\ ); } test "zig fmt: anon list literal 2 element" { try testCanonical( - \\const x = .{ a, b }; + \\test { + \\ const x = .{ a, b }; + \\} \\ ); } test "zig fmt: anon list literal 2 element comma" { try testCanonical( - \\const x = .{ - \\ a, - \\ b, - \\}; + \\test { + \\ const x = .{ + \\ a, + \\ b, + \\ }; + \\} \\ ); } test "zig fmt: anon list literal 3 element" { try testCanonical( - \\const x = .{ a, b, c }; + \\test { + \\ const x = .{ a, b, c }; + \\} \\ ); } test "zig fmt: anon list literal 3 element comma" { try testCanonical( - \\const x = .{ - \\ a, - \\ b, - \\ c, - \\}; + \\test { + \\ const x = .{ + \\ a, + \\ b, + \\ c, + \\ }; + \\} \\ ); } test "zig fmt: array literal 1 element" { try testCanonical( - \\const x = [_]u32{a}; + \\test { + \\ const x = [_]u32{a}; + \\} \\ ); } test "zig fmt: array literal 1 element comma" { try testCanonical( - \\const x = [1]u32{ - \\ a, - \\}; + \\test { + \\ const x = [1]u32{ + \\ a, + \\ }; + \\} \\ ); } test "zig fmt: array literal 2 element" { try testCanonical( - \\const x = [_]u32{ a, b }; + \\test { + \\ const x = [_]u32{ a, b }; + \\} \\ ); } test "zig fmt: array literal 2 element comma" { try testCanonical( - \\const x = [2]u32{ - \\ a, - \\ b, - \\}; + \\test { + \\ const x = [2]u32{ + \\ a, + \\ b, + \\ }; + \\} \\ ); } test "zig fmt: array literal 3 element" { try testCanonical( - \\const x = [_]u32{ a, b, c }; + \\test { + \\ const x = [_]u32{ a, b, c }; + \\} \\ ); } test "zig fmt: array literal 3 element comma" { try testCanonical( - \\const x = [3]u32{ - \\ a, - \\ b, - \\ c, - \\}; + \\test { + \\ const x = [3]u32{ + \\ a, + \\ b, + \\ c, + \\ }; + \\} \\ ); } test "zig fmt: sentinel array literal 1 element" { try testCanonical( - \\const x = [_:9000]u32{a}; + \\test { + \\ const x = [_:9000]u32{a}; + \\} \\ ); } diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 1be114a6a1..cc80b04d38 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -390,7 +390,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac .PtrType => return renderPtrType(ais, tree, tree.ptrType(node), space), .PtrTypeBitRange => return renderPtrType(ais, tree, tree.ptrTypeBitRange(node), space), - .ArrayInitOne => { + .ArrayInitOne, .ArrayInitOneComma => { var elements: [1]ast.Node.Index = undefined; return renderArrayInit(ais, tree, tree.arrayInitOne(&elements, node), space); }, @@ -398,8 +398,12 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac 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), + .ArrayInitDot, + .ArrayInitDotComma, + => return renderArrayInit(ais, tree, tree.arrayInitDot(node), space), + .ArrayInit, + .ArrayInitComma, + => return renderArrayInit(ais, tree, tree.arrayInit(node), space), .StructInitOne => { var fields: [1]ast.Node.Index = undefined;