@@ -1733,6 +1733,74 @@ class cppfront
1733
1733
return ;
1734
1734
}
1735
1735
1736
+ // Check to see if it's just a function call syntax chained with other functions,
1737
+ // and if so use this path to convert it to UFCS
1738
+ if (// there's a single-token expression followed by (, ., and (
1739
+ n.expr ->get_token () && // if the base expression is a single token
1740
+ std::ssize (n.ops ) >= 3 && // and we're of the form:
1741
+ n.ops [0 ].op ->type () == lexeme::LeftParen && // token ( expr-list ) . id-expr ( expr-list )
1742
+ n.ops [1 ].op ->type () == lexeme::Dot &&
1743
+ n.ops [2 ].op ->type () == lexeme::LeftParen
1744
+ )
1745
+ {
1746
+ // If we already replaced this with a capture (which contains the UFCS
1747
+ // work already done when the capture was computed), emit the capture
1748
+ if (!captured_part.empty ()) {
1749
+ printer.print_cpp2 (captured_part, n.position ());
1750
+ return ;
1751
+ }
1752
+
1753
+ // Otherwise, do the UFCS work...
1754
+
1755
+ // If method are chained we need to go from the last to the first
1756
+ // token(a-expr-list).b(b-expr-list).c(c-expr-list) will be tranformed to:
1757
+ // CPP2_UFCS(c, CPP2_UFCS(b, CPP2_UFCS(token, a-expr-list), b-expr-list), c-expr-list )
1758
+ for (auto i = std::ssize (n.ops )-1 ; i > 1 ; i -= 2 )
1759
+ {
1760
+ // The . has its id_expr
1761
+ assert (n.ops [i-1 ].id_expr );
1762
+
1763
+ // The ( has its expr_list and op_close
1764
+ assert (n.ops [i].expr_list && n.ops [i].op_close );
1765
+
1766
+ // --------------------------------------------------------------------
1767
+ // TODO: When MSVC supports __VA_OPT__ in standard mode without the
1768
+ // experimental /Zc:preprocessor switch, use this single line
1769
+ // instead of the dual lines below that special-case _0 args
1770
+ // AND: Make the similarly noted change in cpp2util.h
1771
+ //
1772
+ // If there are no additional arguments, use the CPP2_UFCS_0 version
1773
+ if (!n.ops [i].expr_list ->expressions .empty ()) {
1774
+ printer.print_cpp2 (" CPP2_UFCS(" , n.position ());
1775
+ }
1776
+ else {
1777
+ printer.print_cpp2 (" CPP2_UFCS_0(" , n.position ());
1778
+ }
1779
+ emit (*n.ops [i-1 ].id_expr );
1780
+ printer.print_cpp2 (" , " , n.position ());
1781
+ }
1782
+
1783
+ // emit the first function that starts chaining (the most nested one)
1784
+ emit (*n.expr );
1785
+ if (!n.ops [0 ].expr_list ->expressions .empty ()) {
1786
+ emit (*n.ops [0 ].expr_list );
1787
+ }
1788
+
1789
+ // unroll the nested calls (skipping the first function call)
1790
+ // expr-list need to be added in reversed order then CPP2_UFCS macros
1791
+ for (auto i = 2 ; i < std::ssize (n.ops ); i += 2 ) {
1792
+ // Then tack on any additional arguments
1793
+ if (!n.ops [i].expr_list ->expressions .empty ()) {
1794
+ printer.print_cpp2 (" , " , n.position ());
1795
+ emit (*n.ops [i].expr_list );
1796
+ }
1797
+ printer.print_cpp2 (" )" , n.position ());
1798
+ }
1799
+
1800
+ // And we're done. This path has handled this node, so return...
1801
+ return ;
1802
+ }
1803
+
1736
1804
// Otherwise, we're going to have to potentially do some work to change
1737
1805
// some Cpp2 postfix operators to Cpp1 prefix operators, so let's set up...
1738
1806
auto prefix = std::vector<text_with_pos>{};
0 commit comments