Skip to content

Commit 6a508c8

Browse files
committed
Added more is/as
And fixed some parsing for `obj.func<0>(42);` to not parse as `(obj.func) < (0 > (42));` which I meant to disallow and now do... no relational comparisons in template arg lists (later we can allow them when parenthesized or something like that)
1 parent 21a4d04 commit 6a508c8

File tree

3 files changed

+180
-63
lines changed

3 files changed

+180
-63
lines changed

cpp2util.h

Lines changed: 119 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import std.threading;
4040
#include <iostream>
4141
#include <cassert>
4242
#include <variant>
43+
#include <cstddef>
4344
#endif
4445

4546

@@ -72,20 +73,20 @@ namespace cpp2 {
7273
struct {
7374
template<typename T, typename... Args>
7475
[[nodiscard]] auto cpp2_new(auto ...args) const -> std::unique_ptr<T> {
75-
return std::make_unique<T>(CPP2_FORWARD(args)...);
76+
return std::make_unique<T>(std::forward<decltype(args)>(args)...);
7677
}
7778
} unique;
7879

7980
struct {
8081
template<typename T, typename... Args>
8182
[[nodiscard]] auto cpp2_new(auto ...args) const -> std::shared_ptr<T> {
82-
return std::make_shared<T>(CPP2_FORWARD(args)...);
83+
return std::make_shared<T>(std::forward<decltype(args)>(args)...);
8384
}
8485
} shared;
8586

8687
template<typename T, typename... Args>
8788
[[nodiscard]] auto cpp2_new(auto ...args) -> std::unique_ptr<T> {
88-
return std::make_unique<T>(CPP2_FORWARD(args)...);
89+
return std::make_unique<T>(std::forward<decltype(args)>(args)...);
8990
}
9091

9192

@@ -130,8 +131,8 @@ class deferred_init {
130131
~deferred_init() noexcept { if (init) t.~T(); }
131132
auto value() noexcept -> T& { assert(init); return t; }
132133

133-
auto construct (auto ...args) -> void { assert(!init); new (&t) T(CPP2_FORWARD(args)...); init = true; }
134-
auto construct_list(auto ...args) -> void { assert(!init); new (&t) T{CPP2_FORWARD(args)...}; init = true; }
134+
auto construct (auto ...args) -> void { assert(!init); new (&t) T(std::forward<decltype(args)>(args)...); init = true; }
135+
auto construct_list(auto ...args) -> void { assert(!init); new (&t) T{std::forward<decltype(args)>(args)...}; init = true; }
135136
};
136137

137138
template<typename T>
@@ -270,7 +271,7 @@ auto assert_not_null(auto&& p CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT) -> auto&&
270271
{
271272
// Checking against a default-constructed value should be fine for iterators too
272273
// TODO: validate this works for all pointerlike types
273-
Null.expects(p != CPP2_TYPEOF(p){} CPP2_SOURCE_LOCATION_ARG);
274+
Null.expects(p != CPP2_TYPEOF(p){}, "dynamic null dereference attempt detected" CPP2_SOURCE_LOCATION_ARG);
274275
return std::forward<decltype(p)>(p);
275276
}
276277

@@ -283,82 +284,150 @@ auto assert_not_null(auto&& p CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT) -> auto&&
283284
//
284285
#define CPP2_UFCS(FUNCNAME,PARAM1,...) \
285286
[](auto&& obj, auto&& ...params) { \
286-
if constexpr (requires{ CPP2_FORWARD(obj).FUNCNAME(CPP2_FORWARD(params)...); }) { \
287-
return CPP2_FORWARD(obj).FUNCNAME(CPP2_FORWARD(params)...); \
287+
if constexpr (requires{ std::forward<decltype(obj)>(obj).FUNCNAME(std::forward<decltype(params)>(params)...); }) { \
288+
return std::forward<decltype(obj)>(obj).FUNCNAME(std::forward<decltype(params)>(params)...); \
288289
} else { \
289-
return FUNCNAME(CPP2_FORWARD(obj), CPP2_FORWARD(params)...); \
290+
return FUNCNAME(std::forward<decltype(obj)>(obj), std::forward<decltype(params)>(params)...); \
290291
} \
291292
}(PARAM1, __VA_ARGS__)
292293

293294
#define CPP2_UFCS_0(FUNCNAME,PARAM1) \
294295
[](auto&& obj) { \
295-
if constexpr (requires{ CPP2_FORWARD(obj).FUNCNAME(); }) { \
296-
return CPP2_FORWARD(obj).FUNCNAME(); \
296+
if constexpr (requires{ std::forward<decltype(obj)>(obj).FUNCNAME(); }) { \
297+
return std::forward<decltype(obj)>(obj).FUNCNAME(); \
297298
} else { \
298-
return FUNCNAME(CPP2_FORWARD(obj)); \
299+
return FUNCNAME(std::forward<decltype(obj)>(obj)); \
299300
} \
300301
}(PARAM1)
301302

302303

303-
304-
/*
305304
//-----------------------------------------------------------------------
306305
//
307306
// is and as
308307
//
309308
//-----------------------------------------------------------------------
310309
//
311-
#include <cstddef>
312-
#include <iostream>
313-
#include <cassert>
310+
//-------------------------------------------------------------------------------------------------------------
311+
// Built-in is (partial)
312+
//
313+
314+
// For use when returning "no such thing", such as
315+
// when customizing is/as for std::variant
316+
static std::nullptr_t nonesuch = nullptr;
317+
318+
template< typename C, typename X >
319+
auto is( X const& ) -> bool {
320+
return false;
321+
}
314322

315-
#define typeof(x) std::remove_cvref_t<decltype(x)>
323+
template< typename C, typename X >
324+
requires std::is_same_v<C, X>
325+
auto is( X const& ) -> bool {
326+
return true;
327+
}
328+
329+
template< typename C, typename X >
330+
requires (std::is_base_of_v<C, X> && !std::is_same_v<C,X>)
331+
auto is( X const& ) -> bool {
332+
return true;
333+
}
334+
335+
template< typename C, typename X >
336+
requires (std::is_base_of_v<X, C> && !std::is_same_v<C,X>)
337+
auto is( X const& x ) -> bool {
338+
return dynamic_cast<C const*>(&x) != nullptr;
339+
}
340+
341+
template< typename C, typename X >
342+
requires (std::is_base_of_v<X, C> && !std::is_same_v<C,X>)
343+
auto is( X const* x ) -> bool {
344+
return dynamic_cast<C const&>(x) != nullptr;
345+
}
316346

317347

318348
//-------------------------------------------------------------------------------------------------------------
319-
// Built-in is
349+
// Built-in as (partial)
320350
//
321-
template<typename T, typename X>
322-
auto is( X const& x ) {
323-
return false;
351+
template< typename C, typename X >
352+
requires std::is_base_of_v<C, X>
353+
auto as( X&& x ) -> C&& {
354+
return std::forward<X>(x);
324355
}
325356

326-
template<typename T, typename X>
327-
requires std::is_same_v<T, X>
328-
auto is( X const& x ) {
329-
return true;
357+
template< typename C, typename X >
358+
requires (std::is_base_of_v<X, C> && !std::is_same_v<C,X>)
359+
auto as( X& x ) -> C& {
360+
return dynamic_cast<C&>(x);
361+
}
362+
363+
template< typename C, typename X >
364+
requires (std::is_base_of_v<X, C> && !std::is_same_v<C,X>)
365+
auto as( X const& x ) -> C const& {
366+
return dynamic_cast<C const&>(x);
330367
}
331368

369+
template< typename C, typename X >
370+
requires (std::is_base_of_v<X, C> && !std::is_same_v<C,X>)
371+
auto as( X* x ) -> C* {
372+
return dynamic_cast<C*>(x);
373+
}
374+
375+
template< typename C, typename X >
376+
requires (std::is_base_of_v<X, C> && !std::is_same_v<C,X>)
377+
auto as( X const* x ) -> C const* {
378+
return dynamic_cast<C const*>(x);
379+
}
332380

333381

334382
//-------------------------------------------------------------------------------------------------------------
335-
// variant is and as
383+
// std::variant is and as
336384
//
337385
template<typename... Ts>
338386
constexpr auto operator_is( std::variant<Ts...> const& x ) {
339387
return x.index();
340388
}
341389
template<size_t I, typename... Ts>
342390
constexpr auto operator_as( std::variant<Ts...> const& x ) -> auto&& {
343-
return std::get<I>( x );
391+
if constexpr (I < std::variant_size_v<std::variant<Ts...>>) {
392+
return std::get<I>( x );
393+
}
394+
else {
395+
return nonesuch;
396+
}
344397
}
345398

346399
template<typename T, typename... Ts>
347400
auto is( std::variant<Ts...> const& x ) {
348-
if constexpr (std::is_same_v< typeof(operator_as<0>(x)), T >) if (x.index() == 0) return true;
349-
if constexpr (std::is_same_v< typeof(operator_as<1>(x)), T >) if (x.index() == 1) return true;
350-
if constexpr (std::is_same_v< typeof(operator_as<2>(x)), T >) if (x.index() == 2) return true;
401+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<0>(x)), T >) if (x.index() == 0) return true;
402+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<1>(x)), T >) if (x.index() == 1) return true;
403+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<2>(x)), T >) if (x.index() == 2) return true;
404+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<3>(x)), T >) if (x.index() == 3) return true;
405+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<4>(x)), T >) if (x.index() == 4) return true;
406+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<5>(x)), T >) if (x.index() == 5) return true;
407+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<6>(x)), T >) if (x.index() == 6) return true;
408+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<7>(x)), T >) if (x.index() == 7) return true;
409+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<8>(x)), T >) if (x.index() == 8) return true;
410+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<9>(x)), T >) if (x.index() == 9) return true;
351411
return false;
352412
}
353413

354414
template<typename T, typename... Ts>
355415
auto as( std::variant<Ts...> const& x ) {
356-
if constexpr (std::is_same_v< typeof(operator_as<0>(x)), T >) if (x.index() == 0) return operator_as<0>(x);
357-
if constexpr (std::is_same_v< typeof(operator_as<1>(x)), T >) if (x.index() == 1) return operator_as<1>(x);
358-
if constexpr (std::is_same_v< typeof(operator_as<2>(x)), T >) if (x.index() == 2) return operator_as<2>(x);
416+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<0>(x)), T >) if (x.index() == 0) return operator_as<0>(x);
417+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<1>(x)), T >) if (x.index() == 1) return operator_as<1>(x);
418+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<2>(x)), T >) if (x.index() == 2) return operator_as<2>(x);
419+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<3>(x)), T >) if (x.index() == 3) return operator_as<3>(x);
420+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<4>(x)), T >) if (x.index() == 4) return operator_as<4>(x);
421+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<5>(x)), T >) if (x.index() == 5) return operator_as<5>(x);
422+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<6>(x)), T >) if (x.index() == 6) return operator_as<2>(x);
423+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<7>(x)), T >) if (x.index() == 7) return operator_as<3>(x);
424+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<8>(x)), T >) if (x.index() == 8) return operator_as<4>(x);
425+
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<9>(x)), T >) if (x.index() == 9) return operator_as<5>(x);
359426
throw std::bad_variant_access();
360427
}
361428

429+
430+
/*
362431
//=============================================================================================================
363432
364433
int main() {
@@ -394,4 +463,20 @@ int main() {
394463
using cpp2::cpp2_new;
395464

396465

466+
namespace gsl {
467+
468+
//-----------------------------------------------------------------------
469+
//
470+
// An implementation of GSL's narrow_cast
471+
//
472+
//-----------------------------------------------------------------------
473+
//
474+
template<typename To, typename From>
475+
constexpr auto narrow_cast(From&& from) noexcept -> To
476+
{
477+
return static_cast<To>(std::forward<From>(from));
478+
}
479+
480+
}
481+
397482
#endif

cppfront.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,7 +1160,7 @@ class cppfront
11601160

11611161
// Check that this isn't pointer arithmentic
11621162
// (initial partial implementation)
1163-
if (n.expr->expr.index() == primary_expression_node::id_expression)
1163+
if (n.ops.empty() && n.expr->expr.index() == primary_expression_node::id_expression)
11641164
{
11651165
auto& id = std::get<primary_expression_node::id_expression>(n.expr->expr);
11661166
assert(id);
@@ -1199,7 +1199,7 @@ class cppfront
11991199
return;
12001200
}
12011201

1202-
// Check to see if it's just a function call,
1202+
// Check to see if it's just a function call with "." syntax,
12031203
// and if so use this path to convert it to UFCS
12041204
if (std::ssize(n.ops) == 1 &&
12051205
n.ops.front().op->type() == lexeme::LeftParen &&
@@ -1213,7 +1213,8 @@ class cppfront
12131213
auto& qual = std::get<id_expression_node::qualified>(id->id);
12141214
assert(qual);
12151215
if (std::ssize(qual->ids) == 2 &&
1216-
qual->ids.back().scope_op->type() == lexeme::Dot
1216+
qual->ids.back().scope_op->type() == lexeme::Dot &&
1217+
qual->ids.back().id->get_token()
12171218
)
12181219
{
12191220
// OK, we're in the UFCS syntax case...
@@ -1373,6 +1374,25 @@ class cppfront
13731374
// Handle is/as expressions
13741375
// For now, hack in just a single 'as'-cast
13751376
// TODO: Generalize
1377+
if (!n.terms.empty() && *n.terms.front().op == "is") {
1378+
if (n.terms.size() > 1) {
1379+
errors.emplace_back(
1380+
n.position(),
1381+
"(temporary alpha limitation) this compiler is just starting to learn 'is' and only supports a single is-expression (no chaining with other is/as)"
1382+
);
1383+
return;
1384+
}
1385+
1386+
printer.print_cpp2("cpp2::is<", n.position());
1387+
//printer.preempt_position(n.position());
1388+
emit(*n.terms.front().expr);
1389+
printer.print_cpp2(">(", n.position());
1390+
//printer.preempt_position(n.position());
1391+
emit(*n.expr);
1392+
printer.print_cpp2(")", n.position());
1393+
return;
1394+
}
1395+
13761396
if (!n.terms.empty() && *n.terms.front().op == "as") {
13771397
if (n.terms.size() > 1) {
13781398
errors.emplace_back(
@@ -1382,7 +1402,7 @@ class cppfront
13821402
return;
13831403
}
13841404

1385-
printer.print_cpp2("static_cast<", n.position());
1405+
printer.print_cpp2("cpp2::as<", n.position());
13861406
//printer.preempt_position(n.position());
13871407
emit(*n.terms.front().expr);
13881408
printer.print_cpp2(">(", n.position());

0 commit comments

Comments
 (0)