choice.hpp
Go to the documentation of this file.
1 // Copyright (C) 2020-2023 Jonathan Müller and lexy contributors
2 // SPDX-License-Identifier: BSL-1.0
3 
4 #ifndef LEXY_DSL_CHOICE_HPP_INCLUDED
5 #define LEXY_DSL_CHOICE_HPP_INCLUDED
6 
7 #include <lexy/_detail/tuple.hpp>
8 #include <lexy/dsl/base.hpp>
9 #include <lexy/error.hpp>
10 
11 namespace lexy
12 {
14 {
15  static LEXY_CONSTEVAL auto name()
16  {
17  return "exhausted choice";
18  }
19 };
20 } // namespace lexy
21 
22 namespace lexyd
23 {
24 template <typename... R>
25 struct _chc
26 // Only make it a branch rule if it doesn't have an unconditional branch.
27 // A choice rule with an unconditional branch is itself an unconditional branch, which is most
28 // likely a bug.
29 : std::conditional_t<(lexy::is_unconditional_branch_rule<R> || ...), rule_base, branch_base>
30 {
31  static constexpr auto _any_unconditional = (lexy::is_unconditional_branch_rule<R> || ...);
32 
33  template <typename Reader, typename Indices = lexy::_detail::make_index_sequence<sizeof...(R)>>
34  struct bp;
35  template <typename Reader, std::size_t... Idx>
36  struct bp<Reader, lexy::_detail::index_sequence<Idx...>>
37  {
38  template <typename Rule>
40 
42  std::size_t branch_idx;
43 
44  template <typename ControlBlock>
45  constexpr auto try_parse(const ControlBlock* cb, const Reader& reader)
46  -> std::conditional_t<_any_unconditional, std::true_type, bool>
47  {
48  auto try_r = [&](std::size_t idx, auto& parser) {
49  if (!parser.try_parse(cb, reader))
50  return false;
51 
52  branch_idx = idx;
53  return true;
54  };
55 
56  // Need to try each possible branch.
57  auto found_branch = (try_r(Idx, r_parsers.template get<Idx>()) || ...);
58  if constexpr (_any_unconditional)
59  {
60  LEXY_ASSERT(found_branch,
61  "it is unconditional, but we still haven't found a rule?!");
62  return {};
63  }
64  else
65  {
66  return found_branch;
67  }
68  }
69 
70  template <typename Context>
71  constexpr void cancel(Context& context)
72  {
73  // Need to cancel all branches.
74  (r_parsers.template get<Idx>().cancel(context), ...);
75  }
76 
77  template <typename NextParser, typename Context, typename... Args>
78  LEXY_PARSER_FUNC bool finish(Context& context, Reader& reader, Args&&... args)
79  {
80  // Need to call finish on the selected branch, and cancel on all others before that.
81  auto result = false;
82  (void)((Idx == branch_idx
83  ? (result
84  = r_parsers.template get<Idx>()
85  .template finish<NextParser>(context, reader, LEXY_FWD(args)...),
86  true)
87  : (r_parsers.template get<Idx>().cancel(context), false))
88  || ...);
89  return result;
90  }
91  };
92 
93  template <typename NextParser>
94  struct p
95  {
96  template <typename Context, typename Reader, typename... Args>
97  LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader, Args&&... args)
98  {
99  auto result = false;
100  auto try_r = [&](auto&& parser) {
101  if (!parser.try_parse(context.control_block, reader))
102  {
103  parser.cancel(context);
104  return false;
105  }
106 
107  // LEXY_FWD(args) will break MSVC builds targeting C++17.
108  result = parser.template finish<NextParser>(context, reader,
109  static_cast<Args&&>(args)...);
110  return true;
111  };
112 
113  // Try to parse each branch in order.
114  auto found_branch = (try_r(lexy::branch_parser_for<R, Reader>{}) || ...);
115  if constexpr (_any_unconditional)
116  {
117  LEXY_ASSERT(found_branch,
118  "it is unconditional, but we still haven't found a rule?!");
119  return result;
120  }
121  else
122  {
123  if (found_branch)
124  return result;
125 
126  auto err = lexy::error<Reader, lexy::exhausted_choice>(reader.position());
127  context.on(_ev::error{}, err);
128  return false;
129  }
130  }
131  };
132 };
133 
134 template <typename R, typename S>
135 constexpr auto operator|(R, S)
136 {
137  static_assert(lexy::is_branch_rule<R>, "choice requires a branch condition");
138  static_assert(lexy::is_branch_rule<S>, "choice requires a branch condition");
139  return _chc<R, S>{};
140 }
141 template <typename... R, typename S>
142 constexpr auto operator|(_chc<R...>, S)
143 {
144  static_assert(lexy::is_branch_rule<S>, "choice requires a branch condition");
145  return _chc<R..., S>{};
146 }
147 template <typename R, typename... S>
148 constexpr auto operator|(R, _chc<S...>)
149 {
150  static_assert(lexy::is_branch_rule<R>, "choice requires a branch condition");
151  return _chc<R, S...>{};
152 }
153 template <typename... R, typename... S>
155 {
156  return _chc<R..., S...>{};
157 }
158 } // namespace lexyd
159 
160 #endif // LEXY_DSL_CHOICE_HPP_INCLUDED
161 
LEXY_CONSTEVAL
#define LEXY_CONSTEVAL
Definition: config.hpp:90
lexy::_detail::index_sequence
integer_sequence< std::size_t, Indices... > index_sequence
Definition: integer_sequence.hpp:17
tuple.hpp
lexyd::_chc::_any_unconditional
static constexpr auto _any_unconditional
Definition: choice.hpp:31
lexyd::_chc::bp< Reader, lexy::_detail::index_sequence< Idx... > >::finish
LEXY_PARSER_FUNC bool finish(Context &context, Reader &reader, Args &&... args)
Definition: choice.hpp:78
lexy::branch_parser_for
typename BranchRule::template bp< Reader > branch_parser_for
Definition: dsl/base.hpp:103
lexyd::_chc::bp< Reader, lexy::_detail::index_sequence< Idx... > >::rp
lexy::branch_parser_for< Rule, Reader > rp
Definition: choice.hpp:39
LEXY_FWD
#define LEXY_FWD(...)
Definition: config.hpp:22
lexyd::_chc::bp
Definition: choice.hpp:34
lexy
Definition: any_ref.hpp:12
lexy::_detail::make_index_sequence
typename _make_index_sequence< Size >::type make_index_sequence
Definition: integer_sequence.hpp:55
detail::void
j template void())
Definition: json.hpp:4893
lexy::error
Generic failure.
Definition: error.hpp:14
lexy::parse_events::error
Definition: dsl/base.hpp:55
lexyd::operator|
constexpr auto operator|(R, S)
Definition: choice.hpp:135
lexy::_detail::tuple
Definition: tuple.hpp:60
lexy::exhausted_choice
Definition: choice.hpp:13
LEXY_PARSER_FUNC
#define LEXY_PARSER_FUNC
Definition: dsl/base.hpp:95
lexyd::_chc::bp< Reader, lexy::_detail::index_sequence< Idx... > >::cancel
constexpr void cancel(Context &context)
Definition: choice.hpp:71
base.hpp
lexyd::_chc
Definition: choice.hpp:25
lexyd::_chc::p::parse
static LEXY_PARSER_FUNC bool parse(Context &context, Reader &reader, Args &&... args)
Definition: choice.hpp:97
lexyd::_chc::bp< Reader, lexy::_detail::index_sequence< Idx... > >::r_parsers
lexy::_detail::tuple< rp< R >... > r_parsers
Definition: choice.hpp:41
lexy::exhausted_choice::name
static LEXY_CONSTEVAL auto name()
Definition: choice.hpp:15
lexyd::_chc::bp< Reader, lexy::_detail::index_sequence< Idx... > >::try_parse
constexpr auto try_parse(const ControlBlock *cb, const Reader &reader) -> std::conditional_t< _any_unconditional, std::true_type, bool >
Definition: choice.hpp:45
lexyd
Definition: trace.hpp:22
lexyd::_chc::bp< Reader, lexy::_detail::index_sequence< Idx... > >::branch_idx
std::size_t branch_idx
Definition: choice.hpp:42
LEXY_ASSERT
#define LEXY_ASSERT(Expr, Msg)
Definition: assert.hpp:37
lexyd::_chc::p
Definition: choice.hpp:94
error.hpp


behaviortree_cpp_v4
Author(s): Davide Faconti
autogenerated on Fri Jun 28 2024 02:20:07