18
18
#include " sema.h"
19
19
#include < iostream>
20
20
#include < cstdio>
21
-
21
+ # include < optional >
22
22
23
23
namespace cpp2 {
24
24
@@ -1725,77 +1725,6 @@ class cppfront
1725
1725
captured_part += " _" + std::to_string (mynum);
1726
1726
}
1727
1727
1728
- // Check to see if it's just a function call with "." syntax,
1729
- // and if so use this path to convert it to UFCS
1730
- if (// there's a single-token expression followed by . and (
1731
- n.expr ->get_token () && // if the base expression is a single token
1732
- std::ssize (n.ops ) >= 2 && // and we're of the form:
1733
- n.ops [0 ].op ->type () == lexeme::Dot && // token . id-expr ( expr-list )
1734
- n.ops [1 ].op ->type () == lexeme::LeftParen &&
1735
- // alpha limitation: if it's a function call with more than one template argument (e.g., x.f<1,2>())
1736
- // the UFCS* macros can't handle that right now, so don't UFCS-size it
1737
- n.ops [0 ].id_expr ->template_args_count () < 2 &&
1738
- // and either there's nothing after that, or there's just a $ after that
1739
- (
1740
- std::ssize (n.ops ) == 2 ||
1741
- (std::ssize (n.ops ) == 3 && n.ops [2 ].op ->type () == lexeme::Dollar)
1742
- )
1743
- )
1744
- {
1745
- // If we already replaced this with a capture (which contains the UFCS
1746
- // work already done when the capture was computed), emit the capture
1747
- if (!captured_part.empty ()) {
1748
- printer.print_cpp2 (captured_part, n.position ());
1749
- return ;
1750
- }
1751
-
1752
- // Otherwise, do the UFCS work...
1753
-
1754
- // The . has its id_expr
1755
- assert (n.ops [0 ].id_expr );
1756
-
1757
- // The ( has its expr_list and op_close
1758
- assert (n.ops [1 ].expr_list && n.ops [1 ].op_close );
1759
-
1760
- // --------------------------------------------------------------------
1761
- // TODO: When MSVC supports __VA_OPT__ in standard mode without the
1762
- // experimental /Zc:preprocessor switch, use this single line
1763
- // instead of the dual lines below that special-case _0 args
1764
- // AND: Make the similarly noted change in cpp2util.h
1765
- //
1766
- // printer.print_cpp2("CPP2_UFCS(", n.position());
1767
-
1768
- auto ufcs_string = std::string (" CPP2_UFCS" );
1769
- if (n.ops [0 ].id_expr ->template_args_count () > 0 ) {
1770
- ufcs_string += " _TEMPLATE" ;
1771
- }
1772
- // If there are no additional arguments, use the _0 version
1773
- if (n.ops [1 ].expr_list ->expressions .empty ()) {
1774
- ufcs_string += " _0" ;
1775
- }
1776
- printer.print_cpp2 (ufcs_string+" (" , n.position ());
1777
- // --------------------------------------------------------------------
1778
-
1779
- // Make the "funcname" the first argument to CPP2_UFCS
1780
- emit (*n.ops [0 ].id_expr );
1781
- printer.print_cpp2 (" , " , n.position ());
1782
-
1783
- // Then make the base expression the second argument
1784
- emit (*n.expr );
1785
-
1786
- // Then tack on any additional arguments
1787
- if (!n.ops [1 ].expr_list ->expressions .empty ()) {
1788
- printer.print_cpp2 (" , " , n.position ());
1789
- push_need_expression_list_parens (false );
1790
- emit (*n.ops [1 ].expr_list );
1791
- pop_need_expression_list_parens ();
1792
- }
1793
- printer.print_cpp2 (" )" , n.position ());
1794
-
1795
- // And we're done. This path has handled this node, so return...
1796
- return ;
1797
- }
1798
-
1799
1728
// Otherwise, we're going to have to potentially do some work to change
1800
1729
// some Cpp2 postfix operators to Cpp1 prefix operators, so let's set up...
1801
1730
auto prefix = std::vector<text_with_pos>{};
@@ -1804,6 +1733,31 @@ class cppfront
1804
1733
auto last_was_prefixed = false ;
1805
1734
auto saw_dollar = false ;
1806
1735
1736
+ struct text_chunks_with_parens_position {
1737
+ std::vector<text_with_pos> text_chunks;
1738
+ cpp2::source_position open_pos;
1739
+ cpp2::source_position close_pos;
1740
+ };
1741
+
1742
+ auto args = std::optional<text_chunks_with_parens_position>{};
1743
+
1744
+ auto print_to_string = [&](auto & i, auto ... args) {
1745
+ auto print = std::string{};
1746
+ printer.emit_to_string (&print);
1747
+ emit (i, args...);
1748
+ printer.emit_to_string ();
1749
+ return print;
1750
+ };
1751
+ auto print_to_text_chunks = [&](auto & i, auto ... args) {
1752
+ auto text = std::vector<text_with_pos>{};
1753
+ printer.emit_to_text_chunks (&text);
1754
+ push_need_expression_list_parens (false );
1755
+ emit (i, args...);
1756
+ pop_need_expression_list_parens ();
1757
+ printer.emit_to_text_chunks ();
1758
+ return text;
1759
+ };
1760
+
1807
1761
for (auto i = n.ops .rbegin (); i != n.ops .rend (); ++i)
1808
1762
{
1809
1763
assert (i->op );
@@ -1827,9 +1781,64 @@ class cppfront
1827
1781
}
1828
1782
}
1829
1783
1784
+ // Going backwards if we found LeftParen it might be UFCS
1785
+ // expr_list is emited to args variable for future use
1786
+ if (i->op ->type () == lexeme::LeftParen) {
1787
+
1788
+ assert (i->op );
1789
+ assert (i->op_close );
1790
+ auto local_args = text_chunks_with_parens_position{{}, i->op ->position (), i->op_close ->position ()};
1791
+
1792
+ if (!i->expr_list ->expressions .empty ()) {
1793
+ local_args.text_chunks = print_to_text_chunks (*i->expr_list );
1794
+ }
1795
+
1796
+ args.emplace (std::move (local_args));
1797
+ }
1798
+ // Going backwards if we found Dot and there is args variable
1799
+ // it means that it should be handled by UFCS
1800
+ else if ( i->op ->type () == lexeme::Dot && args )
1801
+ {
1802
+ auto funcname = print_to_string (*i->id_expr );
1803
+
1804
+ // --------------------------------------------------------------------
1805
+ // TODO: When MSVC supports __VA_OPT__ in standard mode without the
1806
+ // experimental /Zc:preprocessor switch, use this single line
1807
+ // instead of the dual lines below that special-case _0 args
1808
+ // AND: Make the similarly noted change in cpp2util.h
1809
+ //
1810
+ // printer.print_cpp2("CPP2_UFCS(", n.position());
1811
+
1812
+ auto ufcs_string = std::string (" CPP2_UFCS" );
1813
+
1814
+ if (i->id_expr ->template_args_count () > 0 ) {
1815
+ ufcs_string += " _TEMPLATE" ;
1816
+ // we need to replace "fun<int,long,double>" to "fun, (<int,long,double>)" to be able to generate
1817
+ // from obj.fun<int, long, double>(1,2) this CPP2_UFCS_TEMPLATE(fun, (<int,long, double>), obj, 1, 2)
1818
+ auto split = funcname.find (' <' ); assert (split != std::string::npos);
1819
+ funcname.insert (split, " , (" );
1820
+ assert (funcname.back () == ' >' );
1821
+ funcname += ' )' ;
1822
+ }
1823
+ // If there are no additional arguments, use the _0 version
1824
+ if (args.value ().text_chunks .empty ()) {
1825
+ ufcs_string += " _0" ;
1826
+ }
1827
+
1828
+ prefix.emplace_back (ufcs_string + " (" + funcname + " , " , i->op ->position () );
1829
+ suffix.emplace_back (" )" , args.value ().close_pos );
1830
+ if (!args.value ().text_chunks .empty ()) {
1831
+ for (auto && e: args.value ().text_chunks ) {
1832
+ suffix.push_back (e);
1833
+ }
1834
+ suffix.emplace_back (" , " , i->op ->position ());
1835
+ }
1836
+ args.reset ();
1837
+ }
1838
+
1830
1839
// Handle the Cpp2 postfix operators that are prefix in Cpp1
1831
1840
//
1832
- if (i->op ->type () == lexeme::MinusMinus ||
1841
+ else if (i->op ->type () == lexeme::MinusMinus ||
1833
1842
i->op ->type () == lexeme::PlusPlus ||
1834
1843
i->op ->type () == lexeme::Multiply ||
1835
1844
i->op ->type () == lexeme::Ampersand ||
@@ -1873,21 +1882,25 @@ class cppfront
1873
1882
}
1874
1883
1875
1884
if (i->id_expr ) {
1876
- auto print = std::string{};
1877
- printer.emit_to_string (&print);
1878
- emit (*i->id_expr , false /* not a local name*/ );
1879
- printer.emit_to_string ();
1885
+
1886
+ if (args) {
1887
+ // if args are stored it means that this is function or method
1888
+ // that is not handled by UFCS and args need to be printed
1889
+ suffix.emplace_back (" )" , args.value ().close_pos );
1890
+ for (auto && e: args.value ().text_chunks ) {
1891
+ suffix.push_back (e);
1892
+ }
1893
+ suffix.emplace_back (" (" , args.value ().open_pos );
1894
+ args.reset ();
1895
+ }
1896
+
1897
+ auto print = print_to_string (*i->id_expr , false /* not a local name*/ );
1880
1898
suffix.emplace_back ( print, i->id_expr ->position () );
1881
1899
}
1882
1900
1883
1901
if (i->expr_list ) {
1884
- auto text = std::vector<text_with_pos>{};
1885
- printer.emit_to_text_chunks (&text);
1886
- push_need_expression_list_parens (false );
1887
- emit (*i->expr_list );
1888
- pop_need_expression_list_parens ();
1889
- printer.emit_to_text_chunks ();
1890
- for (auto && e: text) {
1902
+ auto text = print_to_text_chunks (*i->expr_list );
1903
+ for (auto && e: text) {
1891
1904
suffix.push_back (e);
1892
1905
}
1893
1906
}
@@ -1903,6 +1916,8 @@ class cppfront
1903
1916
}
1904
1917
}
1905
1918
1919
+
1920
+
1906
1921
// Print the prefixes (in forward order)
1907
1922
for (auto & e : prefix) {
1908
1923
printer.print_cpp2 (e.text , n.position ());
@@ -1927,6 +1942,18 @@ class cppfront
1927
1942
}
1928
1943
suppress_move_from_last_use = false ;
1929
1944
1945
+ if (args) {
1946
+ // if after printing core expression args is defined
1947
+ // it means that the chaining started by function call
1948
+ // we need to print its arguments
1949
+ suffix.emplace_back (" )" , args.value ().close_pos );
1950
+ for (auto && e: args.value ().text_chunks ) {
1951
+ suffix.push_back (e);
1952
+ }
1953
+ suffix.emplace_back (" (" , args.value ().open_pos );
1954
+ args.reset ();
1955
+ }
1956
+
1930
1957
// Print the suffixes (in reverse order)
1931
1958
while (!suffix.empty ()) {
1932
1959
printer.print_cpp2 (suffix.back ().text , suffix.back ().pos );
0 commit comments