Skip to content

Commit

Permalink
fix: lower (nested) _braced-init-list_ (argument)
Browse files Browse the repository at this point in the history
  • Loading branch information
JohelEGP committed Oct 4, 2024
1 parent c5feb42 commit 774b373
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 9 deletions.
27 changes: 27 additions & 0 deletions regression-tests/pure2-bugfix-for-nested-lists.cpp2
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
point: @value type = {
public x: int = 0;
public y: int = 0;
operator=: (implicit out this, x_: int, y_: int) = {
x = x_;
y = y_;
}
}

check: (p: point) p;

main: () = {
assert(check((17, 29)).x == 17);
assert(check((17, 29)).y == 29);

board: std::array<std::array<u8, 3>, 3> = ((
('O', 'X', 'O'),
(' ', ('X'), 'X'),
('X', 'O', 'O')
));
assert(board[0] == :std::array<u8, 3> = ('O', 'X', 'O'));
assert(board[1] == :std::array<u8, 3> = (' ', 'X', 'X'));
assert(board[2] == :std::array<u8, 3> = ('X', 'O', 'O'));

// Still parentheses (for now?)
assert((:std::vector = (17, 29)).size() == 2);
}
4 changes: 2 additions & 2 deletions regression-tests/test-results/mixed-default-arguments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ auto cxx2(cpp2::impl::in<int> x, cpp2::impl::in<std::string> y) -> void{
#line 9 "mixed-default-arguments.cpp2"
auto main() -> int{
cxx(1, "test");
cxx({}, {});
cxx({ }, { });
cxx2(1, "test");
cxx2({}, {});
cxx2({ }, { });
}

86 changes: 86 additions & 0 deletions regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@

#define CPP2_IMPORT_STD Yes

//=== Cpp2 type declarations ====================================================


#include "cpp2util.h"

#line 1 "pure2-bugfix-for-nested-lists.cpp2"
class point;
#line 2 "pure2-bugfix-for-nested-lists.cpp2"


//=== Cpp2 type definitions and function declarations ===========================

#line 1 "pure2-bugfix-for-nested-lists.cpp2"
class point {
#line 2 "pure2-bugfix-for-nested-lists.cpp2"
public: int x {0};
public: int y {0};
public: point(cpp2::impl::in<int> x_, cpp2::impl::in<int> y_);
public: [[nodiscard]] auto operator<=>(point const& that) const& -> std::strong_ordering = default;
public: point(point const& that);

public: auto operator=(point const& that) -> point& ;
public: point(point&& that) noexcept;
public: auto operator=(point&& that) noexcept -> point& ;
public: explicit point();

#line 8 "pure2-bugfix-for-nested-lists.cpp2"
};

[[nodiscard]] auto check(cpp2::impl::in<point> p) -> auto;

auto main() -> int;

//=== Cpp2 function definitions =================================================

#line 1 "pure2-bugfix-for-nested-lists.cpp2"

#line 4 "pure2-bugfix-for-nested-lists.cpp2"
point::point(cpp2::impl::in<int> x_, cpp2::impl::in<int> y_)
: x{ x_ }
, y{ y_ }{

#line 7 "pure2-bugfix-for-nested-lists.cpp2"
}


point::point(point const& that)
: x{ that.x }
, y{ that.y }{}

auto point::operator=(point const& that) -> point& {
x = that.x;
y = that.y;
return *this;}
point::point(point&& that) noexcept
: x{ std::move(that).x }
, y{ std::move(that).y }{}
auto point::operator=(point&& that) noexcept -> point& {
x = std::move(that).x;
y = std::move(that).y;
return *this;}
point::point(){}
#line 10 "pure2-bugfix-for-nested-lists.cpp2"
[[nodiscard]] auto check(cpp2::impl::in<point> p) -> auto { return p; }

#line 12 "pure2-bugfix-for-nested-lists.cpp2"
auto main() -> int{
if (cpp2::cpp2_default.is_active() && !(check({ 17, 29 }).x == 17) ) { cpp2::cpp2_default.report_violation(""); }
if (cpp2::cpp2_default.is_active() && !(check({ 17, 29 }).y == 29) ) { cpp2::cpp2_default.report_violation(""); }

std::array<std::array<cpp2::u8,3>,3> board {{ {
'O', 'X', 'O' }, {
' ', { 'X' }, 'X' }, {
'X', 'O', 'O' } }};

if (cpp2::cpp2_default.is_active() && !(CPP2_ASSERT_IN_BOUNDS_LITERAL(board, 0) == std::array<cpp2::u8,3>{'O', 'X', 'O'}) ) { cpp2::cpp2_default.report_violation(""); }
if (cpp2::cpp2_default.is_active() && !(CPP2_ASSERT_IN_BOUNDS_LITERAL(board, 1) == std::array<cpp2::u8,3>{' ', 'X', 'X'}) ) { cpp2::cpp2_default.report_violation(""); }
if (cpp2::cpp2_default.is_active() && !(CPP2_ASSERT_IN_BOUNDS_LITERAL(cpp2::move(board), 2) == std::array<cpp2::u8,3>{'X', 'O', 'O'}) ) { cpp2::cpp2_default.report_violation(""); }

// Still parentheses (for now?)
if (cpp2::cpp2_default.is_active() && !(CPP2_UFCS(size)((std::vector{17, 29})) == 2) ) { cpp2::cpp2_default.report_violation(""); }
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pure2-bugfix-for-nested-lists.cpp2... ok (all Cpp2, passes safety checks)

2 changes: 1 addition & 1 deletion regression-tests/test-results/pure2-hashable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ return ret;

mystruct::mystruct(auto&& i_, auto&& j_, auto&& k_)
requires (std::is_convertible_v<CPP2_TYPEOF(i_), std::add_const_t<cpp2::i32>&> && std::is_convertible_v<CPP2_TYPEOF(j_), std::add_const_t<std::string>&> && std::is_convertible_v<CPP2_TYPEOF(k_), std::add_const_t<cpp2::u64>&>)
: base{ (1) }
: base{ { 1 } }
, i{ CPP2_FORWARD(i_) }
, j{ CPP2_FORWARD(j_) }
, k{ CPP2_FORWARD(k_) }{}
Expand Down
30 changes: 25 additions & 5 deletions source/parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -6296,9 +6296,9 @@ class parser
// Next should be an expression-list followed by a ')'
// If not, then this wasn't a call expression so backtrack to
// the '(' which will be part of the next grammar production
is_inside_call_expr = true;
term.expr_list = expression_list(term.op, lexeme::RightParen);
is_inside_call_expr = false;
is_inside_call_expr = true;
term.expr_list = expression_list(term.op, lexeme::RightParen, true);
is_inside_call_expr = false;

if (
term.expr_list
Expand Down Expand Up @@ -6842,8 +6842,28 @@ class parser
return n;
}

auto add_expression = [&](expression_list_node::term t) {
std::function<void(expression_list_node::term&)> mark_nested_inside_initializer{
[&](expression_list_node::term& u) {
if (
inside_initializer
&& u.expr->is_expression_list()
)
{
auto l = const_cast<expression_list_node*>(u.expr->get_expression_list());
l->inside_initializer = true;
for (auto& e : l->expressions) {
mark_nested_inside_initializer(e);
}
}
}
};
mark_nested_inside_initializer(t);
n->expressions.push_back(std::move(t));
};

// Otherwise remember the first expression
n->expressions.push_back( { pass, std::move(x) } );
add_expression( { pass, std::move(x) } );
// and see if there are more...
while (curr().type() == lexeme::Comma) {
next();
Expand All @@ -6859,7 +6879,7 @@ class parser
error("invalid text in expression list", true, {}, true);
return {};
}
n->expressions.push_back( { pass, std::move(expr) } );
add_expression( { pass, std::move(expr) } );
}

return n;
Expand Down
17 changes: 16 additions & 1 deletion source/to_cpp1.h
Original file line number Diff line number Diff line change
Expand Up @@ -4114,7 +4114,22 @@ class cppfront

assert(x.expr);
current_args.push_back( {x.pass} );
emit(*x.expr);
// In a nested expression-list in an initializer, we can
// take over direct control of emitting it without needing to
// go through the whole grammar, and surround it with braces
if (
n.inside_initializer
&& x.expr->is_expression_list()
)
{
printer.print_cpp2( "{ ", n.position() );
emit(*x.expr->get_expression_list(), false);
printer.print_cpp2( " }", n.position() );
}
// Otherwise, just emit the general expression as usual
else {
emit(*x.expr);
}
current_args.pop_back();

if (is_out) {
Expand Down

0 comments on commit 774b373

Please sign in to comment.