diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index 182422f179..6e31555ca3 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -1552,28 +1552,35 @@ pub const Node = struct { } }; + /// Items sub-nodes appear in memory directly following SwitchCase. pub const SwitchCase = struct { base: Node = Node{ .id = .SwitchCase }, - items: ItemList, arrow_token: TokenIndex, payload: ?*Node, expr: *Node, + items_len: NodeIndex, - pub const ItemList = LinkedList(*Node); + /// After this the caller must initialize the fields_and_decls list. + pub fn alloc(allocator: *mem.Allocator, items_len: NodeIndex) !*SwitchCase { + const bytes = try allocator.alignedAlloc(u8, @alignOf(SwitchCase), sizeInBytes(items_len)); + return @ptrCast(*SwitchCase, bytes.ptr); + } + + pub fn free(self: *SwitchCase, allocator: *mem.Allocator) void { + const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.items_len)]; + allocator.free(bytes); + } pub fn iterate(self: *const SwitchCase) Node.Iterator { - return .{ .parent_node = &self.base, .index = 0, .node = self.items.first }; + return .{ .parent_node = &self.base, .index = 0, .node = null }; } pub fn iterateNext(self: *const SwitchCase, it: *Node.Iterator) ?*Node { var i = it.index; it.index += 1; - if (it.node) |child| { - it.index -= 1; - it.node = child.next; - return child.data; - } + if (i < self.items_len) return self.itemsConst()[i]; + i -= self.items_len; if (self.payload) |payload| { if (i < 1) return payload; @@ -1587,12 +1594,26 @@ pub const Node = struct { } pub fn firstToken(self: *const SwitchCase) TokenIndex { - return self.items.first.?.data.firstToken(); + return self.itemsConst()[0].firstToken(); } pub fn lastToken(self: *const SwitchCase) TokenIndex { return self.expr.lastToken(); } + + pub fn items(self: *SwitchCase) []*Node { + const decls_start = @ptrCast([*]u8, self) + @sizeOf(SwitchCase); + return @ptrCast([*]*Node, decls_start)[0..self.items_len]; + } + + pub fn itemsConst(self: *const SwitchCase) []const *Node { + const decls_start = @ptrCast([*]const u8, self) + @sizeOf(SwitchCase); + return @ptrCast([*]const *Node, decls_start)[0..self.items_len]; + } + + fn sizeInBytes(items_len: NodeIndex) usize { + return @sizeOf(SwitchCase) + @sizeOf(*Node) * @as(usize, items_len); + } }; pub const SwitchElse = struct { diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index 873d2cc252..3c7f0cf06e 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -2205,30 +2205,31 @@ const Parser = struct { /// <- SwitchItem (COMMA SwitchItem)* COMMA? /// / KEYWORD_else fn parseSwitchCase(p: *Parser) !?*Node { - var list = Node.SwitchCase.ItemList{}; - var list_it = &list.first; + var list = std.ArrayList(*Node).init(p.gpa); + defer list.deinit(); if (try p.parseSwitchItem()) |first_item| { - list_it = try p.llpush(*Node, list_it, first_item); + try list.append(first_item); while (p.eatToken(.Comma) != null) { const next_item = (try p.parseSwitchItem()) orelse break; - list_it = try p.llpush(*Node, list_it, next_item); + try list.append(next_item); } } else if (p.eatToken(.Keyword_else)) |else_token| { const else_node = try p.arena.allocator.create(Node.SwitchElse); else_node.* = .{ .token = else_token, }; - list_it = try p.llpush(*Node, list_it, &else_node.base); + try list.append(&else_node.base); } else return null; - const node = try p.arena.allocator.create(Node.SwitchCase); + const node = try Node.SwitchCase.alloc(&p.arena.allocator, list.items.len); node.* = .{ - .items = list, + .items_len = list.items.len, .arrow_token = undefined, // set by caller .payload = null, .expr = undefined, // set by caller }; + std.mem.copy(*Node, node.items(), list.items); return &node.base; } diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 3241f55a38..97ce9617c3 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -1613,37 +1613,35 @@ fn renderExpression( .SwitchCase => { const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base); - assert(switch_case.items.first != null); + assert(switch_case.items_len != 0); const src_has_trailing_comma = blk: { - const last_node = switch_case.items.first.?.findLast().data; + const last_node = switch_case.items()[switch_case.items_len - 1]; const maybe_comma = tree.nextToken(last_node.lastToken()); break :blk tree.tokens[maybe_comma].id == .Comma; }; - if (switch_case.items.first.?.next == null or !src_has_trailing_comma) { - var it = switch_case.items.first; - while (it) |node_node| : (it = node_node.next) { - const node = node_node.data; - if (node_node.next) |next_node| { + if (switch_case.items_len == 1 or !src_has_trailing_comma) { + const items = switch_case.items(); + for (items) |node, i| { + if (i + 1 < items.len) { try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None); const comma_token = tree.nextToken(node.lastToken()); try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // , - try renderExtraNewline(tree, stream, start_col, next_node.data); + try renderExtraNewline(tree, stream, start_col, items[i + 1]); } else { try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Space); } } } else { - var it = switch_case.items.first; - while (it) |node_node| : (it = node_node.next) { - const node = node_node.data; - if (node_node.next) |next_node| { + const items = switch_case.items(); + for (items) |node, i| { + if (i + 1 < items.len) { try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None); const comma_token = tree.nextToken(node.lastToken()); try renderToken(tree, stream, comma_token, indent, start_col, Space.Newline); // , - try renderExtraNewline(tree, stream, start_col, next_node.data); + try renderExtraNewline(tree, stream, start_col, items[i + 1]); try stream.writeByteNTimes(' ', indent); } else { try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Comma);