Skip to content

Commit 9ddc250

Browse files
committed
Generalize _is-as-expression_ and _type-id_
- Allow multiple consecutive `as` - Correctly distinguish 'is/as Type' and 'is expression' - Treat C/C++'s built-in keyword types as type-ids (e.g., `int`) and recognize them in _type-id_ and not in _primary-expression_ - Treat C/C++'s built-in keyword quasi-identifiers are non-keywords (`false,` `new`, `nullptr`, `true`) - Switch to _type-id_ in _unqualified-id_ and , where before we were still having _id-expression_ doing double duty as an early grammar shortcut
1 parent e1b57cf commit 9ddc250

12 files changed

+236
-170
lines changed

include/cpp2util.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ class contract_group {
248248
public:
249249
using handler = void (*)(CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM);
250250

251-
constexpr contract_group (handler h = nullptr) : reporter(h) { }
251+
constexpr contract_group (handler h = {}) : reporter(h) { }
252252
constexpr auto set_handler(handler h) -> handler;
253253
constexpr auto get_handler() const -> handler { return reporter; }
254254
constexpr auto expects (bool b, CPP2_MESSAGE_PARAM msg = "" CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT)
@@ -417,7 +417,7 @@ class out {
417417
T* t;
418418
deferred_init<T>* dt;
419419
};
420-
out<T>* ot = nullptr;
420+
out<T>* ot = {};
421421
bool has_t;
422422

423423
// Each out in a chain contains its own uncaught_count ...

regression-tests/mixed-inspect-values-2.cpp2

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#include <iostream>
33
#include <vector>
44

5-
constexpr auto less_then = [](int value) {
5+
constexpr auto less_than = [](int value) {
66
return [=](auto x) { return x < value;};
77
};
88

@@ -20,16 +20,16 @@ main: () -> int = {
2020
i := 15;
2121

2222
std::cout << inspect i -> std::string {
23-
is (less_then(10)) = "i less than 10";
23+
is (less_than(10)) = "i less than 10";
2424
is (in(11,20)) = "i is between 11 and 20";
2525
is _ = "i is out of our interest";
2626
} << std::endl;
2727

28-
if i is less_then(20) {
28+
if i is (less_than(20)) {
2929
std::cout << "less than 20" << std::endl;
3030
}
3131

32-
if i is in(10,30) {
32+
if i is (in(10,30)) {
3333
std::cout << "i is between 10 and 30" << std::endl;
3434
}
3535

regression-tests/pure2-ufcs-member-access-and-chaining.cpp2

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ main: () -> int = {
1414

1515
get_i(fun()).ufcs();
1616

17-
res := int(42).ufcs();
17+
res := (42).ufcs();
1818

19-
int(j.i).ufcs();
19+
(j.i).ufcs();
2020
}
2121

2222
ufcs: (i:int) -> int = {

regression-tests/test-results/mixed-forwarding.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ requires std::is_same_v<CPP2_TYPEOF(t), std::pair<X,X>>
4040
auto apply_explicit_forward(auto&& t) -> void
4141
requires std::is_same_v<CPP2_TYPEOF(t), std::pair<X,X>>
4242
#line 21 "mixed-forwarding.cpp2"
43-
{ copy_from(CPP2_FORWARD(t).first);// moves
44-
copy_from(CPP2_FORWARD(t).second);// moves
43+
{ copy_from( CPP2_FORWARD(t).first);// moves
44+
copy_from( CPP2_FORWARD(t).second);// moves
4545
}
4646

4747
[[nodiscard]] auto main() -> int{

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#include <iostream>
77
#include <vector>
88

9-
constexpr auto less_then = [](int value) {
9+
constexpr auto less_than = [](int value) {
1010
return [=](auto x) { return x < value;};
1111
};
1212

@@ -30,16 +30,16 @@ constexpr auto empty = [](auto&& x){
3030
auto i { 15 };
3131

3232
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{}; }
33+
if (cpp2::is(__expr, (less_than(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{}; }
3434
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{}; }
3535
else return "i is out of our interest"; }
3636
() << std::endl;
3737

38-
if (cpp2::is(i, less_then(20))) {
38+
if (cpp2::is(i, (less_than(20)))) {
3939
std::cout << "less than 20" << std::endl;
4040
}
4141

42-
if (cpp2::is(std::move(i), in(10, 30))) {
42+
if (cpp2::is(std::move(i), (in(10, 30)))) {
4343
std::cout << "i is between 10 and 30" << std::endl;
4444
}
4545

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,15 @@ auto test(auto const& x) -> void;
3030

3131
std::any a { 0 };
3232
test(a);
33-
a = cpp2::as< std::string>("plugh");
33+
a = cpp2::as<std::string>("plugh");
3434
test(std::move(a));
3535

3636
test(0);
3737
test(1);
3838
test(2);
3939
test(3);
4040
test(-42);
41-
test(cpp2::as< std::string>("xyzzy"));
41+
test(cpp2::as<std::string>("xyzzy"));
4242
test(3.14);
4343
}
4444

regression-tests/test-results/pure2-ufcs-member-access-and-chaining.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ struct fun__ret {
3535

3636
CPP2_UFCS_0(ufcs, get_i(fun()));
3737

38-
auto res { CPP2_UFCS_0(ufcs, int(42)) };
38+
auto res { CPP2_UFCS_0(ufcs, 42) };
3939

40-
CPP2_UFCS_0(ufcs, int(std::move(j).i));
40+
CPP2_UFCS_0(ufcs, (std::move(j).i));
4141
}
4242

4343
[[nodiscard]] auto ufcs(cpp2::in<int> i) -> int{

source/common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ class cmdline_processor
432432
}
433433
}
434434
struct register_flag {
435-
register_flag(int group, std::string_view name, std::string_view description, callback0 handler0, callback1 handler1 = nullptr, std::string_view synonym = {}, bool opt_out = false);
435+
register_flag(int group, std::string_view name, std::string_view description, callback0 handler0, callback1 handler1 = {}, std::string_view synonym = {}, bool opt_out = false);
436436
};
437437

438438
auto set_args(int argc, char* argv[]) -> void {

source/cppfront.cpp

Lines changed: 42 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,7 @@ class positional_printer
598598
// Provide an option to store to a given string instead, which is
599599
// useful for capturing Cpp1-formatted output for generated code
600600
//
601-
auto emit_to_string( std::string* target = nullptr ) -> void {
601+
auto emit_to_string( std::string* target = {} ) -> void {
602602
if (target) {
603603
emit_string_targets.push_back( target );
604604
emit_target_stack.push_back(target_type::string);
@@ -613,7 +613,7 @@ class positional_printer
613613
// useful for postfix expression which have to mix unwrapping operators
614614
// with emitting sub-elements such as expression lists
615615
//
616-
auto emit_to_text_chunks( std::vector<text_with_pos>* target = nullptr ) -> void {
616+
auto emit_to_text_chunks( std::vector<text_with_pos>* target = {} ) -> void {
617617
if (target) {
618618
emit_text_chunks_targets.push_back( target );
619619
emit_target_stack.push_back(target_type::chunks);
@@ -653,7 +653,7 @@ class cppfront
653653

654654
struct arg_info {
655655
passing_style pass = passing_style::in;
656-
token const* ptoken = nullptr;
656+
token const* ptoken = {};
657657
};
658658
std::vector<arg_info> current_args = { {} };
659659

@@ -913,6 +913,14 @@ class cppfront
913913
// is needed where Cpp1 and Cpp2 have different grammar orders
914914
//
915915

916+
auto print_to_string(auto& i, auto... more) -> std::string {
917+
auto print = std::string{};
918+
printer.emit_to_string(&print);
919+
emit(i, more...);
920+
printer.emit_to_string();
921+
return print;
922+
};
923+
916924
//-----------------------------------------------------------------------
917925
// try_emit
918926
//
@@ -1120,8 +1128,8 @@ class cppfront
11201128
printer.print_cpp2(",", a.comma);
11211129
}
11221130
first = false;
1123-
try_emit<unqualified_id_node::expression >(a.arg);
1124-
try_emit<unqualified_id_node::id_expression>(a.arg);
1131+
try_emit<unqualified_id_node::expression>(a.arg);
1132+
try_emit<unqualified_id_node::type_id >(a.arg);
11251133
}
11261134
printer.print_cpp2(">", n.close_angle);
11271135
}
@@ -1188,6 +1196,7 @@ class cppfront
11881196
{
11891197
try_emit<type_id_node::qualified >(n.id);
11901198
try_emit<type_id_node::unqualified>(n.id, false, false);
1199+
try_emit<type_id_node::keyword >(n.id);
11911200

11921201
for (auto i = n.pc_qualifiers.rbegin(); i != n.pc_qualifiers.rend(); ++i) {
11931202
if ((**i) == "const") { printer.print_cpp2(" ", n.position()); }
@@ -1754,13 +1763,6 @@ class cppfront
17541763
}
17551764
};
17561765

1757-
auto print_to_string = [&](auto& i, auto... more) {
1758-
auto print = std::string{};
1759-
printer.emit_to_string(&print);
1760-
emit(i, more...);
1761-
printer.emit_to_string();
1762-
return print;
1763-
};
17641766
auto print_to_text_chunks = [&](auto& i, auto... more) {
17651767
auto text = std::vector<text_with_pos>{};
17661768
printer.emit_to_text_chunks(&text);
@@ -1983,90 +1985,43 @@ class cppfront
19831985

19841986
//-----------------------------------------------------------------------
19851987
//
1986-
template<
1987-
String Name,
1988-
typename Term
1989-
>
1990-
auto emit(binary_expression_node<Name,Term> const& n) -> void
1988+
auto emit(is_as_expression_node const& n) -> void
19911989
{
1992-
assert(n.expr);
1993-
1994-
// Handle is/as expressions
1995-
// TODO: Generalize
1990+
std::string prefix = {};
1991+
std::string suffix = {};
19961992

1997-
// If this is an is_as_expression_node
1998-
//
1999-
if constexpr (std::is_same_v<is_as_expression_node const&, decltype(n)>)
1993+
for (auto i = n.ops.rbegin(); i != n.ops.rend(); ++i)
20001994
{
2001-
if (!n.terms.empty() && *n.terms.front().op == "is")
1995+
// If it's "ISORAS type", emit "cpp2::ISORAS<type>(expr)"
1996+
if (i->type)
20021997
{
2003-
if (n.terms.size() > 1) {
2004-
errors.emplace_back(
2005-
n.position(),
2006-
"(temporary alpha limitation) this compiler is just starting to learn 'is' and only supports a single is-expression (no chaining with other is/as)"
2007-
);
2008-
return;
2009-
}
2010-
2011-
// The term will be a prefix_expression_node
2012-
auto prefix_expr = n.terms.front().expr.get();
2013-
assert (prefix_expr);
2014-
static_assert (std::is_same_v<prefix_expression_node*, decltype(prefix_expr)>);
2015-
2016-
// Hack: In the future we'll distinguish type_id better, but for now
2017-
// "identifier or id_expression w/o ops" works well enough
2018-
//
2019-
// If it's "is type", emit "cpp2::is<type>(expr)"
2020-
if (prefix_expr->ops.empty() && // no prefix ops
2021-
prefix_expr->expr->ops.empty() && // no postfix ops
2022-
(prefix_expr->expr->expr->expr.index() == primary_expression_node::identifier ||
2023-
prefix_expr->expr->expr->expr.index() == primary_expression_node::id_expression
2024-
)
2025-
)
2026-
{
2027-
printer.print_cpp2("cpp2::is<", n.position());
2028-
emit(*n.terms.front().expr);
2029-
printer.print_cpp2(">(", n.position());
2030-
2031-
emit(*n.expr);
2032-
2033-
printer.print_cpp2(")", n.position());
2034-
}
2035-
// Else it's "is value", emit "cpp2::is(expr, value)"
2036-
else
2037-
{
2038-
printer.print_cpp2("cpp2::is(", n.position());
2039-
2040-
emit(*n.expr);
2041-
2042-
printer.print_cpp2(", ", n.position());
2043-
emit(*n.terms.front().expr);
2044-
printer.print_cpp2(")", n.position());
2045-
}
2046-
2047-
return;
1998+
prefix += "cpp2::" + i->op->to_string(true) + "<" + print_to_string(*i->type) + ">(";
1999+
suffix = ")" + suffix;
2000+
}
2001+
// Else it's "is value", emit "cpp2::is(expr, value)"
2002+
else
2003+
{
2004+
assert(i->expr);
2005+
prefix += "cpp2::" + i->op->to_string(true) + "(";
2006+
suffix = ", " + print_to_string(*i->expr) + ")" + suffix;
20482007
}
20492008
}
20502009

2051-
if (!n.terms.empty() && *n.terms.front().op == "as")
2052-
{
2053-
if (n.terms.size() > 1) {
2054-
errors.emplace_back(
2055-
n.position(),
2056-
"(temporary alpha limitation) this compiler is just starting to learn 'as' and only supports a single as-expression (no chaining with other is/as)"
2057-
);
2058-
return;
2059-
}
2010+
printer.print_cpp2(prefix, n.position());
2011+
emit(*n.expr);
2012+
printer.print_cpp2(suffix, n.position());
2013+
}
20602014

2061-
printer.print_cpp2("cpp2::as<", n.position());
2062-
emit(*n.terms.front().expr);
2063-
printer.print_cpp2(">(", n.position());
20642015

2065-
emit(*n.expr);
2066-
2067-
printer.print_cpp2(")", n.position());
2068-
return;
2069-
}
2016+
//-----------------------------------------------------------------------
2017+
//
2018+
template<
2019+
String Name,
2020+
typename Term
2021+
>
2022+
auto emit(binary_expression_node<Name,Term> const& n) -> void
2023+
{
2024+
assert(n.expr);
20702025

20712026
// If this is an assignment expression, don't add std::move on the lhs
20722027
// even if this is a definite last use (only do that when an rvalue is okay)

source/lex.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -439,17 +439,17 @@ auto lex_line(
439439
"^co_yield|^concept|^const|^const_cast|^consteval|^constexpr|^constinit|^continue|"
440440
"^decltype|^default|^double|^do|^dynamic_cast|"
441441
"^else|^enum|^explicit|^export|^extern|"
442-
"^false|^float|^for|^friend|"
442+
"^float|^for|^friend|"
443443
"^goto|"
444444
"^if|^import|^inline|^int|^is|"
445445
"^long|"
446446
"^module|^mutable|"
447-
"^namespace|^new|^noexcept|^nullptr|"
447+
"^namespace|^noexcept|"
448448
"^operator|"
449449
"^private|^protected|^public|"
450450
"^register|^reinterpret_cast|^requires|^return|"
451451
"^short|^signed|^sizeof|^static|^static_assert|^static_cast|^struct|^switch|"
452-
"^template|^this|^thread_local|^throws|^throw|^true|^try|^typedef|^typeid|^typename|"
452+
"^template|^this|^thread_local|^throws|^throw|^try|^typedef|^typeid|^typename|"
453453
"^unsigned|^using|"
454454
"^virtual|^void|^volatile|"
455455
"^wchar_t|^while"

0 commit comments

Comments
 (0)