Skip to content

Commit

Permalink
Initial, partial sketch of token_parser.
Browse files Browse the repository at this point in the history
See #202.
  • Loading branch information
tzlaine committed Nov 29, 2024
1 parent 358adf2 commit f00f4df
Show file tree
Hide file tree
Showing 10 changed files with 253 additions and 34 deletions.
62 changes: 36 additions & 26 deletions include/boost/parser/lexer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,22 @@ namespace boost { namespace parser {
detail::token_kind kind_ : 8;
};

#if BOOST_PARSER_DOXYGEN

/** TODO */
template<typename T>
constexpr bool is_token_v = detail::foo;

#else

template<typename T>
constexpr bool is_token_v = false;

template<typename CharType>
constexpr bool is_token_v<token<CharType>> = true;

#endif

#if defined(BOOST_PARSER_TESTING)
template<typename CharType>
std::ostream & operator<<(std::ostream & os, token<CharType> const & token)
Expand Down Expand Up @@ -279,14 +295,6 @@ namespace boost { namespace parser {
}
#endif

// TODO: Actually, this should go in parse.hpp.
/** TODO */
template<typename CharType, typename Attr = none>
struct token_parser
{
// TODO
};

namespace detail {
template<typename TokenSpec>
constexpr parse_spec parse_spec_for()
Expand Down Expand Up @@ -566,7 +574,7 @@ namespace boost { namespace parser {

namespace detail {
template<typename T>
struct wrapper
struct type_wrapper
{
using type = T;
};
Expand Down Expand Up @@ -603,111 +611,111 @@ namespace boost { namespace parser {
case token_parsed_type::signed_char: {
signed char value;
report_error(
wrapper<decltype(value)>{},
type_wrapper<decltype(value)>{},
Spec.radix,
numeric::parse_int<true, Spec.radix, 1, -1>(f, l, value));
return {id, (long long)value};
}
case token_parsed_type::unsigned_char: {
unsigned char value;
report_error(
wrapper<decltype(value)>{},
type_wrapper<decltype(value)>{},
Spec.radix,
numeric::parse_int<false, Spec.radix, 1, -1>(f, l, value));
return {id, (long long)value};
}
case token_parsed_type::short_: {
short value;
report_error(
wrapper<decltype(value)>{},
type_wrapper<decltype(value)>{},
Spec.radix,
numeric::parse_int<true, Spec.radix, 1, -1>(f, l, value));
return {id, (long long)value};
}
case token_parsed_type::unsigned_short: {
unsigned short value;
report_error(
wrapper<decltype(value)>{},
type_wrapper<decltype(value)>{},
Spec.radix,
numeric::parse_int<false, Spec.radix, 1, -1>(f, l, value));
return {id, (long long)value};
}
case token_parsed_type::int_: {
int value;
report_error(
wrapper<decltype(value)>{},
type_wrapper<decltype(value)>{},
Spec.radix,
numeric::parse_int<true, Spec.radix, 1, -1>(f, l, value));
return {id, (long long)value};
}
case token_parsed_type::unsigned_int: {
unsigned int value;
report_error(
wrapper<decltype(value)>{},
type_wrapper<decltype(value)>{},
Spec.radix,
numeric::parse_int<false, Spec.radix, 1, -1>(f, l, value));
return {id, (long long)value};
}
case token_parsed_type::long_: {
long value;
report_error(
wrapper<decltype(value)>{},
type_wrapper<decltype(value)>{},
Spec.radix,
numeric::parse_int<true, Spec.radix, 1, -1>(f, l, value));
return {id, (long long)value};
}
case token_parsed_type::unsigned_long: {
unsigned long value;
report_error(
wrapper<decltype(value)>{},
type_wrapper<decltype(value)>{},
Spec.radix,
numeric::parse_int<false, Spec.radix, 1, -1>(f, l, value));
return {id, (long long)value};
}
case token_parsed_type::long_long: {
long long value;
report_error(
wrapper<decltype(value)>{},
type_wrapper<decltype(value)>{},
Spec.radix,
numeric::parse_int<true, Spec.radix, 1, -1>(f, l, value));
return {id, (long long)value};
}
case token_parsed_type::unsigned_long_long: {
unsigned long long value;
report_error(
wrapper<decltype(value)>{},
type_wrapper<decltype(value)>{},
Spec.radix,
numeric::parse_int<false, Spec.radix, 1, -1>(f, l, value));
return {id, (long long)value};
}
case token_parsed_type::wchar_t_: {
unsigned int value;
report_error(
wrapper<wchar_t>{},
type_wrapper<wchar_t>{},
Spec.radix,
numeric::parse_int<false, Spec.radix, 1, -1>(f, l, value));
return {id, (long long)value};
}
case token_parsed_type::char8_t_: {
unsigned int value;
report_error(
wrapper<char8_t>{},
type_wrapper<char8_t>{},
Spec.radix,
numeric::parse_int<false, Spec.radix, 1, -1>(f, l, value));
return {id, (long long)value};
}
case token_parsed_type::char16_t_: {
unsigned int value;
report_error(
wrapper<char16_t>{},
type_wrapper<char16_t>{},
Spec.radix,
numeric::parse_int<false, Spec.radix, 1, -1>(f, l, value));
return {id, (long long)value};
}
case token_parsed_type::char32_t_: {
unsigned int value;
report_error(
wrapper<char32_t>{},
type_wrapper<char32_t>{},
Spec.radix,
numeric::parse_int<false, Spec.radix, 1, -1>(f, l, value));
return {id, (long long)value};
Expand All @@ -716,23 +724,23 @@ namespace boost { namespace parser {
case token_parsed_type::float_: {
float value;
report_error(
wrapper<decltype(value)>{},
type_wrapper<decltype(value)>{},
0,
numeric::parse_real(f, l, value));
return {id, (long double)value};
}
case token_parsed_type::double_: {
double value;
report_error(
wrapper<decltype(value)>{},
type_wrapper<decltype(value)>{},
0,
numeric::parse_real(f, l, value));
return {id, (long double)value};
}
case token_parsed_type::long_double: {
long double value;
report_error(
wrapper<decltype(value)>{},
type_wrapper<decltype(value)>{},
0,
numeric::parse_real(f, l, value));
return {id, value};
Expand Down Expand Up @@ -1014,4 +1022,6 @@ namespace boost { namespace parser {

}}

#include <boost/parser/token_parser.hpp>

#endif
2 changes: 2 additions & 0 deletions include/boost/parser/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9424,4 +9424,6 @@ namespace boost { namespace parser {
}
}}

#include <boost/parser/token_parser.hpp>

#endif
4 changes: 4 additions & 0 deletions include/boost/parser/parser_fwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,10 @@ namespace boost { namespace parser {
template<typename T>
struct float_parser;

/** TODO */
template<typename AttributeType = void>
struct token_parser;

/** Applies at most one of the parsers in `OrParser`. If `switch_value_`
matches one or more of the values in the parsers in `OrParser`, the
first such parser is applied, and the success or failure and attribute
Expand Down
126 changes: 126 additions & 0 deletions include/boost/parser/token_parser.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// Copyright (C) 2024 T. Zachary Laine
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PARSER_TOKEN_PARSER_HPP
#if defined(BOOST_PARSER_PARSER_HPP) && defined(BOOST_PARSER_LEXER_HPP)
#define BOOST_PARSER_TOKEN_PARSER_HPP

#include <boost/parser/parser_fwd.hpp>
#include <boost/parser/concepts.hpp>
#include <boost/parser/error_handling.hpp>


namespace boost { namespace parser {

namespace detail {
template<typename AttributeType, typename CharType>
std::optional<AttributeType> token_as(token<CharType> tok)
{
if constexpr (std::same_as<AttributeType, nope>) {
return nope{};
} else if constexpr (std::same_as<
AttributeType,
std::basic_string_view<CharType>>) {
if (tok.has_string_view())
return tok.get_string_view();
return std::nullopt;
} else if constexpr (std::is_floating_point_v<AttributeType>) {
if (tok.has_long_double())
return tok.get_long_double();
return std::nullopt;
} else if constexpr (std::is_integral_v<AttributeType>) {
if (tok.has_long_long())
return AttributeType(tok.get_long_long());
return std::nullopt;
} else {
static_assert(
!std::same_as<CharType, CharType>,
"The only attribute types that can be pulled out of a "
"token are no-attribute, floating-point values, or "
"integral values (including charater types).");
}
}
}

#ifndef BOOST_PARSER_DOXYGEN

// TODO: Needs a printer.
template<typename AttributeType>
struct token_parser
{
using attribute_type = std::conditional_t<
std::is_same_v<AttributeType, void>,
detail::nope,
AttributeType>;

constexpr token_parser() {}

template<
typename Iter,
typename Sentinel,
typename Context,
typename SkipParser>
auto call(
Iter & first,
Sentinel last,
Context const & context,
SkipParser const & skip,
detail::flags flags,
bool & success) const -> attribute_type
{
attribute_type retval;
call(first, last, context, skip, flags, success, retval);
return retval;
}

template<
typename Iter,
typename Sentinel,
typename Context,
typename SkipParser,
typename Attribute>
void call(
Iter & first,
Sentinel last,
Context const & context,
SkipParser const & skip,
detail::flags flags,
bool & success,
Attribute & retval) const
{
using value_type = std::remove_cvref_t<decltype(*first)>;
static_assert(
is_token_v<value_type>,
"token_parser can only be used when parsing sequences of "
"tokens.");

[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);

if (first == last) {
success = false;
return;
}
value_type const x = *first;
// TODO: Test for equality with some expectation, if any.
auto opt_attr = detail::token_as<attribute_type>(x);
if (!opt_attr) {
success = false;
return;
}
detail::assign(retval, *opt_attr);
++first;
}
};

#endif

/** TODO */
constexpr parser_interface<token_parser<detail::nope>> tok;

}}

#endif
#endif
5 changes: 4 additions & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ add_test(NAME parser_api COMMAND parser_api)

add_executable(
compile_tests
compile_include_lexer_parser.cpp
compile_include_parser_lexer.cpp
compile_tests_main.cpp
compile_attribute.cpp
compile_seq_attribute.cpp
Expand All @@ -56,7 +58,7 @@ add_executable(
compile_all_t.cpp
)
set_property(TARGET compile_tests PROPERTY CXX_STANDARD ${CXX_STD})
target_link_libraries(compile_tests parser boost)
target_link_libraries(compile_tests parser boost ctre_single_header)

macro(add_test_executable name)
add_executable(${name} ${name}.cpp)
Expand Down Expand Up @@ -102,6 +104,7 @@ add_test_executable(parser_or_permutations_2)
if (CXX_STD GREATER_EQUAL 20)
add_test_executable(lexer)
add_test_executable(lexer_adobe_files)
add_test_executable(lexer_and_parser)
endif()

if (MSVC)
Expand Down
10 changes: 10 additions & 0 deletions test/compile_include_lexer_parser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (C) 2024 T. Zachary Laine
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/parser/config.hpp>
#if BOOST_PARSER_USE_CONCEPTS
#include <boost/parser/lexer.hpp>
#endif
#include <boost/parser/parser.hpp>
9 changes: 9 additions & 0 deletions test/compile_include_parser_lexer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (C) 2024 T. Zachary Laine
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/parser/parser.hpp>
#if BOOST_PARSER_USE_CONCEPTS
#include <boost/parser/lexer.hpp>
#endif
Loading

0 comments on commit f00f4df

Please sign in to comment.