@@ -1650,6 +1650,70 @@ class cppfront
1650
1650
return ;
1651
1651
}
1652
1652
1653
+ // Check to see if it's just a function call syntax chained with other functions,
1654
+ // and if so use this path to convert it to UFCS
1655
+ if (// there's a single-token expression followed by (, ., and (
1656
+ n.expr ->get_token () && // if the base expression is a single token
1657
+ std::ssize (n.ops ) >= 3 && // and we're of the form:
1658
+ n.ops [0 ].op ->type () == lexeme::LeftParen && // token ( expr-list ) . id-expr ( expr-list )
1659
+ n.ops [1 ].op ->type () == lexeme::Dot &&
1660
+ n.ops [2 ].op ->type () == lexeme::LeftParen
1661
+ )
1662
+ {
1663
+ // If we already replaced this with a capture (which contains the UFCS
1664
+ // work already done when the capture was computed), emit the capture
1665
+ if (!captured_part.empty ()) {
1666
+ printer.print_cpp2 (captured_part, n.position ());
1667
+ return ;
1668
+ }
1669
+
1670
+ // Otherwise, do the UFCS work...
1671
+
1672
+ // If method are chained we need to go from the last to the first
1673
+ // token(a-expr-list).b(b-expr-list).c(c-expr-list) will be tranformed to:
1674
+ // CPP2_UFCS(c, CPP2_UFCS(b, CPP2_UFCS(token, a-expr-list), b-expr-list), c-expr-list )
1675
+ for (auto i = std::ssize (n.ops )-1 ; i > 1 ; i -= 2 )
1676
+ {
1677
+ // The . has its id_expr
1678
+ assert (n.ops [i-1 ].id_expr );
1679
+
1680
+ // The ( has its expr_list and op_close
1681
+ assert (n.ops [i].expr_list && n.ops [i].op_close );
1682
+
1683
+ // If there are no additional arguments, use the CPP2_UFCS_0 version
1684
+ if (!n.ops [i].expr_list ->expressions .empty ()) {
1685
+ printer.print_cpp2 (" CPP2_UFCS(" , n.position ());
1686
+ }
1687
+ else {
1688
+ printer.print_cpp2 (" CPP2_UFCS_0(" , n.position ());
1689
+ }
1690
+ emit (*n.ops [i-1 ].id_expr );
1691
+ printer.print_cpp2 (" , " , n.position ());
1692
+ }
1693
+
1694
+ // emit the first function that starts chaining (the most nested one)
1695
+ emit (*n.expr );
1696
+ printer.print_cpp2 (" (" , n.position ());
1697
+ if (!n.ops [0 ].expr_list ->expressions .empty ()) {
1698
+ emit (*n.ops [0 ].expr_list );
1699
+ }
1700
+ printer.print_cpp2 (" )" , n.position ());
1701
+
1702
+ // unroll the nested calls (skipping the first function call)
1703
+ // expr-list need to be added in reversed order then CPP2_UFCS macros
1704
+ for (auto i = 2 ; i < std::ssize (n.ops ); i += 2 ) {
1705
+ // Then tack on any additional arguments
1706
+ if (!n.ops [i].expr_list ->expressions .empty ()) {
1707
+ printer.print_cpp2 (" , " , n.position ());
1708
+ emit (*n.ops [i].expr_list );
1709
+ }
1710
+ printer.print_cpp2 (" )" , n.position ());
1711
+ }
1712
+
1713
+ // And we're done. This path has handled this node, so return...
1714
+ return ;
1715
+ }
1716
+
1653
1717
// Otherwise, we're going to have to potentially do some work to change
1654
1718
// some Cpp2 postfix operators to Cpp1 prefix operators, so let's set up...
1655
1719
auto prefix = std::vector<text_with_pos>{};
0 commit comments