Skip to content

Commit e10733d

Browse files
committed
UFCS: add chaining to the UFCS calls
Former implementation was not supporting method chaining ```cpp v.a().b().c(); // failed to use UFCS ``` The change converts above code into nested call of `CPP2_UFCS` macros: ```cpp CPP2_UFCS_0(c, CPP2_UFCS_0(b, CPP2_UFCS_0(a, v) ) ); ``` Functions with expr-list are also handled.
1 parent 067e7ed commit e10733d

File tree

1 file changed

+34
-23
lines changed

1 file changed

+34
-23
lines changed

source/cppfront.cpp

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,17 +1595,19 @@ class cppfront
15951595
captured_part += "_" + std::to_string(mynum);
15961596
}
15971597

1598-
// Check to see if it's just a function call with "." syntax,
1598+
// Check to see if it's just a function call with "." syntax (potentially chained with other methods),
15991599
// and if so use this path to convert it to UFCS
16001600
if (// there's a single-token expression followed by . and (
16011601
n.expr->get_token() && // if the base expression is a single token
16021602
std::ssize(n.ops) >= 2 && // and we're of the form:
16031603
n.ops[0].op->type() == lexeme::Dot && // token . id-expr ( expr-list )
16041604
n.ops[1].op->type() == lexeme::LeftParen &&
16051605
// and either there's nothing after that, or there's just a $ after that
1606+
// or there is mathod chaining started
16061607
(
16071608
std::ssize(n.ops) == 2 ||
1608-
(std::ssize(n.ops) == 3 && n.ops[2].op->type() == lexeme::Dollar)
1609+
(std::ssize(n.ops) == 3 && n.ops[2].op->type() == lexeme::Dollar) ||
1610+
(std::ssize(n.ops) > 3 && n.ops[2].op->type() == lexeme::Dot) // fsajdak: chaining identification
16091611
)
16101612
)
16111613
{
@@ -1618,33 +1620,42 @@ class cppfront
16181620

16191621
// Otherwise, do the UFCS work...
16201622

1621-
// The . has its id_expr
1622-
assert (n.ops[0].id_expr);
1623+
// If method are chained we need to go from the last to the first
1624+
// token.a(a-expr-list).b(b-expr-list).c(c-expr-list) will be tranformed to:
1625+
// CPP2_UFCS(c, CPP2_UFCS(b, CPP2_UFCS(a,token, a-expr-list), b-expr-list), c-expr-list )
1626+
for (auto i = std::ssize(n.ops)-1; i > 0; i -= 2)
1627+
{
1628+
// The . has its id_expr
1629+
assert (n.ops[i-1].id_expr);
16231630

1624-
// The ( has its expr_list and op_close
1625-
assert (n.ops[1].expr_list && n.ops[1].op_close);
1631+
// The ( has its expr_list and op_close
1632+
assert (n.ops[i].expr_list && n.ops[i].op_close);
16261633

1627-
// If there are no additional arguments, use the CPP2_UFCS_0 version
1628-
if (!n.ops[1].expr_list->expressions.empty()) {
1629-
printer.print_cpp2("CPP2_UFCS(", n.position());
1630-
}
1631-
else {
1632-
printer.print_cpp2("CPP2_UFCS_0(", n.position());
1634+
// If there are no additional arguments, use the CPP2_UFCS_0 version
1635+
if (!n.ops[i].expr_list->expressions.empty()) {
1636+
printer.print_cpp2("CPP2_UFCS(", n.position());
1637+
}
1638+
else {
1639+
printer.print_cpp2("CPP2_UFCS_0(", n.position());
1640+
}
1641+
emit(*n.ops[i-1].id_expr);
1642+
printer.print_cpp2(", ", n.position());
16331643
}
16341644

1635-
// Make the "funcname" the first argument to CPP2_UFCS
1636-
emit(*n.ops[0].id_expr);
1637-
printer.print_cpp2(", ", n.position());
1638-
1639-
// Then make the base expression the second argument
1640-
emit(*n.expr);
1645+
// expr-list need to be added in reversed order then CPP2_UFCS macros
1646+
for (auto i = 0; i < std::ssize(n.ops); i += 2) {
1647+
// Then make the base expression the second argument - only needed on the most nested call
1648+
if (i == 0) {
1649+
emit(*n.expr);
1650+
}
16411651

1642-
// Then tack on any additional arguments
1643-
if (!n.ops[1].expr_list->expressions.empty()) {
1644-
printer.print_cpp2(", ", n.position());
1645-
emit(*n.ops[1].expr_list);
1652+
// Then tack on any additional arguments
1653+
if (!n.ops[(i+1)].expr_list->expressions.empty()) {
1654+
printer.print_cpp2(", ", n.position());
1655+
emit(*n.ops[(i+1)].expr_list);
1656+
}
1657+
printer.print_cpp2(")", n.position());
16461658
}
1647-
printer.print_cpp2(")", n.position());
16481659

16491660
// And we're done. This path has handled this node, so return...
16501661
return;

0 commit comments

Comments
 (0)