Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions include/ctnp/Algorithm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,56 @@ namespace ctnp::util

return {lower, end};
}

namespace detail
{
struct contains_fn
{
template <
std::input_iterator Iterator,
std::sentinel_for<Iterator> Sentinel,
typename Projection = std::identity,
typename T = util::projected_value_t<Iterator, Projection>>
requires std::indirect_binary_predicate<
std::ranges::equal_to,
std::projected<Iterator, Projection>,
T const*>
[[nodiscard]]
constexpr bool operator()(Iterator first, Sentinel last, T const& value, Projection projection = {}) const
{
auto const iter = std::ranges::find(std::move(first), last, value, std::move(projection));
return iter != last;
}

template <
std::ranges::input_range Range,
typename Projection = std::identity,
typename T = util::projected_value_t<std::ranges::iterator_t<Range>, Projection>>
requires std::indirect_binary_predicate<
std::ranges::equal_to,
std::projected<std::ranges::iterator_t<Range>, Projection>,
T const*>
[[nodiscard]]
constexpr bool operator()(Range&& r, T const& value, Projection projection = {}) const
{
return std::invoke(
*this,
std::ranges::begin(r),
std::ranges::end(r),
value,
std::move(projection));
}
};
}

/**
* \brief Determines, whether the specified value is contained in the given range.
* \return Returns `true`, when the value is contained.
*
* \note This is a backport from c++23 `std::ranges::contains`.
* \see https://en.cppreference.com/w/cpp/algorithm/ranges/contains
*/
inline constexpr detail::contains_fn contains{};
}

#endif
62 changes: 62 additions & 0 deletions include/ctnp/TypeList.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright Dominic (DNKpp) Koepke 2025 - 2025.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)

#ifndef CTNP_TYPE_LIST_HPP
#define CTNP_TYPE_LIST_HPP

#pragma once

#include <concepts>
#include <cstddef>
#include <tuple>
#include <utility>

namespace ctnp::util
{
/**
* \brief A very basic type-list template.
* \tparam Args The types.
*/
template <typename... Args>
struct type_list
{
static constexpr std::size_t size = sizeof...(Args);
};

namespace detail
{
template <typename ProcessedList, typename PendingList>
struct type_list_reverse;

template <typename ProcessedList>
struct type_list_reverse<ProcessedList, type_list<>>
{
using type = ProcessedList;
};

template <typename... ProcessedArgs, typename First, typename... Args>
struct type_list_reverse<type_list<ProcessedArgs...>, type_list<First, Args...>>
: public type_list_reverse<type_list<First, ProcessedArgs...>, type_list<Args...>>
{
};
}

template <typename TypeList>
struct type_list_reverse
{
using type = typename detail::type_list_reverse<type_list<>, TypeList>::type;
};

template <typename TypeList>
using type_list_reverse_t = typename type_list_reverse<TypeList>::type;
}

template <typename... Args>
struct std::tuple_size<ctnp::util::type_list<Args...>> // NOLINT(*-dcl58-cpp)
: std::integral_constant<std::size_t, ctnp::util::type_list<Args...>::size>
{
};

#endif
134 changes: 134 additions & 0 deletions include/ctnp/parsing/Parser.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Copyright Dominic (DNKpp) Koepke 2025 - 2025.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)

#ifndef CTNP_PARSING_PARSER_HPP
#define CTNP_PARSING_PARSER_HPP

#pragma once

#include "ctnp/Lexer.hpp"
#include "ctnp/parsing/Tokens.hpp"

#include <string_view>
#include <variant>
#include <vector>
#include <optional>

namespace ctnp::parsing::detail
{
using TypeResult = std::optional<token::Type>;
using FunctionResult = std::variant<std::monostate, token::Function, token::Type>;

class ParserImpl
{
public:
[[nodiscard]]
explicit ParserImpl(std::string_view const& content) noexcept;

[[nodiscard]]
constexpr std::string_view content() const noexcept
{
return m_Content;
}

[[nodiscard]]
TypeResult parse_type();

[[nodiscard]]
FunctionResult parse_function();

private:
std::string_view m_Content;
lexing::Lexer m_Lexer;
bool m_HasConversionOperator{false};

std::vector<Token> m_TokenStack{};

template <typename LexerTokenClass>
[[nodiscard]]
constexpr LexerTokenClass const* peek_if() const noexcept
{
return std::get_if<LexerTokenClass>(&m_Lexer.peek().classification);
}

void parse();

[[nodiscard]]
bool merge_with_next_token() const noexcept;
[[nodiscard]]
bool process_simple_operator();
void unwrap_msvc_like_function();

static void handle_lexer_token(std::string_view content, lexing::token::End const& end);
void handle_lexer_token(std::string_view content, lexing::token::Space const& space);
void handle_lexer_token(std::string_view content, lexing::token::Identifier const& identifier);
void handle_lexer_token(std::string_view content, lexing::token::Keyword const& keyword);
void handle_lexer_token(std::string_view content, lexing::token::OperatorOrPunctuator const& token);
};

template <typename Visitor>
struct ResultVisitor
{
Visitor& visitor;
std::string_view content;

constexpr void operator()([[maybe_unused]] std::monostate const) const
{
visitor.unrecognized(content);
}

constexpr void operator()(auto const& result) const
{
visitor.begin();
std::invoke(result, visitor);
visitor.end();
}
};
}

namespace ctnp::parsing
{
template <parser_visitor Visitor>
class Parser
{
public:
[[nodiscard]]
explicit constexpr Parser(Visitor visitor, std::string_view content) noexcept(std::is_nothrow_move_constructible_v<Visitor>)
: m_Visitor{std::move(visitor)},
m_Parser{std::move(content)}
{
}

void parse_type()
{
auto& unwrapped = unwrap_visitor(m_Visitor);
if (std::optional const result = m_Parser.parse_type())
{
unwrapped.begin();
std::invoke(*result, m_Visitor);
unwrapped.end();
}
else
{
unwrapped.unrecognized(m_Parser.content());
}
}

void parse_function()
{
auto& unwrapped = unwrap_visitor(m_Visitor);
detail::ResultVisitor<decltype(unwrapped)> visitor{
.visitor = unwrapped,
.content = m_Parser.content()};
std::visit(visitor, m_Parser.parse_function());
}

private:
Visitor m_Visitor;
detail::ParserImpl m_Parser;
};
}

#endif
Loading
Loading