Skip to content

Commit 1b1fc9b

Browse files
committed
Added: UFCS chaining starts on function call
1 parent 1a586ca commit 1b1fc9b

File tree

1 file changed

+70
-0
lines changed

1 file changed

+70
-0
lines changed

source/cppfront.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1700,6 +1700,76 @@ class cppfront
17001700
return;
17011701
}
17021702

1703+
// Check to see if it's just a function call syntax chained with other functions,
1704+
// and if so use this path to convert it to UFCS
1705+
if (// there's a single-token expression followed by (, ., and (
1706+
n.expr->get_token() && // if the base expression is a single token
1707+
std::ssize(n.ops) >= 3 && // and we're of the form:
1708+
n.ops[0].op->type() == lexeme::LeftParen && // token ( expr-list ) . id-expr ( expr-list )
1709+
n.ops[1].op->type() == lexeme::Dot &&
1710+
n.ops[2].op->type() == lexeme::LeftParen
1711+
)
1712+
{
1713+
// If we already replaced this with a capture (which contains the UFCS
1714+
// work already done when the capture was computed), emit the capture
1715+
if (!captured_part.empty()) {
1716+
printer.print_cpp2(captured_part, n.position());
1717+
return;
1718+
}
1719+
1720+
// Otherwise, do the UFCS work...
1721+
1722+
// If method are chained we need to go from the last to the first
1723+
// token(a-expr-list).b(b-expr-list).c(c-expr-list) will be tranformed to:
1724+
// CPP2_UFCS(c, CPP2_UFCS(b, CPP2_UFCS(token, a-expr-list), b-expr-list), c-expr-list )
1725+
for (auto i = std::ssize(n.ops)-1; i > 1; i -= 2)
1726+
{
1727+
// The . has its id_expr
1728+
assert (n.ops[i-1].id_expr);
1729+
1730+
// The ( has its expr_list and op_close
1731+
assert (n.ops[i].expr_list && n.ops[i].op_close);
1732+
1733+
//--------------------------------------------------------------------
1734+
// TODO: When MSVC supports __VA_OPT__ in standard mode without the
1735+
// experimental /Zc:preprocessor switch, use this single line
1736+
// instead of the dual lines below that special-case _0 args
1737+
// AND: Make the similarly noted change in cpp2util.h
1738+
//
1739+
// If there are no additional arguments, use the CPP2_UFCS_0 version
1740+
if (!n.ops[i].expr_list->expressions.empty()) {
1741+
printer.print_cpp2("CPP2_UFCS(", n.position());
1742+
}
1743+
else {
1744+
printer.print_cpp2("CPP2_UFCS_0(", n.position());
1745+
}
1746+
emit(*n.ops[i-1].id_expr);
1747+
printer.print_cpp2(", ", n.position());
1748+
}
1749+
1750+
// emit the first function that starts chaining (the most nested one)
1751+
emit(*n.expr);
1752+
printer.print_cpp2("(", n.position());
1753+
if (!n.ops[0].expr_list->expressions.empty()) {
1754+
emit(*n.ops[0].expr_list);
1755+
}
1756+
printer.print_cpp2(")", n.position());
1757+
1758+
// unroll the nested calls (skipping the first function call)
1759+
// expr-list need to be added in reversed order then CPP2_UFCS macros
1760+
for (auto i = 2; i < std::ssize(n.ops); i += 2) {
1761+
// Then tack on any additional arguments
1762+
if (!n.ops[i].expr_list->expressions.empty()) {
1763+
printer.print_cpp2(", ", n.position());
1764+
emit(*n.ops[i].expr_list);
1765+
}
1766+
printer.print_cpp2(")", n.position());
1767+
}
1768+
1769+
// And we're done. This path has handled this node, so return...
1770+
return;
1771+
}
1772+
17031773
// Otherwise, we're going to have to potentially do some work to change
17041774
// some Cpp2 postfix operators to Cpp1 prefix operators, so let's set up...
17051775
auto prefix = std::vector<text_with_pos>{};

0 commit comments

Comments
 (0)