mimic++ v9.2.1
Loading...
Searching...
No Matches
NameParserReductions.hpp
Go to the documentation of this file.
1// Copyright Dominic (DNKpp) Koepke 2024 - 2025.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at
4// https://www.boost.org/LICENSE_1_0.txt)
5
6#ifndef MIMICPP_PRINTING_TYPE_NAME_PARSER_REDUCTIONS_HPP
7#define MIMICPP_PRINTING_TYPE_NAME_PARSER_REDUCTIONS_HPP
8
9#include "mimic++/Fwd.hpp"
13
14#ifndef MIMICPP_DETAIL_IS_MODULE
15 #include <optional>
16 #include <span>
17 #include <utility>
18 #include <variant>
19#endif
20
22{
23 namespace detail
24 {
25 template <typename Last, typename... Others>
26 [[nodiscard]]
27 constexpr bool is_suffix_of(
28 [[maybe_unused]] util::type_list<Last, Others...> const types,
29 std::span<Token const> const tokenStack) noexcept
30 {
31 if (tokenStack.empty()
32 || !std::holds_alternative<Last>(tokenStack.back()))
33 {
34 return false;
35 }
36
37 if constexpr (0u < sizeof...(Others))
38 {
39 return is_suffix_of(
40 util::type_list<Others...>{},
41 tokenStack.first(tokenStack.size() - 1));
42 }
43 else
44 {
45 return true;
46 }
47 }
48 }
49
50 template <token_type First, token_type... Others>
51 constexpr bool is_suffix_of(std::span<Token const> const tokenStack) noexcept
52 {
53 using types = util::type_list<First, Others...>;
54
55 return 1u + sizeof...(Others) <= tokenStack.size()
56 && detail::is_suffix_of(util::type_list_reverse_t<types>{}, tokenStack);
57 }
58
59 template <token_type Leading, token_type... Others>
60 [[nodiscard]]
61 constexpr auto match_suffix(std::span<Token> const tokenStack) noexcept
62 {
63 if constexpr (0u == sizeof...(Others))
64 {
65 Leading* result{};
66 if (is_suffix_of<Leading>(tokenStack))
67 {
68 result = &std::get<Leading>(tokenStack.back());
69 }
70
71 return result;
72 }
73 else
74 {
75 std::optional<std::tuple<Leading&, Others&...>> result{};
77 {
78 auto const suffix = tokenStack.last(1u + sizeof...(Others));
79
80 result = std::invoke(
81 [&]<std::size_t... indices>([[maybe_unused]] std::index_sequence<indices...> const) noexcept {
82 return std::tie(
83 std::get<Leading>(suffix[0u]),
84 std::get<Others>(suffix[1u + indices])...);
85 },
86 std::index_sequence_for<Others...>{});
87 }
88
89 return result;
90 }
91 }
92
93 constexpr void remove_suffix(std::span<Token>& tokenStack, std::size_t const count) noexcept
94 {
95 MIMICPP_ASSERT(count <= tokenStack.size(), "Count exceeds stack size.");
96 tokenStack = tokenStack.first(tokenStack.size() - count);
97 }
98
99 constexpr void ignore_space(std::span<Token>& tokenStack) noexcept
100 {
101 if (is_suffix_of<token::Space>(tokenStack))
102 {
103 remove_suffix(tokenStack, 1u);
104 }
105 }
106
107 constexpr void ignore_reserved_identifier(std::span<Token>& tokenStack) noexcept
108 {
109 if (auto const* const id = match_suffix<token::Identifier>(tokenStack);
110 id
111 && id->is_reserved())
112 {
113 remove_suffix(tokenStack, 1u);
114 }
115 }
116
117 namespace token
118 {
119 bool try_reduce_as_type(TokenStack& tokenStack);
120
122 {
123 std::span pendingTokens{tokenStack};
124 if (!is_suffix_of<ScopeResolution>(pendingTokens))
125 {
126 return false;
127 }
128 remove_suffix(pendingTokens, 1u);
129
130 ScopeSequence::Scope scope{};
131 if (auto* identifier = match_suffix<Identifier>(pendingTokens))
132 {
133 scope = std::move(*identifier);
134 }
135 else if (auto* funIdentifier = match_suffix<FunctionIdentifier>(pendingTokens))
136 {
137 scope = std::move(*funIdentifier);
138 }
139 else
140 {
141 return false;
142 }
143
144 remove_suffix(pendingTokens, 1u);
145 tokenStack.resize(pendingTokens.size());
146
147 if (auto* sequence = match_suffix<ScopeSequence>(tokenStack))
148 {
149 sequence->scopes.emplace_back(std::move(scope));
150 }
151 else
152 {
153 tokenStack.emplace_back(
155 .scopes = {std::move(scope)}});
156 }
157
158 return true;
159 }
160
162 {
163 std::span pendingTokens{tokenStack};
164 if (std::optional suffix = match_suffix<ArgSequence, ArgSeparator, Type>(pendingTokens))
165 {
166 // Keep ArgSequence
167 remove_suffix(pendingTokens, 2u);
168 auto& [seq, sep, type] = *suffix;
169
170 seq.types.emplace_back(std::move(type));
171 tokenStack.resize(pendingTokens.size());
172
173 return true;
174 }
175
176 if (auto* type = match_suffix<Type>(pendingTokens))
177 {
178 remove_suffix(pendingTokens, 1u);
179
180 ArgSequence seq{};
181 seq.types.emplace_back(std::move(*type));
182 tokenStack.resize(pendingTokens.size());
183 tokenStack.emplace_back(std::move(seq));
184
185 return true;
186 }
187
188 return false;
189 }
190
192 {
193 std::span pendingTokens{tokenStack};
194 if (!is_suffix_of<ClosingAngle>(pendingTokens))
195 {
196 return false;
197 }
198 remove_suffix(pendingTokens, 1u);
199
200 auto* args = match_suffix<ArgSequence>(pendingTokens);
201 if (args)
202 {
203 remove_suffix(pendingTokens, 1u);
204 }
205
206 if (!is_suffix_of<OpeningAngle>(pendingTokens))
207 {
208 return false;
209 }
210 remove_suffix(pendingTokens, 1u);
211
212 auto* id = match_suffix<Identifier>(pendingTokens);
213 if (!id
214 || id->is_template())
215 {
216 return false;
217 }
218
219 if (args)
220 {
221 id->templateArgs = std::move(*args);
222 }
223 else
224 {
225 id->templateArgs.emplace();
226 }
227 tokenStack.resize(pendingTokens.size());
228
229 return true;
230 }
231
233 {
234 std::span pendingTokens{tokenStack};
235 if (!is_suffix_of<ClosingParens>(pendingTokens))
236 {
237 return false;
238 }
239 remove_suffix(pendingTokens, 1u);
240
241 auto* args = match_suffix<ArgSequence>(pendingTokens);
242 if (args)
243 {
244 remove_suffix(pendingTokens, 1u);
245 }
246
247 if (!is_suffix_of<OpeningParens>(pendingTokens))
248 {
249 return false;
250 }
251 remove_suffix(pendingTokens, 1u);
252
253 // There can never be valid function-args in form of `::()`, thus reject it.
254 if (is_suffix_of<ScopeResolution>(pendingTokens)
255 || is_suffix_of<ScopeSequence>(pendingTokens))
256 {
257 return false;
258 }
259
260 FunctionContext funCtx{};
261 if (args)
262 {
263 // We omit function args with only `void`.
264 if (1u != args->types.size()
265 || !args->types.front().is_void())
266 {
267 funCtx.args = std::move(*args);
268 }
269 }
270
271 tokenStack.resize(pendingTokens.size());
272 tokenStack.emplace_back(std::move(funCtx));
273
274 return true;
275 }
276
278 {
279 std::span pendingStack{tokenStack};
280
281 // There may be a space, when the function is wrapped inside single-quotes.
282 ignore_space(pendingStack);
283
284 // Ignore something like `__ptr64` on msvc.
285 ignore_reserved_identifier(pendingStack);
286
287 if (std::optional suffix = match_suffix<Identifier, FunctionContext>(pendingStack))
288 {
289 remove_suffix(pendingStack, 2u);
290
291 auto& [identifier, funCtx] = *suffix;
292 FunctionIdentifier funIdentifier{
293 .identifier = std::move(identifier),
294 .context = std::move(funCtx)};
295
296 tokenStack.resize(pendingStack.size() + 1u);
297 tokenStack.back() = std::move(funIdentifier);
298
299 return true;
300 }
301
302 return false;
303 }
304
305 [[nodiscard]]
306 constexpr bool is_identifier_prefix(std::span<Token const> const tokenStack) noexcept
307 {
308 return tokenStack.empty()
309 || is_suffix_of<Space>(tokenStack)
310 || is_suffix_of<ScopeSequence>(tokenStack)
311 || is_suffix_of<Specs>(tokenStack)
312 || is_suffix_of<Type>(tokenStack)
313 || is_suffix_of<TypeContext>(tokenStack)
314 || is_suffix_of<OpeningAngle>(tokenStack)
315 || is_suffix_of<OpeningParens>(tokenStack)
316 || is_suffix_of<OpeningBacktick>(tokenStack);
317 }
318
319 template <token_type Opening, token_type Closing>
321 {
322 MIMICPP_ASSERT(is_suffix_of<Closing>(tokenStack), "Token-stack does not have the closing token as top.");
323 std::span pendingTokens{tokenStack.begin(), tokenStack.end() - 1};
324
325 auto const openingIter = std::ranges::find_if(
326 pendingTokens.rbegin(),
327 pendingTokens.rend(),
328 [](Token const& token) noexcept { return std::holds_alternative<Opening>(token); });
329 if (openingIter == pendingTokens.rend()
330 || !is_identifier_prefix({pendingTokens.begin(), openingIter.base() - 1}))
331 {
332 return false;
333 }
334
335 // Just treat everything between the opening and closing as placeholder identifier.
336 auto const& opening = std::get<Opening>(*std::ranges::prev(openingIter.base(), 1));
337 auto const& closing = std::get<Closing>(tokenStack.back());
338 auto const contentLength = (closing.content.data() - opening.content.data()) + closing.content.size();
339 StringViewT const content{opening.content.data(), contentLength};
340
341 pendingTokens = std::span{pendingTokens.begin(), openingIter.base() - 1};
342
343 // There may be a space in front of the placeholder, which isn't necessary.
344 ignore_space(pendingTokens);
345
346 tokenStack.resize(pendingTokens.size() + 1u);
347 tokenStack.back() = Identifier{.content = content};
348
349 return true;
350 }
351
353 {
354 std::span pendingTokens{tokenStack};
355
356 auto* const ctx = match_suffix<FunctionContext>(pendingTokens);
357 if (!ctx)
358 {
359 return false;
360 }
361 remove_suffix(pendingTokens, 1u);
362
363 // The return type is always delimited by space from the arg-list.
364 if (!is_suffix_of<Space>(pendingTokens))
365 {
366 // Well, of course there is an exception to the "always".
367 // There is that case on msvc, where it does not add that space between the function-args and the call-convention.
368 // E.g. `void __cdecl()`.
369 // But, as we can be pretty sure from the context, that the identifier can never be the function name, accept it
370 // as valid delimiter.
371 if (auto const* const id = match_suffix<Identifier>(pendingTokens);
372 !id
373 || !id->is_reserved())
374 {
375 return false;
376 }
377 }
378 remove_suffix(pendingTokens, 1u);
379
380 // Ignore call-convention.
381 ignore_reserved_identifier(pendingTokens);
382
383 auto* const returnType = match_suffix<Type>(pendingTokens);
384 if (!returnType)
385 {
386 return false;
387 }
388 remove_suffix(pendingTokens, 1u);
389
390 FunctionType funType{
391 .returnType = std::make_shared<Type>(std::move(*returnType)),
392 .context = std::move(*ctx)};
393
394 tokenStack.resize(
395 std::exchange(pendingTokens, {}).size() + 1u);
396 tokenStack.back().emplace<Type>(std::move(funType));
397
398 return true;
399 }
400
401 inline bool try_reduce_as_function_ptr(TokenStack& tokenStack)
402 {
403 std::span pendingTokens{tokenStack};
404 if (!is_suffix_of<ClosingParens>(pendingTokens))
405 {
406 return false;
407 }
408 remove_suffix(pendingTokens, 1u);
409
410 auto* nestedFunCtx = match_suffix<FunctionContext>(pendingTokens);
411 FunctionPtr* nestedFunPtr{};
412 if (nestedFunCtx)
413 {
414 remove_suffix(pendingTokens, 1u);
415
416 if (auto* ptr = match_suffix<FunctionPtr>(pendingTokens))
417 {
418 nestedFunPtr = ptr;
419 remove_suffix(pendingTokens, 1u);
420 }
421 }
422
423 ignore_space(pendingTokens);
424 // Ignore call-convention.
425 ignore_reserved_identifier(pendingTokens);
426
427 auto* specs = match_suffix<Specs>(pendingTokens);
428 ScopeSequence* scopeSeq{};
429 if (specs && specs->has_ptr())
430 {
431 remove_suffix(pendingTokens, 1u);
432
433 if (auto* const seq = match_suffix<ScopeSequence>(pendingTokens))
434 {
435 scopeSeq = seq;
436 remove_suffix(pendingTokens, 1u);
437 }
438
439 // Ignore call-convention, which may have already been reduced to a type.
440 if (auto const* const type = match_suffix<Type>(pendingTokens))
441 {
442 if (auto const* const regular = std::get_if<RegularType>(&type->state);
443 regular
444 && regular->identifier.is_reserved())
445 {
446 remove_suffix(pendingTokens, 1u);
447 }
448 }
449 }
450 else
451 {
452 RegularType* regular{};
453 if (auto* const type = match_suffix<Type>(pendingTokens))
454 {
455 regular = std::get_if<RegularType>(&type->state);
456 }
457
458 // Unfortunately msvc produces something like `(__cdecl*)` for the function-ptr part.
459 // There is no way to reliably detect whether denotes a function-ptr or argument-list.
460 // So we have to make sure, that the reduction is only called in the right places.
461 // Then we can extract the info from that type.
462 if (!regular
463 || !regular->identifier.is_reserved()
464 || !regular->specs.has_ptr())
465 {
466 return false;
467 }
468
469 specs = &regular->specs;
470 remove_suffix(pendingTokens, 1u);
471 }
472
473 if (!is_suffix_of<OpeningParens>(pendingTokens))
474 {
475 return false;
476 }
477 remove_suffix(pendingTokens, 1u);
478
479 FunctionPtr funPtr{.specs = std::move(*specs)};
480 if (scopeSeq)
481 {
482 funPtr.scopes = std::move(*scopeSeq);
483 }
484
485 if (nestedFunCtx)
486 {
488 .ctx = std::move(*nestedFunCtx)};
489
490 if (nestedFunPtr)
491 {
492 nested.ptr = std::make_shared<FunctionPtr>(std::move(*nestedFunPtr));
493 }
494
495 funPtr.nested = std::move(nested);
496 }
497
498 tokenStack.resize(pendingTokens.size());
499 tokenStack.emplace_back(std::move(funPtr));
500
501 return true;
502 }
503
504 namespace detail
505 {
506 void handled_nested_function_ptr(TokenStack& tokenStack, FunctionPtr::NestedInfo info);
507 }
508
510 {
511 std::span pendingTokens{tokenStack};
512
513 // Ignore something like `__ptr64`.
514 ignore_reserved_identifier(pendingTokens);
515
516 // The return type is always delimited by space from the spec part.
517 if (std::optional suffix = match_suffix<Type, Space, FunctionPtr, FunctionContext>(pendingTokens))
518 {
519 remove_suffix(pendingTokens, 4u);
520 auto& [returnType, space, ptr, ctx] = *suffix;
521
522 std::optional nestedInfo = std::move(ptr.nested);
523 FunctionPtrType ptrType{
524 .returnType = std::make_shared<Type>(std::move(returnType)),
525 .scopes = std::move(ptr.scopes),
526 .specs = std::move(ptr.specs),
527 .context = std::move(ctx)};
528
529 tokenStack.resize(
530 std::exchange(pendingTokens, {}).size() + 1u);
531 tokenStack.back().emplace<Type>(std::move(ptrType));
532
533 // We got something like `ret (*(outer-args))(args)` or `ret (*(*)(outer-args))(args)`, where the currently
534 // processed function-ptr is actually the return-type of the inner function(-ptr).
535 // This may nested in an arbitrary depth!
536 if (nestedInfo)
537 {
538 detail::handled_nested_function_ptr(tokenStack, *std::move(nestedInfo));
539 }
540
541 return true;
542 }
543
544 return false;
545 }
546
547 namespace detail
548 {
549 inline void handled_nested_function_ptr(TokenStack& tokenStack, FunctionPtr::NestedInfo info)
550 {
551 auto& [ptr, ctx] = info;
552
553 // We need to insert an extra space, to follow the general syntax constraints.
554 tokenStack.emplace_back(Space{});
555
556 bool const isFunPtr{ptr};
557 if (ptr)
558 {
559 tokenStack.emplace_back(std::move(*ptr));
560 }
561
562 tokenStack.emplace_back(std::move(ctx));
563
564 if (isFunPtr)
565 {
567 }
568 else
569 {
570 try_reduce_as_function_type(tokenStack);
571 }
572 }
573 }
574
575 inline bool try_reduce_as_regular_type(TokenStack& tokenStack)
576 {
577 std::span pendingTokens{tokenStack};
578 auto* const identifier = match_suffix<Identifier>(pendingTokens);
579 if (!identifier)
580 {
581 return false;
582 }
583 remove_suffix(pendingTokens, 1u);
584
585 // There may be the case, where we already reduced a Type but additionally got something like `__ptr64`.
586 // E.g. `int& __ptr64`. Remove that trailing identifier and treat it as a successful reduction.
587 if (identifier->is_reserved()
588 && is_suffix_of<Type>(pendingTokens))
589 {
590 tokenStack.pop_back();
591
592 return true;
593 }
594
595 auto* const scopes = match_suffix<ScopeSequence>(pendingTokens);
596 if (scopes)
597 {
598 remove_suffix(pendingTokens, 1u);
599 }
600
601 auto* const prefixSpecs = match_suffix<Specs>(pendingTokens);
602 if (prefixSpecs)
603 {
604 // Prefix-specs can only have `const` and/or `volatile`.
605 if (auto const& layers = prefixSpecs->layers;
606 token::Specs::Refness::none != prefixSpecs->refness
607 || prefixSpecs->isNoexcept
608 || 1u != layers.size())
609 {
610 return false;
611 }
612
613 remove_suffix(pendingTokens, 1u);
614 }
615
616 // We do never allow two or more adjacent `Type` tokens, as there is literally no case where this would make sense.
617 if (is_suffix_of<Type>(pendingTokens)
618 || is_suffix_of<FunctionContext>(pendingTokens))
619 {
620 return false;
621 }
622
623 RegularType newType{.identifier = std::move(*identifier)};
624 if (prefixSpecs)
625 {
626 newType.specs = std::move(*prefixSpecs);
627 }
628
629 if (scopes)
630 {
631 newType.scopes = std::move(*scopes);
632 }
633
634 // Ignore something like `class` or `struct` directly in front of a type.
635 if (is_suffix_of<TypeContext>(pendingTokens))
636 {
637 remove_suffix(pendingTokens, 1u);
638 }
639
640 tokenStack.resize(pendingTokens.size());
641 tokenStack.emplace_back(
642 std::in_place_type<Type>,
643 std::move(newType));
644
645 return true;
646 }
647
648 inline bool try_reduce_as_type(TokenStack& tokenStack)
649 {
650 return try_reduce_as_function_ptr_type(tokenStack)
651 || try_reduce_as_function_type(tokenStack)
652 || try_reduce_as_regular_type(tokenStack);
653 }
654
655 inline bool try_reduce_as_function(TokenStack& tokenStack)
656 {
657 std::span pendingTokens{tokenStack};
658 if (auto* funIdentifier = match_suffix<FunctionIdentifier>(pendingTokens))
659 {
660 Function function{
661 .identifier = std::move(*funIdentifier)};
662 remove_suffix(pendingTokens, 1u);
663
664 if (auto* scopes = match_suffix<ScopeSequence>(pendingTokens))
665 {
666 function.scopes = std::move(*scopes);
667 remove_suffix(pendingTokens, 1u);
668 }
669
670 // Ignore call-convention.
671 ignore_reserved_identifier(pendingTokens);
672
673 if (auto* returnType = match_suffix<Type>(pendingTokens))
674 {
675 function.returnType = std::make_shared<Type>(std::move(*returnType));
676 remove_suffix(pendingTokens, 1u);
677 }
678
679 tokenStack.resize(
680 std::exchange(pendingTokens, {}).size());
681 tokenStack.emplace_back(std::move(function));
682
683 return true;
684 }
685
686 return false;
687 }
688
690 {
691 // Functions reported by stacktrace are sometimes not in actual function form,
692 // so we need to be more permissive here.
693 std::optional<FunctionContext> funCtx{};
694 if (auto* const ctx = match_suffix<FunctionContext>(tokenStack))
695 {
696 funCtx = std::move(*ctx);
697 tokenStack.pop_back();
698 }
699
700 try_reduce_as_type(tokenStack);
701 MIMICPP_ASSERT(is_suffix_of<Type>(tokenStack), "Invalid state");
702 auto targetType = std::make_shared<Type>(
703 std::get<Type>(std::move(tokenStack.back())));
704 tokenStack.pop_back();
705
706 MIMICPP_ASSERT(is_suffix_of<OperatorKeyword>(tokenStack), "Invalid state");
707 tokenStack.back() = Identifier{
708 .content = Identifier::OperatorInfo{.symbol = std::move(targetType)}};
709
710 if (funCtx)
711 {
712 tokenStack.emplace_back(*std::move(funCtx));
714 }
715 }
716
717 [[nodiscard]]
718 constexpr Specs& get_or_emplace_specs(TokenStack& tokenStack)
719 {
720 // Maybe wo got something like `type&` and need to reduce that identifier to an actual `Type` token.
721 if (is_suffix_of<Identifier>(tokenStack))
722 {
723 if (try_reduce_as_type(tokenStack))
724 {
725 return std::get<Type>(tokenStack.back()).specs();
726 }
727
728 // The reduction failed, so it's something like `__ptr64` and should be ignored.
729 // This may happen, when specs are attached to functions, like `ret T::foo() & __ptr64`.
730 MIMICPP_ASSERT(std::get<Identifier>(tokenStack.back()).is_reserved(), "Unexpected token.");
731 tokenStack.pop_back();
732 }
733
734 if (auto* const type = match_suffix<Type>(tokenStack))
735 {
736 return type->specs();
737 }
738
739 if (auto* const ctx = match_suffix<FunctionContext>(tokenStack))
740 {
741 return ctx->specs;
742 }
743
744 if (auto* specs = match_suffix<Specs>(tokenStack))
745 {
746 return *specs;
747 }
748
749 // No specs found yet? Assume prefix specs.
750 return std::get<Specs>(tokenStack.emplace_back(Specs{}));
751 }
752 }
753}
754
755#endif
#define MIMICPP_DETAIL_CONSTEXPR_VECTOR
Definition Config.hpp:69
#define MIMICPP_ASSERT(condition, msg)
Definition Config.hpp:51
Definition NameParserTokens.hpp:235
std::vector< Type > types
Definition NameParserTokens.hpp:237
Definition NameParserTokens.hpp:615
Definition NameParserTokens.hpp:466
Definition NameParserTokens.hpp:254
Definition NameParserTokens.hpp:415
Specs specs
Definition NameParserTokens.hpp:419
std::variant< Identifier, FunctionIdentifier > Scope
Definition NameParserTokens.hpp:378
Definition NameParserTokens.hpp:156
@ none
Definition NameParserTokens.hpp:184
Definition NameParserTokens.hpp:517
Definition NameParserTokens.hpp:676
Definition NameParserReductions.hpp:118
constexpr bool try_reduce_as_placeholder_identifier_wrapped(TokenStack &tokenStack)
Definition NameParserReductions.hpp:320
bool try_reduce_as_function(TokenStack &tokenStack)
Definition NameParserReductions.hpp:655
bool try_reduce_as_type(TokenStack &tokenStack)
Definition NameParserReductions.hpp:648
bool try_reduce_as_regular_type(TokenStack &tokenStack)
Definition NameParserReductions.hpp:575
constexpr bool try_reduce_as_template_identifier(TokenStack &tokenStack)
Definition NameParserReductions.hpp:191
MIMICPP_DETAIL_CONSTEXPR_VECTOR bool try_reduce_as_arg_sequence(TokenStack &tokenStack)
Definition NameParserReductions.hpp:161
void reduce_as_conversion_operator_function_identifier(TokenStack &tokenStack)
Definition NameParserReductions.hpp:689
bool try_reduce_as_scope_sequence(TokenStack &tokenStack)
Definition NameParserReductions.hpp:121
bool try_reduce_as_function_identifier(TokenStack &tokenStack)
Definition NameParserReductions.hpp:277
MIMICPP_DETAIL_CONSTEXPR_VECTOR bool try_reduce_as_function_context(TokenStack &tokenStack)
Definition NameParserReductions.hpp:232
bool try_reduce_as_function_ptr(TokenStack &tokenStack)
Definition NameParserReductions.hpp:401
bool try_reduce_as_function_type(TokenStack &tokenStack)
Definition NameParserReductions.hpp:352
constexpr bool is_identifier_prefix(std::span< Token const > const tokenStack) noexcept
Definition NameParserReductions.hpp:306
constexpr Specs & get_or_emplace_specs(TokenStack &tokenStack)
Definition NameParserReductions.hpp:718
bool try_reduce_as_function_ptr_type(TokenStack &tokenStack)
Definition NameParserReductions.hpp:509
Definition NameParser.hpp:27
constexpr void ignore_reserved_identifier(std::span< Token > &tokenStack) noexcept
Definition NameParserReductions.hpp:107
constexpr void remove_suffix(std::span< Token > &tokenStack, std::size_t const count) noexcept
Definition NameParserReductions.hpp:93
std::variant< token::Space, token::OperatorKeyword, token::ScopeResolution, token::ArgSeparator, token::OpeningAngle, token::ClosingAngle, token::OpeningParens, token::ClosingParens, token::OpeningCurly, token::ClosingCurly, token::OpeningBacktick, token::ClosingSingleQuote, token::TypeContext, token::Identifier, token::FunctionIdentifier, token::ScopeSequence, token::ArgSequence, token::FunctionContext, token::FunctionPtr, token::Specs, token::Type, token::Function > Token
Definition NameParserTokens.hpp:649
constexpr bool is_suffix_of(std::span< Token const > const tokenStack) noexcept
Definition NameParserReductions.hpp:51
constexpr auto match_suffix(std::span< Token > const tokenStack) noexcept
Definition NameParserReductions.hpp:61
constexpr void ignore_space(std::span< Token > &tokenStack) noexcept
Definition NameParserReductions.hpp:99
std::vector< Token > TokenStack
Definition NameParserTokens.hpp:673
Definition Fwd.hpp:54
Definition Fwd.hpp:400
typename type_list_reverse< TypeList >::type type_list_reverse_t
Definition TypeList.hpp:58
std::basic_string_view< CharT, CharTraitsT > StringViewT
Definition Fwd.hpp:392
A very basic type-list template.
Definition TypeList.hpp:29
static constexpr std::size_t size
Definition TypeList.hpp:30