Commit b2272073 authored by Dominik Charousset's avatar Dominik Charousset

Make parser state class public

As part of redesigning the config_value_access API, we have to expose
the parser state class to CAF users.
parent 6f23959e
......@@ -76,8 +76,6 @@ public:
using variant_type = detail::tl_apply_t<types, variant>;
using parse_state = detail::parse_state;
// -- constructors, destructors, and assignment operators --------------------
config_value() = default;
......@@ -238,7 +236,7 @@ struct default_config_value_access {
return x;
}
static void parse_cli(config_value::parse_state& ps, T& x) {
static void parse_cli(string_parser_state& ps, T& x) {
detail::parse(ps, x);
}
};
......@@ -411,7 +409,7 @@ struct select_config_value_access<T, select_config_value_hint::is_integral> {
return x;
}
static void parse_cli(config_value::parse_state& ps, T& x) {
static void parse_cli(string_parser_state& ps, T& x) {
detail::parse(ps, x);
}
};
......@@ -471,7 +469,7 @@ struct select_config_value_access<T, select_config_value_hint::is_list> {
return result;
}
static void parse_cli(config_value::parse_state& ps, T& xs) {
static void parse_cli(string_parser_state& ps, T& xs) {
config_value::dictionary result;
bool has_open_token = ps.consume('[');
do {
......@@ -544,7 +542,7 @@ struct select_config_value_access<T, select_config_value_hint::is_map> {
return std::move(*result);
}
static void parse_cli(config_value::parse_state& ps, map_type& xs) {
static void parse_cli(string_parser_state& ps, map_type& xs) {
detail::parse(ps, xs);
}
......@@ -581,7 +579,7 @@ struct config_value_access<float> {
return x;
}
static inline void parse_cli(config_value::parse_state& ps, float& x) {
static inline void parse_cli(string_parser_state& ps, float& x) {
detail::parse(ps, x);
}
};
......@@ -633,7 +631,7 @@ struct config_value_access<std::tuple<Ts...>> {
return result;
}
static void parse_cli(config_value::parse_state& ps, tuple_type& xs) {
static void parse_cli(string_parser_state& ps, tuple_type& xs) {
rec_parse(ps, xs, detail::int_token<0>(), detail::type_list<Ts...>());
}
......@@ -703,13 +701,13 @@ private:
}
template <int Pos>
static void rec_parse(config_value::parse_state&, tuple_type&,
static void rec_parse(string_parser_state&, tuple_type&,
detail::int_token<Pos>, detail::type_list<>) {
// nop
}
template <int Pos, class U, class... Us>
static void rec_parse(config_value::parse_state& ps, tuple_type& xs,
static void rec_parse(string_parser_state& ps, tuple_type& xs,
detail::int_token<Pos>, detail::type_list<U, Us...>) {
using trait = select_config_value_access_t<U>;
trait::parse_cli(std::get<Pos>(xs));
......
......@@ -25,94 +25,94 @@
#include <utility>
#include <vector>
#include "caf/detail/parser/state.hpp"
#include "caf/detail/squashed_int.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/error.hpp"
#include "caf/fwd.hpp"
#include "caf/none.hpp"
#include "caf/parser_state.hpp"
#include "caf/string_view.hpp"
#include "caf/unit.hpp"
namespace caf {
namespace detail {
using parse_state = parser::state<string_view::iterator>;
// -- boolean type -------------------------------------------------------------
void parse(parse_state& ps, bool& x);
void parse(string_parser_state& ps, bool& x);
// -- signed integer types -----------------------------------------------------
void parse(parse_state& ps, int8_t& x);
void parse(string_parser_state& ps, int8_t& x);
void parse(parse_state& ps, int16_t& x);
void parse(string_parser_state& ps, int16_t& x);
void parse(parse_state& ps, int32_t& x);
void parse(string_parser_state& ps, int32_t& x);
void parse(parse_state& ps, int64_t& x);
void parse(string_parser_state& ps, int64_t& x);
// -- unsigned integer types ---------------------------------------------------
void parse(parse_state& ps, uint8_t& x);
void parse(string_parser_state& ps, uint8_t& x);
void parse(parse_state& ps, uint16_t& x);
void parse(string_parser_state& ps, uint16_t& x);
void parse(parse_state& ps, uint32_t& x);
void parse(string_parser_state& ps, uint32_t& x);
void parse(parse_state& ps, uint64_t& x);
void parse(string_parser_state& ps, uint64_t& x);
// -- non-fixed size integer types ---------------------------------------------
template <class T>
detail::enable_if_t<std::is_integral<T>::value> parse(parse_state& ps, T& x) {
detail::enable_if_t<std::is_integral<T>::value> parse(string_parser_state& ps,
T& x) {
using squashed_type = squashed_int_t<T>;
return parse(ps, reinterpret_cast<squashed_type&>(x));
}
// -- floating point types -----------------------------------------------------
void parse(parse_state& ps, float& x);
void parse(string_parser_state& ps, float& x);
void parse(parse_state& ps, double& x);
void parse(string_parser_state& ps, double& x);
// -- CAF types ----------------------------------------------------------------
void parse(parse_state& ps, timespan& x);
void parse(string_parser_state& ps, timespan& x);
void parse(parse_state& ps, atom_value& x);
void parse(string_parser_state& ps, atom_value& x);
void parse(parse_state& ps, ipv4_address& x);
void parse(string_parser_state& ps, ipv4_address& x);
void parse(parse_state& ps, ipv4_subnet& x);
void parse(string_parser_state& ps, ipv4_subnet& x);
void parse(parse_state& ps, ipv4_endpoint& x);
void parse(string_parser_state& ps, ipv4_endpoint& x);
void parse(parse_state& ps, ipv6_address& x);
void parse(string_parser_state& ps, ipv6_address& x);
void parse(parse_state& ps, ipv6_subnet& x);
void parse(string_parser_state& ps, ipv6_subnet& x);
void parse(parse_state& ps, ipv6_endpoint& x);
void parse(string_parser_state& ps, ipv6_endpoint& x);
void parse(parse_state& ps, uri& x);
void parse(string_parser_state& ps, uri& x);
// -- STL types ----------------------------------------------------------------
void parse(parse_state& ps, std::string& x);
void parse(string_parser_state& ps, std::string& x);
// -- container types ----------------------------------------------------------
void parse_element(parse_state& ps, std::string& x, const char* char_blacklist);
void parse_element(string_parser_state& ps, std::string& x,
const char* char_blacklist);
template <class T>
enable_if_t<!is_pair<T>::value> parse_element(parse_state& ps, T& x,
enable_if_t<!is_pair<T>::value> parse_element(string_parser_state& ps, T& x,
const char*) {
parse(ps, x);
}
template <class First, class Second, size_t N>
void parse_element(parse_state& ps, std::pair<First, Second>& kvp,
void parse_element(string_parser_state& ps, std::pair<First, Second>& kvp,
const char (&char_blacklist)[N]) {
static_assert(N > 0, "empty array");
// TODO: consider to guard the blacklist computation with
......@@ -133,7 +133,7 @@ void parse_element(parse_state& ps, std::pair<First, Second>& kvp,
}
template <class T>
enable_if_tt<is_iterable<T>> parse(parse_state& ps, T& xs) {
enable_if_tt<is_iterable<T>> parse(string_parser_state& ps, T& xs) {
using value_type = deconst_kvp_t<typename T::value_type>;
static constexpr auto is_map_type = is_pair<value_type>::value;
static constexpr auto opening_char = is_map_type ? '{' : '[';
......@@ -181,7 +181,7 @@ enable_if_tt<is_iterable<T>> parse(parse_state& ps, T& xs) {
template <class T>
error parse(string_view str, T& x) {
parse_state ps{str.begin(), str.end()};
string_parser_state ps{str.begin(), str.end()};
parse(ps, x);
if (ps.code == pec::success)
return none;
......
......@@ -26,7 +26,6 @@
#include "caf/config.hpp"
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
......@@ -40,9 +39,8 @@ namespace parser {
/// Reads a number, i.e., on success produces either an `int64_t` or a
/// `double`.
template <class Iterator, class Sentinel, class Consumer>
void read_atom(state<Iterator, Sentinel>& ps, Consumer&& consumer,
bool accept_unquoted = false) {
template <class State, class Consumer>
void read_atom(State& ps, Consumer&& consumer, bool accept_unquoted = false) {
size_t pos = 0;
char buf[11];
memset(buf, 0, sizeof(buf));
......
......@@ -24,7 +24,6 @@
#include "caf/config.hpp"
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
......@@ -37,8 +36,8 @@ namespace detail {
namespace parser {
/// Reads a boolean.
template <class Iterator, class Sentinel, class Consumer>
void read_bool(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
template <class State, class Consumer>
void read_bool(State& ps, Consumer&& consumer) {
bool res = false;
auto g = make_scope_guard([&] {
if (ps.code <= pec::trailing_character)
......
......@@ -26,7 +26,6 @@
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/is_digit.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/parser/sub_ascii.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/optional.hpp"
......@@ -45,8 +44,8 @@ namespace parser {
/// @param consumer Sink for generated values.
/// @param start_value Allows another parser to pre-initialize this parser with
/// the pre-decimal value.
template <class Iterator, class Sentinel, class Consumer, class ValueType>
void read_floating_point(state<Iterator, Sentinel>& ps, Consumer&& consumer,
template <class State, class Consumer, class ValueType>
void read_floating_point(State& ps, Consumer&& consumer,
optional<ValueType> start_value,
bool negative = false) {
// Any exponent larger than 511 always overflows.
......@@ -185,8 +184,8 @@ void read_floating_point(state<Iterator, Sentinel>& ps, Consumer&& consumer,
// clang-format on
}
template <class Iterator, class Sentinel, class Consumer>
void read_floating_point(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
template <class State, class Consumer>
void read_floating_point(State& ps, Consumer&& consumer) {
using consumer_type = typename std::decay<Consumer>::type;
using value_type = typename consumer_type::value_type;
return read_floating_point(ps, consumer, optional<value_type>{});
......
......@@ -58,8 +58,8 @@ namespace parser {
// }]
//
template <class Iterator, class Sentinel, class Consumer>
void read_ini_comment(state<Iterator, Sentinel>& ps, Consumer&&) {
template <class State, class Consumer>
void read_ini_comment(State& ps, Consumer&&) {
start();
term_state(init) {
transition(done, '\n')
......@@ -71,11 +71,11 @@ void read_ini_comment(state<Iterator, Sentinel>& ps, Consumer&&) {
fin();
}
template <class Iterator, class Sentinel, class Consumer>
void read_ini_value(state<Iterator, Sentinel>& ps, Consumer&& consumer);
template <class State, class Consumer>
void read_ini_value(State& ps, Consumer&& consumer);
template <class Iterator, class Sentinel, class Consumer>
void read_ini_list(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
template <class State, class Consumer>
void read_ini_list(State& ps, Consumer&& consumer) {
start();
state(init) {
epsilon(before_value)
......@@ -98,8 +98,8 @@ void read_ini_list(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
fin();
}
template <class Iterator, class Sentinel, class Consumer>
void read_ini_map(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
template <class State, class Consumer>
void read_ini_map(State& ps, Consumer&& consumer) {
std::string key;
auto alnum_or_dash = [](char x) {
return isalnum(x) || x == '-' || x == '_';
......@@ -154,8 +154,8 @@ void read_ini_map(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
// clang-format on
}
template <class Iterator, class Sentinel, class Consumer>
void read_ini_uri(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
template <class State, class Consumer>
void read_ini_uri(State& ps, Consumer&& consumer) {
uri_builder builder;
auto g = make_scope_guard([&] {
if (ps.code <= pec::trailing_character)
......@@ -180,8 +180,8 @@ void read_ini_uri(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
fin();
}
template <class Iterator, class Sentinel, class Consumer>
void read_ini_value(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
template <class State, class Consumer>
void read_ini_value(State& ps, Consumer&& consumer) {
start();
state(init) {
fsm_epsilon(read_string(ps, consumer), done, '"')
......@@ -200,8 +200,8 @@ void read_ini_value(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
}
/// Reads an INI formatted input.
template <class Iterator, class Sentinel, class Consumer>
void read_ini_section(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
template <class State, class Consumer>
void read_ini_section(State& ps, Consumer&& consumer) {
using std::swap;
std::string tmp;
auto alnum = [](char x) { return isalnum(x) || x == '_'; };
......@@ -254,8 +254,8 @@ void read_ini_section(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
/// Reads a nested group, e.g., "[foo.bar]" would consume "[foo.]" in read_ini
/// and then delegate to this function for parsing "bar]".
template <class Iterator, class Sentinel, class Consumer>
void read_nested_group(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
template <class State, class Consumer>
void read_nested_group(State& ps, Consumer&& consumer) {
using std::swap;
std::string key;
auto alnum = [](char x) { return isalnum(x) || x == '_'; };
......@@ -290,8 +290,8 @@ void read_nested_group(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
}
/// Reads an INI formatted input.
template <class Iterator, class Sentinel, class Consumer>
void read_ini(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
template <class State, class Consumer>
void read_ini(State& ps, Consumer&& consumer) {
using std::swap;
std::string tmp{"global"};
auto alnum = [](char x) { return isalnum(x) || x == '_'; };
......
......@@ -25,7 +25,6 @@
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/is_digit.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/parser/sub_ascii.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/ipv4_address.hpp"
......@@ -48,8 +47,8 @@ struct read_ipv4_octet_consumer {
}
};
template <class Iterator, class Sentinel, class Consumer>
void read_ipv4_octet(state<Iterator, Sentinel>& ps, Consumer& consumer) {
template <class State, class Consumer>
void read_ipv4_octet(State& ps, Consumer& consumer) {
uint8_t res = 0;
// Reads the a decimal place.
auto rd_decimal = [&](char c) {
......@@ -72,8 +71,8 @@ void read_ipv4_octet(state<Iterator, Sentinel>& ps, Consumer& consumer) {
/// Reads a number, i.e., on success produces either an `int64_t` or a
/// `double`.
template <class Iterator, class Sentinel, class Consumer>
void read_ipv4_address(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
template <class State, class Consumer>
void read_ipv4_address(State& ps, Consumer&& consumer) {
read_ipv4_octet_consumer f;
auto g = make_scope_guard([&] {
if (ps.code <= pec::trailing_character) {
......
......@@ -27,7 +27,6 @@
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/is_digit.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/parser/sub_ascii.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/ipv4_address.hpp"
......@@ -57,8 +56,8 @@ namespace parser {
// h16 = 1*4HEXDIG
/// Reads 16 (hex) bits of an IPv6 address.
template <class Iterator, class Sentinel, class Consumer>
void read_ipv6_h16(state<Iterator, Sentinel>& ps, Consumer& consumer) {
template <class State, class Consumer>
void read_ipv6_h16(State& ps, Consumer& consumer) {
uint16_t res = 0;
size_t digits = 0;
// Reads the a hexadecimal place.
......@@ -83,8 +82,8 @@ void read_ipv6_h16(state<Iterator, Sentinel>& ps, Consumer& consumer) {
}
/// Reads 16 (hex) or 32 (IPv4 notation) bits of an IPv6 address.
template <class Iterator, class Sentinel, class Consumer>
void read_ipv6_h16_or_l32(state<Iterator, Sentinel>& ps, Consumer& consumer) {
template <class State, class Consumer>
void read_ipv6_h16_or_l32(State& ps, Consumer& consumer) {
enum mode_t { indeterminate, v6_bits, v4_octets };
mode_t mode = indeterminate;
uint16_t hex_res = 0;
......@@ -173,8 +172,8 @@ read_ipv6_address_piece_consumer<F> make_read_ipv6_address_piece_consumer(F f) {
/// Reads a number, i.e., on success produces either an `int64_t` or a
/// `double`.
template <class Iterator, class Sentinel, class Consumer>
void read_ipv6_address(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
template <class State, class Consumer>
void read_ipv6_address(State& ps, Consumer&& consumer) {
// IPv6 allows omitting blocks of zeros, splitting the string into a part
// before the zeros (prefix) and a part after the zeros (suffix). For example,
// ff::1 is 00FF0000000000000000000000000001
......
......@@ -26,7 +26,6 @@
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/is_digit.hpp"
#include "caf/detail/parser/read_floating_point.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/parser/sub_ascii.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
......@@ -41,8 +40,8 @@ namespace parser {
/// Reads a number, i.e., on success produces either an `int64_t` or a
/// `double`.
template <class Iterator, class Sentinel, class Consumer>
void read_number(state<Iterator, Sentinel>& ps, Consumer& consumer) {
template <class State, class Consumer>
void read_number(State& ps, Consumer& consumer) {
// Our result when reading an integer number.
int64_t result = 0;
// Computes the result on success.
......
......@@ -27,7 +27,6 @@
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/read_number.hpp"
#include "caf/detail/parser/read_timespan.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/none.hpp"
#include "caf/optional.hpp"
......@@ -45,9 +44,8 @@ namespace parser {
/// Reads a number or a duration, i.e., on success produces an `int64_t`, a
/// `double`, or a `timespan`.
template <class Iterator, class Sentinel, class Consumer>
void read_number_or_timespan(state<Iterator, Sentinel>& ps,
Consumer& consumer) {
template <class State, class Consumer>
void read_number_or_timespan(State& ps, Consumer& consumer) {
using namespace std::chrono;
struct interim_consumer {
variant<none_t, int64_t, double> interim;
......
......@@ -26,7 +26,6 @@
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/is_digit.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/parser/sub_ascii.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
......@@ -41,8 +40,8 @@ namespace parser {
/// Reads a number, i.e., on success produces either an `int64_t` or a
/// `double`.
template <class Iterator, class Sentinel, class Consumer>
void read_signed_integer(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
template <class State, class Consumer>
void read_signed_integer(State& ps, Consumer&& consumer) {
using consumer_type = typename std::decay<Consumer>::type;
using value_type = typename consumer_type::value_type;
static_assert(std::is_integral<value_type>::value
......
......@@ -23,7 +23,6 @@
#include "caf/config.hpp"
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
......@@ -37,8 +36,8 @@ namespace parser {
/// Reads a quoted or unquoted string. Quoted strings allow escaping, while
/// unquoted strings may only include alphanumeric characters.
template <class Iterator, class Sentinel, class Consumer>
void read_string(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
template <class State, class Consumer>
void read_string(State& ps, Consumer&& consumer) {
std::string res;
auto g = caf::detail::make_scope_guard([&] {
if (ps.code <= pec::trailing_character)
......
......@@ -24,7 +24,6 @@
#include "caf/config.hpp"
#include "caf/detail/parser/read_signed_integer.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/optional.hpp"
#include "caf/pec.hpp"
......@@ -39,8 +38,8 @@ namespace detail {
namespace parser {
/// Reads a timespan.
template <class Iterator, class Sentinel, class Consumer>
void read_timespan(state<Iterator, Sentinel>& ps, Consumer&& consumer,
template <class State, class Consumer>
void read_timespan(State& ps, Consumer&& consumer,
optional<int64_t> num = none) {
using namespace std::chrono;
struct interim_consumer {
......
......@@ -26,7 +26,6 @@
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/is_digit.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/parser/sub_ascii.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
......@@ -41,8 +40,8 @@ namespace parser {
/// Reads a number, i.e., on success produces either an `int64_t` or a
/// `double`.
template <class Iterator, class Sentinel, class Consumer>
void read_unsigned_integer(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
template <class State, class Consumer>
void read_unsigned_integer(State& ps, Consumer&& consumer) {
using consumer_type = typename std::decay<Consumer>::type;
using value_type = typename consumer_type::value_type;
static_assert(std::is_integral<value_type>::value
......
......@@ -22,7 +22,6 @@
#include "caf/detail/parser/add_ascii.hpp"
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/read_ipv6_address.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
#include "caf/uri.hpp"
......@@ -47,8 +46,8 @@ namespace parser {
// generate ranges for the subcomponents. URIs can't have linebreaks, so we can
// safely keep track of the position by looking at the column.
template <class Iterator, class Sentinel>
void read_uri_percent_encoded(state<Iterator, Sentinel>& ps, std::string& str) {
template <class State>
void read_uri_percent_encoded(State& ps, std::string& str) {
uint8_t char_code = 0;
auto g = make_scope_guard([&] {
if (ps.code <= pec::trailing_character)
......@@ -75,8 +74,8 @@ inline bool uri_unprotected_char(char c) {
transition(next_state, uri_unprotected_char, dest += ch) \
fsm_transition(read_uri_percent_encoded(ps, dest), next_state, '%')
template <class Iterator, class Sentinel, class Consumer>
void read_uri_query(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
template <class State, class Consumer>
void read_uri_query(State& ps, Consumer&& consumer) {
// Local variables.
uri::query_map result;
std::string key;
......@@ -113,8 +112,8 @@ void read_uri_query(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
fin();
}
template <class Iterator, class Sentinel, class Consumer>
void read_uri(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
template <class State, class Consumer>
void read_uri(State& ps, Consumer&& consumer) {
// Local variables.
std::string str;
uint16_t port = 0;
......
......@@ -56,6 +56,8 @@ template <class> struct timeout_definition;
template <class, class> class stream_stage;
template <class Iterator, class Sentinel = Iterator> struct parser_state;
// -- 3 param templates --------------------------------------------------------
template <class, class, int> class actor_cast_access;
......
......@@ -59,10 +59,10 @@ expected<config_value> parse_impl(T* ptr, string_view str) {
return parse_impl(&tmp, str);
}
using trait = select_config_value_access_t<T>;
config_value::parse_state ps{str.begin(), str.end()};
string_parser_state ps{str.begin(), str.end()};
trait::parse_cli(ps, *ptr);
if (ps.code != pec::success)
return ps.make_error(ps.code);
return make_error(ps);
return config_value{trait::convert(*ptr)};
}
......
......@@ -5,7 +5,7 @@
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
......@@ -21,30 +21,39 @@
#include <cctype>
#include <cstdint>
#include "caf/error.hpp"
#include "caf/fwd.hpp"
#include "caf/pec.hpp"
#include "caf/string_view.hpp"
namespace caf {
namespace detail {
namespace parser {
template <class Iterator, class Sentinel = Iterator>
struct state {
/// Stores all informations necessary for implementing an FSM-based parser.
template <class Iterator, class Sentinel>
struct parser_state {
/// Current position of the parser.
Iterator i;
/// End-of-input marker.
Sentinel e;
/// Current state of the parser.
pec code;
/// Current line in the input.
int32_t line;
/// Position in the current line.
int32_t column;
state() noexcept : i(), e(), code(pec::success), line(1), column(1) {
parser_state() noexcept : i(), e(), code(pec::success), line(1), column(1) {
// nop
}
explicit state(Iterator first) noexcept : state() {
explicit parser_state(Iterator first) noexcept : parser_state() {
i = first;
}
state(Iterator first, Sentinel last) noexcept : state() {
parser_state(Iterator first, Sentinel last) noexcept : parser_state() {
i = first;
e = last;
}
......@@ -91,13 +100,17 @@ struct state {
}
return false;
}
error make_error(pec code) {
return caf::make_error(code, static_cast<size_t>(line),
static_cast<size_t>(column));
}
};
} // namespace parser
} // namespace detail
/// Returns an error object from the current code in `ps` as well as its
/// current position.
template <class Iterator, class Sentinel>
auto make_error(const parser_state<Iterator, Sentinel>& ps)
-> decltype(make_error(ps.code, ps.line, ps.column)) {
return make_error(ps.code, ps.line, ps.column);
}
/// Specialization for parsers operating on string views.
using string_parser_state = parser_state<string_view::iterator>;
} // namespace caf
......@@ -74,7 +74,7 @@ error make_error(pec code);
/// Returns an error object from given error code with additional context
/// information for where the parser stopped in the input.
error make_error(pec code, size_t line, size_t column);
error make_error(pec code, int32_t line, int32_t column);
/// Returns an error object from given error code with additional context
/// information for where the parser stopped in the argument.
......
......@@ -22,7 +22,6 @@
#include <vector>
#include "caf/detail/comparable.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/unordered_flat_map.hpp"
#include "caf/fwd.hpp"
#include "caf/intrusive_ptr.hpp"
......
......@@ -494,8 +494,7 @@ error actor_system_config::parse_config(std::istream& source,
if (!source)
return make_error(sec::runtime_error, "source stream invalid");
detail::ini_consumer consumer{opts, result};
detail::parser::state<ini_iter, ini_sentinel> res;
res.i = ini_iter{&source};
parser_state<ini_iter, ini_sentinel> res{ini_iter{&source}};
detail::parser::read_ini(res, consumer);
if (res.i != res.e)
return make_error(res.code, res.line, res.column);
......
......@@ -26,7 +26,9 @@
#include "caf/detail/parser/read_ini.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/expected.hpp"
#include "caf/parser_state.hpp"
#include "caf/pec.hpp"
#include "caf/string_view.hpp"
namespace caf {
......@@ -66,10 +68,8 @@ expected<config_value> config_value::parse(string_view::iterator first,
if (++i == last)
return make_error(pec::unexpected_eof);
// Dispatch to parser.
parser::state<string_view::iterator> res;
detail::ini_value_consumer f;
res.i = i;
res.e = last;
string_parser_state res{i, last};
parser::read_ini_value(res, f);
if (res.code == pec::success)
return std::move(f.result);
......
......@@ -39,7 +39,7 @@
#include "caf/uri_builder.hpp"
#define PARSE_IMPL(type, parser_name) \
void parse(parse_state& ps, type& x) { \
void parse(string_parser_state& ps, type& x) { \
parser::read_##parser_name(ps, make_consumer(x)); \
}
......@@ -55,7 +55,7 @@ struct literal {
}
};
void parse(parse_state& ps, literal& x) {
void parse(string_parser_state& ps, literal& x) {
CAF_ASSERT(x.str.size() > 0);
if (ps.current() != x.str[0]) {
ps.code = pec::unexpected_character;
......@@ -72,12 +72,12 @@ void parse(parse_state& ps, literal& x) {
ps.code = ps.at_end() ? pec::success : pec::trailing_character;
}
void parse_sequence(parse_state&) {
void parse_sequence(string_parser_state&) {
// End of recursion.
}
template <class T, class... Ts>
void parse_sequence(parse_state& ps, T&& x, Ts&&... xs) {
void parse_sequence(string_parser_state& ps, T&& x, Ts&&... xs) {
parse(ps, x);
// TODO: use `if constexpr` when switching to C++17
if (sizeof...(Ts) > 0) {
......@@ -111,11 +111,11 @@ PARSE_IMPL(double, floating_point)
PARSE_IMPL(timespan, timespan)
void parse(parse_state& ps, atom_value& x) {
void parse(string_parser_state& ps, atom_value& x) {
parser::read_atom(ps, make_consumer(x), true);
}
void parse(parse_state& ps, uri& x) {
void parse(string_parser_state& ps, uri& x) {
uri_builder builder;
if (ps.consume('<')) {
parser::read_uri(ps, builder);
......@@ -126,7 +126,7 @@ void parse(parse_state& ps, uri& x) {
return;
}
} else {
read_uri(ps, builder);
parser::read_uri(ps, builder);
}
if (ps.code <= pec::trailing_character)
x = builder.make();
......@@ -134,7 +134,7 @@ void parse(parse_state& ps, uri& x) {
PARSE_IMPL(ipv4_address, ipv4_address)
void parse(parse_state& ps, ipv4_subnet& x) {
void parse(string_parser_state& ps, ipv4_subnet& x) {
ipv4_address addr;
uint8_t prefix_length;
parse_sequence(ps, addr, literal{"/"}, prefix_length);
......@@ -147,7 +147,7 @@ void parse(parse_state& ps, ipv4_subnet& x) {
}
}
void parse(parse_state& ps, ipv4_endpoint& x) {
void parse(string_parser_state& ps, ipv4_endpoint& x) {
ipv4_address addr;
uint16_t port;
parse_sequence(ps, addr, literal{":"}, port);
......@@ -157,7 +157,7 @@ void parse(parse_state& ps, ipv4_endpoint& x) {
PARSE_IMPL(ipv6_address, ipv6_address)
void parse(parse_state& ps, ipv6_subnet& x) {
void parse(string_parser_state& ps, ipv6_subnet& x) {
// TODO: this algorithm is currently not one-pass. The reason we need to
// check whether the input is a valid ipv4_subnet first is that "1.2.3.0" is
// a valid IPv6 address, but "1.2.3.0/16" results in the wrong subnet when
......@@ -185,7 +185,7 @@ void parse(parse_state& ps, ipv6_subnet& x) {
}
}
void parse(parse_state& ps, ipv6_endpoint& x) {
void parse(string_parser_state& ps, ipv6_endpoint& x) {
ipv6_address addr;
uint16_t port;
if (ps.consume('[')) {
......@@ -200,7 +200,7 @@ void parse(parse_state& ps, ipv6_endpoint& x) {
x = ipv6_endpoint{addr, port};
}
void parse(parse_state& ps, std::string& x) {
void parse(string_parser_state& ps, std::string& x) {
ps.skip_whitespaces();
if (ps.current() == '"') {
parser::read_string(ps, make_consumer(x));
......@@ -213,7 +213,7 @@ void parse(parse_state& ps, std::string& x) {
ps.code = pec::success;
}
void parse_element(parse_state& ps, std::string& x,
void parse_element(string_parser_state& ps, std::string& x,
const char* char_blacklist) {
ps.skip_whitespaces();
if (ps.current() == '"') {
......
......@@ -21,6 +21,7 @@
#include "caf/detail/network_order.hpp"
#include "caf/detail/parser/read_ipv4_address.hpp"
#include "caf/error.hpp"
#include "caf/parser_state.hpp"
#include "caf/pec.hpp"
#include "caf/string_view.hpp"
......@@ -89,8 +90,8 @@ std::string to_string(const ipv4_address& x) {
error parse(string_view str, ipv4_address& dest) {
using namespace detail;
parser::state<string_view::iterator> res{str.begin(), str.end()};
ipv4_address_consumer f{dest};
string_parser_state res{str.begin(), str.end()};
parser::read_ipv4_address(res, f);
if (res.code == pec::success)
return none;
......
......@@ -23,6 +23,7 @@
#include "caf/detail/parser/read_ipv6_address.hpp"
#include "caf/error.hpp"
#include "caf/ipv4_address.hpp"
#include "caf/parser_state.hpp"
#include "caf/pec.hpp"
#include "caf/string_view.hpp"
......@@ -212,8 +213,8 @@ std::string to_string(ipv6_address x) {
error parse(string_view str, ipv6_address& dest) {
using namespace detail;
parser::state<string_view::iterator> res{str.begin(), str.end()};
ipv6_address_consumer f{dest};
string_parser_state res{str.begin(), str.end()};
parser::read_ipv6_address(res, f);
if (res.code == pec::success)
return none;
......
......@@ -54,7 +54,7 @@ error make_error(pec code) {
return {static_cast<uint8_t>(code), atom("parser")};
}
error make_error(pec code, size_t line, size_t column) {
error make_error(pec code, int32_t line, int32_t column) {
config_value::dictionary context;
context["line"] = line;
context["column"] = column;
......
......@@ -146,12 +146,11 @@ std::string to_string(const uri::authority_type& x) {
}
error parse(string_view str, uri& dest) {
detail::parse_state ps{str.begin(), str.end()};
string_parser_state ps{str.begin(), str.end()};
parse(ps, dest);
if (ps.code == pec::success)
return none;
return make_error(ps.code, static_cast<size_t>(ps.line),
static_cast<size_t>(ps.column));
return make_error(ps);
}
expected<uri> make_uri(string_view str) {
......
......@@ -33,7 +33,7 @@ using ls = std::vector<std::string>;
namespace {
const char test_ini[] = R"(
constexpr const string_view test_ini = R"(
is_server=true
port=4242
nodes=["sun", "venus", ]
......@@ -44,7 +44,7 @@ file-name = "foobar.ini" ; our file name
impl = 'foo';some atom
)";
const char test_ini2[] = R"(
constexpr const string_view test_ini2 = R"(
is_server = true
logger = {
file-name = "foobar.ini"
......@@ -58,7 +58,6 @@ nodes = ["sun", "venus"]
)";
struct fixture {
detail::parser::state<std::string::const_iterator> res;
config_option_set options;
settings config;
......@@ -78,20 +77,18 @@ struct fixture {
CAF_TEST_FIXTURE_SCOPE(ini_consumer_tests, fixture)
CAF_TEST(ini_value_consumer) {
std::string str = R"("hello world")";
string_view str = R"("hello world")";
detail::ini_value_consumer consumer;
res.i = str.begin();
res.e = str.end();
string_parser_state res{str.begin(), str.end()};
detail::parser::read_ini_value(res, consumer);
CAF_CHECK_EQUAL(res.code, pec::success);
CAF_CHECK_EQUAL(get<string>(consumer.result), "hello world");
}
CAF_TEST(ini_consumer) {
std::string str = test_ini;
string_view str = test_ini;
detail::ini_consumer consumer{options, config};
res.i = str.begin();
res.e = str.end();
string_parser_state res{str.begin(), str.end()};
detail::parser::read_ini(res, consumer);
CAF_CHECK_EQUAL(res.code, pec::success);
CAF_CHECK_EQUAL(get<bool>(config, "is_server"), true);
......@@ -103,12 +100,11 @@ CAF_TEST(ini_consumer) {
}
CAF_TEST(simplified syntax) {
std::string str = test_ini;
string_view str = test_ini;
CAF_MESSAGE("read test_ini");
{
detail::ini_consumer consumer{options, config};
res.i = str.begin();
res.e = str.end();
string_parser_state res{str.begin(), str.end()};
detail::parser::read_ini(res, consumer);
CAF_CHECK_EQUAL(res.code, pec::success);
}
......@@ -117,8 +113,7 @@ CAF_TEST(simplified syntax) {
CAF_MESSAGE("read test_ini2");
{
detail::ini_consumer consumer{options, config2};
res.i = str.begin();
res.e = str.end();
string_parser_state res{str.begin(), str.end()};
detail::parser::read_ini(res, consumer);
CAF_CHECK_EQUAL(res.code, pec::success);
}
......
......@@ -61,11 +61,11 @@ timespan operator"" _h(unsigned long long x) {
template <class T>
expected<T> read(string_view str) {
T result;
detail::parse_state ps{str.begin(), str.end()};
string_parser_state ps{str.begin(), str.end()};
detail::parse(ps, result);
if (ps.code == pec::success)
return result;
return make_error(ps.code, ps.line, ps.column);
return make_error(ps);
}
} // namespace
......
......@@ -24,6 +24,8 @@
#include <string>
#include "caf/parser_state.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
using namespace caf;
......@@ -40,11 +42,9 @@ struct atom_parser_consumer {
using res_t = variant<pec, atom_value>;
struct atom_parser {
res_t operator()(std::string str) {
detail::parser::state<std::string::iterator> res;
res_t operator()(string_view str) {
atom_parser_consumer f;
res.i = str.begin();
res.e = str.end();
string_parser_state res{str.begin(), str.end()};
detail::parser::read_atom(res, f);
if (res.code == pec::success)
return f.x;
......
......@@ -24,6 +24,8 @@
#include <string>
#include "caf/parser_state.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
using namespace caf;
......@@ -40,11 +42,9 @@ struct bool_parser_consumer {
using res_t = variant<pec, bool>;
struct bool_parser {
res_t operator()(std::string str) {
detail::parser::state<std::string::iterator> res;
res_t operator()(string_view str) {
bool_parser_consumer f;
res.i = str.begin();
res.e = str.end();
string_parser_state res{str.begin(), str.end()};
detail::parser::read_bool(res, f);
if (res.code == pec::success)
return f.x;
......
......@@ -24,8 +24,9 @@
#include <string>
#include "caf/detail/parser/state.hpp"
#include "caf/pec.hpp"
#include "caf/parser_state.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
using namespace caf;
......@@ -43,7 +44,7 @@ struct double_consumer {
optional<double> read(string_view str) {
double_consumer consumer;
detail::parser::state<string_view::iterator> ps{str.begin(), str.end()};
string_parser_state ps{str.begin(), str.end()};
detail::parser::read_floating_point(ps, consumer);
if (ps.code != pec::success)
return none;
......
......@@ -25,6 +25,11 @@
#include <string>
#include <vector>
#include "caf/config_value.hpp"
#include "caf/parser_state.hpp"
#include "caf/pec.hpp"
#include "caf/string_view.hpp"
using namespace caf;
namespace {
......@@ -85,11 +90,9 @@ struct ini_consumer {
};
struct fixture {
expected<log_type> parse(std::string str, bool expect_success = true) {
detail::parser::state<std::string::iterator> res;
expected<log_type> parse(string_view str, bool expect_success = true) {
test_consumer f;
res.i = str.begin();
res.e = str.end();
string_parser_state res{str.begin(), str.end()};
detail::parser::read_ini(res, f);
if ((res.code == pec::success) != expect_success) {
CAF_MESSAGE("unexpected parser result state: " << res.code);
......@@ -105,7 +108,7 @@ log_type make_log(Ts&&... xs) {
}
// Tests basic functionality.
const auto ini0 = R"(
constexpr const string_view ini0 = R"(
[1group]
1value=321
[_foo]
......@@ -204,7 +207,7 @@ const auto ini0_log = make_log(
// clang-format on
// Tests nested parameters.
const auto ini1 = R"(
constexpr const string_view ini1 = R"(
foo {
bar = {
value1 = 1
......@@ -241,11 +244,11 @@ const auto ini1_log = make_log(
);
// clang-format on
const auto ini2 = "#";
constexpr const string_view ini2 = "#";
const auto ini2_log = make_log();
const auto ini3 = "; foobar\n!";
constexpr const string_view ini3 = "; foobar\n!";
const auto ini3_log = make_log();
......
......@@ -27,7 +27,9 @@
#include "caf/detail/parser/add_ascii.hpp"
#include "caf/detail/parser/sub_ascii.hpp"
#include "caf/expected.hpp"
#include "caf/parser_state.hpp"
#include "caf/pec.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
using namespace caf;
......@@ -67,11 +69,9 @@ bool operator==(const res_t& x, const res_t& y) {
}
struct numbers_parser {
res_t operator()(std::string str) {
detail::parser::state<std::string::iterator> res;
res_t operator()(string_view str) {
numbers_parser_consumer f;
res.i = str.begin();
res.e = str.end();
string_parser_state res{str.begin(), str.end()};
detail::parser::read_number(res, f);
if (res.code == pec::success)
return f.x;
......
......@@ -24,6 +24,8 @@
#include <string>
#include "caf/parser_state.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
using namespace caf;
......@@ -68,11 +70,9 @@ bool operator==(const res_t& x, const res_t& y) {
}
struct number_or_timespan_parser {
res_t operator()(std::string str) {
detail::parser::state<std::string::iterator> res;
res_t operator()(string_view str) {
number_or_timespan_parser_consumer f;
res.i = str.begin();
res.e = str.end();
string_parser_state res{str.begin(), str.end()};
detail::parser::read_number_or_timespan(res, f);
if (res.code == pec::success)
return f.x;
......
......@@ -22,8 +22,9 @@
#include "caf/test/dsl.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/parser_state.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
using namespace caf;
......@@ -43,7 +44,7 @@ struct signed_integer_consumer {
template <class T>
optional<T> read(string_view str) {
signed_integer_consumer<T> consumer;
detail::parser::state<string_view::iterator> ps{str.begin(), str.end()};
string_parser_state ps{str.begin(), str.end()};
detail::parser::read_signed_integer(ps, consumer);
if (ps.code != pec::success)
return none;
......@@ -53,7 +54,7 @@ optional<T> read(string_view str) {
template <class T>
bool underflow(string_view str) {
signed_integer_consumer<T> consumer;
detail::parser::state<string_view::iterator> ps{str.begin(), str.end()};
string_parser_state ps{str.begin(), str.end()};
detail::parser::read_signed_integer(ps, consumer);
return ps.code == pec::integer_underflow;
}
......@@ -61,7 +62,7 @@ bool underflow(string_view str) {
template <class T>
bool overflow(string_view str) {
signed_integer_consumer<T> consumer;
detail::parser::state<string_view::iterator> ps{str.begin(), str.end()};
string_parser_state ps{str.begin(), str.end()};
detail::parser::read_signed_integer(ps, consumer);
return ps.code == pec::integer_overflow;
}
......
......@@ -24,6 +24,8 @@
#include <string>
#include "caf/parser_state.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
using namespace caf;
......@@ -40,11 +42,9 @@ struct string_parser_consumer {
using res_t = variant<pec, std::string>;
struct string_parser {
res_t operator()(std::string str) {
detail::parser::state<std::string::iterator> res;
res_t operator()(string_view str) {
string_parser_consumer f;
res.i = str.begin();
res.e = str.end();
string_parser_state res{str.begin(), str.end()};
detail::parser::read_string(res, f);
if (res.code == pec::success)
return f.x;
......
......@@ -24,6 +24,10 @@
#include <chrono>
#include "caf/parser_state.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
using namespace caf;
namespace {
......@@ -62,7 +66,7 @@ struct timespan_consumer {
optional<timespan> read(string_view str) {
timespan_consumer consumer;
detail::parser::state<string_view::iterator> ps{str.begin(), str.end()};
string_parser_state ps{str.begin(), str.end()};
detail::parser::read_timespan(ps, consumer);
if (ps.code != pec::success)
return none;
......
......@@ -22,8 +22,9 @@
#include "caf/test/dsl.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/parser_state.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
using namespace caf;
......@@ -43,7 +44,7 @@ struct unsigned_integer_consumer {
template <class T>
optional<T> read(string_view str) {
unsigned_integer_consumer<T> consumer;
detail::parser::state<string_view::iterator> ps{str.begin(), str.end()};
string_parser_state ps{str.begin(), str.end()};
detail::parser::read_unsigned_integer(ps, consumer);
if (ps.code != pec::success)
return none;
......@@ -53,7 +54,7 @@ optional<T> read(string_view str) {
template <class T>
bool overflow(string_view str) {
unsigned_integer_consumer<T> consumer;
detail::parser::state<string_view::iterator> ps{str.begin(), str.end()};
string_parser_state ps{str.begin(), str.end()};
detail::parser::read_unsigned_integer(ps, consumer);
return ps.code == pec::integer_overflow;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment