33 explicit constexpr NameParser(Visitor visitor,
StringViewT const& content)
noexcept(std::is_nothrow_move_constructible_v<Visitor>)
34 : m_Visitor{std::move(visitor)},
44 if (!finalize<token::Type>())
54 if (m_HasConversionOperator)
65 if (!finalize<token::Function>())
70 if (!finalize<token::Type>())
80 static constexpr lexing::operator_or_punctuator openingAngle{
"<"};
81 static constexpr lexing::operator_or_punctuator closingAngle{
">"};
82 static constexpr lexing::operator_or_punctuator openingCurly{
"{"};
83 static constexpr lexing::operator_or_punctuator closingCurly{
"}"};
84 static constexpr lexing::operator_or_punctuator openingSquare{
"["};
85 static constexpr lexing::operator_or_punctuator closingSquare{
"]"};
86 static constexpr lexing::operator_or_punctuator backtick{
"`"};
87 static constexpr lexing::operator_or_punctuator singleQuote{
"'"};
88 static constexpr lexing::operator_or_punctuator scopeResolution{
"::"};
89 static constexpr lexing::operator_or_punctuator commaSeparator{
","};
90 static constexpr lexing::operator_or_punctuator pointer{
"*"};
91 static constexpr lexing::operator_or_punctuator lvalueRef{
"&"};
92 static constexpr lexing::operator_or_punctuator rvalueRef{
"&&"};
93 static constexpr lexing::operator_or_punctuator colon{
":"};
94 static constexpr lexing::operator_or_punctuator leftShift{
"<<"};
95 static constexpr lexing::operator_or_punctuator rightShift{
">>"};
96 static constexpr lexing::operator_or_punctuator plus{
"+"};
97 static constexpr lexing::operator_or_punctuator exclamationMark{
"!"};
98 static constexpr lexing::operator_or_punctuator tilde{
"~"};
99 static constexpr lexing::keyword operatorKeyword{
"operator"};
100 static constexpr lexing::keyword constKeyword{
"const"};
101 static constexpr lexing::keyword volatileKeyword{
"volatile"};
102 static constexpr lexing::keyword noexceptKeyword{
"noexcept"};
103 static constexpr lexing::keyword coAwaitKeyword{
"co_await"};
104 static constexpr lexing::keyword newKeyword{
"new"};
105 static constexpr lexing::keyword deleteKeyword{
"delete"};
106 static constexpr lexing::keyword classKeyword{
"class"};
107 static constexpr lexing::keyword structKeyword{
"struct"};
108 static constexpr lexing::keyword enumKeyword{
"enum"};
110 static constexpr std::array typeKeywordCollection = {
111 lexing::keyword{
"auto"},
112 lexing::keyword{
"void"},
113 lexing::keyword{
"bool"},
114 lexing::keyword{
"char"},
115 lexing::keyword{
"char8_t"},
116 lexing::keyword{
"char16_t"},
117 lexing::keyword{
"char32_t"},
118 lexing::keyword{
"wchar_t"},
119 lexing::keyword{
"double"},
120 lexing::keyword{
"float"},
121 lexing::keyword{
"int"},
122 lexing::keyword{
"__int64"},
123 lexing::keyword{
"long"},
124 lexing::keyword{
"short"},
125 lexing::keyword{
"signed"},
126 lexing::keyword{
"unsigned"}};
130 lexing::NameLexer m_Lexer;
131 bool m_HasConversionOperator{
false};
133 std::vector<Token> m_TokenStack{};
135 template <
typename LexerTokenClass>
136 constexpr LexerTokenClass
const* peek_if() const noexcept
138 return std::get_if<LexerTokenClass>(&m_Lexer.peek().classification);
141 constexpr void parse()
143 for (lexing::token next = m_Lexer.next();
144 !std::holds_alternative<lexing::end>(next.classification);
145 next = m_Lexer.next())
148 [&](
auto const& tokenClass) { handle_lexer_token(next.content, tokenClass); },
149 next.classification);
153 template <token_type EndToken>
154 constexpr bool finalize()
156 if (1u == m_TokenStack.size())
158 if (
auto const*
const end = std::get_if<EndToken>(&m_TokenStack.back()))
163 std::invoke(*end, m_Visitor);
173 constexpr void emit_unrecognized()
176 unwrapped.unrecognized(m_Content);
179 static constexpr void handle_lexer_token([[maybe_unused]]
StringViewT const content, [[maybe_unused]] lexing::end
const& end)
185 constexpr bool merge_with_next_token() const noexcept
187 auto const*
const keyword = peek_if<lexing::keyword>();
193 constexpr void handle_lexer_token([[maybe_unused]]
StringViewT const content, [[maybe_unused]] lexing::space
const& space)
200 && merge_with_next_token())
202 auto& curContent = std::get<StringViewT>(id->content);
203 auto const [nextContent,
_] = m_Lexer.next();
205 MIMICPP_ASSERT(curContent.data() + curContent.size() == content.data(),
"Violated expectation.");
206 MIMICPP_ASSERT(content.data() + content.size() = nextContent.data(),
"Violated expectation.");
209 nextContent.data() + nextContent.size()};
221 if (
auto const*
const nextOp = peek_if<lexing::operator_or_punctuator>();
223 &&
util::contains(std::array{openingAngle, openingParens, openingCurly, singleQuote, backtick}, *nextOp))
225 m_TokenStack.emplace_back(token::Space{});
229 constexpr void handle_lexer_token([[maybe_unused]]
StringViewT const content, lexing::identifier
const& identifier)
231 m_TokenStack.emplace_back(
232 token::Identifier{.content = identifier.content});
235 constexpr void handle_lexer_token([[maybe_unused]]
StringViewT const content, lexing::keyword
const& keyword)
237 if (constKeyword == keyword)
240 MIMICPP_ASSERT(!specs.layers.empty(),
"Zero spec layers detected.");
241 auto& top = specs.layers.back();
245 else if (volatileKeyword == keyword)
248 MIMICPP_ASSERT(!specs.layers.empty(),
"Zero spec layers detected.");
249 auto& top = specs.layers.back();
251 top.isVolatile =
true;
253 else if (noexceptKeyword == keyword)
256 MIMICPP_ASSERT(!specs.isNoexcept,
"Specs already is a noexcept.");
257 specs.isNoexcept =
true;
259 else if (operatorKeyword == keyword && !process_simple_operator())
262 MIMICPP_ASSERT(!m_HasConversionOperator,
"Multiple conversion operators detected.");
264 m_TokenStack.emplace_back(token::OperatorKeyword{});
265 m_HasConversionOperator =
true;
267 else if (
constexpr std::array collection{classKeyword, structKeyword, enumKeyword};
272 m_TokenStack.emplace_back(token::TypeContext{.content = content});
276 m_TokenStack.emplace_back(
278 .isBuiltinType =
true,
279 .content = content});
283 constexpr bool process_simple_operator()
285 auto dropSpaceInput = [
this] {
286 if (std::holds_alternative<lexing::space>(m_Lexer.peek().classification))
288 std::ignore = m_Lexer.next();
295 if (
auto const next = m_Lexer.peek();
296 auto const* operatorToken = std::get_if<lexing::operator_or_punctuator>(&next.classification))
298 std::ignore = m_Lexer.next();
300 auto const finishMultiOpOperator = [&,
this]([[maybe_unused]] lexing::operator_or_punctuator
const& expectedClosingOp) {
301 auto const [closingContent, classification] = m_Lexer.next();
306 next.content.size() + closingContent.size()};
307 m_TokenStack.emplace_back(
309 .content = token::Identifier::OperatorInfo{.symbol = content}});
312 if (openingParens == *operatorToken)
314 finishMultiOpOperator(closingParens);
316 else if (openingSquare == *operatorToken)
318 finishMultiOpOperator(closingSquare);
323 else if (leftShift == *operatorToken)
327 if (
auto const*
const nextOp = peek_if<lexing::operator_or_punctuator>();
330 && (openingParens == *nextOp || openingAngle == *nextOp))
332 m_TokenStack.emplace_back(
334 .content = token::Identifier::OperatorInfo{.symbol = next.content}});
339 m_TokenStack.emplace_back(
341 .content = token::Identifier::OperatorInfo{.symbol = next.content.substr(0u, 1u)}});
342 handle_lexer_token(next.content.substr(1u, 1u), openingAngle);
347 m_TokenStack.emplace_back(
349 .content = token::Identifier::OperatorInfo{.symbol = next.content}});
356 else if (
auto const* keywordToken = std::get_if<lexing::keyword>(&next.classification);
358 &&
util::contains(std::array{newKeyword, deleteKeyword, coAwaitKeyword}, *keywordToken))
360 std::ignore = m_Lexer.next();
364 if (newKeyword == *keywordToken || deleteKeyword == *keywordToken)
368 if (
auto const*
const opAfter = peek_if<lexing::operator_or_punctuator>();
370 && openingSquare == *opAfter)
373 std::ignore = m_Lexer.next();
375 auto const closing = m_Lexer.next();
376 MIMICPP_ASSERT(closingSquare == std::get<lexing::operator_or_punctuator>(closing.classification),
"Invalid input.");
380 closing.content.data() + closing.content.size()};
384 m_TokenStack.emplace_back(
386 .content = token::Identifier::OperatorInfo{.symbol = content}});
396 constexpr void handle_lexer_token(
StringViewT const content, lexing::operator_or_punctuator
const& token)
398 if (scopeResolution == token)
402 m_TokenStack.emplace_back(
403 std::in_place_type<token::ScopeResolution>,
407 else if (commaSeparator == token)
415 m_TokenStack.emplace_back(
416 std::in_place_type<token::ArgSeparator>,
419 else if (lvalueRef == token)
425 else if (rvalueRef == token)
431 else if (pointer == token)
434 specs.layers.emplace_back();
436 else if (openingAngle == token)
438 m_TokenStack.emplace_back(
439 std::in_place_type<token::OpeningAngle>,
442 else if (closingAngle == token)
450 m_TokenStack.emplace_back(
451 std::in_place_type<token::ClosingAngle>,
456 else if (openingParens == token)
458 m_TokenStack.emplace_back(
459 std::in_place_type<token::OpeningParens>,
462 else if (closingParens == token)
464 bool isNextOpeningParens{
false};
465 if (
auto const*
const nextOp = peek_if<lexing::operator_or_punctuator>())
467 isNextOpeningParens = (openingParens == *nextOp);
472 if (!isNextOpeningParens)
481 m_TokenStack.emplace_back(
482 std::in_place_type<token::ClosingParens>,
485 if (
bool const result = isNextOpeningParens
493 else if (openingCurly == token)
495 m_TokenStack.emplace_back(
496 std::in_place_type<token::OpeningCurly>,
499 else if (closingCurly == token)
501 m_TokenStack.emplace_back(
502 std::in_place_type<token::ClosingCurly>,
506 else if (backtick == token)
508 m_TokenStack.emplace_back(
509 std::in_place_type<token::OpeningBacktick>,
512 else if (singleQuote == token)
516 unwrap_msvc_like_function();
521 m_TokenStack.erase(m_TokenStack.cend() - 3u);
525 m_TokenStack.emplace_back(
526 std::in_place_type<token::ClosingSingleQuote>,
536 else if (leftShift == token)
538 handle_lexer_token(content.substr(0, 1u), openingAngle);
539 handle_lexer_token(content.substr(1u, 1u), openingAngle);
541 else if (rightShift == token)
543 handle_lexer_token(content.substr(0, 1u), closingAngle);
544 handle_lexer_token(content.substr(1u, 1u), closingAngle);
547 else if (tilde == token)
549 if (
auto const* nextId = peek_if<lexing::identifier>())
553 nextId->content.data() + nextId->content.size()};
554 m_TokenStack.emplace_back(token::Identifier{.content = merged});
555 std::ignore = m_Lexer.next();
561 else if (plus == token)
563 if (
auto const*
const nextId = peek_if<lexing::identifier>();
565 && nextId->content.starts_with(
"0x"))
567 std::ignore = m_Lexer.next();
573 else if (exclamationMark == token
576 m_TokenStack.pop_back();
580 void unwrap_msvc_like_function()
584 auto funIdentifier = std::get<token::FunctionIdentifier>(m_TokenStack.back());
585 m_TokenStack.pop_back();
587 std::optional<token::ScopeSequence> scopes{};
590 scopes = std::move(*scopeSeq);
591 m_TokenStack.pop_back();
597 m_TokenStack.pop_back();
601 m_TokenStack.pop_back();
606 m_TokenStack.pop_back();
612 m_TokenStack.emplace_back(*std::move(scopes));
615 m_TokenStack.emplace_back(std::move(funIdentifier));