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 {...@@ -410,7 +410,20 @@ pub const Node = struct {
410410
411 // Operators411 // Operators
412 InfixOp,412 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,
414 /// Not all suffix operations are under this tag. To save memory, some427 /// Not all suffix operations are under this tag. To save memory, some
415 /// suffix operations have dedicated Node tags.428 /// suffix operations have dedicated Node tags.
416 SuffixOp,429 SuffixOp,
...@@ -1797,85 +1810,116 @@ pub const Node = struct {...@@ -1797,85 +1810,116 @@ pub const Node = struct {
1797 }1810 }
1798 };1811 };
17991812
1800 pub const PrefixOp = struct {1813 pub const AddressOf = SimplePrefixOp(.AddressOf);
1801 base: Node = Node{ .id = .PrefixOp },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 },
1802 op_token: TokenIndex,1848 op_token: TokenIndex,
1803 op: Op,
1804 rhs: *Node,1849 rhs: *Node,
1850 len_expr: *Node,
18051851
1806 pub const Op = union(enum) {1852 pub fn iterate(self: *const ArrayType, index: usize) ?*Node {
1807 AddressOf,1853 var i = index;
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 };
18201854
1821 pub const ArrayInfo = struct {1855 if (i < 1) return self.len_expr;
1822 len_expr: *Node,1856 i -= 1;
1823 sentinel: ?*Node,
1824 };
18251857
1826 pub const PtrInfo = struct {1858 if (i < 1) return self.rhs;
1827 allowzero_token: ?TokenIndex = null,1859 i -= 1;
1828 align_info: ?Align = null,1860
1829 const_token: ?TokenIndex = null,1861 return null;
1830 volatile_token: ?TokenIndex = null,1862 }
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 };
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 {
1845 var i = index;1881 var i = index;
18461882
1847 switch (self.op) {1883 if (i < 1) return self.len_expr;
1848 .PtrType, .SliceType => |addr_of_info| {1884 i -= 1;
1849 if (addr_of_info.sentinel) |sentinel| {
1850 if (i < 1) return sentinel;
1851 i -= 1;
1852 }
18531885
1854 if (addr_of_info.align_info) |align_info| {1886 if (i < 1) return self.sentinel;
1855 if (i < 1) return align_info.node;1887 i -= 1;
1856 i -= 1;
1857 }
1858 },
18591888
1860 .ArrayType => |array_info| {1889 if (i < 1) return self.rhs;
1861 if (i < 1) return array_info.len_expr;1890 i -= 1;
1862 i -= 1;
1863 if (array_info.sentinel) |sentinel| {
1864 if (i < 1) return sentinel;
1865 i -= 1;
1866 }
1867 },
18681891
1869 .AddressOf,1892 return null;
1870 .Await,1893 }
1871 .BitNot,1894
1872 .BoolNot,1895 pub fn firstToken(self: *const ArrayTypeSentinel) TokenIndex {
1873 .OptionalType,1896 return self.op_token;
1874 .Negation,1897 }
1875 .NegationWrap,1898
1876 .Try,1899 pub fn lastToken(self: *const ArrayTypeSentinel) TokenIndex {
1877 .Resume,1900 return self.rhs.lastToken();
1878 => {},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;
1879 }1923 }
18801924
1881 if (i < 1) return self.rhs;1925 if (i < 1) return self.rhs;
...@@ -1884,11 +1928,47 @@ pub const Node = struct {...@@ -1884,11 +1928,47 @@ pub const Node = struct {
1884 return null;1928 return null;
1885 }1929 }
18861930
1887 pub fn firstToken(self: *const PrefixOp) TokenIndex {1931 pub fn firstToken(self: *const PtrType) TokenIndex {
1888 return self.op_token;1932 return self.op_token;
1889 }1933 }
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 {
1892 return self.rhs.lastToken();1972 return self.rhs.lastToken();
1893 }1973 }
1894 };1974 };
...@@ -2797,6 +2877,24 @@ pub const Node = struct {...@@ -2797,6 +2877,24 @@ pub const Node = struct {
2797 };2877 };
2798};2878};
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
2800test "iterate" {2898test "iterate" {
2801 var root = Node.Root{2899 var root = Node.Root{
2802 .base = Node{ .id = Node.Id.Root },2900 .base = Node{ .id = Node.Id.Root },
lib/std/zig/parse.zig+243-105
...@@ -1120,10 +1120,9 @@ const Parser = struct {...@@ -1120,10 +1120,9 @@ const Parser = struct {
1120 const expr_node = try p.expectNode(parseExpr, .{1120 const expr_node = try p.expectNode(parseExpr, .{
1121 .ExpectedExpr = .{ .token = p.tok_i },1121 .ExpectedExpr = .{ .token = p.tok_i },
1122 });1122 });
1123 const node = try p.arena.allocator.create(Node.PrefixOp);1123 const node = try p.arena.allocator.create(Node.Resume);
1124 node.* = .{1124 node.* = .{
1125 .op_token = token,1125 .op_token = token,
1126 .op = .Resume,
1127 .rhs = expr_node,1126 .rhs = expr_node,
1128 };1127 };
1129 return &node.base;1128 return &node.base;
...@@ -2413,24 +2412,25 @@ const Parser = struct {...@@ -2413,24 +2412,25 @@ const Parser = struct {
2413 /// / KEYWORD_await2412 /// / KEYWORD_await
2414 fn parsePrefixOp(p: *Parser) !?*Node {2413 fn parsePrefixOp(p: *Parser) !?*Node {
2415 const token = p.nextToken();2414 const token = p.nextToken();
2416 const op: Node.PrefixOp.Op = switch (p.token_ids[token]) {2415 switch (p.token_ids[token]) {
2417 .Bang => .BoolNot,2416 .Bang => return p.allocSimplePrefixOp(.BoolNot, token),
2418 .Minus => .Negation,2417 .Minus => return p.allocSimplePrefixOp(.Negation, token),
2419 .Tilde => .BitNot,2418 .Tilde => return p.allocSimplePrefixOp(.BitNot, token),
2420 .MinusPercent => .NegationWrap,2419 .MinusPercent => return p.allocSimplePrefixOp(.NegationWrap, token),
2421 .Ampersand => .AddressOf,2420 .Ampersand => return p.allocSimplePrefixOp(.AddressOf, token),
2422 .Keyword_try => .Try,2421 .Keyword_try => return p.allocSimplePrefixOp(.Try, token),
2423 .Keyword_await => .Await,2422 .Keyword_await => return p.allocSimplePrefixOp(.Await, token),
2424 else => {2423 else => {
2425 p.putBackToken(token);2424 p.putBackToken(token);
2426 return null;2425 return null;
2427 },2426 },
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));
2431 node.* = .{2432 node.* = .{
2432 .op_token = token,2433 .op_token = token,
2433 .op = op,
2434 .rhs = undefined, // set by caller2434 .rhs = undefined, // set by caller
2435 };2435 };
2436 return &node.base;2436 return &node.base;
...@@ -2450,19 +2450,14 @@ const Parser = struct {...@@ -2450,19 +2450,14 @@ const Parser = struct {
2450 /// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*2450 /// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2451 fn parsePrefixTypeOp(p: *Parser) !?*Node {2451 fn parsePrefixTypeOp(p: *Parser) !?*Node {
2452 if (p.eatToken(.QuestionMark)) |token| {2452 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);
2454 node.* = .{2454 node.* = .{
2455 .op_token = token,2455 .op_token = token,
2456 .op = .OptionalType,
2457 .rhs = undefined, // set by caller2456 .rhs = undefined, // set by caller
2458 };2457 };
2459 return &node.base;2458 return &node.base;
2460 }2459 }
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?
2466 if (p.eatToken(.Keyword_anyframe)) |token| {2461 if (p.eatToken(.Keyword_anyframe)) |token| {
2467 const arrow = p.eatToken(.Arrow) orelse {2462 const arrow = p.eatToken(.Arrow) orelse {
2468 p.putBackToken(token);2463 p.putBackToken(token);
...@@ -2482,11 +2477,15 @@ const Parser = struct {...@@ -2482,11 +2477,15 @@ const Parser = struct {
2482 if (try p.parsePtrTypeStart()) |node| {2477 if (try p.parsePtrTypeStart()) |node| {
2483 // If the token encountered was **, there will be two nodes instead of one.2478 // If the token encountered was **, there will be two nodes instead of one.
2484 // The attributes should be applied to the rightmost operator.2479 // The attributes should be applied to the rightmost operator.
2485 const prefix_op = node.cast(Node.PrefixOp).?;2480 var ptr_info = if (node.cast(Node.PtrType)) |ptr_type|
2486 var ptr_info = if (p.token_ids[prefix_op.op_token] == .AsteriskAsterisk)2481 if (p.token_ids[ptr_type.op_token] == .AsteriskAsterisk)
2487 &prefix_op.rhs.cast(Node.PrefixOp).?.op.PtrType2482 &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
2488 else2487 else
2489 &prefix_op.op.PtrType;2488 unreachable;
24902489
2491 while (true) {2490 while (true) {
2492 if (p.eatToken(.Keyword_align)) |align_token| {2491 if (p.eatToken(.Keyword_align)) |align_token| {
...@@ -2505,7 +2504,7 @@ const Parser = struct {...@@ -2505,7 +2504,7 @@ const Parser = struct {
2505 .ExpectedIntegerLiteral = .{ .token = p.tok_i },2504 .ExpectedIntegerLiteral = .{ .token = p.tok_i },
2506 });2505 });
25072506
2508 break :bit_range_value Node.PrefixOp.PtrInfo.Align.BitRange{2507 break :bit_range_value ast.PtrInfo.Align.BitRange{
2509 .start = range_start,2508 .start = range_start,
2510 .end = range_end,2509 .end = range_end,
2511 };2510 };
...@@ -2519,7 +2518,7 @@ const Parser = struct {...@@ -2519,7 +2518,7 @@ const Parser = struct {
2519 continue;2518 continue;
2520 }2519 }
25212520
2522 ptr_info.align_info = Node.PrefixOp.PtrInfo.Align{2521 ptr_info.align_info = ast.PtrInfo.Align{
2523 .node = expr_node,2522 .node = expr_node,
2524 .bit_range = bit_range,2523 .bit_range = bit_range,
2525 };2524 };
...@@ -2563,58 +2562,54 @@ const Parser = struct {...@@ -2563,58 +2562,54 @@ const Parser = struct {
2563 }2562 }
25642563
2565 if (try p.parseArrayTypeStart()) |node| {2564 if (try p.parseArrayTypeStart()) |node| {
2566 switch (node.cast(Node.PrefixOp).?.op) {2565 if (node.cast(Node.SliceType)) |slice_type| {
2567 .ArrayType => {},2566 // Collect pointer qualifiers in any order, but disallow duplicates
2568 .SliceType => |*slice_type| {2567 while (true) {
2569 // Collect pointer qualifiers in any order, but disallow duplicates2568 if (try p.parseByteAlign()) |align_expr| {
2570 while (true) {2569 if (slice_type.ptr_info.align_info != null) {
2571 if (try p.parseByteAlign()) |align_expr| {2570 try p.errors.append(p.gpa, .{
2572 if (slice_type.align_info != null) {2571 .ExtraAlignQualifier = .{ .token = p.tok_i - 1 },
2573 try p.errors.append(p.gpa, .{2572 });
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 };
2582 continue;2573 continue;
2583 }2574 }
2584 if (p.eatToken(.Keyword_const)) |const_token| {2575 slice_type.ptr_info.align_info = ast.PtrInfo.Align{
2585 if (slice_type.const_token != null) {2576 .node = align_expr,
2586 try p.errors.append(p.gpa, .{2577 .bit_range = null,
2587 .ExtraConstQualifier = .{ .token = p.tok_i - 1 },2578 };
2588 });2579 continue;
2589 continue;2580 }
2590 }2581 if (p.eatToken(.Keyword_const)) |const_token| {
2591 slice_type.const_token = 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 });
2592 continue;2586 continue;
2593 }2587 }
2594 if (p.eatToken(.Keyword_volatile)) |volatile_token| {2588 slice_type.ptr_info.const_token = const_token;
2595 if (slice_type.volatile_token != null) {2589 continue;
2596 try p.errors.append(p.gpa, .{2590 }
2597 .ExtraVolatileQualifier = .{ .token = p.tok_i - 1 },2591 if (p.eatToken(.Keyword_volatile)) |volatile_token| {
2598 });2592 if (slice_type.ptr_info.volatile_token != null) {
2599 continue;2593 try p.errors.append(p.gpa, .{
2600 }2594 .ExtraVolatileQualifier = .{ .token = p.tok_i - 1 },
2601 slice_type.volatile_token = volatile_token;2595 });
2602 continue;2596 continue;
2603 }2597 }
2604 if (p.eatToken(.Keyword_allowzero)) |allowzero_token| {2598 slice_type.ptr_info.volatile_token = volatile_token;
2605 if (slice_type.allowzero_token != null) {2599 continue;
2606 try p.errors.append(p.gpa, .{2600 }
2607 .ExtraAllowZeroQualifier = .{ .token = p.tok_i - 1 },2601 if (p.eatToken(.Keyword_allowzero)) |allowzero_token| {
2608 });2602 if (slice_type.ptr_info.allowzero_token != null) {
2609 continue;2603 try p.errors.append(p.gpa, .{
2610 }2604 .ExtraAllowZeroQualifier = .{ .token = p.tok_i - 1 },
2611 slice_type.allowzero_token = allowzero_token;2605 });
2612 continue;2606 continue;
2613 }2607 }
2614 break;2608 slice_type.ptr_info.allowzero_token = allowzero_token;
2609 continue;
2615 }2610 }
2616 },2611 break;
2617 else => unreachable,2612 }
2618 }2613 }
2619 return node;2614 return node;
2620 }2615 }
...@@ -2728,29 +2723,32 @@ const Parser = struct {...@@ -2728,29 +2723,32 @@ const Parser = struct {
2728 null;2723 null;
2729 const rbracket = try p.expectToken(.RBracket);2724 const rbracket = try p.expectToken(.RBracket);
27302725
2731 const op: Node.PrefixOp.Op = if (expr) |len_expr|2726 if (expr) |len_expr| {
2732 .{2727 if (sentinel) |s| {
2733 .ArrayType = .{2728 const node = try p.arena.allocator.create(Node.ArrayTypeSentinel);
2729 node.* = .{
2730 .op_token = lbracket,
2731 .rhs = undefined, // set by caller
2734 .len_expr = len_expr,2732 .len_expr = len_expr,
2735 .sentinel = sentinel,2733 .sentinel = s,
2736 },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;
2737 }2744 }
2738 else2745 }
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 };
27482746
2749 const node = try p.arena.allocator.create(Node.PrefixOp);2747 const node = try p.arena.allocator.create(Node.SliceType);
2750 node.* = .{2748 node.* = .{
2751 .op_token = lbracket,2749 .op_token = lbracket,
2752 .op = op,
2753 .rhs = undefined, // set by caller2750 .rhs = undefined, // set by caller
2751 .ptr_info = .{ .sentinel = sentinel },
2754 };2752 };
2755 return &node.base;2753 return &node.base;
2756 }2754 }
...@@ -2768,28 +2766,26 @@ const Parser = struct {...@@ -2768,28 +2766,26 @@ const Parser = struct {
2768 })2766 })
2769 else2767 else
2770 null;2768 null;
2771 const node = try p.arena.allocator.create(Node.PrefixOp);2769 const node = try p.arena.allocator.create(Node.PtrType);
2772 node.* = .{2770 node.* = .{
2773 .op_token = asterisk,2771 .op_token = asterisk,
2774 .op = .{ .PtrType = .{ .sentinel = sentinel } },
2775 .rhs = undefined, // set by caller2772 .rhs = undefined, // set by caller
2773 .ptr_info = .{ .sentinel = sentinel },
2776 };2774 };
2777 return &node.base;2775 return &node.base;
2778 }2776 }
27792777
2780 if (p.eatToken(.AsteriskAsterisk)) |double_asterisk| {2778 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);
2782 node.* = .{2780 node.* = .{
2783 .op_token = double_asterisk,2781 .op_token = double_asterisk,
2784 .op = .{ .PtrType = .{} },
2785 .rhs = undefined, // set by caller2782 .rhs = undefined, // set by caller
2786 };2783 };
27872784
2788 // Special case for **, which is its own token2785 // 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);
2790 child.* = .{2787 child.* = .{
2791 .op_token = double_asterisk,2788 .op_token = double_asterisk,
2792 .op = .{ .PtrType = .{} },
2793 .rhs = undefined, // set by caller2789 .rhs = undefined, // set by caller
2794 };2790 };
2795 node.rhs = &child.base;2791 node.rhs = &child.base;
...@@ -2808,10 +2804,9 @@ const Parser = struct {...@@ -2808,10 +2804,9 @@ const Parser = struct {
2808 p.putBackToken(ident);2804 p.putBackToken(ident);
2809 } else {2805 } else {
2810 _ = try p.expectToken(.RBracket);2806 _ = try p.expectToken(.RBracket);
2811 const node = try p.arena.allocator.create(Node.PrefixOp);2807 const node = try p.arena.allocator.create(Node.PtrType);
2812 node.* = .{2808 node.* = .{
2813 .op_token = lbracket,2809 .op_token = lbracket,
2814 .op = .{ .PtrType = .{} },
2815 .rhs = undefined, // set by caller2810 .rhs = undefined, // set by caller
2816 };2811 };
2817 return &node.base;2812 return &node.base;
...@@ -2824,11 +2819,11 @@ const Parser = struct {...@@ -2824,11 +2819,11 @@ const Parser = struct {
2824 else2819 else
2825 null;2820 null;
2826 _ = try p.expectToken(.RBracket);2821 _ = try p.expectToken(.RBracket);
2827 const node = try p.arena.allocator.create(Node.PrefixOp);2822 const node = try p.arena.allocator.create(Node.PtrType);
2828 node.* = .{2823 node.* = .{
2829 .op_token = lbracket,2824 .op_token = lbracket,
2830 .op = .{ .PtrType = .{ .sentinel = sentinel } },
2831 .rhs = undefined, // set by caller2825 .rhs = undefined, // set by caller
2826 .ptr_info = .{ .sentinel = sentinel },
2832 };2827 };
2833 return &node.base;2828 return &node.base;
2834 }2829 }
...@@ -3146,10 +3141,9 @@ const Parser = struct {...@@ -3146,10 +3141,9 @@ const Parser = struct {
31463141
3147 fn parseTry(p: *Parser) !?*Node {3142 fn parseTry(p: *Parser) !?*Node {
3148 const token = p.eatToken(.Keyword_try) orelse return null;3143 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);
3150 node.* = .{3145 node.* = .{
3151 .op_token = token,3146 .op_token = token,
3152 .op = .Try,
3153 .rhs = undefined, // set by caller3147 .rhs = undefined, // set by caller
3154 };3148 };
3155 return &node.base;3149 return &node.base;
...@@ -3228,15 +3222,87 @@ const Parser = struct {...@@ -3228,15 +3222,87 @@ const Parser = struct {
3228 var rightmost_op = first_op;3222 var rightmost_op = first_op;
3229 while (true) {3223 while (true) {
3230 switch (rightmost_op.id) {3224 switch (rightmost_op.id) {
3231 .PrefixOp => {3225 .AddressOf => {
3232 var prefix_op = rightmost_op.cast(Node.PrefixOp).?;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).?;
3233 // If the token encountered was **, there will be two nodes3299 // If the token encountered was **, there will be two nodes
3234 if (p.token_ids[prefix_op.op_token] == .AsteriskAsterisk) {3300 if (p.token_ids[ptr_type.op_token] == .AsteriskAsterisk) {
3235 rightmost_op = prefix_op.rhs;3301 rightmost_op = ptr_type.rhs;
3236 prefix_op = rightmost_op.cast(Node.PrefixOp).?;3302 ptr_type = rightmost_op.cast(Node.PtrType).?;
3237 }3303 }
3238 if (try opParseFn(p)) |rhs| {3304 if (try opParseFn(p)) |rhs| {
3239 prefix_op.rhs = rhs;3305 ptr_type.rhs = rhs;
3240 rightmost_op = rhs;3306 rightmost_op = rhs;
3241 } else break;3307 } else break;
3242 },3308 },
...@@ -3253,8 +3319,80 @@ const Parser = struct {...@@ -3253,8 +3319,80 @@ const Parser = struct {
32533319
3254 // If any prefix op existed, a child node on the RHS is required3320 // If any prefix op existed, a child node on the RHS is required
3255 switch (rightmost_op.id) {3321 switch (rightmost_op.id) {
3256 .PrefixOp => {3322 .AddressOf => {
3257 const prefix_op = rightmost_op.cast(Node.PrefixOp).?;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).?;
3258 prefix_op.rhs = try p.expectNode(childParseFn, .{3396 prefix_op.rhs = try p.expectNode(childParseFn, .{
3259 .InvalidToken = .{ .token = p.tok_i },3397 .InvalidToken = .{ .token = p.tok_i },
3260 });3398 });
lib/std/zig/render.zig+211-145
...@@ -468,166 +468,192 @@ fn renderExpression(...@@ -468,166 +468,192 @@ fn renderExpression(
468 return renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.rhs, space);468 return renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.rhs, space);
469 },469 },
470470
471 .PrefixOp => {471 .BitNot => {
472 const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);472 const bit_not = @fieldParentPtr(ast.Node.BitNot, "base", base);
473473 try renderToken(tree, stream, bit_not.op_token, indent, start_col, Space.None);
474 switch (prefix_op_node.op) {474 return renderExpression(allocator, stream, tree, indent, start_col, bit_not.rhs, space);
475 .PtrType => |ptr_info| {475 },
476 const op_tok_id = tree.token_ids[prefix_op_node.op_token];476 .BoolNot => {
477 switch (op_tok_id) {477 const bool_not = @fieldParentPtr(ast.Node.BoolNot, "base", base);
478 .Asterisk, .AsteriskAsterisk => try stream.writeByte('*'),478 try renderToken(tree, stream, bool_not.op_token, indent, start_col, Space.None);
479 .LBracket => if (tree.token_ids[prefix_op_node.op_token + 2] == .Identifier)479 return renderExpression(allocator, stream, tree, indent, start_col, bool_not.rhs, space);
480 try stream.writeAll("[*c")480 },
481 else481 .Negation => {
482 try stream.writeAll("[*"),482 const negation = @fieldParentPtr(ast.Node.Negation, "base", base);
483 else => unreachable,483 try renderToken(tree, stream, negation.op_token, indent, start_col, Space.None);
484 }484 return renderExpression(allocator, stream, tree, indent, start_col, negation.rhs, space);
485 if (ptr_info.sentinel) |sentinel| {485 },
486 const colon_token = tree.prevToken(sentinel.firstToken());486 .NegationWrap => {
487 try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :487 const negation_wrap = @fieldParentPtr(ast.Node.NegationWrap, "base", base);
488 const sentinel_space = switch (op_tok_id) {488 try renderToken(tree, stream, negation_wrap.op_token, indent, start_col, Space.None);
489 .LBracket => Space.None,489 return renderExpression(allocator, stream, tree, indent, start_col, negation_wrap.rhs, space);
490 else => Space.Space,490 },
491 };491 .OptionalType => {
492 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, sentinel_space);492 const opt_type = @fieldParentPtr(ast.Node.OptionalType, "base", base);
493 }493 try renderToken(tree, stream, opt_type.op_token, indent, start_col, Space.None);
494 switch (op_tok_id) {494 return renderExpression(allocator, stream, tree, indent, start_col, opt_type.rhs, space);
495 .Asterisk, .AsteriskAsterisk => {},495 },
496 .LBracket => try stream.writeByte(']'),496 .AddressOf => {
497 else => unreachable,497 const addr_of = @fieldParentPtr(ast.Node.AddressOf, "base", base);
498 }498 try renderToken(tree, stream, addr_of.op_token, indent, start_col, Space.None);
499 if (ptr_info.allowzero_token) |allowzero_token| {499 return renderExpression(allocator, stream, tree, indent, start_col, addr_of.rhs, space);
500 try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero500 },
501 }501 .Try => {
502 if (ptr_info.align_info) |align_info| {502 const try_node = @fieldParentPtr(ast.Node.Try, "base", base);
503 const lparen_token = tree.prevToken(align_info.node.firstToken());503 try renderToken(tree, stream, try_node.op_token, indent, start_col, Space.Space);
504 const align_token = tree.prevToken(lparen_token);504 return renderExpression(allocator, stream, tree, indent, start_col, try_node.rhs, space);
505505 },
506 try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align506 .Resume => {
507 try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (507 const resume_node = @fieldParentPtr(ast.Node.Resume, "base", base);
508508 try renderToken(tree, stream, resume_node.op_token, indent, start_col, Space.Space);
509 try renderExpression(allocator, stream, tree, indent, start_col, align_info.node, Space.None);509 return renderExpression(allocator, stream, tree, indent, start_col, resume_node.rhs, space);
510510 },
511 if (align_info.bit_range) |bit_range| {511 .Await => {
512 const colon1 = tree.prevToken(bit_range.start.firstToken());512 const await_node = @fieldParentPtr(ast.Node.Await, "base", base);
513 const colon2 = tree.prevToken(bit_range.end.firstToken());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); // :517 .ArrayType => {
516 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.start, Space.None);518 const array_type = @fieldParentPtr(ast.Node.ArrayType, "base", base);
517 try renderToken(tree, stream, colon2, indent, start_col, Space.None); // :519 return renderArrayType(
518 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.end, Space.None);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());548 .PtrType => {
521 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )549 const ptr_type = @fieldParentPtr(ast.Node.PtrType, "base", base);
522 } else {550 const op_tok_id = tree.token_ids[ptr_type.op_token];
523 const rparen_token = tree.nextToken(align_info.node.lastToken());551 switch (op_tok_id) {
524 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )552 .Asterisk, .AsteriskAsterisk => try stream.writeByte('*'),
525 }553 .LBracket => if (tree.token_ids[ptr_type.op_token + 2] == .Identifier)
526 }554 try stream.writeAll("[*c")
527 if (ptr_info.const_token) |const_token| {555 else
528 try renderToken(tree, stream, const_token, indent, start_col, Space.Space); // const556 try stream.writeAll("[*"),
529 }557 else => unreachable,
530 if (ptr_info.volatile_token) |volatile_token| {558 }
531 try renderToken(tree, stream, volatile_token, indent, start_col, Space.Space); // volatile559 if (ptr_type.ptr_info.sentinel) |sentinel| {
532 }560 const colon_token = tree.prevToken(sentinel.firstToken());
533 },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| {580 try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align
536 try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None); // [581 try renderToken(tree, stream, lparen_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 }
545582
546 if (ptr_info.allowzero_token) |allowzero_token| {583 try renderExpression(allocator, stream, tree, indent, start_col, align_info.node, Space.None);
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);
552584
553 try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align585 if (align_info.bit_range) |bit_range| {
554 try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (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| {594 const rparen_token = tree.nextToken(bit_range.end.lastToken());
559 const colon1 = tree.prevToken(bit_range.start.firstToken());595 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
560 const colon2 = tree.prevToken(bit_range.end.firstToken());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); // :610 .SliceType => {
563 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.start, Space.None);611 const slice_type = @fieldParentPtr(ast.Node.SliceType, "base", base);
564 try renderToken(tree, stream, colon2, indent, start_col, Space.None); // :612 try renderToken(tree, stream, slice_type.op_token, indent, start_col, Space.None); // [
565 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.end, 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());622 if (slice_type.ptr_info.allowzero_token) |allowzero_token| {
568 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )623 try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero
569 } else {624 }
570 const rparen_token = tree.nextToken(align_info.node.lastToken());625 if (slice_type.ptr_info.align_info) |align_info| {
571 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )626 const lparen_token = tree.prevToken(align_info.node.firstToken());
572 }627 const align_token = tree.prevToken(lparen_token);
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 },
581628
582 .ArrayType => |array_info| {629 try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align
583 const lbracket = prefix_op_node.op_token;630 try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (
584 const rbracket = tree.nextToken(if (array_info.sentinel) |sentinel|
585 sentinel.lastToken()
586 else
587 array_info.len_expr.lastToken());
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;634 if (align_info.bit_range) |bit_range| {
592 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;635 const colon1 = tree.prevToken(bit_range.start.firstToken());
593 const new_indent = if (ends_with_comment) indent + indent_delta else indent;636 const colon2 = tree.prevToken(bit_range.end.firstToken());
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 },
618637
619 .Try,638 try renderToken(tree, stream, colon1, indent, start_col, Space.None); // :
620 .Resume,639 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.start, Space.None);
621 => {640 try renderToken(tree, stream, colon2, indent, start_col, Space.None); // :
622 try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.Space);641 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.end, Space.None);
623 },
624642
625 .Await => |await_info| {643 const rparen_token = tree.nextToken(bit_range.end.lastToken());
626 try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.Space);644 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
627 },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 }
628 }649 }
629650 if (slice_type.ptr_info.const_token) |const_token| {
630 return renderExpression(allocator, stream, tree, indent, start_col, prefix_op_node.rhs, space);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);
631 },657 },
632658
633 .ArrayInitializer, .ArrayInitializerDot => {659 .ArrayInitializer, .ArrayInitializerDot => {
...@@ -2057,6 +2083,46 @@ fn renderExpression(...@@ -2057,6 +2083,46 @@ fn renderExpression(
2057 }2083 }
2058}2084}
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
2060fn renderAsmOutput(2126fn renderAsmOutput(
2061 allocator: *mem.Allocator,2127 allocator: *mem.Allocator,
2062 stream: anytype,2128 stream: anytype,
src-self-hosted/Module.zig+8
...@@ -1308,10 +1308,18 @@ fn astGenExpr(self: *Module, scope: *Scope, ast_node: *ast.Node) InnerError!*zir...@@ -1308,10 +1308,18 @@ fn astGenExpr(self: *Module, scope: *Scope, ast_node: *ast.Node) InnerError!*zir
1308 .ControlFlowExpression => return self.astGenControlFlowExpression(scope, @fieldParentPtr(ast.Node.ControlFlowExpression, "base", ast_node)),1308 .ControlFlowExpression => return self.astGenControlFlowExpression(scope, @fieldParentPtr(ast.Node.ControlFlowExpression, "base", ast_node)),
1309 .If => return self.astGenIf(scope, @fieldParentPtr(ast.Node.If, "base", ast_node)),1309 .If => return self.astGenIf(scope, @fieldParentPtr(ast.Node.If, "base", ast_node)),
1310 .InfixOp => return self.astGenInfixOp(scope, @fieldParentPtr(ast.Node.InfixOp, "base", ast_node)),1310 .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)),
1311 else => return self.failNode(scope, ast_node, "TODO implement astGenExpr for {}", .{@tagName(ast_node.id)}),1312 else => return self.failNode(scope, ast_node, "TODO implement astGenExpr for {}", .{@tagName(ast_node.id)}),
1312 }1313 }
1313}1314}
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
1315fn astGenInfixOp(self: *Module, scope: *Scope, infix_node: *ast.Node.InfixOp) InnerError!*zir.Inst {1323fn astGenInfixOp(self: *Module, scope: *Scope, infix_node: *ast.Node.InfixOp) InnerError!*zir.Inst {
1316 switch (infix_node.op) {1324 switch (infix_node.op) {
1317 .Assign => {1325 .Assign => {
src-self-hosted/translate_c.zig+80-87
...@@ -1561,7 +1561,7 @@ fn transImplicitCastExpr(...@@ -1561,7 +1561,7 @@ fn transImplicitCastExpr(
1561 return maybeSuppressResult(rp, scope, result_used, sub_expr_node);1561 return maybeSuppressResult(rp, scope, result_used, sub_expr_node);
1562 }1562 }
15631563
1564 const prefix_op = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&");1564 const prefix_op = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
1565 prefix_op.rhs = try transExpr(rp, scope, sub_expr, .used, .r_value);1565 prefix_op.rhs = try transExpr(rp, scope, sub_expr, .used, .r_value);
15661566
1567 return maybeSuppressResult(rp, scope, result_used, &prefix_op.base);1567 return maybeSuppressResult(rp, scope, result_used, &prefix_op.base);
...@@ -1673,11 +1673,7 @@ fn isBoolRes(res: *ast.Node) bool {...@@ -1673,11 +1673,7 @@ fn isBoolRes(res: *ast.Node) bool {
16731673
1674 else => {},1674 else => {},
1675 },1675 },
1676 .PrefixOp => switch (@fieldParentPtr(ast.Node.PrefixOp, "base", res).op) {1676 .BoolNot => return true,
1677 .BoolNot => return true,
1678
1679 else => {},
1680 },
1681 .BoolLiteral => return true,1677 .BoolLiteral => return true,
1682 .GroupedExpression => return isBoolRes(@fieldParentPtr(ast.Node.GroupedExpression, "base", res).expr),1678 .GroupedExpression => return isBoolRes(@fieldParentPtr(ast.Node.GroupedExpression, "base", res).expr),
1683 else => {},1679 else => {},
...@@ -2162,21 +2158,16 @@ fn transCreateNodeArrayType(...@@ -2162,21 +2158,16 @@ fn transCreateNodeArrayType(
2162 source_loc: ZigClangSourceLocation,2158 source_loc: ZigClangSourceLocation,
2163 ty: *const ZigClangType,2159 ty: *const ZigClangType,
2164 len: anytype,2160 len: anytype,
2165) TransError!*ast.Node {2161) !*ast.Node {
2166 var node = try transCreateNodePrefixOp(2162 const node = try rp.c.arena.create(ast.Node.ArrayType);
2167 rp.c,2163 const op_token = try appendToken(rp.c, .LBracket, "[");
2168 .{2164 const len_expr = try transCreateNodeInt(rp.c, len);
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);
2178 _ = try appendToken(rp.c, .RBracket, "]");2165 _ = 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 };
2180 return &node.base;2171 return &node.base;
2181}2172}
21822173
...@@ -2449,7 +2440,7 @@ fn transDoWhileLoop(...@@ -2449,7 +2440,7 @@ fn transDoWhileLoop(
2449 },2440 },
2450 };2441 };
2451 defer cond_scope.deinit();2442 defer cond_scope.deinit();
2452 const prefix_op = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");2443 const prefix_op = try transCreateNodeSimplePrefixOp(rp.c, .BoolNot, .Bang, "!");
2453 prefix_op.rhs = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true);2444 prefix_op.rhs = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true);
2454 _ = try appendToken(rp.c, .RParen, ")");2445 _ = try appendToken(rp.c, .RParen, ")");
2455 if_node.condition = &prefix_op.base;2446 if_node.condition = &prefix_op.base;
...@@ -3036,7 +3027,7 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar...@@ -3036,7 +3027,7 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar
3036 else3027 else
3037 return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),3028 return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
3038 .AddrOf => {3029 .AddrOf => {
3039 const op_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&");3030 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
3040 op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value);3031 op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value);
3041 return &op_node.base;3032 return &op_node.base;
3042 },3033 },
...@@ -3052,7 +3043,7 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar...@@ -3052,7 +3043,7 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar
3052 .Plus => return transExpr(rp, scope, op_expr, used, .r_value),3043 .Plus => return transExpr(rp, scope, op_expr, used, .r_value),
3053 .Minus => {3044 .Minus => {
3054 if (!qualTypeHasWrappingOverflow(ZigClangExpr_getType(op_expr))) {3045 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, "-");
3056 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);3047 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3057 return &op_node.base;3048 return &op_node.base;
3058 } else if (cIsUnsignedInteger(ZigClangExpr_getType(op_expr))) {3049 } else if (cIsUnsignedInteger(ZigClangExpr_getType(op_expr))) {
...@@ -3065,12 +3056,12 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar...@@ -3065,12 +3056,12 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar
3065 return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangUnaryOperator_getBeginLoc(stmt), "C negation with non float non integer", .{});3056 return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangUnaryOperator_getBeginLoc(stmt), "C negation with non float non integer", .{});
3066 },3057 },
3067 .Not => {3058 .Not => {
3068 const op_node = try transCreateNodePrefixOp(rp.c, .BitNot, .Tilde, "~");3059 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .BitNot, .Tilde, "~");
3069 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);3060 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3070 return &op_node.base;3061 return &op_node.base;
3071 },3062 },
3072 .LNot => {3063 .LNot => {
3073 const op_node = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");3064 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .BoolNot, .Bang, "!");
3074 op_node.rhs = try transBoolExpr(rp, scope, op_expr, .used, .r_value, true);3065 op_node.rhs = try transBoolExpr(rp, scope, op_expr, .used, .r_value, true);
3075 return &op_node.base;3066 return &op_node.base;
3076 },3067 },
...@@ -3116,7 +3107,7 @@ fn transCreatePreCrement(...@@ -3116,7 +3107,7 @@ fn transCreatePreCrement(
31163107
3117 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);3108 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
3118 node.eq_token = try appendToken(rp.c, .Equal, "=");3109 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, "&");
3120 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);3111 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3121 node.init_node = &rhs_node.base;3112 node.init_node = &rhs_node.base;
3122 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");3113 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
...@@ -3182,7 +3173,7 @@ fn transCreatePostCrement(...@@ -3182,7 +3173,7 @@ fn transCreatePostCrement(
31823173
3183 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);3174 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
3184 node.eq_token = try appendToken(rp.c, .Equal, "=");3175 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, "&");
3186 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);3177 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3187 node.init_node = &rhs_node.base;3178 node.init_node = &rhs_node.base;
3188 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");3179 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
...@@ -3336,7 +3327,7 @@ fn transCreateCompoundAssign(...@@ -3336,7 +3327,7 @@ fn transCreateCompoundAssign(
33363327
3337 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);3328 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
3338 node.eq_token = try appendToken(rp.c, .Equal, "=");3329 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, "&");
3340 addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value);3331 addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value);
3341 node.init_node = &addr_node.base;3332 node.init_node = &addr_node.base;
3342 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");3333 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
...@@ -3984,16 +3975,15 @@ fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []c...@@ -3984,16 +3975,15 @@ fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []c
3984 return &field_access_node.base;3975 return &field_access_node.base;
3985}3976}
39863977
3987fn transCreateNodePrefixOp(3978fn transCreateNodeSimplePrefixOp(
3988 c: *Context,3979 c: *Context,
3989 op: ast.Node.PrefixOp.Op,3980 comptime tag: ast.Node.Id,
3990 op_tok_id: std.zig.Token.Id,3981 op_tok_id: std.zig.Token.Id,
3991 bytes: []const u8,3982 bytes: []const u8,
3992) !*ast.Node.PrefixOp {3983) !*ast.Node.SimplePrefixOp(tag) {
3993 const node = try c.arena.create(ast.Node.PrefixOp);3984 const node = try c.arena.create(ast.Node.SimplePrefixOp(tag));
3994 node.* = .{3985 node.* = .{
3995 .op_token = try appendToken(c, op_tok_id, bytes),3986 .op_token = try appendToken(c, op_tok_id, bytes),
3996 .op = op,
3997 .rhs = undefined, // translate and set afterward3987 .rhs = undefined, // translate and set afterward
3998 };3988 };
3999 return node;3989 return node;
...@@ -4065,8 +4055,8 @@ fn transCreateNodePtrType(...@@ -4065,8 +4055,8 @@ fn transCreateNodePtrType(
4065 is_const: bool,4055 is_const: bool,
4066 is_volatile: bool,4056 is_volatile: bool,
4067 op_tok_id: std.zig.Token.Id,4057 op_tok_id: std.zig.Token.Id,
4068) !*ast.Node.PrefixOp {4058) !*ast.Node.PtrType {
4069 const node = try c.arena.create(ast.Node.PrefixOp);4059 const node = try c.arena.create(ast.Node.PtrType);
4070 const op_token = switch (op_tok_id) {4060 const op_token = switch (op_tok_id) {
4071 .LBracket => blk: {4061 .LBracket => blk: {
4072 const lbracket = try appendToken(c, .LBracket, "[");4062 const lbracket = try appendToken(c, .LBracket, "[");
...@@ -4086,11 +4076,9 @@ fn transCreateNodePtrType(...@@ -4086,11 +4076,9 @@ fn transCreateNodePtrType(
4086 };4076 };
4087 node.* = .{4077 node.* = .{
4088 .op_token = op_token,4078 .op_token = op_token,
4089 .op = .{4079 .ptr_info = .{
4090 .PtrType = .{4080 .const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null,
4091 .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,
4092 .volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null,
4093 },
4094 },4082 },
4095 .rhs = undefined, // translate and set afterward4083 .rhs = undefined, // translate and set afterward
4096 };4084 };
...@@ -4569,12 +4557,12 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour...@@ -4569,12 +4557,12 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
4569 .Pointer => {4557 .Pointer => {
4570 const child_qt = ZigClangType_getPointeeType(ty);4558 const child_qt = ZigClangType_getPointeeType(ty);
4571 if (qualTypeChildIsFnProto(child_qt)) {4559 if (qualTypeChildIsFnProto(child_qt)) {
4572 const optional_node = try transCreateNodePrefixOp(rp.c, .OptionalType, .QuestionMark, "?");4560 const optional_node = try transCreateNodeSimplePrefixOp(rp.c, .OptionalType, .QuestionMark, "?");
4573 optional_node.rhs = try transQualType(rp, child_qt, source_loc);4561 optional_node.rhs = try transQualType(rp, child_qt, source_loc);
4574 return &optional_node.base;4562 return &optional_node.base;
4575 }4563 }
4576 if (typeIsOpaque(rp.c, ZigClangQualType_getTypePtr(child_qt), source_loc)) {4564 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, "?");
4578 const pointer_node = try transCreateNodePtrType(4566 const pointer_node = try transCreateNodePtrType(
4579 rp.c,4567 rp.c,
4580 ZigClangQualType_isConstQualified(child_qt),4568 ZigClangQualType_isConstQualified(child_qt),
...@@ -4599,21 +4587,8 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour...@@ -4599,21 +4587,8 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
45994587
4600 const size_ap_int = ZigClangConstantArrayType_getSize(const_arr_ty);4588 const size_ap_int = ZigClangConstantArrayType_getSize(const_arr_ty);
4601 const size = ZigClangAPInt_getLimitedValue(size_ap_int, math.maxInt(usize));4589 const size = ZigClangAPInt_getLimitedValue(size_ap_int, math.maxInt(usize));
4602 var node = try transCreateNodePrefixOp(4590 const elem_ty = ZigClangQualType_getTypePtr(ZigClangConstantArrayType_getElementType(const_arr_ty));
4603 rp.c,4591 return try transCreateNodeArrayType(rp, source_loc, elem_ty, size);
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;
4617 },4592 },
4618 .IncompleteArray => {4593 .IncompleteArray => {
4619 const incomplete_array_ty = @ptrCast(*const ZigClangIncompleteArrayType, ty);4594 const incomplete_array_ty = @ptrCast(*const ZigClangIncompleteArrayType, ty);
...@@ -5824,7 +5799,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5824,7 +5799,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5824 if (prev_id == .Keyword_void) {5799 if (prev_id == .Keyword_void) {
5825 const ptr = try transCreateNodePtrType(c, false, false, .Asterisk);5800 const ptr = try transCreateNodePtrType(c, false, false, .Asterisk);
5826 ptr.rhs = node;5801 ptr.rhs = node;
5827 const optional_node = try transCreateNodePrefixOp(c, .OptionalType, .QuestionMark, "?");5802 const optional_node = try transCreateNodeSimplePrefixOp(c, .OptionalType, .QuestionMark, "?");
5828 optional_node.rhs = &ptr.base;5803 optional_node.rhs = &ptr.base;
5829 return &optional_node.base;5804 return &optional_node.base;
5830 } else {5805 } else {
...@@ -5993,18 +5968,18 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5993,18 +5968,18 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
59935968
5994 switch (op_tok.id) {5969 switch (op_tok.id) {
5995 .Bang => {5970 .Bang => {
5996 const node = try transCreateNodePrefixOp(c, .BoolNot, .Bang, "!");5971 const node = try transCreateNodeSimplePrefixOp(c, .BoolNot, .Bang, "!");
5997 node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);5972 node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
5998 return &node.base;5973 return &node.base;
5999 },5974 },
6000 .Minus => {5975 .Minus => {
6001 const node = try transCreateNodePrefixOp(c, .Negation, .Minus, "-");5976 const node = try transCreateNodeSimplePrefixOp(c, .Negation, .Minus, "-");
6002 node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);5977 node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
6003 return &node.base;5978 return &node.base;
6004 },5979 },
6005 .Plus => return try parseCPrefixOpExpr(c, it, source, source_loc, scope),5980 .Plus => return try parseCPrefixOpExpr(c, it, source, source_loc, scope),
6006 .Tilde => {5981 .Tilde => {
6007 const node = try transCreateNodePrefixOp(c, .BitNot, .Tilde, "~");5982 const node = try transCreateNodeSimplePrefixOp(c, .BitNot, .Tilde, "~");
6008 node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);5983 node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
6009 return &node.base;5984 return &node.base;
6010 },5985 },
...@@ -6013,7 +5988,7 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -6013,7 +5988,7 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
6013 return try transCreateNodePtrDeref(c, node);5988 return try transCreateNodePtrDeref(c, node);
6014 },5989 },
6015 .Ampersand => {5990 .Ampersand => {
6016 const node = try transCreateNodePrefixOp(c, .AddressOf, .Ampersand, "&");5991 const node = try transCreateNodeSimplePrefixOp(c, .AddressOf, .Ampersand, "&");
6017 node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);5992 node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
6018 return &node.base;5993 return &node.base;
6019 },5994 },
...@@ -6034,29 +6009,49 @@ fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 {...@@ -6034,29 +6009,49 @@ fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 {
6034}6009}
60356010
6036fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {6011fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
6037 if (node.id == .ContainerDecl) {6012 switch (node.id) {
6038 return node;6013 .ContainerDecl,
6039 } else if (node.id == .PrefixOp) {6014 .AddressOf,
6040 return node;6015 .Await,
6041 } else if (node.cast(ast.Node.Identifier)) |ident| {6016 .BitNot,
6042 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {6017 .BoolNot,
6043 if (value.cast(ast.Node.VarDecl)) |var_decl|6018 .OptionalType,
6044 return getContainer(c, var_decl.init_node.?);6019 .Negation,
6045 }6020 .NegationWrap,
6046 } else if (node.cast(ast.Node.InfixOp)) |infix| {6021 .Resume,
6047 if (infix.op != .Period)6022 .Try,
6048 return null;6023 .ArrayType,
6049 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {6024 .ArrayTypeSentinel,
6050 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {6025 .PtrType,
6051 for (container.fieldsAndDecls()) |field_ref| {6026 .SliceType,
6052 const field = field_ref.cast(ast.Node.ContainerField).?;6027 => return node,
6053 const ident = infix.rhs.cast(ast.Node.Identifier).?;6028
6054 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {6029 .Identifier => {
6055 return getContainer(c, field.type_expr.?);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 }
6056 }6049 }
6057 }6050 }
6058 }6051 }
6059 }6052 },
6053
6054 else => {},
6060 }6055 }
6061 return null;6056 return null;
6062}6057}
...@@ -6091,11 +6086,9 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {...@@ -6091,11 +6086,9 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
6091fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto {6086fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto {
6092 const init = if (ref.cast(ast.Node.VarDecl)) |v| v.init_node.? else return null;6087 const init = if (ref.cast(ast.Node.VarDecl)) |v| v.init_node.? else return null;
6093 if (getContainerTypeOf(c, init)) |ty_node| {6088 if (getContainerTypeOf(c, init)) |ty_node| {
6094 if (ty_node.cast(ast.Node.PrefixOp)) |prefix| {6089 if (ty_node.cast(ast.Node.OptionalType)) |prefix| {
6095 if (prefix.op == .OptionalType) {6090 if (prefix.rhs.cast(ast.Node.FnProto)) |fn_proto| {
6096 if (prefix.rhs.cast(ast.Node.FnProto)) |fn_proto| {6091 return fn_proto;
6097 return fn_proto;
6098 }
6099 }6092 }
6100 }6093 }
6101 }6094 }