@@ -1634,17 +1634,19 @@ class cppfront
1634
1634
captured_part += " _" + std::to_string (mynum);
1635
1635
}
1636
1636
1637
- // Check to see if it's just a function call with "." syntax,
1637
+ // Check to see if it's just a function call with "." syntax (potentially chained with other methods) ,
1638
1638
// and if so use this path to convert it to UFCS
1639
1639
if (// there's a single-token expression followed by . and (
1640
1640
n.expr ->get_token () && // if the base expression is a single token
1641
1641
std::ssize (n.ops ) >= 2 && // and we're of the form:
1642
1642
n.ops [0 ].op ->type () == lexeme::Dot && // token . id-expr ( expr-list )
1643
1643
n.ops [1 ].op ->type () == lexeme::LeftParen &&
1644
1644
// and either there's nothing after that, or there's just a $ after that
1645
+ // or there is mathod chaining started
1645
1646
(
1646
1647
std::ssize (n.ops ) == 2 ||
1647
- (std::ssize (n.ops ) == 3 && n.ops [2 ].op ->type () == lexeme::Dollar)
1648
+ (std::ssize (n.ops ) == 3 && n.ops [2 ].op ->type () == lexeme::Dollar) ||
1649
+ (std::ssize (n.ops ) > 3 && n.ops [2 ].op ->type () == lexeme::Dot) // fsajdak: chaining identification
1648
1650
)
1649
1651
)
1650
1652
{
@@ -1657,44 +1659,52 @@ class cppfront
1657
1659
1658
1660
// Otherwise, do the UFCS work...
1659
1661
1660
- // The . has its id_expr
1661
- assert (n.ops [0 ].id_expr );
1662
-
1663
- // The ( has its expr_list and op_close
1664
- assert (n.ops [1 ].expr_list && n.ops [1 ].op_close );
1665
-
1666
- // --------------------------------------------------------------------
1667
- // TODO: When MSVC supports __VA_OPT__ in standard mode without the
1668
- // experimental /Zc:preprocessor switch, use this single line
1669
- // instead of the dual lines below that special-case _0 args
1670
- // AND: Make the similarly noted change in cpp2util.h
1671
- //
1672
- // printer.print_cpp2("CPP2_UFCS(", n.position());
1673
-
1674
- // If there are no additional arguments, use the CPP2_UFCS_0 version
1675
- if (!n.ops [1 ].expr_list ->expressions .empty ()) {
1676
- printer.print_cpp2 (" CPP2_UFCS(" , n.position ());
1677
- }
1678
- else {
1679
- printer.print_cpp2 (" CPP2_UFCS_0(" , n.position ());
1662
+ // If method are chained we need to go from the last to the first
1663
+ // token.a(a-expr-list).b(b-expr-list).c(c-expr-list) will be tranformed to:
1664
+ // CPP2_UFCS(c, CPP2_UFCS(b, CPP2_UFCS(a,token, a-expr-list), b-expr-list), c-expr-list )
1665
+ for (auto i = std::ssize (n.ops )-1 ; i > 0 ; i -= 2 )
1666
+ {
1667
+ // The . has its id_expr
1668
+ assert (n.ops [i-1 ].id_expr );
1669
+
1670
+ // The ( has its expr_list and op_close
1671
+ assert (n.ops [i].expr_list && n.ops [i].op_close );
1672
+
1673
+ // --------------------------------------------------------------------
1674
+ // TODO: When MSVC supports __VA_OPT__ in standard mode without the
1675
+ // experimental /Zc:preprocessor switch, use this single line
1676
+ // instead of the dual lines below that special-case _0 args
1677
+ // AND: Make the similarly noted change in cpp2util.h
1678
+ //
1679
+ // printer.print_cpp2("CPP2_UFCS(", n.position());
1680
+
1681
+ // If there are no additional arguments, use the CPP2_UFCS_0 version
1682
+ if (!n.ops [i].expr_list ->expressions .empty ()) {
1683
+ printer.print_cpp2 (" CPP2_UFCS(" , n.position ());
1684
+ }
1685
+ else {
1686
+ printer.print_cpp2 (" CPP2_UFCS_0(" , n.position ());
1687
+ }
1688
+ emit (*n.ops [i-1 ].id_expr );
1689
+ printer.print_cpp2 (" , " , n.position ());
1680
1690
}
1681
- // --------------------------------------------------------------------
1682
1691
1683
- // Make the "funcname" the first argument to CPP2_UFCS
1684
- emit (* n.ops [ 0 ]. id_expr );
1685
- printer. print_cpp2 ( " , " , n. position ());
1686
-
1687
- // Then make the base expression the second argument
1688
- emit (*n. expr );
1692
+ // expr-list need to be added in reversed order then CPP2_UFCS macros
1693
+ for ( auto i = 0 ; i < std::ssize ( n.ops ); i += 2 ) {
1694
+ // Then make the base expression the second argument - only needed on the most nested call
1695
+ if (i == 0 ) {
1696
+ emit (*n. expr );
1697
+ }
1689
1698
1690
- // Then tack on any additional arguments
1691
- if (!n.ops [1 ].expr_list ->expressions .empty ()) {
1692
- printer.print_cpp2 (" , " , n.position ());
1693
- push_need_expression_list_parens (false );
1694
- emit (*n.ops [1 ].expr_list );
1695
- pop_need_expression_list_parens ();
1699
+ // Then tack on any additional arguments
1700
+ if (!n.ops [(i+1 )].expr_list ->expressions .empty ()) {
1701
+ printer.print_cpp2 (" , " , n.position ());
1702
+ push_need_expression_list_parens (false );
1703
+ emit (*n.ops [(i+1 )].expr_list );
1704
+ pop_need_expression_list_parens ();
1705
+ }
1706
+ printer.print_cpp2 (" )" , n.position ());
1696
1707
}
1697
- printer.print_cpp2 (" )" , n.position ());
1698
1708
1699
1709
// And we're done. This path has handled this node, so return...
1700
1710
return ;
0 commit comments