authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-21 21:48:01-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-21 22:01:16-04:00
logd37b81d43bc52daa94dd1ad1631018ea0cd11f77
tree349db74ec5b830aabfe5d36ffd3acc182ed73a0d
parent32ecb416f3acc49b80268711562f2c4133a828b9

stage2 parser performance/API improvements

* Extract Call ast node tag out of SuffixOp; parameters go in memory after Call. * Demote AsmInput and AsmOutput from AST nodes to structs inside the Asm node. * The following ast nodes get their sub-node lists directly following them in memory: - ErrorSetDecl - Switch - BuiltinCall * ast.Node.Asm gets slices for inputs, outputs, clobbers instead of singly linked lists Performance changes: throughput: 72.7 MiB/s => 74.0 MiB/s maxrss: 72 KB => 69 KB (nice)

3 files changed, 494 insertions(+), 411 deletions(-)

lib/std/zig/ast.zig+250-137
......@@ -323,7 +323,7 @@ pub const Error = union(enum) {
323323 node: *Node,
324324
325325 pub fn render(self: *const ExpectedCall, tokens: []const Token, stream: var) !void {
326 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ ", found {}", .{
326 return stream.print("expected " ++ @tagName(Node.Id.Call) ++ ", found {}", .{
327327 @tagName(self.node.id),
328328 });
329329 }
......@@ -333,7 +333,7 @@ pub const Error = union(enum) {
333333 node: *Node,
334334
335335 pub fn render(self: *const ExpectedCallOrFnProto, tokens: []const Token, stream: var) !void {
336 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ " or " ++
336 return stream.print("expected " ++ @tagName(Node.Id.Call) ++ " or " ++
337337 @tagName(Node.Id.FnProto) ++ ", found {}", .{@tagName(self.node.id)});
338338 }
339339 };
......@@ -428,15 +428,19 @@ pub const Node = struct {
428428 // Operators
429429 InfixOp,
430430 PrefixOp,
431 /// Not all suffix operations are under this tag. To save memory, some
432 /// suffix operations have dedicated Node tags.
431433 SuffixOp,
432 /// This is a suffix operation but to save memory we have a dedicated Node id for it.
434 /// `T{a, b}`
433435 ArrayInitializer,
434436 /// ArrayInitializer but with `.` instead of a left-hand-side operand.
435437 ArrayInitializerDot,
436 /// This is a suffix operation but to save memory we have a dedicated Node id for it.
438 /// `T{.a = b}`
437439 StructInitializer,
438440 /// StructInitializer but with `.` instead of a left-hand-side operand.
439441 StructInitializerDot,
442 /// `foo()`
443 Call,
440444
441445 // Control flow
442446 Switch,
......@@ -483,8 +487,6 @@ pub const Node = struct {
483487 PointerIndexPayload,
484488 ContainerField,
485489 ErrorTag,
486 AsmInput,
487 AsmOutput,
488490 FieldInitializer,
489491 };
490492
......@@ -780,13 +782,22 @@ pub const Node = struct {
780782 pub const ErrorSetDecl = struct {
781783 base: Node = Node{ .id = .ErrorSetDecl },
782784 error_token: TokenIndex,
783 decls: DeclList,
784785 rbrace_token: TokenIndex,
786 decls_len: NodeIndex,
787
788 /// After this the caller must initialize the decls list.
789 pub fn alloc(allocator: *mem.Allocator, decls_len: NodeIndex) !*ErrorSetDecl {
790 const bytes = try allocator.alignedAlloc(u8, @alignOf(ErrorSetDecl), sizeInBytes(decls_len));
791 return @ptrCast(*ErrorSetDecl, bytes.ptr);
792 }
785793
786 pub const DeclList = LinkedList(*Node);
794 pub fn free(self: *ErrorSetDecl, allocator: *mem.Allocator) void {
795 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.decls_len)];
796 allocator.free(bytes);
797 }
787798
788799 pub fn iterate(self: *const ErrorSetDecl) Node.Iterator {
789 return .{ .parent_node = &self.base, .index = 0, .node = self.decls.first };
800 return .{ .parent_node = &self.base, .index = 0, .node = null };
790801 }
791802
792803 pub fn iterateNext(self: *const ErrorSetDecl, it: *Node.Iterator) ?*Node {
......@@ -802,6 +813,20 @@ pub const Node = struct {
802813 pub fn lastToken(self: *const ErrorSetDecl) TokenIndex {
803814 return self.rbrace_token;
804815 }
816
817 pub fn decls(self: *ErrorSetDecl) []*Node {
818 const decls_start = @ptrCast([*]u8, self) + @sizeOf(ErrorSetDecl);
819 return @ptrCast([*]*Node, decls_start)[0..self.decls_len];
820 }
821
822 pub fn declsConst(self: *const ErrorSetDecl) []const *Node {
823 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(ErrorSetDecl);
824 return @ptrCast([*]const *Node, decls_start)[0..self.decls_len];
825 }
826
827 fn sizeInBytes(decls_len: NodeIndex) usize {
828 return @sizeOf(ErrorSetDecl) + @sizeOf(*Node) * @as(usize, decls_len);
829 }
805830 };
806831
807832 /// The fields and decls Node pointers directly follow this struct in memory.
......@@ -1464,19 +1489,28 @@ pub const Node = struct {
14641489 }
14651490 };
14661491
1492 /// The cases node pointers are found in memory after Switch.
1493 /// They must be SwitchCase or SwitchElse nodes.
14671494 pub const Switch = struct {
14681495 base: Node = Node{ .id = .Switch },
14691496 switch_token: TokenIndex,
1497 rbrace: TokenIndex,
1498 cases_len: NodeIndex,
14701499 expr: *Node,
14711500
1472 /// these must be SwitchCase nodes
1473 cases: CaseList,
1474 rbrace: TokenIndex,
1501 /// After this the caller must initialize the fields_and_decls list.
1502 pub fn alloc(allocator: *mem.Allocator, cases_len: NodeIndex) !*Switch {
1503 const bytes = try allocator.alignedAlloc(u8, @alignOf(Switch), sizeInBytes(cases_len));
1504 return @ptrCast(*Switch, bytes.ptr);
1505 }
14751506
1476 pub const CaseList = LinkedList(*Node);
1507 pub fn free(self: *Switch, allocator: *mem.Allocator) void {
1508 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.cases_len)];
1509 allocator.free(bytes);
1510 }
14771511
14781512 pub fn iterate(self: *const Switch) Node.Iterator {
1479 return .{ .parent_node = &self.base, .index = 0, .node = self.cases.first };
1513 return .{ .parent_node = &self.base, .index = 0, .node = null };
14801514 }
14811515
14821516 pub fn iterateNext(self: *const Switch, it: *Node.Iterator) ?*Node {
......@@ -1502,6 +1536,20 @@ pub const Node = struct {
15021536 pub fn lastToken(self: *const Switch) TokenIndex {
15031537 return self.rbrace;
15041538 }
1539
1540 pub fn cases(self: *Switch) []*Node {
1541 const decls_start = @ptrCast([*]u8, self) + @sizeOf(Switch);
1542 return @ptrCast([*]*Node, decls_start)[0..self.cases_len];
1543 }
1544
1545 pub fn casesConst(self: *const Switch) []const *Node {
1546 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(Switch);
1547 return @ptrCast([*]const *Node, decls_start)[0..self.cases_len];
1548 }
1549
1550 fn sizeInBytes(cases_len: NodeIndex) usize {
1551 return @sizeOf(Switch) + @sizeOf(*Node) * @as(usize, cases_len);
1552 }
15051553 };
15061554
15071555 pub const SwitchCase = struct {
......@@ -2120,6 +2168,66 @@ pub const Node = struct {
21202168 }
21212169 };
21222170
2171 /// Parameter nodes directly follow Call in memory.
2172 pub const Call = struct {
2173 base: Node = Node{ .id = .Call },
2174 lhs: *Node,
2175 rtoken: TokenIndex,
2176 params_len: NodeIndex,
2177 async_token: ?TokenIndex,
2178
2179 /// After this the caller must initialize the fields_and_decls list.
2180 pub fn alloc(allocator: *mem.Allocator, params_len: NodeIndex) !*Call {
2181 const bytes = try allocator.alignedAlloc(u8, @alignOf(Call), sizeInBytes(params_len));
2182 return @ptrCast(*Call, bytes.ptr);
2183 }
2184
2185 pub fn free(self: *Call, allocator: *mem.Allocator) void {
2186 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len)];
2187 allocator.free(bytes);
2188 }
2189
2190 pub fn iterate(self: *const Call) Node.Iterator {
2191 return .{ .parent_node = &self.base, .index = 0, .node = null};
2192 }
2193
2194 pub fn iterateNext(self: *const Call, it: *Node.Iterator) ?*Node {
2195 var i = it.index;
2196 it.index += 1;
2197
2198 if (i < 1) return self.lhs;
2199 i -= 1;
2200
2201 if (i < self.params_len) return self.paramsConst()[i];
2202 i -= self.params_len;
2203
2204 return null;
2205 }
2206
2207 pub fn firstToken(self: *const Call) TokenIndex {
2208 if (self.async_token) |async_token| return async_token;
2209 return self.lhs.firstToken();
2210 }
2211
2212 pub fn lastToken(self: *const Call) TokenIndex {
2213 return self.rtoken;
2214 }
2215
2216 pub fn params(self: *Call) []*Node {
2217 const decls_start = @ptrCast([*]u8, self) + @sizeOf(Call);
2218 return @ptrCast([*]*Node, decls_start)[0..self.params_len];
2219 }
2220
2221 pub fn paramsConst(self: *const Call) []const *Node {
2222 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(Call);
2223 return @ptrCast([*]const *Node, decls_start)[0..self.params_len];
2224 }
2225
2226 fn sizeInBytes(params_len: NodeIndex) usize {
2227 return @sizeOf(Call) + @sizeOf(*Node) * @as(usize, params_len);
2228 }
2229 };
2230
21232231 pub const SuffixOp = struct {
21242232 base: Node = Node{ .id = .SuffixOp },
21252233 op: Op,
......@@ -2127,19 +2235,11 @@ pub const Node = struct {
21272235 rtoken: TokenIndex,
21282236
21292237 pub const Op = union(enum) {
2130 Call: Call,
21312238 ArrayAccess: *Node,
21322239 Slice: Slice,
21332240 Deref,
21342241 UnwrapOptional,
21352242
2136 pub const Call = struct {
2137 params: ParamList,
2138 async_token: ?TokenIndex,
2139
2140 pub const ParamList = LinkedList(*Node);
2141 };
2142
21432243 pub const Slice = struct {
21442244 start: *Node,
21452245 end: ?*Node,
......@@ -2148,12 +2248,7 @@ pub const Node = struct {
21482248 };
21492249
21502250 pub fn iterate(self: *const SuffixOp) Node.Iterator {
2151 return .{ .parent_node = &self.base, .index = 0,
2152 .node = switch(self.op) {
2153 .Call => |call| call.params.first,
2154 else => null,
2155 },
2156 };
2251 return .{ .parent_node = &self.base, .index = 0, .node = null};
21572252 }
21582253
21592254 pub fn iterateNext(self: *const SuffixOp, it: *Node.Iterator) ?*Node {
......@@ -2164,13 +2259,6 @@ pub const Node = struct {
21642259 i -= 1;
21652260
21662261 switch (self.op) {
2167 .Call => |call_info| {
2168 if (it.node) |child| {
2169 it.index -= 1;
2170 it.node = child.next;
2171 return child.data;
2172 }
2173 },
21742262 .ArrayAccess => |index_expr| {
21752263 if (i < 1) return index_expr;
21762264 i -= 1;
......@@ -2197,10 +2285,6 @@ pub const Node = struct {
21972285 }
21982286
21992287 pub fn firstToken(self: *const SuffixOp) TokenIndex {
2200 switch (self.op) {
2201 .Call => |*call_info| if (call_info.async_token) |async_token| return async_token,
2202 else => {},
2203 }
22042288 return self.lhs.firstToken();
22052289 }
22062290
......@@ -2396,22 +2480,36 @@ pub const Node = struct {
23962480 }
23972481 };
23982482
2483 /// Parameters are in memory following BuiltinCall.
23992484 pub const BuiltinCall = struct {
24002485 base: Node = Node{ .id = .BuiltinCall },
2486 params_len: NodeIndex,
24012487 builtin_token: TokenIndex,
2402 params: ParamList,
24032488 rparen_token: TokenIndex,
24042489
2405 pub const ParamList = LinkedList(*Node);
2490 /// After this the caller must initialize the fields_and_decls list.
2491 pub fn alloc(allocator: *mem.Allocator, params_len: NodeIndex) !*BuiltinCall {
2492 const bytes = try allocator.alignedAlloc(u8, @alignOf(BuiltinCall), sizeInBytes(params_len));
2493 return @ptrCast(*BuiltinCall, bytes.ptr);
2494 }
2495
2496 pub fn free(self: *BuiltinCall, allocator: *mem.Allocator) void {
2497 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len)];
2498 allocator.free(bytes);
2499 }
24062500
24072501 pub fn iterate(self: *const BuiltinCall) Node.Iterator {
2408 return .{ .parent_node = &self.base, .index = 0, .node = self.params.first };
2502 return .{ .parent_node = &self.base, .index = 0, .node = null };
24092503 }
24102504
24112505 pub fn iterateNext(self: *const BuiltinCall, it: *Node.Iterator) ?*Node {
2412 const param = it.node orelse return null;
2413 it.node = param.next;
2414 return param.data;
2506 var i = it.index;
2507 it.index += 1;
2508
2509 if (i < self.params_len) return self.paramsConst()[i];
2510 i -= self.params_len;
2511
2512 return null;
24152513 }
24162514
24172515 pub fn firstToken(self: *const BuiltinCall) TokenIndex {
......@@ -2421,6 +2519,20 @@ pub const Node = struct {
24212519 pub fn lastToken(self: *const BuiltinCall) TokenIndex {
24222520 return self.rparen_token;
24232521 }
2522
2523 pub fn params(self: *BuiltinCall) []*Node {
2524 const decls_start = @ptrCast([*]u8, self) + @sizeOf(BuiltinCall);
2525 return @ptrCast([*]*Node, decls_start)[0..self.params_len];
2526 }
2527
2528 pub fn paramsConst(self: *const BuiltinCall) []const *Node {
2529 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(BuiltinCall);
2530 return @ptrCast([*]const *Node, decls_start)[0..self.params_len];
2531 }
2532
2533 fn sizeInBytes(params_len: NodeIndex) usize {
2534 return @sizeOf(BuiltinCall) + @sizeOf(*Node) * @as(usize, params_len);
2535 }
24242536 };
24252537
24262538 pub const StringLiteral = struct {
......@@ -2554,106 +2666,102 @@ pub const Node = struct {
25542666 }
25552667 };
25562668
2557 pub const AsmOutput = struct {
2558 base: Node = Node{ .id = .AsmOutput },
2559 lbracket: TokenIndex,
2560 symbolic_name: *Node,
2561 constraint: *Node,
2562 kind: Kind,
2669 pub const Asm = struct {
2670 base: Node = Node{ .id = .Asm },
2671 asm_token: TokenIndex,
25632672 rparen: TokenIndex,
2673 volatile_token: ?TokenIndex,
2674 template: *Node,
2675 outputs: []Output,
2676 inputs: []Input,
2677 /// A clobber node must be a StringLiteral or MultilineStringLiteral.
2678 clobbers: []*Node,
2679
2680 pub const Output = struct {
2681 lbracket: TokenIndex,
2682 symbolic_name: *Node,
2683 constraint: *Node,
2684 kind: Kind,
2685 rparen: TokenIndex,
2686
2687 pub const Kind = union(enum) {
2688 Variable: *Identifier,
2689 Return: *Node,
2690 };
25642691
2565 pub const Kind = union(enum) {
2566 Variable: *Identifier,
2567 Return: *Node,
2568 };
2692 pub fn iterate(self: *const Output) Node.Iterator {
2693 return .{ .parent_node = &self.base, .index = 0, .node = null };
2694 }
25692695
2570 pub fn iterate(self: *const AsmOutput) Node.Iterator {
2571 return .{ .parent_node = &self.base, .index = 0, .node = null };
2572 }
2696 pub fn iterateNext(self: *const Output, it: *Node.Iterator) ?*Node {
2697 var i = it.index;
2698 it.index += 1;
25732699
2574 pub fn iterateNext(self: *const AsmOutput, it: *Node.Iterator) ?*Node {
2575 var i = it.index;
2576 it.index += 1;
2700 if (i < 1) return self.symbolic_name;
2701 i -= 1;
25772702
2578 if (i < 1) return self.symbolic_name;
2579 i -= 1;
2703 if (i < 1) return self.constraint;
2704 i -= 1;
25802705
2581 if (i < 1) return self.constraint;
2582 i -= 1;
2706 switch (self.kind) {
2707 .Variable => |variable_name| {
2708 if (i < 1) return &variable_name.base;
2709 i -= 1;
2710 },
2711 .Return => |return_type| {
2712 if (i < 1) return return_type;
2713 i -= 1;
2714 },
2715 }
25832716
2584 switch (self.kind) {
2585 .Variable => |variable_name| {
2586 if (i < 1) return &variable_name.base;
2587 i -= 1;
2588 },
2589 .Return => |return_type| {
2590 if (i < 1) return return_type;
2591 i -= 1;
2592 },
2717 return null;
25932718 }
25942719
2595 return null;
2596 }
2597
2598 pub fn firstToken(self: *const AsmOutput) TokenIndex {
2599 return self.lbracket;
2600 }
2601
2602 pub fn lastToken(self: *const AsmOutput) TokenIndex {
2603 return self.rparen;
2604 }
2605 };
2720 pub fn firstToken(self: *const Output) TokenIndex {
2721 return self.lbracket;
2722 }
26062723
2607 pub const AsmInput = struct {
2608 base: Node = Node{ .id = .AsmInput },
2609 lbracket: TokenIndex,
2610 symbolic_name: *Node,
2611 constraint: *Node,
2612 expr: *Node,
2613 rparen: TokenIndex,
2724 pub fn lastToken(self: *const Output) TokenIndex {
2725 return self.rparen;
2726 }
2727 };
26142728
2615 pub fn iterate(self: *const AsmInput) Node.Iterator {
2616 return .{ .parent_node = &self.base, .index = 0, .node = null };
2617 }
2729 pub const Input = struct {
2730 lbracket: TokenIndex,
2731 symbolic_name: *Node,
2732 constraint: *Node,
2733 expr: *Node,
2734 rparen: TokenIndex,
26182735
2619 pub fn iterateNext(self: *const AsmInput, it: *Node.Iterator) ?*Node {
2620 var i = it.index;
2621 it.index += 1;
2736 pub fn iterate(self: *const Input) Node.Iterator {
2737 return .{ .parent_node = &self.base, .index = 0, .node = null };
2738 }
26222739
2623 if (i < 1) return self.symbolic_name;
2624 i -= 1;
2740 pub fn iterateNext(self: *const Input, it: *Node.Iterator) ?*Node {
2741 var i = it.index;
2742 it.index += 1;
26252743
2626 if (i < 1) return self.constraint;
2627 i -= 1;
2744 if (i < 1) return self.symbolic_name;
2745 i -= 1;
26282746
2629 if (i < 1) return self.expr;
2630 i -= 1;
2747 if (i < 1) return self.constraint;
2748 i -= 1;
26312749
2632 return null;
2633 }
2750 if (i < 1) return self.expr;
2751 i -= 1;
26342752
2635 pub fn firstToken(self: *const AsmInput) TokenIndex {
2636 return self.lbracket;
2637 }
2753 return null;
2754 }
26382755
2639 pub fn lastToken(self: *const AsmInput) TokenIndex {
2640 return self.rparen;
2641 }
2642 };
2756 pub fn firstToken(self: *const Input) TokenIndex {
2757 return self.lbracket;
2758 }
26432759
2644 pub const Asm = struct {
2645 base: Node = Node{ .id = .Asm },
2646 asm_token: TokenIndex,
2647 volatile_token: ?TokenIndex,
2648 template: *Node,
2649 outputs: OutputList,
2650 inputs: InputList,
2651 clobbers: ClobberList,
2652 rparen: TokenIndex,
2760 pub fn lastToken(self: *const Input) TokenIndex {
2761 return self.rparen;
2762 }
2763 };
26532764
2654 pub const OutputList = LinkedList(*AsmOutput);
2655 pub const InputList = LinkedList(*AsmInput);
2656 pub const ClobberList = LinkedList(*Node);
26572765
26582766 pub fn iterate(self: *const Asm) Node.Iterator {
26592767 return .{ .parent_node = &self.base, .index = 0, .node = null};
......@@ -2663,19 +2771,24 @@ pub const Node = struct {
26632771 var i = it.index;
26642772 it.index += 1;
26652773
2666 var output: ?*LinkedList(*AsmOutput).Node = self.outputs.first;
2667 while (output) |o| {
2668 if (i < 1) return &o.data.base;
2669 i -= 1;
2670 output = o.next;
2671 }
2774 if (i < self.outputs.len * 3) switch (i % 3) {
2775 0 => return self.outputs[i / 3].symbolic_name,
2776 1 => return self.outputs[i / 3].constraint,
2777 2 => switch (self.outputs[i / 3].kind) {
2778 .Variable => |variable_name| return &variable_name.base,
2779 .Return => |return_type| return return_type,
2780 },
2781 else => unreachable,
2782 };
2783 i -= self.outputs.len * 3;
26722784
2673 var input: ?*LinkedList(*AsmInput).Node = self.inputs.first;
2674 while (input) |o| {
2675 if (i < 1) return &o.data.base;
2676 i -= 1;
2677 input = o.next;
2678 }
2785 if (i < self.inputs.len * 3) switch (i % 3) {
2786 0 => return self.inputs[i / 3].symbolic_name,
2787 1 => return self.inputs[i / 3].constraint,
2788 2 => return self.inputs[i / 3].expr,
2789 else => unreachable,
2790 };
2791 i -= self.inputs.len * 3;
26792792
26802793 return null;
26812794 }
lib/std/zig/parse.zig+93-110
......@@ -520,10 +520,9 @@ const Parser = struct {
520520 p.putBackToken(token);
521521 return null;
522522 };
523 var var_args_token: ?TokenIndex = null;
524523 const name_token = p.eatToken(.Identifier);
525524 const lparen = try p.expectToken(.LParen);
526 const params = try p.parseParamDeclList(&var_args_token);
525 const params = try p.parseParamDeclList();
527526 defer p.gpa.free(params);
528527 const rparen = try p.expectToken(.RParen);
529528 const align_expr = try p.parseByteAlign();
......@@ -547,15 +546,19 @@ const Parser = struct {
547546 else
548547 R{ .Explicit = return_type_expr.? };
549548
550 const params_len = @intCast(NodeIndex, params.len);
549 const var_args_token = if (params.len > 0) blk: {
550 const param_type = params[params.len - 1].param_type;
551 break :blk if (param_type == .var_args) param_type.var_args else null;
552 } else
553 null;
551554
552 const fn_proto_node = try Node.FnProto.alloc(&p.arena.allocator, params_len);
555 const fn_proto_node = try Node.FnProto.alloc(&p.arena.allocator, params.len);
553556 fn_proto_node.* = .{
554557 .doc_comments = null,
555558 .visib_token = null,
556559 .fn_token = fn_token,
557560 .name_token = name_token,
558 .params_len = params_len,
561 .params_len = params.len,
559562 .return_type = return_type,
560563 .var_args_token = var_args_token,
561564 .extern_export_inline_token = null,
......@@ -1455,17 +1458,15 @@ const Parser = struct {
14551458 // ignore this, continue parsing
14561459 return res;
14571460 };
1458 const node = try p.arena.allocator.create(Node.SuffixOp);
1461 defer p.gpa.free(params.list);
1462 const node = try Node.Call.alloc(&p.arena.allocator, params.list.len);
14591463 node.* = .{
14601464 .lhs = res,
1461 .op = .{
1462 .Call = .{
1463 .params = params.list,
1464 .async_token = async_token,
1465 },
1466 },
1465 .params_len = params.list.len,
1466 .async_token = async_token,
14671467 .rtoken = params.rparen,
14681468 };
1469 std.mem.copy(*Node, node.params(), params.list);
14691470 return &node.base;
14701471 }
14711472 if (try p.parsePrimaryTypeExpr()) |expr| {
......@@ -1482,17 +1483,15 @@ const Parser = struct {
14821483 continue;
14831484 }
14841485 if (try p.parseFnCallArguments()) |params| {
1485 const call = try p.arena.allocator.create(Node.SuffixOp);
1486 defer p.gpa.free(params.list);
1487 const call = try Node.Call.alloc(&p.arena.allocator, params.list.len);
14861488 call.* = .{
14871489 .lhs = res,
1488 .op = .{
1489 .Call = .{
1490 .params = params.list,
1491 .async_token = null,
1492 },
1493 },
1490 .params_len = params.list.len,
1491 .async_token = null,
14941492 .rtoken = params.rparen,
14951493 };
1494 std.mem.copy(*Node, call.params(), params.list);
14961495 res = &call.base;
14971496 continue;
14981497 }
......@@ -1615,14 +1614,16 @@ const Parser = struct {
16151614 return null;
16161615 }
16171616 const decls = try p.parseErrorTagList();
1617 defer p.gpa.free(decls);
16181618 const rbrace = try p.expectToken(.RBrace);
16191619
1620 const node = try p.arena.allocator.create(Node.ErrorSetDecl);
1620 const node = try Node.ErrorSetDecl.alloc(&p.arena.allocator, decls.len);
16211621 node.* = .{
16221622 .error_token = error_token,
1623 .decls = decls,
1623 .decls_len = decls.len,
16241624 .rbrace_token = rbrace,
16251625 };
1626 std.mem.copy(*Node, node.decls(), decls);
16261627 return &node.base;
16271628 }
16281629
......@@ -1769,19 +1770,25 @@ const Parser = struct {
17691770 _ = try p.expectToken(.RParen);
17701771 _ = try p.expectToken(.LBrace);
17711772 const cases = try p.parseSwitchProngList();
1773 defer p.gpa.free(cases);
17721774 const rbrace = try p.expectToken(.RBrace);
17731775
1774 const node = try p.arena.allocator.create(Node.Switch);
1776 const node = try Node.Switch.alloc(&p.arena.allocator, cases.len);
17751777 node.* = .{
17761778 .switch_token = switch_token,
17771779 .expr = expr_node,
1778 .cases = cases,
1780 .cases_len = cases.len,
17791781 .rbrace = rbrace,
17801782 };
1783 std.mem.copy(*Node, node.cases(), cases);
17811784 return &node.base;
17821785 }
17831786
17841787 /// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN
1788 /// AsmOutput <- COLON AsmOutputList AsmInput?
1789 /// AsmInput <- COLON AsmInputList AsmClobbers?
1790 /// AsmClobbers <- COLON StringList
1791 /// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL?
17851792 fn parseAsmExpr(p: *Parser) !?*Node {
17861793 const asm_token = p.eatToken(.Keyword_asm) orelse return null;
17871794 const volatile_token = p.eatToken(.Keyword_volatile);
......@@ -1790,19 +1797,39 @@ const Parser = struct {
17901797 .ExpectedExpr = .{ .token = p.tok_i },
17911798 });
17921799
1800 var arena_outputs: []Node.Asm.Output = &[0]Node.Asm.Output{};
1801 var arena_inputs: []Node.Asm.Input = &[0]Node.Asm.Input{};
1802 var arena_clobbers: []*Node = &[0]*Node{};
1803
1804 if (p.eatToken(.Colon) != null) {
1805 const outputs = try p.parseAsmOutputList();
1806 defer p.gpa.free(outputs);
1807 arena_outputs = try p.arena.allocator.dupe(Node.Asm.Output, outputs);
1808
1809 if (p.eatToken(.Colon) != null) {
1810 const inputs = try p.parseAsmInputList();
1811 defer p.gpa.free(inputs);
1812 arena_inputs = try p.arena.allocator.dupe(Node.Asm.Input, inputs);
1813
1814 if (p.eatToken(.Colon) != null) {
1815 const clobbers = try ListParseFn(*Node, parseStringLiteral)(p);
1816 defer p.gpa.free(clobbers);
1817 arena_clobbers = try p.arena.allocator.dupe(*Node, clobbers);
1818 }
1819 }
1820 }
1821
17931822 const node = try p.arena.allocator.create(Node.Asm);
17941823 node.* = .{
17951824 .asm_token = asm_token,
17961825 .volatile_token = volatile_token,
17971826 .template = template,
1798 .outputs = Node.Asm.OutputList{},
1799 .inputs = Node.Asm.InputList{},
1800 .clobbers = Node.Asm.ClobberList{},
1801 .rparen = undefined,
1827 .outputs = arena_outputs,
1828 .inputs = arena_inputs,
1829 .clobbers = arena_clobbers,
1830 .rparen = try p.expectToken(.RParen),
18021831 };
18031832
1804 try p.parseAsmOutput(node);
1805 node.rparen = try p.expectToken(.RParen);
18061833 return &node.base;
18071834 }
18081835
......@@ -1828,15 +1855,8 @@ const Parser = struct {
18281855 return null;
18291856 }
18301857
1831 /// AsmOutput <- COLON AsmOutputList AsmInput?
1832 fn parseAsmOutput(p: *Parser, asm_node: *Node.Asm) !void {
1833 if (p.eatToken(.Colon) == null) return;
1834 asm_node.outputs = try p.parseAsmOutputList();
1835 try p.parseAsmInput(asm_node);
1836 }
1837
18381858 /// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
1839 fn parseAsmOutputItem(p: *Parser) !?*Node.AsmOutput {
1859 fn parseAsmOutputItem(p: *Parser) !?Node.Asm.Output {
18401860 const lbracket = p.eatToken(.LBracket) orelse return null;
18411861 const name = try p.expectNode(parseIdentifier, .{
18421862 .ExpectedIdentifier = .{ .token = p.tok_i },
......@@ -1848,7 +1868,7 @@ const Parser = struct {
18481868 });
18491869
18501870 _ = try p.expectToken(.LParen);
1851 const kind: Node.AsmOutput.Kind = blk: {
1871 const kind: Node.Asm.Output.Kind = blk: {
18521872 if (p.eatToken(.Arrow) != null) {
18531873 const return_ident = try p.expectNode(parseTypeExpr, .{
18541874 .ExpectedTypeExpr = .{ .token = p.tok_i },
......@@ -1862,26 +1882,17 @@ const Parser = struct {
18621882 };
18631883 const rparen = try p.expectToken(.RParen);
18641884
1865 const node = try p.arena.allocator.create(Node.AsmOutput);
1866 node.* = .{
1885 return Node.Asm.Output{
18671886 .lbracket = lbracket,
18681887 .symbolic_name = name,
18691888 .constraint = constraint,
18701889 .kind = kind,
18711890 .rparen = rparen,
18721891 };
1873 return node;
1874 }
1875
1876 /// AsmInput <- COLON AsmInputList AsmClobbers?
1877 fn parseAsmInput(p: *Parser, asm_node: *Node.Asm) !void {
1878 if (p.eatToken(.Colon) == null) return;
1879 asm_node.inputs = try p.parseAsmInputList();
1880 try p.parseAsmClobbers(asm_node);
18811892 }
18821893
18831894 /// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN
1884 fn parseAsmInputItem(p: *Parser) !?*Node.AsmInput {
1895 fn parseAsmInputItem(p: *Parser) !?Node.Asm.Input {
18851896 const lbracket = p.eatToken(.LBracket) orelse return null;
18861897 const name = try p.expectNode(parseIdentifier, .{
18871898 .ExpectedIdentifier = .{ .token = p.tok_i },
......@@ -1898,25 +1909,13 @@ const Parser = struct {
18981909 });
18991910 const rparen = try p.expectToken(.RParen);
19001911
1901 const node = try p.arena.allocator.create(Node.AsmInput);
1902 node.* = .{
1912 return Node.Asm.Input{
19031913 .lbracket = lbracket,
19041914 .symbolic_name = name,
19051915 .constraint = constraint,
19061916 .expr = expr,
19071917 .rparen = rparen,
19081918 };
1909 return node;
1910 }
1911
1912 /// AsmClobbers <- COLON StringList
1913 /// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL?
1914 fn parseAsmClobbers(p: *Parser, asm_node: *Node.Asm) !void {
1915 if (p.eatToken(.Colon) == null) return;
1916 asm_node.clobbers = try ListParseFn(
1917 Node.Asm.ClobberList,
1918 parseStringLiteral,
1919 )(p);
19201919 }
19211920
19221921 /// BreakLabel <- COLON IDENTIFIER
......@@ -1999,7 +1998,7 @@ const Parser = struct {
19991998 }
20001999
20012000 /// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
2002 fn parseParamDecl(p: *Parser, list: *std.ArrayList(Node.FnProto.ParamDecl)) !bool {
2001 fn parseParamDecl(p: *Parser) !?Node.FnProto.ParamDecl {
20032002 const doc_comments = try p.parseDocComment();
20042003 const noalias_token = p.eatToken(.Keyword_noalias);
20052004 const comptime_token = if (noalias_token == null) p.eatToken(.Keyword_comptime) else null;
......@@ -2014,21 +2013,23 @@ const Parser = struct {
20142013 if (noalias_token == null and
20152014 comptime_token == null and
20162015 name_token == null and
2017 doc_comments == null) return false;
2016 doc_comments == null)
2017 {
2018 return null;
2019 }
20182020 try p.errors.append(p.gpa, .{
20192021 .ExpectedParamType = .{ .token = p.tok_i },
20202022 });
20212023 return error.ParseError;
20222024 };
20232025
2024 (try list.addOne()).* = .{
2026 return Node.FnProto.ParamDecl{
20252027 .doc_comments = doc_comments,
20262028 .comptime_token = comptime_token,
20272029 .noalias_token = noalias_token,
20282030 .name_token = name_token,
20292031 .param_type = param_type,
20302032 };
2031 return true;
20322033 }
20332034
20342035 /// ParamType
......@@ -2714,13 +2715,14 @@ const Parser = struct {
27142715 /// ExprList <- (Expr COMMA)* Expr?
27152716 fn parseFnCallArguments(p: *Parser) !?AnnotatedParamList {
27162717 if (p.eatToken(.LParen) == null) return null;
2717 const list = try ListParseFn(std.SinglyLinkedList(*Node), parseExpr)(p);
2718 const list = try ListParseFn(*Node, parseExpr)(p);
2719 errdefer p.gpa.free(list);
27182720 const rparen = try p.expectToken(.RParen);
27192721 return AnnotatedParamList{ .list = list, .rparen = rparen };
27202722 }
27212723
27222724 const AnnotatedParamList = struct {
2723 list: std.SinglyLinkedList(*Node),
2725 list: []*Node,
27242726 rparen: TokenIndex,
27252727 };
27262728
......@@ -2936,62 +2938,40 @@ const Parser = struct {
29362938
29372939 /// IdentifierList <- (IDENTIFIER COMMA)* IDENTIFIER?
29382940 /// Only ErrorSetDecl parses an IdentifierList
2939 fn parseErrorTagList(p: *Parser) !Node.ErrorSetDecl.DeclList {
2940 return ListParseFn(Node.ErrorSetDecl.DeclList, parseErrorTag)(p);
2941 fn parseErrorTagList(p: *Parser) ![]*Node {
2942 return ListParseFn(*Node, parseErrorTag)(p);
29412943 }
29422944
29432945 /// SwitchProngList <- (SwitchProng COMMA)* SwitchProng?
2944 fn parseSwitchProngList(p: *Parser) !Node.Switch.CaseList {
2945 return ListParseFn(Node.Switch.CaseList, parseSwitchProng)(p);
2946 fn parseSwitchProngList(p: *Parser) ![]*Node {
2947 return ListParseFn(*Node, parseSwitchProng)(p);
29462948 }
29472949
29482950 /// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?
2949 fn parseAsmOutputList(p: *Parser) Error!Node.Asm.OutputList {
2950 return ListParseFn(Node.Asm.OutputList, parseAsmOutputItem)(p);
2951 fn parseAsmOutputList(p: *Parser) Error![]Node.Asm.Output {
2952 return ListParseFn(Node.Asm.Output, parseAsmOutputItem)(p);
29512953 }
29522954
29532955 /// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?
2954 fn parseAsmInputList(p: *Parser) Error!Node.Asm.InputList {
2955 return ListParseFn(Node.Asm.InputList, parseAsmInputItem)(p);
2956 fn parseAsmInputList(p: *Parser) Error![]Node.Asm.Input {
2957 return ListParseFn(Node.Asm.Input, parseAsmInputItem)(p);
29562958 }
29572959
29582960 /// ParamDeclList <- (ParamDecl COMMA)* ParamDecl?
2959 fn parseParamDeclList(p: *Parser, var_args_token: *?TokenIndex) ![]Node.FnProto.ParamDecl {
2960 var list = std.ArrayList(Node.FnProto.ParamDecl).init(p.gpa);
2961 defer list.deinit();
2962
2963 while (try p.parseParamDecl(&list)) {
2964 switch (p.tokens[p.tok_i].id) {
2965 .Comma => _ = p.nextToken(),
2966 // all possible delimiters
2967 .Colon, .RParen, .RBrace, .RBracket => break,
2968 else => {
2969 // this is likely just a missing comma,
2970 // continue parsing this list and give an error
2971 try p.errors.append(p.gpa, .{
2972 .ExpectedToken = .{ .token = p.tok_i, .expected_id = .Comma },
2973 });
2974 },
2975 }
2976 }
2977 if (list.items.len != 0) {
2978 const param_type = list.items[list.items.len - 1].param_type;
2979 if (param_type == .var_args) {
2980 var_args_token.* = param_type.var_args;
2981 }
2982 }
2983 return list.toOwnedSlice();
2961 fn parseParamDeclList(p: *Parser) ![]Node.FnProto.ParamDecl {
2962 return ListParseFn(Node.FnProto.ParamDecl, parseParamDecl)(p);
29842963 }
29852964
29862965 const NodeParseFn = fn (p: *Parser) Error!?*Node;
29872966
2988 fn ListParseFn(comptime L: type, comptime nodeParseFn: var) ParseFn(L) {
2967 fn ListParseFn(comptime E: type, comptime nodeParseFn: var) ParseFn([]E) {
29892968 return struct {
2990 pub fn parse(p: *Parser) !L {
2991 var list = L{};
2992 var list_it = &list.first;
2993 while (try nodeParseFn(p)) |node| {
2994 list_it = try p.llpush(L.Node.Data, list_it, node);
2969 pub fn parse(p: *Parser) ![]E {
2970 var list = std.ArrayList(E).init(p.gpa);
2971 defer list.deinit();
2972
2973 while (try nodeParseFn(p)) |item| {
2974 try list.append(item);
29952975
29962976 switch (p.tokens[p.tok_i].id) {
29972977 .Comma => _ = p.nextToken(),
......@@ -3006,7 +2986,7 @@ const Parser = struct {
30062986 },
30072987 }
30082988 }
3009 return list;
2989 return list.toOwnedSlice();
30102990 }
30112991 }.parse;
30122992 }
......@@ -3053,12 +3033,15 @@ const Parser = struct {
30533033 };
30543034 return &node.base;
30553035 };
3056 const node = try p.arena.allocator.create(Node.BuiltinCall);
3036 defer p.gpa.free(params.list);
3037
3038 const node = try Node.BuiltinCall.alloc(&p.arena.allocator, params.list.len);
30573039 node.* = .{
30583040 .builtin_token = token,
3059 .params = params.list,
3041 .params_len = params.list.len,
30603042 .rparen_token = params.rparen,
30613043 };
3044 std.mem.copy(*Node, node.params(), params.list);
30623045 return &node.base;
30633046 }
30643047
lib/std/zig/render.zig+151-164
......@@ -187,7 +187,10 @@ fn renderRoot(
187187}
188188
189189fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) @TypeOf(stream).Error!void {
190 const first_token = node.firstToken();
190 return renderExtraNewlineToken(tree, stream, start_col, node.firstToken());
191}
192
193fn renderExtraNewlineToken(tree: *ast.Tree, stream: var, start_col: *usize, first_token: ast.TokenIndex,) @TypeOf(stream).Error!void {
191194 var prev_token = first_token;
192195 if (prev_token == 0) return;
193196 var newline_threshold: usize = 2;
......@@ -902,74 +905,70 @@ fn renderExpression(
902905 return renderToken(tree, stream, rtoken, indent, start_col, space);
903906 },
904907
905 .SuffixOp => {
906 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
908 .Call => {
909 const call = @fieldParentPtr(ast.Node.Call, "base", base);
910 if (call.async_token) |async_token| {
911 try renderToken(tree, stream, async_token, indent, start_col, Space.Space);
912 }
907913
908 switch (suffix_op.op) {
909 .Call => |*call_info| {
910 if (call_info.async_token) |async_token| {
911 try renderToken(tree, stream, async_token, indent, start_col, Space.Space);
912 }
914 try renderExpression(allocator, stream, tree, indent, start_col, call.lhs, Space.None);
913915
914 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
916 const lparen = tree.nextToken(call.lhs.lastToken());
915917
916 const lparen = tree.nextToken(suffix_op.lhs.lastToken());
918 if (call.params_len == 0) {
919 try renderToken(tree, stream, lparen, indent, start_col, Space.None);
920 return renderToken(tree, stream, call.rtoken, indent, start_col, space);
921 }
917922
918 if (call_info.params.first == null) {
919 try renderToken(tree, stream, lparen, indent, start_col, Space.None);
920 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
921 }
923 const src_has_trailing_comma = blk: {
924 const maybe_comma = tree.prevToken(call.rtoken);
925 break :blk tree.tokens[maybe_comma].id == .Comma;
926 };
922927
923 const src_has_trailing_comma = blk: {
924 const maybe_comma = tree.prevToken(suffix_op.rtoken);
925 break :blk tree.tokens[maybe_comma].id == .Comma;
926 };
928 if (src_has_trailing_comma) {
929 const new_indent = indent + indent_delta;
930 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline);
927931
928 if (src_has_trailing_comma) {
929 const new_indent = indent + indent_delta;
930 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline);
931
932 var it = call_info.params.first;
933 while (true) {
934 const param_node_node = it.?;
935 it = param_node_node.next;
936 const param_node = param_node_node.data;
937
938 const param_node_new_indent = if (param_node.id == .MultilineStringLiteral) blk: {
939 break :blk indent;
940 } else blk: {
941 try stream.writeByteNTimes(' ', new_indent);
942 break :blk new_indent;
943 };
932 const params = call.params();
933 for (params) |param_node, i| {
934 const param_node_new_indent = if (param_node.id == .MultilineStringLiteral) blk: {
935 break :blk indent;
936 } else blk: {
937 try stream.writeByteNTimes(' ', new_indent);
938 break :blk new_indent;
939 };
944940
945 if (it) |next_node| {
946 try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.None);
947 const comma = tree.nextToken(param_node.lastToken());
948 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,
949 try renderExtraNewline(tree, stream, start_col, next_node.data);
950 } else {
951 try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.Comma);
952 try stream.writeByteNTimes(' ', indent);
953 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
954 }
955 }
941 if (i + 1 < params.len) {
942 try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.None);
943 const comma = tree.nextToken(param_node.lastToken());
944 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,
945 try renderExtraNewline(tree, stream, start_col, params[i + 1]);
946 } else {
947 try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.Comma);
948 try stream.writeByteNTimes(' ', indent);
949 return renderToken(tree, stream, call.rtoken, indent, start_col, space);
956950 }
951 }
952 }
957953
958 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
954 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
959955
960 var it = call_info.params.first;
961 while (it) |param_node_node| : (it = param_node_node.next) {
962 const param_node = param_node_node.data;
963 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None);
956 const params = call.params();
957 for (params) |param_node, i| {
958 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None);
964959
965 if (param_node_node.next != null) {
966 const comma = tree.nextToken(param_node.lastToken());
967 try renderToken(tree, stream, comma, indent, start_col, Space.Space);
968 }
969 }
970 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
971 },
960 if (i + 1 < params.len) {
961 const comma = tree.nextToken(param_node.lastToken());
962 try renderToken(tree, stream, comma, indent, start_col, Space.Space);
963 }
964 }
965 return renderToken(tree, stream, call.rtoken, indent, start_col, space);
966 },
967
968 .SuffixOp => {
969 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
972970
971 switch (suffix_op.op) {
973972 .ArrayAccess => |index_expr| {
974973 const lbracket = tree.nextToken(suffix_op.lhs.lastToken());
975974 const rbracket = tree.nextToken(index_expr.lastToken());
......@@ -1288,14 +1287,14 @@ fn renderExpression(
12881287
12891288 const lbrace = tree.nextToken(err_set_decl.error_token);
12901289
1291 if (err_set_decl.decls.first == null) {
1290 if (err_set_decl.decls_len == 0) {
12921291 try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None);
12931292 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
12941293 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space);
12951294 }
12961295
1297 if (err_set_decl.decls.first.?.next == null) blk: {
1298 const node = err_set_decl.decls.first.?.data;
1296 if (err_set_decl.decls_len == 1) blk: {
1297 const node = err_set_decl.decls()[0];
12991298
13001299 // if there are any doc comments or same line comments
13011300 // don't try to put it all on one line
......@@ -1322,16 +1321,15 @@ fn renderExpression(
13221321 try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // {
13231322 const new_indent = indent + indent_delta;
13241323
1325 var it = err_set_decl.decls.first;
1326 while (it) |node_node| : (it = node_node.next) {
1327 const node = node_node.data;
1324 const decls = err_set_decl.decls();
1325 for (decls) |node, i| {
13281326 try stream.writeByteNTimes(' ', new_indent);
13291327
1330 if (node_node.next) |next_node| {
1328 if (i + 1 < decls.len) {
13311329 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None);
13321330 try renderToken(tree, stream, tree.nextToken(node.lastToken()), new_indent, start_col, Space.Newline); // ,
13331331
1334 try renderExtraNewline(tree, stream, start_col, next_node.data);
1332 try renderExtraNewline(tree, stream, start_col, decls[i + 1]);
13351333 } else {
13361334 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma);
13371335 }
......@@ -1342,16 +1340,15 @@ fn renderExpression(
13421340 } else {
13431341 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); // {
13441342
1345 var it = err_set_decl.decls.first;
1346 while (it) |node_node| : (it = node_node.next) {
1347 const node = node_node.data;
1348 if (node_node.next) |next_node| {
1343 const decls = err_set_decl.decls();
1344 for (decls) |node, i| {
1345 if (i + 1 < decls.len) {
13491346 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);
13501347
13511348 const comma_token = tree.nextToken(node.lastToken());
13521349 assert(tree.tokens[comma_token].id == .Comma);
13531350 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
1354 try renderExtraNewline(tree, stream, start_col, next_node.data);
1351 try renderExtraNewline(tree, stream, start_col, decls[i + 1]);
13551352 } else {
13561353 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Space);
13571354 }
......@@ -1401,12 +1398,8 @@ fn renderExpression(
14011398 try renderToken(tree, stream, builtin_call.builtin_token, indent, start_col, Space.None); // @name
14021399
14031400 const src_params_trailing_comma = blk: {
1404 if (builtin_call.params.first == null or
1405 builtin_call.params.first.?.next == null)
1406 {
1407 break :blk false;
1408 }
1409 const last_node = builtin_call.params.first.?.findLast().data;
1401 if (builtin_call.params_len < 2) break :blk false;
1402 const last_node = builtin_call.params()[builtin_call.params_len - 1];
14101403 const maybe_comma = tree.nextToken(last_node.lastToken());
14111404 break :blk tree.tokens[maybe_comma].id == .Comma;
14121405 };
......@@ -1417,12 +1410,11 @@ fn renderExpression(
14171410 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
14181411
14191412 // render all on one line, no trailing comma
1420 var it = builtin_call.params.first;
1421 while (it) |param_node_node| : (it = param_node_node.next) {
1422 const param_node = param_node_node.data;
1413 const params = builtin_call.params();
1414 for (params) |param_node, i| {
14231415 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None);
14241416
1425 if (param_node_node.next != null) {
1417 if (i + 1 < params.len) {
14261418 const comma_token = tree.nextToken(param_node.lastToken());
14271419 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
14281420 }
......@@ -1432,9 +1424,7 @@ fn renderExpression(
14321424 const new_indent = indent + indent_delta;
14331425 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (
14341426
1435 var it = builtin_call.params.first;
1436 while (it) |param_node_node| : (it = param_node_node.next) {
1437 const param_node = param_node_node.data;
1427 for (builtin_call.params()) |param_node| {
14381428 try stream.writeByteNTimes(' ', new_indent);
14391429 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.Comma);
14401430 }
......@@ -1592,7 +1582,7 @@ fn renderExpression(
15921582 const rparen = tree.nextToken(switch_node.expr.lastToken());
15931583 const lbrace = tree.nextToken(rparen);
15941584
1595 if (switch_node.cases.first == null) {
1585 if (switch_node.cases_len == 0) {
15961586 try renderExpression(allocator, stream, tree, indent, start_col, switch_node.expr, Space.None);
15971587 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
15981588 try renderToken(tree, stream, lbrace, indent, start_col, Space.None); // {
......@@ -1606,14 +1596,13 @@ fn renderExpression(
16061596 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
16071597 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); // {
16081598
1609 var it = switch_node.cases.first;
1610 while (it) |node_node| : (it = node_node.next) {
1611 const node = node_node.data;
1599 const cases = switch_node.cases();
1600 for (cases) |node, i| {
16121601 try stream.writeByteNTimes(' ', new_indent);
16131602 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma);
16141603
1615 if (node_node.next) |next_node| {
1616 try renderExtraNewline(tree, stream, start_col, next_node.data);
1604 if (i + 1 < cases.len) {
1605 try renderExtraNewline(tree, stream, start_col, cases[i + 1]);
16171606 }
16181607 }
16191608
......@@ -1929,7 +1918,7 @@ fn renderExpression(
19291918 try renderToken(tree, stream, tree.nextToken(asm_node.asm_token), indent, start_col, Space.None); // (
19301919 }
19311920
1932 if (asm_node.outputs.first == null and asm_node.inputs.first == null and asm_node.clobbers.first == null) {
1921 if (asm_node.outputs.len == 0 and asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
19331922 try renderExpression(allocator, stream, tree, indent, start_col, asm_node.template, Space.None);
19341923 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
19351924 }
......@@ -1949,7 +1938,7 @@ fn renderExpression(
19491938 const colon1 = tree.nextToken(asm_node.template.lastToken());
19501939 const indent_extra = indent_once + 2;
19511940
1952 const colon2 = if (asm_node.outputs.first == null) blk: {
1941 const colon2 = if (asm_node.outputs.len == 0) blk: {
19531942 try renderToken(tree, stream, colon1, indent, start_col, Space.Newline); // :
19541943 try stream.writeByteNTimes(' ', indent_once);
19551944
......@@ -1957,39 +1946,34 @@ fn renderExpression(
19571946 } else blk: {
19581947 try renderToken(tree, stream, colon1, indent, start_col, Space.Space); // :
19591948
1960 var it = asm_node.outputs.first;
1961 while (true) {
1962 const asm_output_node = it.?;
1963 it = asm_output_node.next;
1964 const asm_output = asm_output_node.data;
1965 const node = &asm_output.base;
1966
1967 if (asm_output_node.next) |next_asm_output| {
1968 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.None);
1969 const next_node = &next_asm_output.data.base;
1949 for (asm_node.outputs) |*asm_output, i| {
1950 if (i + 1 < asm_node.outputs.len) {
1951 const next_asm_output = asm_node.outputs[i + 1];
1952 try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.None);
19701953
1971 const comma = tree.prevToken(next_asm_output.data.firstToken());
1954 const comma = tree.prevToken(next_asm_output.firstToken());
19721955 try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,
1973 try renderExtraNewline(tree, stream, start_col, next_node);
1956 try renderExtraNewlineToken(tree, stream, start_col, next_asm_output.firstToken());
19741957
19751958 try stream.writeByteNTimes(' ', indent_extra);
1976 } else if (asm_node.inputs.first == null and asm_node.clobbers.first == null) {
1977 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);
1959 } else if (asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
1960 try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.Newline);
19781961 try stream.writeByteNTimes(' ', indent);
19791962 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
19801963 } else {
1981 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);
1964 try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.Newline);
19821965 try stream.writeByteNTimes(' ', indent_once);
1983 const comma_or_colon = tree.nextToken(node.lastToken());
1966 const comma_or_colon = tree.nextToken(asm_output.lastToken());
19841967 break :blk switch (tree.tokens[comma_or_colon].id) {
19851968 .Comma => tree.nextToken(comma_or_colon),
19861969 else => comma_or_colon,
19871970 };
19881971 }
19891972 }
1973 unreachable;
19901974 };
19911975
1992 const colon3 = if (asm_node.inputs.first == null) blk: {
1976 const colon3 = if (asm_node.inputs.len == 0) blk: {
19931977 try renderToken(tree, stream, colon2, indent, start_col, Space.Newline); // :
19941978 try stream.writeByteNTimes(' ', indent_once);
19951979
......@@ -1997,46 +1981,37 @@ fn renderExpression(
19971981 } else blk: {
19981982 try renderToken(tree, stream, colon2, indent, start_col, Space.Space); // :
19991983
2000 var it = asm_node.inputs.first;
2001 while (true) {
2002 const asm_input_node = it.?;
2003 it = asm_input_node.next;
2004 const node = &asm_input_node.data.base;
2005
2006 if (it) |next_asm_input| {
2007 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.None);
2008 const next_node = &next_asm_input.data.base;
1984 for (asm_node.inputs) |*asm_input, i| {
1985 if (i + 1 < asm_node.inputs.len) {
1986 const next_asm_input = &asm_node.inputs[i + 1];
1987 try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.None);
20091988
2010 const comma = tree.prevToken(next_asm_input.data.firstToken());
1989 const comma = tree.prevToken(next_asm_input.firstToken());
20111990 try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,
2012 try renderExtraNewline(tree, stream, start_col, next_node);
1991 try renderExtraNewlineToken(tree, stream, start_col, next_asm_input.firstToken());
20131992
20141993 try stream.writeByteNTimes(' ', indent_extra);
2015 } else if (asm_node.clobbers.first == null) {
2016 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);
1994 } else if (asm_node.clobbers.len == 0) {
1995 try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.Newline);
20171996 try stream.writeByteNTimes(' ', indent);
20181997 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space); // )
20191998 } else {
2020 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);
1999 try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.Newline);
20212000 try stream.writeByteNTimes(' ', indent_once);
2022 const comma_or_colon = tree.nextToken(node.lastToken());
2001 const comma_or_colon = tree.nextToken(asm_input.lastToken());
20232002 break :blk switch (tree.tokens[comma_or_colon].id) {
20242003 .Comma => tree.nextToken(comma_or_colon),
20252004 else => comma_or_colon,
20262005 };
20272006 }
20282007 }
2008 unreachable;
20292009 };
20302010
20312011 try renderToken(tree, stream, colon3, indent, start_col, Space.Space); // :
20322012
2033 var it = asm_node.clobbers.first;
2034 while (true) {
2035 const clobber_node_node = it.?;
2036 it = clobber_node_node.next;
2037 const clobber_node = clobber_node_node.data;
2038
2039 if (it == null) {
2013 for (asm_node.clobbers) |clobber_node, i| {
2014 if (i + 1 >= asm_node.clobbers.len) {
20402015 try renderExpression(allocator, stream, tree, indent_extra, start_col, clobber_node, Space.Newline);
20412016 try stream.writeByteNTimes(' ', indent);
20422017 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
......@@ -2048,40 +2023,6 @@ fn renderExpression(
20482023 }
20492024 },
20502025
2051 .AsmInput => {
2052 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
2053
2054 try stream.writeAll("[");
2055 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.symbolic_name, Space.None);
2056 try stream.writeAll("] ");
2057 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.constraint, Space.None);
2058 try stream.writeAll(" (");
2059 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.expr, Space.None);
2060 return renderToken(tree, stream, asm_input.lastToken(), indent, start_col, space); // )
2061 },
2062
2063 .AsmOutput => {
2064 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
2065
2066 try stream.writeAll("[");
2067 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.symbolic_name, Space.None);
2068 try stream.writeAll("] ");
2069 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.constraint, Space.None);
2070 try stream.writeAll(" (");
2071
2072 switch (asm_output.kind) {
2073 ast.Node.AsmOutput.Kind.Variable => |variable_name| {
2074 try renderExpression(allocator, stream, tree, indent, start_col, &variable_name.base, Space.None);
2075 },
2076 ast.Node.AsmOutput.Kind.Return => |return_type| {
2077 try stream.writeAll("-> ");
2078 try renderExpression(allocator, stream, tree, indent, start_col, return_type, Space.None);
2079 },
2080 }
2081
2082 return renderToken(tree, stream, asm_output.lastToken(), indent, start_col, space); // )
2083 },
2084
20852026 .EnumLiteral => {
20862027 const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base);
20872028
......@@ -2098,6 +2039,52 @@ fn renderExpression(
20982039 }
20992040}
21002041
2042fn renderAsmOutput(
2043 allocator: *mem.Allocator,
2044 stream: var,
2045 tree: *ast.Tree,
2046 indent: usize,
2047 start_col: *usize,
2048 asm_output: *const ast.Node.Asm.Output,
2049 space: Space,
2050) (@TypeOf(stream).Error || Error)!void {
2051 try stream.writeAll("[");
2052 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.symbolic_name, Space.None);
2053 try stream.writeAll("] ");
2054 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.constraint, Space.None);
2055 try stream.writeAll(" (");
2056
2057 switch (asm_output.kind) {
2058 ast.Node.Asm.Output.Kind.Variable => |variable_name| {
2059 try renderExpression(allocator, stream, tree, indent, start_col, &variable_name.base, Space.None);
2060 },
2061 ast.Node.Asm.Output.Kind.Return => |return_type| {
2062 try stream.writeAll("-> ");
2063 try renderExpression(allocator, stream, tree, indent, start_col, return_type, Space.None);
2064 },
2065 }
2066
2067 return renderToken(tree, stream, asm_output.lastToken(), indent, start_col, space); // )
2068}
2069
2070fn renderAsmInput(
2071 allocator: *mem.Allocator,
2072 stream: var,
2073 tree: *ast.Tree,
2074 indent: usize,
2075 start_col: *usize,
2076 asm_input: *const ast.Node.Asm.Input,
2077 space: Space,
2078) (@TypeOf(stream).Error || Error)!void {
2079 try stream.writeAll("[");
2080 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.symbolic_name, Space.None);
2081 try stream.writeAll("] ");
2082 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.constraint, Space.None);
2083 try stream.writeAll(" (");
2084 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.expr, Space.None);
2085 return renderToken(tree, stream, asm_input.lastToken(), indent, start_col, space); // )
2086}
2087
21012088fn renderVarDecl(
21022089 allocator: *mem.Allocator,
21032090 stream: var,