| author | |
| committer | |
| log | 67273cbe7618253bffa56298b5bea0e1dd37dfc2 |
| tree | 7da05590dbc3b7f19a4cafdf1496a266bd4621a0 |
| parent | 03f14c3102ccd3e1811ccf4fb7cae11a75d3018f |
| parent | a92990f99312c946b5e527517a27a67a5a5513c0 |
| signature | Signed by PGP key 4AEE18F83AFDEB23 |
Stage2 improvements12 files changed, 1010 insertions(+), 464 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+48-23| ... | @@ -36,7 +36,7 @@ bin_file_path: []const u8, | ... | @@ -36,7 +36,7 @@ bin_file_path: []const u8, |
| 36 | decl_exports: std.AutoHashMapUnmanaged(*Decl, []*Export) = .{}, | 36 | decl_exports: std.AutoHashMapUnmanaged(*Decl, []*Export) = .{}, |
| 37 | /// We track which export is associated with the given symbol name for quick | 37 | /// We track which export is associated with the given symbol name for quick |
| 38 | /// detection of symbol collisions. | 38 | /// detection of symbol collisions. |
| 39 | symbol_exports: std.StringHashMap(*Export), | 39 | symbol_exports: std.StringHashMapUnmanaged(*Export) = .{}, |
| 40 | /// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl | 40 | /// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl |
| 41 | /// is modified. Note that the key of this table is not the Decl being exported, but the Decl that | 41 | /// is modified. Note that the key of this table is not the Decl being exported, but the Decl that |
| 42 | /// is performing the export of another Decl. | 42 | /// is performing the export of another Decl. |
| ... | @@ -769,7 +769,6 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module { | ... | @@ -769,7 +769,6 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module { |
| 769 | .bin_file_path = options.bin_file_path, | 769 | .bin_file_path = options.bin_file_path, |
| 770 | .bin_file = bin_file, | 770 | .bin_file = bin_file, |
| 771 | .optimize_mode = options.optimize_mode, | 771 | .optimize_mode = options.optimize_mode, |
| 772 | .symbol_exports = std.StringHashMap(*Export).init(gpa), | ||
| 773 | .work_queue = std.fifo.LinearFifo(WorkItem, .Dynamic).init(gpa), | 772 | .work_queue = std.fifo.LinearFifo(WorkItem, .Dynamic).init(gpa), |
| 774 | .keep_source_files_loaded = options.keep_source_files_loaded, | 773 | .keep_source_files_loaded = options.keep_source_files_loaded, |
| 775 | }; | 774 | }; |
| ... | @@ -812,7 +811,7 @@ pub fn deinit(self: *Module) void { | ... | @@ -812,7 +811,7 @@ pub fn deinit(self: *Module) void { |
| 812 | } | 811 | } |
| 813 | self.export_owners.deinit(gpa); | 812 | self.export_owners.deinit(gpa); |
| 814 | 813 | ||
| 815 | self.symbol_exports.deinit(); | 814 | self.symbol_exports.deinit(gpa); |
| 816 | self.root_scope.destroy(gpa); | 815 | self.root_scope.destroy(gpa); |
| 817 | self.* = undefined; | 816 | self.* = undefined; |
| 818 | } | 817 | } |
| ... | @@ -1309,10 +1308,18 @@ fn astGenExpr(self: *Module, scope: *Scope, ast_node: *ast.Node) InnerError!*zir | ... | @@ -1309,10 +1308,18 @@ fn astGenExpr(self: *Module, scope: *Scope, ast_node: *ast.Node) InnerError!*zir |
| 1309 | .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)), |
| 1310 | .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)), |
| 1311 | .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)), | ||
| 1312 | 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)}), |
| 1313 | } | 1313 | } |
| 1314 | } | 1314 | } |
| 1315 | 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 | |||
| 1316 | 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 { |
| 1317 | switch (infix_node.op) { | 1324 | switch (infix_node.op) { |
| 1318 | .Assign => { | 1325 | .Assign => { |
| ... | @@ -1351,17 +1358,19 @@ fn astGenInfixOp(self: *Module, scope: *Scope, infix_node: *ast.Node.InfixOp) In | ... | @@ -1351,17 +1358,19 @@ fn astGenInfixOp(self: *Module, scope: *Scope, infix_node: *ast.Node.InfixOp) In |
| 1351 | const tree = scope.tree(); | 1358 | const tree = scope.tree(); |
| 1352 | const src = tree.token_locs[infix_node.op_token].start; | 1359 | const src = tree.token_locs[infix_node.op_token].start; |
| 1353 | 1360 | ||
| 1361 | const op: std.math.CompareOperator = switch (infix_node.op) { | ||
| 1362 | .BangEqual => .neq, | ||
| 1363 | .EqualEqual => .eq, | ||
| 1364 | .GreaterThan => .gt, | ||
| 1365 | .GreaterOrEqual => .gte, | ||
| 1366 | .LessThan => .lt, | ||
| 1367 | .LessOrEqual => .lte, | ||
| 1368 | else => unreachable, | ||
| 1369 | }; | ||
| 1370 | |||
| 1354 | return self.addZIRInst(scope, src, zir.Inst.Cmp, .{ | 1371 | return self.addZIRInst(scope, src, zir.Inst.Cmp, .{ |
| 1355 | .lhs = lhs, | 1372 | .lhs = lhs, |
| 1356 | .op = @as(std.math.CompareOperator, switch (infix_node.op) { | 1373 | .op = op, |
| 1357 | .BangEqual => .neq, | ||
| 1358 | .EqualEqual => .eq, | ||
| 1359 | .GreaterThan => .gt, | ||
| 1360 | .GreaterOrEqual => .gte, | ||
| 1361 | .LessThan => .lt, | ||
| 1362 | .LessOrEqual => .lte, | ||
| 1363 | else => unreachable, | ||
| 1364 | }), | ||
| 1365 | .rhs = rhs, | 1374 | .rhs = rhs, |
| 1366 | }, .{}); | 1375 | }, .{}); |
| 1367 | }, | 1376 | }, |
| ... | @@ -1408,11 +1417,13 @@ fn astGenIf(self: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir | ... | @@ -1408,11 +1417,13 @@ fn astGenIf(self: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir |
| 1408 | defer then_scope.instructions.deinit(self.gpa); | 1417 | defer then_scope.instructions.deinit(self.gpa); |
| 1409 | 1418 | ||
| 1410 | const then_result = try self.astGenExpr(&then_scope.base, if_node.body); | 1419 | const then_result = try self.astGenExpr(&then_scope.base, if_node.body); |
| 1411 | const then_src = tree.token_locs[if_node.body.lastToken()].start; | 1420 | if (!then_result.tag.isNoReturn()) { |
| 1412 | _ = try self.addZIRInst(&then_scope.base, then_src, zir.Inst.Break, .{ | 1421 | const then_src = tree.token_locs[if_node.body.lastToken()].start; |
| 1413 | .block = block, | 1422 | _ = try self.addZIRInst(&then_scope.base, then_src, zir.Inst.Break, .{ |
| 1414 | .operand = then_result, | 1423 | .block = block, |
| 1415 | }, .{}); | 1424 | .operand = then_result, |
| 1425 | }, .{}); | ||
| 1426 | } | ||
| 1416 | condbr.positionals.true_body = .{ | 1427 | condbr.positionals.true_body = .{ |
| 1417 | .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items), | 1428 | .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items), |
| 1418 | }; | 1429 | }; |
| ... | @@ -1426,11 +1437,13 @@ fn astGenIf(self: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir | ... | @@ -1426,11 +1437,13 @@ fn astGenIf(self: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir |
| 1426 | 1437 | ||
| 1427 | if (if_node.@"else") |else_node| { | 1438 | if (if_node.@"else") |else_node| { |
| 1428 | const else_result = try self.astGenExpr(&else_scope.base, else_node.body); | 1439 | const else_result = try self.astGenExpr(&else_scope.base, else_node.body); |
| 1429 | const else_src = tree.token_locs[else_node.body.lastToken()].start; | 1440 | if (!else_result.tag.isNoReturn()) { |
| 1430 | _ = try self.addZIRInst(&else_scope.base, else_src, zir.Inst.Break, .{ | 1441 | const else_src = tree.token_locs[else_node.body.lastToken()].start; |
| 1431 | .block = block, | 1442 | _ = try self.addZIRInst(&else_scope.base, else_src, zir.Inst.Break, .{ |
| 1432 | .operand = else_result, | 1443 | .block = block, |
| 1433 | }, .{}); | 1444 | .operand = else_result, |
| 1445 | }, .{}); | ||
| 1446 | } | ||
| 1434 | } else { | 1447 | } else { |
| 1435 | // TODO Optimization opportunity: we can avoid an allocation and a memcpy here | 1448 | // TODO Optimization opportunity: we can avoid an allocation and a memcpy here |
| 1436 | // by directly allocating the body for this one instruction. | 1449 | // by directly allocating the body for this one instruction. |
| ... | @@ -2305,7 +2318,7 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const | ... | @@ -2305,7 +2318,7 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const |
| 2305 | return; | 2318 | return; |
| 2306 | } | 2319 | } |
| 2307 | 2320 | ||
| 2308 | try self.symbol_exports.putNoClobber(symbol_name, new_export); | 2321 | try self.symbol_exports.putNoClobber(self.gpa, symbol_name, new_export); |
| 2309 | self.bin_file.updateDeclExports(self, exported_decl, de_gop.entry.value) catch |err| switch (err) { | 2322 | self.bin_file.updateDeclExports(self, exported_decl, de_gop.entry.value) catch |err| switch (err) { |
| 2310 | error.OutOfMemory => return error.OutOfMemory, | 2323 | error.OutOfMemory => return error.OutOfMemory, |
| 2311 | else => { | 2324 | else => { |
| ... | @@ -2559,6 +2572,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In | ... | @@ -2559,6 +2572,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In |
| 2559 | .condbr => return self.analyzeInstCondBr(scope, old_inst.cast(zir.Inst.CondBr).?), | 2572 | .condbr => return self.analyzeInstCondBr(scope, old_inst.cast(zir.Inst.CondBr).?), |
| 2560 | .isnull => return self.analyzeInstIsNull(scope, old_inst.cast(zir.Inst.IsNull).?), | 2573 | .isnull => return self.analyzeInstIsNull(scope, old_inst.cast(zir.Inst.IsNull).?), |
| 2561 | .isnonnull => return self.analyzeInstIsNonNull(scope, old_inst.cast(zir.Inst.IsNonNull).?), | 2574 | .isnonnull => return self.analyzeInstIsNonNull(scope, old_inst.cast(zir.Inst.IsNonNull).?), |
| 2575 | .boolnot => return self.analyzeInstBoolNot(scope, old_inst.cast(zir.Inst.BoolNot).?), | ||
| 2562 | } | 2576 | } |
| 2563 | } | 2577 | } |
| 2564 | 2578 | ||
| ... | @@ -3236,6 +3250,17 @@ fn analyzeInstCmp(self: *Module, scope: *Scope, inst: *zir.Inst.Cmp) InnerError! | ... | @@ -3236,6 +3250,17 @@ fn analyzeInstCmp(self: *Module, scope: *Scope, inst: *zir.Inst.Cmp) InnerError! |
| 3236 | return self.fail(scope, inst.base.src, "TODO implement more cmp analysis", .{}); | 3250 | return self.fail(scope, inst.base.src, "TODO implement more cmp analysis", .{}); |
| 3237 | } | 3251 | } |
| 3238 | 3252 | ||
| 3253 | fn analyzeInstBoolNot(self: *Module, scope: *Scope, inst: *zir.Inst.BoolNot) InnerError!*Inst { | ||
| 3254 | const uncasted_operand = try self.resolveInst(scope, inst.positionals.operand); | ||
| 3255 | const bool_type = Type.initTag(.bool); | ||
| 3256 | const operand = try self.coerce(scope, bool_type, uncasted_operand); | ||
| 3257 | if (try self.resolveDefinedValue(scope, operand)) |val| { | ||
| 3258 | return self.constBool(scope, inst.base.src, !val.toBool()); | ||
| 3259 | } | ||
| 3260 | const b = try self.requireRuntimeBlock(scope, inst.base.src); | ||
| 3261 | return self.addNewInstArgs(b, inst.base.src, bool_type, Inst.Not, .{ .operand = operand }); | ||
| 3262 | } | ||
| 3263 | |||
| 3239 | fn analyzeInstIsNull(self: *Module, scope: *Scope, inst: *zir.Inst.IsNull) InnerError!*Inst { | 3264 | fn analyzeInstIsNull(self: *Module, scope: *Scope, inst: *zir.Inst.IsNull) InnerError!*Inst { |
| 3240 | const operand = try self.resolveInst(scope, inst.positionals.operand); | 3265 | const operand = try self.resolveInst(scope, inst.positionals.operand); |
| 3241 | return self.analyzeIsNull(scope, inst.base.src, operand, true); | 3266 | return self.analyzeIsNull(scope, inst.base.src, operand, true); |
src-self-hosted/codegen.zig+82-4| ... | @@ -407,6 +407,55 @@ const Function = struct { | ... | @@ -407,6 +407,55 @@ const Function = struct { |
| 407 | .retvoid => return self.genRetVoid(inst.cast(ir.Inst.RetVoid).?, arch), | 407 | .retvoid => return self.genRetVoid(inst.cast(ir.Inst.RetVoid).?, arch), |
| 408 | .sub => return self.genSub(inst.cast(ir.Inst.Sub).?, arch), | 408 | .sub => return self.genSub(inst.cast(ir.Inst.Sub).?, arch), |
| 409 | .unreach => return MCValue{ .unreach = {} }, | 409 | .unreach => return MCValue{ .unreach = {} }, |
| 410 | .not => return self.genNot(inst.cast(ir.Inst.Not).?, arch), | ||
| 411 | } | ||
| 412 | } | ||
| 413 | |||
| 414 | fn genNot(self: *Function, inst: *ir.Inst.Not, comptime arch: std.Target.Cpu.Arch) !MCValue { | ||
| 415 | // No side effects, so if it's unreferenced, do nothing. | ||
| 416 | if (inst.base.isUnused()) | ||
| 417 | return MCValue.dead; | ||
| 418 | const operand = try self.resolveInst(inst.args.operand); | ||
| 419 | switch (operand) { | ||
| 420 | .dead => unreachable, | ||
| 421 | .unreach => unreachable, | ||
| 422 | .compare_flags_unsigned => |op| return MCValue{ | ||
| 423 | .compare_flags_unsigned = switch (op) { | ||
| 424 | .gte => .lt, | ||
| 425 | .gt => .lte, | ||
| 426 | .neq => .eq, | ||
| 427 | .lt => .gte, | ||
| 428 | .lte => .gt, | ||
| 429 | .eq => .neq, | ||
| 430 | }, | ||
| 431 | }, | ||
| 432 | .compare_flags_signed => |op| return MCValue{ | ||
| 433 | .compare_flags_signed = switch (op) { | ||
| 434 | .gte => .lt, | ||
| 435 | .gt => .lte, | ||
| 436 | .neq => .eq, | ||
| 437 | .lt => .gte, | ||
| 438 | .lte => .gt, | ||
| 439 | .eq => .neq, | ||
| 440 | }, | ||
| 441 | }, | ||
| 442 | else => {}, | ||
| 443 | } | ||
| 444 | |||
| 445 | switch (arch) { | ||
| 446 | .x86_64 => { | ||
| 447 | var imm = ir.Inst.Constant{ | ||
| 448 | .base = .{ | ||
| 449 | .tag = .constant, | ||
| 450 | .deaths = 0, | ||
| 451 | .ty = inst.args.operand.ty, | ||
| 452 | .src = inst.args.operand.src, | ||
| 453 | }, | ||
| 454 | .val = Value.initTag(.bool_true), | ||
| 455 | }; | ||
| 456 | return try self.genX8664BinMath(&inst.base, inst.args.operand, &imm.base, 6, 0x30); | ||
| 457 | }, | ||
| 458 | else => return self.fail(inst.base.src, "TODO implement NOT for {}", .{self.target.cpu.arch}), | ||
| 410 | } | 459 | } |
| 411 | } | 460 | } |
| 412 | 461 | ||
| ... | @@ -434,7 +483,7 @@ const Function = struct { | ... | @@ -434,7 +483,7 @@ const Function = struct { |
| 434 | } | 483 | } |
| 435 | } | 484 | } |
| 436 | 485 | ||
| 437 | /// ADD, SUB | 486 | /// ADD, SUB, XOR, OR, AND |
| 438 | fn genX8664BinMath(self: *Function, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst, opx: u8, mr: u8) !MCValue { | 487 | fn genX8664BinMath(self: *Function, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst, opx: u8, mr: u8) !MCValue { |
| 439 | try self.code.ensureCapacity(self.code.items.len + 8); | 488 | try self.code.ensureCapacity(self.code.items.len + 8); |
| 440 | 489 | ||
| ... | @@ -695,7 +744,7 @@ const Function = struct { | ... | @@ -695,7 +744,7 @@ const Function = struct { |
| 695 | 744 | ||
| 696 | fn genCondBr(self: *Function, inst: *ir.Inst.CondBr, comptime arch: std.Target.Cpu.Arch) !MCValue { | 745 | fn genCondBr(self: *Function, inst: *ir.Inst.CondBr, comptime arch: std.Target.Cpu.Arch) !MCValue { |
| 697 | switch (arch) { | 746 | switch (arch) { |
| 698 | .i386, .x86_64 => { | 747 | .x86_64 => { |
| 699 | try self.code.ensureCapacity(self.code.items.len + 6); | 748 | try self.code.ensureCapacity(self.code.items.len + 6); |
| 700 | 749 | ||
| 701 | const cond = try self.resolveInst(inst.args.condition); | 750 | const cond = try self.resolveInst(inst.args.condition); |
| ... | @@ -724,7 +773,20 @@ const Function = struct { | ... | @@ -724,7 +773,20 @@ const Function = struct { |
| 724 | }; | 773 | }; |
| 725 | return self.genX86CondBr(inst, opcode, arch); | 774 | return self.genX86CondBr(inst, opcode, arch); |
| 726 | }, | 775 | }, |
| 727 | else => return self.fail(inst.base.src, "TODO implement condbr {} when condition not already in the compare flags", .{self.target.cpu.arch}), | 776 | .register => |reg_usize| { |
| 777 | const reg = @intToEnum(Reg(arch), @intCast(u8, reg_usize)); | ||
| 778 | // test reg, 1 | ||
| 779 | // TODO detect al, ax, eax | ||
| 780 | try self.code.ensureCapacity(self.code.items.len + 4); | ||
| 781 | self.rex(.{ .b = reg.isExtended(), .w = reg.size() == 64 }); | ||
| 782 | self.code.appendSliceAssumeCapacity(&[_]u8{ | ||
| 783 | 0xf6, | ||
| 784 | @as(u8, 0xC0) | (0 << 3) | @truncate(u3, reg.id()), | ||
| 785 | 0x01, | ||
| 786 | }); | ||
| 787 | return self.genX86CondBr(inst, 0x84, arch); | ||
| 788 | }, | ||
| 789 | else => return self.fail(inst.base.src, "TODO implement condbr {} when condition is {}", .{ self.target.cpu.arch, @tagName(cond) }), | ||
| 728 | } | 790 | } |
| 729 | }, | 791 | }, |
| 730 | else => return self.fail(inst.base.src, "TODO implement condbr for {}", .{self.target.cpu.arch}), | 792 | else => return self.fail(inst.base.src, "TODO implement condbr for {}", .{self.target.cpu.arch}), |
| ... | @@ -812,6 +874,8 @@ const Function = struct { | ... | @@ -812,6 +874,8 @@ const Function = struct { |
| 812 | } | 874 | } |
| 813 | 875 | ||
| 814 | fn genAsm(self: *Function, inst: *ir.Inst.Assembly, comptime arch: Target.Cpu.Arch) !MCValue { | 876 | fn genAsm(self: *Function, inst: *ir.Inst.Assembly, comptime arch: Target.Cpu.Arch) !MCValue { |
| 877 | if (!inst.args.is_volatile and inst.base.isUnused()) | ||
| 878 | return MCValue.dead; | ||
| 815 | if (arch != .x86_64 and arch != .i386) { | 879 | if (arch != .x86_64 and arch != .i386) { |
| 816 | return self.fail(inst.base.src, "TODO implement inline asm support for more architectures", .{}); | 880 | return self.fail(inst.base.src, "TODO implement inline asm support for more architectures", .{}); |
| 817 | } | 881 | } |
| ... | @@ -880,7 +944,18 @@ const Function = struct { | ... | @@ -880,7 +944,18 @@ const Function = struct { |
| 880 | .none => unreachable, | 944 | .none => unreachable, |
| 881 | .unreach => unreachable, | 945 | .unreach => unreachable, |
| 882 | .compare_flags_unsigned => |op| { | 946 | .compare_flags_unsigned => |op| { |
| 883 | return self.fail(src, "TODO set register with compare flags value (unsigned)", .{}); | 947 | try self.code.ensureCapacity(self.code.items.len + 3); |
| 948 | self.rex(.{ .b = reg.isExtended(), .w = reg.size() == 64 }); | ||
| 949 | const opcode: u8 = switch (op) { | ||
| 950 | .gte => 0x93, | ||
| 951 | .gt => 0x97, | ||
| 952 | .neq => 0x95, | ||
| 953 | .lt => 0x92, | ||
| 954 | .lte => 0x96, | ||
| 955 | .eq => 0x94, | ||
| 956 | }; | ||
| 957 | const id = @as(u8, reg.id() & 0b111); | ||
| 958 | self.code.appendSliceAssumeCapacity(&[_]u8{ 0x0f, opcode, 0xC0 | id }); | ||
| 884 | }, | 959 | }, |
| 885 | .compare_flags_signed => |op| { | 960 | .compare_flags_signed => |op| { |
| 886 | return self.fail(src, "TODO set register with compare flags value (signed)", .{}); | 961 | return self.fail(src, "TODO set register with compare flags value (signed)", .{}); |
| ... | @@ -1135,6 +1210,9 @@ const Function = struct { | ... | @@ -1135,6 +1210,9 @@ const Function = struct { |
| 1135 | } | 1210 | } |
| 1136 | return MCValue{ .immediate = typed_value.val.toUnsignedInt() }; | 1211 | return MCValue{ .immediate = typed_value.val.toUnsignedInt() }; |
| 1137 | }, | 1212 | }, |
| 1213 | .Bool => { | ||
| 1214 | return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; | ||
| 1215 | }, | ||
| 1138 | .ComptimeInt => unreachable, // semantic analysis prevents this | 1216 | .ComptimeInt => unreachable, // semantic analysis prevents this |
| 1139 | .ComptimeFloat => unreachable, // semantic analysis prevents this | 1217 | .ComptimeFloat => unreachable, // semantic analysis prevents this |
| 1140 | else => return self.fail(src, "TODO implement const of type '{}'", .{typed_value.ty}), | 1218 | else => return self.fail(src, "TODO implement const of type '{}'", .{typed_value.ty}), |
src-self-hosted/ir.zig+23-8| ... | @@ -14,30 +14,35 @@ pub const Inst = struct { | ... | @@ -14,30 +14,35 @@ pub const Inst = struct { |
| 14 | tag: Tag, | 14 | tag: Tag, |
| 15 | /// Each bit represents the index of an `Inst` parameter in the `args` field. | 15 | /// Each bit represents the index of an `Inst` parameter in the `args` field. |
| 16 | /// If a bit is set, it marks the end of the lifetime of the corresponding | 16 | /// If a bit is set, it marks the end of the lifetime of the corresponding |
| 17 | /// instruction parameter. For example, 0b000_00101 means that the first and | 17 | /// instruction parameter. For example, 0b101 means that the first and |
| 18 | /// third `Inst` parameters' lifetimes end after this instruction, and will | 18 | /// third `Inst` parameters' lifetimes end after this instruction, and will |
| 19 | /// not have any more following references. | 19 | /// not have any more following references. |
| 20 | /// The most significant bit being set means that the instruction itself is | 20 | /// The most significant bit being set means that the instruction itself is |
| 21 | /// never referenced, in other words its lifetime ends as soon as it finishes. | 21 | /// never referenced, in other words its lifetime ends as soon as it finishes. |
| 22 | /// If bit 7 (0b1xxx_xxxx) is set, it means this instruction itself is unreferenced. | 22 | /// If bit 15 (0b1xxx_xxxx_xxxx_xxxx) is set, it means this instruction itself is unreferenced. |
| 23 | /// If bit 6 (0bx1xx_xxxx) is set, it means this is a special case and the | 23 | /// If bit 14 (0bx1xx_xxxx_xxxx_xxxx) is set, it means this is a special case and the |
| 24 | /// lifetimes of operands are encoded elsewhere. | 24 | /// lifetimes of operands are encoded elsewhere. |
| 25 | deaths: u8 = undefined, | 25 | deaths: DeathsInt = undefined, |
| 26 | ty: Type, | 26 | ty: Type, |
| 27 | /// Byte offset into the source. | 27 | /// Byte offset into the source. |
| 28 | src: usize, | 28 | src: usize, |
| 29 | 29 | ||
| 30 | pub const DeathsInt = u16; | ||
| 31 | pub const DeathsBitIndex = std.math.Log2Int(DeathsInt); | ||
| 32 | pub const unreferenced_bit_index = @typeInfo(DeathsInt).Int.bits - 1; | ||
| 33 | pub const deaths_bits = unreferenced_bit_index - 1; | ||
| 34 | |||
| 30 | pub fn isUnused(self: Inst) bool { | 35 | pub fn isUnused(self: Inst) bool { |
| 31 | return (self.deaths & 0b1000_0000) != 0; | 36 | return (self.deaths & (1 << unreferenced_bit_index)) != 0; |
| 32 | } | 37 | } |
| 33 | 38 | ||
| 34 | pub fn operandDies(self: Inst, index: u3) bool { | 39 | pub fn operandDies(self: Inst, index: DeathsBitIndex) bool { |
| 35 | assert(index < 6); | 40 | assert(index < deaths_bits); |
| 36 | return @truncate(u1, self.deaths << index) != 0; | 41 | return @truncate(u1, self.deaths << index) != 0; |
| 37 | } | 42 | } |
| 38 | 43 | ||
| 39 | pub fn specialOperandDeaths(self: Inst) bool { | 44 | pub fn specialOperandDeaths(self: Inst) bool { |
| 40 | return (self.deaths & 0b1000_0000) != 0; | 45 | return (self.deaths & (1 << deaths_bits)) != 0; |
| 41 | } | 46 | } |
| 42 | 47 | ||
| 43 | pub const Tag = enum { | 48 | pub const Tag = enum { |
| ... | @@ -60,6 +65,7 @@ pub const Inst = struct { | ... | @@ -60,6 +65,7 @@ pub const Inst = struct { |
| 60 | retvoid, | 65 | retvoid, |
| 61 | sub, | 66 | sub, |
| 62 | unreach, | 67 | unreach, |
| 68 | not, | ||
| 63 | }; | 69 | }; |
| 64 | 70 | ||
| 65 | pub fn cast(base: *Inst, comptime T: type) ?*T { | 71 | pub fn cast(base: *Inst, comptime T: type) ?*T { |
| ... | @@ -194,6 +200,15 @@ pub const Inst = struct { | ... | @@ -194,6 +200,15 @@ pub const Inst = struct { |
| 194 | false_death_count: u32 = 0, | 200 | false_death_count: u32 = 0, |
| 195 | }; | 201 | }; |
| 196 | 202 | ||
| 203 | pub const Not = struct { | ||
| 204 | pub const base_tag = Tag.not; | ||
| 205 | |||
| 206 | base: Inst, | ||
| 207 | args: struct { | ||
| 208 | operand: *Inst, | ||
| 209 | }, | ||
| 210 | }; | ||
| 211 | |||
| 197 | pub const Constant = struct { | 212 | pub const Constant = struct { |
| 198 | pub const base_tag = Tag.constant; | 213 | pub const base_tag = Tag.constant; |
| 199 | base: Inst, | 214 | base: Inst, |
src-self-hosted/liveness.zig+27-8| ... | @@ -34,7 +34,7 @@ fn analyzeInstGeneric(arena: *std.mem.Allocator, table: *std.AutoHashMap(*ir.Ins | ... | @@ -34,7 +34,7 @@ fn analyzeInstGeneric(arena: *std.mem.Allocator, table: *std.AutoHashMap(*ir.Ins |
| 34 | inline for (std.meta.declarations(ir.Inst)) |decl| { | 34 | inline for (std.meta.declarations(ir.Inst)) |decl| { |
| 35 | switch (decl.data) { | 35 | switch (decl.data) { |
| 36 | .Type => |T| { | 36 | .Type => |T| { |
| 37 | if (@hasDecl(T, "base_tag")) { | 37 | if (@typeInfo(T) == .Struct and @hasDecl(T, "base_tag")) { |
| 38 | if (T.base_tag == base.tag) { | 38 | if (T.base_tag == base.tag) { |
| 39 | return analyzeInst(arena, table, T, @fieldParentPtr(T, "base", base)); | 39 | return analyzeInst(arena, table, T, @fieldParentPtr(T, "base", base)); |
| 40 | } | 40 | } |
| ... | @@ -47,7 +47,13 @@ fn analyzeInstGeneric(arena: *std.mem.Allocator, table: *std.AutoHashMap(*ir.Ins | ... | @@ -47,7 +47,13 @@ fn analyzeInstGeneric(arena: *std.mem.Allocator, table: *std.AutoHashMap(*ir.Ins |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | fn analyzeInst(arena: *std.mem.Allocator, table: *std.AutoHashMap(*ir.Inst, void), comptime T: type, inst: *T) error{OutOfMemory}!void { | 49 | fn analyzeInst(arena: *std.mem.Allocator, table: *std.AutoHashMap(*ir.Inst, void), comptime T: type, inst: *T) error{OutOfMemory}!void { |
| 50 | inst.base.deaths = 0; | 50 | if (table.contains(&inst.base)) { |
| 51 | inst.base.deaths = 0; | ||
| 52 | } else { | ||
| 53 | // No tombstone for this instruction means it is never referenced, | ||
| 54 | // and its birth marks its own death. Very metal 🤘 | ||
| 55 | inst.base.deaths = 1 << ir.Inst.unreferenced_bit_index; | ||
| 56 | } | ||
| 51 | 57 | ||
| 52 | switch (T) { | 58 | switch (T) { |
| 53 | ir.Inst.Constant => return, | 59 | ir.Inst.Constant => return, |
| ... | @@ -106,15 +112,28 @@ fn analyzeInst(arena: *std.mem.Allocator, table: *std.AutoHashMap(*ir.Inst, void | ... | @@ -106,15 +112,28 @@ fn analyzeInst(arena: *std.mem.Allocator, table: *std.AutoHashMap(*ir.Inst, void |
| 106 | // instruction, and the deaths flag for the CondBr instruction will indicate whether the | 112 | // instruction, and the deaths flag for the CondBr instruction will indicate whether the |
| 107 | // condition's lifetime ends immediately before entering any branch. | 113 | // condition's lifetime ends immediately before entering any branch. |
| 108 | }, | 114 | }, |
| 115 | ir.Inst.Call => { | ||
| 116 | // Call instructions have a runtime-known number of operands so we have to handle them ourselves here. | ||
| 117 | const needed_bits = 1 + inst.args.args.len; | ||
| 118 | if (needed_bits <= ir.Inst.deaths_bits) { | ||
| 119 | var bit_i: ir.Inst.DeathsBitIndex = 0; | ||
| 120 | { | ||
| 121 | const prev = try table.fetchPut(inst.args.func, {}); | ||
| 122 | if (prev == null) inst.base.deaths |= @as(ir.Inst.DeathsInt, 1) << bit_i; | ||
| 123 | bit_i += 1; | ||
| 124 | } | ||
| 125 | for (inst.args.args) |arg| { | ||
| 126 | const prev = try table.fetchPut(arg, {}); | ||
| 127 | if (prev == null) inst.base.deaths |= @as(ir.Inst.DeathsInt, 1) << bit_i; | ||
| 128 | bit_i += 1; | ||
| 129 | } | ||
| 130 | } else { | ||
| 131 | @panic("Handle liveness analysis for function calls with many parameters"); | ||
| 132 | } | ||
| 133 | }, | ||
| 109 | else => {}, | 134 | else => {}, |
| 110 | } | 135 | } |
| 111 | 136 | ||
| 112 | if (!table.contains(&inst.base)) { | ||
| 113 | // No tombstone for this instruction means it is never referenced, | ||
| 114 | // and its birth marks its own death. Very metal 🤘 | ||
| 115 | inst.base.deaths |= 1 << 7; | ||
| 116 | } | ||
| 117 | |||
| 118 | const Args = ir.Inst.Args(T); | 137 | const Args = ir.Inst.Args(T); |
| 119 | if (Args == void) { | 138 | if (Args == void) { |
| 120 | return; | 139 | return; |
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 | } |
src-self-hosted/type.zig+17-2| ... | @@ -163,6 +163,22 @@ pub const Type = extern union { | ... | @@ -163,6 +163,22 @@ pub const Type = extern union { |
| 163 | return sentinel_b == null; | 163 | return sentinel_b == null; |
| 164 | } | 164 | } |
| 165 | }, | 165 | }, |
| 166 | .Fn => { | ||
| 167 | if (!a.fnReturnType().eql(b.fnReturnType())) | ||
| 168 | return false; | ||
| 169 | if (a.fnCallingConvention() != b.fnCallingConvention()) | ||
| 170 | return false; | ||
| 171 | const a_param_len = a.fnParamLen(); | ||
| 172 | const b_param_len = b.fnParamLen(); | ||
| 173 | if (a_param_len != b_param_len) | ||
| 174 | return false; | ||
| 175 | var i: usize = 0; | ||
| 176 | while (i < a_param_len) : (i += 1) { | ||
| 177 | if (!a.fnParamType(i).eql(b.fnParamType(i))) | ||
| 178 | return false; | ||
| 179 | } | ||
| 180 | return true; | ||
| 181 | }, | ||
| 166 | .Float, | 182 | .Float, |
| 167 | .Struct, | 183 | .Struct, |
| 168 | .Optional, | 184 | .Optional, |
| ... | @@ -170,14 +186,13 @@ pub const Type = extern union { | ... | @@ -170,14 +186,13 @@ pub const Type = extern union { |
| 170 | .ErrorSet, | 186 | .ErrorSet, |
| 171 | .Enum, | 187 | .Enum, |
| 172 | .Union, | 188 | .Union, |
| 173 | .Fn, | ||
| 174 | .BoundFn, | 189 | .BoundFn, |
| 175 | .Opaque, | 190 | .Opaque, |
| 176 | .Frame, | 191 | .Frame, |
| 177 | .AnyFrame, | 192 | .AnyFrame, |
| 178 | .Vector, | 193 | .Vector, |
| 179 | .EnumLiteral, | 194 | .EnumLiteral, |
| 180 | => @panic("TODO implement more Type equality comparison"), | 195 | => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }), |
| 181 | } | 196 | } |
| 182 | } | 197 | } |
| 183 | 198 |
src-self-hosted/value.zig+23-11| ... | @@ -427,8 +427,6 @@ pub const Value = extern union { | ... | @@ -427,8 +427,6 @@ pub const Value = extern union { |
| 427 | .fn_ccc_void_no_args_type, | 427 | .fn_ccc_void_no_args_type, |
| 428 | .single_const_pointer_to_comptime_int_type, | 428 | .single_const_pointer_to_comptime_int_type, |
| 429 | .const_slice_u8_type, | 429 | .const_slice_u8_type, |
| 430 | .bool_true, | ||
| 431 | .bool_false, | ||
| 432 | .null_value, | 430 | .null_value, |
| 433 | .function, | 431 | .function, |
| 434 | .ref_val, | 432 | .ref_val, |
| ... | @@ -441,8 +439,11 @@ pub const Value = extern union { | ... | @@ -441,8 +439,11 @@ pub const Value = extern union { |
| 441 | 439 | ||
| 442 | .the_one_possible_value, // An integer with one possible value is always zero. | 440 | .the_one_possible_value, // An integer with one possible value is always zero. |
| 443 | .zero, | 441 | .zero, |
| 442 | .bool_false, | ||
| 444 | => return BigIntMutable.init(&space.limbs, 0).toConst(), | 443 | => return BigIntMutable.init(&space.limbs, 0).toConst(), |
| 445 | 444 | ||
| 445 | .bool_true => return BigIntMutable.init(&space.limbs, 1).toConst(), | ||
| 446 | |||
| 446 | .int_u64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_u64).?.int).toConst(), | 447 | .int_u64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_u64).?.int).toConst(), |
| 447 | .int_i64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_i64).?.int).toConst(), | 448 | .int_i64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_i64).?.int).toConst(), |
| 448 | .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt(), | 449 | .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt(), |
| ... | @@ -493,8 +494,6 @@ pub const Value = extern union { | ... | @@ -493,8 +494,6 @@ pub const Value = extern union { |
| 493 | .fn_ccc_void_no_args_type, | 494 | .fn_ccc_void_no_args_type, |
| 494 | .single_const_pointer_to_comptime_int_type, | 495 | .single_const_pointer_to_comptime_int_type, |
| 495 | .const_slice_u8_type, | 496 | .const_slice_u8_type, |
| 496 | .bool_true, | ||
| 497 | .bool_false, | ||
| 498 | .null_value, | 497 | .null_value, |
| 499 | .function, | 498 | .function, |
| 500 | .ref_val, | 499 | .ref_val, |
| ... | @@ -507,8 +506,11 @@ pub const Value = extern union { | ... | @@ -507,8 +506,11 @@ pub const Value = extern union { |
| 507 | 506 | ||
| 508 | .zero, | 507 | .zero, |
| 509 | .the_one_possible_value, // an integer with one possible value is always zero | 508 | .the_one_possible_value, // an integer with one possible value is always zero |
| 509 | .bool_false, | ||
| 510 | => return 0, | 510 | => return 0, |
| 511 | 511 | ||
| 512 | .bool_true => return 1, | ||
| 513 | |||
| 512 | .int_u64 => return self.cast(Payload.Int_u64).?.int, | 514 | .int_u64 => return self.cast(Payload.Int_u64).?.int, |
| 513 | .int_i64 => return @intCast(u64, self.cast(Payload.Int_u64).?.int), | 515 | .int_i64 => return @intCast(u64, self.cast(Payload.Int_u64).?.int), |
| 514 | .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().to(u64) catch unreachable, | 516 | .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().to(u64) catch unreachable, |
| ... | @@ -560,8 +562,6 @@ pub const Value = extern union { | ... | @@ -560,8 +562,6 @@ pub const Value = extern union { |
| 560 | .fn_ccc_void_no_args_type, | 562 | .fn_ccc_void_no_args_type, |
| 561 | .single_const_pointer_to_comptime_int_type, | 563 | .single_const_pointer_to_comptime_int_type, |
| 562 | .const_slice_u8_type, | 564 | .const_slice_u8_type, |
| 563 | .bool_true, | ||
| 564 | .bool_false, | ||
| 565 | .null_value, | 565 | .null_value, |
| 566 | .function, | 566 | .function, |
| 567 | .ref_val, | 567 | .ref_val, |
| ... | @@ -574,8 +574,11 @@ pub const Value = extern union { | ... | @@ -574,8 +574,11 @@ pub const Value = extern union { |
| 574 | 574 | ||
| 575 | .the_one_possible_value, // an integer with one possible value is always zero | 575 | .the_one_possible_value, // an integer with one possible value is always zero |
| 576 | .zero, | 576 | .zero, |
| 577 | .bool_false, | ||
| 577 | => return 0, | 578 | => return 0, |
| 578 | 579 | ||
| 580 | .bool_true => return 1, | ||
| 581 | |||
| 579 | .int_u64 => { | 582 | .int_u64 => { |
| 580 | const x = self.cast(Payload.Int_u64).?.int; | 583 | const x = self.cast(Payload.Int_u64).?.int; |
| 581 | if (x == 0) return 0; | 584 | if (x == 0) return 0; |
| ... | @@ -632,8 +635,6 @@ pub const Value = extern union { | ... | @@ -632,8 +635,6 @@ pub const Value = extern union { |
| 632 | .fn_ccc_void_no_args_type, | 635 | .fn_ccc_void_no_args_type, |
| 633 | .single_const_pointer_to_comptime_int_type, | 636 | .single_const_pointer_to_comptime_int_type, |
| 634 | .const_slice_u8_type, | 637 | .const_slice_u8_type, |
| 635 | .bool_true, | ||
| 636 | .bool_false, | ||
| 637 | .null_value, | 638 | .null_value, |
| 638 | .function, | 639 | .function, |
| 639 | .ref_val, | 640 | .ref_val, |
| ... | @@ -646,8 +647,18 @@ pub const Value = extern union { | ... | @@ -646,8 +647,18 @@ pub const Value = extern union { |
| 646 | .zero, | 647 | .zero, |
| 647 | .undef, | 648 | .undef, |
| 648 | .the_one_possible_value, // an integer with one possible value is always zero | 649 | .the_one_possible_value, // an integer with one possible value is always zero |
| 650 | .bool_false, | ||
| 649 | => return true, | 651 | => return true, |
| 650 | 652 | ||
| 653 | .bool_true => { | ||
| 654 | const info = ty.intInfo(target); | ||
| 655 | if (info.signed) { | ||
| 656 | return info.bits >= 2; | ||
| 657 | } else { | ||
| 658 | return info.bits >= 1; | ||
| 659 | } | ||
| 660 | }, | ||
| 661 | |||
| 651 | .int_u64 => switch (ty.zigTypeTag()) { | 662 | .int_u64 => switch (ty.zigTypeTag()) { |
| 652 | .Int => { | 663 | .Int => { |
| 653 | const x = self.cast(Payload.Int_u64).?.int; | 664 | const x = self.cast(Payload.Int_u64).?.int; |
| ... | @@ -796,8 +807,6 @@ pub const Value = extern union { | ... | @@ -796,8 +807,6 @@ pub const Value = extern union { |
| 796 | .fn_ccc_void_no_args_type, | 807 | .fn_ccc_void_no_args_type, |
| 797 | .single_const_pointer_to_comptime_int_type, | 808 | .single_const_pointer_to_comptime_int_type, |
| 798 | .const_slice_u8_type, | 809 | .const_slice_u8_type, |
| 799 | .bool_true, | ||
| 800 | .bool_false, | ||
| 801 | .null_value, | 810 | .null_value, |
| 802 | .function, | 811 | .function, |
| 803 | .ref_val, | 812 | .ref_val, |
| ... | @@ -810,8 +819,11 @@ pub const Value = extern union { | ... | @@ -810,8 +819,11 @@ pub const Value = extern union { |
| 810 | 819 | ||
| 811 | .zero, | 820 | .zero, |
| 812 | .the_one_possible_value, // an integer with one possible value is always zero | 821 | .the_one_possible_value, // an integer with one possible value is always zero |
| 822 | .bool_false, | ||
| 813 | => return .eq, | 823 | => return .eq, |
| 814 | 824 | ||
| 825 | .bool_true => return .gt, | ||
| 826 | |||
| 815 | .int_u64 => return std.math.order(lhs.cast(Payload.Int_u64).?.int, 0), | 827 | .int_u64 => return std.math.order(lhs.cast(Payload.Int_u64).?.int, 0), |
| 816 | .int_i64 => return std.math.order(lhs.cast(Payload.Int_i64).?.int, 0), | 828 | .int_i64 => return std.math.order(lhs.cast(Payload.Int_i64).?.int, 0), |
| 817 | .int_big_positive => return lhs.cast(Payload.IntBigPositive).?.asBigInt().orderAgainstScalar(0), | 829 | .int_big_positive => return lhs.cast(Payload.IntBigPositive).?.asBigInt().orderAgainstScalar(0), |
| ... | @@ -855,7 +867,7 @@ pub const Value = extern union { | ... | @@ -855,7 +867,7 @@ pub const Value = extern union { |
| 855 | pub fn toBool(self: Value) bool { | 867 | pub fn toBool(self: Value) bool { |
| 856 | return switch (self.tag()) { | 868 | return switch (self.tag()) { |
| 857 | .bool_true => true, | 869 | .bool_true => true, |
| 858 | .bool_false => false, | 870 | .bool_false, .zero => false, |
| 859 | else => unreachable, | 871 | else => unreachable, |
| 860 | }; | 872 | }; |
| 861 | } | 873 | } |
src-self-hosted/zir.zig+30| ... | @@ -56,6 +56,7 @@ pub const Inst = struct { | ... | @@ -56,6 +56,7 @@ pub const Inst = struct { |
| 56 | declval, | 56 | declval, |
| 57 | /// Same as declval but the parameter is a `*Module.Decl` rather than a name. | 57 | /// Same as declval but the parameter is a `*Module.Decl` rather than a name. |
| 58 | declval_in_module, | 58 | declval_in_module, |
| 59 | boolnot, | ||
| 59 | /// String Literal. Makes an anonymous Decl and then takes a pointer to it. | 60 | /// String Literal. Makes an anonymous Decl and then takes a pointer to it. |
| 60 | str, | 61 | str, |
| 61 | int, | 62 | int, |
| ... | @@ -115,6 +116,7 @@ pub const Inst = struct { | ... | @@ -115,6 +116,7 @@ pub const Inst = struct { |
| 115 | .cmp, | 116 | .cmp, |
| 116 | .isnull, | 117 | .isnull, |
| 117 | .isnonnull, | 118 | .isnonnull, |
| 119 | .boolnot, | ||
| 118 | => false, | 120 | => false, |
| 119 | 121 | ||
| 120 | .condbr, | 122 | .condbr, |
| ... | @@ -143,6 +145,7 @@ pub const Inst = struct { | ... | @@ -143,6 +145,7 @@ pub const Inst = struct { |
| 143 | .declval_in_module => DeclValInModule, | 145 | .declval_in_module => DeclValInModule, |
| 144 | .compileerror => CompileError, | 146 | .compileerror => CompileError, |
| 145 | .@"const" => Const, | 147 | .@"const" => Const, |
| 148 | .boolnot => BoolNot, | ||
| 146 | .str => Str, | 149 | .str => Str, |
| 147 | .int => Int, | 150 | .int => Int, |
| 148 | .inttype => IntType, | 151 | .inttype => IntType, |
| ... | @@ -299,6 +302,16 @@ pub const Inst = struct { | ... | @@ -299,6 +302,16 @@ pub const Inst = struct { |
| 299 | kw_args: struct {}, | 302 | kw_args: struct {}, |
| 300 | }; | 303 | }; |
| 301 | 304 | ||
| 305 | pub const BoolNot = struct { | ||
| 306 | pub const base_tag = Tag.boolnot; | ||
| 307 | base: Inst, | ||
| 308 | |||
| 309 | positionals: struct { | ||
| 310 | operand: *Inst, | ||
| 311 | }, | ||
| 312 | kw_args: struct {}, | ||
| 313 | }; | ||
| 314 | |||
| 302 | pub const Str = struct { | 315 | pub const Str = struct { |
| 303 | pub const base_tag = Tag.str; | 316 | pub const base_tag = Tag.str; |
| 304 | base: Inst, | 317 | base: Inst, |
| ... | @@ -762,6 +775,7 @@ const Writer = struct { | ... | @@ -762,6 +775,7 @@ const Writer = struct { |
| 762 | .declval_in_module => return self.writeInstToStreamGeneric(stream, .declval_in_module, inst), | 775 | .declval_in_module => return self.writeInstToStreamGeneric(stream, .declval_in_module, inst), |
| 763 | .compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, inst), | 776 | .compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, inst), |
| 764 | .@"const" => return self.writeInstToStreamGeneric(stream, .@"const", inst), | 777 | .@"const" => return self.writeInstToStreamGeneric(stream, .@"const", inst), |
| 778 | .boolnot => return self.writeInstToStreamGeneric(stream, .boolnot, inst), | ||
| 765 | .str => return self.writeInstToStreamGeneric(stream, .str, inst), | 779 | .str => return self.writeInstToStreamGeneric(stream, .str, inst), |
| 766 | .int => return self.writeInstToStreamGeneric(stream, .int, inst), | 780 | .int => return self.writeInstToStreamGeneric(stream, .int, inst), |
| 767 | .inttype => return self.writeInstToStreamGeneric(stream, .inttype, inst), | 781 | .inttype => return self.writeInstToStreamGeneric(stream, .inttype, inst), |
| ... | @@ -1658,6 +1672,22 @@ const EmitZIR = struct { | ... | @@ -1658,6 +1672,22 @@ const EmitZIR = struct { |
| 1658 | }; | 1672 | }; |
| 1659 | for (body.instructions) |inst| { | 1673 | for (body.instructions) |inst| { |
| 1660 | const new_inst = switch (inst.tag) { | 1674 | const new_inst = switch (inst.tag) { |
| 1675 | .not => blk: { | ||
| 1676 | const old_inst = inst.cast(ir.Inst.Not).?; | ||
| 1677 | assert(inst.ty.zigTypeTag() == .Bool); | ||
| 1678 | const new_inst = try self.arena.allocator.create(Inst.BoolNot); | ||
| 1679 | new_inst.* = .{ | ||
| 1680 | .base = .{ | ||
| 1681 | .src = inst.src, | ||
| 1682 | .tag = Inst.BoolNot.base_tag, | ||
| 1683 | }, | ||
| 1684 | .positionals = .{ | ||
| 1685 | .operand = try self.resolveInst(new_body, old_inst.args.operand), | ||
| 1686 | }, | ||
| 1687 | .kw_args = .{}, | ||
| 1688 | }; | ||
| 1689 | break :blk &new_inst.base; | ||
| 1690 | }, | ||
| 1661 | .add => blk: { | 1691 | .add => blk: { |
| 1662 | const old_inst = inst.cast(ir.Inst.Add).?; | 1692 | const old_inst = inst.cast(ir.Inst.Add).?; |
| 1663 | const new_inst = try self.arena.allocator.create(Inst.Add); | 1693 | const new_inst = try self.arena.allocator.create(Inst.Add); |
test/stage2/compare_output.zig+57| ... | @@ -170,4 +170,61 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -170,4 +170,61 @@ pub fn addCases(ctx: *TestContext) !void { |
| 170 | "", | 170 | "", |
| 171 | ); | 171 | ); |
| 172 | } | 172 | } |
| 173 | { | ||
| 174 | var case = ctx.exe("assert function", linux_x64); | ||
| 175 | case.addCompareOutput( | ||
| 176 | \\export fn _start() noreturn { | ||
| 177 | \\ add(3, 4); | ||
| 178 | \\ | ||
| 179 | \\ exit(); | ||
| 180 | \\} | ||
| 181 | \\ | ||
| 182 | \\fn add(a: u32, b: u32) void { | ||
| 183 | \\ assert(a + b == 7); | ||
| 184 | \\} | ||
| 185 | \\ | ||
| 186 | \\pub fn assert(ok: bool) void { | ||
| 187 | \\ if (!ok) unreachable; // assertion failure | ||
| 188 | \\} | ||
| 189 | \\ | ||
| 190 | \\fn exit() noreturn { | ||
| 191 | \\ asm volatile ("syscall" | ||
| 192 | \\ : | ||
| 193 | \\ : [number] "{rax}" (231), | ||
| 194 | \\ [arg1] "{rdi}" (0) | ||
| 195 | \\ : "rcx", "r11", "memory" | ||
| 196 | \\ ); | ||
| 197 | \\ unreachable; | ||
| 198 | \\} | ||
| 199 | , | ||
| 200 | "", | ||
| 201 | ); | ||
| 202 | case.addCompareOutput( | ||
| 203 | \\export fn _start() noreturn { | ||
| 204 | \\ add(100, 200); | ||
| 205 | \\ | ||
| 206 | \\ exit(); | ||
| 207 | \\} | ||
| 208 | \\ | ||
| 209 | \\fn add(a: u32, b: u32) void { | ||
| 210 | \\ assert(a + b == 300); | ||
| 211 | \\} | ||
| 212 | \\ | ||
| 213 | \\pub fn assert(ok: bool) void { | ||
| 214 | \\ if (!ok) unreachable; // assertion failure | ||
| 215 | \\} | ||
| 216 | \\ | ||
| 217 | \\fn exit() noreturn { | ||
| 218 | \\ asm volatile ("syscall" | ||
| 219 | \\ : | ||
| 220 | \\ : [number] "{rax}" (231), | ||
| 221 | \\ [arg1] "{rdi}" (0) | ||
| 222 | \\ : "rcx", "r11", "memory" | ||
| 223 | \\ ); | ||
| 224 | \\ unreachable; | ||
| 225 | \\} | ||
| 226 | , | ||
| 227 | "", | ||
| 228 | ); | ||
| 229 | } | ||
| 173 | } | 230 | } |