expression.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_DSL_EXPRESSION_HPP_INCLUDED
5 #define LEXY_DSL_EXPRESSION_HPP_INCLUDED
6 
7 #include <lexy/action/base.hpp>
8 #include <lexy/dsl/base.hpp>
9 #include <lexy/dsl/literal.hpp>
10 #include <lexy/dsl/operator.hpp>
11 
12 // Expression parsing algorithm uses an adapted version of Pratt parsing, as described here:
13 // https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html
14 // In particular:
15 // * precedence specified implicitly by type type hierarchy
16 // * support for list and single precedence
17 // * support for operator groups that require additional parentheses
18 // * generate proper parse tree events
19 
20 //=== dsl ===//
21 namespace lexyd
22 {
25 {
26  static LEXY_CONSTEVAL auto name()
27  {
28  return "atom";
29  }
30 };
31 
33 template <typename... Operands>
35 {};
36 
37 struct infix_op_left : _operation_base // a ~ b ~ c == (a ~ b) ~ c
38 {};
39 struct infix_op_right : _operation_base // a ~ b ~ c == a ~ (b ~ c)
40 {};
41 struct infix_op_list : _operation_base // a ~ b ~ c kept as-is
42 {};
43 struct infix_op_single : _operation_base // a ~ b ~ c is an error
44 {};
45 
47 {};
48 
50 {};
51 } // namespace lexyd
52 
53 //=== implementation ===//
54 namespace lexy::_detail
55 {
57 {
58  unsigned group;
59  unsigned lhs, rhs;
60 
61  static constexpr auto left(unsigned group, unsigned level)
62  {
63  return binding_power{group, 2 * level, 2 * level + 1};
64  }
65  static constexpr auto right(unsigned group, unsigned level)
66  {
67  return binding_power{group, 2 * level + 1, 2 * level};
68  }
69  static constexpr auto prefix(unsigned group, unsigned level)
70  {
71  // prefix is sort of left-associative, so right side odd.
72  return binding_power{group, 0, 2 * level + 1};
73  }
74  static constexpr auto postfix(unsigned group, unsigned level)
75  {
76  // postfix is sort of right-associative, so left side odd.
77  return binding_power{group, 2 * level + 1, 0};
78  }
79 
80  constexpr bool is_valid() const
81  {
82  return lhs > 0 || rhs > 0;
83  }
84  constexpr bool is_infix() const
85  {
86  return lhs > 0 && rhs > 0;
87  }
88  constexpr bool is_postfix() const
89  {
90  return lhs > 0 && rhs == 0;
91  }
92  constexpr bool is_prefix() const
93  {
94  return lhs == 0 && rhs > 0;
95  }
96 };
97 
98 template <typename Operation>
99 constexpr binding_power get_binding_power(unsigned cur_group, unsigned cur_level)
100 {
101  if constexpr (std::is_base_of_v<lexyd::infix_op_left, Operation>
102  // We treat a list as left associative operator for simplicity here.
103  // It doesn't really matter, as it will only consider operators from the
104  // same operation anyway.
105  || std::is_base_of_v<lexyd::infix_op_list, Operation>
106  // For the purposes of error recovery, single is left associative.
107  || std::is_base_of_v<lexyd::infix_op_single, Operation>)
108  return binding_power::left(cur_group, cur_level);
109  else if constexpr (std::is_base_of_v<lexyd::infix_op_right, Operation>)
110  return binding_power::right(cur_group, cur_level);
111  else if constexpr (std::is_base_of_v<lexyd::prefix_op, Operation>)
112  return binding_power::prefix(cur_group, cur_level);
113  else if constexpr (std::is_base_of_v<lexyd::postfix_op, Operation>)
114  return binding_power::postfix(cur_group, cur_level);
115 }
116 
117 template <typename DestOperation>
119 {
120  static constexpr auto transition(lexyd::atom, unsigned cur_group, unsigned)
121  {
122  // Not found, return an invalid operator, but return the current group.
123  // This is the highest group encountered.
124  return binding_power{cur_group, 0, 0};
125  }
126  template <typename CurOperation>
127  static constexpr auto transition(CurOperation op, unsigned cur_group, unsigned cur_level)
128  {
129  // Normal operation: keep group the same, but increment level.
130  return get(op, cur_group, cur_level + 1);
131  }
132  template <typename... Operations>
133  static constexpr auto transition(lexyd::groups<Operations...>, unsigned cur_group,
134  unsigned cur_level)
135  {
136  auto result = binding_power{cur_group, 0, 0};
137  // Try to find the destination in each group.
138  // Before we transition, we increment the group to create a new one,
139  // afterwards we update group to the highest group encountered so far.
140  // That way, we don't re-use group numbers.
141  // Note that we don't increment the level, as that is handled by the overload above.
142  (void)((result = transition(Operations{}, cur_group + 1, cur_level),
143  cur_group = result.group, result.is_valid())
144  || ...);
145  return result;
146  }
147 
148  template <typename CurOperation>
149  static constexpr auto get(CurOperation, unsigned cur_group, unsigned cur_level)
150  {
151  if constexpr (std::is_same_v<DestOperation, CurOperation>)
152  return get_binding_power<CurOperation>(cur_group, cur_level);
153  else
154  return transition(typename CurOperation::operand{}, cur_group, cur_level);
155  }
156 };
157 
158 // Returns the binding power of an operator in an expression.
159 template <typename Expr, typename Operation>
160 constexpr auto binding_power_of(Operation)
161 {
162  return _binding_power_of<Operation>::transition(typename Expr::operation{}, 0, 0);
163 }
164 } // namespace lexy::_detail
165 
166 namespace lexy::_detail
167 {
168 template <typename Operation>
170 
171 template <typename... Operations>
173 {
174  template <typename T>
175  constexpr auto operator+(T) const
176  {
177  return operation_list<Operations..., T>{};
178  }
179  template <typename... T>
180  constexpr auto operator+(operation_list<T...>) const
181  {
182  return operation_list<Operations..., T...>{};
183  }
184 
185  static constexpr auto size = sizeof...(Operations);
186 
187  using ops = decltype((typename op_of<Operations>::op_literals{} + ... + op_lit_list{}));
188 
189  template <template <typename> typename Continuation, typename Context, typename Reader,
190  typename... Args>
191  static constexpr bool apply(Context& context, Reader& reader, parsed_operator<Reader> op,
192  Args&&... args)
193  {
194  auto result = false;
195 
196  auto cur_idx = std::size_t(0);
197  (void)((cur_idx <= op.idx && op.idx < cur_idx + op_of<Operations>::op_literals::size
198  ? (result
199  = Continuation<Operations>::parse(context, reader,
201  op.idx - cur_idx},
202  LEXY_FWD(args)...),
203  true)
204  : (cur_idx += op_of<Operations>::op_literals::size, false))
205  || ...);
206 
207  return result;
208  }
209 };
210 
211 template <bool Pre, unsigned MinBindingPower>
213 {
214  template <unsigned CurLevel>
215  static constexpr auto get(lexyd::atom)
216  {
217  return operation_list{};
218  }
219  template <unsigned CurLevel, typename... Operations>
220  static constexpr auto get(lexyd::groups<Operations...>)
221  {
222  return (get<CurLevel>(Operations{}) + ...);
223  }
224  template <unsigned CurLevel, typename Operation>
225  static constexpr auto get(Operation)
226  {
227  constexpr auto bp = get_binding_power<Operation>(0, CurLevel);
228 
229  auto tail = get<CurLevel + 1>(typename Operation::operand{});
230  constexpr auto is_prefix = std::is_base_of_v<lexyd::prefix_op, Operation>;
231  if constexpr (is_prefix == Pre
232  && ((is_prefix && bp.rhs >= MinBindingPower)
233  || (!is_prefix && bp.lhs >= MinBindingPower)))
234  return tail + Operation{};
235  else
236  return tail;
237  }
238 };
239 
240 // prefix operations
241 template <typename Expr, unsigned MinBindingPower>
242 using pre_operation_list_of = decltype(_operation_list_of<true, MinBindingPower>::template get<1>(
243  typename Expr::operation{}));
244 
245 // infix and postfix operations
246 template <typename Expr, unsigned MinBindingPower>
247 using post_operation_list_of = decltype(_operation_list_of<false, MinBindingPower>::template get<1>(
248  typename Expr::operation{}));
249 } // namespace lexy::_detail
250 
251 //=== expression rule ===//
252 namespace lexyd
253 {
254 template <typename RootOperation>
255 struct _expr : rule_base
256 {
257  struct _state
258  {
259  unsigned cur_group = 0;
260  unsigned cur_nesting_level = 0;
261  };
262 
263  template <typename Operation>
265  {
266  struct _op_cont
267  {
268  template <typename Context, typename Reader, typename... Args>
269  LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader, _state& state,
270  Args&&... op_args)
271  {
272  using namespace lexy::_detail;
273 
274  constexpr auto value_type_void = std::is_void_v<typename Context::value_type>;
275  constexpr auto binding_power
276  = binding_power_of<typename Context::production>(Operation{});
277 
278  if constexpr (std::is_base_of_v<infix_op_list, Operation>)
279  {
280  // We need to handle a list infix operator specially,
281  // and parse an arbitrary amount of lhs.
282  // For that, we use a loop and a sink.
283  auto sink = context.value_callback().sink();
284 
285  // We need to pass the initial lhs to the sink.
286  if constexpr (!value_type_void)
287  sink(*LEXY_MOV(context.value));
288  context.value = {};
289 
290  // As well as the operator we've already got.
291  sink(LEXY_FWD(op_args)...);
292 
293  auto result = true;
294  while (true)
295  {
296  // Parse (another) value.
297  if (!_parse<binding_power.rhs>(context, reader, state))
298  {
299  result = false;
300  break;
301  }
302 
303  if constexpr (!value_type_void)
304  sink(*LEXY_MOV(context.value));
305  context.value = {};
306 
307  using op_rule = op_of<Operation>;
308  auto op = parse_operator<typename op_rule::op_literals>(reader);
309  if (op.idx >= op_rule::op_literals::size)
310  {
311  // The list ends at this point.
312  reader.reset(op.cur);
313  break;
314  }
315 
316  // Need to finish the operator properly, by passing it to the sink.
317  if (!op_rule::template op_finish<lexy::sink_parser>(context, reader, op,
318  sink))
319  {
320  result = false;
321  break;
322  }
323  }
324 
325  // We store the final value of the sink no matter the parse result.
326  if constexpr (value_type_void)
327  {
328  LEXY_MOV(sink).finish();
329  context.value.emplace();
330  }
331  else
332  {
333  context.value.emplace(LEXY_MOV(sink).finish());
334  }
335 
336  // If we've failed at any point, propagate failure now.
337  if (!result)
338  return false;
339  }
340  else if constexpr (binding_power.is_prefix())
341  {
342  if (!_parse<binding_power.rhs>(context, reader, state))
343  return false;
344 
345  auto value = LEXY_MOV(context.value);
346  context.value = {};
347 
348  if constexpr (value_type_void)
349  context.value.emplace_result(context.value_callback(),
350  LEXY_FWD(op_args)...);
351  else
352  context.value.emplace_result(context.value_callback(), LEXY_FWD(op_args)...,
353  *LEXY_MOV(value));
354  }
355  else if constexpr (binding_power.is_infix())
356  {
357  auto lhs = LEXY_MOV(context.value);
358  context.value = {};
359 
360  if (!_parse<binding_power.rhs>(context, reader, state))
361  {
362  // Put it back, so we can properly recover.
363  context.value = LEXY_MOV(lhs);
364  return false;
365  }
366 
367  auto rhs = LEXY_MOV(context.value);
368  context.value = {};
369 
370  if constexpr (value_type_void)
371  context.value.emplace_result(context.value_callback(),
372  LEXY_FWD(op_args)...);
373  else
374  context.value.emplace_result(context.value_callback(), *LEXY_MOV(lhs),
375  LEXY_FWD(op_args)..., *LEXY_MOV(rhs));
376 
377  if constexpr (std::is_base_of_v<infix_op_single, Operation>)
378  {
379  using op_rule = op_of<Operation>;
380  auto op = parse_operator<typename op_rule::op_literals>(reader);
381  if (op.idx < op_rule::op_literals::size)
382  {
383  using tag = typename Context::production::operator_chain_error;
384  auto err
385  = lexy::error<Reader, tag>(op.cur.position(), reader.position());
386  context.on(_ev::error{}, err);
387  }
388  reader.reset(op.cur);
389  }
390  }
391  else if constexpr (binding_power.is_postfix())
392  {
393  auto value = LEXY_MOV(context.value);
394  context.value = {};
395 
396  if constexpr (value_type_void)
397  context.value.emplace_result(context.value_callback(),
398  LEXY_FWD(op_args)...);
399  else
400  context.value.emplace_result(context.value_callback(), *LEXY_MOV(value),
401  LEXY_FWD(op_args)...);
402  }
403 
404  context.on(_ev::operation_chain_op{}, Operation{}, reader.position());
405  return true;
406  }
407  };
408 
409  template <typename Context, typename Reader>
410  static constexpr bool parse(Context& context, Reader& reader,
412  {
413  using namespace lexy::_detail;
414  using production = typename Context::production;
415 
416  // Check whether we might have nested to far.
417  if (state.cur_nesting_level++ >= production::max_operator_nesting)
418  {
419  using tag = typename production::operator_nesting_error;
420  auto err = lexy::error<Reader, tag>(op.cur.position(), reader.position());
421  context.on(_ev::error{}, err);
422 
423  // We do not recover, to prevent stack overflow.
424  reader.reset(op.cur);
425  return false;
426  }
427 
428  // If the operator is part of a group, check whether it matches.
429  constexpr auto binding_power = binding_power_of<production>(Operation{});
430  if constexpr (binding_power.group != 0)
431  {
432  if (state.cur_group == 0)
433  {
434  // We didn't have any operator group yet, set it.
435  state.cur_group = binding_power.group;
436  }
437  else if (state.cur_group != binding_power.group)
438  {
439  // Operators can't be grouped.
440  using tag = typename production::operator_group_error;
441  auto err = lexy::error<Reader, tag>(op.cur.position(), reader.position());
442  context.on(_ev::error{}, err);
443  // Trivially recover, but don't update group:
444  // let the first one stick.
445  }
446  }
447 
448  // Finish the operator and parse a RHS, if necessary.
449  return op_of<Operation>::template op_finish<_op_cont>(context, reader, op, state);
450  }
451  };
452 
453  template <unsigned MinBindingPower, typename Context, typename Reader>
454  static constexpr bool _parse_lhs(Context& context, Reader& reader, _state& state)
455  {
456  using namespace lexy::_detail;
457 
459  using atom_parser
460  = lexy::parser_for<LEXY_DECAY_DECLTYPE(Context::production::atom), final_parser>;
461 
462  if constexpr (op_list::size == 0)
463  {
464  // We don't have any prefix operators, so parse an atom directly.
465  (void)state;
466  return atom_parser::parse(context, reader);
467  }
468  else
469  {
470  auto op = lexy::_detail::parse_operator<typename op_list::ops>(reader);
471  if (op.idx >= op_list::ops::size)
472  {
473  // We don't have a prefix operator, so it must be an atom.
474  reader.reset(op.cur);
475  return atom_parser::parse(context, reader);
476  }
477 
478  auto start_event = context.on(_ev::operation_chain_start{}, op.cur.position());
479  auto result = op_list::template apply<_continuation>(context, reader, op, state);
480  context.on(_ev::operation_chain_finish{}, LEXY_MOV(start_event), reader.position());
481  return result;
482  }
483  }
484 
485  template <unsigned MinBindingPower, typename Context, typename Reader>
486  static constexpr bool _parse(Context& context, Reader& reader, _state& state)
487  {
488  using namespace lexy::_detail;
490 
491  if constexpr (op_list::size == 0)
492  {
493  // We don't have any post operators, so we only parse the left-hand-side.
494  return _parse_lhs<MinBindingPower>(context, reader, state);
495  }
496  else
497  {
498  auto start_event = context.on(_ev::operation_chain_start{}, reader.position());
499  if (!_parse_lhs<MinBindingPower>(context, reader, state))
500  {
501  context.on(_ev::operation_chain_finish{}, LEXY_MOV(start_event), reader.position());
502  return false;
503  }
504 
505  auto result = true;
506  while (true)
507  {
508  auto op = parse_operator<typename op_list::ops>(reader);
509  if (op.idx >= op_list::ops::size)
510  {
511  reader.reset(op.cur);
512  break;
513  }
514 
515  result = op_list::template apply<_continuation>(context, reader, op, state);
516  if (!result)
517  break;
518  }
519 
520  context.on(_ev::operation_chain_finish{}, LEXY_MOV(start_event), reader.position());
521  return result;
522  }
523 
524  return false; // unreachable
525  }
526 
527  template <typename NextParser>
528  struct p
529  {
530  template <typename Context, typename Reader>
531  LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader)
532  {
533  static_assert(std::is_same_v<NextParser, lexy::_detail::final_parser>);
534 
535  using production = typename Context::production;
536  constexpr auto binding_power = lexy::_detail::binding_power_of<production>(
538  // The MinBindingPower is determined by the root operation.
539  // The initial operand is always on the left, so we use the left binding power.
540  // However, for a prefix operator it is zero, but then it's a right operand so we use
541  // that.
542  constexpr auto min_binding_power
544 
545  _state state;
546  _parse<min_binding_power>(context, reader, state);
547 
548  // Regardless of parse errors, we can recover if we already had a value at some point.
549  return !!context.value;
550  }
551  };
552 };
553 } // namespace lexyd
554 
555 //=== expression_production ===//
556 namespace lexy
557 {
559 {
560  static LEXY_CONSTEVAL auto name()
561  {
562  return "maximum operator nesting level exceeded";
563  }
564 };
565 
567 {
568  static LEXY_CONSTEVAL auto name()
569  {
570  return "operator cannot be chained";
571  }
572 };
573 
575 {
576  static LEXY_CONSTEVAL auto name()
577  {
578  return "operator cannot be mixed with previous operators";
579  }
580 };
581 
583 {
585  static constexpr auto max_operator_nesting = 256; // arbitrary power of two
586 
589 
590  static constexpr auto rule = lexyd::_expr<void>{};
591 };
592 
593 template <typename Expr, typename RootOperation>
595 {
596  static constexpr auto rule = lexyd::_expr<RootOperation>{};
597 };
598 } // namespace lexy
599 
600 #endif // LEXY_DSL_EXPRESSION_HPP_INCLUDED
601 
cx::size
constexpr auto size(const C &c) -> decltype(c.size())
Definition: wildcards.hpp:636
lexy::_detail::_binding_power_of::get
static constexpr auto get(CurOperation, unsigned cur_group, unsigned cur_level)
Definition: expression.hpp:149
LEXY_MOV
#define LEXY_MOV(...)
Definition: config.hpp:29
lexyd::_expr::p
Definition: expression.hpp:528
lexy::_detail::binding_power::right
static constexpr auto right(unsigned group, unsigned level)
Definition: expression.hpp:65
LEXY_CONSTEVAL
#define LEXY_CONSTEVAL
Definition: config.hpp:98
lexy::_detail::binding_power::is_infix
constexpr bool is_infix() const
Definition: expression.hpp:84
literal.hpp
lexy::operator_chain_error::name
static LEXY_CONSTEVAL auto name()
Definition: expression.hpp:568
lexy::_detail::operation_list::size
static constexpr auto size
Definition: expression.hpp:185
lexy::_detail::operation_list::apply
static constexpr bool apply(Context &context, Reader &reader, parsed_operator< Reader > op, Args &&... args)
Definition: expression.hpp:191
lexy::_detail::binding_power::lhs
unsigned lhs
Definition: expression.hpp:59
lexy::_detail::get_binding_power
constexpr binding_power get_binding_power(unsigned cur_group, unsigned cur_level)
Definition: expression.hpp:99
lexyd::_expr::_state::cur_nesting_level
unsigned cur_nesting_level
Definition: expression.hpp:260
lexy::_detail::binding_power
Definition: expression.hpp:56
LEXY_FWD
#define LEXY_FWD(...)
Definition: config.hpp:30
lexy::_detail::type_or
std::conditional_t< std::is_void_v< T >, Fallback, T > type_or
Definition: config.hpp:64
lexy::_detail::binding_power_of
constexpr auto binding_power_of(Operation)
Definition: expression.hpp:160
lexyd::_expr::_continuation
Definition: expression.hpp:264
lexy::_detail::op_of
LEXY_DECAY_DECLTYPE(Operation::op) op_of
Definition: expression.hpp:169
lexy
Definition: any_ref.hpp:12
lexy::operator_group_error::name
static LEXY_CONSTEVAL auto name()
Definition: expression.hpp:576
lexyd::_expr::p::parse
static LEXY_PARSER_FUNC bool parse(Context &context, Reader &reader)
Definition: expression.hpp:531
lexyd::_expr::_parse
static constexpr bool _parse(Context &context, Reader &reader, _state &state)
Definition: expression.hpp:486
lexy::_detail::operation_list::operator+
constexpr auto operator+(T) const
Definition: expression.hpp:175
detail::void
j template void())
Definition: json.hpp:4893
lexyd::_expr::_continuation::parse
static constexpr bool parse(Context &context, Reader &reader, lexy::_detail::parsed_operator< Reader > op, _state &state)
Definition: expression.hpp:410
lexyd::_operation_base
Definition: grammar.hpp:37
lexy::_detail::operation_list::operator+
constexpr auto operator+(operation_list< T... >) const
Definition: expression.hpp:180
lexy::error
Generic failure.
Definition: error.hpp:14
lexy::_detail::binding_power::postfix
static constexpr auto postfix(unsigned group, unsigned level)
Definition: expression.hpp:74
lexy::_detail::parsed_operator
Definition: operator.hpp:76
lexy::parse
constexpr auto parse(const Input &input, const ErrorCallback &callback)
Parses the production into a value, invoking the callback on error.
Definition: parse.hpp:171
lexyd::_expr::_continuation::_op_cont
Definition: expression.hpp:266
lexy::parse_events::error
Definition: dsl/base.hpp:68
lexy::_detail::binding_power::group
unsigned group
Definition: expression.hpp:58
lexy::_detail::_binding_power_of::transition
static constexpr auto transition(CurOperation op, unsigned cur_group, unsigned cur_level)
Definition: expression.hpp:127
operator.hpp
lexy::_detail::post_operation_list_of
decltype(_operation_list_of< false, MinBindingPower >::template get< 1 >(typename Expr::operation{})) post_operation_list_of
Definition: expression.hpp:248
lexy::_detail::_binding_power_of::transition
static constexpr auto transition(lexyd::atom, unsigned cur_group, unsigned)
Definition: expression.hpp:120
lexy::_detail::binding_power::is_postfix
constexpr bool is_postfix() const
Definition: expression.hpp:88
lexyd::_expr::_continuation::_op_cont::parse
static LEXY_PARSER_FUNC bool parse(Context &context, Reader &reader, _state &state, Args &&... op_args)
Definition: expression.hpp:269
lexy::_detail::_operation_list_of::get
static constexpr auto get(lexyd::groups< Operations... >)
Definition: expression.hpp:220
lexyd::groups
Operation that selects between multiple ones.
Definition: expression.hpp:34
lexy::operator_group_error
Definition: expression.hpp:574
lexyd::infix_op_list
Definition: expression.hpp:41
lexy::_detail::op_lit_list
Definition: operator.hpp:48
LEXY_DECAY_DECLTYPE
#define LEXY_DECAY_DECLTYPE(...)
Definition: config.hpp:34
lexyd::rule_base
Definition: grammar.hpp:17
lexyd::_expr::_state::cur_group
unsigned cur_group
Definition: expression.hpp:259
lexyd::atom::name
static LEXY_CONSTEVAL auto name()
Definition: expression.hpp:26
LEXY_PARSER_FUNC
#define LEXY_PARSER_FUNC
Definition: dsl/base.hpp:108
lexy::op
typename LEXY_DECAY_DECLTYPE(Operator)::op_tag_type op
Definition: operator.hpp:41
lexyd::atom
Operation that just parses the atomic rule.
Definition: expression.hpp:24
lexyd::postfix_op
Definition: expression.hpp:46
lexy::parse_events::operation_chain_op
Definition: dsl/base.hpp:48
lexyd::infix_op_right
Definition: expression.hpp:39
lexy::subexpression_production
Definition: expression.hpp:594
base.hpp
lexy::_detail
Definition: any_ref.hpp:12
lexyd::prefix_op
Definition: expression.hpp:49
lexy::_detail::_binding_power_of::transition
static constexpr auto transition(lexyd::groups< Operations... >, unsigned cur_group, unsigned cur_level)
Definition: expression.hpp:133
lexyd::infix_op_left
Definition: expression.hpp:37
lexy::_detail::operation_list
Definition: expression.hpp:172
lexy::_detail::final_parser
Definition: action/base.hpp:164
lexy::operator_chain_error
Definition: expression.hpp:566
lexy::parser_for
typename Rule::template p< NextParser > parser_for
Definition: dsl/base.hpp:113
lexy::_detail::_operation_list_of
Definition: expression.hpp:212
lexy::_detail::binding_power::rhs
unsigned rhs
Definition: expression.hpp:59
lexy::max_operator_nesting_exceeded
Definition: expression.hpp:558
lexyd::infix_op_single
Definition: expression.hpp:43
lexy::_detail::binding_power::prefix
static constexpr auto prefix(unsigned group, unsigned level)
Definition: expression.hpp:69
base.hpp
lexy::expression_production
Definition: expression.hpp:582
lexy::_detail::_operation_list_of::get
static constexpr auto get(Operation)
Definition: expression.hpp:225
lexy::max_operator_nesting_exceeded::name
static LEXY_CONSTEVAL auto name()
Definition: expression.hpp:560
lexy::_detail::binding_power::is_valid
constexpr bool is_valid() const
Definition: expression.hpp:80
lexyd::_expr::_parse_lhs
static constexpr bool _parse_lhs(Context &context, Reader &reader, _state &state)
Definition: expression.hpp:454
lexy::_detail::binding_power::left
static constexpr auto left(unsigned group, unsigned level)
Definition: expression.hpp:61
lexyd::_expr
Definition: expression.hpp:255
lexy::parse_events::operation_chain_finish
Definition: dsl/base.hpp:52
lexyd
Definition: trace.hpp:22
lexy::_detail::_binding_power_of
Definition: expression.hpp:118
lexyd::op
constexpr auto op(Literal)
Definition: operator.hpp:197
lexy::_detail::pre_operation_list_of
decltype(_operation_list_of< true, MinBindingPower >::template get< 1 >(typename Expr::operation{})) pre_operation_list_of
Definition: expression.hpp:243
lexy::_detail::operation_list::ops
decltype((typename op_of< Operations >::op_literals{}+...+op_lit_list{})) ops
Definition: expression.hpp:187
lexy::_detail::binding_power::is_prefix
constexpr bool is_prefix() const
Definition: expression.hpp:92
lexyd::_expr::_state
Definition: expression.hpp:257
lexy::_detail::_operation_list_of::get
static constexpr auto get(lexyd::atom)
Definition: expression.hpp:215
lexy::parse_events::operation_chain_start
Definition: dsl/base.hpp:44


behaviortree_cpp_v4
Author(s): Davide Faconti
autogenerated on Fri Dec 13 2024 03:19:16