authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-27 17:39:55-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-05-27 17:39:55-04:00
log4bf8ec99521f2b8b056475ec703a06a8b149cca5
tree000dbc2db20fa4b2cd248339f30326b2b41e656d
parent7674a8b43d42434a2ed424ca0778bb348e1e3d70
parent80c86ec9608478ade64964e7206487b6178853af
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #8910 from mattbork/parser-small-allocs

Use shared scratch buffer to avoid allocating and freeing many small lists in parse.zig

1 files changed, 85 insertions(+), 92 deletions(-)

lib/std/zig/parse.zig+85-92
...@@ -43,11 +43,13 @@ pub fn parse(gpa: *Allocator, source: []const u8) Allocator.Error!Tree {...@@ -43,11 +43,13 @@ pub fn parse(gpa: *Allocator, source: []const u8) Allocator.Error!Tree {
43 .errors = .{},43 .errors = .{},
44 .nodes = .{},44 .nodes = .{},
45 .extra_data = .{},45 .extra_data = .{},
46 .scratch = .{},
46 .tok_i = 0,47 .tok_i = 0,
47 };48 };
48 defer parser.errors.deinit(gpa);49 defer parser.errors.deinit(gpa);
49 defer parser.nodes.deinit(gpa);50 defer parser.nodes.deinit(gpa);
50 defer parser.extra_data.deinit(gpa);51 defer parser.extra_data.deinit(gpa);
52 defer parser.scratch.deinit(gpa);
5153
52 // Empirically, Zig source code has a 2:1 ratio of tokens to AST nodes.54 // Empirically, Zig source code has a 2:1 ratio of tokens to AST nodes.
53 // Make sure at least 1 so we can use appendAssumeCapacity on the root node below.55 // Make sure at least 1 so we can use appendAssumeCapacity on the root node below.
...@@ -93,17 +95,11 @@ const Parser = struct {...@@ -93,17 +95,11 @@ const Parser = struct {
93 errors: std.ArrayListUnmanaged(AstError),95 errors: std.ArrayListUnmanaged(AstError),
94 nodes: ast.NodeList,96 nodes: ast.NodeList,
95 extra_data: std.ArrayListUnmanaged(Node.Index),97 extra_data: std.ArrayListUnmanaged(Node.Index),
98 scratch: std.ArrayListUnmanaged(Node.Index),
9699
97 const SmallSpan = union(enum) {100 const SmallSpan = union(enum) {
98 zero_or_one: Node.Index,101 zero_or_one: Node.Index,
99 multi: []Node.Index,102 multi: Node.SubRange,
100
101 fn deinit(self: SmallSpan, gpa: *Allocator) void {
102 switch (self) {
103 .zero_or_one => {},
104 .multi => |list| gpa.free(list),
105 }
106 }
107 };103 };
108104
109 const Members = struct {105 const Members = struct {
...@@ -204,8 +200,8 @@ const Parser = struct {...@@ -204,8 +200,8 @@ const Parser = struct {
204 /// /200 /// /
205 /// TopLevelComptime <- KEYWORD_comptime BlockExpr201 /// TopLevelComptime <- KEYWORD_comptime BlockExpr
206 fn parseContainerMembers(p: *Parser) !Members {202 fn parseContainerMembers(p: *Parser) !Members {
207 var list = std.ArrayList(Node.Index).init(p.gpa);203 const scratch_top = p.scratch.items.len;
208 defer list.deinit();204 defer p.scratch.shrinkRetainingCapacity(scratch_top);
209205
210 var field_state: union(enum) {206 var field_state: union(enum) {
211 /// No fields have been seen.207 /// No fields have been seen.
...@@ -233,7 +229,7 @@ const Parser = struct {...@@ -233,7 +229,7 @@ const Parser = struct {
233 if (field_state == .seen) {229 if (field_state == .seen) {
234 field_state = .{ .end = test_decl_node };230 field_state = .{ .end = test_decl_node };
235 }231 }
236 try list.append(test_decl_node);232 try p.scratch.append(p.gpa, test_decl_node);
237 }233 }
238 trailing = false;234 trailing = false;
239 },235 },
...@@ -254,7 +250,7 @@ const Parser = struct {...@@ -254,7 +250,7 @@ const Parser = struct {
254 field_state = .err;250 field_state = .err;
255 },251 },
256 }252 }
257 try list.append(container_field);253 try p.scratch.append(p.gpa, container_field);
258 switch (p.token_tags[p.tok_i]) {254 switch (p.token_tags[p.tok_i]) {
259 .comma => {255 .comma => {
260 p.tok_i += 1;256 p.tok_i += 1;
...@@ -294,7 +290,7 @@ const Parser = struct {...@@ -294,7 +290,7 @@ const Parser = struct {
294 if (field_state == .seen) {290 if (field_state == .seen) {
295 field_state = .{ .end = comptime_node };291 field_state = .{ .end = comptime_node };
296 }292 }
297 try list.append(comptime_node);293 try p.scratch.append(p.gpa, comptime_node);
298 }294 }
299 trailing = false;295 trailing = false;
300 },296 },
...@@ -310,7 +306,7 @@ const Parser = struct {...@@ -310,7 +306,7 @@ const Parser = struct {
310 if (field_state == .seen) {306 if (field_state == .seen) {
311 field_state = .{ .end = top_level_decl };307 field_state = .{ .end = top_level_decl };
312 }308 }
313 try list.append(top_level_decl);309 try p.scratch.append(p.gpa, top_level_decl);
314 }310 }
315 trailing = p.token_tags[p.tok_i - 1] == .semicolon;311 trailing = p.token_tags[p.tok_i - 1] == .semicolon;
316 },312 },
...@@ -320,7 +316,7 @@ const Parser = struct {...@@ -320,7 +316,7 @@ const Parser = struct {
320 if (field_state == .seen) {316 if (field_state == .seen) {
321 field_state = .{ .end = node };317 field_state = .{ .end = node };
322 }318 }
323 try list.append(node);319 try p.scratch.append(p.gpa, node);
324 }320 }
325 trailing = p.token_tags[p.tok_i - 1] == .semicolon;321 trailing = p.token_tags[p.tok_i - 1] == .semicolon;
326 },322 },
...@@ -338,7 +334,7 @@ const Parser = struct {...@@ -338,7 +334,7 @@ const Parser = struct {
338 if (field_state == .seen) {334 if (field_state == .seen) {
339 field_state = .{ .end = top_level_decl };335 field_state = .{ .end = top_level_decl };
340 }336 }
341 try list.append(top_level_decl);337 try p.scratch.append(p.gpa, top_level_decl);
342 }338 }
343 trailing = p.token_tags[p.tok_i - 1] == .semicolon;339 trailing = p.token_tags[p.tok_i - 1] == .semicolon;
344 },340 },
...@@ -357,7 +353,7 @@ const Parser = struct {...@@ -357,7 +353,7 @@ const Parser = struct {
357 field_state = .err;353 field_state = .err;
358 },354 },
359 }355 }
360 try list.append(container_field);356 try p.scratch.append(p.gpa, container_field);
361 switch (p.token_tags[p.tok_i]) {357 switch (p.token_tags[p.tok_i]) {
362 .comma => {358 .comma => {
363 p.tok_i += 1;359 p.tok_i += 1;
...@@ -393,7 +389,8 @@ const Parser = struct {...@@ -393,7 +389,8 @@ const Parser = struct {
393 }389 }
394 }390 }
395391
396 switch (list.items.len) {392 const items = p.scratch.items[scratch_top..];
393 switch (items.len) {
397 0 => return Members{394 0 => return Members{
398 .len = 0,395 .len = 0,
399 .lhs = 0,396 .lhs = 0,
...@@ -402,20 +399,20 @@ const Parser = struct {...@@ -402,20 +399,20 @@ const Parser = struct {
402 },399 },
403 1 => return Members{400 1 => return Members{
404 .len = 1,401 .len = 1,
405 .lhs = list.items[0],402 .lhs = items[0],
406 .rhs = 0,403 .rhs = 0,
407 .trailing = trailing,404 .trailing = trailing,
408 },405 },
409 2 => return Members{406 2 => return Members{
410 .len = 2,407 .len = 2,
411 .lhs = list.items[0],408 .lhs = items[0],
412 .rhs = list.items[1],409 .rhs = items[1],
413 .trailing = trailing,410 .trailing = trailing,
414 },411 },
415 else => {412 else => {
416 const span = try p.listToSpan(list.items);413 const span = try p.listToSpan(items);
417 return Members{414 return Members{
418 .len = list.items.len,415 .len = items.len,
419 .lhs = span.start,416 .lhs = span.start,
420 .rhs = span.end,417 .rhs = span.end,
421 .trailing = trailing,418 .trailing = trailing,
...@@ -648,7 +645,6 @@ const Parser = struct {...@@ -648,7 +645,6 @@ const Parser = struct {
648645
649 _ = p.eatToken(.identifier);646 _ = p.eatToken(.identifier);
650 const params = try p.parseParamDeclList();647 const params = try p.parseParamDeclList();
651 defer params.deinit(p.gpa);
652 const align_expr = try p.parseByteAlign();648 const align_expr = try p.parseByteAlign();
653 const section_expr = try p.parseLinkSection();649 const section_expr = try p.parseLinkSection();
654 const callconv_expr = try p.parseCallconv();650 const callconv_expr = try p.parseCallconv();
...@@ -671,8 +667,7 @@ const Parser = struct {...@@ -671,8 +667,7 @@ const Parser = struct {
671 .rhs = return_type_expr,667 .rhs = return_type_expr,
672 },668 },
673 }),669 }),
674 .multi => |list| {670 .multi => |span| {
675 const span = try p.listToSpan(list);
676 return p.setNode(fn_proto_index, .{671 return p.setNode(fn_proto_index, .{
677 .tag = .fn_proto_multi,672 .tag = .fn_proto_multi,
678 .main_token = fn_token,673 .main_token = fn_token,
...@@ -701,8 +696,7 @@ const Parser = struct {...@@ -701,8 +696,7 @@ const Parser = struct {
701 .rhs = return_type_expr,696 .rhs = return_type_expr,
702 },697 },
703 }),698 }),
704 .multi => |list| {699 .multi => |span| {
705 const span = try p.listToSpan(list);
706 return p.setNode(fn_proto_index, .{700 return p.setNode(fn_proto_index, .{
707 .tag = .fn_proto,701 .tag = .fn_proto,
708 .main_token = fn_token,702 .main_token = fn_token,
...@@ -1894,20 +1888,20 @@ const Parser = struct {...@@ -1894,20 +1888,20 @@ const Parser = struct {
1894 });1888 });
1895 }1889 }
18961890
1897 var statements = std.ArrayList(Node.Index).init(p.gpa);1891 const scratch_top = p.scratch.items.len;
1898 defer statements.deinit();1892 defer p.scratch.shrinkRetainingCapacity(scratch_top);
18991893
1900 try statements.appendSlice(&.{ stmt_one, stmt_two });1894 try p.scratch.appendSlice(p.gpa, &.{ stmt_one, stmt_two });
19011895
1902 while (true) {1896 while (true) {
1903 const statement = try p.expectStatementRecoverable();1897 const statement = try p.expectStatementRecoverable();
1904 if (statement == 0) break;1898 if (statement == 0) break;
1905 try statements.append(statement);1899 try p.scratch.append(p.gpa, statement);
1906 if (p.token_tags[p.tok_i] == .r_brace) break;1900 if (p.token_tags[p.tok_i] == .r_brace) break;
1907 }1901 }
1908 _ = try p.expectToken(.r_brace);1902 _ = try p.expectToken(.r_brace);
1909 const semicolon = p.token_tags[p.tok_i - 2] == .semicolon;1903 const semicolon = p.token_tags[p.tok_i - 2] == .semicolon;
1910 const statements_span = try p.listToSpan(statements.items);1904 const statements_span = try p.listToSpan(p.scratch.items[scratch_top..]);
1911 return p.addNode(.{1905 return p.addNode(.{
1912 .tag = if (semicolon) .block_semicolon else .block,1906 .tag = if (semicolon) .block_semicolon else .block,
1913 .main_token = lbrace,1907 .main_token = lbrace,
...@@ -2041,14 +2035,14 @@ const Parser = struct {...@@ -2041,14 +2035,14 @@ const Parser = struct {
2041 });2035 });
2042 }2036 }
20432037
2044 var init_list = std.ArrayList(Node.Index).init(p.gpa);2038 const scratch_top = p.scratch.items.len;
2045 defer init_list.deinit();2039 defer p.scratch.shrinkRetainingCapacity(scratch_top);
20462040
2047 try init_list.append(field_init);2041 try p.scratch.append(p.gpa, field_init);
20482042
2049 while (true) {2043 while (true) {
2050 const next = try p.expectFieldInit();2044 const next = try p.expectFieldInit();
2051 try init_list.append(next);2045 try p.scratch.append(p.gpa, next);
20522046
2053 switch (p.token_tags[p.nextToken()]) {2047 switch (p.token_tags[p.nextToken()]) {
2054 .comma => {2048 .comma => {
...@@ -2068,7 +2062,7 @@ const Parser = struct {...@@ -2068,7 +2062,7 @@ const Parser = struct {
2068 },2062 },
2069 }2063 }
2070 }2064 }
2071 const span = try p.listToSpan(init_list.items);2065 const span = try p.listToSpan(p.scratch.items[scratch_top..]);
2072 return p.addNode(.{2066 return p.addNode(.{
2073 .tag = if (p.token_tags[p.tok_i - 2] == .comma) .struct_init_comma else .struct_init,2067 .tag = if (p.token_tags[p.tok_i - 2] == .comma) .struct_init_comma else .struct_init,
2074 .main_token = lbrace,2068 .main_token = lbrace,
...@@ -2098,22 +2092,22 @@ const Parser = struct {...@@ -2098,22 +2092,22 @@ const Parser = struct {
2098 try p.warnExpected(.comma);2092 try p.warnExpected(.comma);
2099 }2093 }
21002094
2101 var init_list = std.ArrayList(Node.Index).init(p.gpa);2095 const scratch_top = p.scratch.items.len;
2102 defer init_list.deinit();2096 defer p.scratch.shrinkRetainingCapacity(scratch_top);
21032097
2104 try init_list.append(elem_init);2098 try p.scratch.append(p.gpa, elem_init);
21052099
2106 var trailing_comma = true;2100 var trailing_comma = true;
2107 var next = try p.parseExpr();2101 var next = try p.parseExpr();
2108 while (next != 0) : (next = try p.parseExpr()) {2102 while (next != 0) : (next = try p.parseExpr()) {
2109 try init_list.append(next);2103 try p.scratch.append(p.gpa, next);
2110 if (p.eatToken(.comma) == null) {2104 if (p.eatToken(.comma) == null) {
2111 trailing_comma = false;2105 trailing_comma = false;
2112 break;2106 break;
2113 }2107 }
2114 }2108 }
2115 _ = try p.expectToken(.r_brace);2109 _ = try p.expectToken(.r_brace);
2116 const span = try p.listToSpan(init_list.items);2110 const span = try p.listToSpan(p.scratch.items[scratch_top..]);
2117 return p.addNode(.{2111 return p.addNode(.{
2118 .tag = if (trailing_comma) .array_init_comma else .array_init,2112 .tag = if (trailing_comma) .array_init_comma else .array_init,
2119 .main_token = lbrace,2113 .main_token = lbrace,
...@@ -2188,18 +2182,18 @@ const Parser = struct {...@@ -2188,18 +2182,18 @@ const Parser = struct {
2188 try p.warnExpected(.comma);2182 try p.warnExpected(.comma);
2189 }2183 }
21902184
2191 var param_list = std.ArrayList(Node.Index).init(p.gpa);2185 const scratch_top = p.scratch.items.len;
2192 defer param_list.deinit();2186 defer p.scratch.shrinkRetainingCapacity(scratch_top);
21932187
2194 try param_list.append(param_one);2188 try p.scratch.append(p.gpa, param_one);
21952189
2196 while (true) {2190 while (true) {
2197 const next = try p.expectExpr();2191 const next = try p.expectExpr();
2198 try param_list.append(next);2192 try p.scratch.append(p.gpa, next);
2199 switch (p.token_tags[p.nextToken()]) {2193 switch (p.token_tags[p.nextToken()]) {
2200 .comma => {2194 .comma => {
2201 if (p.eatToken(.r_paren)) |_| {2195 if (p.eatToken(.r_paren)) |_| {
2202 const span = try p.listToSpan(param_list.items);2196 const span = try p.listToSpan(p.scratch.items[scratch_top..]);
2203 return p.addNode(.{2197 return p.addNode(.{
2204 .tag = .async_call_comma,2198 .tag = .async_call_comma,
2205 .main_token = lparen,2199 .main_token = lparen,
...@@ -2216,7 +2210,7 @@ const Parser = struct {...@@ -2216,7 +2210,7 @@ const Parser = struct {
2216 }2210 }
2217 },2211 },
2218 .r_paren => {2212 .r_paren => {
2219 const span = try p.listToSpan(param_list.items);2213 const span = try p.listToSpan(p.scratch.items[scratch_top..]);
2220 return p.addNode(.{2214 return p.addNode(.{
2221 .tag = .async_call,2215 .tag = .async_call,
2222 .main_token = lparen,2216 .main_token = lparen,
...@@ -2277,18 +2271,18 @@ const Parser = struct {...@@ -2277,18 +2271,18 @@ const Parser = struct {
2277 try p.warnExpected(.comma);2271 try p.warnExpected(.comma);
2278 }2272 }
22792273
2280 var param_list = std.ArrayList(Node.Index).init(p.gpa);2274 const scratch_top = p.scratch.items.len;
2281 defer param_list.deinit();2275 defer p.scratch.shrinkRetainingCapacity(scratch_top);
22822276
2283 try param_list.append(param_one);2277 try p.scratch.append(p.gpa, param_one);
22842278
2285 while (true) {2279 while (true) {
2286 const next = try p.expectExpr();2280 const next = try p.expectExpr();
2287 try param_list.append(next);2281 try p.scratch.append(p.gpa, next);
2288 switch (p.token_tags[p.nextToken()]) {2282 switch (p.token_tags[p.nextToken()]) {
2289 .comma => {2283 .comma => {
2290 if (p.eatToken(.r_paren)) |_| {2284 if (p.eatToken(.r_paren)) |_| {
2291 const span = try p.listToSpan(param_list.items);2285 const span = try p.listToSpan(p.scratch.items[scratch_top..]);
2292 break :res try p.addNode(.{2286 break :res try p.addNode(.{
2293 .tag = .call_comma,2287 .tag = .call_comma,
2294 .main_token = lparen,2288 .main_token = lparen,
...@@ -2305,7 +2299,7 @@ const Parser = struct {...@@ -2305,7 +2299,7 @@ const Parser = struct {
2305 }2299 }
2306 },2300 },
2307 .r_paren => {2301 .r_paren => {
2308 const span = try p.listToSpan(param_list.items);2302 const span = try p.listToSpan(p.scratch.items[scratch_top..]);
2309 break :res try p.addNode(.{2303 break :res try p.addNode(.{
2310 .tag = .call,2304 .tag = .call,
2311 .main_token = lparen,2305 .main_token = lparen,
...@@ -2602,15 +2596,15 @@ const Parser = struct {...@@ -2602,15 +2596,15 @@ const Parser = struct {
2602 if (comma_two == null) {2596 if (comma_two == null) {
2603 try p.warnExpected(.comma);2597 try p.warnExpected(.comma);
2604 }2598 }
2605 var init_list = std.ArrayList(Node.Index).init(p.gpa);2599 const scratch_top = p.scratch.items.len;
2606 defer init_list.deinit();2600 defer p.scratch.shrinkRetainingCapacity(scratch_top);
26072601
2608 try init_list.appendSlice(&.{ field_init_one, field_init_two });2602 try p.scratch.appendSlice(p.gpa, &.{ field_init_one, field_init_two });
26092603
2610 while (true) {2604 while (true) {
2611 const next = try p.expectFieldInit();2605 const next = try p.expectFieldInit();
2612 assert(next != 0);2606 assert(next != 0);
2613 try init_list.append(next);2607 try p.scratch.append(p.gpa, next);
2614 switch (p.token_tags[p.nextToken()]) {2608 switch (p.token_tags[p.nextToken()]) {
2615 .comma => {2609 .comma => {
2616 if (p.eatToken(.r_brace)) |_| break;2610 if (p.eatToken(.r_brace)) |_| break;
...@@ -2627,7 +2621,7 @@ const Parser = struct {...@@ -2627,7 +2621,7 @@ const Parser = struct {
2627 },2621 },
2628 }2622 }
2629 }2623 }
2630 const span = try p.listToSpan(init_list.items);2624 const span = try p.listToSpan(p.scratch.items[scratch_top..]);
2631 const trailing_comma = p.token_tags[p.tok_i - 2] == .comma;2625 const trailing_comma = p.token_tags[p.tok_i - 2] == .comma;
2632 return p.addNode(.{2626 return p.addNode(.{
2633 .tag = if (trailing_comma) .struct_init_dot_comma else .struct_init_dot,2627 .tag = if (trailing_comma) .struct_init_dot_comma else .struct_init_dot,
...@@ -2669,15 +2663,15 @@ const Parser = struct {...@@ -2669,15 +2663,15 @@ const Parser = struct {
2669 if (comma_two == null) {2663 if (comma_two == null) {
2670 try p.warnExpected(.comma);2664 try p.warnExpected(.comma);
2671 }2665 }
2672 var init_list = std.ArrayList(Node.Index).init(p.gpa);2666 const scratch_top = p.scratch.items.len;
2673 defer init_list.deinit();2667 defer p.scratch.shrinkRetainingCapacity(scratch_top);
26742668
2675 try init_list.appendSlice(&.{ elem_init_one, elem_init_two });2669 try p.scratch.appendSlice(p.gpa, &.{ elem_init_one, elem_init_two });
26762670
2677 while (true) {2671 while (true) {
2678 const next = try p.expectExpr();2672 const next = try p.expectExpr();
2679 if (next == 0) break;2673 if (next == 0) break;
2680 try init_list.append(next);2674 try p.scratch.append(p.gpa, next);
2681 switch (p.token_tags[p.nextToken()]) {2675 switch (p.token_tags[p.nextToken()]) {
2682 .comma => {2676 .comma => {
2683 if (p.eatToken(.r_brace)) |_| break;2677 if (p.eatToken(.r_brace)) |_| break;
...@@ -2694,7 +2688,7 @@ const Parser = struct {...@@ -2694,7 +2688,7 @@ const Parser = struct {
2694 },2688 },
2695 }2689 }
2696 }2690 }
2697 const span = try p.listToSpan(init_list.items);2691 const span = try p.listToSpan(p.scratch.items[scratch_top..]);
2698 return p.addNode(.{2692 return p.addNode(.{
2699 .tag = if (p.token_tags[p.tok_i - 2] == .comma) .array_init_dot_comma else .array_init_dot,2693 .tag = if (p.token_tags[p.tok_i - 2] == .comma) .array_init_dot_comma else .array_init_dot,
2700 .main_token = lbrace,2694 .main_token = lbrace,
...@@ -2924,13 +2918,13 @@ const Parser = struct {...@@ -2924,13 +2918,13 @@ const Parser = struct {
29242918
2925 _ = try p.expectToken(.colon);2919 _ = try p.expectToken(.colon);
29262920
2927 var list = std.ArrayList(Node.Index).init(p.gpa);2921 const scratch_top = p.scratch.items.len;
2928 defer list.deinit();2922 defer p.scratch.shrinkRetainingCapacity(scratch_top);
29292923
2930 while (true) {2924 while (true) {
2931 const output_item = try p.parseAsmOutputItem();2925 const output_item = try p.parseAsmOutputItem();
2932 if (output_item == 0) break;2926 if (output_item == 0) break;
2933 try list.append(output_item);2927 try p.scratch.append(p.gpa, output_item);
2934 switch (p.token_tags[p.tok_i]) {2928 switch (p.token_tags[p.tok_i]) {
2935 .comma => p.tok_i += 1,2929 .comma => p.tok_i += 1,
2936 .colon, .r_paren, .r_brace, .r_bracket => break, // All possible delimiters.2930 .colon, .r_paren, .r_brace, .r_bracket => break, // All possible delimiters.
...@@ -2945,7 +2939,7 @@ const Parser = struct {...@@ -2945,7 +2939,7 @@ const Parser = struct {
2945 while (true) {2939 while (true) {
2946 const input_item = try p.parseAsmInputItem();2940 const input_item = try p.parseAsmInputItem();
2947 if (input_item == 0) break;2941 if (input_item == 0) break;
2948 try list.append(input_item);2942 try p.scratch.append(p.gpa, input_item);
2949 switch (p.token_tags[p.tok_i]) {2943 switch (p.token_tags[p.tok_i]) {
2950 .comma => p.tok_i += 1,2944 .comma => p.tok_i += 1,
2951 .colon, .r_paren, .r_brace, .r_bracket => break, // All possible delimiters.2945 .colon, .r_paren, .r_brace, .r_bracket => break, // All possible delimiters.
...@@ -2971,7 +2965,7 @@ const Parser = struct {...@@ -2971,7 +2965,7 @@ const Parser = struct {
2971 }2965 }
2972 }2966 }
2973 const rparen = try p.expectToken(.r_paren);2967 const rparen = try p.expectToken(.r_paren);
2974 const span = try p.listToSpan(list.items);2968 const span = try p.listToSpan(p.scratch.items[scratch_top..]);
2975 return p.addNode(.{2969 return p.addNode(.{
2976 .tag = .@"asm",2970 .tag = .@"asm",
2977 .main_token = asm_token,2971 .main_token = asm_token,
...@@ -3192,16 +3186,16 @@ const Parser = struct {...@@ -3192,16 +3186,16 @@ const Parser = struct {
3192 });3186 });
3193 }3187 }
31943188
3195 var list = std.ArrayList(Node.Index).init(p.gpa);3189 const scratch_top = p.scratch.items.len;
3196 defer list.deinit();3190 defer p.scratch.shrinkRetainingCapacity(scratch_top);
31973191
3198 try list.append(first_item);3192 try p.scratch.append(p.gpa, first_item);
3199 while (p.eatToken(.comma)) |_| {3193 while (p.eatToken(.comma)) |_| {
3200 const next_item = try p.parseSwitchItem();3194 const next_item = try p.parseSwitchItem();
3201 if (next_item == 0) break;3195 if (next_item == 0) break;
3202 try list.append(next_item);3196 try p.scratch.append(p.gpa, next_item);
3203 }3197 }
3204 const span = try p.listToSpan(list.items);3198 const span = try p.listToSpan(p.scratch.items[scratch_top..]);
3205 const arrow_token = try p.expectToken(.equal_angle_bracket_right);3199 const arrow_token = try p.expectToken(.equal_angle_bracket_right);
3206 _ = try p.parsePtrPayload();3200 _ = try p.parsePtrPayload();
3207 return p.addNode(.{3201 return p.addNode(.{
...@@ -3602,15 +3596,14 @@ const Parser = struct {...@@ -3602,15 +3596,14 @@ const Parser = struct {
3602 if (param != 0) break param;3596 if (param != 0) break param;
3603 } else unreachable;3597 } else unreachable;
36043598
3605 var list = std.ArrayList(Node.Index).init(p.gpa);3599 const scratch_top = p.scratch.items.len;
3606 defer list.deinit();3600 defer p.scratch.shrinkRetainingCapacity(scratch_top);
36073601 try p.scratch.appendSlice(p.gpa, &.{ param_one, param_two });
3608 try list.appendSlice(&.{ param_one, param_two });
36093602
3610 while (true) {3603 while (true) {
3611 switch (p.token_tags[p.nextToken()]) {3604 switch (p.token_tags[p.nextToken()]) {
3612 .comma => {},3605 .comma => {},
3613 .r_paren => return SmallSpan{ .multi = list.toOwnedSlice() },3606 .r_paren => return SmallSpan{ .multi = try p.listToSpan(p.scratch.items[scratch_top..]) },
3614 .colon, .r_brace, .r_bracket => {3607 .colon, .r_brace, .r_bracket => {
3615 p.tok_i -= 1;3608 p.tok_i -= 1;
3616 return p.failExpected(.r_paren);3609 return p.failExpected(.r_paren);
...@@ -3623,10 +3616,10 @@ const Parser = struct {...@@ -3623,10 +3616,10 @@ const Parser = struct {
3623 },3616 },
3624 }3617 }
3625 if (p.eatToken(.r_paren)) |_| {3618 if (p.eatToken(.r_paren)) |_| {
3626 return SmallSpan{ .multi = list.toOwnedSlice() };3619 return SmallSpan{ .multi = try p.listToSpan(p.scratch.items[scratch_top..]) };
3627 }3620 }
3628 const param = try p.expectParamDecl();3621 const param = try p.expectParamDecl();
3629 if (param != 0) try list.append(param);3622 if (param != 0) try p.scratch.append(p.gpa, param);
3630 }3623 }
3631 }3624 }
36323625
...@@ -3635,14 +3628,14 @@ const Parser = struct {...@@ -3635,14 +3628,14 @@ const Parser = struct {
3635 fn ListParseFn(comptime nodeParseFn: anytype) (fn (p: *Parser) Error!Node.SubRange) {3628 fn ListParseFn(comptime nodeParseFn: anytype) (fn (p: *Parser) Error!Node.SubRange) {
3636 return struct {3629 return struct {
3637 pub fn parse(p: *Parser) Error!Node.SubRange {3630 pub fn parse(p: *Parser) Error!Node.SubRange {
3638 var list = std.ArrayList(Node.Index).init(p.gpa);3631 const scratch_top = p.scratch.items.len;
3639 defer list.deinit();3632 defer p.scratch.shrinkRetainingCapacity(scratch_top);
36403633
3641 while (true) {3634 while (true) {
3642 const item = try nodeParseFn(p);3635 const item = try nodeParseFn(p);
3643 if (item == 0) break;3636 if (item == 0) break;
36443637
3645 try list.append(item);3638 try p.scratch.append(p.gpa, item);
36463639
3647 switch (p.token_tags[p.tok_i]) {3640 switch (p.token_tags[p.tok_i]) {
3648 .comma => p.tok_i += 1,3641 .comma => p.tok_i += 1,
...@@ -3655,7 +3648,7 @@ const Parser = struct {...@@ -3655,7 +3648,7 @@ const Parser = struct {
3655 },3648 },
3656 }3649 }
3657 }3650 }
3658 return p.listToSpan(list.items);3651 return p.listToSpan(p.scratch.items[scratch_top..]);
3659 }3652 }
3660 }.parse;3653 }.parse;
3661 }3654 }
...@@ -3746,18 +3739,18 @@ const Parser = struct {...@@ -3746,18 +3739,18 @@ const Parser = struct {
3746 },3739 },
3747 }3740 }
37483741
3749 var list = std.ArrayList(Node.Index).init(p.gpa);3742 const scratch_top = p.scratch.items.len;
3750 defer list.deinit();3743 defer p.scratch.shrinkRetainingCapacity(scratch_top);
37513744
3752 try list.appendSlice(&.{ param_one, param_two });3745 try p.scratch.appendSlice(p.gpa, &.{ param_one, param_two });
37533746
3754 while (true) {3747 while (true) {
3755 const param = try p.expectExpr();3748 const param = try p.expectExpr();
3756 try list.append(param);3749 try p.scratch.append(p.gpa, param);
3757 switch (p.token_tags[p.nextToken()]) {3750 switch (p.token_tags[p.nextToken()]) {
3758 .comma => {3751 .comma => {
3759 if (p.eatToken(.r_paren)) |_| {3752 if (p.eatToken(.r_paren)) |_| {
3760 const params = try p.listToSpan(list.items);3753 const params = try p.listToSpan(p.scratch.items[scratch_top..]);
3761 return p.addNode(.{3754 return p.addNode(.{
3762 .tag = .builtin_call_comma,3755 .tag = .builtin_call_comma,
3763 .main_token = builtin_token,3756 .main_token = builtin_token,
...@@ -3770,7 +3763,7 @@ const Parser = struct {...@@ -3770,7 +3763,7 @@ const Parser = struct {
3770 continue;3763 continue;
3771 },3764 },
3772 .r_paren => {3765 .r_paren => {
3773 const params = try p.listToSpan(list.items);3766 const params = try p.listToSpan(p.scratch.items[scratch_top..]);
3774 return p.addNode(.{3767 return p.addNode(.{
3775 .tag = .builtin_call,3768 .tag = .builtin_call,
3776 .main_token = builtin_token,3769 .main_token = builtin_token,