| author | |
| committer | |
| log | 7c2c0e36f8378d8efaf64d859bdffb91007db82a |
| tree | a8335099205f30d5bf9b4478ee9d73824b2f0abf |
| parent | 5db9f306ba88087d269dc5fe5672a5af5ab55333 |
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 | }; |
| 483 | 482 | ||
| ... | @@ -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 | } |
| 821 | 819 | ||
| 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 | }; |
| 981 | 979 | ||
| 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 is | 996 | is_extern_prototype: bool = false, // TODO: Remove once extern fn rewriting is |
| 998 | is_async: bool = false, // TODO: remove once async fn rewriting is | 997 | is_async: bool = false, // TODO: remove once async fn rewriting is |
| 999 | 998 | ||
| 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 | }; |
| 1007 | 1004 | ||
| 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 | } |
| 1011 | 1069 | ||
| 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 | } |
| 1020 | 1078 | ||
| 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; | ||
| 1026 | 1090 | ||
| 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 | }; |
| 1068 | 1146 | ||
| 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 | }; |
| 1104 | 1182 | ||
| 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).?; |
| 72 | 72 | ||
| 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); |
| 75 | 75 | ||
| 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 ContainerMembers | 96 | /// / ContainerField COMMA ContainerMembers |
| 97 | /// / ContainerField | 97 | /// / 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(); |
| 102 | 102 | ||
| 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 | else | 545 | else |
| 545 | R{ .Explicit = return_type_expr.? }; | 546 | R{ .Explicit = return_type_expr.? }; |
| 546 | 547 | ||
| 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); | ||
| 565 | 567 | ||
| 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 | } |
| 1937 | 1939 | ||
| 1938 | /// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType | 1940 | /// 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 and | 1953 | if (noalias_token == null and |
| 1952 | comptime_token == null and | 1954 | comptime_token == null and |
| 1953 | name_token == null and | 1955 | 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 | }; |
| 1960 | 1962 | ||
| 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 | } |
| 1971 | 1972 | ||
| 1972 | /// ParamType | 1973 | /// ParamType |
| 1973 | /// <- KEYWORD_var | 1974 | /// <- KEYWORD_var |
| 1974 | /// / DOT3 | 1975 | /// / DOT3 |
| 1975 | /// / TypeExpr | 1976 | /// / 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 broken | 1978 | // 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 { |
| 2587 | 2588 | ||
| 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 | else | 2593 | 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 should | 2620 | // 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 | } |
| 2659 | 2660 | ||
| 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 | }; |
| 2664 | 2665 | ||
| ... | @@ -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 | } |
| 2803 | 2804 | ||
| 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 | }; |
| 2809 | 2810 | ||
| 2810 | /// ContainerDeclType | 2811 | /// ContainerDeclType |
| ... | @@ -2893,14 +2894,11 @@ const Parser = struct { | ... | @@ -2893,14 +2894,11 @@ const Parser = struct { |
| 2893 | } | 2894 | } |
| 2894 | 2895 | ||
| 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); | ||
| 2903 | 2900 | ||
| 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 delimiters | 2904 | // 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 | } |
| 2925 | 2923 | ||
| 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); // ( |
| 1480 | 1480 | ||
| 1481 | // render all on one line, no trailing comma | 1481 | // 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); | ||
| 1486 | 1484 | ||
| 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); // ( |
| 1496 | 1494 | ||
| 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); |
| 2171 | 2164 | ||
| 2172 | if (param_decl.comptime_token) |comptime_token| { | 2165 | if (param_decl.comptime_token) |comptime_token| { |