| ... | ... | @@ -1552,34 +1552,47 @@ const PrecClass = struct { |
| 1552 | 1552 | |
| 1553 | 1553 | root, |
| 1554 | 1554 | |
| 1555 | | /// For this to work correctly we require that all subgroups are strictly adjacent |
| 1556 | | /// Major groups are defined by the first text before an underscore |
| 1557 | | const Major: type = b: { |
| 1558 | | var major_names: []const []const u8 = &.{}; |
| 1559 | | for (std.meta.fieldNames(Group)) |fieldname| { |
| 1560 | | var major_name: []const u8 = fieldname[0..]; |
| 1561 | | for (fieldname, 0..) |c, i| { |
| 1562 | | if (c == '_') { |
| 1563 | | major_name = fieldname[0..i]; |
| 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 | | } |
| 1555 | const Major = enum { |
| 1556 | top, |
| 1557 | arithmetic, |
| 1558 | bitwise, |
| 1559 | comparison, |
| 1560 | bool, |
| 1561 | recovery, |
| 1562 | root, |
| 1563 | }; |
| 1571 | 1564 | |
| 1572 | | const IntType = std.math.IntFittingRange(0, major_names.len - 1); |
| 1573 | | var values: [major_names.len]IntType = undefined; |
| 1574 | | for (0..major_names.len) |i| values[i] = i; |
| 1565 | fn getMajor(group: Group) Major { |
| 1566 | return switch (group) { |
| 1567 | .top, |
| 1568 | => .top, |
| 1575 | 1569 | |
| 1576 | | break :b @Enum( |
| 1577 | | IntType, |
| 1578 | | .exhaustive, |
| 1579 | | major_names, |
| 1580 | | &values, |
| 1581 | | ); |
| 1582 | | }; |
| 1570 | .arithmetic_product_chainable, |
| 1571 | .arithmetic_mod_nonchainable, |
| 1572 | .arithmetic_sum, |
| 1573 | => .arithmetic, |
| 1574 | |
| 1575 | .bitwise_shift, |
| 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 | 1598 | pub const start: PrecClass = .{ .group = .root }; |
| ... | ... | @@ -1598,29 +1611,22 @@ const PrecClass = struct { |
| 1598 | 1611 | |
| 1599 | 1612 | fn setMajorRelation(prec_array: *PrecedenceArray, major_a: Group.Major, rel: Rel, major_b: Group.Major) void { |
| 1600 | 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 | 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; |
| 1607 | | prec_array.*[j][i] = rel.inverted(); |
| 1619 | prec_array[i][j] = rel; |
| 1620 | prec_array[j][i] = rel.inverted(); |
| 1608 | 1621 | } |
| 1609 | 1622 | } |
| 1610 | 1623 | } |
| 1611 | 1624 | |
| 1612 | 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; |
| 1614 | | prec_array.*[@backingInt(minor_b)][@backingInt(minor_a)] = rel.inverted(); |
| 1626 | prec_array[@backingInt(minor_a)][@backingInt(minor_b)] = rel; |
| 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 | 1630 | /// order[y][x] --> y cmp x |
| 1625 | 1631 | const precedence_ordering = b: { |
| 1626 | 1632 | @setEvalBranchQuota(20_000); |
| ... | ... | @@ -1646,7 +1652,7 @@ const PrecClass = struct { |
| 1646 | 1652 | setMinorRelation(&order, .arithmetic_mod_nonchainable, .gt, .arithmetic_sum); |
| 1647 | 1653 | setMinorRelation(&order, .arithmetic_product_chainable, .gt, .arithmetic_sum); |
| 1648 | 1654 | |
| 1649 | | computeTransativeOrdering(&order); |
| 1655 | computeTransitiveOrdering(&order); |
| 1650 | 1656 | break :b order; |
| 1651 | 1657 | }; |
| 1652 | 1658 | |
| ... | ... | @@ -1658,7 +1664,7 @@ const PrecClass = struct { |
| 1658 | 1664 | /// == != < > <= >= |
| 1659 | 1665 | /// and |
| 1660 | 1666 | /// or |
| 1661 | | const v16_precedence_ordering = b: { |
| 1667 | const v0_16_precedence_ordering = b: { |
| 1662 | 1668 | @setEvalBranchQuota(20_000); |
| 1663 | 1669 | |
| 1664 | 1670 | var order: PrecedenceArray = @splat(@splat(null)); |
| ... | ... | @@ -1685,7 +1691,7 @@ const PrecClass = struct { |
| 1685 | 1691 | |
| 1686 | 1692 | setMinorRelation(&order, .bool_or, .gt, .root); |
| 1687 | 1693 | |
| 1688 | | computeTransativeOrdering(&order); |
| 1694 | computeTransitiveOrdering(&order); |
| 1689 | 1695 | for (order) |row| { |
| 1690 | 1696 | for (row) |item| { |
| 1691 | 1697 | if (item == null) @compileError("Null entry in old precedence ordering which had none."); |
| ... | ... | @@ -1698,11 +1704,11 @@ const PrecClass = struct { |
| 1698 | 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 { |
| 1702 | | return PrecClass.v16_precedence_ordering[@backingInt(lhs.group)][@backingInt(rhs.group)].?; |
| 1707 | pub fn v0_16_cmp(lhs: PrecClass, rhs: PrecClass) Rel { |
| 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 | 1712 | for (0..Group.num_distinct) |i| for (0..Group.num_distinct) |j| for (0..Group.num_distinct) |k| { |
| 1707 | 1713 | if (order[i][j] == null or order[j][k] == null) continue; |
| 1708 | 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 | 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 | 1775 | fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32) Error!?Node.Index { |
| 1787 | 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 | 1782 | const info = operTable[@backingInt(tok_tag)]; |
| 1794 | 1783 | |
| 1795 | 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 | 1785 | const prev_op_tok_tag = p.tokenTag(prev_operator_token); |
| 1798 | 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 | 1788 | try p.warnMsg(.{ |
| 1801 | 1789 | .tag = .ambiguous_operator_precedence, |
| 1802 | 1790 | .is_note = false, |
| ... | ... | @@ -1810,7 +1798,7 @@ fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32 |
| 1810 | 1798 | .is_note = true, |
| 1811 | 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 | 1802 | try p.warnMsg(.{ |
| 1815 | 1803 | .tag = .hint_operator_precedence_left, |
| 1816 | 1804 | .is_note = true, |
| ... | ... | @@ -1830,7 +1818,7 @@ fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32 |
| 1830 | 1818 | }); |
| 1831 | 1819 | } |
| 1832 | 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 | 1824 | if (rel == .lt) { |
| ... | ... | @@ -1838,7 +1826,6 @@ fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32 |
| 1838 | 1826 | } |
| 1839 | 1827 | |
| 1840 | 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 | 1829 | if (info.prec.group == .comparison) { |
| 1843 | 1830 | try p.warn(.chained_comparison_operators); |
| 1844 | 1831 | } else { |