authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-13 20:13:51-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-13 20:13:51-07:00
log14cef9dd3d8074b0dc2ee48a0905300ce6317aed
tree246220eb1846d00a982c33d8e0fae5b5f4ee150c
parent204f61d7f5aa7b5e27bdaaab9237fca17096ad3e

stage2 parser: split out PrefixOp into separate AST Nodes

This is part of a larger effort to improve the memory layout of AST nodes of the self-hosted parser to reduce wasted memory. Reduction of wasted memory also translates to improved performance because of fewer memory allocations, and fewer cache misses. Compared to master, when running `zig fmt` on the std lib: * cache-misses: 801,829 => 768,624 * instructions: 3,234,877,167 => 3,232,075,022 * peak memory: 81480 KB => 75964 KB

5 files changed, 711 insertions(+), 408 deletions(-)

lib/std/zig/ast.zig+169-71
......@@ -410,7 +410,20 @@ pub const Node = struct {
410410
411411 // Operators
412412 InfixOp,
413 PrefixOp,
413 AddressOf,
414 Await,
415 BitNot,
416 BoolNot,
417 OptionalType,
418 Negation,
419 NegationWrap,
420 Resume,
421 Try,
422 ArrayType,
423 /// ArrayType but has a sentinel node.
424 ArrayTypeSentinel,
425 PtrType,
426 SliceType,
414427 /// Not all suffix operations are under this tag. To save memory, some
415428 /// suffix operations have dedicated Node tags.
416429 SuffixOp,
......@@ -1797,85 +1810,116 @@ pub const Node = struct {
17971810 }
17981811 };
17991812
1800 pub const PrefixOp = struct {
1801 base: Node = Node{ .id = .PrefixOp },
1813 pub const AddressOf = SimplePrefixOp(.AddressOf);
1814 pub const Await = SimplePrefixOp(.Await);
1815 pub const BitNot = SimplePrefixOp(.BitNot);
1816 pub const BoolNot = SimplePrefixOp(.BoolNot);
1817 pub const OptionalType = SimplePrefixOp(.OptionalType);
1818 pub const Negation = SimplePrefixOp(.Negation);
1819 pub const NegationWrap = SimplePrefixOp(.NegationWrap);
1820 pub const Resume = SimplePrefixOp(.Resume);
1821 pub const Try = SimplePrefixOp(.Try);
1822
1823 pub fn SimplePrefixOp(comptime tag: Id) type {
1824 return struct {
1825 base: Node = Node{ .id = tag },
1826 op_token: TokenIndex,
1827 rhs: *Node,
1828
1829 const Self = @This();
1830
1831 pub fn iterate(self: *const Self, index: usize) ?*Node {
1832 if (index == 0) return self.rhs;
1833 return null;
1834 }
1835
1836 pub fn firstToken(self: *const Self) TokenIndex {
1837 return self.op_token;
1838 }
1839
1840 pub fn lastToken(self: *const Self) TokenIndex {
1841 return self.rhs.lastToken();
1842 }
1843 };
1844 }
1845
1846 pub const ArrayType = struct {
1847 base: Node = Node{ .id = .ArrayType },
18021848 op_token: TokenIndex,
1803 op: Op,
18041849 rhs: *Node,
1850 len_expr: *Node,
18051851
1806 pub const Op = union(enum) {
1807 AddressOf,
1808 ArrayType: ArrayInfo,
1809 Await,
1810 BitNot,
1811 BoolNot,
1812 OptionalType,
1813 Negation,
1814 NegationWrap,
1815 Resume,
1816 PtrType: PtrInfo,
1817 SliceType: PtrInfo,
1818 Try,
1819 };
1852 pub fn iterate(self: *const ArrayType, index: usize) ?*Node {
1853 var i = index;
18201854
1821 pub const ArrayInfo = struct {
1822 len_expr: *Node,
1823 sentinel: ?*Node,
1824 };
1855 if (i < 1) return self.len_expr;
1856 i -= 1;
18251857
1826 pub const PtrInfo = struct {
1827 allowzero_token: ?TokenIndex = null,
1828 align_info: ?Align = null,
1829 const_token: ?TokenIndex = null,
1830 volatile_token: ?TokenIndex = null,
1831 sentinel: ?*Node = null,
1832
1833 pub const Align = struct {
1834 node: *Node,
1835 bit_range: ?BitRange,
1836
1837 pub const BitRange = struct {
1838 start: *Node,
1839 end: *Node,
1840 };
1841 };
1842 };
1858 if (i < 1) return self.rhs;
1859 i -= 1;
1860
1861 return null;
1862 }
18431863
1844 pub fn iterate(self: *const PrefixOp, index: usize) ?*Node {
1864 pub fn firstToken(self: *const ArrayType) TokenIndex {
1865 return self.op_token;
1866 }
1867
1868 pub fn lastToken(self: *const ArrayType) TokenIndex {
1869 return self.rhs.lastToken();
1870 }
1871 };
1872
1873 pub const ArrayTypeSentinel = struct {
1874 base: Node = Node{ .id = .ArrayTypeSentinel },
1875 op_token: TokenIndex,
1876 rhs: *Node,
1877 len_expr: *Node,
1878 sentinel: *Node,
1879
1880 pub fn iterate(self: *const ArrayTypeSentinel, index: usize) ?*Node {
18451881 var i = index;
18461882
1847 switch (self.op) {
1848 .PtrType, .SliceType => |addr_of_info| {
1849 if (addr_of_info.sentinel) |sentinel| {
1850 if (i < 1) return sentinel;
1851 i -= 1;
1852 }
1883 if (i < 1) return self.len_expr;
1884 i -= 1;
18531885
1854 if (addr_of_info.align_info) |align_info| {
1855 if (i < 1) return align_info.node;
1856 i -= 1;
1857 }
1858 },
1886 if (i < 1) return self.sentinel;
1887 i -= 1;
18591888
1860 .ArrayType => |array_info| {
1861 if (i < 1) return array_info.len_expr;
1862 i -= 1;
1863 if (array_info.sentinel) |sentinel| {
1864 if (i < 1) return sentinel;
1865 i -= 1;
1866 }
1867 },
1889 if (i < 1) return self.rhs;
1890 i -= 1;
18681891
1869 .AddressOf,
1870 .Await,
1871 .BitNot,
1872 .BoolNot,
1873 .OptionalType,
1874 .Negation,
1875 .NegationWrap,
1876 .Try,
1877 .Resume,
1878 => {},
1892 return null;
1893 }
1894
1895 pub fn firstToken(self: *const ArrayTypeSentinel) TokenIndex {
1896 return self.op_token;
1897 }
1898
1899 pub fn lastToken(self: *const ArrayTypeSentinel) TokenIndex {
1900 return self.rhs.lastToken();
1901 }
1902 };
1903
1904 pub const PtrType = struct {
1905 base: Node = Node{ .id = .PtrType },
1906 op_token: TokenIndex,
1907 rhs: *Node,
1908 /// TODO Add a u8 flags field to Node where it would otherwise be padding, and each bit represents
1909 /// one of these possibly-null things. Then we have them directly follow the PtrType in memory.
1910 ptr_info: PtrInfo = .{},
1911
1912 pub fn iterate(self: *const PtrType, index: usize) ?*Node {
1913 var i = index;
1914
1915 if (self.ptr_info.sentinel) |sentinel| {
1916 if (i < 1) return sentinel;
1917 i -= 1;
1918 }
1919
1920 if (self.ptr_info.align_info) |align_info| {
1921 if (i < 1) return align_info.node;
1922 i -= 1;
18791923 }
18801924
18811925 if (i < 1) return self.rhs;
......@@ -1884,11 +1928,47 @@ pub const Node = struct {
18841928 return null;
18851929 }
18861930
1887 pub fn firstToken(self: *const PrefixOp) TokenIndex {
1931 pub fn firstToken(self: *const PtrType) TokenIndex {
18881932 return self.op_token;
18891933 }
18901934
1891 pub fn lastToken(self: *const PrefixOp) TokenIndex {
1935 pub fn lastToken(self: *const PtrType) TokenIndex {
1936 return self.rhs.lastToken();
1937 }
1938 };
1939
1940 pub const SliceType = struct {
1941 base: Node = Node{ .id = .SliceType },
1942 op_token: TokenIndex,
1943 rhs: *Node,
1944 /// TODO Add a u8 flags field to Node where it would otherwise be padding, and each bit represents
1945 /// one of these possibly-null things. Then we have them directly follow the SliceType in memory.
1946 ptr_info: PtrInfo = .{},
1947
1948 pub fn iterate(self: *const SliceType, index: usize) ?*Node {
1949 var i = index;
1950
1951 if (self.ptr_info.sentinel) |sentinel| {
1952 if (i < 1) return sentinel;
1953 i -= 1;
1954 }
1955
1956 if (self.ptr_info.align_info) |align_info| {
1957 if (i < 1) return align_info.node;
1958 i -= 1;
1959 }
1960
1961 if (i < 1) return self.rhs;
1962 i -= 1;
1963
1964 return null;
1965 }
1966
1967 pub fn firstToken(self: *const SliceType) TokenIndex {
1968 return self.op_token;
1969 }
1970
1971 pub fn lastToken(self: *const SliceType) TokenIndex {
18921972 return self.rhs.lastToken();
18931973 }
18941974 };
......@@ -2797,6 +2877,24 @@ pub const Node = struct {
27972877 };
27982878};
27992879
2880pub const PtrInfo = struct {
2881 allowzero_token: ?TokenIndex = null,
2882 align_info: ?Align = null,
2883 const_token: ?TokenIndex = null,
2884 volatile_token: ?TokenIndex = null,
2885 sentinel: ?*Node = null,
2886
2887 pub const Align = struct {
2888 node: *Node,
2889 bit_range: ?BitRange = null,
2890
2891 pub const BitRange = struct {
2892 start: *Node,
2893 end: *Node,
2894 };
2895 };
2896};
2897
28002898test "iterate" {
28012899 var root = Node.Root{
28022900 .base = Node{ .id = Node.Id.Root },
lib/std/zig/parse.zig+243-105
......@@ -1120,10 +1120,9 @@ const Parser = struct {
11201120 const expr_node = try p.expectNode(parseExpr, .{
11211121 .ExpectedExpr = .{ .token = p.tok_i },
11221122 });
1123 const node = try p.arena.allocator.create(Node.PrefixOp);
1123 const node = try p.arena.allocator.create(Node.Resume);
11241124 node.* = .{
11251125 .op_token = token,
1126 .op = .Resume,
11271126 .rhs = expr_node,
11281127 };
11291128 return &node.base;
......@@ -2413,24 +2412,25 @@ const Parser = struct {
24132412 /// / KEYWORD_await
24142413 fn parsePrefixOp(p: *Parser) !?*Node {
24152414 const token = p.nextToken();
2416 const op: Node.PrefixOp.Op = switch (p.token_ids[token]) {
2417 .Bang => .BoolNot,
2418 .Minus => .Negation,
2419 .Tilde => .BitNot,
2420 .MinusPercent => .NegationWrap,
2421 .Ampersand => .AddressOf,
2422 .Keyword_try => .Try,
2423 .Keyword_await => .Await,
2415 switch (p.token_ids[token]) {
2416 .Bang => return p.allocSimplePrefixOp(.BoolNot, token),
2417 .Minus => return p.allocSimplePrefixOp(.Negation, token),
2418 .Tilde => return p.allocSimplePrefixOp(.BitNot, token),
2419 .MinusPercent => return p.allocSimplePrefixOp(.NegationWrap, token),
2420 .Ampersand => return p.allocSimplePrefixOp(.AddressOf, token),
2421 .Keyword_try => return p.allocSimplePrefixOp(.Try, token),
2422 .Keyword_await => return p.allocSimplePrefixOp(.Await, token),
24242423 else => {
24252424 p.putBackToken(token);
24262425 return null;
24272426 },
2428 };
2427 }
2428 }
24292429
2430 const node = try p.arena.allocator.create(Node.PrefixOp);
2430 fn allocSimplePrefixOp(p: *Parser, comptime tag: Node.Id, token: TokenIndex) !?*Node {
2431 const node = try p.arena.allocator.create(Node.SimplePrefixOp(tag));
24312432 node.* = .{
24322433 .op_token = token,
2433 .op = op,
24342434 .rhs = undefined, // set by caller
24352435 };
24362436 return &node.base;
......@@ -2450,19 +2450,14 @@ const Parser = struct {
24502450 /// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
24512451 fn parsePrefixTypeOp(p: *Parser) !?*Node {
24522452 if (p.eatToken(.QuestionMark)) |token| {
2453 const node = try p.arena.allocator.create(Node.PrefixOp);
2453 const node = try p.arena.allocator.create(Node.OptionalType);
24542454 node.* = .{
24552455 .op_token = token,
2456 .op = .OptionalType,
24572456 .rhs = undefined, // set by caller
24582457 };
24592458 return &node.base;
24602459 }
24612460
2462 // TODO: Returning a AnyFrameType instead of PrefixOp makes casting and setting .rhs or
2463 // .return_type more difficult for the caller (see parsePrefixOpExpr helper).
2464 // Consider making the AnyFrameType a member of PrefixOp and add a
2465 // PrefixOp.AnyFrameType variant?
24662461 if (p.eatToken(.Keyword_anyframe)) |token| {
24672462 const arrow = p.eatToken(.Arrow) orelse {
24682463 p.putBackToken(token);
......@@ -2482,11 +2477,15 @@ const Parser = struct {
24822477 if (try p.parsePtrTypeStart()) |node| {
24832478 // If the token encountered was **, there will be two nodes instead of one.
24842479 // The attributes should be applied to the rightmost operator.
2485 const prefix_op = node.cast(Node.PrefixOp).?;
2486 var ptr_info = if (p.token_ids[prefix_op.op_token] == .AsteriskAsterisk)
2487 &prefix_op.rhs.cast(Node.PrefixOp).?.op.PtrType
2480 var ptr_info = if (node.cast(Node.PtrType)) |ptr_type|
2481 if (p.token_ids[ptr_type.op_token] == .AsteriskAsterisk)
2482 &ptr_type.rhs.cast(Node.PtrType).?.ptr_info
2483 else
2484 &ptr_type.ptr_info
2485 else if (node.cast(Node.SliceType)) |slice_type|
2486 &slice_type.ptr_info
24882487 else
2489 &prefix_op.op.PtrType;
2488 unreachable;
24902489
24912490 while (true) {
24922491 if (p.eatToken(.Keyword_align)) |align_token| {
......@@ -2505,7 +2504,7 @@ const Parser = struct {
25052504 .ExpectedIntegerLiteral = .{ .token = p.tok_i },
25062505 });
25072506
2508 break :bit_range_value Node.PrefixOp.PtrInfo.Align.BitRange{
2507 break :bit_range_value ast.PtrInfo.Align.BitRange{
25092508 .start = range_start,
25102509 .end = range_end,
25112510 };
......@@ -2519,7 +2518,7 @@ const Parser = struct {
25192518 continue;
25202519 }
25212520
2522 ptr_info.align_info = Node.PrefixOp.PtrInfo.Align{
2521 ptr_info.align_info = ast.PtrInfo.Align{
25232522 .node = expr_node,
25242523 .bit_range = bit_range,
25252524 };
......@@ -2563,58 +2562,54 @@ const Parser = struct {
25632562 }
25642563
25652564 if (try p.parseArrayTypeStart()) |node| {
2566 switch (node.cast(Node.PrefixOp).?.op) {
2567 .ArrayType => {},
2568 .SliceType => |*slice_type| {
2569 // Collect pointer qualifiers in any order, but disallow duplicates
2570 while (true) {
2571 if (try p.parseByteAlign()) |align_expr| {
2572 if (slice_type.align_info != null) {
2573 try p.errors.append(p.gpa, .{
2574 .ExtraAlignQualifier = .{ .token = p.tok_i - 1 },
2575 });
2576 continue;
2577 }
2578 slice_type.align_info = Node.PrefixOp.PtrInfo.Align{
2579 .node = align_expr,
2580 .bit_range = null,
2581 };
2565 if (node.cast(Node.SliceType)) |slice_type| {
2566 // Collect pointer qualifiers in any order, but disallow duplicates
2567 while (true) {
2568 if (try p.parseByteAlign()) |align_expr| {
2569 if (slice_type.ptr_info.align_info != null) {
2570 try p.errors.append(p.gpa, .{
2571 .ExtraAlignQualifier = .{ .token = p.tok_i - 1 },
2572 });
25822573 continue;
25832574 }
2584 if (p.eatToken(.Keyword_const)) |const_token| {
2585 if (slice_type.const_token != null) {
2586 try p.errors.append(p.gpa, .{
2587 .ExtraConstQualifier = .{ .token = p.tok_i - 1 },
2588 });
2589 continue;
2590 }
2591 slice_type.const_token = const_token;
2575 slice_type.ptr_info.align_info = ast.PtrInfo.Align{
2576 .node = align_expr,
2577 .bit_range = null,
2578 };
2579 continue;
2580 }
2581 if (p.eatToken(.Keyword_const)) |const_token| {
2582 if (slice_type.ptr_info.const_token != null) {
2583 try p.errors.append(p.gpa, .{
2584 .ExtraConstQualifier = .{ .token = p.tok_i - 1 },
2585 });
25922586 continue;
25932587 }
2594 if (p.eatToken(.Keyword_volatile)) |volatile_token| {
2595 if (slice_type.volatile_token != null) {
2596 try p.errors.append(p.gpa, .{
2597 .ExtraVolatileQualifier = .{ .token = p.tok_i - 1 },
2598 });
2599 continue;
2600 }
2601 slice_type.volatile_token = volatile_token;
2588 slice_type.ptr_info.const_token = const_token;
2589 continue;
2590 }
2591 if (p.eatToken(.Keyword_volatile)) |volatile_token| {
2592 if (slice_type.ptr_info.volatile_token != null) {
2593 try p.errors.append(p.gpa, .{
2594 .ExtraVolatileQualifier = .{ .token = p.tok_i - 1 },
2595 });
26022596 continue;
26032597 }
2604 if (p.eatToken(.Keyword_allowzero)) |allowzero_token| {
2605 if (slice_type.allowzero_token != null) {
2606 try p.errors.append(p.gpa, .{
2607 .ExtraAllowZeroQualifier = .{ .token = p.tok_i - 1 },
2608 });
2609 continue;
2610 }
2611 slice_type.allowzero_token = allowzero_token;
2598 slice_type.ptr_info.volatile_token = volatile_token;
2599 continue;
2600 }
2601 if (p.eatToken(.Keyword_allowzero)) |allowzero_token| {
2602 if (slice_type.ptr_info.allowzero_token != null) {
2603 try p.errors.append(p.gpa, .{
2604 .ExtraAllowZeroQualifier = .{ .token = p.tok_i - 1 },
2605 });
26122606 continue;
26132607 }
2614 break;
2608 slice_type.ptr_info.allowzero_token = allowzero_token;
2609 continue;
26152610 }
2616 },
2617 else => unreachable,
2611 break;
2612 }
26182613 }
26192614 return node;
26202615 }
......@@ -2728,29 +2723,32 @@ const Parser = struct {
27282723 null;
27292724 const rbracket = try p.expectToken(.RBracket);
27302725
2731 const op: Node.PrefixOp.Op = if (expr) |len_expr|
2732 .{
2733 .ArrayType = .{
2726 if (expr) |len_expr| {
2727 if (sentinel) |s| {
2728 const node = try p.arena.allocator.create(Node.ArrayTypeSentinel);
2729 node.* = .{
2730 .op_token = lbracket,
2731 .rhs = undefined, // set by caller
27342732 .len_expr = len_expr,
2735 .sentinel = sentinel,
2736 },
2733 .sentinel = s,
2734 };
2735 return &node.base;
2736 } else {
2737 const node = try p.arena.allocator.create(Node.ArrayType);
2738 node.* = .{
2739 .op_token = lbracket,
2740 .rhs = undefined, // set by caller
2741 .len_expr = len_expr,
2742 };
2743 return &node.base;
27372744 }
2738 else
2739 .{
2740 .SliceType = Node.PrefixOp.PtrInfo{
2741 .allowzero_token = null,
2742 .align_info = null,
2743 .const_token = null,
2744 .volatile_token = null,
2745 .sentinel = sentinel,
2746 },
2747 };
2745 }
27482746
2749 const node = try p.arena.allocator.create(Node.PrefixOp);
2747 const node = try p.arena.allocator.create(Node.SliceType);
27502748 node.* = .{
27512749 .op_token = lbracket,
2752 .op = op,
27532750 .rhs = undefined, // set by caller
2751 .ptr_info = .{ .sentinel = sentinel },
27542752 };
27552753 return &node.base;
27562754 }
......@@ -2768,28 +2766,26 @@ const Parser = struct {
27682766 })
27692767 else
27702768 null;
2771 const node = try p.arena.allocator.create(Node.PrefixOp);
2769 const node = try p.arena.allocator.create(Node.PtrType);
27722770 node.* = .{
27732771 .op_token = asterisk,
2774 .op = .{ .PtrType = .{ .sentinel = sentinel } },
27752772 .rhs = undefined, // set by caller
2773 .ptr_info = .{ .sentinel = sentinel },
27762774 };
27772775 return &node.base;
27782776 }
27792777
27802778 if (p.eatToken(.AsteriskAsterisk)) |double_asterisk| {
2781 const node = try p.arena.allocator.create(Node.PrefixOp);
2779 const node = try p.arena.allocator.create(Node.PtrType);
27822780 node.* = .{
27832781 .op_token = double_asterisk,
2784 .op = .{ .PtrType = .{} },
27852782 .rhs = undefined, // set by caller
27862783 };
27872784
27882785 // Special case for **, which is its own token
2789 const child = try p.arena.allocator.create(Node.PrefixOp);
2786 const child = try p.arena.allocator.create(Node.PtrType);
27902787 child.* = .{
27912788 .op_token = double_asterisk,
2792 .op = .{ .PtrType = .{} },
27932789 .rhs = undefined, // set by caller
27942790 };
27952791 node.rhs = &child.base;
......@@ -2808,10 +2804,9 @@ const Parser = struct {
28082804 p.putBackToken(ident);
28092805 } else {
28102806 _ = try p.expectToken(.RBracket);
2811 const node = try p.arena.allocator.create(Node.PrefixOp);
2807 const node = try p.arena.allocator.create(Node.PtrType);
28122808 node.* = .{
28132809 .op_token = lbracket,
2814 .op = .{ .PtrType = .{} },
28152810 .rhs = undefined, // set by caller
28162811 };
28172812 return &node.base;
......@@ -2824,11 +2819,11 @@ const Parser = struct {
28242819 else
28252820 null;
28262821 _ = try p.expectToken(.RBracket);
2827 const node = try p.arena.allocator.create(Node.PrefixOp);
2822 const node = try p.arena.allocator.create(Node.PtrType);
28282823 node.* = .{
28292824 .op_token = lbracket,
2830 .op = .{ .PtrType = .{ .sentinel = sentinel } },
28312825 .rhs = undefined, // set by caller
2826 .ptr_info = .{ .sentinel = sentinel },
28322827 };
28332828 return &node.base;
28342829 }
......@@ -3146,10 +3141,9 @@ const Parser = struct {
31463141
31473142 fn parseTry(p: *Parser) !?*Node {
31483143 const token = p.eatToken(.Keyword_try) orelse return null;
3149 const node = try p.arena.allocator.create(Node.PrefixOp);
3144 const node = try p.arena.allocator.create(Node.Try);
31503145 node.* = .{
31513146 .op_token = token,
3152 .op = .Try,
31533147 .rhs = undefined, // set by caller
31543148 };
31553149 return &node.base;
......@@ -3228,15 +3222,87 @@ const Parser = struct {
32283222 var rightmost_op = first_op;
32293223 while (true) {
32303224 switch (rightmost_op.id) {
3231 .PrefixOp => {
3232 var prefix_op = rightmost_op.cast(Node.PrefixOp).?;
3225 .AddressOf => {
3226 if (try opParseFn(p)) |rhs| {
3227 rightmost_op.cast(Node.AddressOf).?.rhs = rhs;
3228 rightmost_op = rhs;
3229 } else break;
3230 },
3231 .Await => {
3232 if (try opParseFn(p)) |rhs| {
3233 rightmost_op.cast(Node.Await).?.rhs = rhs;
3234 rightmost_op = rhs;
3235 } else break;
3236 },
3237 .BitNot => {
3238 if (try opParseFn(p)) |rhs| {
3239 rightmost_op.cast(Node.BitNot).?.rhs = rhs;
3240 rightmost_op = rhs;
3241 } else break;
3242 },
3243 .BoolNot => {
3244 if (try opParseFn(p)) |rhs| {
3245 rightmost_op.cast(Node.BoolNot).?.rhs = rhs;
3246 rightmost_op = rhs;
3247 } else break;
3248 },
3249 .OptionalType => {
3250 if (try opParseFn(p)) |rhs| {
3251 rightmost_op.cast(Node.OptionalType).?.rhs = rhs;
3252 rightmost_op = rhs;
3253 } else break;
3254 },
3255 .Negation => {
3256 if (try opParseFn(p)) |rhs| {
3257 rightmost_op.cast(Node.Negation).?.rhs = rhs;
3258 rightmost_op = rhs;
3259 } else break;
3260 },
3261 .NegationWrap => {
3262 if (try opParseFn(p)) |rhs| {
3263 rightmost_op.cast(Node.NegationWrap).?.rhs = rhs;
3264 rightmost_op = rhs;
3265 } else break;
3266 },
3267 .Resume => {
3268 if (try opParseFn(p)) |rhs| {
3269 rightmost_op.cast(Node.Resume).?.rhs = rhs;
3270 rightmost_op = rhs;
3271 } else break;
3272 },
3273 .Try => {
3274 if (try opParseFn(p)) |rhs| {
3275 rightmost_op.cast(Node.Try).?.rhs = rhs;
3276 rightmost_op = rhs;
3277 } else break;
3278 },
3279 .ArrayType => {
3280 if (try opParseFn(p)) |rhs| {
3281 rightmost_op.cast(Node.ArrayType).?.rhs = rhs;
3282 rightmost_op = rhs;
3283 } else break;
3284 },
3285 .ArrayTypeSentinel => {
3286 if (try opParseFn(p)) |rhs| {
3287 rightmost_op.cast(Node.ArrayTypeSentinel).?.rhs = rhs;
3288 rightmost_op = rhs;
3289 } else break;
3290 },
3291 .SliceType => {
3292 if (try opParseFn(p)) |rhs| {
3293 rightmost_op.cast(Node.SliceType).?.rhs = rhs;
3294 rightmost_op = rhs;
3295 } else break;
3296 },
3297 .PtrType => {
3298 var ptr_type = rightmost_op.cast(Node.PtrType).?;
32333299 // If the token encountered was **, there will be two nodes
3234 if (p.token_ids[prefix_op.op_token] == .AsteriskAsterisk) {
3235 rightmost_op = prefix_op.rhs;
3236 prefix_op = rightmost_op.cast(Node.PrefixOp).?;
3300 if (p.token_ids[ptr_type.op_token] == .AsteriskAsterisk) {
3301 rightmost_op = ptr_type.rhs;
3302 ptr_type = rightmost_op.cast(Node.PtrType).?;
32373303 }
32383304 if (try opParseFn(p)) |rhs| {
3239 prefix_op.rhs = rhs;
3305 ptr_type.rhs = rhs;
32403306 rightmost_op = rhs;
32413307 } else break;
32423308 },
......@@ -3253,8 +3319,80 @@ const Parser = struct {
32533319
32543320 // If any prefix op existed, a child node on the RHS is required
32553321 switch (rightmost_op.id) {
3256 .PrefixOp => {
3257 const prefix_op = rightmost_op.cast(Node.PrefixOp).?;
3322 .AddressOf => {
3323 const prefix_op = rightmost_op.cast(Node.AddressOf).?;
3324 prefix_op.rhs = try p.expectNode(childParseFn, .{
3325 .InvalidToken = .{ .token = p.tok_i },
3326 });
3327 },
3328 .Await => {
3329 const prefix_op = rightmost_op.cast(Node.Await).?;
3330 prefix_op.rhs = try p.expectNode(childParseFn, .{
3331 .InvalidToken = .{ .token = p.tok_i },
3332 });
3333 },
3334 .BitNot => {
3335 const prefix_op = rightmost_op.cast(Node.BitNot).?;
3336 prefix_op.rhs = try p.expectNode(childParseFn, .{
3337 .InvalidToken = .{ .token = p.tok_i },
3338 });
3339 },
3340 .BoolNot => {
3341 const prefix_op = rightmost_op.cast(Node.BoolNot).?;
3342 prefix_op.rhs = try p.expectNode(childParseFn, .{
3343 .InvalidToken = .{ .token = p.tok_i },
3344 });
3345 },
3346 .OptionalType => {
3347 const prefix_op = rightmost_op.cast(Node.OptionalType).?;
3348 prefix_op.rhs = try p.expectNode(childParseFn, .{
3349 .InvalidToken = .{ .token = p.tok_i },
3350 });
3351 },
3352 .Negation => {
3353 const prefix_op = rightmost_op.cast(Node.Negation).?;
3354 prefix_op.rhs = try p.expectNode(childParseFn, .{
3355 .InvalidToken = .{ .token = p.tok_i },
3356 });
3357 },
3358 .NegationWrap => {
3359 const prefix_op = rightmost_op.cast(Node.NegationWrap).?;
3360 prefix_op.rhs = try p.expectNode(childParseFn, .{
3361 .InvalidToken = .{ .token = p.tok_i },
3362 });
3363 },
3364 .Resume => {
3365 const prefix_op = rightmost_op.cast(Node.Resume).?;
3366 prefix_op.rhs = try p.expectNode(childParseFn, .{
3367 .InvalidToken = .{ .token = p.tok_i },
3368 });
3369 },
3370 .Try => {
3371 const prefix_op = rightmost_op.cast(Node.Try).?;
3372 prefix_op.rhs = try p.expectNode(childParseFn, .{
3373 .InvalidToken = .{ .token = p.tok_i },
3374 });
3375 },
3376 .ArrayType => {
3377 const prefix_op = rightmost_op.cast(Node.ArrayType).?;
3378 prefix_op.rhs = try p.expectNode(childParseFn, .{
3379 .InvalidToken = .{ .token = p.tok_i },
3380 });
3381 },
3382 .ArrayTypeSentinel => {
3383 const prefix_op = rightmost_op.cast(Node.ArrayTypeSentinel).?;
3384 prefix_op.rhs = try p.expectNode(childParseFn, .{
3385 .InvalidToken = .{ .token = p.tok_i },
3386 });
3387 },
3388 .PtrType => {
3389 const prefix_op = rightmost_op.cast(Node.PtrType).?;
3390 prefix_op.rhs = try p.expectNode(childParseFn, .{
3391 .InvalidToken = .{ .token = p.tok_i },
3392 });
3393 },
3394 .SliceType => {
3395 const prefix_op = rightmost_op.cast(Node.SliceType).?;
32583396 prefix_op.rhs = try p.expectNode(childParseFn, .{
32593397 .InvalidToken = .{ .token = p.tok_i },
32603398 });
lib/std/zig/render.zig+211-145
......@@ -468,166 +468,192 @@ fn renderExpression(
468468 return renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.rhs, space);
469469 },
470470
471 .PrefixOp => {
472 const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);
473
474 switch (prefix_op_node.op) {
475 .PtrType => |ptr_info| {
476 const op_tok_id = tree.token_ids[prefix_op_node.op_token];
477 switch (op_tok_id) {
478 .Asterisk, .AsteriskAsterisk => try stream.writeByte('*'),
479 .LBracket => if (tree.token_ids[prefix_op_node.op_token + 2] == .Identifier)
480 try stream.writeAll("[*c")
481 else
482 try stream.writeAll("[*"),
483 else => unreachable,
484 }
485 if (ptr_info.sentinel) |sentinel| {
486 const colon_token = tree.prevToken(sentinel.firstToken());
487 try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :
488 const sentinel_space = switch (op_tok_id) {
489 .LBracket => Space.None,
490 else => Space.Space,
491 };
492 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, sentinel_space);
493 }
494 switch (op_tok_id) {
495 .Asterisk, .AsteriskAsterisk => {},
496 .LBracket => try stream.writeByte(']'),
497 else => unreachable,
498 }
499 if (ptr_info.allowzero_token) |allowzero_token| {
500 try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero
501 }
502 if (ptr_info.align_info) |align_info| {
503 const lparen_token = tree.prevToken(align_info.node.firstToken());
504 const align_token = tree.prevToken(lparen_token);
505
506 try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align
507 try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (
508
509 try renderExpression(allocator, stream, tree, indent, start_col, align_info.node, Space.None);
510
511 if (align_info.bit_range) |bit_range| {
512 const colon1 = tree.prevToken(bit_range.start.firstToken());
513 const colon2 = tree.prevToken(bit_range.end.firstToken());
471 .BitNot => {
472 const bit_not = @fieldParentPtr(ast.Node.BitNot, "base", base);
473 try renderToken(tree, stream, bit_not.op_token, indent, start_col, Space.None);
474 return renderExpression(allocator, stream, tree, indent, start_col, bit_not.rhs, space);
475 },
476 .BoolNot => {
477 const bool_not = @fieldParentPtr(ast.Node.BoolNot, "base", base);
478 try renderToken(tree, stream, bool_not.op_token, indent, start_col, Space.None);
479 return renderExpression(allocator, stream, tree, indent, start_col, bool_not.rhs, space);
480 },
481 .Negation => {
482 const negation = @fieldParentPtr(ast.Node.Negation, "base", base);
483 try renderToken(tree, stream, negation.op_token, indent, start_col, Space.None);
484 return renderExpression(allocator, stream, tree, indent, start_col, negation.rhs, space);
485 },
486 .NegationWrap => {
487 const negation_wrap = @fieldParentPtr(ast.Node.NegationWrap, "base", base);
488 try renderToken(tree, stream, negation_wrap.op_token, indent, start_col, Space.None);
489 return renderExpression(allocator, stream, tree, indent, start_col, negation_wrap.rhs, space);
490 },
491 .OptionalType => {
492 const opt_type = @fieldParentPtr(ast.Node.OptionalType, "base", base);
493 try renderToken(tree, stream, opt_type.op_token, indent, start_col, Space.None);
494 return renderExpression(allocator, stream, tree, indent, start_col, opt_type.rhs, space);
495 },
496 .AddressOf => {
497 const addr_of = @fieldParentPtr(ast.Node.AddressOf, "base", base);
498 try renderToken(tree, stream, addr_of.op_token, indent, start_col, Space.None);
499 return renderExpression(allocator, stream, tree, indent, start_col, addr_of.rhs, space);
500 },
501 .Try => {
502 const try_node = @fieldParentPtr(ast.Node.Try, "base", base);
503 try renderToken(tree, stream, try_node.op_token, indent, start_col, Space.Space);
504 return renderExpression(allocator, stream, tree, indent, start_col, try_node.rhs, space);
505 },
506 .Resume => {
507 const resume_node = @fieldParentPtr(ast.Node.Resume, "base", base);
508 try renderToken(tree, stream, resume_node.op_token, indent, start_col, Space.Space);
509 return renderExpression(allocator, stream, tree, indent, start_col, resume_node.rhs, space);
510 },
511 .Await => {
512 const await_node = @fieldParentPtr(ast.Node.Await, "base", base);
513 try renderToken(tree, stream, await_node.op_token, indent, start_col, Space.Space);
514 return renderExpression(allocator, stream, tree, indent, start_col, await_node.rhs, space);
515 },
514516
515 try renderToken(tree, stream, colon1, indent, start_col, Space.None); // :
516 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.start, Space.None);
517 try renderToken(tree, stream, colon2, indent, start_col, Space.None); // :
518 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.end, Space.None);
517 .ArrayType => {
518 const array_type = @fieldParentPtr(ast.Node.ArrayType, "base", base);
519 return renderArrayType(
520 allocator,
521 stream,
522 tree,
523 indent,
524 start_col,
525 array_type.op_token,
526 array_type.rhs,
527 array_type.len_expr,
528 null,
529 space,
530 );
531 },
532 .ArrayTypeSentinel => {
533 const array_type = @fieldParentPtr(ast.Node.ArrayTypeSentinel, "base", base);
534 return renderArrayType(
535 allocator,
536 stream,
537 tree,
538 indent,
539 start_col,
540 array_type.op_token,
541 array_type.rhs,
542 array_type.len_expr,
543 array_type.sentinel,
544 space,
545 );
546 },
519547
520 const rparen_token = tree.nextToken(bit_range.end.lastToken());
521 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
522 } else {
523 const rparen_token = tree.nextToken(align_info.node.lastToken());
524 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
525 }
526 }
527 if (ptr_info.const_token) |const_token| {
528 try renderToken(tree, stream, const_token, indent, start_col, Space.Space); // const
529 }
530 if (ptr_info.volatile_token) |volatile_token| {
531 try renderToken(tree, stream, volatile_token, indent, start_col, Space.Space); // volatile
532 }
533 },
548 .PtrType => {
549 const ptr_type = @fieldParentPtr(ast.Node.PtrType, "base", base);
550 const op_tok_id = tree.token_ids[ptr_type.op_token];
551 switch (op_tok_id) {
552 .Asterisk, .AsteriskAsterisk => try stream.writeByte('*'),
553 .LBracket => if (tree.token_ids[ptr_type.op_token + 2] == .Identifier)
554 try stream.writeAll("[*c")
555 else
556 try stream.writeAll("[*"),
557 else => unreachable,
558 }
559 if (ptr_type.ptr_info.sentinel) |sentinel| {
560 const colon_token = tree.prevToken(sentinel.firstToken());
561 try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :
562 const sentinel_space = switch (op_tok_id) {
563 .LBracket => Space.None,
564 else => Space.Space,
565 };
566 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, sentinel_space);
567 }
568 switch (op_tok_id) {
569 .Asterisk, .AsteriskAsterisk => {},
570 .LBracket => try stream.writeByte(']'),
571 else => unreachable,
572 }
573 if (ptr_type.ptr_info.allowzero_token) |allowzero_token| {
574 try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero
575 }
576 if (ptr_type.ptr_info.align_info) |align_info| {
577 const lparen_token = tree.prevToken(align_info.node.firstToken());
578 const align_token = tree.prevToken(lparen_token);
534579
535 .SliceType => |ptr_info| {
536 try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None); // [
537 if (ptr_info.sentinel) |sentinel| {
538 const colon_token = tree.prevToken(sentinel.firstToken());
539 try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :
540 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);
541 try renderToken(tree, stream, tree.nextToken(sentinel.lastToken()), indent, start_col, Space.None); // ]
542 } else {
543 try renderToken(tree, stream, tree.nextToken(prefix_op_node.op_token), indent, start_col, Space.None); // ]
544 }
580 try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align
581 try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (
545582
546 if (ptr_info.allowzero_token) |allowzero_token| {
547 try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero
548 }
549 if (ptr_info.align_info) |align_info| {
550 const lparen_token = tree.prevToken(align_info.node.firstToken());
551 const align_token = tree.prevToken(lparen_token);
583 try renderExpression(allocator, stream, tree, indent, start_col, align_info.node, Space.None);
552584
553 try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align
554 try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (
585 if (align_info.bit_range) |bit_range| {
586 const colon1 = tree.prevToken(bit_range.start.firstToken());
587 const colon2 = tree.prevToken(bit_range.end.firstToken());
555588
556 try renderExpression(allocator, stream, tree, indent, start_col, align_info.node, Space.None);
589 try renderToken(tree, stream, colon1, indent, start_col, Space.None); // :
590 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.start, Space.None);
591 try renderToken(tree, stream, colon2, indent, start_col, Space.None); // :
592 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.end, Space.None);
557593
558 if (align_info.bit_range) |bit_range| {
559 const colon1 = tree.prevToken(bit_range.start.firstToken());
560 const colon2 = tree.prevToken(bit_range.end.firstToken());
594 const rparen_token = tree.nextToken(bit_range.end.lastToken());
595 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
596 } else {
597 const rparen_token = tree.nextToken(align_info.node.lastToken());
598 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
599 }
600 }
601 if (ptr_type.ptr_info.const_token) |const_token| {
602 try renderToken(tree, stream, const_token, indent, start_col, Space.Space); // const
603 }
604 if (ptr_type.ptr_info.volatile_token) |volatile_token| {
605 try renderToken(tree, stream, volatile_token, indent, start_col, Space.Space); // volatile
606 }
607 return renderExpression(allocator, stream, tree, indent, start_col, ptr_type.rhs, space);
608 },
561609
562 try renderToken(tree, stream, colon1, indent, start_col, Space.None); // :
563 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.start, Space.None);
564 try renderToken(tree, stream, colon2, indent, start_col, Space.None); // :
565 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.end, Space.None);
610 .SliceType => {
611 const slice_type = @fieldParentPtr(ast.Node.SliceType, "base", base);
612 try renderToken(tree, stream, slice_type.op_token, indent, start_col, Space.None); // [
613 if (slice_type.ptr_info.sentinel) |sentinel| {
614 const colon_token = tree.prevToken(sentinel.firstToken());
615 try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :
616 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);
617 try renderToken(tree, stream, tree.nextToken(sentinel.lastToken()), indent, start_col, Space.None); // ]
618 } else {
619 try renderToken(tree, stream, tree.nextToken(slice_type.op_token), indent, start_col, Space.None); // ]
620 }
566621
567 const rparen_token = tree.nextToken(bit_range.end.lastToken());
568 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
569 } else {
570 const rparen_token = tree.nextToken(align_info.node.lastToken());
571 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
572 }
573 }
574 if (ptr_info.const_token) |const_token| {
575 try renderToken(tree, stream, const_token, indent, start_col, Space.Space);
576 }
577 if (ptr_info.volatile_token) |volatile_token| {
578 try renderToken(tree, stream, volatile_token, indent, start_col, Space.Space);
579 }
580 },
622 if (slice_type.ptr_info.allowzero_token) |allowzero_token| {
623 try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero
624 }
625 if (slice_type.ptr_info.align_info) |align_info| {
626 const lparen_token = tree.prevToken(align_info.node.firstToken());
627 const align_token = tree.prevToken(lparen_token);
581628
582 .ArrayType => |array_info| {
583 const lbracket = prefix_op_node.op_token;
584 const rbracket = tree.nextToken(if (array_info.sentinel) |sentinel|
585 sentinel.lastToken()
586 else
587 array_info.len_expr.lastToken());
629 try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align
630 try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (
588631
589 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
632 try renderExpression(allocator, stream, tree, indent, start_col, align_info.node, Space.None);
590633
591 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
592 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;
593 const new_indent = if (ends_with_comment) indent + indent_delta else indent;
594 const new_space = if (ends_with_comment) Space.Newline else Space.None;
595 try renderExpression(allocator, stream, tree, new_indent, start_col, array_info.len_expr, new_space);
596 if (starts_with_comment) {
597 try stream.writeByte('\n');
598 }
599 if (ends_with_comment or starts_with_comment) {
600 try stream.writeByteNTimes(' ', indent);
601 }
602 if (array_info.sentinel) |sentinel| {
603 const colon_token = tree.prevToken(sentinel.firstToken());
604 try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :
605 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);
606 }
607 try renderToken(tree, stream, rbracket, indent, start_col, Space.None); // ]
608 },
609 .BitNot,
610 .BoolNot,
611 .Negation,
612 .NegationWrap,
613 .OptionalType,
614 .AddressOf,
615 => {
616 try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None);
617 },
634 if (align_info.bit_range) |bit_range| {
635 const colon1 = tree.prevToken(bit_range.start.firstToken());
636 const colon2 = tree.prevToken(bit_range.end.firstToken());
618637
619 .Try,
620 .Resume,
621 => {
622 try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.Space);
623 },
638 try renderToken(tree, stream, colon1, indent, start_col, Space.None); // :
639 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.start, Space.None);
640 try renderToken(tree, stream, colon2, indent, start_col, Space.None); // :
641 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.end, Space.None);
624642
625 .Await => |await_info| {
626 try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.Space);
627 },
643 const rparen_token = tree.nextToken(bit_range.end.lastToken());
644 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
645 } else {
646 const rparen_token = tree.nextToken(align_info.node.lastToken());
647 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
648 }
628649 }
629
630 return renderExpression(allocator, stream, tree, indent, start_col, prefix_op_node.rhs, space);
650 if (slice_type.ptr_info.const_token) |const_token| {
651 try renderToken(tree, stream, const_token, indent, start_col, Space.Space);
652 }
653 if (slice_type.ptr_info.volatile_token) |volatile_token| {
654 try renderToken(tree, stream, volatile_token, indent, start_col, Space.Space);
655 }
656 return renderExpression(allocator, stream, tree, indent, start_col, slice_type.rhs, space);
631657 },
632658
633659 .ArrayInitializer, .ArrayInitializerDot => {
......@@ -2057,6 +2083,46 @@ fn renderExpression(
20572083 }
20582084}
20592085
2086fn renderArrayType(
2087 allocator: *mem.Allocator,
2088 stream: anytype,
2089 tree: *ast.Tree,
2090 indent: usize,
2091 start_col: *usize,
2092 lbracket: ast.TokenIndex,
2093 rhs: *ast.Node,
2094 len_expr: *ast.Node,
2095 opt_sentinel: ?*ast.Node,
2096 space: Space,
2097) (@TypeOf(stream).Error || Error)!void {
2098 const rbracket = tree.nextToken(if (opt_sentinel) |sentinel|
2099 sentinel.lastToken()
2100 else
2101 len_expr.lastToken());
2102
2103 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
2104
2105 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
2106 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;
2107 const new_indent = if (ends_with_comment) indent + indent_delta else indent;
2108 const new_space = if (ends_with_comment) Space.Newline else Space.None;
2109 try renderExpression(allocator, stream, tree, new_indent, start_col, len_expr, new_space);
2110 if (starts_with_comment) {
2111 try stream.writeByte('\n');
2112 }
2113 if (ends_with_comment or starts_with_comment) {
2114 try stream.writeByteNTimes(' ', indent);
2115 }
2116 if (opt_sentinel) |sentinel| {
2117 const colon_token = tree.prevToken(sentinel.firstToken());
2118 try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :
2119 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);
2120 }
2121 try renderToken(tree, stream, rbracket, indent, start_col, Space.None); // ]
2122
2123 return renderExpression(allocator, stream, tree, indent, start_col, rhs, space);
2124}
2125
20602126fn renderAsmOutput(
20612127 allocator: *mem.Allocator,
20622128 stream: anytype,
src-self-hosted/Module.zig+8
......@@ -1308,10 +1308,18 @@ fn astGenExpr(self: *Module, scope: *Scope, ast_node: *ast.Node) InnerError!*zir
13081308 .ControlFlowExpression => return self.astGenControlFlowExpression(scope, @fieldParentPtr(ast.Node.ControlFlowExpression, "base", ast_node)),
13091309 .If => return self.astGenIf(scope, @fieldParentPtr(ast.Node.If, "base", ast_node)),
13101310 .InfixOp => return self.astGenInfixOp(scope, @fieldParentPtr(ast.Node.InfixOp, "base", ast_node)),
1311 .BoolNot => return self.astGenBoolNot(scope, @fieldParentPtr(ast.Node.BoolNot, "base", ast_node)),
13111312 else => return self.failNode(scope, ast_node, "TODO implement astGenExpr for {}", .{@tagName(ast_node.id)}),
13121313 }
13131314}
13141315
1316fn astGenBoolNot(self: *Module, scope: *Scope, node: *ast.Node.BoolNot) InnerError!*zir.Inst {
1317 const operand = try self.astGenExpr(scope, node.rhs);
1318 const tree = scope.tree();
1319 const src = tree.token_locs[node.op_token].start;
1320 return self.addZIRInst(scope, src, zir.Inst.BoolNot, .{ .operand = operand }, .{});
1321}
1322
13151323fn astGenInfixOp(self: *Module, scope: *Scope, infix_node: *ast.Node.InfixOp) InnerError!*zir.Inst {
13161324 switch (infix_node.op) {
13171325 .Assign => {
src-self-hosted/translate_c.zig+80-87
......@@ -1561,7 +1561,7 @@ fn transImplicitCastExpr(
15611561 return maybeSuppressResult(rp, scope, result_used, sub_expr_node);
15621562 }
15631563
1564 const prefix_op = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
1564 const prefix_op = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
15651565 prefix_op.rhs = try transExpr(rp, scope, sub_expr, .used, .r_value);
15661566
15671567 return maybeSuppressResult(rp, scope, result_used, &prefix_op.base);
......@@ -1673,11 +1673,7 @@ fn isBoolRes(res: *ast.Node) bool {
16731673
16741674 else => {},
16751675 },
1676 .PrefixOp => switch (@fieldParentPtr(ast.Node.PrefixOp, "base", res).op) {
1677 .BoolNot => return true,
1678
1679 else => {},
1680 },
1676 .BoolNot => return true,
16811677 .BoolLiteral => return true,
16821678 .GroupedExpression => return isBoolRes(@fieldParentPtr(ast.Node.GroupedExpression, "base", res).expr),
16831679 else => {},
......@@ -2162,21 +2158,16 @@ fn transCreateNodeArrayType(
21622158 source_loc: ZigClangSourceLocation,
21632159 ty: *const ZigClangType,
21642160 len: anytype,
2165) TransError!*ast.Node {
2166 var node = try transCreateNodePrefixOp(
2167 rp.c,
2168 .{
2169 .ArrayType = .{
2170 .len_expr = undefined,
2171 .sentinel = null,
2172 },
2173 },
2174 .LBracket,
2175 "[",
2176 );
2177 node.op.ArrayType.len_expr = try transCreateNodeInt(rp.c, len);
2161) !*ast.Node {
2162 const node = try rp.c.arena.create(ast.Node.ArrayType);
2163 const op_token = try appendToken(rp.c, .LBracket, "[");
2164 const len_expr = try transCreateNodeInt(rp.c, len);
21782165 _ = try appendToken(rp.c, .RBracket, "]");
2179 node.rhs = try transType(rp, ty, source_loc);
2166 node.* = .{
2167 .op_token = op_token,
2168 .rhs = try transType(rp, ty, source_loc),
2169 .len_expr = len_expr,
2170 };
21802171 return &node.base;
21812172}
21822173
......@@ -2449,7 +2440,7 @@ fn transDoWhileLoop(
24492440 },
24502441 };
24512442 defer cond_scope.deinit();
2452 const prefix_op = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");
2443 const prefix_op = try transCreateNodeSimplePrefixOp(rp.c, .BoolNot, .Bang, "!");
24532444 prefix_op.rhs = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true);
24542445 _ = try appendToken(rp.c, .RParen, ")");
24552446 if_node.condition = &prefix_op.base;
......@@ -3036,7 +3027,7 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar
30363027 else
30373028 return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
30383029 .AddrOf => {
3039 const op_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
3030 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
30403031 op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value);
30413032 return &op_node.base;
30423033 },
......@@ -3052,7 +3043,7 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar
30523043 .Plus => return transExpr(rp, scope, op_expr, used, .r_value),
30533044 .Minus => {
30543045 if (!qualTypeHasWrappingOverflow(ZigClangExpr_getType(op_expr))) {
3055 const op_node = try transCreateNodePrefixOp(rp.c, .Negation, .Minus, "-");
3046 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .Negation, .Minus, "-");
30563047 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
30573048 return &op_node.base;
30583049 } else if (cIsUnsignedInteger(ZigClangExpr_getType(op_expr))) {
......@@ -3065,12 +3056,12 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar
30653056 return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangUnaryOperator_getBeginLoc(stmt), "C negation with non float non integer", .{});
30663057 },
30673058 .Not => {
3068 const op_node = try transCreateNodePrefixOp(rp.c, .BitNot, .Tilde, "~");
3059 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .BitNot, .Tilde, "~");
30693060 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
30703061 return &op_node.base;
30713062 },
30723063 .LNot => {
3073 const op_node = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");
3064 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .BoolNot, .Bang, "!");
30743065 op_node.rhs = try transBoolExpr(rp, scope, op_expr, .used, .r_value, true);
30753066 return &op_node.base;
30763067 },
......@@ -3116,7 +3107,7 @@ fn transCreatePreCrement(
31163107
31173108 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
31183109 node.eq_token = try appendToken(rp.c, .Equal, "=");
3119 const rhs_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
3110 const rhs_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
31203111 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
31213112 node.init_node = &rhs_node.base;
31223113 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
......@@ -3182,7 +3173,7 @@ fn transCreatePostCrement(
31823173
31833174 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
31843175 node.eq_token = try appendToken(rp.c, .Equal, "=");
3185 const rhs_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
3176 const rhs_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
31863177 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
31873178 node.init_node = &rhs_node.base;
31883179 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
......@@ -3336,7 +3327,7 @@ fn transCreateCompoundAssign(
33363327
33373328 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
33383329 node.eq_token = try appendToken(rp.c, .Equal, "=");
3339 const addr_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
3330 const addr_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
33403331 addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value);
33413332 node.init_node = &addr_node.base;
33423333 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
......@@ -3984,16 +3975,15 @@ fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []c
39843975 return &field_access_node.base;
39853976}
39863977
3987fn transCreateNodePrefixOp(
3978fn transCreateNodeSimplePrefixOp(
39883979 c: *Context,
3989 op: ast.Node.PrefixOp.Op,
3980 comptime tag: ast.Node.Id,
39903981 op_tok_id: std.zig.Token.Id,
39913982 bytes: []const u8,
3992) !*ast.Node.PrefixOp {
3993 const node = try c.arena.create(ast.Node.PrefixOp);
3983) !*ast.Node.SimplePrefixOp(tag) {
3984 const node = try c.arena.create(ast.Node.SimplePrefixOp(tag));
39943985 node.* = .{
39953986 .op_token = try appendToken(c, op_tok_id, bytes),
3996 .op = op,
39973987 .rhs = undefined, // translate and set afterward
39983988 };
39993989 return node;
......@@ -4065,8 +4055,8 @@ fn transCreateNodePtrType(
40654055 is_const: bool,
40664056 is_volatile: bool,
40674057 op_tok_id: std.zig.Token.Id,
4068) !*ast.Node.PrefixOp {
4069 const node = try c.arena.create(ast.Node.PrefixOp);
4058) !*ast.Node.PtrType {
4059 const node = try c.arena.create(ast.Node.PtrType);
40704060 const op_token = switch (op_tok_id) {
40714061 .LBracket => blk: {
40724062 const lbracket = try appendToken(c, .LBracket, "[");
......@@ -4086,11 +4076,9 @@ fn transCreateNodePtrType(
40864076 };
40874077 node.* = .{
40884078 .op_token = op_token,
4089 .op = .{
4090 .PtrType = .{
4091 .const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null,
4092 .volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null,
4093 },
4079 .ptr_info = .{
4080 .const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null,
4081 .volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null,
40944082 },
40954083 .rhs = undefined, // translate and set afterward
40964084 };
......@@ -4569,12 +4557,12 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
45694557 .Pointer => {
45704558 const child_qt = ZigClangType_getPointeeType(ty);
45714559 if (qualTypeChildIsFnProto(child_qt)) {
4572 const optional_node = try transCreateNodePrefixOp(rp.c, .OptionalType, .QuestionMark, "?");
4560 const optional_node = try transCreateNodeSimplePrefixOp(rp.c, .OptionalType, .QuestionMark, "?");
45734561 optional_node.rhs = try transQualType(rp, child_qt, source_loc);
45744562 return &optional_node.base;
45754563 }
45764564 if (typeIsOpaque(rp.c, ZigClangQualType_getTypePtr(child_qt), source_loc)) {
4577 const optional_node = try transCreateNodePrefixOp(rp.c, .OptionalType, .QuestionMark, "?");
4565 const optional_node = try transCreateNodeSimplePrefixOp(rp.c, .OptionalType, .QuestionMark, "?");
45784566 const pointer_node = try transCreateNodePtrType(
45794567 rp.c,
45804568 ZigClangQualType_isConstQualified(child_qt),
......@@ -4599,21 +4587,8 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
45994587
46004588 const size_ap_int = ZigClangConstantArrayType_getSize(const_arr_ty);
46014589 const size = ZigClangAPInt_getLimitedValue(size_ap_int, math.maxInt(usize));
4602 var node = try transCreateNodePrefixOp(
4603 rp.c,
4604 .{
4605 .ArrayType = .{
4606 .len_expr = undefined,
4607 .sentinel = null,
4608 },
4609 },
4610 .LBracket,
4611 "[",
4612 );
4613 node.op.ArrayType.len_expr = try transCreateNodeInt(rp.c, size);
4614 _ = try appendToken(rp.c, .RBracket, "]");
4615 node.rhs = try transQualType(rp, ZigClangConstantArrayType_getElementType(const_arr_ty), source_loc);
4616 return &node.base;
4590 const elem_ty = ZigClangQualType_getTypePtr(ZigClangConstantArrayType_getElementType(const_arr_ty));
4591 return try transCreateNodeArrayType(rp, source_loc, elem_ty, size);
46174592 },
46184593 .IncompleteArray => {
46194594 const incomplete_array_ty = @ptrCast(*const ZigClangIncompleteArrayType, ty);
......@@ -5824,7 +5799,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
58245799 if (prev_id == .Keyword_void) {
58255800 const ptr = try transCreateNodePtrType(c, false, false, .Asterisk);
58265801 ptr.rhs = node;
5827 const optional_node = try transCreateNodePrefixOp(c, .OptionalType, .QuestionMark, "?");
5802 const optional_node = try transCreateNodeSimplePrefixOp(c, .OptionalType, .QuestionMark, "?");
58285803 optional_node.rhs = &ptr.base;
58295804 return &optional_node.base;
58305805 } else {
......@@ -5993,18 +5968,18 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
59935968
59945969 switch (op_tok.id) {
59955970 .Bang => {
5996 const node = try transCreateNodePrefixOp(c, .BoolNot, .Bang, "!");
5971 const node = try transCreateNodeSimplePrefixOp(c, .BoolNot, .Bang, "!");
59975972 node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
59985973 return &node.base;
59995974 },
60005975 .Minus => {
6001 const node = try transCreateNodePrefixOp(c, .Negation, .Minus, "-");
5976 const node = try transCreateNodeSimplePrefixOp(c, .Negation, .Minus, "-");
60025977 node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
60035978 return &node.base;
60045979 },
60055980 .Plus => return try parseCPrefixOpExpr(c, it, source, source_loc, scope),
60065981 .Tilde => {
6007 const node = try transCreateNodePrefixOp(c, .BitNot, .Tilde, "~");
5982 const node = try transCreateNodeSimplePrefixOp(c, .BitNot, .Tilde, "~");
60085983 node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
60095984 return &node.base;
60105985 },
......@@ -6013,7 +5988,7 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
60135988 return try transCreateNodePtrDeref(c, node);
60145989 },
60155990 .Ampersand => {
6016 const node = try transCreateNodePrefixOp(c, .AddressOf, .Ampersand, "&");
5991 const node = try transCreateNodeSimplePrefixOp(c, .AddressOf, .Ampersand, "&");
60175992 node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
60185993 return &node.base;
60195994 },
......@@ -6034,29 +6009,49 @@ fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 {
60346009}
60356010
60366011fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
6037 if (node.id == .ContainerDecl) {
6038 return node;
6039 } else if (node.id == .PrefixOp) {
6040 return node;
6041 } else if (node.cast(ast.Node.Identifier)) |ident| {
6042 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
6043 if (value.cast(ast.Node.VarDecl)) |var_decl|
6044 return getContainer(c, var_decl.init_node.?);
6045 }
6046 } else if (node.cast(ast.Node.InfixOp)) |infix| {
6047 if (infix.op != .Period)
6048 return null;
6049 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {
6050 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
6051 for (container.fieldsAndDecls()) |field_ref| {
6052 const field = field_ref.cast(ast.Node.ContainerField).?;
6053 const ident = infix.rhs.cast(ast.Node.Identifier).?;
6054 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
6055 return getContainer(c, field.type_expr.?);
6012 switch (node.id) {
6013 .ContainerDecl,
6014 .AddressOf,
6015 .Await,
6016 .BitNot,
6017 .BoolNot,
6018 .OptionalType,
6019 .Negation,
6020 .NegationWrap,
6021 .Resume,
6022 .Try,
6023 .ArrayType,
6024 .ArrayTypeSentinel,
6025 .PtrType,
6026 .SliceType,
6027 => return node,
6028
6029 .Identifier => {
6030 const ident = node.cast(ast.Node.Identifier).?;
6031 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
6032 if (value.cast(ast.Node.VarDecl)) |var_decl|
6033 return getContainer(c, var_decl.init_node.?);
6034 }
6035 },
6036
6037 .InfixOp => {
6038 const infix = node.cast(ast.Node.InfixOp).?;
6039 if (infix.op != .Period)
6040 return null;
6041 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {
6042 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
6043 for (container.fieldsAndDecls()) |field_ref| {
6044 const field = field_ref.cast(ast.Node.ContainerField).?;
6045 const ident = infix.rhs.cast(ast.Node.Identifier).?;
6046 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
6047 return getContainer(c, field.type_expr.?);
6048 }
60566049 }
60576050 }
60586051 }
6059 }
6052 },
6053
6054 else => {},
60606055 }
60616056 return null;
60626057}
......@@ -6091,11 +6086,9 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
60916086fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto {
60926087 const init = if (ref.cast(ast.Node.VarDecl)) |v| v.init_node.? else return null;
60936088 if (getContainerTypeOf(c, init)) |ty_node| {
6094 if (ty_node.cast(ast.Node.PrefixOp)) |prefix| {
6095 if (prefix.op == .OptionalType) {
6096 if (prefix.rhs.cast(ast.Node.FnProto)) |fn_proto| {
6097 return fn_proto;
6098 }
6089 if (ty_node.cast(ast.Node.OptionalType)) |prefix| {
6090 if (prefix.rhs.cast(ast.Node.FnProto)) |fn_proto| {
6091 return fn_proto;
60996092 }
61006093 }
61016094 }