mirror of
https://github.com/matrix-construct/construct
synced 2024-11-25 16:22:35 +01:00
ircd::spirit: Split into headers; move into directory; reorg definitions.
This commit is contained in:
parent
26f99b8ccc
commit
5104e284cb
6 changed files with 765 additions and 680 deletions
|
@ -1,7 +1,7 @@
|
||||||
// Matrix Construct
|
// The Construct
|
||||||
//
|
//
|
||||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
// Copyright (C) The Construct Developers, Authors & Contributors
|
||||||
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
// Copyright (C) 2016-2020 Jason Volk <jason@zemos.net>
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -55,156 +55,10 @@
|
||||||
#pragma clang attribute pop
|
#pragma clang attribute pop
|
||||||
#pragma clang attribute pop
|
#pragma clang attribute pop
|
||||||
|
|
||||||
namespace ircd {
|
#include <ircd/spirit/spirit.h>
|
||||||
namespace spirit
|
#include <ircd/spirit/expectation_failure.h>
|
||||||
__attribute__((visibility("default")))
|
#include <ircd/spirit/parse.h>
|
||||||
{
|
#include <ircd/spirit/generate.h>
|
||||||
template<class parent_error> struct expectation_failure;
|
|
||||||
|
|
||||||
IRCD_EXCEPTION(ircd::error, error);
|
|
||||||
IRCD_EXCEPTION(error, generator_error);
|
|
||||||
IRCD_EXCEPTION(generator_error, buffer_overrun);
|
|
||||||
}}
|
|
||||||
|
|
||||||
namespace ircd {
|
|
||||||
namespace spirit
|
|
||||||
__attribute__((visibility("internal")))
|
|
||||||
{
|
|
||||||
namespace phx = boost::phoenix;
|
|
||||||
namespace fusion = boost::fusion;
|
|
||||||
namespace spirit = boost::spirit;
|
|
||||||
namespace ascii = spirit::ascii;
|
|
||||||
namespace karma = spirit::karma;
|
|
||||||
namespace qi = spirit::qi;
|
|
||||||
|
|
||||||
using _val_type = phx::actor<spirit::attribute<0>>;
|
|
||||||
using _r0_type = phx::actor<spirit::attribute<0>>;
|
|
||||||
using _r1_type = phx::actor<spirit::attribute<1>>;
|
|
||||||
using _r2_type = phx::actor<spirit::attribute<2>>;
|
|
||||||
using _r3_type = phx::actor<spirit::attribute<3>>;
|
|
||||||
|
|
||||||
using spirit::unused_type;
|
|
||||||
using spirit::auto_;
|
|
||||||
using spirit::_pass;
|
|
||||||
using spirit::_val;
|
|
||||||
|
|
||||||
using qi::locals;
|
|
||||||
using qi::_a;
|
|
||||||
using qi::_a_type;
|
|
||||||
using qi::_r1_type;
|
|
||||||
using qi::raw;
|
|
||||||
using qi::omit;
|
|
||||||
using qi::matches;
|
|
||||||
using qi::hold;
|
|
||||||
using qi::eoi;
|
|
||||||
using qi::eps;
|
|
||||||
using qi::expect;
|
|
||||||
using qi::attr;
|
|
||||||
using qi::attr_cast;
|
|
||||||
using qi::repeat;
|
|
||||||
using qi::lit;
|
|
||||||
using qi::char_;
|
|
||||||
using qi::byte_;
|
|
||||||
using qi::string;
|
|
||||||
using qi::short_;
|
|
||||||
using qi::ushort_;
|
|
||||||
using qi::word;
|
|
||||||
using qi::big_word;
|
|
||||||
using qi::little_word;
|
|
||||||
using qi::int_;
|
|
||||||
using qi::uint_;
|
|
||||||
using qi::dword;
|
|
||||||
using qi::big_dword;
|
|
||||||
using qi::little_dword;
|
|
||||||
using qi::long_;
|
|
||||||
using qi::ulong_;
|
|
||||||
using qi::qword;
|
|
||||||
using qi::big_qword;
|
|
||||||
using qi::little_qword;
|
|
||||||
using qi::float_;
|
|
||||||
using qi::bin_float;
|
|
||||||
using qi::big_bin_float;
|
|
||||||
using qi::little_bin_float;
|
|
||||||
using qi::double_;
|
|
||||||
using qi::bin_double;
|
|
||||||
using qi::big_bin_double;
|
|
||||||
using qi::little_bin_double;
|
|
||||||
using spirit::repository::qi::seek;
|
|
||||||
|
|
||||||
using karma::lit;
|
|
||||||
using karma::char_;
|
|
||||||
using karma::long_;
|
|
||||||
using karma::double_;
|
|
||||||
using karma::bool_;
|
|
||||||
using karma::eps;
|
|
||||||
using karma::attr_cast;
|
|
||||||
using karma::maxwidth;
|
|
||||||
using karma::buffer;
|
|
||||||
using karma::skip;
|
|
||||||
|
|
||||||
using prop_mask = mpl_::int_
|
|
||||||
<
|
|
||||||
karma::generator_properties::no_properties
|
|
||||||
| karma::generator_properties::buffering
|
|
||||||
| karma::generator_properties::counting
|
|
||||||
| karma::generator_properties::tracking
|
|
||||||
| karma::generator_properties::disabling
|
|
||||||
>;
|
|
||||||
|
|
||||||
using sink_type = karma::detail::output_iterator<char *, prop_mask, unused_type>;
|
|
||||||
|
|
||||||
template<size_t idx,
|
|
||||||
class semantic_context>
|
|
||||||
auto &
|
|
||||||
attr_at(semantic_context&&);
|
|
||||||
|
|
||||||
template<size_t idx,
|
|
||||||
class semantic_context>
|
|
||||||
auto &
|
|
||||||
local_at(semantic_context&&);
|
|
||||||
}}
|
|
||||||
|
|
||||||
namespace ircd::spirit::local
|
|
||||||
{
|
|
||||||
using qi::_0;
|
|
||||||
using qi::_1;
|
|
||||||
using qi::_2;
|
|
||||||
using qi::_3;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ircd {
|
|
||||||
namespace spirit
|
|
||||||
__attribute__((visibility("default")))
|
|
||||||
{
|
|
||||||
// parse.cc
|
|
||||||
extern thread_local char rule_buffer[64];
|
|
||||||
extern thread_local char generator_buffer[8][64_KiB];
|
|
||||||
extern thread_local struct generator_state *generator_state;
|
|
||||||
}}
|
|
||||||
|
|
||||||
namespace ircd {
|
|
||||||
namespace spirit
|
|
||||||
__attribute__((visibility("internal")))
|
|
||||||
{
|
|
||||||
struct substring_view;
|
|
||||||
struct custom_parser;
|
|
||||||
BOOST_SPIRIT_TERMINAL(custom);
|
|
||||||
|
|
||||||
template<class gen,
|
|
||||||
class... attr>
|
|
||||||
bool parse(const char *&start, const char *const &stop, gen&&, attr&&...);
|
|
||||||
|
|
||||||
template<class parent_error,
|
|
||||||
size_t error_show_max = 48,
|
|
||||||
class gen,
|
|
||||||
class... attr>
|
|
||||||
bool parse(const char *&start, const char *const &stop, gen&&, attr&&...);
|
|
||||||
|
|
||||||
template<bool truncation = false,
|
|
||||||
class gen,
|
|
||||||
class... attr>
|
|
||||||
bool generate(mutable_buffer &out, gen&&, attr&&...);
|
|
||||||
}}
|
|
||||||
|
|
||||||
namespace ircd
|
namespace ircd
|
||||||
{
|
{
|
||||||
|
@ -212,526 +66,4 @@ namespace ircd
|
||||||
using spirit::parse;
|
using spirit::parse;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace boost {
|
#endif HAVE_IRCD_SPIRIT_H
|
||||||
namespace spirit
|
|
||||||
__attribute__((visibility("internal")))
|
|
||||||
{
|
|
||||||
namespace qi
|
|
||||||
{
|
|
||||||
template<class modifiers>
|
|
||||||
struct make_primitive<ircd::spirit::tag::custom, modifiers>;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct use_terminal<qi::domain, ircd::spirit::tag::custom>
|
|
||||||
:mpl::true_
|
|
||||||
{};
|
|
||||||
}}
|
|
||||||
|
|
||||||
struct [[gnu::visibility("internal")]]
|
|
||||||
ircd::spirit::custom_parser
|
|
||||||
:qi::primitive_parser<custom_parser>
|
|
||||||
{
|
|
||||||
template<class context,
|
|
||||||
class iterator>
|
|
||||||
struct attribute
|
|
||||||
{
|
|
||||||
using type = iterator;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class context>
|
|
||||||
boost::spirit::info what(context &) const
|
|
||||||
{
|
|
||||||
return boost::spirit::info("custom");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class iterator,
|
|
||||||
class context,
|
|
||||||
class skipper,
|
|
||||||
class attr>
|
|
||||||
bool parse(iterator &, const iterator &, context &, const skipper &, attr &) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class modifiers>
|
|
||||||
struct [[gnu::visibility("internal")]]
|
|
||||||
boost::spirit::qi::make_primitive<ircd::spirit::tag::custom, modifiers>
|
|
||||||
{
|
|
||||||
using result_type = ircd::spirit::custom_parser;
|
|
||||||
|
|
||||||
result_type operator()(unused_type, unused_type) const
|
|
||||||
{
|
|
||||||
return result_type{};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ircd::spirit::substring_view
|
|
||||||
:ircd::string_view
|
|
||||||
{
|
|
||||||
using _iterator = boost::spirit::karma::detail::indirect_iterator<const char *>;
|
|
||||||
using _iterator_range = boost::iterator_range<_iterator>;
|
|
||||||
|
|
||||||
using ircd::string_view::string_view;
|
|
||||||
explicit substring_view(const _iterator_range &range)
|
|
||||||
:ircd::string_view
|
|
||||||
{
|
|
||||||
std::addressof(*range.begin()), std::addressof(*range.end())
|
|
||||||
}
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class parent_error>
|
|
||||||
struct __attribute__((visibility("default")))
|
|
||||||
ircd::spirit::expectation_failure
|
|
||||||
:parent_error
|
|
||||||
{
|
|
||||||
template<class it = const char *>
|
|
||||||
expectation_failure(const qi::expectation_failure<it> &e,
|
|
||||||
const ssize_t &show_max = 64);
|
|
||||||
|
|
||||||
template<class it = const char *>
|
|
||||||
expectation_failure(const qi::expectation_failure<it> &e,
|
|
||||||
const it &start,
|
|
||||||
const ssize_t &show_max = 64);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class parent>
|
|
||||||
template<class it>
|
|
||||||
ircd::spirit::expectation_failure<parent>::expectation_failure(const qi::expectation_failure<it> &e,
|
|
||||||
const ssize_t &show_max)
|
|
||||||
:parent
|
|
||||||
{
|
|
||||||
"Expected %s. You input %zd invalid characters :%s",
|
|
||||||
ircd::string(rule_buffer, e.what_),
|
|
||||||
std::distance(e.first, e.last),
|
|
||||||
string_view{e.first, e.first + std::min(std::distance(e.first, e.last), show_max)}
|
|
||||||
}
|
|
||||||
{}
|
|
||||||
|
|
||||||
template<class parent>
|
|
||||||
template<class it>
|
|
||||||
ircd::spirit::expectation_failure<parent>::expectation_failure(const qi::expectation_failure<it> &e,
|
|
||||||
const it &start,
|
|
||||||
const ssize_t &show_max)
|
|
||||||
:parent
|
|
||||||
{
|
|
||||||
"Expected %s. You input %zd invalid characters somewhere between position %zd and %zd :%s",
|
|
||||||
ircd::string(rule_buffer, e.what_),
|
|
||||||
std::distance(e.first, e.last),
|
|
||||||
std::distance(start, e.first),
|
|
||||||
std::distance(start, e.last),
|
|
||||||
string_view{e.first, e.first + std::min(std::distance(e.first, e.last), show_max)}
|
|
||||||
}
|
|
||||||
{}
|
|
||||||
|
|
||||||
struct [[gnu::visibility("hidden")]]
|
|
||||||
ircd::spirit::generator_state
|
|
||||||
{
|
|
||||||
/// The number of instances stacked behind the current state
|
|
||||||
static uint depth() noexcept;
|
|
||||||
|
|
||||||
/// User's buffer.
|
|
||||||
mutable_buffer &out;
|
|
||||||
|
|
||||||
/// Previous in buffer stack
|
|
||||||
struct generator_state *prev {nullptr};
|
|
||||||
|
|
||||||
/// The number of characters we're storing in buffer
|
|
||||||
uint consumed {0};
|
|
||||||
|
|
||||||
/// The number of characters attempted, which may be larger than
|
|
||||||
/// the buffer capacity indicating an overflow amount.
|
|
||||||
uint generated {0};
|
|
||||||
};
|
|
||||||
|
|
||||||
inline uint
|
|
||||||
ircd::spirit::generator_state::depth()
|
|
||||||
noexcept
|
|
||||||
{
|
|
||||||
uint ret(0);
|
|
||||||
for(auto p(ircd::spirit::generator_state); p; p = p->prev)
|
|
||||||
++ret;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool truncation,
|
|
||||||
class gen,
|
|
||||||
class... attr>
|
|
||||||
[[using gnu: always_inline, gnu_inline]]
|
|
||||||
extern inline bool
|
|
||||||
ircd::spirit::generate(mutable_buffer &out,
|
|
||||||
gen&& g,
|
|
||||||
attr&&... a)
|
|
||||||
|
|
||||||
{
|
|
||||||
const auto max(size(out));
|
|
||||||
const auto start(data(out));
|
|
||||||
struct generator_state state
|
|
||||||
{
|
|
||||||
out
|
|
||||||
};
|
|
||||||
|
|
||||||
const scope_restore _state
|
|
||||||
{
|
|
||||||
generator_state, &state
|
|
||||||
};
|
|
||||||
|
|
||||||
sink_type sink
|
|
||||||
{
|
|
||||||
begin(out)
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto ret
|
|
||||||
{
|
|
||||||
karma::generate(sink, std::forward<gen>(g), std::forward<attr>(a)...)
|
|
||||||
};
|
|
||||||
|
|
||||||
assert(state.generated >= state.consumed);
|
|
||||||
const auto overflow
|
|
||||||
{
|
|
||||||
state.generated - state.consumed
|
|
||||||
};
|
|
||||||
|
|
||||||
if constexpr(truncation)
|
|
||||||
{
|
|
||||||
begin(out) = begin(out) > end(out)? end(out): begin(out);
|
|
||||||
assert(begin(out) <= end(out));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(unlikely(overflow || begin(out) > end(out)))
|
|
||||||
{
|
|
||||||
begin(out) = start;
|
|
||||||
assert(begin(out) <= end(out));
|
|
||||||
|
|
||||||
char pbuf[2][48];
|
|
||||||
throw buffer_overrun
|
|
||||||
{
|
|
||||||
"Insufficient buffer of %s; required at least %s",
|
|
||||||
pretty(pbuf[0], iec(state.consumed)),
|
|
||||||
pretty(pbuf[1], iec(state.generated)),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(begin(out) >= end(out) - max);
|
|
||||||
assert(begin(out) <= end(out));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class parent_error,
|
|
||||||
size_t error_show_max,
|
|
||||||
class gen,
|
|
||||||
class... attr>
|
|
||||||
[[using gnu: always_inline, gnu_inline, artificial]]
|
|
||||||
extern inline bool
|
|
||||||
ircd::spirit::parse(const char *&start,
|
|
||||||
const char *const &stop,
|
|
||||||
gen&& g,
|
|
||||||
attr&&... a)
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return qi::parse(start, stop, std::forward<gen>(g), std::forward<attr>(a)...);
|
|
||||||
}
|
|
||||||
catch(const qi::expectation_failure<const char *> &e)
|
|
||||||
{
|
|
||||||
throw expectation_failure<parent_error>
|
|
||||||
{
|
|
||||||
e, start, error_show_max
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class gen,
|
|
||||||
class... attr>
|
|
||||||
[[using gnu: always_inline, gnu_inline, artificial]]
|
|
||||||
extern inline bool
|
|
||||||
ircd::spirit::parse(const char *&start,
|
|
||||||
const char *const &stop,
|
|
||||||
gen&& g,
|
|
||||||
attr&&... a)
|
|
||||||
{
|
|
||||||
return qi::parse(start, stop, std::forward<gen>(g), std::forward<attr>(a)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<size_t idx,
|
|
||||||
class semantic_context>
|
|
||||||
inline auto &
|
|
||||||
ircd::spirit::local_at(semantic_context&& c)
|
|
||||||
{
|
|
||||||
return boost::fusion::at_c<idx>(c.locals);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<size_t idx,
|
|
||||||
class semantic_context>
|
|
||||||
inline auto &
|
|
||||||
ircd::spirit::attr_at(semantic_context&& c)
|
|
||||||
{
|
|
||||||
return boost::fusion::at_c<idx>(c.attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// boost::spirit::karma
|
|
||||||
//
|
|
||||||
|
|
||||||
namespace boost::spirit::karma::detail
|
|
||||||
{
|
|
||||||
template<> struct enable_buffering<ircd::spirit::sink_type>;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct [[gnu::visibility("internal")]]
|
|
||||||
boost::spirit::karma::detail::enable_buffering<ircd::spirit::sink_type>
|
|
||||||
{
|
|
||||||
uint width
|
|
||||||
{
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
uint depth
|
|
||||||
{
|
|
||||||
ircd::spirit::generator_state::depth()
|
|
||||||
};
|
|
||||||
|
|
||||||
ircd::mutable_buffer buffer
|
|
||||||
{
|
|
||||||
depth?
|
|
||||||
ircd::spirit::generator_buffer[depth - 1]:
|
|
||||||
data(ircd::spirit::generator_state->out),
|
|
||||||
|
|
||||||
depth?
|
|
||||||
std::min(width, uint(sizeof(ircd::spirit::generator_buffer[depth - 1]))):
|
|
||||||
size(ircd::spirit::generator_state->out),
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ircd::spirit::generator_state state
|
|
||||||
{
|
|
||||||
buffer, ircd::spirit::generator_state
|
|
||||||
};
|
|
||||||
|
|
||||||
ircd::scope_restore<struct ircd::spirit::generator_state *> stack_state
|
|
||||||
{
|
|
||||||
ircd::spirit::generator_state, std::addressof(state)
|
|
||||||
};
|
|
||||||
|
|
||||||
std::size_t buffer_size() const
|
|
||||||
{
|
|
||||||
return state.generated;
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable()
|
|
||||||
{
|
|
||||||
const auto width
|
|
||||||
{
|
|
||||||
this->width != -1U? this->width: state.consumed
|
|
||||||
};
|
|
||||||
|
|
||||||
assert(width >= state.consumed);
|
|
||||||
const uint off
|
|
||||||
{
|
|
||||||
width - state.consumed
|
|
||||||
};
|
|
||||||
|
|
||||||
const ircd::const_buffer src
|
|
||||||
{
|
|
||||||
state.out, state.consumed
|
|
||||||
};
|
|
||||||
|
|
||||||
const ircd::mutable_buffer dst
|
|
||||||
{
|
|
||||||
state.out + off
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto moved
|
|
||||||
{
|
|
||||||
ircd::move(dst, src)
|
|
||||||
};
|
|
||||||
|
|
||||||
assert(moved == state.consumed);
|
|
||||||
state.consumed = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool buffer_copy(std::size_t maxwidth = std::size_t(-1))
|
|
||||||
{
|
|
||||||
assert(state.prev);
|
|
||||||
#if __has_builtin(__builtin_assume)
|
|
||||||
__builtin_assume(state.prev != nullptr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto &prev
|
|
||||||
{
|
|
||||||
*state.prev
|
|
||||||
};
|
|
||||||
|
|
||||||
const bool prev_base
|
|
||||||
{
|
|
||||||
prev.prev == nullptr
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto width
|
|
||||||
{
|
|
||||||
this->width != -1U? this->width: state.consumed
|
|
||||||
};
|
|
||||||
|
|
||||||
const ircd::const_buffer src
|
|
||||||
{
|
|
||||||
state.out, std::max(state.consumed, width)
|
|
||||||
};
|
|
||||||
|
|
||||||
const ircd::mutable_buffer dst
|
|
||||||
{
|
|
||||||
data(prev.out) - (prev_base? state.consumed: -prev.consumed),
|
|
||||||
prev_base? state.consumed: (size(prev.out) - prev.consumed)
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto copied
|
|
||||||
{
|
|
||||||
ircd::copy(dst, src)
|
|
||||||
};
|
|
||||||
|
|
||||||
prev.generated += state.generated;
|
|
||||||
prev.consumed += copied;
|
|
||||||
return true; // sink.good();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename OutputIterator>
|
|
||||||
bool buffer_copy_to(OutputIterator& sink, std::size_t maxwidth = std::size_t(-1)) const
|
|
||||||
{
|
|
||||||
ircd::always_assert(false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename RestIterator>
|
|
||||||
bool buffer_copy_rest(RestIterator& sink, std::size_t start_at = 0) const
|
|
||||||
{
|
|
||||||
ircd::always_assert(false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
enable_buffering(ircd::spirit::sink_type &sink,
|
|
||||||
std::size_t width = std::size_t(-1))
|
|
||||||
:width
|
|
||||||
{
|
|
||||||
uint(width)
|
|
||||||
}
|
|
||||||
{
|
|
||||||
assert(size(buffer) != 0);
|
|
||||||
assert(this->depth <= 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
~enable_buffering() noexcept
|
|
||||||
{
|
|
||||||
assert(ircd::spirit::generator_state == &state);
|
|
||||||
//disable();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline bool
|
|
||||||
boost::spirit::karma::detail::buffering_policy::output(const char &value)
|
|
||||||
{
|
|
||||||
assert(ircd::spirit::generator_state);
|
|
||||||
#if __has_builtin(__builtin_assume)
|
|
||||||
__builtin_assume(ircd::spirit::generator_state != nullptr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto &state
|
|
||||||
{
|
|
||||||
*ircd::spirit::generator_state
|
|
||||||
};
|
|
||||||
|
|
||||||
const bool buffering
|
|
||||||
{
|
|
||||||
this->buffer != nullptr
|
|
||||||
};
|
|
||||||
|
|
||||||
const bool base
|
|
||||||
{
|
|
||||||
state.prev == nullptr
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint off
|
|
||||||
{
|
|
||||||
ircd::boolmask<uint>(!base | buffering) & state.consumed
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto dst
|
|
||||||
{
|
|
||||||
state.out + off
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto copied
|
|
||||||
{
|
|
||||||
ircd::copy(dst, value)
|
|
||||||
};
|
|
||||||
|
|
||||||
state.consumed += copied;
|
|
||||||
state.generated += sizeof(char);
|
|
||||||
return !buffering;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline void
|
|
||||||
boost::spirit::karma::detail::position_policy::output(const char &value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
template<>
|
|
||||||
template<>
|
|
||||||
inline void
|
|
||||||
boost::spirit::karma::detail::counting_policy<ircd::spirit::sink_type>::output(const char &value)
|
|
||||||
{
|
|
||||||
assert(count == nullptr);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template<>
|
|
||||||
template<>
|
|
||||||
inline bool
|
|
||||||
boost::spirit::karma::detail::disabling_output_iterator
|
|
||||||
<
|
|
||||||
boost::spirit::karma::detail::buffering_policy,
|
|
||||||
boost::spirit::karma::detail::counting_policy<ircd::spirit::sink_type>,
|
|
||||||
boost::spirit::karma::detail::position_policy
|
|
||||||
>
|
|
||||||
::output(const char &value)
|
|
||||||
{
|
|
||||||
assert(do_output);
|
|
||||||
this->counting_policy::output(value);
|
|
||||||
this->tracking_policy::output(value);
|
|
||||||
return this->buffering_policy::output(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
template<>
|
|
||||||
inline void
|
|
||||||
ircd::spirit::sink_type::operator=(const char &value)
|
|
||||||
{
|
|
||||||
this->base_iterator::output(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline ircd::spirit::sink_type &
|
|
||||||
ircd::spirit::sink_type::operator++()
|
|
||||||
{
|
|
||||||
(*sink) += !this->base_iterator::has_buffer();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline ircd::spirit::sink_type
|
|
||||||
ircd::spirit::sink_type::operator++(int)
|
|
||||||
{
|
|
||||||
auto copy(*this);
|
|
||||||
(*sink) += !this->base_iterator::has_buffer();
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline bool
|
|
||||||
ircd::spirit::sink_type::good()
|
|
||||||
const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // HAVE_IRCD_SPIRIT_H
|
|
||||||
|
|
66
include/ircd/spirit/expectation_failure.h
Normal file
66
include/ircd/spirit/expectation_failure.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
// The Construct
|
||||||
|
//
|
||||||
|
// Copyright (C) The Construct Developers, Authors & Contributors
|
||||||
|
// Copyright (C) 2016-2020 Jason Volk <jason@zemos.net>
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice is present in all copies. The
|
||||||
|
// full license for this software is available in the LICENSE file.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#define HAVE_IRCD_SPIRIT_EXPECTATION_FAILURE_H
|
||||||
|
|
||||||
|
namespace ircd {
|
||||||
|
namespace spirit
|
||||||
|
__attribute__((visibility("default")))
|
||||||
|
{
|
||||||
|
template<class parent_error> struct expectation_failure;
|
||||||
|
|
||||||
|
// parse.cc
|
||||||
|
extern thread_local char rule_buffer[64];
|
||||||
|
}}
|
||||||
|
|
||||||
|
template<class parent_error>
|
||||||
|
struct __attribute__((visibility("default")))
|
||||||
|
ircd::spirit::expectation_failure
|
||||||
|
:parent_error
|
||||||
|
{
|
||||||
|
template<class it = const char *>
|
||||||
|
expectation_failure(const qi::expectation_failure<it> &e,
|
||||||
|
const ssize_t &show_max = 64);
|
||||||
|
|
||||||
|
template<class it = const char *>
|
||||||
|
expectation_failure(const qi::expectation_failure<it> &e,
|
||||||
|
const it &start,
|
||||||
|
const ssize_t &show_max = 64);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class parent>
|
||||||
|
template<class it>
|
||||||
|
ircd::spirit::expectation_failure<parent>::expectation_failure(const qi::expectation_failure<it> &e,
|
||||||
|
const ssize_t &show_max)
|
||||||
|
:parent
|
||||||
|
{
|
||||||
|
"Expected %s. You input %zd invalid characters :%s",
|
||||||
|
ircd::string(rule_buffer, e.what_),
|
||||||
|
std::distance(e.first, e.last),
|
||||||
|
string_view{e.first, e.first + std::min(std::distance(e.first, e.last), show_max)}
|
||||||
|
}
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<class parent>
|
||||||
|
template<class it>
|
||||||
|
ircd::spirit::expectation_failure<parent>::expectation_failure(const qi::expectation_failure<it> &e,
|
||||||
|
const it &start,
|
||||||
|
const ssize_t &show_max)
|
||||||
|
:parent
|
||||||
|
{
|
||||||
|
"Expected %s. You input %zd invalid characters somewhere between position %zd and %zd :%s",
|
||||||
|
ircd::string(rule_buffer, e.what_),
|
||||||
|
std::distance(e.first, e.last),
|
||||||
|
std::distance(start, e.first),
|
||||||
|
std::distance(start, e.last),
|
||||||
|
string_view{e.first, e.first + std::min(std::distance(e.first, e.last), show_max)}
|
||||||
|
}
|
||||||
|
{}
|
425
include/ircd/spirit/generate.h
Normal file
425
include/ircd/spirit/generate.h
Normal file
|
@ -0,0 +1,425 @@
|
||||||
|
// The Construct
|
||||||
|
//
|
||||||
|
// Copyright (C) The Construct Developers, Authors & Contributors
|
||||||
|
// Copyright (C) 2016-2020 Jason Volk <jason@zemos.net>
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice is present in all copies. The
|
||||||
|
// full license for this software is available in the LICENSE file.
|
||||||
|
|
||||||
|
#define HAVE_IRCD_SPIRIT_GENERATE_H
|
||||||
|
|
||||||
|
/// This file is not part of the IRCd standard include list (stdinc.h) because
|
||||||
|
/// it involves extremely expensive boost headers for creating formal spirit
|
||||||
|
/// grammars. This file is automatically included in the spirit.h group.
|
||||||
|
|
||||||
|
namespace ircd {
|
||||||
|
namespace spirit
|
||||||
|
__attribute__((visibility("default")))
|
||||||
|
{
|
||||||
|
IRCD_EXCEPTION(error, generator_error);
|
||||||
|
IRCD_EXCEPTION(generator_error, buffer_overrun);
|
||||||
|
|
||||||
|
extern thread_local struct generator_state *generator_state;
|
||||||
|
extern thread_local char generator_buffer[8][64_KiB];
|
||||||
|
}}
|
||||||
|
|
||||||
|
namespace ircd {
|
||||||
|
namespace spirit
|
||||||
|
__attribute__((visibility("internal")))
|
||||||
|
{
|
||||||
|
using prop_mask = mpl_::int_
|
||||||
|
<
|
||||||
|
karma::generator_properties::no_properties
|
||||||
|
| karma::generator_properties::buffering
|
||||||
|
| karma::generator_properties::counting
|
||||||
|
| karma::generator_properties::tracking
|
||||||
|
| karma::generator_properties::disabling
|
||||||
|
>;
|
||||||
|
|
||||||
|
using sink_type = karma::detail::output_iterator<char *, prop_mask, unused_type>;
|
||||||
|
|
||||||
|
template<bool truncation = false,
|
||||||
|
class gen,
|
||||||
|
class... attr>
|
||||||
|
bool generate(mutable_buffer &out, gen&&, attr&&...);
|
||||||
|
}}
|
||||||
|
|
||||||
|
struct [[gnu::visibility("hidden")]]
|
||||||
|
ircd::spirit::generator_state
|
||||||
|
{
|
||||||
|
/// The number of instances stacked behind the current state
|
||||||
|
static uint depth() noexcept;
|
||||||
|
|
||||||
|
/// User's buffer.
|
||||||
|
mutable_buffer &out;
|
||||||
|
|
||||||
|
/// Previous in buffer stack
|
||||||
|
struct generator_state *prev {nullptr};
|
||||||
|
|
||||||
|
/// The number of characters we're storing in buffer
|
||||||
|
uint consumed {0};
|
||||||
|
|
||||||
|
/// The number of characters attempted, which may be larger than
|
||||||
|
/// the buffer capacity indicating an overflow amount.
|
||||||
|
uint generated {0};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<bool truncation,
|
||||||
|
class gen,
|
||||||
|
class... attr>
|
||||||
|
[[using gnu: always_inline, gnu_inline]]
|
||||||
|
extern inline bool
|
||||||
|
ircd::spirit::generate(mutable_buffer &out,
|
||||||
|
gen&& g,
|
||||||
|
attr&&... a)
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto max(size(out));
|
||||||
|
const auto start(data(out));
|
||||||
|
struct generator_state state
|
||||||
|
{
|
||||||
|
out
|
||||||
|
};
|
||||||
|
|
||||||
|
const scope_restore _state
|
||||||
|
{
|
||||||
|
generator_state, &state
|
||||||
|
};
|
||||||
|
|
||||||
|
sink_type sink
|
||||||
|
{
|
||||||
|
begin(out)
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto ret
|
||||||
|
{
|
||||||
|
karma::generate(sink, std::forward<gen>(g), std::forward<attr>(a)...)
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(state.generated >= state.consumed);
|
||||||
|
const auto overflow
|
||||||
|
{
|
||||||
|
state.generated - state.consumed
|
||||||
|
};
|
||||||
|
|
||||||
|
if constexpr(truncation)
|
||||||
|
{
|
||||||
|
begin(out) = begin(out) > end(out)? end(out): begin(out);
|
||||||
|
assert(begin(out) <= end(out));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(unlikely(overflow || begin(out) > end(out)))
|
||||||
|
{
|
||||||
|
begin(out) = start;
|
||||||
|
assert(begin(out) <= end(out));
|
||||||
|
|
||||||
|
char pbuf[2][48];
|
||||||
|
throw buffer_overrun
|
||||||
|
{
|
||||||
|
"Insufficient buffer of %s; required at least %s",
|
||||||
|
pretty(pbuf[0], iec(state.consumed)),
|
||||||
|
pretty(pbuf[1], iec(state.generated)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(begin(out) >= end(out) - max);
|
||||||
|
assert(begin(out) <= end(out));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint
|
||||||
|
ircd::spirit::generator_state::depth()
|
||||||
|
noexcept
|
||||||
|
{
|
||||||
|
uint ret(0);
|
||||||
|
for(auto p(ircd::spirit::generator_state); p; p = p->prev)
|
||||||
|
++ret;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// boost::spirit::karma
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace boost::spirit::karma::detail
|
||||||
|
{
|
||||||
|
template<> struct enable_buffering<ircd::spirit::sink_type>;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct [[gnu::visibility("internal")]]
|
||||||
|
boost::spirit::karma::detail::enable_buffering<ircd::spirit::sink_type>
|
||||||
|
{
|
||||||
|
uint width
|
||||||
|
{
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
uint depth
|
||||||
|
{
|
||||||
|
ircd::spirit::generator_state::depth()
|
||||||
|
};
|
||||||
|
|
||||||
|
ircd::mutable_buffer buffer
|
||||||
|
{
|
||||||
|
depth?
|
||||||
|
ircd::spirit::generator_buffer[depth - 1]:
|
||||||
|
data(ircd::spirit::generator_state->out),
|
||||||
|
|
||||||
|
depth?
|
||||||
|
sizeof(ircd::spirit::generator_buffer[depth - 1]):
|
||||||
|
size(ircd::spirit::generator_state->out),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ircd::spirit::generator_state state
|
||||||
|
{
|
||||||
|
buffer, ircd::spirit::generator_state
|
||||||
|
};
|
||||||
|
|
||||||
|
ircd::scope_restore<struct ircd::spirit::generator_state *> stack_state
|
||||||
|
{
|
||||||
|
ircd::spirit::generator_state, std::addressof(state)
|
||||||
|
};
|
||||||
|
|
||||||
|
std::size_t buffer_size() const
|
||||||
|
{
|
||||||
|
return state.generated;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename OutputIterator>
|
||||||
|
bool buffer_copy_to(OutputIterator& sink, std::size_t maxwidth = std::size_t(-1)) const = delete;
|
||||||
|
|
||||||
|
template<typename RestIterator>
|
||||||
|
bool buffer_copy_rest(RestIterator& sink, std::size_t start_at = 0) const = delete;
|
||||||
|
|
||||||
|
bool buffer_copy(std::size_t maxwidth = std::size_t(-1));
|
||||||
|
|
||||||
|
void disable();
|
||||||
|
|
||||||
|
enable_buffering(ircd::spirit::sink_type &sink, std::size_t width = std::size_t(-1));
|
||||||
|
~enable_buffering() noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline
|
||||||
|
boost::spirit::karma::detail::enable_buffering<ircd::spirit::sink_type>::enable_buffering(ircd::spirit::sink_type &sink,
|
||||||
|
std::size_t width)
|
||||||
|
:width
|
||||||
|
{
|
||||||
|
uint(width)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assert(size(buffer) != 0);
|
||||||
|
assert(this->depth <= 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
boost::spirit::karma::detail::enable_buffering<ircd::spirit::sink_type>::~enable_buffering()
|
||||||
|
noexcept
|
||||||
|
{
|
||||||
|
assert(ircd::spirit::generator_state == &state);
|
||||||
|
//disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
boost::spirit::karma::detail::enable_buffering<ircd::spirit::sink_type>::disable()
|
||||||
|
{
|
||||||
|
const auto width
|
||||||
|
{
|
||||||
|
this->width != -1U? this->width: state.consumed
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint off
|
||||||
|
{
|
||||||
|
width > state.consumed? width - state.consumed: 0U
|
||||||
|
};
|
||||||
|
|
||||||
|
const ircd::const_buffer src
|
||||||
|
{
|
||||||
|
state.out, state.consumed
|
||||||
|
};
|
||||||
|
|
||||||
|
const ircd::mutable_buffer dst
|
||||||
|
{
|
||||||
|
state.out + off
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto moved
|
||||||
|
{
|
||||||
|
ircd::move(dst, src)
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(moved == state.consumed);
|
||||||
|
state.consumed = !off? state.consumed: 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
boost::spirit::karma::detail::enable_buffering<ircd::spirit::sink_type>::buffer_copy(std::size_t maxwidth)
|
||||||
|
{
|
||||||
|
assert(state.prev);
|
||||||
|
#if __has_builtin(__builtin_assume)
|
||||||
|
__builtin_assume(state.prev != nullptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto &prev
|
||||||
|
{
|
||||||
|
*state.prev
|
||||||
|
};
|
||||||
|
|
||||||
|
const bool prev_base
|
||||||
|
{
|
||||||
|
prev.prev == nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto width
|
||||||
|
{
|
||||||
|
this->width != -1U? this->width: state.consumed
|
||||||
|
};
|
||||||
|
|
||||||
|
const ircd::const_buffer src
|
||||||
|
{
|
||||||
|
state.out, std::max(state.consumed, width)
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto dst_disp
|
||||||
|
{
|
||||||
|
prev_base? -ssize_t(state.consumed): ssize_t(prev.consumed)
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto dst_size
|
||||||
|
{
|
||||||
|
prev_base? state.consumed: size(prev.out) - prev.consumed
|
||||||
|
};
|
||||||
|
|
||||||
|
const ircd::mutable_buffer dst
|
||||||
|
{
|
||||||
|
data(prev.out) + dst_disp, dst_size
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto copied
|
||||||
|
{
|
||||||
|
ircd::copy(dst, src)
|
||||||
|
};
|
||||||
|
|
||||||
|
prev.generated += state.generated;
|
||||||
|
prev.consumed += copied;
|
||||||
|
return true; // sink.good();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool
|
||||||
|
boost::spirit::karma::detail::buffering_policy::output(const char &value)
|
||||||
|
{
|
||||||
|
assert(ircd::spirit::generator_state);
|
||||||
|
#if __has_builtin(__builtin_assume)
|
||||||
|
__builtin_assume(ircd::spirit::generator_state != nullptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto &state
|
||||||
|
{
|
||||||
|
*ircd::spirit::generator_state
|
||||||
|
};
|
||||||
|
|
||||||
|
const bool buffering
|
||||||
|
{
|
||||||
|
this->buffer != nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
const bool base
|
||||||
|
{
|
||||||
|
state.prev == nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint off
|
||||||
|
{
|
||||||
|
ircd::boolmask<uint>(!base | buffering) & state.consumed
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto dst
|
||||||
|
{
|
||||||
|
state.out + off
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto copied
|
||||||
|
{
|
||||||
|
ircd::copy(dst, value)
|
||||||
|
};
|
||||||
|
|
||||||
|
state.consumed += copied;
|
||||||
|
state.generated += sizeof(char);
|
||||||
|
return !buffering;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void
|
||||||
|
boost::spirit::karma::detail::position_policy::output(const char &value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
template<>
|
||||||
|
template<>
|
||||||
|
inline void
|
||||||
|
boost::spirit::karma::detail::counting_policy<ircd::spirit::sink_type>::output(const char &value)
|
||||||
|
{
|
||||||
|
assert(count == nullptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<>
|
||||||
|
template<>
|
||||||
|
inline bool
|
||||||
|
boost::spirit::karma::detail::disabling_output_iterator
|
||||||
|
<
|
||||||
|
boost::spirit::karma::detail::buffering_policy,
|
||||||
|
boost::spirit::karma::detail::counting_policy<ircd::spirit::sink_type>,
|
||||||
|
boost::spirit::karma::detail::position_policy
|
||||||
|
>
|
||||||
|
::output(const char &value)
|
||||||
|
{
|
||||||
|
assert(do_output);
|
||||||
|
this->counting_policy::output(value);
|
||||||
|
this->tracking_policy::output(value);
|
||||||
|
return this->buffering_policy::output(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
template<>
|
||||||
|
inline void
|
||||||
|
ircd::spirit::sink_type::operator=(const char &value)
|
||||||
|
{
|
||||||
|
this->base_iterator::output(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline ircd::spirit::sink_type &
|
||||||
|
ircd::spirit::sink_type::operator++()
|
||||||
|
{
|
||||||
|
const bool has_buffer
|
||||||
|
{
|
||||||
|
this->base_iterator::has_buffer()
|
||||||
|
};
|
||||||
|
|
||||||
|
(*sink) += !has_buffer;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline ircd::spirit::sink_type
|
||||||
|
ircd::spirit::sink_type::operator++(int)
|
||||||
|
{
|
||||||
|
auto copy(*this);
|
||||||
|
++(*this);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool
|
||||||
|
ircd::spirit::sink_type::good()
|
||||||
|
const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
132
include/ircd/spirit/parse.h
Normal file
132
include/ircd/spirit/parse.h
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
// The Construct
|
||||||
|
//
|
||||||
|
// Copyright (C) The Construct Developers, Authors & Contributors
|
||||||
|
// Copyright (C) 2016-2020 Jason Volk <jason@zemos.net>
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice is present in all copies. The
|
||||||
|
// full license for this software is available in the LICENSE file.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#define HAVE_IRCD_SPIRIT_PARSE_H
|
||||||
|
|
||||||
|
namespace ircd {
|
||||||
|
namespace spirit
|
||||||
|
__attribute__((visibility("internal")))
|
||||||
|
{
|
||||||
|
struct substring_view;
|
||||||
|
struct custom_parser;
|
||||||
|
BOOST_SPIRIT_TERMINAL(custom);
|
||||||
|
|
||||||
|
template<class gen,
|
||||||
|
class... attr>
|
||||||
|
bool parse(const char *&start, const char *const &stop, gen&&, attr&&...);
|
||||||
|
|
||||||
|
template<class parent_error,
|
||||||
|
size_t error_show_max = 48,
|
||||||
|
class gen,
|
||||||
|
class... attr>
|
||||||
|
bool parse(const char *&start, const char *const &stop, gen&&, attr&&...);
|
||||||
|
}}
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace spirit
|
||||||
|
__attribute__((visibility("internal")))
|
||||||
|
{
|
||||||
|
namespace qi
|
||||||
|
{
|
||||||
|
template<class modifiers>
|
||||||
|
struct make_primitive<ircd::spirit::tag::custom, modifiers>;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct use_terminal<qi::domain, ircd::spirit::tag::custom>
|
||||||
|
:mpl::true_
|
||||||
|
{};
|
||||||
|
}}
|
||||||
|
|
||||||
|
struct [[gnu::visibility("internal")]]
|
||||||
|
ircd::spirit::custom_parser
|
||||||
|
:qi::primitive_parser<custom_parser>
|
||||||
|
{
|
||||||
|
template<class context,
|
||||||
|
class iterator>
|
||||||
|
struct attribute
|
||||||
|
{
|
||||||
|
using type = iterator;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class context>
|
||||||
|
boost::spirit::info what(context &) const
|
||||||
|
{
|
||||||
|
return boost::spirit::info("custom");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class iterator,
|
||||||
|
class context,
|
||||||
|
class skipper,
|
||||||
|
class attr>
|
||||||
|
bool parse(iterator &, const iterator &, context &, const skipper &, attr &) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class modifiers>
|
||||||
|
struct [[gnu::visibility("internal")]]
|
||||||
|
boost::spirit::qi::make_primitive<ircd::spirit::tag::custom, modifiers>
|
||||||
|
{
|
||||||
|
using result_type = ircd::spirit::custom_parser;
|
||||||
|
|
||||||
|
result_type operator()(unused_type, unused_type) const
|
||||||
|
{
|
||||||
|
return result_type{};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ircd::spirit::substring_view
|
||||||
|
:ircd::string_view
|
||||||
|
{
|
||||||
|
using _iterator = boost::spirit::karma::detail::indirect_iterator<const char *>;
|
||||||
|
using _iterator_range = boost::iterator_range<_iterator>;
|
||||||
|
|
||||||
|
using ircd::string_view::string_view;
|
||||||
|
explicit substring_view(const _iterator_range &range)
|
||||||
|
:ircd::string_view
|
||||||
|
{
|
||||||
|
std::addressof(*range.begin()), std::addressof(*range.end())
|
||||||
|
}
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class parent_error,
|
||||||
|
size_t error_show_max,
|
||||||
|
class gen,
|
||||||
|
class... attr>
|
||||||
|
[[using gnu: always_inline, gnu_inline, artificial]]
|
||||||
|
extern inline bool
|
||||||
|
ircd::spirit::parse(const char *&start,
|
||||||
|
const char *const &stop,
|
||||||
|
gen&& g,
|
||||||
|
attr&&... a)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return qi::parse(start, stop, std::forward<gen>(g), std::forward<attr>(a)...);
|
||||||
|
}
|
||||||
|
catch(const qi::expectation_failure<const char *> &e)
|
||||||
|
{
|
||||||
|
throw expectation_failure<parent_error>
|
||||||
|
{
|
||||||
|
e, start, error_show_max
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class gen,
|
||||||
|
class... attr>
|
||||||
|
[[using gnu: always_inline, gnu_inline, artificial]]
|
||||||
|
extern inline bool
|
||||||
|
ircd::spirit::parse(const char *&start,
|
||||||
|
const char *const &stop,
|
||||||
|
gen&& g,
|
||||||
|
attr&&... a)
|
||||||
|
{
|
||||||
|
return qi::parse(start, stop, std::forward<gen>(g), std::forward<attr>(a)...);
|
||||||
|
}
|
130
include/ircd/spirit/spirit.h
Normal file
130
include/ircd/spirit/spirit.h
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
// The Construct
|
||||||
|
//
|
||||||
|
// Copyright (C) The Construct Developers, Authors & Contributors
|
||||||
|
// Copyright (C) 2016-2020 Jason Volk <jason@zemos.net>
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice is present in all copies. The
|
||||||
|
// full license for this software is available in the LICENSE file.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#define HAVE_IRCD_SPIRIT_SPIRIT_H
|
||||||
|
|
||||||
|
namespace ircd {
|
||||||
|
namespace spirit
|
||||||
|
__attribute__((visibility("default")))
|
||||||
|
{
|
||||||
|
IRCD_EXCEPTION(ircd::error, error);
|
||||||
|
}}
|
||||||
|
|
||||||
|
namespace ircd {
|
||||||
|
namespace spirit
|
||||||
|
__attribute__((visibility("internal")))
|
||||||
|
{
|
||||||
|
namespace phx = boost::phoenix;
|
||||||
|
namespace fusion = boost::fusion;
|
||||||
|
namespace spirit = boost::spirit;
|
||||||
|
namespace ascii = spirit::ascii;
|
||||||
|
namespace karma = spirit::karma;
|
||||||
|
namespace qi = spirit::qi;
|
||||||
|
|
||||||
|
using _val_type = phx::actor<spirit::attribute<0>>;
|
||||||
|
using _r0_type = phx::actor<spirit::attribute<0>>;
|
||||||
|
using _r1_type = phx::actor<spirit::attribute<1>>;
|
||||||
|
using _r2_type = phx::actor<spirit::attribute<2>>;
|
||||||
|
using _r3_type = phx::actor<spirit::attribute<3>>;
|
||||||
|
|
||||||
|
using spirit::unused_type;
|
||||||
|
using spirit::auto_;
|
||||||
|
using spirit::_pass;
|
||||||
|
using spirit::_val;
|
||||||
|
|
||||||
|
using qi::locals;
|
||||||
|
using qi::_a;
|
||||||
|
using qi::_a_type;
|
||||||
|
using qi::_r1_type;
|
||||||
|
using qi::raw;
|
||||||
|
using qi::omit;
|
||||||
|
using qi::matches;
|
||||||
|
using qi::hold;
|
||||||
|
using qi::eoi;
|
||||||
|
using qi::eps;
|
||||||
|
using qi::expect;
|
||||||
|
using qi::attr;
|
||||||
|
using qi::attr_cast;
|
||||||
|
using qi::repeat;
|
||||||
|
using qi::lit;
|
||||||
|
using qi::char_;
|
||||||
|
using qi::byte_;
|
||||||
|
using qi::string;
|
||||||
|
using qi::short_;
|
||||||
|
using qi::ushort_;
|
||||||
|
using qi::word;
|
||||||
|
using qi::big_word;
|
||||||
|
using qi::little_word;
|
||||||
|
using qi::int_;
|
||||||
|
using qi::uint_;
|
||||||
|
using qi::dword;
|
||||||
|
using qi::big_dword;
|
||||||
|
using qi::little_dword;
|
||||||
|
using qi::long_;
|
||||||
|
using qi::ulong_;
|
||||||
|
using qi::qword;
|
||||||
|
using qi::big_qword;
|
||||||
|
using qi::little_qword;
|
||||||
|
using qi::float_;
|
||||||
|
using qi::bin_float;
|
||||||
|
using qi::big_bin_float;
|
||||||
|
using qi::little_bin_float;
|
||||||
|
using qi::double_;
|
||||||
|
using qi::bin_double;
|
||||||
|
using qi::big_bin_double;
|
||||||
|
using qi::little_bin_double;
|
||||||
|
using spirit::repository::qi::seek;
|
||||||
|
|
||||||
|
using karma::lit;
|
||||||
|
using karma::char_;
|
||||||
|
using karma::long_;
|
||||||
|
using karma::double_;
|
||||||
|
using karma::bool_;
|
||||||
|
using karma::eps;
|
||||||
|
using karma::attr_cast;
|
||||||
|
using karma::maxwidth;
|
||||||
|
using karma::buffer;
|
||||||
|
using karma::skip;
|
||||||
|
|
||||||
|
template<size_t idx,
|
||||||
|
class semantic_context>
|
||||||
|
auto &
|
||||||
|
attr_at(semantic_context&&);
|
||||||
|
|
||||||
|
template<size_t idx,
|
||||||
|
class semantic_context>
|
||||||
|
auto &
|
||||||
|
local_at(semantic_context&&);
|
||||||
|
}}
|
||||||
|
|
||||||
|
namespace ircd::spirit::local
|
||||||
|
{
|
||||||
|
using qi::_0;
|
||||||
|
using qi::_1;
|
||||||
|
using qi::_2;
|
||||||
|
using qi::_3;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t idx,
|
||||||
|
class semantic_context>
|
||||||
|
inline auto &
|
||||||
|
ircd::spirit::local_at(semantic_context&& c)
|
||||||
|
{
|
||||||
|
return boost::fusion::at_c<idx>(c.locals);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t idx,
|
||||||
|
class semantic_context>
|
||||||
|
inline auto &
|
||||||
|
ircd::spirit::attr_at(semantic_context&& c)
|
||||||
|
{
|
||||||
|
return boost::fusion::at_c<idx>(c.attributes);
|
||||||
|
}
|
|
@ -28,15 +28,15 @@ decltype(ircd::spirit::rule_buffer)
|
||||||
ircd::spirit::rule_buffer
|
ircd::spirit::rule_buffer
|
||||||
alignas(64);
|
alignas(64);
|
||||||
|
|
||||||
|
thread_local
|
||||||
|
decltype(ircd::spirit::generator_state)
|
||||||
|
ircd::spirit::generator_state;
|
||||||
|
|
||||||
thread_local
|
thread_local
|
||||||
decltype(ircd::spirit::generator_buffer)
|
decltype(ircd::spirit::generator_buffer)
|
||||||
ircd::spirit::generator_buffer
|
ircd::spirit::generator_buffer
|
||||||
alignas(64);
|
alignas(64);
|
||||||
|
|
||||||
thread_local
|
|
||||||
decltype(ircd::spirit::generator_state)
|
|
||||||
ircd::spirit::generator_state;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Museum of historical comments
|
// Museum of historical comments
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in a new issue