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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions include/iris/x4/char/char_parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ struct char_parser : parser<Derived>
[[nodiscard]] static constexpr bool
parse(It& first, Se const& last, Context const& ctx, Attr& attr)
noexcept(
std::is_nothrow_copy_assignable_v<It> &&
noexcept(x4::skip_over(first, last, ctx)) &&
noexcept(first != last) &&
noexcept(Derived::test(static_cast<classify_type>(*first), ctx)) &&
Expand All @@ -49,11 +50,12 @@ struct char_parser : parser<Derived>
static_assert(!CharIncompatibleWith<std::iter_value_t<It>, char_type>, "Mixing incompatible char types is not allowed");
static_assert(!CharLike<Attr> || !CharIncompatibleWith<Attr, char_type>, "Mixing incompatible char types is not allowed");

x4::skip_over(first, last, ctx);
auto it = first;
x4::skip_over(it, last, ctx);

if (first != last && Derived::test(static_cast<classify_type>(*first), ctx)) {
x4::move_to(std::iter_value_t<It>{*first}, attr);
++first;
if (it != last && Derived::test(static_cast<classify_type>(*it), ctx)) {
x4::move_to(std::iter_value_t<It>{*it++}, attr);
first = it;
return true;
}
return false;
Expand All @@ -64,6 +66,7 @@ struct char_parser : parser<Derived>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& ctx, Attr& attr) const
noexcept(
std::is_nothrow_copy_assignable_v<It> &&
noexcept(x4::skip_over(first, last, ctx)) &&
noexcept(first != last) &&
noexcept(this->derived().test(static_cast<classify_type>(*first), ctx)) &&
Expand All @@ -74,11 +77,12 @@ struct char_parser : parser<Derived>
static_assert(!CharIncompatibleWith<std::iter_value_t<It>, char_type>, "Mixing incompatible char types is not allowed");
static_assert(!CharLike<Attr> || !CharIncompatibleWith<Attr, char_type>, "Mixing incompatible char types is not allowed");

x4::skip_over(first, last, ctx);
auto it = first;
x4::skip_over(it, last, ctx);

if (first != last && this->derived().test(static_cast<classify_type>(*first), ctx)) {
x4::move_to(std::iter_value_t<It>{*first}, attr);
++first;
if (it != last && this->derived().test(static_cast<classify_type>(*it), ctx)) {
x4::move_to(std::iter_value_t<It>{*it++}, attr);
first = it;
return true;
}
return false;
Expand Down
9 changes: 6 additions & 3 deletions include/iris/x4/directive/lexeme.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,16 @@ struct lexeme_directive : proxy_parser<Subject, lexeme_directive<Subject>>
>
)
{
x4::skip_over(first, last, ctx); // pre-skip
auto it = first;
x4::skip_over(it, last, ctx); // pre-skip

return this->subject.parse(
first, last,
bool const ok = this->subject.parse(
it, last,
x4::remove_first_context<contexts::skipper>(ctx), // no skipper
attr
);
if (ok) first = it;
return ok;
}

[[nodiscard]] constexpr std::string get_x4_info() const
Expand Down
1 change: 0 additions & 1 deletion include/iris/x4/directive/no_skip.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
=============================================================================*/

#include <iris/x4/core/context.hpp>
#include <iris/x4/core/skip_over.hpp>
#include <iris/x4/core/parser.hpp>

#include <iterator>
Expand Down
1 change: 0 additions & 1 deletion include/iris/x4/directive/omit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ struct omit_directive : unary_parser<Subject, omit_directive<Subject>>
parse(It& first, Se const& last, Context const& ctx, Attr const&) const
noexcept(is_nothrow_parsable_v<Subject, It, Se, Context, unused_type>)
{
static_assert(Parsable<Subject, It, Se, Context, unused_type>);
return this->subject.parse(first, last, ctx, unused);
}
};
Expand Down
1 change: 0 additions & 1 deletion include/iris/x4/directive/skip.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
=============================================================================*/

#include <iris/x4/core/context.hpp>
#include <iris/x4/core/skip_over.hpp>
#include <iris/x4/core/parser.hpp>

#include <iris/x4/char/char_class_tags.hpp>
Expand Down
42 changes: 28 additions & 14 deletions include/iris/x4/numeric/bool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,25 +74,32 @@ struct bool_parser : parser<bool_parser<T, Policy>>

constexpr bool_parser(Policy const&) = delete; // Policy should be stateless

// Attribute is `T` or `unused_type`
template<std::forward_iterator It, std::sentinel_for<It> Se, class Context, class U>
requires
std::same_as<std::remove_const_t<U>, T> ||
std::same_as<std::remove_const_t<U>, unused_type>
[[nodiscard]] static constexpr bool
parse(It& first, Se const& last, Context const& ctx, U& attr)
noexcept(
std::is_nothrow_copy_assignable_v<It> &&
noexcept(x4::skip_over(first, last, ctx)) &&
noexcept(Policy::parse_true(first, last, attr, x4::get_case_compare<traits::char_encoding_for<std::remove_const_t<std::iter_value_t<It>>>>(ctx))) &&
noexcept(Policy::parse_false(first, last, attr, x4::get_case_compare<traits::char_encoding_for<std::remove_const_t<std::iter_value_t<It>>>>(ctx)))
noexcept(Policy::parse_true(first, last, attr, x4::get_case_compare<traits::char_encoding_for<std::iter_value_t<It>>>(ctx))) &&
noexcept(Policy::parse_false(first, last, attr, x4::get_case_compare<traits::char_encoding_for<std::iter_value_t<It>>>(ctx)))
)
{
x4::skip_over(first, last, ctx);
auto it = first;
x4::skip_over(it, last, ctx);

auto const& compare = x4::get_case_compare<traits::char_encoding_for<std::remove_const_t<std::iter_value_t<It>>>>(ctx);
return Policy::parse_true(first, last, attr, compare)
|| Policy::parse_false(first, last, attr, compare);
auto const& compare = x4::get_case_compare<traits::char_encoding_for<std::iter_value_t<It>>>(ctx);
bool const ok = Policy::parse_true(it, last, attr, compare)
|| Policy::parse_false(it, last, attr, compare);

if (ok) first = it;
return ok;
}

// Attribute is NOT (`T` or `unused_type`)
template<std::forward_iterator It, std::sentinel_for<It> Se, class Context, class Attr>
[[nodiscard]] static constexpr bool
parse(It& first, Se const& last, Context const& ctx, Attr& attr)
Expand Down Expand Up @@ -141,25 +148,33 @@ struct literal_bool_parser : parser<literal_bool_parser<T, Policy>>
template<class U>
constexpr literal_bool_parser(U&&, Policy const&) = delete; // Policy should be stateless

// Attribute is `T` or `unused_type`
template<std::forward_iterator It, std::sentinel_for<It> Se, class Context, class U>
requires
std::same_as<std::remove_const_t<U>, T> ||
std::same_as<std::remove_const_t<U>, unused_type>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& ctx, U& attr) const
noexcept(
std::is_nothrow_copy_assignable_v<It> &&
noexcept(x4::skip_over(first, last, ctx)) &&
noexcept(Policy::parse_true(first, last, attr, x4::get_case_compare<traits::char_encoding_for<std::remove_const_t<std::iter_value_t<It>>>>(ctx))) &&
noexcept(Policy::parse_false(first, last, attr, x4::get_case_compare<traits::char_encoding_for<std::remove_const_t<std::iter_value_t<It>>>>(ctx)))
noexcept(Policy::parse_true(first, last, attr, x4::get_case_compare<traits::char_encoding_for<std::iter_value_t<It>>>(ctx))) &&
noexcept(Policy::parse_false(first, last, attr, x4::get_case_compare<traits::char_encoding_for<std::iter_value_t<It>>>(ctx)))
)
{
x4::skip_over(first, last, ctx);
auto it = first;
x4::skip_over(it, last, ctx);

auto const& compare = x4::get_case_compare<traits::char_encoding_for<std::iter_value_t<It>>>(ctx);
bool const ok = (expected_bool_ && Policy::parse_true(it, last, attr, compare))
|| (!expected_bool_ && Policy::parse_false(it, last, attr, compare));

auto const& compare = x4::get_case_compare<traits::char_encoding_for<std::remove_const_t<std::iter_value_t<It>>>>(ctx);
return (expected_bool_ && Policy::parse_true(first, last, attr, compare))
|| (!expected_bool_ && Policy::parse_false(first, last, attr, compare));
if (ok) first = it;
return ok;
}

// Attribute is NOT (`T` or `unused_type`)
// Needs temporary instance of `T` and do conversion
template<std::forward_iterator It, std::sentinel_for<It> Se, class Context, class Attr>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& ctx, Attr& attr) const
Expand All @@ -171,8 +186,7 @@ struct literal_bool_parser : parser<literal_bool_parser<T, Policy>>
{
static_assert(X4NonUnusedAttribute<Attr>);

// this case is called when Attribute is not T
T attr_{};
T attr_;
if (literal_bool_parser::parse(first, last, ctx, attr_)) {
x4::move_to(std::move(attr_), attr);
return true;
Expand Down
8 changes: 6 additions & 2 deletions include/iris/x4/numeric/int.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,16 @@ struct int_parser : parser<int_parser<T, Radix, MinDigits, MaxDigits>>
[[nodiscard]] static constexpr bool
parse(It& first, Se const& last, Context const& ctx, Attr& attr)
noexcept(
std::is_nothrow_copy_assignable_v<It> &&
noexcept(x4::skip_over(first, last, ctx)) &&
noexcept(numeric::extract_int<T, Radix, MinDigits, MaxDigits>::call(first, last, attr))
)
{
x4::skip_over(first, last, ctx);
return numeric::extract_int<T, Radix, MinDigits, MaxDigits>::call(first, last, attr);
auto it = first;
x4::skip_over(it, last, ctx);
bool const ok = numeric::extract_int<T, Radix, MinDigits, MaxDigits>::call(it, last, attr);
if (ok) first = it;
return ok;
}

[[nodiscard]] static std::string get_x4_info()
Expand Down
8 changes: 6 additions & 2 deletions include/iris/x4/numeric/real.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,12 +229,16 @@ struct real_parser : parser<real_parser<T, Policy>>
[[nodiscard]] static constexpr bool
parse(It& first, Se const& last, Context const& ctx, U& attr)
noexcept(
std::is_nothrow_copy_assignable_v<It> &&
noexcept(x4::skip_over(first, last, ctx)) &&
noexcept(numeric::extract_real<T, Policy>::parse(first, last, attr))
)
{
x4::skip_over(first, last, ctx);
return numeric::extract_real<T, Policy>::parse(first, last, attr);
auto it = first;
x4::skip_over(it, last, ctx);
bool const ok = numeric::extract_real<T, Policy>::parse(it, last, attr);
if (ok) first = it;
return ok;
}

template<std::forward_iterator It, std::sentinel_for<It> Se, class Context, class Attr>
Expand Down
8 changes: 6 additions & 2 deletions include/iris/x4/numeric/uint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,16 @@ struct uint_parser : parser<uint_parser<T, Radix, MinDigits, MaxDigits>>
[[nodiscard]] static constexpr bool
parse(It& first, Se const& last, Context const& ctx, Attr& attr)
noexcept(
std::is_nothrow_copy_assignable_v<It> &&
noexcept(x4::skip_over(first, last, ctx)) &&
noexcept(numeric::extract_uint<T, Radix, MinDigits, MaxDigits>::call(first, last, attr))
)
{
x4::skip_over(first, last, ctx);
return numeric::extract_uint<T, Radix, MinDigits, MaxDigits>::call(first, last, attr);
auto it = first;
x4::skip_over(it, last, ctx);
bool const ok = numeric::extract_uint<T, Radix, MinDigits, MaxDigits>::call(it, last, attr);
if (ok) first = it;
return ok;
}

[[nodiscard]] static std::string get_x4_info()
Expand Down
3 changes: 3 additions & 0 deletions include/iris/x4/operator/alternative.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ struct alternative : binary_parser<Left, Right, alternative<Left, Right>>
public:
using binary_parser<Left, Right, alternative>::binary_parser;

// unused_type attribute
template<std::forward_iterator It, std::sentinel_for<It> Se, class Context, X4UnusedAttribute UnusedAttr>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& ctx, UnusedAttr const&) const
Expand All @@ -120,6 +121,7 @@ struct alternative : binary_parser<Left, Right, alternative<Left, Right>>
//
// You also should add test to `attribute.cpp`.

// Non-container attribute
template<std::forward_iterator It, std::sentinel_for<It> Se, class Context, X4NonUnusedAttribute Attr>
requires (!traits::X4Container<Attr>)
[[nodiscard]] constexpr bool
Expand Down Expand Up @@ -151,6 +153,7 @@ struct alternative : binary_parser<Left, Right, alternative<Left, Right>>
return false; // `attr` is untouched
}

// Container attribute
template<std::forward_iterator It, std::sentinel_for<It> Se, class Context, traits::X4Container ContainerAttr>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& ctx, ContainerAttr& attr) const
Expand Down
2 changes: 1 addition & 1 deletion include/iris/x4/operator/and_predicate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ struct and_predicate : unary_parser<Subject, and_predicate<Subject>>
is_nothrow_parsable_v<Subject, It, Se, Context, unused_type>
)
{
It it = first;
auto it = first;
return this->subject.parse(it, last, ctx, unused);
}
};
Expand Down
17 changes: 9 additions & 8 deletions include/iris/x4/operator/difference.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ struct difference : binary_parser<Left, Right, difference<Left, Right>>
parse(It& first, Se const& last, Context const& ctx, Attr& attr) const
{
// Try `Right`
It const orig_first = first;
if (this->right.parse(first, last, ctx, unused)) {
auto it = first;
if (this->right.parse(it, last, ctx, unused)) {
// `Right` succeeds, we fail.
first = orig_first;
// We don't need to advance the iterator on this situation.
return false;
}
if constexpr (has_context_v<Context, contexts::expectation_failure>) {
Expand All @@ -49,11 +49,12 @@ struct difference : binary_parser<Left, Right, difference<Left, Right>>
}
// `Right` failed, now try `Left` ------------------

// Rollback iterator
// This rolls back the iterator position, including the amount skipped by
// `Right`'s skipper (`x4::skip_over(...)`).
first = orig_first;
return this->left.parse(first, last, ctx, attr);
// Try `Left` on the original position, effectively reverting the amount
// skipped by `Right`'s skipper (`x4::skip_over(...)`).
it = first;
bool const ok = this->left.parse(it, last, ctx, attr);
if (ok) first = it;
return ok;
}
};

Expand Down
13 changes: 9 additions & 4 deletions include/iris/x4/primitive/eoi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <iris/x4/core/unused.hpp>

#include <iterator>
#include <type_traits>

namespace iris::x4 {

Expand All @@ -24,15 +25,19 @@ struct eoi_parser : parser<eoi_parser>
using attribute_type = unused_type;

template<std::forward_iterator It, std::sentinel_for<It> Se, class Context, X4Attribute Attr>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& ctx, Attr&) const
[[nodiscard]] static constexpr bool
parse(It& first, Se const& last, Context const& ctx, Attr&)
noexcept(
std::is_nothrow_copy_assignable_v<It> &&
noexcept(x4::skip_over(first, last, ctx)) &&
noexcept(first == last)
)
{
x4::skip_over(first, last, ctx);
return first == last;
auto it = first;
x4::skip_over(it, last, ctx);
bool const ok = it == last;
if (ok) first = it;
return ok;
}
};

Expand Down
26 changes: 16 additions & 10 deletions include/iris/x4/primitive/eol.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,32 @@ struct eol_parser : parser<eol_parser>
using attribute_type = unused_type;

template<std::forward_iterator It, std::sentinel_for<It> Se, class Context, X4Attribute Attr>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& ctx, Attr&) const
// TODO: noexcept
[[nodiscard]] static constexpr bool
parse(It& first, Se const& last, Context const& ctx, Attr&)
noexcept(
std::is_nothrow_copy_assignable_v<It> &&
noexcept(x4::skip_over(first, last, ctx)) &&
noexcept(first != last) &&
noexcept(*first == static_cast<std::iter_value_t<It>>('\r')) &&
noexcept(++first)
)
{
x4::skip_over(first, last, ctx);
It iter = first;
auto it = first;
x4::skip_over(it, last, ctx);
bool matched = false;

using iter_value_type = std::iter_value_t<It>;

if (iter != last && *iter == static_cast<iter_value_type>('\r')) {
if (it != last && *it == static_cast<iter_value_type>('\r')) {
matched = true;
++iter;
++it;
}
if (iter != last && *iter == static_cast<iter_value_type>('\n')) {
if (it != last && *it == static_cast<iter_value_type>('\n')) {
matched = true;
++iter;
++it;
}

if (matched) first = iter;
if (matched) first = it;
return matched;
}
};
Expand Down
Loading
Loading