grammar.hpp
Go to the documentation of this file.
1 // Copyright (C) 2020-2024 Jonathan Müller and lexy contributors
2 // SPDX-License-Identifier: BSL-1.0
3 
4 #ifndef LEXY_GRAMMAR_HPP_INCLUDED
5 #define LEXY_GRAMMAR_HPP_INCLUDED
6 
7 #include <cstdint>
11 #include <lexy/callback/base.hpp>
12 
13 //=== rule ===//
14 // We use a shorthand namespace to decrease symbol size.
15 namespace lexyd
16 {
17 struct rule_base
18 {};
19 
21 {};
22 
24 {};
25 
27 {};
29 {};
30 struct _lset_base
31 {};
32 struct _lit_base
33 {};
34 struct _sep_base
35 {};
36 
38 {};
39 } // namespace lexyd
40 
41 namespace lexy
42 {
43 namespace dsl = lexyd;
44 
45 template <typename T>
46 constexpr bool is_rule = std::is_base_of_v<dsl::rule_base, T>;
47 
48 template <typename T>
49 constexpr bool is_branch_rule = std::is_base_of_v<dsl::branch_base, T>;
50 template <typename T>
51 constexpr bool is_unconditional_branch_rule = std::is_base_of_v<dsl::unconditional_branch_base, T>;
52 
53 template <typename T>
54 constexpr bool is_token_rule = std::is_base_of_v<dsl::_token_base, T>;
55 
56 template <typename T>
57 constexpr bool is_char_class_rule = std::is_base_of_v<dsl::_char_class_base, T>;
58 template <typename T>
59 constexpr bool is_literal_rule = std::is_base_of_v<dsl::_lit_base, T>;
60 template <typename T>
61 constexpr bool is_literal_set_rule = std::is_base_of_v<dsl::_lset_base, T>;
62 
63 template <typename T>
64 constexpr auto is_separator = std::is_base_of_v<lexy::dsl::_sep_base, T>;
65 
66 template <typename T>
67 constexpr auto is_operation = std::is_base_of_v<lexy::dsl::_operation_base, T>;
68 
69 template <typename... T>
70 constexpr bool _require_branch_rule = (is_branch_rule<T> && ...);
71 } // namespace lexy
72 
73 #define LEXY_REQUIRE_BRANCH_RULE(Rule, Name) \
74  static_assert(lexy::_require_branch_rule<Rule>, Name \
75  " requires a branch condition." \
76  " You may need to use `>>` to specify the condition that is used for dispatch." \
77  " See https://lexy.foonathan.net/learn/branching/ for more information.")
78 
79 //=== predefined_token_kind ===//
80 namespace lexy
81 {
82 enum predefined_token_kind : std::uint_least16_t
83 {
84  unknown_token_kind = UINT_LEAST16_MAX,
85 
86  error_token_kind = UINT_LEAST16_MAX - 1,
87  whitespace_token_kind = UINT_LEAST16_MAX - 2,
88  any_token_kind = UINT_LEAST16_MAX - 3,
89 
90  literal_token_kind = UINT_LEAST16_MAX - 4,
91  position_token_kind = UINT_LEAST16_MAX - 5,
92  eof_token_kind = UINT_LEAST16_MAX - 6,
93 
94  identifier_token_kind = UINT_LEAST16_MAX - 7,
95  digits_token_kind = UINT_LEAST16_MAX - 8,
96 
98 };
99 
100 template <typename T>
101 constexpr const char* token_kind_name(const T&) noexcept
102 {
103  return "token";
104 }
105 constexpr const char* token_kind_name(predefined_token_kind kind) noexcept
106 {
107  switch (kind)
108  {
109  case unknown_token_kind:
110  return "token";
111 
112  case error_token_kind:
113  return "error token";
115  return "whitespace";
116  case any_token_kind:
117  return "any";
118 
119  case literal_token_kind:
120  return "literal";
121  case position_token_kind:
122  return "position";
123  case eof_token_kind:
124  return "EOF";
125 
127  return "identifier";
128  case digits_token_kind:
129  return "digits";
130  }
131 
132  return ""; // unreachable
133 }
134 
136 template <typename TokenRule>
138 
139 template <typename TokenRule>
140 constexpr auto token_kind_of<const TokenRule> = token_kind_of<TokenRule>;
141 } // namespace lexy
142 
143 //=== production ===//
144 namespace lexy
145 {
146 template <typename Production>
147 using production_rule = LEXY_DECAY_DECLTYPE(Production::rule);
148 
149 template <typename Production>
150 constexpr bool is_production = _detail::is_detected<production_rule, Production>;
151 
157 {};
158 
159 template <typename Production>
160 constexpr bool is_token_production = std::is_base_of_v<token_production, Production>;
161 
166 {};
167 
168 template <typename Production>
169 constexpr bool is_transparent_production = std::is_base_of_v<transparent_production, Production>;
170 
171 template <typename Production>
173 {
174  return _detail::type_name<Production>();
175 }
176 
177 template <typename Production>
179 
180 template <typename EntryProduction>
182 {
183  if constexpr (_detail::is_detected<_detect_max_recursion_depth, EntryProduction>)
185  else
186  return 1024; // Arbitrary power of two.
187 }
188 
189 template <typename T>
190 using _enable_production_or_operation = std::enable_if_t<is_production<T> || is_operation<T>>;
191 
193 {
194  const char* const* id;
195  const char* name;
196  bool is_token;
198 
199  template <typename Production, typename = _enable_production_or_operation<Production>>
200  constexpr production_info(Production)
201  : id(_detail::type_id<Production>()), name(production_name<Production>()),
202  is_token(is_token_production<Production>),
204  {}
205 
206  friend constexpr bool operator==(production_info lhs, production_info rhs)
207  {
208  return lhs.id == rhs.id;
209  }
210  friend constexpr bool operator!=(production_info lhs, production_info rhs)
211  {
212  return !(lhs == rhs);
213  }
214 };
215 } // namespace lexy
216 
217 namespace lexy
218 {
219 template <typename Production>
221 
222 template <typename Production>
223 constexpr auto _production_defines_whitespace
224  = lexy::_detail::is_detected<_detect_whitespace, Production>;
225 
226 template <typename Production, typename WhitespaceProduction>
228 {
229  if constexpr (_production_defines_whitespace<Production>)
230  {
231  // We have whitespace defined in the production.
232  return Production::whitespace;
233  }
234  else if constexpr (_production_defines_whitespace<WhitespaceProduction>)
235  {
236  // We have whitespace defined in the whitespace production.
238  }
239 
240  // If we didn't have any cases, function returns void.
241 }
242 template <typename Production, typename WhitespaceProduction>
243 using production_whitespace = decltype(_production_whitespace<Production, WhitespaceProduction>());
244 } // namespace lexy
245 
246 namespace lexy
247 {
248 template <typename To, typename... Args>
249 inline constexpr auto _is_convertible = false;
250 template <typename To, typename Arg>
251 inline constexpr auto _is_convertible<To, Arg> = std::is_convertible_v<Arg, To>;
252 template <>
253 inline constexpr auto _is_convertible<void> = true;
254 
255 template <typename ParseState, typename Production>
256 using _detect_value_of =
257  // We're testing a non-const ParseState on purpose, to handle cases where a user forgot to const
258  // qualify value_of() (it causes a hard error instead of going to ::value).
259  typename decltype(LEXY_DECLVAL(ParseState&).value_of(Production{}))::return_type;
260 
261 template <typename Production>
263 
264 template <typename Production, typename Sink>
266 {
267  Sink _sink;
268 
269  using return_type = typename Sink::return_type;
270 
271  LEXY_FORCE_INLINE constexpr _sfinae_sink(Production, Sink&& sink) : _sink(LEXY_MOV(sink)) {}
272 
273  template <typename... Args>
274  LEXY_FORCE_INLINE constexpr void operator()(Args&&... args)
275  {
276  if constexpr (!is_sink_callback_for<Sink, Args&&...>)
277  // We're attempting to call a sink of Production with the given arguments, but no such
278  // overload exists.
279  static_assert(_detail::error<Production, Args...>,
280  "missing value sink callback overload for production");
281  _sink(LEXY_FWD(args)...);
282  }
283 
284  LEXY_FORCE_INLINE constexpr auto finish() &&
285  {
286  return LEXY_MOV(_sink).finish();
287  }
288 };
289 
290 template <typename Production, typename ParseState = void>
291 constexpr bool production_has_value_callback
292  = lexy::_detail::is_detected<_detect_value_of, ParseState, Production>
293  || lexy::_detail::is_detected<_detect_value, Production>;
294 
295 template <typename Production, typename ParseState = void>
297 {
298  static constexpr auto _get_value([[maybe_unused]] ParseState* state)
299  {
300  if constexpr (lexy::_detail::is_detected<_detect_value_of, ParseState, Production>)
301  return state->value_of(Production{});
302  else
303  return Production::value;
304  }
305  using _type = decltype(_get_value(nullptr));
306 
307  static auto _return_type_callback()
308  {
309  if constexpr (lexy::is_callback<_type>)
310  return _get_value(nullptr);
311  else if constexpr (lexy::is_sink<_type, std::add_lvalue_reference_t<ParseState>>)
312  return _get_value(nullptr).sink(LEXY_DECLVAL(ParseState&));
313  else
314  return _get_value(nullptr).sink();
315  }
316 
317 public:
318  constexpr explicit production_value_callback(ParseState* state) : _state(state) {}
319 
320  template <typename State = ParseState, typename = std::enable_if_t<std::is_void_v<State>>>
321  constexpr production_value_callback() : _state(nullptr)
322  {}
323  template <typename State = ParseState,
324  typename = std::enable_if_t<std::is_same_v<State, ParseState>>>
325  constexpr explicit production_value_callback(State& state) : _state(&state)
326  {}
327 
328  using return_type = typename decltype(_return_type_callback())::return_type;
329 
330  constexpr auto sink() const
331  {
332  if constexpr (lexy::is_sink<_type, std::add_lvalue_reference_t<ParseState>>)
333  {
334  return _sfinae_sink(Production{}, _get_value(_state).sink(*_state));
335  }
336  else
337  {
338  // We're attempting to obtain a sink for Production, but none was provided.
339  // As Production uses a list rule, it needs a sink.
340  static_assert(lexy::is_sink<_type>, "missing value sink for production");
341  return _sfinae_sink(Production{}, _get_value(_state).sink());
342  }
343  }
344 
345  template <typename... Args>
346  constexpr return_type operator()(Args&&... args) const
347  {
348  if constexpr (lexy::is_callback_with_state_for<_type, ParseState, Args&&...>
349  && !std::is_void_v<ParseState>)
350  {
351  return _get_value(_state)[*_state](LEXY_FWD(args)...);
352  }
353  else if constexpr (lexy::is_callback_for<_type, Args&&...>)
354  {
355  return _get_value(_state)(LEXY_FWD(args)...);
356  }
357  else if constexpr ((lexy::is_sink<_type> //
358  || lexy::is_sink<_type, std::add_lvalue_reference_t<ParseState>>) //
359  &&_is_convertible<return_type, Args&&...>)
360  {
361  // We don't have a matching callback, but it is a single argument that has
362  // the correct type already, or we return void and have no arguments.
363  // Assume it came from the list sink and return the value without invoking a
364  // callback.
365  return (LEXY_FWD(args), ...);
366  }
367  else
368  {
369  // We're attempting to call the callback of Production with the given arguments, but no
370  // such overload exists.
371  static_assert(_detail::error<Production, Args...>,
372  "missing value callback overload for production");
373  }
374  }
375 
376 private:
377  ParseState* _state;
378 };
379 } // namespace lexy
380 
381 #endif // LEXY_GRAMMAR_HPP_INCLUDED
lexy::production_value_callback::production_value_callback
constexpr production_value_callback(State &state)
Definition: grammar.hpp:325
detect.hpp
LEXY_MOV
#define LEXY_MOV(...)
Definition: config.hpp:29
lexy::eof_token_kind
@ eof_token_kind
Definition: grammar.hpp:92
LEXY_CONSTEVAL
#define LEXY_CONSTEVAL
Definition: config.hpp:98
lexy::production_info::production_info
constexpr production_info(Production)
Definition: grammar.hpp:200
lexy::any_token_kind
@ any_token_kind
Definition: grammar.hpp:88
lexyd::branch_base
Definition: grammar.hpp:20
lexy::unknown_token_kind
@ unknown_token_kind
Definition: grammar.hpp:84
base.hpp
lexy::is_operation
constexpr auto is_operation
Definition: grammar.hpp:67
lexy::_production_defines_whitespace
constexpr auto _production_defines_whitespace
Definition: grammar.hpp:224
lexy::production_value_callback::_type
decltype(_get_value(nullptr)) _type
Definition: grammar.hpp:305
config.hpp
lexyd::_sep_base
Definition: grammar.hpp:34
lexy::_detect_value
decltype(Production::value) _detect_value
Definition: grammar.hpp:262
lexy::production_info::id
const char *const * id
Definition: grammar.hpp:194
lexy::position_token_kind
@ position_token_kind
Definition: grammar.hpp:91
lexy::production_value_callback::production_value_callback
constexpr production_value_callback(ParseState *state)
Definition: grammar.hpp:318
lexy::_detect_max_recursion_depth
decltype(Production::max_recursion_depth) _detect_max_recursion_depth
Definition: grammar.hpp:178
LEXY_FWD
#define LEXY_FWD(...)
Definition: config.hpp:30
lexy::_is_convertible< To, Arg >
constexpr auto _is_convertible< To, Arg >
Definition: grammar.hpp:251
lexy::production_has_value_callback
constexpr bool production_has_value_callback
Definition: grammar.hpp:292
lexy::production_info::name
const char * name
Definition: grammar.hpp:195
magic_enum::detail::value
constexpr E value(std::size_t i) noexcept
Definition: magic_enum.hpp:664
lexy::production_info::operator!=
constexpr friend bool operator!=(production_info lhs, production_info rhs)
Definition: grammar.hpp:210
lexy::production_value_callback::_state
ParseState * _state
Definition: grammar.hpp:377
lexy
Definition: any_ref.hpp:12
lexy::predefined_token_kind
predefined_token_kind
Definition: grammar.hpp:82
lexy::token_kind_of< const TokenRule >
constexpr auto token_kind_of< const TokenRule >
Definition: grammar.hpp:140
lexy::is_production
constexpr bool is_production
Definition: grammar.hpp:150
lexy::literal_token_kind
@ literal_token_kind
Definition: grammar.hpp:90
lexy::_is_convertible< void >
constexpr auto _is_convertible< void >
Definition: grammar.hpp:253
lexy::production_info::is_token
bool is_token
Definition: grammar.hpp:196
lexy::is_literal_set_rule
constexpr bool is_literal_set_rule
Definition: grammar.hpp:61
lexyd::_operation_base
Definition: grammar.hpp:37
lexy::is_sink
constexpr bool is_sink
Definition: callback/base.hpp:50
lexy::is_separator
constexpr auto is_separator
Definition: grammar.hpp:64
lexy::is_branch_rule
constexpr bool is_branch_rule
Definition: grammar.hpp:49
lexy::_enable_production_or_operation
std::enable_if_t< is_production< T >||is_operation< T > > _enable_production_or_operation
Definition: grammar.hpp:190
lexy::whitespace_token_kind
@ whitespace_token_kind
Definition: grammar.hpp:87
lexy::_detail::type_id
constexpr const char *const * type_id()
Definition: type_name.hpp:112
lexy::production_value_callback
Definition: grammar.hpp:296
lexy::_sfinae_sink::_sink
Sink _sink
Definition: grammar.hpp:267
lexy::production_value_callback::_get_value
static constexpr auto _get_value([[maybe_unused]] ParseState *state)
Definition: grammar.hpp:298
lexy::_sfinae_sink::operator()
constexpr LEXY_FORCE_INLINE void operator()(Args &&... args)
Definition: grammar.hpp:274
lexy::production_info::operator==
constexpr friend bool operator==(production_info lhs, production_info rhs)
Definition: grammar.hpp:206
lexyd::unconditional_branch_base
Definition: grammar.hpp:23
lexy::production_info::is_transparent
bool is_transparent
Definition: grammar.hpp:197
lexy::token_production
Definition: grammar.hpp:156
lexyd::_char_class_base
Definition: grammar.hpp:28
lexy::production_value_callback::_return_type_callback
static auto _return_type_callback()
Definition: grammar.hpp:307
lexy::_sfinae_sink::_sfinae_sink
constexpr LEXY_FORCE_INLINE _sfinae_sink(Production, Sink &&sink)
Definition: grammar.hpp:271
lexyd::_lset_base
Definition: grammar.hpp:30
LEXY_DECAY_DECLTYPE
#define LEXY_DECAY_DECLTYPE(...)
Definition: config.hpp:34
lexyd::rule_base
Definition: grammar.hpp:17
lexy::_sfinae_sink::finish
constexpr LEXY_FORCE_INLINE auto finish() &&
Definition: grammar.hpp:284
lexy::_detect_whitespace
decltype(Production::whitespace) _detect_whitespace
Definition: grammar.hpp:220
lexy::digits_token_kind
@ digits_token_kind
Definition: grammar.hpp:95
lexy::production_value_callback::return_type
typename decltype(_return_type_callback())::return_type return_type
Definition: grammar.hpp:328
lexy::production_rule
LEXY_DECAY_DECLTYPE(Production::rule) production_rule
Definition: grammar.hpp:147
lexy::token_kind_name
constexpr const char * token_kind_name(const T &) noexcept
Definition: grammar.hpp:101
lexy::error_token_kind
@ error_token_kind
Definition: grammar.hpp:86
lexy::production_whitespace
decltype(_production_whitespace< Production, WhitespaceProduction >()) production_whitespace
Definition: grammar.hpp:243
lexyd::_token_base
Definition: grammar.hpp:26
lexy::is_rule
constexpr bool is_rule
Definition: grammar.hpp:46
lexy::transparent_production
Definition: grammar.hpp:165
lexy::_production_whitespace
auto _production_whitespace()
Definition: grammar.hpp:227
LEXY_FORCE_INLINE
#define LEXY_FORCE_INLINE
Definition: config.hpp:171
lexy::production_value_callback::sink
constexpr auto sink() const
Definition: grammar.hpp:330
lexy::_unicode_db::whitespace
@ whitespace
Definition: unicode_database.hpp:69
lexy::identifier_token_kind
@ identifier_token_kind
Definition: grammar.hpp:94
lexy::max_recursion_depth
LEXY_CONSTEVAL std::size_t max_recursion_depth()
Definition: grammar.hpp:181
lexy::is_token_rule
constexpr bool is_token_rule
Definition: grammar.hpp:54
lexy::is_unconditional_branch_rule
constexpr bool is_unconditional_branch_rule
Definition: grammar.hpp:51
lexy::_require_branch_rule
constexpr bool _require_branch_rule
Definition: grammar.hpp:70
lexy::_detect_value_of
typename decltype(LEXY_DECLVAL(ParseState &).value_of(Production{}))::return_type _detect_value_of
Definition: grammar.hpp:259
lexy::is_literal_rule
constexpr bool is_literal_rule
Definition: grammar.hpp:59
lexy::production_info
Definition: grammar.hpp:192
lexy::production_name
const LEXY_CONSTEVAL char * production_name()
Definition: grammar.hpp:172
lexy::_smallest_predefined_token_kind
@ _smallest_predefined_token_kind
Definition: grammar.hpp:97
type_name.hpp
LEXY_DECLVAL
#define LEXY_DECLVAL(...)
Definition: config.hpp:32
lexy::_sfinae_sink::return_type
typename Sink::return_type return_type
Definition: grammar.hpp:269
lexy::_is_convertible
constexpr auto _is_convertible
Definition: grammar.hpp:249
lexy::_sfinae_sink
Definition: grammar.hpp:265
lexyd::_lit_base
Definition: grammar.hpp:32
lexyd
Definition: trace.hpp:22
lexy::is_transparent_production
constexpr bool is_transparent_production
Definition: grammar.hpp:169
lexy::production_value_callback::operator()
constexpr return_type operator()(Args &&... args) const
Definition: grammar.hpp:346
lexy::is_char_class_rule
constexpr bool is_char_class_rule
Definition: grammar.hpp:57
lexy::is_token_production
constexpr bool is_token_production
Definition: grammar.hpp:160
lexy::token_kind_of
constexpr auto token_kind_of
Specialize to define the token kind of a rule.
Definition: grammar.hpp:137
lexy::production_value_callback::production_value_callback
constexpr production_value_callback()
Definition: grammar.hpp:321


behaviortree_cpp_v4
Author(s): Davide Faconti
autogenerated on Fri Nov 1 2024 02:20:51