diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index 9f32c6e54..e705aea47 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -1648,10 +1648,15 @@ pub const Node = struct { pub const SuffixOp = struct { base: Node, - lhs: *Node, + lhs: Lhs, op: Op, rtoken: TokenIndex, + pub const Lhs = union(enum) { + node: *Node, + dot: TokenIndex, + }; + pub const Op = union(enum) { Call: Call, ArrayAccess: *Node, @@ -1679,8 +1684,13 @@ pub const Node = struct { pub fn iterate(self: *SuffixOp, index: usize) ?*Node { var i = index; - if (i < 1) return self.lhs; - i -= 1; + switch (self.lhs) { + .node => |node| { + if (i == 0) return node; + i -= 1; + }, + .dot => {}, + } switch (self.op) { .Call => |*call_info| { @@ -1721,7 +1731,10 @@ pub const Node = struct { .Call => |*call_info| if (call_info.async_token) |async_token| return async_token, else => {}, } - return self.lhs.firstToken(); + switch (self.lhs) { + .node => |node| return node.firstToken(), + .dot => |dot| return dot, + } } pub fn lastToken(self: *const SuffixOp) TokenIndex { diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index 4c6c461c0..6d5d4b5f2 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -1026,16 +1026,16 @@ fn parseWhileExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// CurlySuffixExpr <- TypeExpr InitList? fn parseCurlySuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const type_expr = (try parseTypeExpr(arena, it, tree)) orelse return null; - const init_list = (try parseInitList(arena, it, tree)) orelse return type_expr; - init_list.cast(Node.SuffixOp).?.lhs = type_expr; - return init_list; + const suffix_op = (try parseInitList(arena, it, tree)) orelse return type_expr; + suffix_op.lhs.node = type_expr; + return &suffix_op.base; } /// InitList /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE /// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE /// / LBRACE RBRACE -fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { +fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.SuffixOp { const lbrace = eatToken(it, .LBrace) orelse return null; var init_list = Node.SuffixOp.Op.InitList.init(arena); @@ -1064,11 +1064,11 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = try arena.create(Node.SuffixOp); node.* = Node.SuffixOp{ .base = Node{ .id = .SuffixOp }, - .lhs = undefined, // set by caller + .lhs = .{.node = undefined}, // set by caller .op = op, .rtoken = try expectToken(it, tree, .RBrace), }; - return &node.base; + return node; } /// TypeExpr <- PrefixTypeOp* ErrorUnionExpr @@ -1117,7 +1117,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { while (try parseSuffixOp(arena, it, tree)) |node| { switch (node.id) { - .SuffixOp => node.cast(Node.SuffixOp).?.lhs = res, + .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{.node = res}, .InfixOp => node.cast(Node.InfixOp).?.lhs = res, else => unreachable, } @@ -1133,7 +1133,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = try arena.create(Node.SuffixOp); node.* = Node.SuffixOp{ .base = Node{ .id = .SuffixOp }, - .lhs = res, + .lhs = .{.node = res}, .op = Node.SuffixOp.Op{ .Call = Node.SuffixOp.Op.Call{ .params = params.list, @@ -1150,7 +1150,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { while (true) { if (try parseSuffixOp(arena, it, tree)) |node| { switch (node.id) { - .SuffixOp => node.cast(Node.SuffixOp).?.lhs = res, + .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{.node = res}, .InfixOp => node.cast(Node.InfixOp).?.lhs = res, else => unreachable, } @@ -1161,7 +1161,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const call = try arena.create(Node.SuffixOp); call.* = Node.SuffixOp{ .base = Node{ .id = .SuffixOp }, - .lhs = res, + .lhs = .{.node = res}, .op = Node.SuffixOp.Op{ .Call = Node.SuffixOp.Op.Call{ .params = params.list, @@ -1215,7 +1215,7 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N return &node.base; } if (try parseContainerDecl(arena, it, tree)) |node| return node; - if (try parseEnumLiteral(arena, it, tree)) |node| return node; + if (try parseAnonLiteral(arena, it, tree)) |node| return node; if (try parseErrorSetDecl(arena, it, tree)) |node| return node; if (try parseFloatLiteral(arena, it, tree)) |node| return node; if (try parseFnProto(arena, it, tree)) |node| return node; @@ -1494,16 +1494,28 @@ fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { } /// DOT IDENTIFIER -fn parseEnumLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { +fn parseAnonLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const dot = eatToken(it, .Period) orelse return null; - const name = try expectToken(it, tree, .Identifier); - const node = try arena.create(Node.EnumLiteral); - node.* = Node.EnumLiteral{ - .base = Node{ .id = .EnumLiteral }, - .dot = dot, - .name = name, - }; - return &node.base; + + // anon enum literal + if (eatToken(it, .Identifier)) |name| { + const node = try arena.create(Node.EnumLiteral); + node.* = Node.EnumLiteral{ + .base = Node{ .id = .EnumLiteral }, + .dot = dot, + .name = name, + }; + return &node.base; + } + + // anon container literal + if (try parseInitList(arena, it, tree)) |node| { + node.lhs = .{.dot = dot}; + return &node.base; + } + + putBackToken(it, dot); + return null; } /// AsmOutput <- COLON AsmOutputList AsmInput? diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index e9b4cd645..f61442adf 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -1,3 +1,20 @@ +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: async function" { try testCanonical( \\pub const Server = struct { diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index c6912087c..c82493929 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -538,9 +538,9 @@ fn renderExpression( try renderToken(tree, stream, async_token, indent, start_col, Space.Space); } - try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); + try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); - const lparen = tree.nextToken(suffix_op.lhs.lastToken()); + const lparen = tree.nextToken(suffix_op.lhs.node.lastToken()); if (call_info.params.len == 0) { try renderToken(tree, stream, lparen, indent, start_col, Space.None); @@ -598,7 +598,7 @@ fn renderExpression( const lbracket = tree.prevToken(index_expr.firstToken()); const rbracket = tree.nextToken(index_expr.lastToken()); - try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); + try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [ const starts_with_comment = tree.tokens.at(lbracket + 1).id == .LineComment; @@ -616,18 +616,18 @@ fn renderExpression( }, ast.Node.SuffixOp.Op.Deref => { - try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); + try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .* }, ast.Node.SuffixOp.Op.UnwrapOptional => { - try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); + try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // . return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ? }, @TagType(ast.Node.SuffixOp.Op).Slice => |range| { - try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); + try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); const lbracket = tree.prevToken(range.start.firstToken()); const dotdot = tree.nextToken(range.start.lastToken()); @@ -647,10 +647,16 @@ fn renderExpression( }, ast.Node.SuffixOp.Op.StructInitializer => |*field_inits| { - const lbrace = tree.nextToken(suffix_op.lhs.lastToken()); + const lbrace = switch (suffix_op.lhs) { + .dot => |dot| tree.nextToken(dot), + .node => |node| tree.nextToken(node.lastToken()), + }; if (field_inits.len == 0) { - try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); + switch (suffix_op.lhs) { + .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), + .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), + } try renderToken(tree, stream, lbrace, indent + indent_delta, start_col, Space.None); return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); } @@ -691,7 +697,10 @@ fn renderExpression( break :blk; } - try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); + switch (suffix_op.lhs) { + .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), + .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), + } try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); try renderExpression(allocator, stream, tree, indent, start_col, &field_init.base, Space.Space); return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); @@ -699,7 +708,10 @@ fn renderExpression( if (!src_has_trailing_comma and src_same_line and expr_outputs_one_line) { // render all on one line, no trailing comma - try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); + switch (suffix_op.lhs) { + .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), + .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), + } try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); var it = field_inits.iterator(0); @@ -719,7 +731,10 @@ fn renderExpression( const new_indent = indent + indent_delta; - try renderExpression(allocator, stream, tree, new_indent, start_col, suffix_op.lhs, Space.None); + switch (suffix_op.lhs) { + .dot => |dot| try renderToken(tree, stream, dot, new_indent, start_col, Space.None), + .node => |node| try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None), + } try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); var it = field_inits.iterator(0); @@ -743,23 +758,35 @@ fn renderExpression( }, ast.Node.SuffixOp.Op.ArrayInitializer => |*exprs| { - const lbrace = tree.nextToken(suffix_op.lhs.lastToken()); + const lbrace = switch (suffix_op.lhs) { + .dot => |dot| tree.nextToken(dot), + .node => |node| tree.nextToken(node.lastToken()), + }; if (exprs.len == 0) { - try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); + switch (suffix_op.lhs) { + .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), + .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), + } try renderToken(tree, stream, lbrace, indent, start_col, Space.None); return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); } if (exprs.len == 1 and tree.tokens.at(exprs.at(0).*.lastToken() + 1).id == .RBrace) { const expr = exprs.at(0).*; - try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); + switch (suffix_op.lhs) { + .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), + .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), + } try renderToken(tree, stream, lbrace, indent, start_col, Space.None); try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None); return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); } - try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); + switch (suffix_op.lhs) { + .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), + .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), + } // scan to find row size const maybe_row_size: ?usize = blk: {