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) {...@@ -323,7 +323,7 @@ pub const Error = union(enum) {
323 node: *Node,323 node: *Node,
324324
325 pub fn render(self: *const ExpectedCall, tokens: []const Token, stream: var) !void {325 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 {}", .{
327 @tagName(self.node.id),327 @tagName(self.node.id),
328 });328 });
329 }329 }
...@@ -333,7 +333,7 @@ pub const Error = union(enum) {...@@ -333,7 +333,7 @@ pub const Error = union(enum) {
333 node: *Node,333 node: *Node,
334334
335 pub fn render(self: *const ExpectedCallOrFnProto, tokens: []const Token, stream: var) !void {335 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 " ++
337 @tagName(Node.Id.FnProto) ++ ", found {}", .{@tagName(self.node.id)});337 @tagName(Node.Id.FnProto) ++ ", found {}", .{@tagName(self.node.id)});
338 }338 }
339 };339 };
...@@ -428,15 +428,19 @@ pub const Node = struct {...@@ -428,15 +428,19 @@ pub const Node = struct {
428 // Operators428 // Operators
429 InfixOp,429 InfixOp,
430 PrefixOp,430 PrefixOp,
431 /// Not all suffix operations are under this tag. To save memory, some
432 /// suffix operations have dedicated Node tags.
431 SuffixOp,433 SuffixOp,
432 /// This is a suffix operation but to save memory we have a dedicated Node id for it.434 /// `T{a, b}`
433 ArrayInitializer,435 ArrayInitializer,
434 /// ArrayInitializer but with `.` instead of a left-hand-side operand.436 /// ArrayInitializer but with `.` instead of a left-hand-side operand.
435 ArrayInitializerDot,437 ArrayInitializerDot,
436 /// This is a suffix operation but to save memory we have a dedicated Node id for it.438 /// `T{.a = b}`
437 StructInitializer,439 StructInitializer,
438 /// StructInitializer but with `.` instead of a left-hand-side operand.440 /// StructInitializer but with `.` instead of a left-hand-side operand.
439 StructInitializerDot,441 StructInitializerDot,
442 /// `foo()`
443 Call,
440444
441 // Control flow445 // Control flow
442 Switch,446 Switch,
...@@ -483,8 +487,6 @@ pub const Node = struct {...@@ -483,8 +487,6 @@ pub const Node = struct {
483 PointerIndexPayload,487 PointerIndexPayload,
484 ContainerField,488 ContainerField,
485 ErrorTag,489 ErrorTag,
486 AsmInput,
487 AsmOutput,
488 FieldInitializer,490 FieldInitializer,
489 };491 };
490492
...@@ -780,13 +782,22 @@ pub const Node = struct {...@@ -780,13 +782,22 @@ pub const Node = struct {
780 pub const ErrorSetDecl = struct {782 pub const ErrorSetDecl = struct {
781 base: Node = Node{ .id = .ErrorSetDecl },783 base: Node = Node{ .id = .ErrorSetDecl },
782 error_token: TokenIndex,784 error_token: TokenIndex,
783 decls: DeclList,
784 rbrace_token: TokenIndex,785 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
788 pub fn iterate(self: *const ErrorSetDecl) Node.Iterator {799 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 };
790 }801 }
791802
792 pub fn iterateNext(self: *const ErrorSetDecl, it: *Node.Iterator) ?*Node {803 pub fn iterateNext(self: *const ErrorSetDecl, it: *Node.Iterator) ?*Node {
...@@ -802,6 +813,20 @@ pub const Node = struct {...@@ -802,6 +813,20 @@ pub const Node = struct {
802 pub fn lastToken(self: *const ErrorSetDecl) TokenIndex {813 pub fn lastToken(self: *const ErrorSetDecl) TokenIndex {
803 return self.rbrace_token;814 return self.rbrace_token;
804 }815 }
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 }
805 };830 };
806831
807 /// The fields and decls Node pointers directly follow this struct in memory.832 /// The fields and decls Node pointers directly follow this struct in memory.
...@@ -1464,19 +1489,28 @@ pub const Node = struct {...@@ -1464,19 +1489,28 @@ pub const Node = struct {
1464 }1489 }
1465 };1490 };
14661491
1492 /// The cases node pointers are found in memory after Switch.
1493 /// They must be SwitchCase or SwitchElse nodes.
1467 pub const Switch = struct {1494 pub const Switch = struct {
1468 base: Node = Node{ .id = .Switch },1495 base: Node = Node{ .id = .Switch },
1469 switch_token: TokenIndex,1496 switch_token: TokenIndex,
1497 rbrace: TokenIndex,
1498 cases_len: NodeIndex,
1470 expr: *Node,1499 expr: *Node,
14711500
1472 /// these must be SwitchCase nodes1501 /// After this the caller must initialize the fields_and_decls list.
1473 cases: CaseList,1502 pub fn alloc(allocator: *mem.Allocator, cases_len: NodeIndex) !*Switch {
1474 rbrace: TokenIndex,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
1478 pub fn iterate(self: *const Switch) Node.Iterator {1512 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 };
1480 }1514 }
14811515
1482 pub fn iterateNext(self: *const Switch, it: *Node.Iterator) ?*Node {1516 pub fn iterateNext(self: *const Switch, it: *Node.Iterator) ?*Node {
...@@ -1502,6 +1536,20 @@ pub const Node = struct {...@@ -1502,6 +1536,20 @@ pub const Node = struct {
1502 pub fn lastToken(self: *const Switch) TokenIndex {1536 pub fn lastToken(self: *const Switch) TokenIndex {
1503 return self.rbrace;1537 return self.rbrace;
1504 }1538 }
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 }
1505 };1553 };
15061554
1507 pub const SwitchCase = struct {1555 pub const SwitchCase = struct {
...@@ -2120,6 +2168,66 @@ pub const Node = struct {...@@ -2120,6 +2168,66 @@ pub const Node = struct {
2120 }2168 }
2121 };2169 };
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
2123 pub const SuffixOp = struct {2231 pub const SuffixOp = struct {
2124 base: Node = Node{ .id = .SuffixOp },2232 base: Node = Node{ .id = .SuffixOp },
2125 op: Op,2233 op: Op,
...@@ -2127,19 +2235,11 @@ pub const Node = struct {...@@ -2127,19 +2235,11 @@ pub const Node = struct {
2127 rtoken: TokenIndex,2235 rtoken: TokenIndex,
21282236
2129 pub const Op = union(enum) {2237 pub const Op = union(enum) {
2130 Call: Call,
2131 ArrayAccess: *Node,2238 ArrayAccess: *Node,
2132 Slice: Slice,2239 Slice: Slice,
2133 Deref,2240 Deref,
2134 UnwrapOptional,2241 UnwrapOptional,
21352242
2136 pub const Call = struct {
2137 params: ParamList,
2138 async_token: ?TokenIndex,
2139
2140 pub const ParamList = LinkedList(*Node);
2141 };
2142
2143 pub const Slice = struct {2243 pub const Slice = struct {
2144 start: *Node,2244 start: *Node,
2145 end: ?*Node,2245 end: ?*Node,
...@@ -2148,12 +2248,7 @@ pub const Node = struct {...@@ -2148,12 +2248,7 @@ pub const Node = struct {
2148 };2248 };
21492249
2150 pub fn iterate(self: *const SuffixOp) Node.Iterator {2250 pub fn iterate(self: *const SuffixOp) Node.Iterator {
2151 return .{ .parent_node = &self.base, .index = 0,2251 return .{ .parent_node = &self.base, .index = 0, .node = null};
2152 .node = switch(self.op) {
2153 .Call => |call| call.params.first,
2154 else => null,
2155 },
2156 };
2157 }2252 }
21582253
2159 pub fn iterateNext(self: *const SuffixOp, it: *Node.Iterator) ?*Node {2254 pub fn iterateNext(self: *const SuffixOp, it: *Node.Iterator) ?*Node {
...@@ -2164,13 +2259,6 @@ pub const Node = struct {...@@ -2164,13 +2259,6 @@ pub const Node = struct {
2164 i -= 1;2259 i -= 1;
21652260
2166 switch (self.op) {2261 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 },
2174 .ArrayAccess => |index_expr| {2262 .ArrayAccess => |index_expr| {
2175 if (i < 1) return index_expr;2263 if (i < 1) return index_expr;
2176 i -= 1;2264 i -= 1;
...@@ -2197,10 +2285,6 @@ pub const Node = struct {...@@ -2197,10 +2285,6 @@ pub const Node = struct {
2197 }2285 }
21982286
2199 pub fn firstToken(self: *const SuffixOp) TokenIndex {2287 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 }
2204 return self.lhs.firstToken();2288 return self.lhs.firstToken();
2205 }2289 }
22062290
...@@ -2396,22 +2480,36 @@ pub const Node = struct {...@@ -2396,22 +2480,36 @@ pub const Node = struct {
2396 }2480 }
2397 };2481 };
23982482
2483 /// Parameters are in memory following BuiltinCall.
2399 pub const BuiltinCall = struct {2484 pub const BuiltinCall = struct {
2400 base: Node = Node{ .id = .BuiltinCall },2485 base: Node = Node{ .id = .BuiltinCall },
2486 params_len: NodeIndex,
2401 builtin_token: TokenIndex,2487 builtin_token: TokenIndex,
2402 params: ParamList,
2403 rparen_token: TokenIndex,2488 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
2407 pub fn iterate(self: *const BuiltinCall) Node.Iterator {2501 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 };
2409 }2503 }
24102504
2411 pub fn iterateNext(self: *const BuiltinCall, it: *Node.Iterator) ?*Node {2505 pub fn iterateNext(self: *const BuiltinCall, it: *Node.Iterator) ?*Node {
2412 const param = it.node orelse return null;2506 var i = it.index;
2413 it.node = param.next;2507 it.index += 1;
2414 return param.data;2508
2509 if (i < self.params_len) return self.paramsConst()[i];
2510 i -= self.params_len;
2511
2512 return null;
2415 }2513 }
24162514
2417 pub fn firstToken(self: *const BuiltinCall) TokenIndex {2515 pub fn firstToken(self: *const BuiltinCall) TokenIndex {
...@@ -2421,6 +2519,20 @@ pub const Node = struct {...@@ -2421,6 +2519,20 @@ pub const Node = struct {
2421 pub fn lastToken(self: *const BuiltinCall) TokenIndex {2519 pub fn lastToken(self: *const BuiltinCall) TokenIndex {
2422 return self.rparen_token;2520 return self.rparen_token;
2423 }2521 }
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 }
2424 };2536 };
24252537
2426 pub const StringLiteral = struct {2538 pub const StringLiteral = struct {
...@@ -2554,106 +2666,102 @@ pub const Node = struct {...@@ -2554,106 +2666,102 @@ pub const Node = struct {
2554 }2666 }
2555 };2667 };
25562668
2557 pub const AsmOutput = struct {2669 pub const Asm = struct {
2558 base: Node = Node{ .id = .AsmOutput },2670 base: Node = Node{ .id = .Asm },
2559 lbracket: TokenIndex,2671 asm_token: TokenIndex,
2560 symbolic_name: *Node,
2561 constraint: *Node,
2562 kind: Kind,
2563 rparen: TokenIndex,2672 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) {2692 pub fn iterate(self: *const Output) Node.Iterator {
2566 Variable: *Identifier,2693 return .{ .parent_node = &self.base, .index = 0, .node = null };
2567 Return: *Node,2694 }
2568 };
25692695
2570 pub fn iterate(self: *const AsmOutput) Node.Iterator {2696 pub fn iterateNext(self: *const Output, it: *Node.Iterator) ?*Node {
2571 return .{ .parent_node = &self.base, .index = 0, .node = null };2697 var i = it.index;
2572 }2698 it.index += 1;
25732699
2574 pub fn iterateNext(self: *const AsmOutput, it: *Node.Iterator) ?*Node {2700 if (i < 1) return self.symbolic_name;
2575 var i = it.index;2701 i -= 1;
2576 it.index += 1;
25772702
2578 if (i < 1) return self.symbolic_name;2703 if (i < 1) return self.constraint;
2579 i -= 1;2704 i -= 1;
25802705
2581 if (i < 1) return self.constraint;2706 switch (self.kind) {
2582 i -= 1;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) {2717 return null;
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 },
2593 }2718 }
25942719
2595 return null;2720 pub fn firstToken(self: *const Output) TokenIndex {
2596 }2721 return self.lbracket;
25972722 }
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 };
26062723
2607 pub const AsmInput = struct {2724 pub fn lastToken(self: *const Output) TokenIndex {
2608 base: Node = Node{ .id = .AsmInput },2725 return self.rparen;
2609 lbracket: TokenIndex,2726 }
2610 symbolic_name: *Node,2727 };
2611 constraint: *Node,
2612 expr: *Node,
2613 rparen: TokenIndex,
26142728
2615 pub fn iterate(self: *const AsmInput) Node.Iterator {2729 pub const Input = struct {
2616 return .{ .parent_node = &self.base, .index = 0, .node = null };2730 lbracket: TokenIndex,
2617 }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 {2736 pub fn iterate(self: *const Input) Node.Iterator {
2620 var i = it.index;2737 return .{ .parent_node = &self.base, .index = 0, .node = null };
2621 it.index += 1;2738 }
26222739
2623 if (i < 1) return self.symbolic_name;2740 pub fn iterateNext(self: *const Input, it: *Node.Iterator) ?*Node {
2624 i -= 1;2741 var i = it.index;
2742 it.index += 1;
26252743
2626 if (i < 1) return self.constraint;2744 if (i < 1) return self.symbolic_name;
2627 i -= 1;2745 i -= 1;
26282746
2629 if (i < 1) return self.expr;2747 if (i < 1) return self.constraint;
2630 i -= 1;2748 i -= 1;
26312749
2632 return null;2750 if (i < 1) return self.expr;
2633 }2751 i -= 1;
26342752
2635 pub fn firstToken(self: *const AsmInput) TokenIndex {2753 return null;
2636 return self.lbracket;2754 }
2637 }
26382755
2639 pub fn lastToken(self: *const AsmInput) TokenIndex {2756 pub fn firstToken(self: *const Input) TokenIndex {
2640 return self.rparen;2757 return self.lbracket;
2641 }2758 }
2642 };
26432759
2644 pub const Asm = struct {2760 pub fn lastToken(self: *const Input) TokenIndex {
2645 base: Node = Node{ .id = .Asm },2761 return self.rparen;
2646 asm_token: TokenIndex,2762 }
2647 volatile_token: ?TokenIndex,2763 };
2648 template: *Node,
2649 outputs: OutputList,
2650 inputs: InputList,
2651 clobbers: ClobberList,
2652 rparen: TokenIndex,
26532764
2654 pub const OutputList = LinkedList(*AsmOutput);
2655 pub const InputList = LinkedList(*AsmInput);
2656 pub const ClobberList = LinkedList(*Node);
26572765
2658 pub fn iterate(self: *const Asm) Node.Iterator {2766 pub fn iterate(self: *const Asm) Node.Iterator {
2659 return .{ .parent_node = &self.base, .index = 0, .node = null};2767 return .{ .parent_node = &self.base, .index = 0, .node = null};
...@@ -2663,19 +2771,24 @@ pub const Node = struct {...@@ -2663,19 +2771,24 @@ pub const Node = struct {
2663 var i = it.index;2771 var i = it.index;
2664 it.index += 1;2772 it.index += 1;
26652773
2666 var output: ?*LinkedList(*AsmOutput).Node = self.outputs.first;2774 if (i < self.outputs.len * 3) switch (i % 3) {
2667 while (output) |o| {2775 0 => return self.outputs[i / 3].symbolic_name,
2668 if (i < 1) return &o.data.base;2776 1 => return self.outputs[i / 3].constraint,
2669 i -= 1;2777 2 => switch (self.outputs[i / 3].kind) {
2670 output = o.next;2778 .Variable => |variable_name| return &variable_name.base,
2671 }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;2785 if (i < self.inputs.len * 3) switch (i % 3) {
2674 while (input) |o| {2786 0 => return self.inputs[i / 3].symbolic_name,
2675 if (i < 1) return &o.data.base;2787 1 => return self.inputs[i / 3].constraint,
2676 i -= 1;2788 2 => return self.inputs[i / 3].expr,
2677 input = o.next;2789 else => unreachable,
2678 }2790 };
2791 i -= self.inputs.len * 3;
26792792
2680 return null;2793 return null;
2681 }2794 }
lib/std/zig/parse.zig+93-110
...@@ -520,10 +520,9 @@ const Parser = struct {...@@ -520,10 +520,9 @@ const Parser = struct {
520 p.putBackToken(token);520 p.putBackToken(token);
521 return null;521 return null;
522 };522 };
523 var var_args_token: ?TokenIndex = null;
524 const name_token = p.eatToken(.Identifier);523 const name_token = p.eatToken(.Identifier);
525 const lparen = try p.expectToken(.LParen);524 const lparen = try p.expectToken(.LParen);
526 const params = try p.parseParamDeclList(&var_args_token);525 const params = try p.parseParamDeclList();
527 defer p.gpa.free(params);526 defer p.gpa.free(params);
528 const rparen = try p.expectToken(.RParen);527 const rparen = try p.expectToken(.RParen);
529 const align_expr = try p.parseByteAlign();528 const align_expr = try p.parseByteAlign();
...@@ -547,15 +546,19 @@ const Parser = struct {...@@ -547,15 +546,19 @@ const Parser = struct {
547 else546 else
548 R{ .Explicit = return_type_expr.? };547 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);
553 fn_proto_node.* = .{556 fn_proto_node.* = .{
554 .doc_comments = null,557 .doc_comments = null,
555 .visib_token = null,558 .visib_token = null,
556 .fn_token = fn_token,559 .fn_token = fn_token,
557 .name_token = name_token,560 .name_token = name_token,
558 .params_len = params_len,561 .params_len = params.len,
559 .return_type = return_type,562 .return_type = return_type,
560 .var_args_token = var_args_token,563 .var_args_token = var_args_token,
561 .extern_export_inline_token = null,564 .extern_export_inline_token = null,
...@@ -1455,17 +1458,15 @@ const Parser = struct {...@@ -1455,17 +1458,15 @@ const Parser = struct {
1455 // ignore this, continue parsing1458 // ignore this, continue parsing
1456 return res;1459 return res;
1457 };1460 };
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);
1459 node.* = .{1463 node.* = .{
1460 .lhs = res,1464 .lhs = res,
1461 .op = .{1465 .params_len = params.list.len,
1462 .Call = .{1466 .async_token = async_token,
1463 .params = params.list,
1464 .async_token = async_token,
1465 },
1466 },
1467 .rtoken = params.rparen,1467 .rtoken = params.rparen,
1468 };1468 };
1469 std.mem.copy(*Node, node.params(), params.list);
1469 return &node.base;1470 return &node.base;
1470 }1471 }
1471 if (try p.parsePrimaryTypeExpr()) |expr| {1472 if (try p.parsePrimaryTypeExpr()) |expr| {
...@@ -1482,17 +1483,15 @@ const Parser = struct {...@@ -1482,17 +1483,15 @@ const Parser = struct {
1482 continue;1483 continue;
1483 }1484 }
1484 if (try p.parseFnCallArguments()) |params| {1485 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);
1486 call.* = .{1488 call.* = .{
1487 .lhs = res,1489 .lhs = res,
1488 .op = .{1490 .params_len = params.list.len,
1489 .Call = .{1491 .async_token = null,
1490 .params = params.list,
1491 .async_token = null,
1492 },
1493 },
1494 .rtoken = params.rparen,1492 .rtoken = params.rparen,
1495 };1493 };
1494 std.mem.copy(*Node, call.params(), params.list);
1496 res = &call.base;1495 res = &call.base;
1497 continue;1496 continue;
1498 }1497 }
...@@ -1615,14 +1614,16 @@ const Parser = struct {...@@ -1615,14 +1614,16 @@ const Parser = struct {
1615 return null;1614 return null;
1616 }1615 }
1617 const decls = try p.parseErrorTagList();1616 const decls = try p.parseErrorTagList();
1617 defer p.gpa.free(decls);
1618 const rbrace = try p.expectToken(.RBrace);1618 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);
1621 node.* = .{1621 node.* = .{
1622 .error_token = error_token,1622 .error_token = error_token,
1623 .decls = decls,1623 .decls_len = decls.len,
1624 .rbrace_token = rbrace,1624 .rbrace_token = rbrace,
1625 };1625 };
1626 std.mem.copy(*Node, node.decls(), decls);
1626 return &node.base;1627 return &node.base;
1627 }1628 }
16281629
...@@ -1769,19 +1770,25 @@ const Parser = struct {...@@ -1769,19 +1770,25 @@ const Parser = struct {
1769 _ = try p.expectToken(.RParen);1770 _ = try p.expectToken(.RParen);
1770 _ = try p.expectToken(.LBrace);1771 _ = try p.expectToken(.LBrace);
1771 const cases = try p.parseSwitchProngList();1772 const cases = try p.parseSwitchProngList();
1773 defer p.gpa.free(cases);
1772 const rbrace = try p.expectToken(.RBrace);1774 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);
1775 node.* = .{1777 node.* = .{
1776 .switch_token = switch_token,1778 .switch_token = switch_token,
1777 .expr = expr_node,1779 .expr = expr_node,
1778 .cases = cases,1780 .cases_len = cases.len,
1779 .rbrace = rbrace,1781 .rbrace = rbrace,
1780 };1782 };
1783 std.mem.copy(*Node, node.cases(), cases);
1781 return &node.base;1784 return &node.base;
1782 }1785 }
17831786
1784 /// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN1787 /// 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?
1785 fn parseAsmExpr(p: *Parser) !?*Node {1792 fn parseAsmExpr(p: *Parser) !?*Node {
1786 const asm_token = p.eatToken(.Keyword_asm) orelse return null;1793 const asm_token = p.eatToken(.Keyword_asm) orelse return null;
1787 const volatile_token = p.eatToken(.Keyword_volatile);1794 const volatile_token = p.eatToken(.Keyword_volatile);
...@@ -1790,19 +1797,39 @@ const Parser = struct {...@@ -1790,19 +1797,39 @@ const Parser = struct {
1790 .ExpectedExpr = .{ .token = p.tok_i },1797 .ExpectedExpr = .{ .token = p.tok_i },
1791 });1798 });
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
1793 const node = try p.arena.allocator.create(Node.Asm);1822 const node = try p.arena.allocator.create(Node.Asm);
1794 node.* = .{1823 node.* = .{
1795 .asm_token = asm_token,1824 .asm_token = asm_token,
1796 .volatile_token = volatile_token,1825 .volatile_token = volatile_token,
1797 .template = template,1826 .template = template,
1798 .outputs = Node.Asm.OutputList{},1827 .outputs = arena_outputs,
1799 .inputs = Node.Asm.InputList{},1828 .inputs = arena_inputs,
1800 .clobbers = Node.Asm.ClobberList{},1829 .clobbers = arena_clobbers,
1801 .rparen = undefined,1830 .rparen = try p.expectToken(.RParen),
1802 };1831 };
18031832
1804 try p.parseAsmOutput(node);
1805 node.rparen = try p.expectToken(.RParen);
1806 return &node.base;1833 return &node.base;
1807 }1834 }
18081835
...@@ -1828,15 +1855,8 @@ const Parser = struct {...@@ -1828,15 +1855,8 @@ const Parser = struct {
1828 return null;1855 return null;
1829 }1856 }
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
1838 /// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN1858 /// 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 {
1840 const lbracket = p.eatToken(.LBracket) orelse return null;1860 const lbracket = p.eatToken(.LBracket) orelse return null;
1841 const name = try p.expectNode(parseIdentifier, .{1861 const name = try p.expectNode(parseIdentifier, .{
1842 .ExpectedIdentifier = .{ .token = p.tok_i },1862 .ExpectedIdentifier = .{ .token = p.tok_i },
...@@ -1848,7 +1868,7 @@ const Parser = struct {...@@ -1848,7 +1868,7 @@ const Parser = struct {
1848 });1868 });
18491869
1850 _ = try p.expectToken(.LParen);1870 _ = try p.expectToken(.LParen);
1851 const kind: Node.AsmOutput.Kind = blk: {1871 const kind: Node.Asm.Output.Kind = blk: {
1852 if (p.eatToken(.Arrow) != null) {1872 if (p.eatToken(.Arrow) != null) {
1853 const return_ident = try p.expectNode(parseTypeExpr, .{1873 const return_ident = try p.expectNode(parseTypeExpr, .{
1854 .ExpectedTypeExpr = .{ .token = p.tok_i },1874 .ExpectedTypeExpr = .{ .token = p.tok_i },
...@@ -1862,26 +1882,17 @@ const Parser = struct {...@@ -1862,26 +1882,17 @@ const Parser = struct {
1862 };1882 };
1863 const rparen = try p.expectToken(.RParen);1883 const rparen = try p.expectToken(.RParen);
18641884
1865 const node = try p.arena.allocator.create(Node.AsmOutput);1885 return Node.Asm.Output{
1866 node.* = .{
1867 .lbracket = lbracket,1886 .lbracket = lbracket,
1868 .symbolic_name = name,1887 .symbolic_name = name,
1869 .constraint = constraint,1888 .constraint = constraint,
1870 .kind = kind,1889 .kind = kind,
1871 .rparen = rparen,1890 .rparen = rparen,
1872 };1891 };
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);
1881 }1892 }
18821893
1883 /// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN1894 /// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN
1884 fn parseAsmInputItem(p: *Parser) !?*Node.AsmInput {1895 fn parseAsmInputItem(p: *Parser) !?Node.Asm.Input {
1885 const lbracket = p.eatToken(.LBracket) orelse return null;1896 const lbracket = p.eatToken(.LBracket) orelse return null;
1886 const name = try p.expectNode(parseIdentifier, .{1897 const name = try p.expectNode(parseIdentifier, .{
1887 .ExpectedIdentifier = .{ .token = p.tok_i },1898 .ExpectedIdentifier = .{ .token = p.tok_i },
...@@ -1898,25 +1909,13 @@ const Parser = struct {...@@ -1898,25 +1909,13 @@ const Parser = struct {
1898 });1909 });
1899 const rparen = try p.expectToken(.RParen);1910 const rparen = try p.expectToken(.RParen);
19001911
1901 const node = try p.arena.allocator.create(Node.AsmInput);1912 return Node.Asm.Input{
1902 node.* = .{
1903 .lbracket = lbracket,1913 .lbracket = lbracket,
1904 .symbolic_name = name,1914 .symbolic_name = name,
1905 .constraint = constraint,1915 .constraint = constraint,
1906 .expr = expr,1916 .expr = expr,
1907 .rparen = rparen,1917 .rparen = rparen,
1908 };1918 };
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);
1920 }1919 }
19211920
1922 /// BreakLabel <- COLON IDENTIFIER1921 /// BreakLabel <- COLON IDENTIFIER
...@@ -1999,7 +1998,7 @@ const Parser = struct {...@@ -1999,7 +1998,7 @@ const Parser = struct {
1999 }1998 }
20001999
2001 /// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType2000 /// 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 {
2003 const doc_comments = try p.parseDocComment();2002 const doc_comments = try p.parseDocComment();
2004 const noalias_token = p.eatToken(.Keyword_noalias);2003 const noalias_token = p.eatToken(.Keyword_noalias);
2005 const comptime_token = if (noalias_token == null) p.eatToken(.Keyword_comptime) else null;2004 const comptime_token = if (noalias_token == null) p.eatToken(.Keyword_comptime) else null;
...@@ -2014,21 +2013,23 @@ const Parser = struct {...@@ -2014,21 +2013,23 @@ const Parser = struct {
2014 if (noalias_token == null and2013 if (noalias_token == null and
2015 comptime_token == null and2014 comptime_token == null and
2016 name_token == null and2015 name_token == null and
2017 doc_comments == null) return false;2016 doc_comments == null)
2017 {
2018 return null;
2019 }
2018 try p.errors.append(p.gpa, .{2020 try p.errors.append(p.gpa, .{
2019 .ExpectedParamType = .{ .token = p.tok_i },2021 .ExpectedParamType = .{ .token = p.tok_i },
2020 });2022 });
2021 return error.ParseError;2023 return error.ParseError;
2022 };2024 };
20232025
2024 (try list.addOne()).* = .{2026 return Node.FnProto.ParamDecl{
2025 .doc_comments = doc_comments,2027 .doc_comments = doc_comments,
2026 .comptime_token = comptime_token,2028 .comptime_token = comptime_token,
2027 .noalias_token = noalias_token,2029 .noalias_token = noalias_token,
2028 .name_token = name_token,2030 .name_token = name_token,
2029 .param_type = param_type,2031 .param_type = param_type,
2030 };2032 };
2031 return true;
2032 }2033 }
20332034
2034 /// ParamType2035 /// ParamType
...@@ -2714,13 +2715,14 @@ const Parser = struct {...@@ -2714,13 +2715,14 @@ const Parser = struct {
2714 /// ExprList <- (Expr COMMA)* Expr?2715 /// ExprList <- (Expr COMMA)* Expr?
2715 fn parseFnCallArguments(p: *Parser) !?AnnotatedParamList {2716 fn parseFnCallArguments(p: *Parser) !?AnnotatedParamList {
2716 if (p.eatToken(.LParen) == null) return null;2717 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);
2718 const rparen = try p.expectToken(.RParen);2720 const rparen = try p.expectToken(.RParen);
2719 return AnnotatedParamList{ .list = list, .rparen = rparen };2721 return AnnotatedParamList{ .list = list, .rparen = rparen };
2720 }2722 }
27212723
2722 const AnnotatedParamList = struct {2724 const AnnotatedParamList = struct {
2723 list: std.SinglyLinkedList(*Node),2725 list: []*Node,
2724 rparen: TokenIndex,2726 rparen: TokenIndex,
2725 };2727 };
27262728
...@@ -2936,62 +2938,40 @@ const Parser = struct {...@@ -2936,62 +2938,40 @@ const Parser = struct {
29362938
2937 /// IdentifierList <- (IDENTIFIER COMMA)* IDENTIFIER?2939 /// IdentifierList <- (IDENTIFIER COMMA)* IDENTIFIER?
2938 /// Only ErrorSetDecl parses an IdentifierList2940 /// Only ErrorSetDecl parses an IdentifierList
2939 fn parseErrorTagList(p: *Parser) !Node.ErrorSetDecl.DeclList {2941 fn parseErrorTagList(p: *Parser) ![]*Node {
2940 return ListParseFn(Node.ErrorSetDecl.DeclList, parseErrorTag)(p);2942 return ListParseFn(*Node, parseErrorTag)(p);
2941 }2943 }
29422944
2943 /// SwitchProngList <- (SwitchProng COMMA)* SwitchProng?2945 /// SwitchProngList <- (SwitchProng COMMA)* SwitchProng?
2944 fn parseSwitchProngList(p: *Parser) !Node.Switch.CaseList {2946 fn parseSwitchProngList(p: *Parser) ![]*Node {
2945 return ListParseFn(Node.Switch.CaseList, parseSwitchProng)(p);2947 return ListParseFn(*Node, parseSwitchProng)(p);
2946 }2948 }
29472949
2948 /// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?2950 /// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?
2949 fn parseAsmOutputList(p: *Parser) Error!Node.Asm.OutputList {2951 fn parseAsmOutputList(p: *Parser) Error![]Node.Asm.Output {
2950 return ListParseFn(Node.Asm.OutputList, parseAsmOutputItem)(p);2952 return ListParseFn(Node.Asm.Output, parseAsmOutputItem)(p);
2951 }2953 }
29522954
2953 /// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?2955 /// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?
2954 fn parseAsmInputList(p: *Parser) Error!Node.Asm.InputList {2956 fn parseAsmInputList(p: *Parser) Error![]Node.Asm.Input {
2955 return ListParseFn(Node.Asm.InputList, parseAsmInputItem)(p);2957 return ListParseFn(Node.Asm.Input, parseAsmInputItem)(p);
2956 }2958 }
29572959
2958 /// ParamDeclList <- (ParamDecl COMMA)* ParamDecl?2960 /// ParamDeclList <- (ParamDecl COMMA)* ParamDecl?
2959 fn parseParamDeclList(p: *Parser, var_args_token: *?TokenIndex) ![]Node.FnProto.ParamDecl {2961 fn parseParamDeclList(p: *Parser) ![]Node.FnProto.ParamDecl {
2960 var list = std.ArrayList(Node.FnProto.ParamDecl).init(p.gpa);2962 return ListParseFn(Node.FnProto.ParamDecl, parseParamDecl)(p);
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();
2984 }2963 }
29852964
2986 const NodeParseFn = fn (p: *Parser) Error!?*Node;2965 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) {
2989 return struct {2968 return struct {
2990 pub fn parse(p: *Parser) !L {2969 pub fn parse(p: *Parser) ![]E {
2991 var list = L{};2970 var list = std.ArrayList(E).init(p.gpa);
2992 var list_it = &list.first;2971 defer list.deinit();
2993 while (try nodeParseFn(p)) |node| {2972
2994 list_it = try p.llpush(L.Node.Data, list_it, node);2973 while (try nodeParseFn(p)) |item| {
2974 try list.append(item);
29952975
2996 switch (p.tokens[p.tok_i].id) {2976 switch (p.tokens[p.tok_i].id) {
2997 .Comma => _ = p.nextToken(),2977 .Comma => _ = p.nextToken(),
...@@ -3006,7 +2986,7 @@ const Parser = struct {...@@ -3006,7 +2986,7 @@ const Parser = struct {
3006 },2986 },
3007 }2987 }
3008 }2988 }
3009 return list;2989 return list.toOwnedSlice();
3010 }2990 }
3011 }.parse;2991 }.parse;
3012 }2992 }
...@@ -3053,12 +3033,15 @@ const Parser = struct {...@@ -3053,12 +3033,15 @@ const Parser = struct {
3053 };3033 };
3054 return &node.base;3034 return &node.base;
3055 };3035 };
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);
3057 node.* = .{3039 node.* = .{
3058 .builtin_token = token,3040 .builtin_token = token,
3059 .params = params.list,3041 .params_len = params.list.len,
3060 .rparen_token = params.rparen,3042 .rparen_token = params.rparen,
3061 };3043 };
3044 std.mem.copy(*Node, node.params(), params.list);
3062 return &node.base;3045 return &node.base;
3063 }3046 }
30643047
lib/std/zig/render.zig+151-164
...@@ -187,7 +187,10 @@ fn renderRoot(...@@ -187,7 +187,10 @@ fn renderRoot(
187}187}
188188
189fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) @TypeOf(stream).Error!void {189fn 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 {
191 var prev_token = first_token;194 var prev_token = first_token;
192 if (prev_token == 0) return;195 if (prev_token == 0) return;
193 var newline_threshold: usize = 2;196 var newline_threshold: usize = 2;
...@@ -902,74 +905,70 @@ fn renderExpression(...@@ -902,74 +905,70 @@ fn renderExpression(
902 return renderToken(tree, stream, rtoken, indent, start_col, space);905 return renderToken(tree, stream, rtoken, indent, start_col, space);
903 },906 },
904907
905 .SuffixOp => {908 .Call => {
906 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);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) {914 try renderExpression(allocator, stream, tree, indent, start_col, call.lhs, Space.None);
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 }
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) {923 const src_has_trailing_comma = blk: {
919 try renderToken(tree, stream, lparen, indent, start_col, Space.None);924 const maybe_comma = tree.prevToken(call.rtoken);
920 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);925 break :blk tree.tokens[maybe_comma].id == .Comma;
921 }926 };
922927
923 const src_has_trailing_comma = blk: {928 if (src_has_trailing_comma) {
924 const maybe_comma = tree.prevToken(suffix_op.rtoken);929 const new_indent = indent + indent_delta;
925 break :blk tree.tokens[maybe_comma].id == .Comma;930 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline);
926 };
927931
928 if (src_has_trailing_comma) {932 const params = call.params();
929 const new_indent = indent + indent_delta;933 for (params) |param_node, i| {
930 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline);934 const param_node_new_indent = if (param_node.id == .MultilineStringLiteral) blk: {
931935 break :blk indent;
932 var it = call_info.params.first;936 } else blk: {
933 while (true) {937 try stream.writeByteNTimes(' ', new_indent);
934 const param_node_node = it.?;938 break :blk new_indent;
935 it = param_node_node.next;939 };
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 };
944940
945 if (it) |next_node| {941 if (i + 1 < params.len) {
946 try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.None);942 try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.None);
947 const comma = tree.nextToken(param_node.lastToken());943 const comma = tree.nextToken(param_node.lastToken());
948 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,944 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,
949 try renderExtraNewline(tree, stream, start_col, next_node.data);945 try renderExtraNewline(tree, stream, start_col, params[i + 1]);
950 } else {946 } else {
951 try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.Comma);947 try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.Comma);
952 try stream.writeByteNTimes(' ', indent);948 try stream.writeByteNTimes(' ', indent);
953 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);949 return renderToken(tree, stream, call.rtoken, indent, start_col, space);
954 }
955 }
956 }950 }
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;956 const params = call.params();
961 while (it) |param_node_node| : (it = param_node_node.next) {957 for (params) |param_node, i| {
962 const param_node = param_node_node.data;958 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None);
963 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None);
964959
965 if (param_node_node.next != null) {960 if (i + 1 < params.len) {
966 const comma = tree.nextToken(param_node.lastToken());961 const comma = tree.nextToken(param_node.lastToken());
967 try renderToken(tree, stream, comma, indent, start_col, Space.Space);962 try renderToken(tree, stream, comma, indent, start_col, Space.Space);
968 }963 }
969 }964 }
970 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);965 return renderToken(tree, stream, call.rtoken, indent, start_col, space);
971 },966 },
967
968 .SuffixOp => {
969 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
972970
971 switch (suffix_op.op) {
973 .ArrayAccess => |index_expr| {972 .ArrayAccess => |index_expr| {
974 const lbracket = tree.nextToken(suffix_op.lhs.lastToken());973 const lbracket = tree.nextToken(suffix_op.lhs.lastToken());
975 const rbracket = tree.nextToken(index_expr.lastToken());974 const rbracket = tree.nextToken(index_expr.lastToken());
...@@ -1288,14 +1287,14 @@ fn renderExpression(...@@ -1288,14 +1287,14 @@ fn renderExpression(
12881287
1289 const lbrace = tree.nextToken(err_set_decl.error_token);1288 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) {
1292 try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None);1291 try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None);
1293 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);1292 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
1294 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space);1293 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space);
1295 }1294 }
12961295
1297 if (err_set_decl.decls.first.?.next == null) blk: {1296 if (err_set_decl.decls_len == 1) blk: {
1298 const node = err_set_decl.decls.first.?.data;1297 const node = err_set_decl.decls()[0];
12991298
1300 // if there are any doc comments or same line comments1299 // if there are any doc comments or same line comments
1301 // don't try to put it all on one line1300 // don't try to put it all on one line
...@@ -1322,16 +1321,15 @@ fn renderExpression(...@@ -1322,16 +1321,15 @@ fn renderExpression(
1322 try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // {1321 try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // {
1323 const new_indent = indent + indent_delta;1322 const new_indent = indent + indent_delta;
13241323
1325 var it = err_set_decl.decls.first;1324 const decls = err_set_decl.decls();
1326 while (it) |node_node| : (it = node_node.next) {1325 for (decls) |node, i| {
1327 const node = node_node.data;
1328 try stream.writeByteNTimes(' ', new_indent);1326 try stream.writeByteNTimes(' ', new_indent);
13291327
1330 if (node_node.next) |next_node| {1328 if (i + 1 < decls.len) {
1331 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None);1329 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None);
1332 try renderToken(tree, stream, tree.nextToken(node.lastToken()), new_indent, start_col, Space.Newline); // ,1330 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]);
1335 } else {1333 } else {
1336 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma);1334 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma);
1337 }1335 }
...@@ -1342,16 +1340,15 @@ fn renderExpression(...@@ -1342,16 +1340,15 @@ fn renderExpression(
1342 } else {1340 } else {
1343 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); // {1341 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); // {
13441342
1345 var it = err_set_decl.decls.first;1343 const decls = err_set_decl.decls();
1346 while (it) |node_node| : (it = node_node.next) {1344 for (decls) |node, i| {
1347 const node = node_node.data;1345 if (i + 1 < decls.len) {
1348 if (node_node.next) |next_node| {
1349 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);1346 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);
13501347
1351 const comma_token = tree.nextToken(node.lastToken());1348 const comma_token = tree.nextToken(node.lastToken());
1352 assert(tree.tokens[comma_token].id == .Comma);1349 assert(tree.tokens[comma_token].id == .Comma);
1353 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,1350 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]);
1355 } else {1352 } else {
1356 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Space);1353 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Space);
1357 }1354 }
...@@ -1401,12 +1398,8 @@ fn renderExpression(...@@ -1401,12 +1398,8 @@ fn renderExpression(
1401 try renderToken(tree, stream, builtin_call.builtin_token, indent, start_col, Space.None); // @name1398 try renderToken(tree, stream, builtin_call.builtin_token, indent, start_col, Space.None); // @name
14021399
1403 const src_params_trailing_comma = blk: {1400 const src_params_trailing_comma = blk: {
1404 if (builtin_call.params.first == null or1401 if (builtin_call.params_len < 2) break :blk false;
1405 builtin_call.params.first.?.next == null)1402 const last_node = builtin_call.params()[builtin_call.params_len - 1];
1406 {
1407 break :blk false;
1408 }
1409 const last_node = builtin_call.params.first.?.findLast().data;
1410 const maybe_comma = tree.nextToken(last_node.lastToken());1403 const maybe_comma = tree.nextToken(last_node.lastToken());
1411 break :blk tree.tokens[maybe_comma].id == .Comma;1404 break :blk tree.tokens[maybe_comma].id == .Comma;
1412 };1405 };
...@@ -1417,12 +1410,11 @@ fn renderExpression(...@@ -1417,12 +1410,11 @@ fn renderExpression(
1417 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (1410 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
14181411
1419 // render all on one line, no trailing comma1412 // render all on one line, no trailing comma
1420 var it = builtin_call.params.first;1413 const params = builtin_call.params();
1421 while (it) |param_node_node| : (it = param_node_node.next) {1414 for (params) |param_node, i| {
1422 const param_node = param_node_node.data;
1423 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None);1415 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) {
1426 const comma_token = tree.nextToken(param_node.lastToken());1418 const comma_token = tree.nextToken(param_node.lastToken());
1427 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,1419 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
1428 }1420 }
...@@ -1432,9 +1424,7 @@ fn renderExpression(...@@ -1432,9 +1424,7 @@ fn renderExpression(
1432 const new_indent = indent + indent_delta;1424 const new_indent = indent + indent_delta;
1433 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (1425 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (
14341426
1435 var it = builtin_call.params.first;1427 for (builtin_call.params()) |param_node| {
1436 while (it) |param_node_node| : (it = param_node_node.next) {
1437 const param_node = param_node_node.data;
1438 try stream.writeByteNTimes(' ', new_indent);1428 try stream.writeByteNTimes(' ', new_indent);
1439 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.Comma);1429 try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.Comma);
1440 }1430 }
...@@ -1592,7 +1582,7 @@ fn renderExpression(...@@ -1592,7 +1582,7 @@ fn renderExpression(
1592 const rparen = tree.nextToken(switch_node.expr.lastToken());1582 const rparen = tree.nextToken(switch_node.expr.lastToken());
1593 const lbrace = tree.nextToken(rparen);1583 const lbrace = tree.nextToken(rparen);
15941584
1595 if (switch_node.cases.first == null) {1585 if (switch_node.cases_len == 0) {
1596 try renderExpression(allocator, stream, tree, indent, start_col, switch_node.expr, Space.None);1586 try renderExpression(allocator, stream, tree, indent, start_col, switch_node.expr, Space.None);
1597 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )1587 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
1598 try renderToken(tree, stream, lbrace, indent, start_col, Space.None); // {1588 try renderToken(tree, stream, lbrace, indent, start_col, Space.None); // {
...@@ -1606,14 +1596,13 @@ fn renderExpression(...@@ -1606,14 +1596,13 @@ fn renderExpression(
1606 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )1596 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
1607 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); // {1597 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); // {
16081598
1609 var it = switch_node.cases.first;1599 const cases = switch_node.cases();
1610 while (it) |node_node| : (it = node_node.next) {1600 for (cases) |node, i| {
1611 const node = node_node.data;
1612 try stream.writeByteNTimes(' ', new_indent);1601 try stream.writeByteNTimes(' ', new_indent);
1613 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma);1602 try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma);
16141603
1615 if (node_node.next) |next_node| {1604 if (i + 1 < cases.len) {
1616 try renderExtraNewline(tree, stream, start_col, next_node.data);1605 try renderExtraNewline(tree, stream, start_col, cases[i + 1]);
1617 }1606 }
1618 }1607 }
16191608
...@@ -1929,7 +1918,7 @@ fn renderExpression(...@@ -1929,7 +1918,7 @@ fn renderExpression(
1929 try renderToken(tree, stream, tree.nextToken(asm_node.asm_token), indent, start_col, Space.None); // (1918 try renderToken(tree, stream, tree.nextToken(asm_node.asm_token), indent, start_col, Space.None); // (
1930 }1919 }
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) {
1933 try renderExpression(allocator, stream, tree, indent, start_col, asm_node.template, Space.None);1922 try renderExpression(allocator, stream, tree, indent, start_col, asm_node.template, Space.None);
1934 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);1923 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
1935 }1924 }
...@@ -1949,7 +1938,7 @@ fn renderExpression(...@@ -1949,7 +1938,7 @@ fn renderExpression(
1949 const colon1 = tree.nextToken(asm_node.template.lastToken());1938 const colon1 = tree.nextToken(asm_node.template.lastToken());
1950 const indent_extra = indent_once + 2;1939 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: {
1953 try renderToken(tree, stream, colon1, indent, start_col, Space.Newline); // :1942 try renderToken(tree, stream, colon1, indent, start_col, Space.Newline); // :
1954 try stream.writeByteNTimes(' ', indent_once);1943 try stream.writeByteNTimes(' ', indent_once);
19551944
...@@ -1957,39 +1946,34 @@ fn renderExpression(...@@ -1957,39 +1946,34 @@ fn renderExpression(
1957 } else blk: {1946 } else blk: {
1958 try renderToken(tree, stream, colon1, indent, start_col, Space.Space); // :1947 try renderToken(tree, stream, colon1, indent, start_col, Space.Space); // :
19591948
1960 var it = asm_node.outputs.first;1949 for (asm_node.outputs) |*asm_output, i| {
1961 while (true) {1950 if (i + 1 < asm_node.outputs.len) {
1962 const asm_output_node = it.?;1951 const next_asm_output = asm_node.outputs[i + 1];
1963 it = asm_output_node.next;1952 try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.None);
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;
19701953
1971 const comma = tree.prevToken(next_asm_output.data.firstToken());1954 const comma = tree.prevToken(next_asm_output.firstToken());
1972 try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,1955 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
1975 try stream.writeByteNTimes(' ', indent_extra);1958 try stream.writeByteNTimes(' ', indent_extra);
1976 } else if (asm_node.inputs.first == null and asm_node.clobbers.first == null) {1959 } else if (asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
1977 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);1960 try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.Newline);
1978 try stream.writeByteNTimes(' ', indent);1961 try stream.writeByteNTimes(' ', indent);
1979 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);1962 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
1980 } else {1963 } 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);
1982 try stream.writeByteNTimes(' ', indent_once);1965 try stream.writeByteNTimes(' ', indent_once);
1983 const comma_or_colon = tree.nextToken(node.lastToken());1966 const comma_or_colon = tree.nextToken(asm_output.lastToken());
1984 break :blk switch (tree.tokens[comma_or_colon].id) {1967 break :blk switch (tree.tokens[comma_or_colon].id) {
1985 .Comma => tree.nextToken(comma_or_colon),1968 .Comma => tree.nextToken(comma_or_colon),
1986 else => comma_or_colon,1969 else => comma_or_colon,
1987 };1970 };
1988 }1971 }
1989 }1972 }
1973 unreachable;
1990 };1974 };
19911975
1992 const colon3 = if (asm_node.inputs.first == null) blk: {1976 const colon3 = if (asm_node.inputs.len == 0) blk: {
1993 try renderToken(tree, stream, colon2, indent, start_col, Space.Newline); // :1977 try renderToken(tree, stream, colon2, indent, start_col, Space.Newline); // :
1994 try stream.writeByteNTimes(' ', indent_once);1978 try stream.writeByteNTimes(' ', indent_once);
19951979
...@@ -1997,46 +1981,37 @@ fn renderExpression(...@@ -1997,46 +1981,37 @@ fn renderExpression(
1997 } else blk: {1981 } else blk: {
1998 try renderToken(tree, stream, colon2, indent, start_col, Space.Space); // :1982 try renderToken(tree, stream, colon2, indent, start_col, Space.Space); // :
19991983
2000 var it = asm_node.inputs.first;1984 for (asm_node.inputs) |*asm_input, i| {
2001 while (true) {1985 if (i + 1 < asm_node.inputs.len) {
2002 const asm_input_node = it.?;1986 const next_asm_input = &asm_node.inputs[i + 1];
2003 it = asm_input_node.next;1987 try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.None);
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;
20091988
2010 const comma = tree.prevToken(next_asm_input.data.firstToken());1989 const comma = tree.prevToken(next_asm_input.firstToken());
2011 try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,1990 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
2014 try stream.writeByteNTimes(' ', indent_extra);1993 try stream.writeByteNTimes(' ', indent_extra);
2015 } else if (asm_node.clobbers.first == null) {1994 } else if (asm_node.clobbers.len == 0) {
2016 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);1995 try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.Newline);
2017 try stream.writeByteNTimes(' ', indent);1996 try stream.writeByteNTimes(' ', indent);
2018 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space); // )1997 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space); // )
2019 } else {1998 } 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);
2021 try stream.writeByteNTimes(' ', indent_once);2000 try stream.writeByteNTimes(' ', indent_once);
2022 const comma_or_colon = tree.nextToken(node.lastToken());2001 const comma_or_colon = tree.nextToken(asm_input.lastToken());
2023 break :blk switch (tree.tokens[comma_or_colon].id) {2002 break :blk switch (tree.tokens[comma_or_colon].id) {
2024 .Comma => tree.nextToken(comma_or_colon),2003 .Comma => tree.nextToken(comma_or_colon),
2025 else => comma_or_colon,2004 else => comma_or_colon,
2026 };2005 };
2027 }2006 }
2028 }2007 }
2008 unreachable;
2029 };2009 };
20302010
2031 try renderToken(tree, stream, colon3, indent, start_col, Space.Space); // :2011 try renderToken(tree, stream, colon3, indent, start_col, Space.Space); // :
20322012
2033 var it = asm_node.clobbers.first;2013 for (asm_node.clobbers) |clobber_node, i| {
2034 while (true) {2014 if (i + 1 >= asm_node.clobbers.len) {
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) {
2040 try renderExpression(allocator, stream, tree, indent_extra, start_col, clobber_node, Space.Newline);2015 try renderExpression(allocator, stream, tree, indent_extra, start_col, clobber_node, Space.Newline);
2041 try stream.writeByteNTimes(' ', indent);2016 try stream.writeByteNTimes(' ', indent);
2042 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);2017 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
...@@ -2048,40 +2023,6 @@ fn renderExpression(...@@ -2048,40 +2023,6 @@ fn renderExpression(
2048 }2023 }
2049 },2024 },
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
2085 .EnumLiteral => {2026 .EnumLiteral => {
2086 const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base);2027 const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base);
20872028
...@@ -2098,6 +2039,52 @@ fn renderExpression(...@@ -2098,6 +2039,52 @@ fn renderExpression(
2098 }2039 }
2099}2040}
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
2101fn renderVarDecl(2088fn renderVarDecl(
2102 allocator: *mem.Allocator,2089 allocator: *mem.Allocator,
2103 stream: var,2090 stream: var,