| 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,7 +410,20 @@ pub const Node = struct { |
| 410 | 410 | ||
| 411 | // Operators | 411 | // 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, some | 427 | /// 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 | }; |
| 1799 | 1812 | ||
| 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, | ||
| 1805 | 1851 | ||
| 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 | }; | ||
| 1820 | 1854 | ||
| 1821 | pub const ArrayInfo = struct { | 1855 | if (i < 1) return self.len_expr; |
| 1822 | len_expr: *Node, | 1856 | i -= 1; |
| 1823 | sentinel: ?*Node, | ||
| 1824 | }; | ||
| 1825 | 1857 | ||
| 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 | }; | ||
| 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 | var i = index; | 1881 | var i = index; |
| 1846 | 1882 | ||
| 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 | } | ||
| 1853 | 1885 | ||
| 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 | }, | ||
| 1859 | 1888 | ||
| 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 | }, | ||
| 1868 | 1891 | ||
| 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 | } |
| 1880 | 1924 | ||
| 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 | } |
| 1886 | 1930 | ||
| 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 | } |
| 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 | 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 | }; |
| 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 | test "iterate" { | 2898 | test "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_await | 2412 | /// / 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 | } | ||
| 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 | node.* = .{ | 2432 | node.* = .{ |
| 2432 | .op_token = token, | 2433 | .op_token = token, |
| 2433 | .op = op, | ||
| 2434 | .rhs = undefined, // set by caller | 2434 | .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 caller | 2456 | .rhs = undefined, // set by caller |
| 2458 | }; | 2457 | }; |
| 2459 | return &node.base; | 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 | 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.PtrType | 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 | else | 2487 | else |
| 2489 | &prefix_op.op.PtrType; | 2488 | unreachable; |
| 2490 | 2489 | ||
| 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 | }); |
| 2507 | 2506 | ||
| 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 | } |
| 2521 | 2520 | ||
| 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 | } |
| 2564 | 2563 | ||
| 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 duplicates | 2568 | 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); |
| 2730 | 2725 | ||
| 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 | else | 2745 | } |
| 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 | }; | ||
| 2748 | 2746 | ||
| 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 caller | 2750 | .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 | else | 2767 | 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 caller | 2772 | .rhs = undefined, // set by caller |
| 2773 | .ptr_info = .{ .sentinel = sentinel }, | ||
| 2776 | }; | 2774 | }; |
| 2777 | return &node.base; | 2775 | return &node.base; |
| 2778 | } | 2776 | } |
| 2779 | 2777 | ||
| 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 caller | 2782 | .rhs = undefined, // set by caller |
| 2786 | }; | 2783 | }; |
| 2787 | 2784 | ||
| 2788 | // Special case for **, which is its own token | 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 | child.* = .{ | 2787 | child.* = .{ |
| 2791 | .op_token = double_asterisk, | 2788 | .op_token = double_asterisk, |
| 2792 | .op = .{ .PtrType = .{} }, | ||
| 2793 | .rhs = undefined, // set by caller | 2789 | .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 caller | 2810 | .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 | else | 2819 | 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 caller | 2825 | .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 { |
| 3146 | 3141 | ||
| 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 caller | 3147 | .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 nodes | 3299 | // 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 { |
| 3253 | 3319 | ||
| 3254 | // If any prefix op existed, a child node on the RHS is required | 3320 | // 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 | }, |
| 470 | 470 | ||
| 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); |
| 473 | 473 | 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 | else | 481 | .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); // allowzero | 500 | }, |
| 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); |
| 505 | 505 | }, | |
| 506 | try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align | 506 | .Resume => { |
| 507 | try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // ( | 507 | const resume_node = @fieldParentPtr(ast.Node.Resume, "base", base); |
| 508 | 508 | 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); |
| 510 | 510 | }, | |
| 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 | }, | ||
| 514 | 516 | ||
| 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 | }, | ||
| 519 | 547 | ||
| 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); // const | 556 | 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); // volatile | 559 | 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); | ||
| 534 | 579 | ||
| 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 | } | ||
| 545 | 582 | ||
| 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); | ||
| 552 | 584 | ||
| 553 | try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align | 585 | 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()); | ||
| 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| { | 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 | }, | ||
| 561 | 609 | ||
| 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 | } | ||
| 566 | 621 | ||
| 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 | }, | ||
| 581 | 628 | ||
| 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()); | ||
| 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; | 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 | }, | ||
| 618 | 637 | ||
| 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 | }, | ||
| 624 | 642 | ||
| 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 | } |
| 629 | 650 | 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 | }, |
| 632 | 658 | ||
| 633 | .ArrayInitializer, .ArrayInitializerDot => { | 659 | .ArrayInitializer, .ArrayInitializerDot => { |
| ... | @@ -2057,6 +2083,46 @@ fn renderExpression( | ... | @@ -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 | fn renderAsmOutput( | 2126 | fn 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 | } |
| 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 | fn astGenInfixOp(self: *Module, scope: *Scope, infix_node: *ast.Node.InfixOp) InnerError!*zir.Inst { | 1323 | fn 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 | } |
| 1563 | 1563 | ||
| 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); |
| 1566 | 1566 | ||
| 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 { |
| 1673 | 1673 | ||
| 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 | } |
| 2182 | 2173 | ||
| ... | @@ -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 | else | 3027 | 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( |
| 3116 | 3107 | ||
| 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( |
| 3182 | 3173 | ||
| 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( |
| 3336 | 3327 | ||
| 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 | } |
| 3986 | 3977 | ||
| 3987 | fn transCreateNodePrefixOp( | 3978 | fn 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 afterward | 3987 | .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 afterward | 4083 | .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 |
| 4599 | 4587 | ||
| 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, |
| 5993 | 5968 | ||
| 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 | } |
| 6035 | 6010 | ||
| 6036 | fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node { | 6011 | fn 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 { |
| 6091 | fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto { | 6086 | fn 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 | } |