authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2021-02-06 22:55:29+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-02-06 21:29:45-08:00
log33915cb1ed88417d3495c160ffd15c93f9197e5b
tree98de1c8df774c75ddc405ed2405e533a3310dc70
parentd898945786b527b09ef056099e923e946425e146

zig fmt: implement pointer types

rename PtrType => PtrTypeBitRange, SliceType => PtrType This rename was done as the current SliceType is used for non-bitrange pointers as well as slices and because PtrTypeSentinel/PtrTypeAligned are also used for slices. Therefore using the same Ptr prefix for all these pointer/slice nodes is an improvement.

4 files changed, 307 insertions(+), 139 deletions(-)

lib/std/zig/ast.zig+168-14
......@@ -387,10 +387,22 @@ pub const Tree = struct {
387387 }
388388 },
389389
390 .PtrTypeAligned => unreachable, // TODO
391 .PtrTypeSentinel => unreachable, // TODO
392 .PtrType => unreachable, // TODO
393 .SliceType => unreachable, // TODO
390 .PtrTypeAligned,
391 .PtrTypeSentinel,
392 .PtrType,
393 .PtrTypeBitRange,
394 => {
395 const main_token = main_tokens[n];
396 return switch (token_tags[main_token]) {
397 .Asterisk => switch (token_tags[main_token - 1]) {
398 .LBrace => main_token - 1,
399 else => main_token,
400 },
401 .LBrace => main_token,
402 else => unreachable,
403 };
404 },
405
394406 .SwitchCaseMulti => unreachable, // TODO
395407 .WhileSimple => unreachable, // TODO
396408 .WhileCont => unreachable, // TODO
......@@ -477,6 +489,10 @@ pub const Tree = struct {
477489 .IfSimple,
478490 .WhileSimple,
479491 .FnDecl,
492 .PtrTypeAligned,
493 .PtrTypeSentinel,
494 .PtrType,
495 .PtrTypeBitRange,
480496 => n = datas[n].rhs,
481497
482498 .FieldAccess,
......@@ -698,10 +714,6 @@ pub const Tree = struct {
698714 .SwitchRange => unreachable, // TODO
699715 .ArrayType => unreachable, // TODO
700716 .ArrayTypeSentinel => unreachable, // TODO
701 .PtrTypeAligned => unreachable, // TODO
702 .PtrTypeSentinel => unreachable, // TODO
703 .PtrType => unreachable, // TODO
704 .SliceType => unreachable, // TODO
705717 .SwitchCaseMulti => unreachable, // TODO
706718 .WhileCont => unreachable, // TODO
707719 .While => unreachable, // TODO
......@@ -1028,6 +1040,60 @@ pub const Tree = struct {
10281040 };
10291041 }
10301042
1043 pub fn ptrTypeAligned(tree: Tree, node: Node.Index) Full.PtrType {
1044 assert(tree.nodes.items(.tag)[node] == .PtrTypeAligned);
1045 const data = tree.nodes.items(.data)[node];
1046 return tree.fullPtrType(.{
1047 .main_token = tree.nodes.items(.main_token)[node],
1048 .align_node = data.lhs,
1049 .sentinel = 0,
1050 .bit_range_start = 0,
1051 .bit_range_end = 0,
1052 .child_type = data.rhs,
1053 });
1054 }
1055
1056 pub fn ptrTypeSentinel(tree: Tree, node: Node.Index) Full.PtrType {
1057 assert(tree.nodes.items(.tag)[node] == .PtrTypeSentinel);
1058 const data = tree.nodes.items(.data)[node];
1059 return tree.fullPtrType(.{
1060 .main_token = tree.nodes.items(.main_token)[node],
1061 .align_node = 0,
1062 .sentinel = data.lhs,
1063 .bit_range_start = 0,
1064 .bit_range_end = 0,
1065 .child_type = data.rhs,
1066 });
1067 }
1068
1069 pub fn ptrType(tree: Tree, node: Node.Index) Full.PtrType {
1070 assert(tree.nodes.items(.tag)[node] == .PtrType);
1071 const data = tree.nodes.items(.data)[node];
1072 const extra = tree.extraData(data.lhs, Node.PtrType);
1073 return tree.fullPtrType(.{
1074 .main_token = tree.nodes.items(.main_token)[node],
1075 .align_node = extra.align_node,
1076 .sentinel = extra.sentinel,
1077 .bit_range_start = 0,
1078 .bit_range_end = 0,
1079 .child_type = data.rhs,
1080 });
1081 }
1082
1083 pub fn ptrTypeBitRange(tree: Tree, node: Node.Index) Full.PtrType {
1084 assert(tree.nodes.items(.tag)[node] == .PtrTypeBitRange);
1085 const data = tree.nodes.items(.data)[node];
1086 const extra = tree.extraData(data.lhs, Node.PtrTypeBitRange);
1087 return tree.fullPtrType(.{
1088 .main_token = tree.nodes.items(.main_token)[node],
1089 .align_node = extra.align_node,
1090 .sentinel = extra.sentinel,
1091 .bit_range_start = extra.bit_range_start,
1092 .bit_range_end = extra.bit_range_end,
1093 .child_type = data.rhs,
1094 });
1095 }
1096
10311097 pub fn containerDeclTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) Full.ContainerDecl {
10321098 assert(tree.nodes.items(.tag)[node] == .ContainerDeclTwo or
10331099 tree.nodes.items(.tag)[node] == .ContainerDeclTwoComma);
......@@ -1195,6 +1261,64 @@ pub const Tree = struct {
11951261 return result;
11961262 }
11971263
1264 fn fullPtrType(tree: Tree, info: Full.PtrType.Ast) Full.PtrType {
1265 const token_tags = tree.tokens.items(.tag);
1266 // TODO: looks like stage1 isn't quite smart enough to handle enum
1267 // literals in some places here
1268 const Kind = Full.PtrType.Kind;
1269 const kind: Kind = switch (token_tags[info.main_token]) {
1270 .Asterisk => switch (token_tags[info.main_token + 1]) {
1271 .RBracket => .many,
1272 .Colon => .sentinel,
1273 .Identifier => if (token_tags[info.main_token - 1] == .LBracket) Kind.c else .one,
1274 else => .one,
1275 },
1276 .LBracket => switch (token_tags[info.main_token + 1]) {
1277 .RBracket => Kind.slice,
1278 .Colon => .slice_sentinel,
1279 else => unreachable,
1280 },
1281 else => unreachable,
1282 };
1283 var result: Full.PtrType = .{
1284 .kind = kind,
1285 .allowzero_token = null,
1286 .const_token = null,
1287 .volatile_token = null,
1288 .ast = info,
1289 };
1290 // We need to be careful that we don't iterate over any sub-expressions
1291 // here while looking for modifiers as that could result in false
1292 // positives. Therefore, start after a sentinel if there is one and
1293 // skip over any align node and bit range nodes.
1294 var i = if (kind == .sentinel or kind == .slice_sentinel) blk: {
1295 assert(info.sentinel != 0);
1296 break :blk tree.lastToken(info.sentinel) + 1;
1297 } else blk: {
1298 assert(info.sentinel == 0);
1299 break :blk info.main_token;
1300 };
1301 const end = tree.firstToken(info.child_type);
1302 while (i < end) : (i += 1) {
1303 switch (token_tags[i]) {
1304 .Keyword_allowzero => result.allowzero_token = i,
1305 .Keyword_const => result.const_token = i,
1306 .Keyword_volatile => result.volatile_token = i,
1307 .Keyword_align => {
1308 assert(info.align_node != 0);
1309 if (info.bit_range_end != 0) {
1310 assert(info.bit_range_start != 0);
1311 i = tree.lastToken(info.bit_range_end) + 1;
1312 } else {
1313 i = tree.lastToken(info.align_node) + 1;
1314 }
1315 },
1316 else => {},
1317 }
1318 }
1319 return result;
1320 }
1321
11981322 fn fullContainerDecl(tree: Tree, info: Full.ContainerDecl.Ast) Full.ContainerDecl {
11991323 const token_tags = tree.tokens.items(.tag);
12001324 var result: Full.ContainerDecl = .{
......@@ -1302,6 +1426,32 @@ pub const Full = struct {
13021426 };
13031427 };
13041428
1429 pub const PtrType = struct {
1430 kind: Kind,
1431 allowzero_token: ?TokenIndex,
1432 const_token: ?TokenIndex,
1433 volatile_token: ?TokenIndex,
1434 ast: Ast,
1435
1436 pub const Kind = enum {
1437 one,
1438 many,
1439 sentinel,
1440 c,
1441 slice,
1442 slice_sentinel,
1443 };
1444
1445 pub const Ast = struct {
1446 main_token: TokenIndex,
1447 align_node: Node.Index,
1448 sentinel: Node.Index,
1449 bit_range_start: Node.Index,
1450 bit_range_end: Node.Index,
1451 child_type: Node.Index,
1452 };
1453 };
1454
13051455 pub const ContainerDecl = struct {
13061456 layout_token: ?TokenIndex,
13071457 ast: Ast,
......@@ -1696,16 +1846,19 @@ pub const Node = struct {
16961846 /// `[*]align(lhs) rhs`. lhs can be omitted.
16971847 /// `*align(lhs) rhs`. lhs can be omitted.
16981848 /// `[]rhs`.
1849 /// main_token is the asterisk if a pointer or the lbrace if a slice
16991850 PtrTypeAligned,
17001851 /// `[*:lhs]rhs`. lhs can be omitted.
17011852 /// `*rhs`.
17021853 /// `[:lhs]rhs`.
1854 /// main_token is the asterisk if a pointer or the lbrace if a slice
17031855 PtrTypeSentinel,
17041856 /// lhs is index into PtrType. rhs is the element type expression.
1857 /// main_token is the asterisk if a pointer or the lbrace if a slice
17051858 PtrType,
1706 /// lhs is index into SliceType. rhs is the element type expression.
1707 /// Can be pointer or slice, depending on main_token.
1708 SliceType,
1859 /// lhs is index into PtrTypeBitRange. rhs is the element type expression.
1860 /// main_token is the asterisk if a pointer or the lbrace if a slice
1861 PtrTypeBitRange,
17091862 /// `lhs[rhs..]`
17101863 /// main_token is the `[`.
17111864 SliceOpen,
......@@ -1954,14 +2107,15 @@ pub const Node = struct {
19542107 pub const PtrType = struct {
19552108 sentinel: Index,
19562109 align_node: Index,
1957 bit_range_start: Index,
1958 bit_range_end: Index,
19592110 };
19602111
1961 pub const SliceType = struct {
2112 pub const PtrTypeBitRange = struct {
19622113 sentinel: Index,
19632114 align_node: Index,
2115 bit_range_start: Index,
2116 bit_range_end: Index,
19642117 };
2118
19652119 pub const SubRange = struct {
19662120 /// Index into sub_list.
19672121 start: Index,
lib/std/zig/parse.zig+10-10
......@@ -1618,10 +1618,10 @@ const Parser = struct {
16181618 });
16191619 } else {
16201620 return p.addNode(.{
1621 .tag = .PtrType,
1621 .tag = .PtrTypeBitRange,
16221622 .main_token = asterisk,
16231623 .data = .{
1624 .lhs = try p.addExtra(Node.PtrType{
1624 .lhs = try p.addExtra(Node.PtrTypeBitRange{
16251625 .sentinel = 0,
16261626 .align_node = mods.align_node,
16271627 .bit_range_start = mods.bit_range_start,
......@@ -1648,10 +1648,10 @@ const Parser = struct {
16481648 });
16491649 } else {
16501650 break :inner try p.addNode(.{
1651 .tag = .PtrType,
1651 .tag = .PtrTypeBitRange,
16521652 .main_token = asterisk,
16531653 .data = .{
1654 .lhs = try p.addExtra(Node.PtrType{
1654 .lhs = try p.addExtra(Node.PtrTypeBitRange{
16551655 .sentinel = 0,
16561656 .align_node = mods.align_node,
16571657 .bit_range_start = mods.bit_range_start,
......@@ -1713,10 +1713,10 @@ const Parser = struct {
17131713 });
17141714 } else {
17151715 return p.addNode(.{
1716 .tag = .SliceType,
1716 .tag = .PtrType,
17171717 .main_token = asterisk,
17181718 .data = .{
1719 .lhs = try p.addExtra(.{
1719 .lhs = try p.addExtra(Node.PtrType{
17201720 .sentinel = sentinel,
17211721 .align_node = mods.align_node,
17221722 }),
......@@ -1726,10 +1726,10 @@ const Parser = struct {
17261726 }
17271727 } else {
17281728 return p.addNode(.{
1729 .tag = .PtrType,
1729 .tag = .PtrTypeBitRange,
17301730 .main_token = asterisk,
17311731 .data = .{
1732 .lhs = try p.addExtra(.{
1732 .lhs = try p.addExtra(Node.PtrTypeBitRange{
17331733 .sentinel = sentinel,
17341734 .align_node = mods.align_node,
17351735 .bit_range_start = mods.bit_range_start,
......@@ -1777,10 +1777,10 @@ const Parser = struct {
17771777 });
17781778 } else {
17791779 return p.addNode(.{
1780 .tag = .SliceType,
1780 .tag = .PtrType,
17811781 .main_token = lbracket,
17821782 .data = .{
1783 .lhs = try p.addExtra(.{
1783 .lhs = try p.addExtra(Node.PtrType{
17841784 .sentinel = sentinel,
17851785 .align_node = mods.align_node,
17861786 }),
lib/std/zig/parser_test.zig+53-1
......@@ -345,7 +345,59 @@ test "zig fmt: builtin call with trailing comma" {
345345// \\
346346// );
347347//}
348//
348
349test "zig fmt: pointer-to-one with modifiers" {
350 try testCanonical(
351 \\const x: *u32 = undefined;
352 \\const y: *allowzero align(8) const volatile u32 = undefined;
353 \\const z: *allowzero align(8:4:2) const volatile u32 = undefined;
354 \\
355 );
356}
357
358test "zig fmt: pointer-to-many with modifiers" {
359 try testCanonical(
360 \\const x: [*]u32 = undefined;
361 \\const y: [*]allowzero align(8) const volatile u32 = undefined;
362 \\const z: [*]allowzero align(8:4:2) const volatile u32 = undefined;
363 \\
364 );
365}
366
367test "zig fmt: sentinel pointer with modifiers" {
368 try testCanonical(
369 \\const x: [*:42]u32 = undefined;
370 \\const y: [*:42]allowzero align(8) const volatile u32 = undefined;
371 \\const y: [*:42]allowzero align(8:4:2) const volatile u32 = undefined;
372 \\
373 );
374}
375
376test "zig fmt: c pointer with modifiers" {
377 try testCanonical(
378 \\const x: [*c]u32 = undefined;
379 \\const y: [*c]allowzero align(8) const volatile u32 = undefined;
380 \\const z: [*c]allowzero align(8:4:2) const volatile u32 = undefined;
381 \\
382 );
383}
384
385test "zig fmt: slice with modifiers" {
386 try testCanonical(
387 \\const x: []u32 = undefined;
388 \\const y: []allowzero align(8) const volatile u32 = undefined;
389 \\
390 );
391}
392
393test "zig fmt: sentinel slice with modifiers" {
394 try testCanonical(
395 \\const x: [:42]u32 = undefined;
396 \\const y: [:42]allowzero align(8) const volatile u32 = undefined;
397 \\
398 );
399}
400
349401//test "zig fmt: anon literal in array" {
350402// try testCanonical(
351403// \\var arr: [2]Foo = .{
lib/std/zig/render.zig+76-114
......@@ -370,120 +370,10 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
370370 .ArrayType => return renderArrayType(ais, tree, tree.arrayType(node), space),
371371 .ArrayTypeSentinel => return renderArrayType(ais, tree, tree.arrayTypeSentinel(node), space),
372372
373 .PtrType => unreachable, // TODO
374 .PtrTypeAligned => unreachable, // TODO
375 .PtrTypeSentinel => unreachable, // TODO
376 //.PtrType => {
377 // const ptr_type = @fieldParentPtr(ast.Node.PtrType, "base", base);
378 // const op_tok_id = tree.token_tags[ptr_type.op_token];
379 // switch (op_tok_id) {
380 // .Asterisk, .AsteriskAsterisk => try ais.writer().writeByte('*'),
381 // .LBracket => if (tree.token_tags[ptr_type.op_token + 2] == .Identifier)
382 // try ais.writer().writeAll("[*c")
383 // else
384 // try ais.writer().writeAll("[*"),
385 // else => unreachable,
386 // }
387 // if (ptr_type.ptr_info.sentinel) |sentinel| {
388 // const colon_token = tree.prevToken(sentinel.firstToken());
389 // try renderToken(ais, tree, colon_token, Space.None); // :
390 // const sentinel_space = switch (op_tok_id) {
391 // .LBracket => Space.None,
392 // else => Space.Space,
393 // };
394 // try renderExpression(ais, tree, sentinel, sentinel_space);
395 // }
396 // switch (op_tok_id) {
397 // .Asterisk, .AsteriskAsterisk => {},
398 // .LBracket => try ais.writer().writeByte(']'),
399 // else => unreachable,
400 // }
401 // if (ptr_type.ptr_info.allowzero_token) |allowzero_token| {
402 // try renderToken(ais, tree, allowzero_token, Space.Space); // allowzero
403 // }
404 // if (ptr_type.ptr_info.align_info) |align_info| {
405 // const lparen_token = tree.prevToken(align_info.node.firstToken());
406 // const align_token = tree.prevToken(lparen_token);
407
408 // try renderToken(ais, tree, align_token, Space.None); // align
409 // try renderToken(ais, tree, lparen_token, Space.None); // (
410
411 // try renderExpression(ais, tree, align_info.node, Space.None);
412
413 // if (align_info.bit_range) |bit_range| {
414 // const colon1 = tree.prevToken(bit_range.start.firstToken());
415 // const colon2 = tree.prevToken(bit_range.end.firstToken());
416
417 // try renderToken(ais, tree, colon1, Space.None); // :
418 // try renderExpression(ais, tree, bit_range.start, Space.None);
419 // try renderToken(ais, tree, colon2, Space.None); // :
420 // try renderExpression(ais, tree, bit_range.end, Space.None);
421
422 // const rparen_token = tree.nextToken(bit_range.end.lastToken());
423 // try renderToken(ais, tree, rparen_token, Space.Space); // )
424 // } else {
425 // const rparen_token = tree.nextToken(align_info.node.lastToken());
426 // try renderToken(ais, tree, rparen_token, Space.Space); // )
427 // }
428 // }
429 // if (ptr_type.ptr_info.const_token) |const_token| {
430 // try renderToken(ais, tree, const_token, Space.Space); // const
431 // }
432 // if (ptr_type.ptr_info.volatile_token) |volatile_token| {
433 // try renderToken(ais, tree, volatile_token, Space.Space); // volatile
434 // }
435 // return renderExpression(ais, tree, ptr_type.rhs, space);
436 //},
437
438 .SliceType => unreachable, // TODO
439 //.SliceType => {
440 // const slice_type = @fieldParentPtr(ast.Node.SliceType, "base", base);
441 // try renderToken(ais, tree, slice_type.op_token, Space.None); // [
442 // if (slice_type.ptr_info.sentinel) |sentinel| {
443 // const colon_token = tree.prevToken(sentinel.firstToken());
444 // try renderToken(ais, tree, colon_token, Space.None); // :
445 // try renderExpression(ais, tree, sentinel, Space.None);
446 // try renderToken(ais, tree, tree.nextToken(sentinel.lastToken()), Space.None); // ]
447 // } else {
448 // try renderToken(ais, tree, tree.nextToken(slice_type.op_token), Space.None); // ]
449 // }
450
451 // if (slice_type.ptr_info.allowzero_token) |allowzero_token| {
452 // try renderToken(ais, tree, allowzero_token, Space.Space); // allowzero
453 // }
454 // if (slice_type.ptr_info.align_info) |align_info| {
455 // const lparen_token = tree.prevToken(align_info.node.firstToken());
456 // const align_token = tree.prevToken(lparen_token);
457
458 // try renderToken(ais, tree, align_token, Space.None); // align
459 // try renderToken(ais, tree, lparen_token, Space.None); // (
460
461 // try renderExpression(ais, tree, align_info.node, Space.None);
462
463 // if (align_info.bit_range) |bit_range| {
464 // const colon1 = tree.prevToken(bit_range.start.firstToken());
465 // const colon2 = tree.prevToken(bit_range.end.firstToken());
466
467 // try renderToken(ais, tree, colon1, Space.None); // :
468 // try renderExpression(ais, tree, bit_range.start, Space.None);
469 // try renderToken(ais, tree, colon2, Space.None); // :
470 // try renderExpression(ais, tree, bit_range.end, Space.None);
471
472 // const rparen_token = tree.nextToken(bit_range.end.lastToken());
473 // try renderToken(ais, tree, rparen_token, Space.Space); // )
474 // } else {
475 // const rparen_token = tree.nextToken(align_info.node.lastToken());
476 // try renderToken(ais, tree, rparen_token, Space.Space); // )
477 // }
478 // }
479 // if (slice_type.ptr_info.const_token) |const_token| {
480 // try renderToken(ais, tree, const_token, Space.Space);
481 // }
482 // if (slice_type.ptr_info.volatile_token) |volatile_token| {
483 // try renderToken(ais, tree, volatile_token, Space.Space);
484 // }
485 // return renderExpression(ais, tree, slice_type.rhs, space);
486 //},
373 .PtrTypeAligned => return renderPtrType(ais, tree, tree.ptrTypeAligned(node), space),
374 .PtrTypeSentinel => return renderPtrType(ais, tree, tree.ptrTypeSentinel(node), space),
375 .PtrType => return renderPtrType(ais, tree, tree.ptrType(node), space),
376 .PtrTypeBitRange => return renderPtrType(ais, tree, tree.ptrTypeBitRange(node), space),
487377
488378 .ArrayInitOne => {
489379 var elements: [1]ast.Node.Index = undefined;
......@@ -1180,6 +1070,78 @@ fn renderArrayType(
11801070 return renderExpression(ais, tree, array_type.ast.elem_type, space);
11811071}
11821072
1073fn renderPtrType(
1074 ais: *Ais,
1075 tree: ast.Tree,
1076 ptr_type: ast.Full.PtrType,
1077 space: Space,
1078) Error!void {
1079 switch (ptr_type.kind) {
1080 .one => {
1081 try renderToken(ais, tree, ptr_type.ast.main_token, .None); // asterisk
1082 },
1083 .many => {
1084 try renderToken(ais, tree, ptr_type.ast.main_token - 1, .None); // lbracket
1085 try renderToken(ais, tree, ptr_type.ast.main_token, .None); // asterisk
1086 try renderToken(ais, tree, ptr_type.ast.main_token + 1, .None); // rbracket
1087 },
1088 .sentinel => {
1089 try renderToken(ais, tree, ptr_type.ast.main_token - 1, .None); // lbracket
1090 try renderToken(ais, tree, ptr_type.ast.main_token, .None); // asterisk
1091 try renderToken(ais, tree, ptr_type.ast.main_token + 1, .None); // colon
1092 try renderExpression(ais, tree, ptr_type.ast.sentinel, .None);
1093 try renderToken(ais, tree, tree.lastToken(ptr_type.ast.sentinel) + 1, .None); // rbracket
1094 },
1095 .c => {
1096 try renderToken(ais, tree, ptr_type.ast.main_token - 1, .None); // lbracket
1097 try renderToken(ais, tree, ptr_type.ast.main_token, .None); // asterisk
1098 try renderToken(ais, tree, ptr_type.ast.main_token + 1, .None); // c
1099 try renderToken(ais, tree, ptr_type.ast.main_token + 2, .None); // rbracket
1100 },
1101 .slice => {
1102 try renderToken(ais, tree, ptr_type.ast.main_token, .None); // lbracket
1103 try renderToken(ais, tree, ptr_type.ast.main_token + 1, .None); // rbracket
1104 },
1105 .slice_sentinel => {
1106 try renderToken(ais, tree, ptr_type.ast.main_token, .None); // lbracket
1107 try renderToken(ais, tree, ptr_type.ast.main_token + 1, .None); // colon
1108 try renderExpression(ais, tree, ptr_type.ast.sentinel, .None);
1109 try renderToken(ais, tree, tree.lastToken(ptr_type.ast.sentinel) + 1, .None); // rbracket
1110 },
1111 }
1112
1113 if (ptr_type.allowzero_token) |allowzero_token| {
1114 try renderToken(ais, tree, allowzero_token, .Space);
1115 }
1116
1117 if (ptr_type.ast.align_node != 0) {
1118 const align_first = tree.firstToken(ptr_type.ast.align_node);
1119 try renderToken(ais, tree, align_first - 2, .None); // align
1120 try renderToken(ais, tree, align_first - 1, .None); // lparen
1121 try renderExpression(ais, tree, ptr_type.ast.align_node, .None);
1122 if (ptr_type.ast.bit_range_start != 0) {
1123 assert(ptr_type.ast.bit_range_end != 0);
1124 try renderToken(ais, tree, tree.firstToken(ptr_type.ast.bit_range_start) - 1, .None); // colon
1125 try renderExpression(ais, tree, ptr_type.ast.bit_range_start, .None);
1126 try renderToken(ais, tree, tree.firstToken(ptr_type.ast.bit_range_end) - 1, .None); // colon
1127 try renderExpression(ais, tree, ptr_type.ast.bit_range_end, .None);
1128 try renderToken(ais, tree, tree.lastToken(ptr_type.ast.bit_range_end) + 1, .Space); // rparen
1129 } else {
1130 try renderToken(ais, tree, tree.lastToken(ptr_type.ast.align_node) + 1, .Space); // rparen
1131 }
1132 }
1133
1134 if (ptr_type.const_token) |const_token| {
1135 try renderToken(ais, tree, const_token, .Space);
1136 }
1137
1138 if (ptr_type.volatile_token) |volatile_token| {
1139 try renderToken(ais, tree, volatile_token, .Space);
1140 }
1141
1142 try renderExpression(ais, tree, ptr_type.ast.child_type, space);
1143}
1144
11831145fn renderAsmOutput(
11841146 allocator: *mem.Allocator,
11851147 ais: *Ais,