From 2a1ec5c3294d3a531752256312da3fb800c004d4 Mon Sep 17 00:00:00 2001 From: Filip Sajdak Date: Fri, 14 Oct 2022 14:07:18 +0200 Subject: [PATCH 1/4] Add support for literals in inspect alternatives --- source/cppfront.cpp | 7 +++++-- source/parse.h | 14 +++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/source/cppfront.cpp b/source/cppfront.cpp index 893ae3f09c..9292340f5b 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -1282,8 +1282,11 @@ class cppfront auto id = std::string{}; printer.emit_to_string(&id); - assert(alt->id_expression); - emit(*alt->id_expression); + assert(alt->id_expression || alt->literal); + if (alt->id_expression) + emit(*alt->id_expression); + else if (alt->literal) + emit(*alt->literal); printer.emit_to_string(); assert (*alt->is_as_keyword == "is" || *alt->is_as_keyword == "as"); diff --git a/source/parse.h b/source/parse.h index 9521e34720..5d00a1dcd8 100644 --- a/source/parse.h +++ b/source/parse.h @@ -667,6 +667,7 @@ struct alternative_node std::unique_ptr id_expression; source_position equal_sign; std::unique_ptr statement; + token const* literal; auto position() const -> source_position { @@ -776,8 +777,11 @@ auto alternative_node::visit(auto& v, int depth) -> void } assert (is_as_keyword); v.start(*is_as_keyword, depth+1); - assert (id_expression); - id_expression->visit(v, depth+1); + assert (id_expression || literal); + if (id_expression) + id_expression->visit(v, depth+1); + else if (literal) + literal->visit(v, depth+1); assert (statement); statement->visit(v, depth+1); v.end(*this, depth); @@ -2346,8 +2350,12 @@ class parser if (auto id = id_expression()) { n->id_expression = std::move(id); } + else if (is_literal(curr().type())) { + n->literal = &curr(); + next(); + } else { - error("expected id-expression after 'is' in inspect alternative"); + error("expected id-expression or literal after 'is' in inspect alternative"); return {}; } From b7668e911950a5df999d3659ee84c7cd646cc6a7 Mon Sep 17 00:00:00 2001 From: Filip Sajdak Date: Tue, 18 Oct 2022 00:28:45 +0200 Subject: [PATCH 2/4] Add is() specialisations for literals --- include/cpp2util.h | 88 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/include/cpp2util.h b/include/cpp2util.h index b1a7a3339b..7d876137a0 100644 --- a/include/cpp2util.h +++ b/include/cpp2util.h @@ -615,6 +615,94 @@ auto is( X const& x ) -> bool { return x == X(); } +//------------------------------------------------------------------------------------------------------------- +// Built-in is (literals) +// + +template< auto value, typename X, typename V = CPP2_TYPEOF(value)> + // This requires are needed for gcc compiler to avoid ambiguity when value is double + requires ( + (std::floating_point && !std::floating_point) || + (std::integral && !std::integral) || + (std::is_enum_v && !std::is_same_v ) + ) +constexpr auto is( X const& x ) -> bool { + return false; +} + +template< auto value, typename X > + requires (std::is_enum_v && std::is_same_v) +constexpr auto is( X const& x ) -> bool { + return x == value; +} + +template< auto value, typename X > + requires std::integral && std::integral +constexpr auto is( X const& x ) -> bool { + return x == value; +} + +// Workaroud for lack of support for floating point template argument by clang and MSVC +struct double_wrapper { + double value = {}; + + template + requires std::is_floating_point_v + constexpr double_wrapper(T d) : value(d) {} + + constexpr operator double() const { + return value; + } + + template + constexpr bool operator==(T rhs) const { + return value == rhs; + } +}; + +// This is needed to solve some issue with clang - probably clang bug. +// Without it clang is not able to match with default specialisation: +// template< auto value, typename X > auto is( X const& x ) -> bool; +#if defined(__clang__) + +template< double_wrapper value, typename X > +constexpr auto is( X const& x ) -> bool { + if constexpr (std::is_floating_point_v) + return x == value; + else + return false; +} + +#else + +template< double_wrapper value, typename X > + requires std::is_floating_point_v +constexpr auto is( X const& x ) -> bool { + return x == value; +} + +#endif + +template +struct cstring_wrapper { + char cs[N]; + + constexpr cstring_wrapper(const char (&s)[N]) noexcept { + std::copy(s, s+N, cs); + } + + constexpr bool operator==(const std::string_view& sv) const noexcept { + return std::equal(cs, cs+N-1, sv.begin(), sv.end()); // N-1 as sv is not null-terminated + } +}; + +template< cstring_wrapper value, typename X > +constexpr auto is( X const& x ) -> bool { + if constexpr (std::is_convertible_v) + return value == x; + else + return false; +} //------------------------------------------------------------------------------------------------------------- // Built-in as (partial) From cd03b8ec6b749ca3bb60297e35e1797592783b65 Mon Sep 17 00:00:00 2001 From: Filip Sajdak Date: Sun, 23 Oct 2022 03:30:37 +0200 Subject: [PATCH 3/4] Add possibility to use lambda in is-statements --- include/cpp2util.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/include/cpp2util.h b/include/cpp2util.h index 7d876137a0..018d74b78d 100644 --- a/include/cpp2util.h +++ b/include/cpp2util.h @@ -704,6 +704,31 @@ constexpr auto is( X const& x ) -> bool { return false; } +template + requires ( + requires { &F::operator(); } + ) +struct lambda_wrapper { + F f; + Capture capture; + + constexpr lambda_wrapper(F f, Capture capture = {}) + : f{f}, capture{capture} {} + + template + auto operator()(X&& x) const { + if constexpr (std::is_same_v) + return f(std::forward(x)); + else + return f(std::forward(x), capture); + } +}; + +template< lambda_wrapper value, typename X > +constexpr auto is( X const& x ) -> bool { + return value(x); +} + //------------------------------------------------------------------------------------------------------------- // Built-in as (partial) // From 1bb321c6dad92aec14e1cbd9563e1191369f0181 Mon Sep 17 00:00:00 2001 From: Filip Sajdak Date: Sun, 23 Oct 2022 21:53:23 +0200 Subject: [PATCH 4/4] Add parsing and cppfront emit lambdas in alternatives --- source/cppfront.cpp | 10 ++++++++-- source/parse.h | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/source/cppfront.cpp b/source/cppfront.cpp index 9292340f5b..f3682689db 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -1283,10 +1283,16 @@ class cppfront auto id = std::string{}; printer.emit_to_string(&id); assert(alt->id_expression || alt->literal); - if (alt->id_expression) + if (alt->id_expression) { emit(*alt->id_expression); - else if (alt->literal) + if (alt->expr) { + push_need_expression_list_parens(true); + emit(*alt->expr); + pop_need_expression_list_parens(); + } + } else if (alt->literal) { emit(*alt->literal); + } printer.emit_to_string(); assert (*alt->is_as_keyword == "is" || *alt->is_as_keyword == "as"); diff --git a/source/parse.h b/source/parse.h index 5d00a1dcd8..3842797237 100644 --- a/source/parse.h +++ b/source/parse.h @@ -668,6 +668,7 @@ struct alternative_node source_position equal_sign; std::unique_ptr statement; token const* literal; + std::unique_ptr expr; auto position() const -> source_position { @@ -2359,6 +2360,25 @@ class parser return {}; } + if (curr().type() == lexeme::LeftParen) { + auto open_paren = curr().position(); + next(); + auto expr_list = expression_list(open_paren); + if (!expr_list) { + error("unexpected text - ( is not followed by an expression-list"); + next(); + return {}; + } + if (curr().type() != lexeme::RightParen) { + error("unexpected text - expression-list is not terminated by )"); + next(); + return {}; + } + expr_list->close_paren = curr().position(); + next(); + n->expr = std::move(expr_list); + } + if (curr().type() != lexeme::Assignment) { error("expected = at start of inspect alternative body"); return {};