authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-20 17:39:54-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-20 17:39:54-04:00
log7c2c0e36f8378d8efaf64d859bdffb91007db82a
treea8335099205f30d5bf9b4478ee9d73824b2f0abf
parent5db9f306ba88087d269dc5fe5672a5af5ab55333

stage2 parser: different memory layout of ParamDecl

Instead of being its own node, it's a struct inside FnProto. Instead of FnProto having a SinglyLinkedList of ParamDecl nodes, ParamDecls are appended directly in memory after the FnProto. throughput: 72.2 MiB/s => 72.9 MiB/s maxrss: 70 KB => 68 KB Importantly, the API is improved as well since the data is arranged linearly in memory.

3 files changed, 123 insertions(+), 105 deletions(-)

lib/std/zig/ast.zig+89-62
...@@ -477,7 +477,6 @@ pub const Node = struct {...@@ -477,7 +477,6 @@ pub const Node = struct {
477 ErrorTag,477 ErrorTag,
478 AsmInput,478 AsmInput,
479 AsmOutput,479 AsmOutput,
480 ParamDecl,
481 FieldInitializer,480 FieldInitializer,
482 };481 };
483482
...@@ -533,7 +532,6 @@ pub const Node = struct {...@@ -533,7 +532,6 @@ pub const Node = struct {
533 switch (n.id) {532 switch (n.id) {
534 .Root,533 .Root,
535 .ContainerField,534 .ContainerField,
536 .ParamDecl,
537 .Block,535 .Block,
538 .Payload,536 .Payload,
539 .PointerPayload,537 .PointerPayload,
...@@ -819,7 +817,7 @@ pub const Node = struct {...@@ -819,7 +817,7 @@ pub const Node = struct {
819 return @ptrCast(*ContainerDecl, bytes.ptr);817 return @ptrCast(*ContainerDecl, bytes.ptr);
820 }818 }
821819
822 pub fn free(self: *Decl, allocator: *mem.Allocator) void {820 pub fn free(self: *ContainerDecl, allocator: *mem.Allocator) void {
823 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.fields_and_decls_len)];821 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.fields_and_decls_len)];
824 allocator.free(bytes);822 allocator.free(bytes);
825 }823 }
...@@ -979,13 +977,14 @@ pub const Node = struct {...@@ -979,13 +977,14 @@ pub const Node = struct {
979 }977 }
980 };978 };
981979
980 /// The params are directly after the FnProto in memory.
982 pub const FnProto = struct {981 pub const FnProto = struct {
983 base: Node = Node{ .id = .FnProto },982 base: Node = Node{ .id = .FnProto },
984 doc_comments: ?*DocComment,983 doc_comments: ?*DocComment,
985 visib_token: ?TokenIndex,984 visib_token: ?TokenIndex,
986 fn_token: TokenIndex,985 fn_token: TokenIndex,
987 name_token: ?TokenIndex,986 name_token: ?TokenIndex,
988 params: ParamList,987 params_len: NodeIndex,
989 return_type: ReturnType,988 return_type: ReturnType,
990 var_args_token: ?TokenIndex,989 var_args_token: ?TokenIndex,
991 extern_export_inline_token: ?TokenIndex,990 extern_export_inline_token: ?TokenIndex,
...@@ -997,16 +996,75 @@ pub const Node = struct {...@@ -997,16 +996,75 @@ pub const Node = struct {
997 is_extern_prototype: bool = false, // TODO: Remove once extern fn rewriting is996 is_extern_prototype: bool = false, // TODO: Remove once extern fn rewriting is
998 is_async: bool = false, // TODO: remove once async fn rewriting is997 is_async: bool = false, // TODO: remove once async fn rewriting is
999998
1000 pub const ParamList = LinkedList(*Node);
1001
1002 pub const ReturnType = union(enum) {999 pub const ReturnType = union(enum) {
1003 Explicit: *Node,1000 Explicit: *Node,
1004 InferErrorSet: *Node,1001 InferErrorSet: *Node,
1005 Invalid: TokenIndex,1002 Invalid: TokenIndex,
1006 };1003 };
10071004
1005 pub const ParamDecl = struct {
1006 doc_comments: ?*DocComment,
1007 comptime_token: ?TokenIndex,
1008 noalias_token: ?TokenIndex,
1009 name_token: ?TokenIndex,
1010 param_type: ParamType,
1011
1012 pub const ParamType = union(enum) {
1013 var_type: *Node,
1014 var_args: TokenIndex,
1015 type_expr: *Node,
1016 };
1017
1018 pub fn iterate(self: *const ParamDecl) Node.Iterator {
1019 return .{ .parent_node = &self.base, .index = 0, .node = null };
1020 }
1021
1022 pub fn iterateNext(self: *const ParamDecl, it: *Node.Iterator) ?*Node {
1023 var i = it.index;
1024 it.index += 1;
1025
1026 if (i < 1) {
1027 switch (self.param_type) {
1028 .var_args => return null,
1029 .var_type, .type_expr => |node| return node,
1030 }
1031 }
1032 i -= 1;
1033
1034 return null;
1035 }
1036
1037 pub fn firstToken(self: *const ParamDecl) TokenIndex {
1038 if (self.comptime_token) |comptime_token| return comptime_token;
1039 if (self.noalias_token) |noalias_token| return noalias_token;
1040 if (self.name_token) |name_token| return name_token;
1041 switch (self.param_type) {
1042 .var_args => |tok| return tok,
1043 .var_type, .type_expr => |node| return node.firstToken(),
1044 }
1045 }
1046
1047 pub fn lastToken(self: *const ParamDecl) TokenIndex {
1048 switch (self.param_type) {
1049 .var_args => |tok| return tok,
1050 .var_type, .type_expr => |node| return node.lastToken(),
1051 }
1052 }
1053 };
1054
1055 /// After this the caller must initialize the params list.
1056 pub fn alloc(allocator: *mem.Allocator, params_len: NodeIndex) !*FnProto {
1057 const bytes = try allocator.alignedAlloc(u8, @alignOf(FnProto), sizeInBytes(params_len));
1058 return @ptrCast(*FnProto, bytes.ptr);
1059 }
1060
1061 pub fn free(self: *FnProto, allocator: *mem.Allocator) void {
1062 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len)];
1063 allocator.free(bytes);
1064 }
1065
1008 pub fn iterate(self: *const FnProto) Node.Iterator {1066 pub fn iterate(self: *const FnProto) Node.Iterator {
1009 return .{ .parent_node = &self.base, .index = 0, .node = self.params.first };1067 return .{ .parent_node = &self.base, .index = 0, .node = null };
1010 }1068 }
10111069
1012 pub fn iterateNext(self: *const FnProto, it: *Node.Iterator) ?*Node {1070 pub fn iterateNext(self: *const FnProto, it: *Node.Iterator) ?*Node {
...@@ -1018,11 +1076,17 @@ pub const Node = struct {...@@ -1018,11 +1076,17 @@ pub const Node = struct {
1018 i -= 1;1076 i -= 1;
1019 }1077 }
10201078
1021 if (it.node) |param| {1079 if (i < self.params_len) {
1022 it.index -= 1;1080 switch (self.paramsConst()[i].param_type) {
1023 it.node = param.next;1081 .var_type => |n| return n,
1024 return param.data;1082 .var_args => {
1083 i += 1;
1084 it.index += 1;
1085 },
1086 .type_expr => |n| return n,
1087 }
1025 }1088 }
1089 i -= self.params_len;
10261090
1027 if (self.align_expr) |align_expr| {1091 if (self.align_expr) |align_expr| {
1028 if (i < 1) return align_expr;1092 if (i < 1) return align_expr;
...@@ -1064,6 +1128,20 @@ pub const Node = struct {...@@ -1064,6 +1128,20 @@ pub const Node = struct {
1064 .Invalid => |tok| return tok,1128 .Invalid => |tok| return tok,
1065 }1129 }
1066 }1130 }
1131
1132 pub fn params(self: *FnProto) []ParamDecl {
1133 const decls_start = @ptrCast([*]u8, self) + @sizeOf(FnProto);
1134 return @ptrCast([*]ParamDecl, decls_start)[0..self.params_len];
1135 }
1136
1137 pub fn paramsConst(self: *const FnProto) []const ParamDecl {
1138 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(FnProto);
1139 return @ptrCast([*]const ParamDecl, decls_start)[0..self.params_len];
1140 }
1141
1142 fn sizeInBytes(params_len: NodeIndex) usize {
1143 return @sizeOf(FnProto) + @sizeOf(ParamDecl) * @as(usize, params_len);
1144 }
1067 };1145 };
10681146
1069 pub const AnyFrameType = struct {1147 pub const AnyFrameType = struct {
...@@ -1102,57 +1180,6 @@ pub const Node = struct {...@@ -1102,57 +1180,6 @@ pub const Node = struct {
1102 }1180 }
1103 };1181 };
11041182
1105 pub const ParamDecl = struct {
1106 base: Node = Node{ .id = .ParamDecl },
1107 doc_comments: ?*DocComment,
1108 comptime_token: ?TokenIndex,
1109 noalias_token: ?TokenIndex,
1110 name_token: ?TokenIndex,
1111 param_type: ParamType,
1112
1113 pub const ParamType = union(enum) {
1114 var_type: *Node,
1115 var_args: TokenIndex,
1116 type_expr: *Node,
1117 };
1118
1119 pub fn iterate(self: *const ParamDecl) Node.Iterator {
1120 return .{ .parent_node = &self.base, .index = 0, .node = null };
1121 }
1122
1123 pub fn iterateNext(self: *const ParamDecl, it: *Node.Iterator) ?*Node {
1124 var i = it.index;
1125 it.index += 1;
1126
1127 if (i < 1) {
1128 switch (self.param_type) {
1129 .var_args => return null,
1130 .var_type, .type_expr => |node| return node,
1131 }
1132 }
1133 i -= 1;
1134
1135 return null;
1136 }
1137
1138 pub fn firstToken(self: *const ParamDecl) TokenIndex {
1139 if (self.comptime_token) |comptime_token| return comptime_token;
1140 if (self.noalias_token) |noalias_token| return noalias_token;
1141 if (self.name_token) |name_token| return name_token;
1142 switch (self.param_type) {
1143 .var_args => |tok| return tok,
1144 .var_type, .type_expr => |node| return node.firstToken(),
1145 }
1146 }
1147
1148 pub fn lastToken(self: *const ParamDecl) TokenIndex {
1149 switch (self.param_type) {
1150 .var_args => |tok| return tok,
1151 .var_type, .type_expr => |node| return node.lastToken(),
1152 }
1153 }
1154 };
1155
1156 pub const Block = struct {1183 pub const Block = struct {
1157 base: Node = Node{ .id = .Block },1184 base: Node = Node{ .id = .Block },
1158 label: ?TokenIndex,1185 label: ?TokenIndex,
lib/std/zig/parse.zig+27-29
...@@ -71,7 +71,7 @@ const Parser = struct {...@@ -71,7 +71,7 @@ const Parser = struct {
71 const eof_token = p.eatToken(.Eof).?;71 const eof_token = p.eatToken(.Eof).?;
7272
73 const node = try Node.Root.create(&p.arena.allocator, decls.len, eof_token);73 const node = try Node.Root.create(&p.arena.allocator, decls.len, eof_token);
74 std.mem.copy(*ast.Node, node.decls(), decls);74 std.mem.copy(*Node, node.decls(), decls);
7575
76 return node;76 return node;
77 }77 }
...@@ -96,8 +96,8 @@ const Parser = struct {...@@ -96,8 +96,8 @@ const Parser = struct {
96 /// / ContainerField COMMA ContainerMembers96 /// / ContainerField COMMA ContainerMembers
97 /// / ContainerField97 /// / ContainerField
98 /// /98 /// /
99 fn parseContainerMembers(p: *Parser, top_level: bool) ![]*ast.Node {99 fn parseContainerMembers(p: *Parser, top_level: bool) ![]*Node {
100 var list = std.ArrayList(*ast.Node).init(p.gpa);100 var list = std.ArrayList(*Node).init(p.gpa);
101 defer list.deinit();101 defer list.deinit();
102102
103 var field_state: union(enum) {103 var field_state: union(enum) {
...@@ -522,6 +522,7 @@ const Parser = struct {...@@ -522,6 +522,7 @@ const Parser = struct {
522 const name_token = p.eatToken(.Identifier);522 const name_token = p.eatToken(.Identifier);
523 const lparen = try p.expectToken(.LParen);523 const lparen = try p.expectToken(.LParen);
524 const params = try p.parseParamDeclList(&var_args_token);524 const params = try p.parseParamDeclList(&var_args_token);
525 defer p.gpa.free(params);
525 const rparen = try p.expectToken(.RParen);526 const rparen = try p.expectToken(.RParen);
526 const align_expr = try p.parseByteAlign();527 const align_expr = try p.parseByteAlign();
527 const section_expr = try p.parseLinkSection();528 const section_expr = try p.parseLinkSection();
...@@ -544,13 +545,13 @@ const Parser = struct {...@@ -544,13 +545,13 @@ const Parser = struct {
544 else545 else
545 R{ .Explicit = return_type_expr.? };546 R{ .Explicit = return_type_expr.? };
546547
547 const fn_proto_node = try p.arena.allocator.create(Node.FnProto);548 const fn_proto_node = try Node.FnProto.alloc(&p.arena.allocator, params.len);
548 fn_proto_node.* = .{549 fn_proto_node.* = .{
549 .doc_comments = null,550 .doc_comments = null,
550 .visib_token = null,551 .visib_token = null,
551 .fn_token = fn_token,552 .fn_token = fn_token,
552 .name_token = name_token,553 .name_token = name_token,
553 .params = params,554 .params_len = params.len,
554 .return_type = return_type,555 .return_type = return_type,
555 .var_args_token = var_args_token,556 .var_args_token = var_args_token,
556 .extern_export_inline_token = null,557 .extern_export_inline_token = null,
...@@ -562,6 +563,7 @@ const Parser = struct {...@@ -562,6 +563,7 @@ const Parser = struct {
562 .is_extern_prototype = is_extern,563 .is_extern_prototype = is_extern,
563 .is_async = is_async,564 .is_async = is_async,
564 };565 };
566 std.mem.copy(Node.FnProto.ParamDecl, fn_proto_node.params(), params);
565567
566 return &fn_proto_node.base;568 return &fn_proto_node.base;
567 }569 }
...@@ -621,7 +623,7 @@ const Parser = struct {...@@ -621,7 +623,7 @@ const Parser = struct {
621 var type_expr: ?*Node = null;623 var type_expr: ?*Node = null;
622 if (p.eatToken(.Colon)) |_| {624 if (p.eatToken(.Colon)) |_| {
623 if (p.eatToken(.Keyword_var)) |var_tok| {625 if (p.eatToken(.Keyword_var)) |var_tok| {
624 const node = try p.arena.allocator.create(ast.Node.VarType);626 const node = try p.arena.allocator.create(Node.VarType);
625 node.* = .{ .token = var_tok };627 node.* = .{ .token = var_tok };
626 type_expr = &node.base;628 type_expr = &node.base;
627 } else {629 } else {
...@@ -1936,7 +1938,7 @@ const Parser = struct {...@@ -1936,7 +1938,7 @@ const Parser = struct {
1936 }1938 }
19371939
1938 /// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType1940 /// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
1939 fn parseParamDecl(p: *Parser) !?*Node {1941 fn parseParamDecl(p: *Parser, list: *std.ArrayList(Node.FnProto.ParamDecl)) !bool {
1940 const doc_comments = try p.parseDocComment();1942 const doc_comments = try p.parseDocComment();
1941 const noalias_token = p.eatToken(.Keyword_noalias);1943 const noalias_token = p.eatToken(.Keyword_noalias);
1942 const comptime_token = if (noalias_token == null) p.eatToken(.Keyword_comptime) else null;1944 const comptime_token = if (noalias_token == null) p.eatToken(.Keyword_comptime) else null;
...@@ -1951,31 +1953,30 @@ const Parser = struct {...@@ -1951,31 +1953,30 @@ const Parser = struct {
1951 if (noalias_token == null and1953 if (noalias_token == null and
1952 comptime_token == null and1954 comptime_token == null and
1953 name_token == null and1955 name_token == null and
1954 doc_comments == null) return null;1956 doc_comments == null) return false;
1955 try p.errors.append(p.gpa, .{1957 try p.errors.append(p.gpa, .{
1956 .ExpectedParamType = .{ .token = p.tok_i },1958 .ExpectedParamType = .{ .token = p.tok_i },
1957 });1959 });
1958 return error.ParseError;1960 return error.ParseError;
1959 };1961 };
19601962
1961 const param_decl = try p.arena.allocator.create(Node.ParamDecl);1963 (try list.addOne()).* = .{
1962 param_decl.* = .{
1963 .doc_comments = doc_comments,1964 .doc_comments = doc_comments,
1964 .comptime_token = comptime_token,1965 .comptime_token = comptime_token,
1965 .noalias_token = noalias_token,1966 .noalias_token = noalias_token,
1966 .name_token = name_token,1967 .name_token = name_token,
1967 .param_type = param_type,1968 .param_type = param_type,
1968 };1969 };
1969 return &param_decl.base;1970 return true;
1970 }1971 }
19711972
1972 /// ParamType1973 /// ParamType
1973 /// <- KEYWORD_var1974 /// <- KEYWORD_var
1974 /// / DOT31975 /// / DOT3
1975 /// / TypeExpr1976 /// / TypeExpr
1976 fn parseParamType(p: *Parser) !?Node.ParamDecl.ParamType {1977 fn parseParamType(p: *Parser) !?Node.FnProto.ParamDecl.ParamType {
1977 // TODO cast from tuple to error union is broken1978 // TODO cast from tuple to error union is broken
1978 const P = Node.ParamDecl.ParamType;1979 const P = Node.FnProto.ParamDecl.ParamType;
1979 if (try p.parseVarType()) |node| return P{ .var_type = node };1980 if (try p.parseVarType()) |node| return P{ .var_type = node };
1980 if (p.eatToken(.Ellipsis3)) |token| return P{ .var_args = token };1981 if (p.eatToken(.Ellipsis3)) |token| return P{ .var_args = token };
1981 if (try p.parseTypeExpr()) |node| return P{ .type_expr = node };1982 if (try p.parseTypeExpr()) |node| return P{ .type_expr = node };
...@@ -2587,7 +2588,7 @@ const Parser = struct {...@@ -2587,7 +2588,7 @@ const Parser = struct {
25872588
2588 if (p.eatToken(.Ellipsis2) != null) {2589 if (p.eatToken(.Ellipsis2) != null) {
2589 const end_expr = try p.parseExpr();2590 const end_expr = try p.parseExpr();
2590 const sentinel: ?*ast.Node = if (p.eatToken(.Colon) != null)2591 const sentinel: ?*Node = if (p.eatToken(.Colon) != null)
2591 try p.parseExpr()2592 try p.parseExpr()
2592 else2593 else
2593 null;2594 null;
...@@ -2616,7 +2617,7 @@ const Parser = struct {...@@ -2616,7 +2617,7 @@ const Parser = struct {
2616 if (p.eatToken(.Period)) |period| {2617 if (p.eatToken(.Period)) |period| {
2617 if (try p.parseIdentifier()) |identifier| {2618 if (try p.parseIdentifier()) |identifier| {
2618 // TODO: It's a bit weird to return an InfixOp from the SuffixOp parser.2619 // TODO: It's a bit weird to return an InfixOp from the SuffixOp parser.
2619 // Should there be an ast.Node.SuffixOp.FieldAccess variant? Or should2620 // Should there be an Node.SuffixOp.FieldAccess variant? Or should
2620 // this grammar rule be altered?2621 // this grammar rule be altered?
2621 const node = try p.arena.allocator.create(Node.InfixOp);2622 const node = try p.arena.allocator.create(Node.InfixOp);
2622 node.* = .{2623 node.* = .{
...@@ -2652,13 +2653,13 @@ const Parser = struct {...@@ -2652,13 +2653,13 @@ const Parser = struct {
2652 /// ExprList <- (Expr COMMA)* Expr?2653 /// ExprList <- (Expr COMMA)* Expr?
2653 fn parseFnCallArguments(p: *Parser) !?AnnotatedParamList {2654 fn parseFnCallArguments(p: *Parser) !?AnnotatedParamList {
2654 if (p.eatToken(.LParen) == null) return null;2655 if (p.eatToken(.LParen) == null) return null;
2655 const list = try ListParseFn(Node.FnProto.ParamList, parseExpr)(p);2656 const list = try ListParseFn(std.SinglyLinkedList(*Node), parseExpr)(p);
2656 const rparen = try p.expectToken(.RParen);2657 const rparen = try p.expectToken(.RParen);
2657 return AnnotatedParamList{ .list = list, .rparen = rparen };2658 return AnnotatedParamList{ .list = list, .rparen = rparen };
2658 }2659 }
26592660
2660 const AnnotatedParamList = struct {2661 const AnnotatedParamList = struct {
2661 list: Node.FnProto.ParamList, // NOTE: may also be any other type SegmentedList(*Node, 2)2662 list: std.SinglyLinkedList(*Node),
2662 rparen: TokenIndex,2663 rparen: TokenIndex,
2663 };2664 };
26642665
...@@ -2797,14 +2798,14 @@ const Parser = struct {...@@ -2797,14 +2798,14 @@ const Parser = struct {
2797 .lbrace_token = lbrace,2798 .lbrace_token = lbrace,
2798 .rbrace_token = rbrace,2799 .rbrace_token = rbrace,
2799 };2800 };
2800 std.mem.copy(*ast.Node, node.fieldsAndDecls(), members);2801 std.mem.copy(*Node, node.fieldsAndDecls(), members);
2801 return &node.base;2802 return &node.base;
2802 }2803 }
28032804
2804 /// Holds temporary data until we are ready to construct the full ContainerDecl AST node.2805 /// Holds temporary data until we are ready to construct the full ContainerDecl AST node.
2805 const ContainerDeclType = struct {2806 const ContainerDeclType = struct {
2806 kind_token: TokenIndex,2807 kind_token: TokenIndex,
2807 init_arg_expr: ast.Node.ContainerDecl.InitArg,2808 init_arg_expr: Node.ContainerDecl.InitArg,
2808 };2809 };
28092810
2810 /// ContainerDeclType2811 /// ContainerDeclType
...@@ -2893,14 +2894,11 @@ const Parser = struct {...@@ -2893,14 +2894,11 @@ const Parser = struct {
2893 }2894 }
28942895
2895 /// ParamDeclList <- (ParamDecl COMMA)* ParamDecl?2896 /// ParamDeclList <- (ParamDecl COMMA)* ParamDecl?
2896 fn parseParamDeclList(p: *Parser, var_args_token: *?TokenIndex) !Node.FnProto.ParamList {2897 fn parseParamDeclList(p: *Parser, var_args_token: *?TokenIndex) ![]Node.FnProto.ParamDecl {
2897 var list = Node.FnProto.ParamList{};2898 var list = std.ArrayList(Node.FnProto.ParamDecl).init(p.gpa);
2898 var list_it = &list.first;2899 defer list.deinit();
2899 var last: ?*Node = null;
2900 while (try p.parseParamDecl()) |node| {
2901 last = node;
2902 list_it = try p.llpush(*Node, list_it, node);
29032900
2901 while (try p.parseParamDecl(&list)) {
2904 switch (p.tokens[p.tok_i].id) {2902 switch (p.tokens[p.tok_i].id) {
2905 .Comma => _ = p.nextToken(),2903 .Comma => _ = p.nextToken(),
2906 // all possible delimiters2904 // all possible delimiters
...@@ -2914,13 +2912,13 @@ const Parser = struct {...@@ -2914,13 +2912,13 @@ const Parser = struct {
2914 },2912 },
2915 }2913 }
2916 }2914 }
2917 if (last) |node| {2915 if (list.items.len != 0) {
2918 const param_type = node.cast(Node.ParamDecl).?.param_type;2916 const param_type = list.items[list.items.len - 1].param_type;
2919 if (param_type == .var_args) {2917 if (param_type == .var_args) {
2920 var_args_token.* = param_type.var_args;2918 var_args_token.* = param_type.var_args;
2921 }2919 }
2922 }2920 }
2923 return list;2921 return list.toOwnedSlice();
2924 }2922 }
29252923
2926 const NodeParseFn = fn (p: *Parser) Error!?*Node;2924 const NodeParseFn = fn (p: *Parser) Error!?*Node;
lib/std/zig/render.zig+7-14
...@@ -1479,13 +1479,11 @@ fn renderExpression(...@@ -1479,13 +1479,11 @@ fn renderExpression(
1479 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (1479 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
14801480
1481 // render all on one line, no trailing comma1481 // render all on one line, no trailing comma
1482 var it = fn_proto.params.first;1482 for (fn_proto.params()) |param_decl, i| {
1483 while (it) |param_decl_node_node| : (it = param_decl_node_node.next) {1483 try renderParamDecl(allocator, stream, tree, indent, start_col, param_decl, Space.None);
1484 const param_decl_node = param_decl_node_node.data;
1485 try renderParamDecl(allocator, stream, tree, indent, start_col, param_decl_node, Space.None);
14861484
1487 if (param_decl_node_node.next != null) {1485 if (i + 1 < fn_proto.params_len) {
1488 const comma = tree.nextToken(param_decl_node.lastToken());1486 const comma = tree.nextToken(param_decl.lastToken());
1489 try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,1487 try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,
1490 }1488 }
1491 }1489 }
...@@ -1494,11 +1492,9 @@ fn renderExpression(...@@ -1494,11 +1492,9 @@ fn renderExpression(
1494 const new_indent = indent + indent_delta;1492 const new_indent = indent + indent_delta;
1495 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (1493 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (
14961494
1497 var it = fn_proto.params.first;1495 for (fn_proto.params()) |param_decl| {
1498 while (it) |param_decl_node_node| : (it = param_decl_node_node.next) {
1499 const param_decl_node = param_decl_node_node.data;
1500 try stream.writeByteNTimes(' ', new_indent);1496 try stream.writeByteNTimes(' ', new_indent);
1501 try renderParamDecl(allocator, stream, tree, new_indent, start_col, param_decl_node, Space.Comma);1497 try renderParamDecl(allocator, stream, tree, new_indent, start_col, param_decl, Space.Comma);
1502 }1498 }
1503 try stream.writeByteNTimes(' ', indent);1499 try stream.writeByteNTimes(' ', indent);
1504 }1500 }
...@@ -2079,7 +2075,6 @@ fn renderExpression(...@@ -2079,7 +2075,6 @@ fn renderExpression(
2079 .VarDecl,2075 .VarDecl,
2080 .Use,2076 .Use,
2081 .TestDecl,2077 .TestDecl,
2082 .ParamDecl,
2083 => unreachable,2078 => unreachable,
2084 }2079 }
2085}2080}
...@@ -2162,11 +2157,9 @@ fn renderParamDecl(...@@ -2162,11 +2157,9 @@ fn renderParamDecl(
2162 tree: *ast.Tree,2157 tree: *ast.Tree,
2163 indent: usize,2158 indent: usize,
2164 start_col: *usize,2159 start_col: *usize,
2165 base: *ast.Node,2160 param_decl: ast.Node.FnProto.ParamDecl,
2166 space: Space,2161 space: Space,
2167) (@TypeOf(stream).Error || Error)!void {2162) (@TypeOf(stream).Error || Error)!void {
2168 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
2169
2170 try renderDocComments(tree, stream, param_decl, indent, start_col);2163 try renderDocComments(tree, stream, param_decl, indent, start_col);
21712164
2172 if (param_decl.comptime_token) |comptime_token| {2165 if (param_decl.comptime_token) |comptime_token| {