diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index 9f9064f88d..63c6168ed9 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -2204,7 +2204,7 @@ pub const Node = struct { }; pub const VarType = struct { - base: Node, + base: Node = Node{ .id = .VarType }, token: TokenIndex, pub fn iterate(self: *VarType, index: usize) ?*Node { diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index fd15cda11a..3ece8d150b 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -410,10 +410,16 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No var align_expr: ?*Node = null; var type_expr: ?*Node = null; if (eatToken(it, .Colon)) |_| { - type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ - .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, - }); - align_expr = try parseByteAlign(arena, it, tree); + if (eatToken(it, .Keyword_var)) |var_tok| { + const node = try arena.create(ast.Node.VarType); + node.* = .{ .token = var_tok }; + type_expr = &node.base; + } else { + type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ + .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, + }); + align_expr = try parseByteAlign(arena, it, tree); + } } const value_expr = if (eatToken(it, .Equal)) |_| @@ -576,7 +582,8 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node /// LabeledStatement <- BlockLabel? (Block / LoopStatement) fn parseLabeledStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - const label_token = parseBlockLabel(arena, it, tree); + var colon: TokenIndex = undefined; + const label_token = parseBlockLabel(arena, it, tree, &colon); if (try parseBlock(arena, it, tree)) |node| { node.cast(Node.Block).?.label = label_token; @@ -757,7 +764,8 @@ fn parseBlockExprStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) ! /// BlockExpr <- BlockLabel? Block fn parseBlockExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node { - const label_token = parseBlockLabel(arena, it, tree); + var colon: TokenIndex = undefined; + const label_token = parseBlockLabel(arena, it, tree, &colon); const block_node = (try parseBlock(arena, it, tree)) orelse { if (label_token) |label| { putBackToken(it, label + 1); // ":" @@ -913,7 +921,8 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node return &node.base; } - const label = parseBlockLabel(arena, it, tree); + var colon: TokenIndex = undefined; + const label = parseBlockLabel(arena, it, tree, &colon); if (try parseLoopExpr(arena, it, tree)) |node| { if (node.cast(Node.For)) |for_node| { for_node.label = label; @@ -1354,7 +1363,8 @@ fn parseIfTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// <- BlockLabel Block /// / BlockLabel? LoopTypeExpr fn parseLabeledTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - const label = parseBlockLabel(arena, it, tree); + var colon: TokenIndex = undefined; + const label = parseBlockLabel(arena, it, tree, &colon); if (label) |token| { if (try parseBlock(arena, it, tree)) |node| { @@ -1372,12 +1382,9 @@ fn parseLabeledTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N return node; } - if (label != null) { - // If we saw a label, there should have been a block next - try tree.errors.push(AstError{ - .ExpectedLBrace = AstError.ExpectedLBrace{ .token = it.index }, - }); - return error.ParseError; + if (label) |token| { + putBackToken(it, colon); + putBackToken(it, token); } return null; } @@ -1641,9 +1648,12 @@ fn parseBreakLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { } /// BlockLabel <- IDENTIFIER COLON -fn parseBlockLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree) ?TokenIndex { +fn parseBlockLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree, colon_token: *TokenIndex) ?TokenIndex { const identifier = eatToken(it, .Identifier) orelse return null; - if (eatToken(it, .Colon) != null) return identifier; + if (eatToken(it, .Colon)) |colon| { + colon_token.* = colon; + return identifier; + } putBackToken(it, identifier); return null; } diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index ce19588722..0d38ec5ccb 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -1,3 +1,30 @@ +test "zig fmt: var struct field" { + try testCanonical( + \\pub const Pointer = struct { + \\ sentinel: var, + \\}; + \\ + ); +} + +test "zig fmt: sentinel-terminated array type" { + try testCanonical( + \\pub fn cStrToPrefixedFileW(s: [*:0]const u8) ![PATH_MAX_WIDE:0]u16 { + \\ return sliceToPrefixedFileW(mem.toSliceConst(u8, s)); + \\} + \\ + ); +} + +test "zig fmt: sentinel-terminated slice type" { + try testCanonical( + \\pub fn toSlice(self: Buffer) [:0]u8 { + \\ return self.list.toSlice()[0..self.len()]; + \\} + \\ + ); +} + test "zig fmt: anon literal in array" { try testCanonical( \\var arr: [2]Foo = .{ diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index d6e2456455..1b6aaf7102 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -477,7 +477,14 @@ fn renderExpression( ast.Node.PrefixOp.Op.SliceType => |ptr_info| { try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None); // [ - try renderToken(tree, stream, tree.nextToken(prefix_op_node.op_token), indent, start_col, Space.None); // ] + if (ptr_info.sentinel) |sentinel| { + const colon_token = tree.prevToken(sentinel.firstToken()); + try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // : + try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None); + try renderToken(tree, stream, tree.nextToken(sentinel.lastToken()), indent, start_col, Space.None); // ] + } else { + try renderToken(tree, stream, tree.nextToken(prefix_op_node.op_token), indent, start_col, Space.None); // ] + } if (ptr_info.allowzero_token) |allowzero_token| { try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero