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
24 changes: 19 additions & 5 deletions include/iris/x4/rule.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

namespace iris::x4 {

template<class RuleID, X4Attribute Attr = unused_type, bool ForceAttribute = false>
template<class RuleID, class RuleAttr = unused_type, bool ForceAttribute = false>
struct rule;

namespace detail {
Expand Down Expand Up @@ -385,12 +385,12 @@ concept RuleAttrCompatible =

} // detail

template<class RuleID, X4Attribute RuleAttr, bool ForceAttr>
template<class RuleID, class RuleAttr, bool ForceAttr>
struct rule : parser<rule<RuleID, RuleAttr, ForceAttr>>
{
static_assert(X4Attribute<RuleAttr>);
static_assert(X4UnusedAttribute<RuleAttr> || !std::is_const_v<RuleAttr>, "Rule attribute cannot be const qualified");
static_assert(!std::is_same_v<std::remove_const_t<RuleAttr>, unused_container_type>, "`rule` with `unused_container_type` is not supported");
// This type MUST be constructible with incomplete types.
// Do NOT add `static_assert`s or other constructs that cause eager
// instantiation of `RuleAttr` within this class body.

using id = RuleID;
using attribute_type = RuleAttr;
Expand Down Expand Up @@ -419,6 +419,7 @@ struct rule : parser<rule<RuleID, RuleAttr, ForceAttr>>
parse(It& first, Se const& last, Context const& ctx, Exposed& exposed_attr) const
// never noexcept; requires very complex implementation details
{
check_invariants();
static_assert(has_attribute, "A rule must have an attribute. Check your rule definition.");

// Remove the `_rule_var` context. This makes the actual `context` type passed to
Expand Down Expand Up @@ -476,6 +477,7 @@ struct rule : parser<rule<RuleID, RuleAttr, ForceAttr>>
parse(It& first, Se const& last, Context const& ctx, unused_type const&) const
// never noexcept; requires very complex implementation details
{
check_invariants();
// make sure we pass exactly the rule attribute type
attribute_type no_attr; // default-initialize

Expand All @@ -497,6 +499,7 @@ struct rule : parser<rule<RuleID, RuleAttr, ForceAttr>>
>
)
{
check_invariants();
return {as_parser(std::forward<RHS>(rhs)), name};
}

Expand All @@ -511,6 +514,7 @@ struct rule : parser<rule<RuleID, RuleAttr, ForceAttr>>
>
)
{
check_invariants();
return {as_parser(std::forward<RHS>(rhs)), name};
}

Expand All @@ -530,6 +534,7 @@ struct rule : parser<rule<RuleID, RuleAttr, ForceAttr>>
>
)
{
check_invariants();
return {as_parser(std::forward<RHS>(rhs)), name};
}

Expand All @@ -544,8 +549,17 @@ struct rule : parser<rule<RuleID, RuleAttr, ForceAttr>>
>
)
{
check_invariants();
return {as_parser(std::forward<RHS>(rhs)), name};
}

private:
static constexpr void check_invariants() noexcept
{
static_assert(X4Attribute<RuleAttr>);
static_assert(X4UnusedAttribute<RuleAttr> || !std::is_const_v<RuleAttr>, "Rule attribute cannot be const qualified");
static_assert(!std::is_same_v<std::remove_const_t<RuleAttr>, unused_container_type>, "`rule` with `unused_container_type` is not supported");
}
};

namespace detail {
Expand Down
7 changes: 7 additions & 0 deletions test/x4/rule1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@
#include <iris/x4/operator/sequence.hpp>
#include <iris/x4/operator/kleene.hpp>

TEST_CASE("rule: constructible with incomplete type")
{
struct incomplete_type;
[[maybe_unused]] constexpr x4::rule<struct incomplete_type_id, incomplete_type, false> incomplete_type_rule_a{};
[[maybe_unused]] constexpr x4::rule<struct incomplete_type_id, incomplete_type, true> incomplete_type_rule_b{};
}

TEST_CASE("rule1")
{
using namespace x4::standard;
Expand Down
Loading