Skip to content

Commit 327ceeb

Browse files
committed
Add predicate support for is outside inspect, see #90
1 parent 68e465a commit 327ceeb

17 files changed

+180
-26
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
2+
#include <iostream>
3+
#include <vector>
4+
5+
constexpr auto less_then = [](int value) {
6+
return [=](auto x) { return x < value;};
7+
};
8+
9+
constexpr auto in = [](auto min, auto max) {
10+
return [=](auto x) {
11+
return min <= x && x <= max;
12+
};
13+
};
14+
15+
constexpr auto empty = [](auto&& x){
16+
return std::empty(x);
17+
};
18+
19+
main: () -> int = {
20+
i := 15;
21+
22+
std::cout << inspect i -> std::string {
23+
is (less_then(10)) = "i less than 10";
24+
is (in(11,20)) = "i is between 11 and 20";
25+
is _ = "i is out of our interest";
26+
} << std::endl;
27+
28+
if i is less_then(20) {
29+
std::cout << "less than 20" << std::endl;
30+
}
31+
32+
if i is in(10,30) {
33+
std::cout << "i is between 10 and 30" << std::endl;
34+
}
35+
36+
v : std::vector<int> = ();
37+
38+
if empty(v) {
39+
std::cout << "v is empty" << std::endl;
40+
}
41+
42+
if v is (empty) {
43+
std::cout << "v is empty" << std::endl;
44+
}
45+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
i is between 11 and 20
2+
less than 20
3+
i is between 10 and 30
4+
v is empty
5+
v is empty

regression-tests/test-results/clang-12/mixed-inspect-values-2.cpp.output

Whitespace-only changes.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
i is between 11 and 20
2+
less than 20
3+
i is between 10 and 30
4+
v is empty
5+
v is empty

regression-tests/test-results/gcc-10/mixed-inspect-values-2.cpp.output

Whitespace-only changes.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// ----- Cpp2 support -----
2+
#include "cpp2util.h"
3+
4+
#line 1 "mixed-inspect-values-2.cpp2"
5+
6+
#include <iostream>
7+
#include <vector>
8+
9+
constexpr auto less_then = [](int value) {
10+
return [=](auto x) { return x < value;};
11+
};
12+
13+
constexpr auto in = [](auto min, auto max) {
14+
return [=](auto x) {
15+
return min <= x && x <= max;
16+
};
17+
};
18+
19+
constexpr auto empty = [](auto&& x){
20+
return std::empty(x);
21+
};
22+
23+
[[nodiscard]] auto main() -> int;
24+
25+
//=== Cpp2 definitions ==========================================================
26+
27+
#line 18 "mixed-inspect-values-2.cpp2"
28+
29+
[[nodiscard]] auto main() -> int{
30+
auto i { 15 };
31+
32+
std::cout << [&] () -> std::string { auto&& __expr = i;
33+
if (cpp2::is(__expr, (less_then(10)))) { if constexpr( requires{"i less than 10";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("i less than 10")),std::string> ) return "i less than 10"; else return std::string{}; else return std::string{}; }
34+
else if (cpp2::is(__expr, in(11, 20))) { if constexpr( requires{"i is between 11 and 20";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("i is between 11 and 20")),std::string> ) return "i is between 11 and 20"; else return std::string{}; else return std::string{}; }
35+
else return "i is out of our interest"; }
36+
() << std::endl;
37+
38+
if (cpp2::is(i, less_then(20))) {
39+
std::cout << "less than 20" << std::endl;
40+
}
41+
42+
if (cpp2::is(std::move(i), in(10, 30))) {
43+
std::cout << "i is between 10 and 30" << std::endl;
44+
}
45+
46+
std::vector<int> v { };
47+
48+
if (empty(v)) {
49+
std::cout << "v is empty" << std::endl;
50+
}
51+
52+
if (cpp2::is(std::move(v), (empty))) {
53+
std::cout << "v is empty" << std::endl;
54+
}
55+
}
56+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
mixed-inspect-values-2.cpp2... ok (mixed Cpp1/Cpp2, Cpp2 code passes safety checks)
2+

regression-tests/test-results/mixed-inspect-values.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ auto test(auto const& x) -> void{
4747
std::cout << [&] () -> std::string { auto&& __expr = x;
4848
if (cpp2::is(__expr, 0)) { if constexpr( requires{"zero";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("zero")),std::string> ) return "zero"; else return std::string{}; else return std::string{}; }
4949
else if (cpp2::is(__expr, (in(1, 2)))) { if constexpr( requires{"1 or 2";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("1 or 2")),std::string> ) return "1 or 2"; else return std::string{}; else return std::string{}; }
50-
else if (cpp2::is(__expr, (in_2_3))) { if constexpr( requires{"3";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("3")),std::string> ) return "3"; else return std::string{}; else return std::string{}; }
51-
else if (cpp2::is(__expr, (std::move(forty_two)))) { if constexpr( requires{"the answer";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("the answer")),std::string> ) return "the answer"; else return std::string{}; else return std::string{}; }
50+
else if (cpp2::is(__expr, in_2_3)) { if constexpr( requires{"3";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("3")),std::string> ) return "3"; else return std::string{}; else return std::string{}; }
51+
else if (cpp2::is(__expr, std::move(forty_two))) { if constexpr( requires{"the answer";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("the answer")),std::string> ) return "the answer"; else return std::string{}; else return std::string{}; }
5252
else if (cpp2::is<int>(__expr)) { if constexpr( requires{"integer " + cpp2::to_string(x);} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("integer " + cpp2::to_string(x))),std::string> ) return "integer " + cpp2::to_string(x); else return std::string{}; else return std::string{}; }
5353
else if (cpp2::is<std::string>(__expr)) { if constexpr( requires{cpp2::as<std::string>(x);} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((cpp2::as<std::string>(x))),std::string> ) return cpp2::as<std::string>(x); else return std::string{}; else return std::string{}; }
5454
else return "(no match)"; }
55-
()
56-
<< "\n";}
55+
() << "\n";
56+
}
5757

regression-tests/test-results/mixed-inspect-with-typeof-of-template-arg-list.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ auto calc() {
2020
return [&] () -> int { auto&& __expr = v;
2121
if (cpp2::is<int>(__expr)) { if constexpr( requires{calc<1,2>();} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((calc<1,2>())),int> ) return calc<1,2>(); else return int{}; else return int{}; }
2222
else return 0; }
23-
()
24-
; }
23+
();
24+
}
2525

2626
[[nodiscard]] auto main() -> int{
2727
return fun(42);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
i is between 11 and 20
2+
less than 20
3+
i is between 10 and 30
4+
v is empty
5+
v is empty
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
mixed-inspect-values-2.cpp

regression-tests/test-results/pure2-inspect-expression-in-generic-function-multiple-types.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ auto test_generic(auto const& x, auto const& msg) -> void{
3838
if (cpp2::is<int>(__expr)) { if constexpr( requires{"integer " + std::to_string(cpp2::as<int>(x));} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("integer " + std::to_string(cpp2::as<int>(x)))),std::string> ) return "integer " + std::to_string(cpp2::as<int>(x)); else return std::string{}; else return std::string{}; }
3939
else if (cpp2::is<std::string>(__expr)) { if constexpr( requires{'"' + cpp2::as<std::string>(x) + '"';} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(('"' + cpp2::as<std::string>(x) + '"')),std::string> ) return '"' + cpp2::as<std::string>(x) + '"'; else return std::string{}; else return std::string{}; }
4040
else return "not an int or string"; }
41-
()
41+
()
4242
<< "\n";
4343
}
4444

regression-tests/test-results/pure2-inspect-expression-with-as-in-generic-function.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ auto print_an_int(auto const& x) -> void{
2424
<< [&] () -> std::string { auto&& __expr = x;
2525
if (cpp2::is<int>(__expr)) { if constexpr( requires{std::to_string(cpp2::as<int>(x));} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((std::to_string(cpp2::as<int>(x)))),std::string> ) return std::to_string(cpp2::as<int>(x)); else return std::string{}; else return std::string{}; }
2626
else return "not an int"; }
27-
()
27+
()
2828
<< "\n";
2929
}
3030

regression-tests/test-results/pure2-inspect-fallback-with-variant-any-optional.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ auto test_generic(auto const& x, auto const& msg) -> void{
3333
else if (cpp2::is<std::any>(__expr)) { if constexpr( requires{" matches std::any";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((" matches std::any")),std::string> ) return " matches std::any"; else return std::string{}; else return std::string{}; }
3434
else if (cpp2::is<std::optional<std::string>>(__expr)) { if constexpr( requires{" matches std::optional<std::string>";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((" matches std::optional<std::string>")),std::string> ) return " matches std::optional<std::string>"; else return std::string{}; else return std::string{}; }
3535
else return " no match"; }
36-
()
36+
()
3737
<< "\n";
3838
}
3939

regression-tests/test-results/pure2-inspect-generic-void-empty-with-variant-any-optional.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ auto test_generic(auto const& x, auto const& msg) -> void{
3434
<< [&] () -> std::string { auto&& __expr = x;
3535
if (cpp2::is<void>(__expr)) { if constexpr( requires{" VOYDE AND EMPTIE";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((" VOYDE AND EMPTIE")),std::string> ) return " VOYDE AND EMPTIE"; else return std::string{}; else return std::string{}; }
3636
else return " no match"; }
37-
()
37+
()
3838
<< "\n";
3939
}
4040

regression-tests/test-results/pure2-type-safety-2-with-inspect-expression.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ auto test_generic(auto const& x, auto const& msg) -> void{
3737
<< [&] () -> std::string { auto&& __expr = x;
3838
if (cpp2::is<int>(__expr)) { if constexpr( requires{std::to_string(cpp2::as<int>(x));} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((std::to_string(cpp2::as<int>(x)))),std::string> ) return std::to_string(cpp2::as<int>(x)); else return std::string{}; else return std::string{}; }
3939
else return "not an int"; }
40-
()
40+
()
4141
<< "\n";
4242
}
4343

source/cppfront.cpp

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1383,7 +1383,7 @@ class cppfront
13831383
if (is_expression) {
13841384
printer.print_cpp2("()", n.close_brace);
13851385
}
1386-
printer.print_cpp2("\n", n.close_brace);
1386+
//printer.print_cpp2("\n", n.close_brace);
13871387
}
13881388

13891389

@@ -1972,24 +1972,59 @@ class cppfront
19721972

19731973
// Handle is/as expressions
19741974
// TODO: Generalize
1975-
if (!n.terms.empty() && *n.terms.front().op == "is")
1975+
1976+
// If this is an is_as_expression_node
1977+
//
1978+
if constexpr (std::is_same_v<is_as_expression_node const&, decltype(n)>)
19761979
{
1977-
if (n.terms.size() > 1) {
1978-
errors.emplace_back(
1979-
n.position(),
1980-
"(temporary alpha limitation) this compiler is just starting to learn 'is' and only supports a single is-expression (no chaining with other is/as)"
1981-
);
1982-
return;
1983-
}
1980+
if (!n.terms.empty() && *n.terms.front().op == "is")
1981+
{
1982+
if (n.terms.size() > 1) {
1983+
errors.emplace_back(
1984+
n.position(),
1985+
"(temporary alpha limitation) this compiler is just starting to learn 'is' and only supports a single is-expression (no chaining with other is/as)"
1986+
);
1987+
return;
1988+
}
19841989

1985-
printer.print_cpp2("cpp2::is<", n.position());
1986-
emit(*n.terms.front().expr);
1987-
printer.print_cpp2(">(", n.position());
1990+
// The term will be a prefix_expression_node
1991+
auto prefix_expr = n.terms.front().expr.get();
1992+
assert (prefix_expr);
1993+
static_assert (std::is_same_v<prefix_expression_node*, decltype(prefix_expr)>);
1994+
1995+
// In the future we'll distinguish type_id better, but for now
1996+
// "identifier or id_expression w/o ops" works well enough
1997+
//
1998+
// If it's "is type", emit "cpp2::is<type>(expr)"
1999+
if (prefix_expr->ops.empty() && // no prefix ops
2000+
prefix_expr->expr->ops.empty() && // no postfix ops
2001+
(prefix_expr->expr->expr->expr.index() == primary_expression_node::identifier ||
2002+
prefix_expr->expr->expr->expr.index() == primary_expression_node::id_expression
2003+
)
2004+
)
2005+
{
2006+
printer.print_cpp2("cpp2::is<", n.position());
2007+
emit(*n.terms.front().expr);
2008+
printer.print_cpp2(">(", n.position());
19882009

1989-
emit(*n.expr);
2010+
emit(*n.expr);
19902011

1991-
printer.print_cpp2(")", n.position());
1992-
return;
2012+
printer.print_cpp2(")", n.position());
2013+
}
2014+
// Else it's "is value", emit "cpp2::is(expr, value)"
2015+
else
2016+
{
2017+
printer.print_cpp2("cpp2::is(", n.position());
2018+
2019+
emit(*n.expr);
2020+
2021+
printer.print_cpp2(", ", n.position());
2022+
emit(*n.terms.front().expr);
2023+
printer.print_cpp2(")", n.position());
2024+
}
2025+
2026+
return;
2027+
}
19932028
}
19942029

19952030
if (!n.terms.empty() && *n.terms.front().op == "as")

0 commit comments

Comments
 (0)