| ... | ... | @@ -116,6 +116,24 @@ pub const Parser = struct { |
| 116 | 116 | }; |
| 117 | 117 | } |
| 118 | 118 | |
| 119 | const LabelCtx = struct { |
| 120 | label: ?Token, |
| 121 | dest_ptr: DestPtr, |
| 122 | }; |
| 123 | |
| 124 | const InlineCtx = struct { |
| 125 | label: ?Token, |
| 126 | inline_token: ?Token, |
| 127 | dest_ptr: DestPtr, |
| 128 | }; |
| 129 | |
| 130 | const LoopCtx = struct { |
| 131 | label: ?Token, |
| 132 | inline_token: ?Token, |
| 133 | loop_token: Token, |
| 134 | dest_ptr: DestPtr, |
| 135 | }; |
| 136 | |
| 119 | 137 | const State = union(enum) { |
| 120 | 138 | TopLevel, |
| 121 | 139 | TopLevelExtern: TopLevelDeclCtx, |
| ... | ... | @@ -137,15 +155,22 @@ pub const Parser = struct { |
| 137 | 155 | ParamDecl: &ast.NodeFnProto, |
| 138 | 156 | ParamDeclComma, |
| 139 | 157 | FnDef: &ast.NodeFnProto, |
| 158 | LabeledExpression: LabelCtx, |
| 159 | Inline: InlineCtx, |
| 160 | While: LoopCtx, |
| 161 | For: LoopCtx, |
| 140 | 162 | Block: &ast.NodeBlock, |
| 163 | Else: &?&ast.NodeElse, |
| 164 | WhileContinueExpr: &?&ast.Node, |
| 141 | 165 | Statement: &ast.NodeBlock, |
| 166 | Semicolon: &const &const ast.Node, |
| 142 | 167 | ExprListItemOrEnd: ExprListCtx, |
| 143 | 168 | ExprListCommaOrEnd: ExprListCtx, |
| 144 | 169 | FieldInitListItemOrEnd: ListSave(&ast.NodeFieldInitializer), |
| 145 | 170 | FieldInitListCommaOrEnd: ListSave(&ast.NodeFieldInitializer), |
| 146 | 171 | FieldListCommaOrEnd: &ast.NodeContainerDecl, |
| 147 | 172 | SwitchCaseOrEnd: ListSave(&ast.NodeSwitchCase), |
| 148 | | Payload: DestPtr, |
| 173 | Payload: &?&ast.NodePayload, |
| 149 | 174 | SwitchCaseCommaOrEnd: ListSave(&ast.NodeSwitchCase), |
| 150 | 175 | SwitchCaseItem: &ArrayList(&ast.Node), |
| 151 | 176 | SwitchCaseItemCommaOrEnd: &ArrayList(&ast.Node), |
| ... | ... | @@ -157,9 +182,6 @@ pub const Parser = struct { |
| 157 | 182 | /// "leaked" nodes. TODO: Figure out if it's nessesary to handle leaked nodes. |
| 158 | 183 | Optional: RevertState, |
| 159 | 184 | |
| 160 | | /// Optional can be reverted by adding the Required state to the stack. |
| 161 | | Required, |
| 162 | | |
| 163 | 185 | Expression: DestPtr, |
| 164 | 186 | RangeExpressionBegin: DestPtr, |
| 165 | 187 | RangeExpressionEnd: DestPtr, |
| ... | ... | @@ -598,8 +620,7 @@ pub const Parser = struct { |
| 598 | 620 | continue; |
| 599 | 621 | }, |
| 600 | 622 | |
| 601 | | State.Optional, |
| 602 | | State.Required => { }, |
| 623 | State.Optional => { }, |
| 603 | 624 | |
| 604 | 625 | State.Expression => |dest_ptr| { |
| 605 | 626 | const token = self.getNextToken(); |
| ... | ... | @@ -626,10 +647,51 @@ pub const Parser = struct { |
| 626 | 647 | continue; |
| 627 | 648 | }, |
| 628 | 649 | Token.Id.Keyword_break => { |
| 629 | | @panic("TODO: break"); |
| 650 | const label = blk: { |
| 651 | const colon = self.getNextToken(); |
| 652 | if (colon.id != Token.Id.Colon) { |
| 653 | self.putBackToken(colon); |
| 654 | break :blk null; |
| 655 | } |
| 656 | |
| 657 | break :blk (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue; |
| 658 | }; |
| 659 | |
| 660 | const node = try self.createControlFlowExpr(arena, token, |
| 661 | ast.NodeControlFlowExpression.Kind { |
| 662 | .Break = label, |
| 663 | } |
| 664 | ); |
| 665 | dest_ptr.store(&node.base); |
| 666 | |
| 667 | stack.append(State { |
| 668 | .Optional = RevertState { |
| 669 | .parser = *self, |
| 670 | .tokenizer = *self.tokenizer, |
| 671 | .ptr = &node.rhs, |
| 672 | } |
| 673 | }) catch unreachable; |
| 674 | try stack.append(State { .Expression = DestPtr { .NullableField = &node.rhs } }); |
| 675 | continue; |
| 630 | 676 | }, |
| 631 | 677 | Token.Id.Keyword_continue => { |
| 632 | | @panic("TODO: break"); |
| 678 | const label = blk: { |
| 679 | const colon = self.getNextToken(); |
| 680 | if (colon.id != Token.Id.Colon) { |
| 681 | self.putBackToken(colon); |
| 682 | break :blk null; |
| 683 | } |
| 684 | |
| 685 | break :blk (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue; |
| 686 | }; |
| 687 | |
| 688 | const node = try self.createControlFlowExpr(arena, token, |
| 689 | ast.NodeControlFlowExpression.Kind { |
| 690 | .Continue = label, |
| 691 | } |
| 692 | ); |
| 693 | dest_ptr.store(&node.base); |
| 694 | continue; |
| 633 | 695 | }, |
| 634 | 696 | Token.Id.Keyword_cancel => { |
| 635 | 697 | @panic("TODO: cancel"); |
| ... | ... | @@ -707,14 +769,7 @@ pub const Parser = struct { |
| 707 | 769 | |
| 708 | 770 | stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable; |
| 709 | 771 | try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }); |
| 710 | | try stack.append(State { |
| 711 | | .Optional = RevertState { |
| 712 | | .tokenizer = *self.tokenizer, |
| 713 | | .parser = *self, |
| 714 | | .ptr = &node.op.Catch, |
| 715 | | } |
| 716 | | }); |
| 717 | | try stack.append(State { .Payload = DestPtr { .NullableField = &node.op.Catch } }); |
| 772 | try stack.append(State { .Payload = &node.op.Catch }); |
| 718 | 773 | continue; |
| 719 | 774 | }, |
| 720 | 775 | Token.Id.QuestionMarkQuestionMark => { |
| ... | ... | @@ -1370,16 +1425,12 @@ pub const Parser = struct { |
| 1370 | 1425 | continue; |
| 1371 | 1426 | } |
| 1372 | 1427 | |
| 1373 | | const block = try self.createBlock(arena, (?Token)(token), Token(undefined)); |
| 1374 | | dest_ptr.store(&block.base); |
| 1375 | | |
| 1376 | | stack.append(State { .Block = block }) catch unreachable; |
| 1377 | | try stack.append(State { |
| 1378 | | .ExpectTokenSave = ExpectTokenSave { |
| 1379 | | .id = Token.Id.LBrace, |
| 1380 | | .ptr = &block.lbrace, |
| 1428 | stack.append(State { |
| 1429 | .LabeledExpression = LabelCtx { |
| 1430 | .label = token, |
| 1431 | .dest_ptr = dest_ptr |
| 1381 | 1432 | } |
| 1382 | | }); |
| 1433 | }) catch unreachable; |
| 1383 | 1434 | continue; |
| 1384 | 1435 | }, |
| 1385 | 1436 | Token.Id.LBrace => { |
| ... | ... | @@ -1398,26 +1449,31 @@ pub const Parser = struct { |
| 1398 | 1449 | Token.Id.Keyword_if => { |
| 1399 | 1450 | @panic("TODO: inline if"); |
| 1400 | 1451 | }, |
| 1452 | Token.Id.Keyword_inline => { |
| 1453 | stack.append(State { |
| 1454 | .Inline = InlineCtx { |
| 1455 | .label = null, |
| 1456 | .inline_token = token, |
| 1457 | .dest_ptr = dest_ptr, |
| 1458 | } |
| 1459 | }) catch unreachable; |
| 1460 | continue; |
| 1461 | }, |
| 1401 | 1462 | Token.Id.Keyword_while => { |
| 1402 | | const node = try arena.create(ast.NodeWhile); |
| 1403 | | *node = ast.NodeWhile { |
| 1404 | | .base = self.initNode(ast.Node.Id.While), |
| 1405 | | .while_token = token, |
| 1406 | | .condition = undefined, |
| 1407 | | .payload = null, |
| 1408 | | .continue_expr = null, |
| 1409 | | .body = undefined, |
| 1410 | | .@"else" = null, |
| 1411 | | }; |
| 1412 | | dest_ptr.store(&node.base); |
| 1413 | | |
| 1414 | | @panic("TODO: inline while"); |
| 1463 | stack.append(State { |
| 1464 | .While = LoopCtx { |
| 1465 | .label = null, |
| 1466 | .inline_token = null, |
| 1467 | .loop_token = token, |
| 1468 | .dest_ptr = dest_ptr, |
| 1469 | } |
| 1470 | }) catch unreachable; |
| 1471 | continue; |
| 1415 | 1472 | }, |
| 1416 | 1473 | Token.Id.Keyword_for => { |
| 1417 | 1474 | @panic("TODO: inline for"); |
| 1418 | 1475 | }, |
| 1419 | 1476 | Token.Id.Keyword_switch => { |
| 1420 | | @breakpoint(); |
| 1421 | 1477 | const node = try arena.create(ast.NodeSwitch); |
| 1422 | 1478 | *node = ast.NodeSwitch { |
| 1423 | 1479 | .base = self.initNode(ast.Node.Id.Switch), |
| ... | ... | @@ -1558,15 +1614,7 @@ pub const Parser = struct { |
| 1558 | 1614 | try list_state.list.append(node); |
| 1559 | 1615 | stack.append(State { .SwitchCaseCommaOrEnd = list_state }) catch unreachable; |
| 1560 | 1616 | try stack.append(State { .Expression = DestPtr{ .Field = &node.expr } }); |
| 1561 | | try stack.append(State { |
| 1562 | | .Optional = RevertState { |
| 1563 | | .tokenizer = *self.tokenizer, |
| 1564 | | .parser = *self, |
| 1565 | | .ptr = &node.payload, |
| 1566 | | } |
| 1567 | | }); |
| 1568 | | try stack.append(State { .Payload = DestPtr { .NullableField = &node.payload } }); |
| 1569 | | try stack.append(State.Required); |
| 1617 | try stack.append(State { .Payload = &node.payload }); |
| 1570 | 1618 | |
| 1571 | 1619 | const maybe_else = self.getNextToken(); |
| 1572 | 1620 | if (maybe_else.id == Token.Id.Keyword_else) { |
| ... | ... | @@ -1585,32 +1633,6 @@ pub const Parser = struct { |
| 1585 | 1633 | } |
| 1586 | 1634 | }, |
| 1587 | 1635 | |
| 1588 | | State.Payload => |dest_ptr| { |
| 1589 | | const lpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue; |
| 1590 | | |
| 1591 | | const is_ptr = blk: { |
| 1592 | | const asterik = self.getNextToken(); |
| 1593 | | if (asterik.id == Token.Id.Asterisk) { |
| 1594 | | break :blk true; |
| 1595 | | } else { |
| 1596 | | self.putBackToken(asterik); |
| 1597 | | break :blk false; |
| 1598 | | } |
| 1599 | | }; |
| 1600 | | |
| 1601 | | const ident = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue; |
| 1602 | | const rpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue; |
| 1603 | | const node = try arena.create(ast.NodePayload); |
| 1604 | | *node = ast.NodePayload { |
| 1605 | | .base = self.initNode(ast.Node.Id.Payload), |
| 1606 | | .lpipe = lpipe, |
| 1607 | | .is_ptr = is_ptr, |
| 1608 | | .symbol = try self.createIdentifier(arena, ident), |
| 1609 | | .rpipe = rpipe |
| 1610 | | }; |
| 1611 | | dest_ptr.store(&node.base); |
| 1612 | | }, |
| 1613 | | |
| 1614 | 1636 | State.SwitchCaseItem => |case_items| { |
| 1615 | 1637 | stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable; |
| 1616 | 1638 | try stack.append(State { .RangeExpressionBegin = DestPtr{ .Field = try case_items.addOne() } }); |
| ... | ... | @@ -1642,6 +1664,68 @@ pub const Parser = struct { |
| 1642 | 1664 | continue; |
| 1643 | 1665 | }, |
| 1644 | 1666 | |
| 1667 | State.Else => |dest| { |
| 1668 | const else_token = self.getNextToken(); |
| 1669 | if (else_token.id != Token.Id.Keyword_else) { |
| 1670 | self.putBackToken(else_token); |
| 1671 | continue; |
| 1672 | } |
| 1673 | |
| 1674 | const node = try arena.create(ast.NodeElse); |
| 1675 | *node = ast.NodeElse { |
| 1676 | .base = self.initNode(ast.Node.Id.Else), |
| 1677 | .else_token = else_token, |
| 1678 | .payload = null, |
| 1679 | .body = undefined, |
| 1680 | }; |
| 1681 | *dest = node; |
| 1682 | |
| 1683 | stack.append(State { .Expression = DestPtr { .Field = &node.body } }) catch unreachable; |
| 1684 | try stack.append(State { .Payload = &node.payload }); |
| 1685 | }, |
| 1686 | |
| 1687 | State.WhileContinueExpr => |dest| { |
| 1688 | const colon = self.getNextToken(); |
| 1689 | if (colon.id != Token.Id.Colon) { |
| 1690 | self.putBackToken(colon); |
| 1691 | continue; |
| 1692 | } |
| 1693 | |
| 1694 | _ = (try self.eatToken(&stack, Token.Id.LParen)) ?? continue; |
| 1695 | stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable; |
| 1696 | try stack.append(State { .Expression = DestPtr { .NullableField = dest } }); |
| 1697 | }, |
| 1698 | |
| 1699 | State.Payload => |dest| { |
| 1700 | const lpipe = self.getNextToken(); |
| 1701 | if (lpipe.id != Token.Id.Pipe) { |
| 1702 | self.putBackToken(lpipe); |
| 1703 | continue; |
| 1704 | } |
| 1705 | |
| 1706 | const is_ptr = blk: { |
| 1707 | const asterik = self.getNextToken(); |
| 1708 | if (asterik.id == Token.Id.Asterisk) { |
| 1709 | break :blk true; |
| 1710 | } else { |
| 1711 | self.putBackToken(asterik); |
| 1712 | break :blk false; |
| 1713 | } |
| 1714 | }; |
| 1715 | |
| 1716 | const ident = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue; |
| 1717 | const rpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue; |
| 1718 | const node = try arena.create(ast.NodePayload); |
| 1719 | *node = ast.NodePayload { |
| 1720 | .base = self.initNode(ast.Node.Id.Payload), |
| 1721 | .lpipe = lpipe, |
| 1722 | .is_ptr = is_ptr, |
| 1723 | .symbol = try self.createIdentifier(arena, ident), |
| 1724 | .rpipe = rpipe |
| 1725 | }; |
| 1726 | *dest = node; |
| 1727 | }, |
| 1728 | |
| 1645 | 1729 | State.AddrOfModifiers => |addr_of_info| { |
| 1646 | 1730 | var token = self.getNextToken(); |
| 1647 | 1731 | switch (token.id) { |
| ... | ... | @@ -1803,6 +1887,114 @@ pub const Parser = struct { |
| 1803 | 1887 | } |
| 1804 | 1888 | }, |
| 1805 | 1889 | |
| 1890 | State.LabeledExpression => |ctx| { |
| 1891 | const token = self.getNextToken(); |
| 1892 | switch (token.id) { |
| 1893 | Token.Id.LBrace => { |
| 1894 | const block = try self.createBlock(arena, (?Token)(ctx.label), token); |
| 1895 | ctx.dest_ptr.store(&block.base); |
| 1896 | |
| 1897 | stack.append(State { .Block = block }) catch unreachable; |
| 1898 | continue; |
| 1899 | }, |
| 1900 | Token.Id.Keyword_while => { |
| 1901 | stack.append(State { |
| 1902 | .While = LoopCtx { |
| 1903 | .label = ctx.label, |
| 1904 | .inline_token = null, |
| 1905 | .loop_token = token, |
| 1906 | .dest_ptr = ctx.dest_ptr, |
| 1907 | } |
| 1908 | }) catch unreachable; |
| 1909 | continue; |
| 1910 | }, |
| 1911 | Token.Id.Keyword_for => { |
| 1912 | stack.append(State { |
| 1913 | .For = LoopCtx { |
| 1914 | .label = ctx.label, |
| 1915 | .inline_token = null, |
| 1916 | .loop_token = token, |
| 1917 | .dest_ptr = ctx.dest_ptr, |
| 1918 | } |
| 1919 | }) catch unreachable; |
| 1920 | continue; |
| 1921 | }, |
| 1922 | Token.Id.Keyword_inline => { |
| 1923 | stack.append(State { |
| 1924 | .Inline = InlineCtx { |
| 1925 | .label = ctx.label, |
| 1926 | .inline_token = token, |
| 1927 | .dest_ptr = ctx.dest_ptr, |
| 1928 | } |
| 1929 | }) catch unreachable; |
| 1930 | continue; |
| 1931 | }, |
| 1932 | else => { |
| 1933 | try self.parseError(&stack, token, "expected 'while', 'for', 'inline' or '{{', found {}", @tagName(token.id)); |
| 1934 | continue; |
| 1935 | }, |
| 1936 | } |
| 1937 | }, |
| 1938 | |
| 1939 | State.Inline => |ctx| { |
| 1940 | const token = self.getNextToken(); |
| 1941 | switch (token.id) { |
| 1942 | Token.Id.Keyword_while => { |
| 1943 | stack.append(State { |
| 1944 | .While = LoopCtx { |
| 1945 | .inline_token = ctx.inline_token, |
| 1946 | .label = ctx.label, |
| 1947 | .loop_token = token, |
| 1948 | .dest_ptr = ctx.dest_ptr, |
| 1949 | } |
| 1950 | }) catch unreachable; |
| 1951 | continue; |
| 1952 | }, |
| 1953 | Token.Id.Keyword_for => { |
| 1954 | stack.append(State { |
| 1955 | .For = LoopCtx { |
| 1956 | .inline_token = ctx.inline_token, |
| 1957 | .label = ctx.label, |
| 1958 | .loop_token = token, |
| 1959 | .dest_ptr = ctx.dest_ptr, |
| 1960 | } |
| 1961 | }) catch unreachable; |
| 1962 | continue; |
| 1963 | }, |
| 1964 | else => { |
| 1965 | try self.parseError(&stack, token, "expected 'while' or 'for', found {}", @tagName(token.id)); |
| 1966 | continue; |
| 1967 | }, |
| 1968 | } |
| 1969 | }, |
| 1970 | |
| 1971 | State.While => |ctx| { |
| 1972 | const node = try arena.create(ast.NodeWhile); |
| 1973 | *node = ast.NodeWhile { |
| 1974 | .base = self.initNode(ast.Node.Id.While), |
| 1975 | .label = ctx.label, |
| 1976 | .inline_token = ctx.inline_token, |
| 1977 | .while_token = ctx.loop_token, |
| 1978 | .condition = undefined, |
| 1979 | .payload = null, |
| 1980 | .continue_expr = null, |
| 1981 | .body = undefined, |
| 1982 | .@"else" = null, |
| 1983 | }; |
| 1984 | ctx.dest_ptr.store(&node.base); |
| 1985 | |
| 1986 | stack.append(State { .Else = &node.@"else" }) catch unreachable; |
| 1987 | try stack.append(State { .Expression = DestPtr { .Field = &node.body } }); |
| 1988 | try stack.append(State { .WhileContinueExpr = &node.continue_expr }); |
| 1989 | try stack.append(State { .Payload = &node.payload }); |
| 1990 | try stack.append(State { .ExpectToken = Token.Id.RParen }); |
| 1991 | try stack.append(State { .Expression = DestPtr { .Field = &node.condition } }); |
| 1992 | try stack.append(State { .ExpectToken = Token.Id.LParen }); |
| 1993 | }, |
| 1994 | |
| 1995 | State.For => |ctx| { |
| 1996 | }, |
| 1997 | |
| 1806 | 1998 | State.Block => |block| { |
| 1807 | 1999 | const token = self.getNextToken(); |
| 1808 | 2000 | switch (token.id) { |
| ... | ... | @@ -1841,28 +2033,6 @@ pub const Parser = struct { |
| 1841 | 2033 | stack.append(State { .VarDecl = var_decl }) catch unreachable; |
| 1842 | 2034 | continue; |
| 1843 | 2035 | }, |
| 1844 | | Token.Id.Identifier => { |
| 1845 | | const maybe_colon = self.getNextToken(); |
| 1846 | | if (maybe_colon.id != Token.Id.Colon) { |
| 1847 | | self.putBackToken(maybe_colon); |
| 1848 | | self.putBackToken(next); |
| 1849 | | stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable; |
| 1850 | | try stack.append(State { .Expression = DestPtr{.Field = try block.statements.addOne() } }); |
| 1851 | | continue; |
| 1852 | | } |
| 1853 | | |
| 1854 | | const inner_block = try self.createBlock(arena, (?Token)(next), Token(undefined)); |
| 1855 | | try block.statements.append(&inner_block.base); |
| 1856 | | |
| 1857 | | stack.append(State { .Block = inner_block }) catch unreachable; |
| 1858 | | try stack.append(State { |
| 1859 | | .ExpectTokenSave = ExpectTokenSave { |
| 1860 | | .id = Token.Id.LBrace, |
| 1861 | | .ptr = &inner_block.lbrace, |
| 1862 | | } |
| 1863 | | }); |
| 1864 | | continue; |
| 1865 | | }, |
| 1866 | 2036 | Token.Id.LBrace => { |
| 1867 | 2037 | const inner_block = try self.createBlock(arena, (?Token)(null), next); |
| 1868 | 2038 | try block.statements.append(&inner_block.base); |
| ... | ... | @@ -1870,22 +2040,53 @@ pub const Parser = struct { |
| 1870 | 2040 | stack.append(State { .Block = inner_block }) catch unreachable; |
| 1871 | 2041 | continue; |
| 1872 | 2042 | }, |
| 1873 | | Token.Id.Keyword_suspend, Token.Id.Keyword_if, |
| 1874 | | Token.Id.Keyword_while, Token.Id.Keyword_for, |
| 1875 | | Token.Id.Keyword_switch => { |
| 1876 | | self.putBackToken(next); |
| 1877 | | stack.append(State { .Expression = DestPtr{.Field = try block.statements.addOne() } }) catch unreachable; |
| 1878 | | continue; |
| 1879 | | }, |
| 1880 | 2043 | else => { |
| 1881 | 2044 | self.putBackToken(next); |
| 1882 | | stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable; |
| 1883 | | try stack.append(State { .Expression = DestPtr{.Field = try block.statements.addOne() } }); |
| 2045 | const statememt = try block.statements.addOne(); |
| 2046 | stack.append(State { .Semicolon = statememt }) catch unreachable; |
| 2047 | try stack.append(State { .Expression = DestPtr{.Field = statememt } }); |
| 1884 | 2048 | continue; |
| 1885 | 2049 | } |
| 1886 | 2050 | } |
| 1887 | 2051 | |
| 1888 | 2052 | }, |
| 2053 | |
| 2054 | State.Semicolon => |node_ptr| { |
| 2055 | const node = *node_ptr; |
| 2056 | switch (node.id) { |
| 2057 | ast.Node.Id.Root, |
| 2058 | ast.Node.Id.StructField, |
| 2059 | ast.Node.Id.UnionTag, |
| 2060 | ast.Node.Id.EnumTag, |
| 2061 | ast.Node.Id.ParamDecl, |
| 2062 | ast.Node.Id.Block, |
| 2063 | ast.Node.Id.Payload, |
| 2064 | ast.Node.Id.Switch, |
| 2065 | ast.Node.Id.SwitchCase, |
| 2066 | ast.Node.Id.SwitchElse, |
| 2067 | ast.Node.Id.FieldInitializer, |
| 2068 | ast.Node.Id.LineComment, |
| 2069 | ast.Node.Id.TestDecl => continue, |
| 2070 | ast.Node.Id.While => { |
| 2071 | const while_node = @fieldParentPtr(ast.NodeWhile, "base", node); |
| 2072 | if (while_node.@"else") |@"else"| { |
| 2073 | stack.append(State { .Semicolon = &@"else".base }) catch unreachable; |
| 2074 | continue; |
| 2075 | } |
| 2076 | |
| 2077 | stack.append(State { .Semicolon = &while_node.body }) catch unreachable; |
| 2078 | continue; |
| 2079 | }, |
| 2080 | ast.Node.Id.Else => { |
| 2081 | const else_node = @fieldParentPtr(ast.NodeElse, "base", node); |
| 2082 | stack.append(State { .Semicolon = &else_node.body }) catch unreachable; |
| 2083 | continue; |
| 2084 | }, |
| 2085 | else => { |
| 2086 | _ = (try self.eatToken(&stack, Token.Id.Semicolon)) ?? continue; |
| 2087 | } |
| 2088 | } |
| 2089 | } |
| 1889 | 2090 | } |
| 1890 | 2091 | } |
| 1891 | 2092 | } |
| ... | ... | @@ -2295,9 +2496,6 @@ pub const Parser = struct { |
| 2295 | 2496 | *revert.ptr = null; |
| 2296 | 2497 | return; |
| 2297 | 2498 | }, |
| 2298 | | State.Required => { |
| 2299 | | return error.StateRequired; |
| 2300 | | }, |
| 2301 | 2499 | else => { } |
| 2302 | 2500 | } |
| 2303 | 2501 | } |
| ... | ... | @@ -2361,6 +2559,7 @@ pub const Parser = struct { |
| 2361 | 2559 | Expression: &ast.Node, |
| 2362 | 2560 | VarDecl: &ast.NodeVarDecl, |
| 2363 | 2561 | Statement: &ast.Node, |
| 2562 | Semicolon: &ast.Node, |
| 2364 | 2563 | FieldInitializer: &ast.NodeFieldInitializer, |
| 2365 | 2564 | PrintIndent, |
| 2366 | 2565 | Indent: usize, |
| ... | ... | @@ -2589,7 +2788,7 @@ pub const Parser = struct { |
| 2589 | 2788 | if (prefix_op_node.op == ast.NodeInfixOp.InfixOp.Catch) { |
| 2590 | 2789 | if (prefix_op_node.op.Catch) |payload| { |
| 2591 | 2790 | try stack.append(RenderState { .Text = " " }); |
| 2592 | | try stack.append(RenderState { .Expression = payload }); |
| 2791 | try stack.append(RenderState { .Expression = &payload.base }); |
| 2593 | 2792 | } |
| 2594 | 2793 | try stack.append(RenderState { .Text = " catch " }); |
| 2595 | 2794 | } else { |
| ... | ... | @@ -3013,7 +3212,7 @@ pub const Parser = struct { |
| 3013 | 3212 | try stack.append(RenderState { .Expression = switch_case.expr }); |
| 3014 | 3213 | if (switch_case.payload) |payload| { |
| 3015 | 3214 | try stack.append(RenderState { .Text = " " }); |
| 3016 | | try stack.append(RenderState { .Expression = payload }); |
| 3215 | try stack.append(RenderState { .Expression = &payload.base }); |
| 3017 | 3216 | } |
| 3018 | 3217 | try stack.append(RenderState { .Text = " => "}); |
| 3019 | 3218 | |
| ... | ... | @@ -3032,7 +3231,74 @@ pub const Parser = struct { |
| 3032 | 3231 | const switch_else = @fieldParentPtr(ast.NodeSwitchElse, "base", base); |
| 3033 | 3232 | try stream.print("{}", self.tokenizer.getTokenSlice(switch_else.token)); |
| 3034 | 3233 | }, |
| 3035 | | ast.Node.Id.While => @panic("TODO: Render while"), |
| 3234 | ast.Node.Id.Else => { |
| 3235 | const else_node = @fieldParentPtr(ast.NodeElse, "base", base); |
| 3236 | try stream.print("{} ", self.tokenizer.getTokenSlice(else_node.else_token)); |
| 3237 | |
| 3238 | if (else_node.body.id == ast.Node.Id.Block) { |
| 3239 | try stack.append(RenderState { .Expression = else_node.body }); |
| 3240 | } else { |
| 3241 | try stack.append(RenderState { .Indent = indent }); |
| 3242 | try stack.append(RenderState { .Expression = else_node.body }); |
| 3243 | try stack.append(RenderState.PrintIndent); |
| 3244 | try stack.append(RenderState { .Indent = indent + indent_delta }); |
| 3245 | try stack.append(RenderState { .Text = "\n" }); |
| 3246 | } |
| 3247 | |
| 3248 | if (else_node.payload) |payload| { |
| 3249 | try stack.append(RenderState { .Text = " " }); |
| 3250 | try stack.append(RenderState { .Expression = &payload.base }); |
| 3251 | } |
| 3252 | }, |
| 3253 | ast.Node.Id.While => { |
| 3254 | const while_node = @fieldParentPtr(ast.NodeWhile, "base", base); |
| 3255 | if (while_node.label) |label| { |
| 3256 | try stream.print("{}: ", self.tokenizer.getTokenSlice(label)); |
| 3257 | } |
| 3258 | |
| 3259 | if (while_node.inline_token) |inline_token| { |
| 3260 | try stream.print("{} ", self.tokenizer.getTokenSlice(inline_token)); |
| 3261 | } |
| 3262 | |
| 3263 | try stream.print("{} ", self.tokenizer.getTokenSlice(while_node.while_token)); |
| 3264 | |
| 3265 | if (while_node.@"else") |@"else"| { |
| 3266 | try stack.append(RenderState { .Expression = &@"else".base }); |
| 3267 | |
| 3268 | if (while_node.body.id == ast.Node.Id.Block) { |
| 3269 | try stack.append(RenderState { .Text = " " }); |
| 3270 | } else { |
| 3271 | try stack.append(RenderState { .Text = "\n" }); |
| 3272 | } |
| 3273 | } |
| 3274 | |
| 3275 | if (while_node.body.id == ast.Node.Id.Block) { |
| 3276 | try stack.append(RenderState { .Expression = while_node.body }); |
| 3277 | try stack.append(RenderState { .Text = " " }); |
| 3278 | } else { |
| 3279 | try stack.append(RenderState { .Indent = indent }); |
| 3280 | try stack.append(RenderState { .Expression = while_node.body }); |
| 3281 | try stack.append(RenderState.PrintIndent); |
| 3282 | try stack.append(RenderState { .Indent = indent + indent_delta }); |
| 3283 | try stack.append(RenderState { .Text = "\n" }); |
| 3284 | } |
| 3285 | |
| 3286 | if (while_node.continue_expr) |continue_expr| { |
| 3287 | try stack.append(RenderState { .Text = ")" }); |
| 3288 | try stack.append(RenderState { .Expression = continue_expr }); |
| 3289 | try stack.append(RenderState { .Text = ": (" }); |
| 3290 | try stack.append(RenderState { .Text = " " }); |
| 3291 | } |
| 3292 | |
| 3293 | if (while_node.payload) |payload| { |
| 3294 | try stack.append(RenderState { .Expression = &payload.base }); |
| 3295 | try stack.append(RenderState { .Text = " " }); |
| 3296 | } |
| 3297 | |
| 3298 | try stack.append(RenderState { .Text = ")" }); |
| 3299 | try stack.append(RenderState { .Expression = while_node.condition }); |
| 3300 | try stack.append(RenderState { .Text = "(" }); |
| 3301 | }, |
| 3036 | 3302 | |
| 3037 | 3303 | ast.Node.Id.StructField, |
| 3038 | 3304 | ast.Node.Id.UnionTag, |
| ... | ... | @@ -3077,13 +3343,45 @@ pub const Parser = struct { |
| 3077 | 3343 | const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", base); |
| 3078 | 3344 | try stack.append(RenderState { .VarDecl = var_decl}); |
| 3079 | 3345 | }, |
| 3080 | | ast.Node.Id.Block, ast.Node.Id.Switch => { |
| 3081 | | try stack.append(RenderState { .Expression = base}); |
| 3082 | | }, |
| 3083 | 3346 | else => { |
| 3084 | | try stack.append(RenderState { .Text = ";"}); |
| 3085 | | try stack.append(RenderState { .Expression = base}); |
| 3347 | try stack.append(RenderState { .Semicolon = base }); |
| 3348 | try stack.append(RenderState { .Expression = base }); |
| 3349 | }, |
| 3350 | } |
| 3351 | }, |
| 3352 | RenderState.Semicolon => |base| { |
| 3353 | switch (base.id) { |
| 3354 | ast.Node.Id.Root, |
| 3355 | ast.Node.Id.StructField, |
| 3356 | ast.Node.Id.UnionTag, |
| 3357 | ast.Node.Id.EnumTag, |
| 3358 | ast.Node.Id.ParamDecl, |
| 3359 | ast.Node.Id.Block, |
| 3360 | ast.Node.Id.Payload, |
| 3361 | ast.Node.Id.Switch, |
| 3362 | ast.Node.Id.SwitchCase, |
| 3363 | ast.Node.Id.SwitchElse, |
| 3364 | ast.Node.Id.FieldInitializer, |
| 3365 | ast.Node.Id.LineComment, |
| 3366 | ast.Node.Id.TestDecl => {}, |
| 3367 | ast.Node.Id.While => { |
| 3368 | const while_node = @fieldParentPtr(ast.NodeWhile, "base", base); |
| 3369 | if (while_node.@"else") |@"else"| { |
| 3370 | stack.append(RenderState { .Semicolon = &@"else".base }) catch unreachable; |
| 3371 | continue; |
| 3372 | } |
| 3373 | |
| 3374 | stack.append(RenderState { .Semicolon = while_node.body }) catch unreachable; |
| 3375 | continue; |
| 3376 | }, |
| 3377 | ast.Node.Id.Else => { |
| 3378 | const else_node = @fieldParentPtr(ast.NodeElse, "base", base); |
| 3379 | stack.append(RenderState { .Semicolon = else_node.body }) catch unreachable; |
| 3380 | continue; |
| 3086 | 3381 | }, |
| 3382 | else => { |
| 3383 | try stack.append(RenderState { .Text = ";" }); |
| 3384 | } |
| 3087 | 3385 | } |
| 3088 | 3386 | }, |
| 3089 | 3387 | RenderState.Indent => |new_indent| indent = new_indent, |
| ... | ... | @@ -3690,8 +3988,11 @@ test "zig fmt: while" { |
| 3690 | 3988 | \\ continue; |
| 3691 | 3989 | \\ |
| 3692 | 3990 | \\ i = 0; |
| 3693 | | \\ var j usize = 0; |
| 3694 | | \\ while (i < 10) : ({ i += 1; j += 1; }) { |
| 3991 | \\ var j: usize = 0; |
| 3992 | \\ while (i < 10) : ({ |
| 3993 | \\ i += 1; |
| 3994 | \\ j += 1; |
| 3995 | \\ }) { |
| 3695 | 3996 | \\ continue; |
| 3696 | 3997 | \\ } |
| 3697 | 3998 | \\ |
| ... | ... | @@ -3711,7 +4012,7 @@ test "zig fmt: while" { |
| 3711 | 4012 | \\ break 7; |
| 3712 | 4013 | \\ } else { |
| 3713 | 4014 | \\ unreachable; |
| 3714 | | \\ } |
| 4015 | \\ }; |
| 3715 | 4016 | \\ |
| 3716 | 4017 | \\ var a: error!u8 = 0; |
| 3717 | 4018 | \\ while (a) |v| { |
| ... | ... | @@ -3721,7 +4022,7 @@ test "zig fmt: while" { |
| 3721 | 4022 | \\ } |
| 3722 | 4023 | \\ |
| 3723 | 4024 | \\ comptime var k: usize = 0; |
| 3724 | | \\ inline while (i < 10) (i += 1) |
| 4025 | \\ inline while (i < 10) : (i += 1) |
| 3725 | 4026 | \\ j += 2; |
| 3726 | 4027 | \\} |
| 3727 | 4028 | \\ |