expression.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_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.set_position(op.pos);
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 = lexy::error<Reader, tag>(op.pos, reader.position());
385  context.on(_ev::error{}, err);
386  }
387  reader.set_position(op.pos);
388  }
389  }
390  else if constexpr (binding_power.is_postfix())
391  {
392  auto value = LEXY_MOV(context.value);
393  context.value = {};
394 
395  if constexpr (value_type_void)
396  context.value.emplace_result(context.value_callback(),
397  LEXY_FWD(op_args)...);
398  else
399  context.value.emplace_result(context.value_callback(), *LEXY_MOV(value),
400  LEXY_FWD(op_args)...);
401  }
402 
403  context.on(_ev::operation_chain_op{}, Operation{}, reader.position());
404  return true;
405  }
406  };
407 
408  template <typename Context, typename Reader>
409  static constexpr bool parse(Context& context, Reader& reader,
411  {
412  using namespace lexy::_detail;
413  using production = typename Context::production;
414 
415  // Check whether we might have nested to far.
416  if (state.cur_nesting_level++ >= production::max_operator_nesting)
417  {
418  using tag = typename production::operator_nesting_error;
419  auto err = lexy::error<Reader, tag>(op.pos, reader.position());
420  context.on(_ev::error{}, err);
421 
422  // We do not recover, to prevent stack overflow.
423  reader.set_position(op.pos);
424  return false;
425  }
426 
427  // If the operator is part of a group, check whether it matches.
428  constexpr auto binding_power = binding_power_of<production>(Operation{});
429  if constexpr (binding_power.group != 0)
430  {
431  if (state.cur_group == 0)
432  {
433  // We didn't have any operator group yet, set it.
434  state.cur_group = binding_power.group;
435  }
436  else if (state.cur_group != binding_power.group)
437  {
438  // Operators can't be grouped.
439  using tag = typename production::operator_group_error;
440  auto err = lexy::error<Reader, tag>(op.pos, reader.position());
441  context.on(_ev::error{}, err);
442  // Trivially recover, but don't update group:
443  // let the first one stick.
444  }
445  }
446 
447  // Finish the operator and parse a RHS, if necessary.
448  return op_of<Operation>::template op_finish<_op_cont>(context, reader, op, state);
449  }
450  };
451 
452  template <unsigned MinBindingPower, typename Context, typename Reader>
453  static constexpr bool _parse_lhs(Context& context, Reader& reader, _state& state)
454  {
455  using namespace lexy::_detail;
456 
458  using atom_parser
459  = lexy::parser_for<LEXY_DECAY_DECLTYPE(Context::production::atom), final_parser>;
460 
461  if constexpr (op_list::size == 0)
462  {
463  // We don't have any prefix operators, so parse an atom directly.
464  (void)state;
465  return atom_parser::parse(context, reader);
466  }
467  else
468  {
469  auto op = lexy::_detail::parse_operator<typename op_list::ops>(reader);
470  if (op.idx >= op_list::ops::size)
471  {
472  // We don't have a prefix operator, so it must be an atom.
473  reader.set_position(op.pos);
474  return atom_parser::parse(context, reader);
475  }
476 
477  auto start_event = context.on(_ev::operation_chain_start{}, op.pos);
478  auto result = op_list::template apply<_continuation>(context, reader, op, state);
479  context.on(_ev::operation_chain_finish{}, LEXY_MOV(start_event), reader.position());
480  return result;
481  }
482  }
483 
484  template <unsigned MinBindingPower, typename Context, typename Reader>
485  static constexpr bool _parse(Context& context, Reader& reader, _state& state)
486  {
487  using namespace lexy::_detail;
489 
490  if constexpr (op_list::size == 0)
491  {
492  // We don't have any post operators, so we only parse the left-hand-side.
493  return _parse_lhs<MinBindingPower>(context, reader, state);
494  }
495  else
496  {
497  auto start_event = context.on(_ev::operation_chain_start{}, reader.position());
498  if (!_parse_lhs<MinBindingPower>(context, reader, state))
499  {
500  context.on(_ev::operation_chain_finish{}, LEXY_MOV(start_event), reader.position());
501  return false;
502  }
503 
504  auto result = true;
505  while (true)
506  {
507  auto op = parse_operator<typename op_list::ops>(reader);
508  if (op.idx >= op_list::ops::size)
509  {
510  reader.set_position(op.pos);
511  break;
512  }
513 
514  result = op_list::template apply<_continuation>(context, reader, op, state);
515  if (!result)
516  break;
517  }
518 
519  context.on(_ev::operation_chain_finish{}, LEXY_MOV(start_event), reader.position());
520  return result;
521  }
522 
523  return false; // unreachable
524  }
525 
526  template <typename NextParser>
527  struct p
528  {
529  template <typename Context, typename Reader>
530  LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader)
531  {
532  static_assert(std::is_same_v<NextParser, lexy::_detail::final_parser>);
533 
534  using production = typename Context::production;
535  constexpr auto binding_power = lexy::_detail::binding_power_of<production>(
537  // The MinBindingPower is determined by the root operation.
538  // The initial operand is always on the left, so we use the left binding power.
539  // However, for a prefix operator it is zero, but then it's a right operand so we use
540  // that.
541  constexpr auto min_binding_power
543 
544  _state state;
545  _parse<min_binding_power>(context, reader, state);
546 
547  // Regardless of parse errors, we can recover if we already had a value at some point.
548  return !!context.value;
549  }
550  };
551 };
552 } // namespace lexyd
553 
554 //=== expression_production ===//
555 namespace lexy
556 {
558 {
559  static LEXY_CONSTEVAL auto name()
560  {
561  return "maximum operator nesting level exceeded";
562  }
563 };
564 
566 {
567  static LEXY_CONSTEVAL auto name()
568  {
569  return "operator cannot be chained";
570  }
571 };
572 
574 {
575  static LEXY_CONSTEVAL auto name()
576  {
577  return "operator cannot be mixed with previous operators";
578  }
579 };
580 
582 {
584  static constexpr auto max_operator_nesting = 256; // arbitrary power of two
585 
588 
589  static constexpr auto rule = lexyd::_expr<void>{};
590 };
591 
592 template <typename Expr, typename RootOperation>
594 {
595  static constexpr auto rule = lexyd::_expr<RootOperation>{};
596 };
597 } // namespace lexy
598 
599 #endif // LEXY_DSL_EXPRESSION_HPP_INCLUDED
600 
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:21
lexyd::_expr::p
Definition: expression.hpp:527
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:90
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:567
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:22
lexy::_detail::type_or
std::conditional_t< std::is_void_v< T >, Fallback, T > type_or
Definition: config.hpp:56
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:575
lexyd::_expr::p::parse
static LEXY_PARSER_FUNC bool parse(Context &context, Reader &reader)
Definition: expression.hpp:530
lexyd::_expr::_parse
static constexpr bool _parse(Context &context, Reader &reader, _state &state)
Definition: expression.hpp:485
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:409
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:55
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:573
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:26
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:95
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:35
lexyd::infix_op_right
Definition: expression.hpp:39
lexy::subexpression_production
Definition: expression.hpp:593
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:565
lexy::parser_for
typename Rule::template p< NextParser > parser_for
Definition: dsl/base.hpp:100
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:557
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:581
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:559
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:453
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:39
lexyd
Definition: trace.hpp:22
lexy::_detail::_binding_power_of
Definition: expression.hpp:118
lexyd::op
constexpr auto op(Literal)
Definition: operator.hpp:177
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:31


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