| author | |
| committer | |
| log | d37b81d43bc52daa94dd1ad1631018ea0cd11f77 |
| tree | 349db74ec5b830aabfe5d36ffd3acc182ed73a0d |
| parent | 32ecb416f3acc49b80268711562f2c4133a828b9 |
* 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, |
| 324 | 324 | ||
| 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, |
| 334 | 334 | ||
| 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 | // Operators | 428 | // 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, | ||
| 440 | 444 | ||
| 441 | // Control flow | 445 | // 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 | }; |
| 490 | 492 | ||
| ... | @@ -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 | } | ||
| 785 | 793 | ||
| 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 | } | ||
| 787 | 798 | ||
| 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 | } |
| 791 | 802 | ||
| 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 | }; |
| 806 | 831 | ||
| 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 | }; |
| 1466 | 1491 | ||
| 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, |
| 1471 | 1500 | ||
| 1472 | /// these must be SwitchCase nodes | 1501 | /// 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 | } | ||
| 1475 | 1506 | ||
| 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 | } | ||
| 1477 | 1511 | ||
| 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 | } |
| 1481 | 1515 | ||
| 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 | }; |
| 1506 | 1554 | ||
| 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 | }; |
| 2122 | 2170 | ||
| 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, |
| 2128 | 2236 | ||
| 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, |
| 2135 | 2242 | ||
| 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 | }; |
| 2149 | 2249 | ||
| 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 | } |
| 2158 | 2253 | ||
| 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; |
| 2165 | 2260 | ||
| 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 | } |
| 2198 | 2286 | ||
| 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 | } |
| 2206 | 2290 | ||
| ... | @@ -2396,22 +2480,36 @@ pub const Node = struct { | ... | @@ -2396,22 +2480,36 @@ pub const Node = struct { |
| 2396 | } | 2480 | } |
| 2397 | }; | 2481 | }; |
| 2398 | 2482 | ||
| 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, |
| 2404 | 2489 | ||
| 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 | } | ||
| 2406 | 2500 | ||
| 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 | } |
| 2410 | 2504 | ||
| 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 | } |
| 2416 | 2514 | ||
| 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 | }; |
| 2425 | 2537 | ||
| 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 | }; |
| 2556 | 2668 | ||
| 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 | }; | ||
| 2564 | 2691 | ||
| 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 | }; | ||
| 2569 | 2695 | ||
| 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; |
| 2573 | 2699 | ||
| 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; | ||
| 2577 | 2702 | ||
| 2578 | if (i < 1) return self.symbolic_name; | 2703 | if (i < 1) return self.constraint; |
| 2579 | i -= 1; | 2704 | i -= 1; |
| 2580 | 2705 | ||
| 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 | } | ||
| 2583 | 2716 | ||
| 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 | } |
| 2594 | 2719 | ||
| 2595 | return null; | 2720 | pub fn firstToken(self: *const Output) TokenIndex { |
| 2596 | } | 2721 | return self.lbracket; |
| 2597 | 2722 | } | |
| 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 | }; | ||
| 2606 | 2723 | ||
| 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, | ||
| 2614 | 2728 | ||
| 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, | ||
| 2618 | 2735 | ||
| 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 | } |
| 2622 | 2739 | ||
| 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; | ||
| 2625 | 2743 | ||
| 2626 | if (i < 1) return self.constraint; | 2744 | if (i < 1) return self.symbolic_name; |
| 2627 | i -= 1; | 2745 | i -= 1; |
| 2628 | 2746 | ||
| 2629 | if (i < 1) return self.expr; | 2747 | if (i < 1) return self.constraint; |
| 2630 | i -= 1; | 2748 | i -= 1; |
| 2631 | 2749 | ||
| 2632 | return null; | 2750 | if (i < 1) return self.expr; |
| 2633 | } | 2751 | i -= 1; |
| 2634 | 2752 | ||
| 2635 | pub fn firstToken(self: *const AsmInput) TokenIndex { | 2753 | return null; |
| 2636 | return self.lbracket; | 2754 | } |
| 2637 | } | ||
| 2638 | 2755 | ||
| 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 | }; | ||
| 2643 | 2759 | ||
| 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, | ||
| 2653 | 2764 | ||
| 2654 | pub const OutputList = LinkedList(*AsmOutput); | ||
| 2655 | pub const InputList = LinkedList(*AsmInput); | ||
| 2656 | pub const ClobberList = LinkedList(*Node); | ||
| 2657 | 2765 | ||
| 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; |
| 2665 | 2773 | ||
| 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; | ||
| 2672 | 2784 | ||
| 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; | ||
| 2679 | 2792 | ||
| 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 | else | 546 | else |
| 548 | R{ .Explicit = return_type_expr.? }; | 547 | R{ .Explicit = return_type_expr.? }; |
| 549 | 548 | ||
| 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; | ||
| 551 | 554 | ||
| 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 parsing | 1458 | // 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); |
| 1619 | 1619 | ||
| 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 | } |
| 1628 | 1629 | ||
| ... | @@ -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); |
| 1773 | 1775 | ||
| 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 | } |
| 1783 | 1786 | ||
| 1784 | /// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN | 1787 | /// 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 | }); |
| 1792 | 1799 | ||
| 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 | }; |
| 1803 | 1832 | ||
| 1804 | try p.parseAsmOutput(node); | ||
| 1805 | node.rparen = try p.expectToken(.RParen); | ||
| 1806 | return &node.base; | 1833 | return &node.base; |
| 1807 | } | 1834 | } |
| 1808 | 1835 | ||
| ... | @@ -1828,15 +1855,8 @@ const Parser = struct { | ... | @@ -1828,15 +1855,8 @@ const Parser = struct { |
| 1828 | return null; | 1855 | return null; |
| 1829 | } | 1856 | } |
| 1830 | 1857 | ||
| 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) RPAREN | 1858 | /// 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 | }); |
| 1849 | 1869 | ||
| 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); |
| 1864 | 1884 | ||
| 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 | } |
| 1882 | 1893 | ||
| 1883 | /// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN | 1894 | /// 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); |
| 1900 | 1911 | ||
| 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 | } |
| 1921 | 1920 | ||
| 1922 | /// BreakLabel <- COLON IDENTIFIER | 1921 | /// BreakLabel <- COLON IDENTIFIER |
| ... | @@ -1999,7 +1998,7 @@ const Parser = struct { | ... | @@ -1999,7 +1998,7 @@ const Parser = struct { |
| 1999 | } | 1998 | } |
| 2000 | 1999 | ||
| 2001 | /// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType | 2000 | /// 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 and | 2013 | if (noalias_token == null and |
| 2015 | comptime_token == null and | 2014 | comptime_token == null and |
| 2016 | name_token == null and | 2015 | 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 | }; |
| 2023 | 2025 | ||
| 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 | } |
| 2033 | 2034 | ||
| 2034 | /// ParamType | 2035 | /// 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 | } |
| 2721 | 2723 | ||
| 2722 | const AnnotatedParamList = struct { | 2724 | const AnnotatedParamList = struct { |
| 2723 | list: std.SinglyLinkedList(*Node), | 2725 | list: []*Node, |
| 2724 | rparen: TokenIndex, | 2726 | rparen: TokenIndex, |
| 2725 | }; | 2727 | }; |
| 2726 | 2728 | ||
| ... | @@ -2936,62 +2938,40 @@ const Parser = struct { | ... | @@ -2936,62 +2938,40 @@ const Parser = struct { |
| 2936 | 2938 | ||
| 2937 | /// IdentifierList <- (IDENTIFIER COMMA)* IDENTIFIER? | 2939 | /// IdentifierList <- (IDENTIFIER COMMA)* IDENTIFIER? |
| 2938 | /// Only ErrorSetDecl parses an IdentifierList | 2940 | /// 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 | } |
| 2942 | 2944 | ||
| 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 | } |
| 2947 | 2949 | ||
| 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 | } |
| 2952 | 2954 | ||
| 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 | } |
| 2957 | 2959 | ||
| 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 | } |
| 2985 | 2964 | ||
| 2986 | const NodeParseFn = fn (p: *Parser) Error!?*Node; | 2965 | const NodeParseFn = fn (p: *Parser) Error!?*Node; |
| 2987 | 2966 | ||
| 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); | ||
| 2995 | 2975 | ||
| 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 | } |
| 3064 | 3047 |
lib/std/zig/render.zig+151-164| ... | @@ -187,7 +187,10 @@ fn renderRoot( | ... | @@ -187,7 +187,10 @@ fn renderRoot( |
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) @TypeOf(stream).Error!void { | 189 | fn 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 | |||
| 193 | fn 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 | }, |
| 904 | 907 | ||
| 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 | } | ||
| 907 | 913 | ||
| 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 | } | ||
| 913 | 915 | ||
| 914 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); | 916 | const lparen = tree.nextToken(call.lhs.lastToken()); |
| 915 | 917 | ||
| 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 | } | ||
| 917 | 922 | ||
| 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 | }; |
| 922 | 927 | ||
| 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 | }; | ||
| 927 | 931 | ||
| 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: { |
| 931 | 935 | 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 | }; | ||
| 944 | 940 | ||
| 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 | } | ||
| 957 | 953 | ||
| 958 | try renderToken(tree, stream, lparen, indent, start_col, Space.None); // ( | 954 | try renderToken(tree, stream, lparen, indent, start_col, Space.None); // ( |
| 959 | 955 | ||
| 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); | ||
| 964 | 959 | ||
| 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); | ||
| 972 | 970 | ||
| 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( |
| 1288 | 1287 | ||
| 1289 | const lbrace = tree.nextToken(err_set_decl.error_token); | 1288 | const lbrace = tree.nextToken(err_set_decl.error_token); |
| 1290 | 1289 | ||
| 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 | } |
| 1296 | 1295 | ||
| 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]; |
| 1299 | 1298 | ||
| 1300 | // if there are any doc comments or same line comments | 1299 | // if there are any doc comments or same line comments |
| 1301 | // don't try to put it all on one line | 1300 | // 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; |
| 1324 | 1323 | ||
| 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); |
| 1329 | 1327 | ||
| 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); // , |
| 1333 | 1331 | ||
| 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); // { |
| 1344 | 1342 | ||
| 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); |
| 1350 | 1347 | ||
| 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); // @name | 1398 | try renderToken(tree, stream, builtin_call.builtin_token, indent, start_col, Space.None); // @name |
| 1402 | 1399 | ||
| 1403 | const src_params_trailing_comma = blk: { | 1400 | const src_params_trailing_comma = blk: { |
| 1404 | if (builtin_call.params.first == null or | 1401 | 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); // ( |
| 1418 | 1411 | ||
| 1419 | // render all on one line, no trailing comma | 1412 | // 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); |
| 1424 | 1416 | ||
| 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); // ( |
| 1434 | 1426 | ||
| 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); |
| 1594 | 1584 | ||
| 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); // { |
| 1608 | 1598 | ||
| 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); |
| 1614 | 1603 | ||
| 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 | } |
| 1619 | 1608 | ||
| ... | @@ -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 | } |
| 1931 | 1920 | ||
| 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; |
| 1951 | 1940 | ||
| 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); |
| 1955 | 1944 | ||
| ... | @@ -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); // : |
| 1959 | 1948 | ||
| 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; | ||
| 1970 | 1953 | ||
| 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()); |
| 1974 | 1957 | ||
| 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 | }; |
| 1991 | 1975 | ||
| 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); |
| 1995 | 1979 | ||
| ... | @@ -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); // : |
| 1999 | 1983 | ||
| 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; | ||
| 2009 | 1988 | ||
| 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()); |
| 2013 | 1992 | ||
| 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 | }; |
| 2030 | 2010 | ||
| 2031 | try renderToken(tree, stream, colon3, indent, start_col, Space.Space); // : | 2011 | try renderToken(tree, stream, colon3, indent, start_col, Space.Space); // : |
| 2032 | 2012 | ||
| 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 | }, |
| 2050 | 2025 | ||
| 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); |
| 2087 | 2028 | ||
| ... | @@ -2098,6 +2039,52 @@ fn renderExpression( | ... | @@ -2098,6 +2039,52 @@ fn renderExpression( |
| 2098 | } | 2039 | } |
| 2099 | } | 2040 | } |
| 2100 | 2041 | ||
| 2042 | fn 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 | |||
| 2070 | fn 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 | |||
| 2101 | fn renderVarDecl( | 2088 | fn renderVarDecl( |
| 2102 | allocator: *mem.Allocator, | 2089 | allocator: *mem.Allocator, |
| 2103 | stream: var, | 2090 | stream: var, |