@@ -1726,77 +1726,6 @@ class cppfront
1726
1726
captured_part += " _" + std::to_string (mynum);
1727
1727
}
1728
1728
1729
- // Check to see if it's just a function call with "." syntax,
1730
- // and if so use this path to convert it to UFCS
1731
- if (// there's a single-token expression followed by . and (
1732
- n.expr ->get_token () && // if the base expression is a single token
1733
- std::ssize (n.ops ) >= 2 && // and we're of the form:
1734
- n.ops [0 ].op ->type () == lexeme::Dot && // token . id-expr ( expr-list )
1735
- n.ops [1 ].op ->type () == lexeme::LeftParen &&
1736
- // alpha limitation: if it's a function call with more than one template argument (e.g., x.f<1,2>())
1737
- // the UFCS* macros can't handle that right now, so don't UFCS-size it
1738
- n.ops [0 ].id_expr ->template_args_count () < 2 &&
1739
- // and either there's nothing after that, or there's just a $ after that
1740
- (
1741
- std::ssize (n.ops ) == 2 ||
1742
- (std::ssize (n.ops ) == 3 && n.ops [2 ].op ->type () == lexeme::Dollar)
1743
- )
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
- // The . has its id_expr
1756
- assert (n.ops [0 ].id_expr );
1757
-
1758
- // The ( has its expr_list and op_close
1759
- assert (n.ops [1 ].expr_list && n.ops [1 ].op_close );
1760
-
1761
- // --------------------------------------------------------------------
1762
- // TODO: When MSVC supports __VA_OPT__ in standard mode without the
1763
- // experimental /Zc:preprocessor switch, use this single line
1764
- // instead of the dual lines below that special-case _0 args
1765
- // AND: Make the similarly noted change in cpp2util.h
1766
- //
1767
- // printer.print_cpp2("CPP2_UFCS(", n.position());
1768
-
1769
- auto ufcs_string = std::string (" CPP2_UFCS" );
1770
- if (n.ops [0 ].id_expr ->template_args_count () > 0 ) {
1771
- ufcs_string += " _TEMPLATE" ;
1772
- }
1773
- // If there are no additional arguments, use the _0 version
1774
- if (n.ops [1 ].expr_list ->expressions .empty ()) {
1775
- ufcs_string += " _0" ;
1776
- }
1777
- printer.print_cpp2 (ufcs_string+" (" , n.position ());
1778
- // --------------------------------------------------------------------
1779
-
1780
- // Make the "funcname" the first argument to CPP2_UFCS
1781
- emit (*n.ops [0 ].id_expr );
1782
- printer.print_cpp2 (" , " , n.position ());
1783
-
1784
- // Then make the base expression the second argument
1785
- emit (*n.expr );
1786
-
1787
- // Then tack on any additional arguments
1788
- if (!n.ops [1 ].expr_list ->expressions .empty ()) {
1789
- printer.print_cpp2 (" , " , n.position ());
1790
- push_need_expression_list_parens (false );
1791
- emit (*n.ops [1 ].expr_list );
1792
- pop_need_expression_list_parens ();
1793
- }
1794
- printer.print_cpp2 (" )" , n.position ());
1795
-
1796
- // And we're done. This path has handled this node, so return...
1797
- return ;
1798
- }
1799
-
1800
1729
// Otherwise, we're going to have to potentially do some work to change
1801
1730
// some Cpp2 postfix operators to Cpp1 prefix operators, so let's set up...
1802
1731
auto prefix = std::vector<text_with_pos>{};
@@ -1805,6 +1734,25 @@ class cppfront
1805
1734
auto last_was_prefixed = false ;
1806
1735
auto saw_dollar = false ;
1807
1736
1737
+ auto args = std::optional<std::vector<text_with_pos>>{};
1738
+
1739
+ auto print_to_string = [&](auto & i, auto ... args) {
1740
+ auto print = std::string{};
1741
+ printer.emit_to_string (&print);
1742
+ emit (i, args...);
1743
+ printer.emit_to_string ();
1744
+ return print;
1745
+ };
1746
+ auto print_to_text_chunks = [&](auto & i, auto ... args) {
1747
+ auto text = std::vector<text_with_pos>{};
1748
+ printer.emit_to_text_chunks (&text);
1749
+ push_need_expression_list_parens (false );
1750
+ emit (i, args...);
1751
+ pop_need_expression_list_parens ();
1752
+ printer.emit_to_text_chunks ();
1753
+ return text;
1754
+ };
1755
+
1808
1756
for (auto i = n.ops .rbegin (); i != n.ops .rend (); ++i)
1809
1757
{
1810
1758
assert (i->op );
@@ -1828,9 +1776,57 @@ class cppfront
1828
1776
}
1829
1777
}
1830
1778
1779
+ // Going backwards if we found LeftParen it might be UFCS
1780
+ // expr_list is emited to args variable for future use
1781
+ if (i->op ->type () == lexeme::LeftParen) {
1782
+
1783
+ args.emplace ();
1784
+
1785
+ if (!i->expr_list ->expressions .empty ()) {
1786
+ args.emplace (print_to_text_chunks (*i->expr_list ));
1787
+ }
1788
+
1789
+ }
1790
+ // Going backwards if we found Dot and there is args variable
1791
+ // it means that it should be handled by UFCS
1792
+ else if ( i->op ->type () == lexeme::Dot && args
1793
+ // don't use UFCS for methods with more than one template argument
1794
+ && i->id_expr && i->id_expr ->template_args_count () < 2
1795
+ )
1796
+ {
1797
+ auto funcname = print_to_string (*i->id_expr );
1798
+
1799
+ // --------------------------------------------------------------------
1800
+ // TODO: When MSVC supports __VA_OPT__ in standard mode without the
1801
+ // experimental /Zc:preprocessor switch, use this single line
1802
+ // instead of the dual lines below that special-case _0 args
1803
+ // AND: Make the similarly noted change in cpp2util.h
1804
+ //
1805
+ // printer.print_cpp2("CPP2_UFCS(", n.position());
1806
+
1807
+ auto ufcs_string = std::string (" CPP2_UFCS" );
1808
+ if (i->id_expr ->template_args_count () > 0 ) {
1809
+ ufcs_string += " _TEMPLATE" ;
1810
+ }
1811
+ // If there are no additional arguments, use the _0 version
1812
+ if (args.value ().empty ()) {
1813
+ ufcs_string += " _0" ;
1814
+ }
1815
+
1816
+ prefix.emplace_back (ufcs_string + " (" + funcname + " , " , i->op ->position () );
1817
+ suffix.emplace_back (" )" , i->op ->position () );
1818
+ if (!args.value ().empty ()) {
1819
+ for (auto && e: args.value ()) {
1820
+ suffix.push_back (e);
1821
+ }
1822
+ suffix.emplace_back (" , " , i->op ->position ());
1823
+ }
1824
+ args.reset ();
1825
+ }
1826
+
1831
1827
// Handle the Cpp2 postfix operators that are prefix in Cpp1
1832
1828
//
1833
- if (i->op ->type () == lexeme::MinusMinus ||
1829
+ else if (i->op ->type () == lexeme::MinusMinus ||
1834
1830
i->op ->type () == lexeme::PlusPlus ||
1835
1831
i->op ->type () == lexeme::Multiply ||
1836
1832
i->op ->type () == lexeme::Ampersand ||
@@ -1874,21 +1870,25 @@ class cppfront
1874
1870
}
1875
1871
1876
1872
if (i->id_expr ) {
1877
- auto print = std::string{};
1878
- printer.emit_to_string (&print);
1879
- emit (*i->id_expr , false /* not a local name*/ );
1880
- printer.emit_to_string ();
1873
+
1874
+ if (args) {
1875
+ // if args are stored it means that this is function or method
1876
+ // that is not handled by UFCS e.g. that has more than one template argument
1877
+ suffix.emplace_back (" )" , n.position ());
1878
+ for (auto && e: args.value ()) {
1879
+ suffix.push_back (e);
1880
+ }
1881
+ suffix.emplace_back (" (" , n.position ());
1882
+ args.reset ();
1883
+ }
1884
+
1885
+ auto print = print_to_string (*i->id_expr , false /* not a local name*/ );
1881
1886
suffix.emplace_back ( print, i->id_expr ->position () );
1882
1887
}
1883
1888
1884
1889
if (i->expr_list ) {
1885
- auto text = std::vector<text_with_pos>{};
1886
- printer.emit_to_text_chunks (&text);
1887
- push_need_expression_list_parens (false );
1888
- emit (*i->expr_list );
1889
- pop_need_expression_list_parens ();
1890
- printer.emit_to_text_chunks ();
1891
- for (auto && e: text) {
1890
+ auto text = print_to_text_chunks (*i->expr_list );
1891
+ for (auto && e: text) {
1892
1892
suffix.push_back (e);
1893
1893
}
1894
1894
}
@@ -1904,6 +1904,8 @@ class cppfront
1904
1904
}
1905
1905
}
1906
1906
1907
+
1908
+
1907
1909
// Print the prefixes (in forward order)
1908
1910
for (auto & e : prefix) {
1909
1911
printer.print_cpp2 (e.text , n.position ());
@@ -1928,6 +1930,18 @@ class cppfront
1928
1930
}
1929
1931
suppress_move_from_last_use = false ;
1930
1932
1933
+ if (args) {
1934
+ // if after printing core expression args is defined
1935
+ // it means that the chaining started by function call
1936
+ // we need to print its arguments
1937
+ suffix.emplace_back (" )" , n.position ());
1938
+ for (auto && e: args.value ()) {
1939
+ suffix.push_back (e);
1940
+ }
1941
+ suffix.emplace_back (" (" , n.position ());
1942
+ args.reset ();
1943
+ }
1944
+
1931
1945
// Print the suffixes (in reverse order)
1932
1946
while (!suffix.empty ()) {
1933
1947
printer.print_cpp2 (suffix.back ().text , suffix.back ().pos );
0 commit comments