| author | |
| committer | |
| log | 14cef9dd3d8074b0dc2ee48a0905300ce6317aed |
| tree | 246220eb1846d00a982c33d8e0fae5b5f4ee150c |
| parent | 204f61d7f5aa7b5e27bdaaab9237fca17096ad3e |
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 KB5 files changed, 711 insertions(+), 408 deletions(-)
lib/std/zig/ast.zig+169-71| ... | ... | @@ -410,7 +410,20 @@ pub const Node = struct { |
| 410 | 410 | |
| 411 | 411 | // Operators |
| 412 | 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 | 427 | /// Not all suffix operations are under this tag. To save memory, some |
| 415 | 428 | /// suffix operations have dedicated Node tags. |
| 416 | 429 | SuffixOp, |
| ... | ... | @@ -1797,85 +1810,116 @@ pub const Node = struct { |
| 1797 | 1810 | } |
| 1798 | 1811 | }; |
| 1799 | 1812 | |
| 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 }, | |
| 1802 | 1848 | op_token: TokenIndex, |
| 1803 | op: Op, | |
| 1804 | 1849 | rhs: *Node, |
| 1850 | len_expr: *Node, | |
| 1805 | 1851 | |
| 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; | |
| 1820 | 1854 | |
| 1821 | pub const ArrayInfo = struct { | |
| 1822 | len_expr: *Node, | |
| 1823 | sentinel: ?*Node, | |
| 1824 | }; | |
| 1855 | if (i < 1) return self.len_expr; | |
| 1856 | i -= 1; | |
| 1825 | 1857 | |
| 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 | } | |
| 1843 | 1863 | |
| 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 | 1881 | var i = index; |
| 1846 | 1882 | |
| 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; | |
| 1853 | 1885 | |
| 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; | |
| 1859 | 1888 | |
| 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; | |
| 1868 | 1891 | |
| 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; | |
| 1879 | 1923 | } |
| 1880 | 1924 | |
| 1881 | 1925 | if (i < 1) return self.rhs; |
| ... | ... | @@ -1884,11 +1928,47 @@ pub const Node = struct { |
| 1884 | 1928 | return null; |
| 1885 | 1929 | } |
| 1886 | 1930 | |
| 1887 | pub fn firstToken(self: *const PrefixOp) TokenIndex { | |
| 1931 | pub fn firstToken(self: *const PtrType) TokenIndex { | |
| 1888 | 1932 | return self.op_token; |
| 1889 | 1933 | } |
| 1890 | 1934 | |
| 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 | 1972 | return self.rhs.lastToken(); |
| 1893 | 1973 | } |
| 1894 | 1974 | }; |
| ... | ... | @@ -2797,6 +2877,24 @@ pub const Node = struct { |
| 2797 | 2877 | }; |
| 2798 | 2878 | }; |
| 2799 | 2879 | |
| 2880 | pub 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 | ||
| 2800 | 2898 | test "iterate" { |
| 2801 | 2899 | var root = Node.Root{ |
| 2802 | 2900 | .base = Node{ .id = Node.Id.Root }, |
lib/std/zig/parse.zig+243-105| ... | ... | @@ -1120,10 +1120,9 @@ const Parser = struct { |
| 1120 | 1120 | const expr_node = try p.expectNode(parseExpr, .{ |
| 1121 | 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 | 1124 | node.* = .{ |
| 1125 | 1125 | .op_token = token, |
| 1126 | .op = .Resume, | |
| 1127 | 1126 | .rhs = expr_node, |
| 1128 | 1127 | }; |
| 1129 | 1128 | return &node.base; |
| ... | ... | @@ -2413,24 +2412,25 @@ const Parser = struct { |
| 2413 | 2412 | /// / KEYWORD_await |
| 2414 | 2413 | fn parsePrefixOp(p: *Parser) !?*Node { |
| 2415 | 2414 | 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), | |
| 2424 | 2423 | else => { |
| 2425 | 2424 | p.putBackToken(token); |
| 2426 | 2425 | return null; |
| 2427 | 2426 | }, |
| 2428 | }; | |
| 2427 | } | |
| 2428 | } | |
| 2429 | 2429 | |
| 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 | 2432 | node.* = .{ |
| 2432 | 2433 | .op_token = token, |
| 2433 | .op = op, | |
| 2434 | 2434 | .rhs = undefined, // set by caller |
| 2435 | 2435 | }; |
| 2436 | 2436 | return &node.base; |
| ... | ... | @@ -2450,19 +2450,14 @@ const Parser = struct { |
| 2450 | 2450 | /// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* |
| 2451 | 2451 | fn parsePrefixTypeOp(p: *Parser) !?*Node { |
| 2452 | 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 | 2454 | node.* = .{ |
| 2455 | 2455 | .op_token = token, |
| 2456 | .op = .OptionalType, | |
| 2457 | 2456 | .rhs = undefined, // set by caller |
| 2458 | 2457 | }; |
| 2459 | 2458 | return &node.base; |
| 2460 | 2459 | } |
| 2461 | 2460 | |
| 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 | 2461 | if (p.eatToken(.Keyword_anyframe)) |token| { |
| 2467 | 2462 | const arrow = p.eatToken(.Arrow) orelse { |
| 2468 | 2463 | p.putBackToken(token); |
| ... | ... | @@ -2482,11 +2477,15 @@ const Parser = struct { |
| 2482 | 2477 | if (try p.parsePtrTypeStart()) |node| { |
| 2483 | 2478 | // If the token encountered was **, there will be two nodes instead of one. |
| 2484 | 2479 | // 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 | |
| 2488 | 2487 | else |
| 2489 | &prefix_op.op.PtrType; | |
| 2488 | unreachable; | |
| 2490 | 2489 | |
| 2491 | 2490 | while (true) { |
| 2492 | 2491 | if (p.eatToken(.Keyword_align)) |align_token| { |
| ... | ... | @@ -2505,7 +2504,7 @@ const Parser = struct { |
| 2505 | 2504 | .ExpectedIntegerLiteral = .{ .token = p.tok_i }, |
| 2506 | 2505 | }); |
| 2507 | 2506 | |
| 2508 | break :bit_range_value Node.PrefixOp.PtrInfo.Align.BitRange{ | |
| 2507 | break :bit_range_value ast.PtrInfo.Align.BitRange{ | |
| 2509 | 2508 | .start = range_start, |
| 2510 | 2509 | .end = range_end, |
| 2511 | 2510 | }; |
| ... | ... | @@ -2519,7 +2518,7 @@ const Parser = struct { |
| 2519 | 2518 | continue; |
| 2520 | 2519 | } |
| 2521 | 2520 | |
| 2522 | ptr_info.align_info = Node.PrefixOp.PtrInfo.Align{ | |
| 2521 | ptr_info.align_info = ast.PtrInfo.Align{ | |
| 2523 | 2522 | .node = expr_node, |
| 2524 | 2523 | .bit_range = bit_range, |
| 2525 | 2524 | }; |
| ... | ... | @@ -2563,58 +2562,54 @@ const Parser = struct { |
| 2563 | 2562 | } |
| 2564 | 2563 | |
| 2565 | 2564 | 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 | }); | |
| 2582 | 2573 | continue; |
| 2583 | 2574 | } |
| 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 | }); | |
| 2592 | 2586 | continue; |
| 2593 | 2587 | } |
| 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 | }); | |
| 2602 | 2596 | continue; |
| 2603 | 2597 | } |
| 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 | }); | |
| 2612 | 2606 | continue; |
| 2613 | 2607 | } |
| 2614 | break; | |
| 2608 | slice_type.ptr_info.allowzero_token = allowzero_token; | |
| 2609 | continue; | |
| 2615 | 2610 | } |
| 2616 | }, | |
| 2617 | else => unreachable, | |
| 2611 | break; | |
| 2612 | } | |
| 2618 | 2613 | } |
| 2619 | 2614 | return node; |
| 2620 | 2615 | } |
| ... | ... | @@ -2728,29 +2723,32 @@ const Parser = struct { |
| 2728 | 2723 | null; |
| 2729 | 2724 | const rbracket = try p.expectToken(.RBracket); |
| 2730 | 2725 | |
| 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 | |
| 2734 | 2732 | .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; | |
| 2737 | 2744 | } |
| 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 | } | |
| 2748 | 2746 | |
| 2749 | const node = try p.arena.allocator.create(Node.PrefixOp); | |
| 2747 | const node = try p.arena.allocator.create(Node.SliceType); | |
| 2750 | 2748 | node.* = .{ |
| 2751 | 2749 | .op_token = lbracket, |
| 2752 | .op = op, | |
| 2753 | 2750 | .rhs = undefined, // set by caller |
| 2751 | .ptr_info = .{ .sentinel = sentinel }, | |
| 2754 | 2752 | }; |
| 2755 | 2753 | return &node.base; |
| 2756 | 2754 | } |
| ... | ... | @@ -2768,28 +2766,26 @@ const Parser = struct { |
| 2768 | 2766 | }) |
| 2769 | 2767 | else |
| 2770 | 2768 | null; |
| 2771 | const node = try p.arena.allocator.create(Node.PrefixOp); | |
| 2769 | const node = try p.arena.allocator.create(Node.PtrType); | |
| 2772 | 2770 | node.* = .{ |
| 2773 | 2771 | .op_token = asterisk, |
| 2774 | .op = .{ .PtrType = .{ .sentinel = sentinel } }, | |
| 2775 | 2772 | .rhs = undefined, // set by caller |
| 2773 | .ptr_info = .{ .sentinel = sentinel }, | |
| 2776 | 2774 | }; |
| 2777 | 2775 | return &node.base; |
| 2778 | 2776 | } |
| 2779 | 2777 | |
| 2780 | 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 | 2780 | node.* = .{ |
| 2783 | 2781 | .op_token = double_asterisk, |
| 2784 | .op = .{ .PtrType = .{} }, | |
| 2785 | 2782 | .rhs = undefined, // set by caller |
| 2786 | 2783 | }; |
| 2787 | 2784 | |
| 2788 | 2785 | // 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 | 2787 | child.* = .{ |
| 2791 | 2788 | .op_token = double_asterisk, |
| 2792 | .op = .{ .PtrType = .{} }, | |
| 2793 | 2789 | .rhs = undefined, // set by caller |
| 2794 | 2790 | }; |
| 2795 | 2791 | node.rhs = &child.base; |
| ... | ... | @@ -2808,10 +2804,9 @@ const Parser = struct { |
| 2808 | 2804 | p.putBackToken(ident); |
| 2809 | 2805 | } else { |
| 2810 | 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 | 2808 | node.* = .{ |
| 2813 | 2809 | .op_token = lbracket, |
| 2814 | .op = .{ .PtrType = .{} }, | |
| 2815 | 2810 | .rhs = undefined, // set by caller |
| 2816 | 2811 | }; |
| 2817 | 2812 | return &node.base; |
| ... | ... | @@ -2824,11 +2819,11 @@ const Parser = struct { |
| 2824 | 2819 | else |
| 2825 | 2820 | null; |
| 2826 | 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 | 2823 | node.* = .{ |
| 2829 | 2824 | .op_token = lbracket, |
| 2830 | .op = .{ .PtrType = .{ .sentinel = sentinel } }, | |
| 2831 | 2825 | .rhs = undefined, // set by caller |
| 2826 | .ptr_info = .{ .sentinel = sentinel }, | |
| 2832 | 2827 | }; |
| 2833 | 2828 | return &node.base; |
| 2834 | 2829 | } |
| ... | ... | @@ -3146,10 +3141,9 @@ const Parser = struct { |
| 3146 | 3141 | |
| 3147 | 3142 | fn parseTry(p: *Parser) !?*Node { |
| 3148 | 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 | 3145 | node.* = .{ |
| 3151 | 3146 | .op_token = token, |
| 3152 | .op = .Try, | |
| 3153 | 3147 | .rhs = undefined, // set by caller |
| 3154 | 3148 | }; |
| 3155 | 3149 | return &node.base; |
| ... | ... | @@ -3228,15 +3222,87 @@ const Parser = struct { |
| 3228 | 3222 | var rightmost_op = first_op; |
| 3229 | 3223 | while (true) { |
| 3230 | 3224 | 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).?; | |
| 3233 | 3299 | // 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).?; | |
| 3237 | 3303 | } |
| 3238 | 3304 | if (try opParseFn(p)) |rhs| { |
| 3239 | prefix_op.rhs = rhs; | |
| 3305 | ptr_type.rhs = rhs; | |
| 3240 | 3306 | rightmost_op = rhs; |
| 3241 | 3307 | } else break; |
| 3242 | 3308 | }, |
| ... | ... | @@ -3253,8 +3319,80 @@ const Parser = struct { |
| 3253 | 3319 | |
| 3254 | 3320 | // If any prefix op existed, a child node on the RHS is required |
| 3255 | 3321 | 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).?; | |
| 3258 | 3396 | prefix_op.rhs = try p.expectNode(childParseFn, .{ |
| 3259 | 3397 | .InvalidToken = .{ .token = p.tok_i }, |
| 3260 | 3398 | }); |
lib/std/zig/render.zig+211-145| ... | ... | @@ -468,166 +468,192 @@ fn renderExpression( |
| 468 | 468 | return renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.rhs, space); |
| 469 | 469 | }, |
| 470 | 470 | |
| 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 | }, | |
| 514 | 516 | |
| 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 | }, | |
| 519 | 547 | |
| 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); | |
| 534 | 579 | |
| 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); // ( | |
| 545 | 582 | |
| 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); | |
| 552 | 584 | |
| 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()); | |
| 555 | 588 | |
| 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); | |
| 557 | 593 | |
| 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 | }, | |
| 561 | 609 | |
| 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 | } | |
| 566 | 621 | |
| 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); | |
| 581 | 628 | |
| 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); // ( | |
| 588 | 631 | |
| 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); | |
| 590 | 633 | |
| 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()); | |
| 618 | 637 | |
| 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); | |
| 624 | 642 | |
| 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 | } | |
| 628 | 649 | } |
| 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); | |
| 631 | 657 | }, |
| 632 | 658 | |
| 633 | 659 | .ArrayInitializer, .ArrayInitializerDot => { |
| ... | ... | @@ -2057,6 +2083,46 @@ fn renderExpression( |
| 2057 | 2083 | } |
| 2058 | 2084 | } |
| 2059 | 2085 | |
| 2086 | fn 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 | ||
| 2060 | 2126 | fn renderAsmOutput( |
| 2061 | 2127 | allocator: *mem.Allocator, |
| 2062 | 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 | 1308 | .ControlFlowExpression => return self.astGenControlFlowExpression(scope, @fieldParentPtr(ast.Node.ControlFlowExpression, "base", ast_node)), |
| 1309 | 1309 | .If => return self.astGenIf(scope, @fieldParentPtr(ast.Node.If, "base", ast_node)), |
| 1310 | 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 | 1312 | else => return self.failNode(scope, ast_node, "TODO implement astGenExpr for {}", .{@tagName(ast_node.id)}), |
| 1312 | 1313 | } |
| 1313 | 1314 | } |
| 1314 | 1315 | |
| 1316 | fn 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 | ||
| 1315 | 1323 | fn astGenInfixOp(self: *Module, scope: *Scope, infix_node: *ast.Node.InfixOp) InnerError!*zir.Inst { |
| 1316 | 1324 | switch (infix_node.op) { |
| 1317 | 1325 | .Assign => { |
src-self-hosted/translate_c.zig+80-87| ... | ... | @@ -1561,7 +1561,7 @@ fn transImplicitCastExpr( |
| 1561 | 1561 | return maybeSuppressResult(rp, scope, result_used, sub_expr_node); |
| 1562 | 1562 | } |
| 1563 | 1563 | |
| 1564 | const prefix_op = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&"); | |
| 1564 | const prefix_op = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&"); | |
| 1565 | 1565 | prefix_op.rhs = try transExpr(rp, scope, sub_expr, .used, .r_value); |
| 1566 | 1566 | |
| 1567 | 1567 | return maybeSuppressResult(rp, scope, result_used, &prefix_op.base); |
| ... | ... | @@ -1673,11 +1673,7 @@ fn isBoolRes(res: *ast.Node) bool { |
| 1673 | 1673 | |
| 1674 | 1674 | else => {}, |
| 1675 | 1675 | }, |
| 1676 | .PrefixOp => switch (@fieldParentPtr(ast.Node.PrefixOp, "base", res).op) { | |
| 1677 | .BoolNot => return true, | |
| 1678 | ||
| 1679 | else => {}, | |
| 1680 | }, | |
| 1676 | .BoolNot => return true, | |
| 1681 | 1677 | .BoolLiteral => return true, |
| 1682 | 1678 | .GroupedExpression => return isBoolRes(@fieldParentPtr(ast.Node.GroupedExpression, "base", res).expr), |
| 1683 | 1679 | else => {}, |
| ... | ... | @@ -2162,21 +2158,16 @@ fn transCreateNodeArrayType( |
| 2162 | 2158 | source_loc: ZigClangSourceLocation, |
| 2163 | 2159 | ty: *const ZigClangType, |
| 2164 | 2160 | 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); | |
| 2178 | 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 | 2171 | return &node.base; |
| 2181 | 2172 | } |
| 2182 | 2173 | |
| ... | ... | @@ -2449,7 +2440,7 @@ fn transDoWhileLoop( |
| 2449 | 2440 | }, |
| 2450 | 2441 | }; |
| 2451 | 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 | 2444 | prefix_op.rhs = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true); |
| 2454 | 2445 | _ = try appendToken(rp.c, .RParen, ")"); |
| 2455 | 2446 | if_node.condition = &prefix_op.base; |
| ... | ... | @@ -3036,7 +3027,7 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar |
| 3036 | 3027 | else |
| 3037 | 3028 | return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used), |
| 3038 | 3029 | .AddrOf => { |
| 3039 | const op_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&"); | |
| 3030 | const op_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&"); | |
| 3040 | 3031 | op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value); |
| 3041 | 3032 | return &op_node.base; |
| 3042 | 3033 | }, |
| ... | ... | @@ -3052,7 +3043,7 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar |
| 3052 | 3043 | .Plus => return transExpr(rp, scope, op_expr, used, .r_value), |
| 3053 | 3044 | .Minus => { |
| 3054 | 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 | 3047 | op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value); |
| 3057 | 3048 | return &op_node.base; |
| 3058 | 3049 | } else if (cIsUnsignedInteger(ZigClangExpr_getType(op_expr))) { |
| ... | ... | @@ -3065,12 +3056,12 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar |
| 3065 | 3056 | return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangUnaryOperator_getBeginLoc(stmt), "C negation with non float non integer", .{}); |
| 3066 | 3057 | }, |
| 3067 | 3058 | .Not => { |
| 3068 | const op_node = try transCreateNodePrefixOp(rp.c, .BitNot, .Tilde, "~"); | |
| 3059 | const op_node = try transCreateNodeSimplePrefixOp(rp.c, .BitNot, .Tilde, "~"); | |
| 3069 | 3060 | op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value); |
| 3070 | 3061 | return &op_node.base; |
| 3071 | 3062 | }, |
| 3072 | 3063 | .LNot => { |
| 3073 | const op_node = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!"); | |
| 3064 | const op_node = try transCreateNodeSimplePrefixOp(rp.c, .BoolNot, .Bang, "!"); | |
| 3074 | 3065 | op_node.rhs = try transBoolExpr(rp, scope, op_expr, .used, .r_value, true); |
| 3075 | 3066 | return &op_node.base; |
| 3076 | 3067 | }, |
| ... | ... | @@ -3116,7 +3107,7 @@ fn transCreatePreCrement( |
| 3116 | 3107 | |
| 3117 | 3108 | const node = try transCreateNodeVarDecl(rp.c, false, true, ref); |
| 3118 | 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 | 3111 | rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value); |
| 3121 | 3112 | node.init_node = &rhs_node.base; |
| 3122 | 3113 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); |
| ... | ... | @@ -3182,7 +3173,7 @@ fn transCreatePostCrement( |
| 3182 | 3173 | |
| 3183 | 3174 | const node = try transCreateNodeVarDecl(rp.c, false, true, ref); |
| 3184 | 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 | 3177 | rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value); |
| 3187 | 3178 | node.init_node = &rhs_node.base; |
| 3188 | 3179 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); |
| ... | ... | @@ -3336,7 +3327,7 @@ fn transCreateCompoundAssign( |
| 3336 | 3327 | |
| 3337 | 3328 | const node = try transCreateNodeVarDecl(rp.c, false, true, ref); |
| 3338 | 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 | 3331 | addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value); |
| 3341 | 3332 | node.init_node = &addr_node.base; |
| 3342 | 3333 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); |
| ... | ... | @@ -3984,16 +3975,15 @@ fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []c |
| 3984 | 3975 | return &field_access_node.base; |
| 3985 | 3976 | } |
| 3986 | 3977 | |
| 3987 | fn transCreateNodePrefixOp( | |
| 3978 | fn transCreateNodeSimplePrefixOp( | |
| 3988 | 3979 | c: *Context, |
| 3989 | op: ast.Node.PrefixOp.Op, | |
| 3980 | comptime tag: ast.Node.Id, | |
| 3990 | 3981 | op_tok_id: std.zig.Token.Id, |
| 3991 | 3982 | 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)); | |
| 3994 | 3985 | node.* = .{ |
| 3995 | 3986 | .op_token = try appendToken(c, op_tok_id, bytes), |
| 3996 | .op = op, | |
| 3997 | 3987 | .rhs = undefined, // translate and set afterward |
| 3998 | 3988 | }; |
| 3999 | 3989 | return node; |
| ... | ... | @@ -4065,8 +4055,8 @@ fn transCreateNodePtrType( |
| 4065 | 4055 | is_const: bool, |
| 4066 | 4056 | is_volatile: bool, |
| 4067 | 4057 | 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); | |
| 4070 | 4060 | const op_token = switch (op_tok_id) { |
| 4071 | 4061 | .LBracket => blk: { |
| 4072 | 4062 | const lbracket = try appendToken(c, .LBracket, "["); |
| ... | ... | @@ -4086,11 +4076,9 @@ fn transCreateNodePtrType( |
| 4086 | 4076 | }; |
| 4087 | 4077 | node.* = .{ |
| 4088 | 4078 | .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, | |
| 4094 | 4082 | }, |
| 4095 | 4083 | .rhs = undefined, // translate and set afterward |
| 4096 | 4084 | }; |
| ... | ... | @@ -4569,12 +4557,12 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 4569 | 4557 | .Pointer => { |
| 4570 | 4558 | const child_qt = ZigClangType_getPointeeType(ty); |
| 4571 | 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 | 4561 | optional_node.rhs = try transQualType(rp, child_qt, source_loc); |
| 4574 | 4562 | return &optional_node.base; |
| 4575 | 4563 | } |
| 4576 | 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 | 4566 | const pointer_node = try transCreateNodePtrType( |
| 4579 | 4567 | rp.c, |
| 4580 | 4568 | ZigClangQualType_isConstQualified(child_qt), |
| ... | ... | @@ -4599,21 +4587,8 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 4599 | 4587 | |
| 4600 | 4588 | const size_ap_int = ZigClangConstantArrayType_getSize(const_arr_ty); |
| 4601 | 4589 | 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); | |
| 4617 | 4592 | }, |
| 4618 | 4593 | .IncompleteArray => { |
| 4619 | 4594 | const incomplete_array_ty = @ptrCast(*const ZigClangIncompleteArrayType, ty); |
| ... | ... | @@ -5824,7 +5799,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5824 | 5799 | if (prev_id == .Keyword_void) { |
| 5825 | 5800 | const ptr = try transCreateNodePtrType(c, false, false, .Asterisk); |
| 5826 | 5801 | ptr.rhs = node; |
| 5827 | const optional_node = try transCreateNodePrefixOp(c, .OptionalType, .QuestionMark, "?"); | |
| 5802 | const optional_node = try transCreateNodeSimplePrefixOp(c, .OptionalType, .QuestionMark, "?"); | |
| 5828 | 5803 | optional_node.rhs = &ptr.base; |
| 5829 | 5804 | return &optional_node.base; |
| 5830 | 5805 | } else { |
| ... | ... | @@ -5993,18 +5968,18 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5993 | 5968 | |
| 5994 | 5969 | switch (op_tok.id) { |
| 5995 | 5970 | .Bang => { |
| 5996 | const node = try transCreateNodePrefixOp(c, .BoolNot, .Bang, "!"); | |
| 5971 | const node = try transCreateNodeSimplePrefixOp(c, .BoolNot, .Bang, "!"); | |
| 5997 | 5972 | node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope); |
| 5998 | 5973 | return &node.base; |
| 5999 | 5974 | }, |
| 6000 | 5975 | .Minus => { |
| 6001 | const node = try transCreateNodePrefixOp(c, .Negation, .Minus, "-"); | |
| 5976 | const node = try transCreateNodeSimplePrefixOp(c, .Negation, .Minus, "-"); | |
| 6002 | 5977 | node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope); |
| 6003 | 5978 | return &node.base; |
| 6004 | 5979 | }, |
| 6005 | 5980 | .Plus => return try parseCPrefixOpExpr(c, it, source, source_loc, scope), |
| 6006 | 5981 | .Tilde => { |
| 6007 | const node = try transCreateNodePrefixOp(c, .BitNot, .Tilde, "~"); | |
| 5982 | const node = try transCreateNodeSimplePrefixOp(c, .BitNot, .Tilde, "~"); | |
| 6008 | 5983 | node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope); |
| 6009 | 5984 | return &node.base; |
| 6010 | 5985 | }, |
| ... | ... | @@ -6013,7 +5988,7 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 6013 | 5988 | return try transCreateNodePtrDeref(c, node); |
| 6014 | 5989 | }, |
| 6015 | 5990 | .Ampersand => { |
| 6016 | const node = try transCreateNodePrefixOp(c, .AddressOf, .Ampersand, "&"); | |
| 5991 | const node = try transCreateNodeSimplePrefixOp(c, .AddressOf, .Ampersand, "&"); | |
| 6017 | 5992 | node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope); |
| 6018 | 5993 | return &node.base; |
| 6019 | 5994 | }, |
| ... | ... | @@ -6034,29 +6009,49 @@ fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 { |
| 6034 | 6009 | } |
| 6035 | 6010 | |
| 6036 | 6011 | fn 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 | } | |
| 6056 | 6049 | } |
| 6057 | 6050 | } |
| 6058 | 6051 | } |
| 6059 | } | |
| 6052 | }, | |
| 6053 | ||
| 6054 | else => {}, | |
| 6060 | 6055 | } |
| 6061 | 6056 | return null; |
| 6062 | 6057 | } |
| ... | ... | @@ -6091,11 +6086,9 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node { |
| 6091 | 6086 | fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto { |
| 6092 | 6087 | const init = if (ref.cast(ast.Node.VarDecl)) |v| v.init_node.? else return null; |
| 6093 | 6088 | 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; | |
| 6099 | 6092 | } |
| 6100 | 6093 | } |
| 6101 | 6094 | } |