@@ -1667,17 +1667,19 @@ class cppfront
1667
1667
captured_part += " _" + std::to_string (mynum);
1668
1668
}
1669
1669
1670
- // Check to see if it's just a function call with "." syntax,
1670
+ // Check to see if it's just a function call with "." syntax (potentially chained with other methods) ,
1671
1671
// and if so use this path to convert it to UFCS
1672
1672
if (// there's a single-token expression followed by . and (
1673
1673
n.expr ->get_token () && // if the base expression is a single token
1674
1674
std::ssize (n.ops ) >= 2 && // and we're of the form:
1675
1675
n.ops [0 ].op ->type () == lexeme::Dot && // token . id-expr ( expr-list )
1676
1676
n.ops [1 ].op ->type () == lexeme::LeftParen &&
1677
1677
// and either there's nothing after that, or there's just a $ after that
1678
+ // or there is mathod chaining started
1678
1679
(
1679
1680
std::ssize (n.ops ) == 2 ||
1680
- (std::ssize (n.ops ) == 3 && n.ops [2 ].op ->type () == lexeme::Dollar)
1681
+ (std::ssize (n.ops ) == 3 && n.ops [2 ].op ->type () == lexeme::Dollar) ||
1682
+ (std::ssize (n.ops ) > 3 && n.ops [2 ].op ->type () == lexeme::Dot) // fsajdak: chaining identification
1681
1683
)
1682
1684
)
1683
1685
{
@@ -1690,44 +1692,52 @@ class cppfront
1690
1692
1691
1693
// Otherwise, do the UFCS work...
1692
1694
1693
- // The . has its id_expr
1694
- assert (n.ops [0 ].id_expr );
1695
-
1696
- // The ( has its expr_list and op_close
1697
- assert (n.ops [1 ].expr_list && n.ops [1 ].op_close );
1698
-
1699
- // --------------------------------------------------------------------
1700
- // TODO: When MSVC supports __VA_OPT__ in standard mode without the
1701
- // experimental /Zc:preprocessor switch, use this single line
1702
- // instead of the dual lines below that special-case _0 args
1703
- // AND: Make the similarly noted change in cpp2util.h
1704
- //
1705
- // printer.print_cpp2("CPP2_UFCS(", n.position());
1706
-
1707
- // If there are no additional arguments, use the CPP2_UFCS_0 version
1708
- if (!n.ops [1 ].expr_list ->expressions .empty ()) {
1709
- printer.print_cpp2 (" CPP2_UFCS(" , n.position ());
1710
- }
1711
- else {
1712
- printer.print_cpp2 (" CPP2_UFCS_0(" , n.position ());
1695
+ // If method are chained we need to go from the last to the first
1696
+ // token.a(a-expr-list).b(b-expr-list).c(c-expr-list) will be tranformed to:
1697
+ // CPP2_UFCS(c, CPP2_UFCS(b, CPP2_UFCS(a,token, a-expr-list), b-expr-list), c-expr-list )
1698
+ for (auto i = std::ssize (n.ops )-1 ; i > 0 ; i -= 2 )
1699
+ {
1700
+ // The . has its id_expr
1701
+ assert (n.ops [i-1 ].id_expr );
1702
+
1703
+ // The ( has its expr_list and op_close
1704
+ assert (n.ops [i].expr_list && n.ops [i].op_close );
1705
+
1706
+ // --------------------------------------------------------------------
1707
+ // TODO: When MSVC supports __VA_OPT__ in standard mode without the
1708
+ // experimental /Zc:preprocessor switch, use this single line
1709
+ // instead of the dual lines below that special-case _0 args
1710
+ // AND: Make the similarly noted change in cpp2util.h
1711
+ //
1712
+ // printer.print_cpp2("CPP2_UFCS(", n.position());
1713
+
1714
+ // If there are no additional arguments, use the CPP2_UFCS_0 version
1715
+ if (!n.ops [i].expr_list ->expressions .empty ()) {
1716
+ printer.print_cpp2 (" CPP2_UFCS(" , n.position ());
1717
+ }
1718
+ else {
1719
+ printer.print_cpp2 (" CPP2_UFCS_0(" , n.position ());
1720
+ }
1721
+ emit (*n.ops [i-1 ].id_expr );
1722
+ printer.print_cpp2 (" , " , n.position ());
1713
1723
}
1714
- // --------------------------------------------------------------------
1715
1724
1716
- // Make the "funcname" the first argument to CPP2_UFCS
1717
- emit (* n.ops [ 0 ]. id_expr );
1718
- printer. print_cpp2 ( " , " , n. position ());
1719
-
1720
- // Then make the base expression the second argument
1721
- emit (*n. expr );
1725
+ // expr-list need to be added in reversed order then CPP2_UFCS macros
1726
+ for ( auto i = 0 ; i < std::ssize ( n.ops ); i += 2 ) {
1727
+ // Then make the base expression the second argument - only needed on the most nested call
1728
+ if (i == 0 ) {
1729
+ emit (*n. expr );
1730
+ }
1722
1731
1723
- // Then tack on any additional arguments
1724
- if (!n.ops [1 ].expr_list ->expressions .empty ()) {
1725
- printer.print_cpp2 (" , " , n.position ());
1726
- push_need_expression_list_parens (false );
1727
- emit (*n.ops [1 ].expr_list );
1728
- pop_need_expression_list_parens ();
1732
+ // Then tack on any additional arguments
1733
+ if (!n.ops [(i+1 )].expr_list ->expressions .empty ()) {
1734
+ printer.print_cpp2 (" , " , n.position ());
1735
+ push_need_expression_list_parens (false );
1736
+ emit (*n.ops [(i+1 )].expr_list );
1737
+ pop_need_expression_list_parens ();
1738
+ }
1739
+ printer.print_cpp2 (" )" , n.position ());
1729
1740
}
1730
- printer.print_cpp2 (" )" , n.position ());
1731
1741
1732
1742
// And we're done. This path has handled this node, so return...
1733
1743
return ;
0 commit comments