| ... | @@ -1552,34 +1552,47 @@ const PrecClass = struct { | ... | @@ -1552,34 +1552,47 @@ const PrecClass = struct { |
| 1552 | | 1552 | |
| 1553 | root, | 1553 | root, |
| 1554 | | 1554 | |
| 1555 | /// For this to work correctly we require that all subgroups are strictly adjacent | 1555 | const Major = enum { |
| 1556 | /// Major groups are defined by the first text before an underscore | 1556 | top, |
| 1557 | const Major: type = b: { | 1557 | arithmetic, |
| 1558 | var major_names: []const []const u8 = &.{}; | 1558 | bitwise, |
| 1559 | for (std.meta.fieldNames(Group)) |fieldname| { | 1559 | comparison, |
| 1560 | var major_name: []const u8 = fieldname[0..]; | 1560 | bool, |
| 1561 | for (fieldname, 0..) |c, i| { | 1561 | recovery, |
| 1562 | if (c == '_') { | 1562 | root, |
| 1563 | major_name = fieldname[0..i]; | 1563 | }; |
| 1564 | break; | | |
| 1565 | } | | |
| 1566 | } | | |
| 1567 | if (major_names.len == 0 or !std.mem.eql(u8, major_name, major_names[major_names.len - 1])) { | | |
| 1568 | major_names = major_names ++ &[1][]const u8{major_name}; | | |
| 1569 | } | | |
| 1570 | } | | |
| 1571 | | 1564 | |
| 1572 | const IntType = std.math.IntFittingRange(0, major_names.len - 1); | 1565 | fn getMajor(group: Group) Major { |
| 1573 | var values: [major_names.len]IntType = undefined; | 1566 | return switch (group) { |
| 1574 | for (0..major_names.len) |i| values[i] = i; | 1567 | .top, |
| | 1568 | => .top, |
| 1575 | | 1569 | |
| 1576 | break :b @Enum( | 1570 | .arithmetic_product_chainable, |
| 1577 | IntType, | 1571 | .arithmetic_mod_nonchainable, |
| 1578 | .exhaustive, | 1572 | .arithmetic_sum, |
| 1579 | major_names, | 1573 | => .arithmetic, |
| 1580 | &values, | 1574 | |
| 1581 | ); | 1575 | .bitwise_shift, |
| 1582 | }; | 1576 | .bitwise_and, |
| | 1577 | .bitwise_xor, |
| | 1578 | .bitwise_or, |
| | 1579 | => .bitwise, |
| | 1580 | |
| | 1581 | .comparison, |
| | 1582 | => .comparison, |
| | 1583 | |
| | 1584 | .bool_and, |
| | 1585 | .bool_or, |
| | 1586 | => .bool, |
| | 1587 | |
| | 1588 | .recovery_orelse, |
| | 1589 | .recovery_catch, |
| | 1590 | => .recovery, |
| | 1591 | |
| | 1592 | .root, |
| | 1593 | => .root, |
| | 1594 | }; |
| | 1595 | } |
| 1583 | }; | 1596 | }; |
| 1584 | | 1597 | |
| 1585 | pub const start: PrecClass = .{ .group = .root }; | 1598 | pub const start: PrecClass = .{ .group = .root }; |
| ... | @@ -1598,29 +1611,22 @@ const PrecClass = struct { | ... | @@ -1598,29 +1611,22 @@ const PrecClass = struct { |
| 1598 | | 1611 | |
| 1599 | fn setMajorRelation(prec_array: *PrecedenceArray, major_a: Group.Major, rel: Rel, major_b: Group.Major) void { | 1612 | fn setMajorRelation(prec_array: *PrecedenceArray, major_a: Group.Major, rel: Rel, major_b: Group.Major) void { |
| 1600 | for (std.meta.fieldNames(Group), 0..) |fieldname_i, i| { | 1613 | for (std.meta.fieldNames(Group), 0..) |fieldname_i, i| { |
| 1601 | if (!std.mem.startsWith(u8, fieldname_i, @tagName(major_a))) continue; | 1614 | if (@field(Group, fieldname_i).getMajor() != major_a) continue; |
| 1602 | | 1615 | |
| 1603 | for (std.meta.fieldNames(Group), 0..) |fieldname_j, j| { | 1616 | for (std.meta.fieldNames(Group), 0..) |fieldname_j, j| { |
| 1604 | if (!std.mem.startsWith(u8, fieldname_j, @tagName(major_b))) continue; | 1617 | if (@field(Group, fieldname_j).getMajor() != major_b) continue; |
| 1605 | | 1618 | |
| 1606 | prec_array.*[i][j] = rel; | 1619 | prec_array[i][j] = rel; |
| 1607 | prec_array.*[j][i] = rel.inverted(); | 1620 | prec_array[j][i] = rel.inverted(); |
| 1608 | } | 1621 | } |
| 1609 | } | 1622 | } |
| 1610 | } | 1623 | } |
| 1611 | | 1624 | |
| 1612 | fn setMinorRelation(prec_array: *PrecedenceArray, minor_a: Group, rel: Rel, minor_b: Group) void { | 1625 | fn setMinorRelation(prec_array: *PrecedenceArray, minor_a: Group, rel: Rel, minor_b: Group) void { |
| 1613 | prec_array.*[@backingInt(minor_a)][@backingInt(minor_b)] = rel; | 1626 | prec_array[@backingInt(minor_a)][@backingInt(minor_b)] = rel; |
| 1614 | prec_array.*[@backingInt(minor_b)][@backingInt(minor_a)] = rel.inverted(); | 1627 | prec_array[@backingInt(minor_b)][@backingInt(minor_a)] = rel.inverted(); |
| 1615 | } | 1628 | } |
| 1616 | | 1629 | |
| 1617 | /// Arithmetic_* > Comparison | | |
| 1618 | /// Bitwise_* > Comparison | | |
| 1619 | /// Comparison > Bool_* > Root | | |
| 1620 | /// Recovery > Root | | |
| 1621 | /// | | |
| 1622 | /// *_Product > *_Sum | | |
| 1623 | /// | | |
| 1624 | /// order[y][x] --> y cmp x | 1630 | /// order[y][x] --> y cmp x |
| 1625 | const precedence_ordering = b: { | 1631 | const precedence_ordering = b: { |
| 1626 | @setEvalBranchQuota(20_000); | 1632 | @setEvalBranchQuota(20_000); |
| ... | @@ -1646,7 +1652,7 @@ const PrecClass = struct { | ... | @@ -1646,7 +1652,7 @@ const PrecClass = struct { |
| 1646 | setMinorRelation(&order, .arithmetic_mod_nonchainable, .gt, .arithmetic_sum); | 1652 | setMinorRelation(&order, .arithmetic_mod_nonchainable, .gt, .arithmetic_sum); |
| 1647 | setMinorRelation(&order, .arithmetic_product_chainable, .gt, .arithmetic_sum); | 1653 | setMinorRelation(&order, .arithmetic_product_chainable, .gt, .arithmetic_sum); |
| 1648 | | 1654 | |
| 1649 | computeTransativeOrdering(&order); | 1655 | computeTransitiveOrdering(&order); |
| 1650 | break :b order; | 1656 | break :b order; |
| 1651 | }; | 1657 | }; |
| 1652 | | 1658 | |
| ... | @@ -1658,7 +1664,7 @@ const PrecClass = struct { | ... | @@ -1658,7 +1664,7 @@ const PrecClass = struct { |
| 1658 | /// == != < > <= >= | 1664 | /// == != < > <= >= |
| 1659 | /// and | 1665 | /// and |
| 1660 | /// or | 1666 | /// or |
| 1661 | const v16_precedence_ordering = b: { | 1667 | const v0_16_precedence_ordering = b: { |
| 1662 | @setEvalBranchQuota(20_000); | 1668 | @setEvalBranchQuota(20_000); |
| 1663 | | 1669 | |
| 1664 | var order: PrecedenceArray = @splat(@splat(null)); | 1670 | var order: PrecedenceArray = @splat(@splat(null)); |
| ... | @@ -1685,7 +1691,7 @@ const PrecClass = struct { | ... | @@ -1685,7 +1691,7 @@ const PrecClass = struct { |
| 1685 | | 1691 | |
| 1686 | setMinorRelation(&order, .bool_or, .gt, .root); | 1692 | setMinorRelation(&order, .bool_or, .gt, .root); |
| 1687 | | 1693 | |
| 1688 | computeTransativeOrdering(&order); | 1694 | computeTransitiveOrdering(&order); |
| 1689 | for (order) |row| { | 1695 | for (order) |row| { |
| 1690 | for (row) |item| { | 1696 | for (row) |item| { |
| 1691 | if (item == null) @compileError("Null entry in old precedence ordering which had none."); | 1697 | if (item == null) @compileError("Null entry in old precedence ordering which had none."); |
| ... | @@ -1698,11 +1704,11 @@ const PrecClass = struct { | ... | @@ -1698,11 +1704,11 @@ const PrecClass = struct { |
| 1698 | return PrecClass.precedence_ordering[@backingInt(lhs.group)][@backingInt(rhs.group)]; | 1704 | return PrecClass.precedence_ordering[@backingInt(lhs.group)][@backingInt(rhs.group)]; |
| 1699 | } | 1705 | } |
| 1700 | | 1706 | |
| 1701 | pub fn v16_cmp(lhs: PrecClass, rhs: PrecClass) Rel { | 1707 | pub fn v0_16_cmp(lhs: PrecClass, rhs: PrecClass) Rel { |
| 1702 | return PrecClass.v16_precedence_ordering[@backingInt(lhs.group)][@backingInt(rhs.group)].?; | 1708 | return PrecClass.v0_16_precedence_ordering[@backingInt(lhs.group)][@backingInt(rhs.group)].?; |
| 1703 | } | 1709 | } |
| 1704 | | 1710 | |
| 1705 | fn computeTransativeOrdering(order: *PrecedenceArray) void { | 1711 | fn computeTransitiveOrdering(order: *PrecedenceArray) void { |
| 1706 | for (0..Group.num_distinct) |i| for (0..Group.num_distinct) |j| for (0..Group.num_distinct) |k| { | 1712 | for (0..Group.num_distinct) |i| for (0..Group.num_distinct) |j| for (0..Group.num_distinct) |k| { |
| 1707 | if (order[i][j] == null or order[j][k] == null) continue; | 1713 | if (order[i][j] == null or order[j][k] == null) continue; |
| 1708 | // X < Y < Z ==> X < Z X > Y > Z ==> X > Z | 1714 | // X < Y < Z ==> X < Z X > Y > Z ==> X > Z |
| ... | @@ -1766,23 +1772,6 @@ const operTable = std.enums.directEnumArrayDefault(Token.Tag, OperInfo, .{ .prec | ... | @@ -1766,23 +1772,6 @@ const operTable = std.enums.directEnumArrayDefault(Token.Tag, OperInfo, .{ .prec |
| 1766 | // zig fmt: on | 1772 | // zig fmt: on |
| 1767 | }); | 1773 | }); |
| 1768 | | 1774 | |
| 1769 | fn comptimePrecedenceFromNodeTag(comptime tag: Node.Tag) PrecClass { | | |
| 1770 | for (operTable) |data| { | | |
| 1771 | if (data.tag == tag) return data.prec; | | |
| 1772 | } | | |
| 1773 | return .{ .group = .top, .assoc = .left }; | | |
| 1774 | } | | |
| 1775 | | | |
| 1776 | pub fn precedenceFromNodeTag(tag: Node.Tag) PrecClass { | | |
| 1777 | return switch (tag) { | | |
| 1778 | inline else => |ct_tag| comptimePrecedenceFromNodeTag(ct_tag), | | |
| 1779 | }; | | |
| 1780 | } | | |
| 1781 | | | |
| 1782 | pub fn newPrecedenceBetween(left_tok: Node.Tag, right_tok: Node.Tag) ?PrecClass.Rel { | | |
| 1783 | return precedenceFromNodeTag(left_tok).cmp(precedenceFromNodeTag(right_tok)); | | |
| 1784 | } | | |
| 1785 | | | |
| 1786 | fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32) Error!?Node.Index { | 1775 | fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32) Error!?Node.Index { |
| 1787 | var node = try p.parsePrefixExpr() orelse return null; | 1776 | var node = try p.parsePrefixExpr() orelse return null; |
| 1788 | | 1777 | |
| ... | @@ -1793,10 +1782,9 @@ fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32 | ... | @@ -1793,10 +1782,9 @@ fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32 |
| 1793 | const info = operTable[@backingInt(tok_tag)]; | 1782 | const info = operTable[@backingInt(tok_tag)]; |
| 1794 | | 1783 | |
| 1795 | const rel = info.prec.cmp(min_exc_prec) orelse b: { | 1784 | const rel = info.prec.cmp(min_exc_prec) orelse b: { |
| 1796 | // This issues warnings if the relation is null, which it never is in 0.16.0 | | |
| 1797 | const prev_op_tok_tag = p.tokenTag(prev_operator_token); | 1785 | const prev_op_tok_tag = p.tokenTag(prev_operator_token); |
| 1798 | const prev_op_info = operTable[@backingInt(prev_op_tok_tag)]; | 1786 | const prev_op_info = operTable[@backingInt(prev_op_tok_tag)]; |
| 1799 | const v16_rel = prev_op_info.prec.v16_cmp(info.prec); | 1787 | const v0_16_rel = prev_op_info.prec.v0_16_cmp(info.prec); |
| 1800 | try p.warnMsg(.{ | 1788 | try p.warnMsg(.{ |
| 1801 | .tag = .ambiguous_operator_precedence, | 1789 | .tag = .ambiguous_operator_precedence, |
| 1802 | .is_note = false, | 1790 | .is_note = false, |
| ... | @@ -1810,7 +1798,7 @@ fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32 | ... | @@ -1810,7 +1798,7 @@ fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32 |
| 1810 | .is_note = true, | 1798 | .is_note = true, |
| 1811 | .token = prev_operator_token, | 1799 | .token = prev_operator_token, |
| 1812 | }); | 1800 | }); |
| 1813 | if (v16_rel == .gt or v16_rel == .eq) { | 1801 | if (v0_16_rel == .gt or v0_16_rel == .eq) { |
| 1814 | try p.warnMsg(.{ | 1802 | try p.warnMsg(.{ |
| 1815 | .tag = .hint_operator_precedence_left, | 1803 | .tag = .hint_operator_precedence_left, |
| 1816 | .is_note = true, | 1804 | .is_note = true, |
| ... | @@ -1830,7 +1818,7 @@ fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32 | ... | @@ -1830,7 +1818,7 @@ fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32 |
| 1830 | }); | 1818 | }); |
| 1831 | } | 1819 | } |
| 1832 | // Use the old precedence rules to construct the tree to ease automatic fixups | 1820 | // Use the old precedence rules to construct the tree to ease automatic fixups |
| 1833 | break :b info.prec.v16_cmp(min_exc_prec); | 1821 | break :b info.prec.v0_16_cmp(min_exc_prec); |
| 1834 | }; | 1822 | }; |
| 1835 | | 1823 | |
| 1836 | if (rel == .lt) { | 1824 | if (rel == .lt) { |
| ... | @@ -1838,7 +1826,6 @@ fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32 | ... | @@ -1838,7 +1826,6 @@ fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32 |
| 1838 | } | 1826 | } |
| 1839 | | 1827 | |
| 1840 | if (min_exc_prec.group == info.prec.group and min_exc_prec.assoc == .none and info.prec.assoc == .none) { | 1828 | if (min_exc_prec.group == info.prec.group and min_exc_prec.assoc == .none and info.prec.assoc == .none) { |
| 1841 | //Special cased check to maintain the old more helpful error for chained comparisons. | | |
| 1842 | if (info.prec.group == .comparison) { | 1829 | if (info.prec.group == .comparison) { |
| 1843 | try p.warn(.chained_comparison_operators); | 1830 | try p.warn(.chained_comparison_operators); |
| 1844 | } else { | 1831 | } else { |