parse_tree.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_PARSE_TREE_HPP_INCLUDED
5 #define LEXY_PARSE_TREE_HPP_INCLUDED
6 
11 #include <lexy/grammar.hpp>
12 #include <lexy/token.hpp>
13 
14 //=== internal: pt_node ===//
15 namespace lexy::_detail
16 {
17 template <typename Reader>
18 class pt_node;
19 template <typename Reader>
21 template <typename Reader>
23 
24 template <typename Reader>
25 class pt_node
26 {
27 public:
28  static constexpr auto type_token = 0b0u;
29  static constexpr auto type_production = 0b1u;
30 
31  static constexpr auto role_sibling = 0b0u;
32  static constexpr auto role_parent = 0b1u;
33 
34  //=== information about the current node ===//
35  unsigned type() const noexcept
36  {
37  return _value & 0b1;
38  }
39 
40  auto as_token() noexcept
41  {
42  return type() == type_token ? static_cast<pt_node_token<Reader>*>(this) : nullptr;
43  }
44  auto as_production() noexcept
45  {
46  return type() == type_production ? static_cast<pt_node_production<Reader>*>(this) : nullptr;
47  }
48 
49  //=== information about the next node ===//
50  void set_sibling(pt_node<Reader>* sibling) noexcept
51  {
53  }
54  void set_parent(pt_node_production<Reader>* parent) noexcept
55  {
57  }
58 
59  unsigned next_role() const noexcept
60  {
61  return (_value & 0b10) >> 1;
62  }
63 
64  pt_node<Reader>* next_node() const noexcept
65  {
66  // NOLINTNEXTLINE: We need pointer conversion.
67  return reinterpret_cast<pt_node<Reader>*>(_value & ~std::uintptr_t(0b11));
68  }
69 
70 protected:
71  explicit pt_node(unsigned type)
72  // We initializy it to a null parent pointer.
73  // This means it is automatically an empty child range.
75  {}
76 
77 private:
78  static std::uintptr_t _make_packed_ptr(pt_node<Reader>* ptr, unsigned type, unsigned role)
79  {
80  auto result = reinterpret_cast<std::uintptr_t>(ptr);
81  LEXY_PRECONDITION((result & 0b11) == 0);
82 
83  result |= (role & 0b1) << 1;
84  result |= (type & 0b1);
85 
86  return result;
87  }
88 
89  // Stores an address of the "next" node in the tree.
90  // Stores a bit that remembers whether the next node is a sibling or parent (the role).
91  // Stores a bit that remembers whether *this* node is a token or production.
92  std::uintptr_t _value;
93 };
94 
95 template <typename Reader>
96 struct pt_node_token : pt_node<Reader>
97 {
98  // If it's random access, we store size instead of end.
99  static constexpr auto _optimize_end
100  = _detail::is_random_access_iterator<typename Reader::iterator>;
101  using _end_t
102  // If we can optimize it, we store the size as a uint32_t, otherwise the iterator.
103  = std::conditional_t<_optimize_end, std::uint_least32_t, typename Reader::iterator>;
104 
105  typename Reader::iterator begin;
107  ::uint_least16_t kind;
108 
109  explicit pt_node_token(std::uint_least16_t kind, typename Reader::iterator begin,
110  typename Reader::iterator end) noexcept
112  {
113  update_end(end);
114  }
115 
116  typename Reader::iterator end() const noexcept
117  {
118  if constexpr (_optimize_end)
119  return begin + end_impl;
120  else
121  return end_impl;
122  }
123 
124  void update_end(typename Reader::iterator end) noexcept
125  {
126  if constexpr (_optimize_end)
127  {
128  static_assert(sizeof(pt_node_token) == 3 * sizeof(void*));
129 
130  auto size = std::size_t(end - begin);
131  LEXY_PRECONDITION(size <= UINT_LEAST32_MAX);
132  end_impl = std::uint_least32_t(size);
133  }
134  else
135  {
136  static_assert(sizeof(pt_node_token) <= 4 * sizeof(void*));
137 
138  end_impl = end;
139  }
140  }
141 };
142 
143 template <typename Reader>
144 struct pt_node_production : pt_node<Reader>
145 {
146  static constexpr std::size_t child_count_bits = sizeof(std::size_t) * CHAR_BIT - 2;
147 
148  const char* const* id;
150  std::size_t token_production : 1;
151  std::size_t first_child_adjacent : 1;
152 
153  explicit pt_node_production(production_info info) noexcept
155  token_production(info.is_token), first_child_adjacent(true)
156  {
157  static_assert(sizeof(pt_node_production) == 3 * sizeof(void*));
158  LEXY_PRECONDITION(!info.is_transparent);
159  }
160 
162  {
163  auto memory = static_cast<void*>(this + 1);
164  if (child_count == 0)
165  {
166  // We don't have a child at all.
167  return nullptr;
168  }
169  else if (first_child_adjacent)
170  {
171  // The first child is stored immediately afterwards.
172  return static_cast<pt_node<Reader>*>(memory);
173  }
174  else
175  {
176  // We're only storing a pointer to the first child immediately afterwards.
177  return *static_cast<pt_node<Reader>**>(memory);
178  }
179  }
180 };
181 } // namespace lexy::_detail
182 
183 //=== internal: pt_buffer ===//
184 namespace lexy::_detail
185 {
186 // Basic stack allocator to store all the nodes of a tree.
187 template <typename MemoryResource>
189 {
191 
192  static constexpr std::size_t block_size = 4096 - sizeof(void*);
193 
194  struct block
195  {
197  unsigned char memory[block_size];
198 
199  static block* allocate(resource_ptr resource)
200  {
201  auto memory = resource->allocate(sizeof(block), alignof(block));
202  auto ptr = ::new (memory) block; // Don't initialize array!
203  ptr->next = nullptr;
204  return ptr;
205  }
206 
207  static block* deallocate(resource_ptr resource, block* ptr)
208  {
209  auto next = ptr->next;
210  resource->deallocate(ptr, sizeof(block), alignof(block));
211  return next;
212  }
213 
214  unsigned char* end() noexcept
215  {
216  return &memory[block_size];
217  }
218  };
219 
220 public:
221  //=== constructors/destructors/assignment ===//
222  explicit constexpr pt_buffer(MemoryResource* resource) noexcept
223  : _resource(resource), _head(nullptr), _cur_block(nullptr), _cur_pos(nullptr)
224  {}
225 
226  pt_buffer(pt_buffer&& other) noexcept
227  : _resource(other._resource), _head(other._head), _cur_block(other._cur_block),
228  _cur_pos(other._cur_pos)
229  {
230  other._head = other._cur_block = nullptr;
231  other._cur_pos = nullptr;
232  }
233 
234  ~pt_buffer() noexcept
235  {
236  auto cur = _head;
237  while (cur != nullptr)
238  cur = block::deallocate(_resource, cur);
239  }
240 
241  pt_buffer& operator=(pt_buffer&& other) noexcept
242  {
243  lexy::_detail::swap(_resource, other._resource);
244  lexy::_detail::swap(_head, other._head);
245  lexy::_detail::swap(_cur_block, other._cur_block);
246  lexy::_detail::swap(_cur_pos, other._cur_pos);
247  return *this;
248  }
249 
250  //=== allocation ===//
251  // Allocates the first block for the buffer.
252  // Must be called before everything else.
253  // (If done in the constructor, it would require a move that does allocation which we don't
254  // want).
255  // If called after being initialized, destroys all nodes without releasing memory.
256  void reset()
257  {
258  if (!_head)
260 
261  _cur_block = _head;
262  _cur_pos = &_cur_block->memory[0];
263  }
264 
265  void reserve(std::size_t size)
266  {
267  if (remaining_capacity() < size)
268  {
270  _cur_block->next = next;
271  _cur_block = next;
272  _cur_pos = &_cur_block->memory[0];
273  }
274  }
275 
276  template <typename T, typename... Args>
277  T* allocate(Args&&... args)
278  {
279  static_assert(std::is_trivially_copyable_v<T>);
280  static_assert(alignof(T) == alignof(void*));
281  constexpr auto size = sizeof(T); // NOLINT: It's fine, we want to allocate for a pointer.
282  LEXY_PRECONDITION(_cur_block); // Forgot to call .init().
283  LEXY_PRECONDITION(remaining_capacity() >= size); // Forgot to call .reserve().
284 
285  auto memory = _cur_pos;
286  _cur_pos += size;
287  return ::new (static_cast<void*>(memory)) T(LEXY_FWD(args)...);
288  }
289 
290  void* top()
291  {
292  return _cur_pos;
293  }
294 
295  void unwind(void* marker) noexcept
296  {
297  auto pos = static_cast<unsigned char*>(marker);
298 
299  // Note: this is not guaranteed to work by the standard;
300  // We'd have to go through std::less instead.
301  // However, on all implementations I care about, std::less just does < anyway.
302  if (_cur_block->memory <= pos && pos < _cur_block->end())
303  // We're still in the same block, just reset position.
304  _cur_pos = pos;
305  else
306  // Reset to the beginning of the current block only.
307  // This can waste memory, but this is not a problem here:
308  // unwind() is only used to backtrack a production, which happens after a couple of
309  // tokens only; the memory waste is directly proportional to the lookahead length.
311  }
312 
313 private:
314  std::size_t remaining_capacity() const noexcept
315  {
316  return std::size_t(_cur_block->end() - _cur_pos);
317  }
318 
320  block* _head;
321 
322  block* _cur_block;
323  unsigned char* _cur_pos;
324 };
325 } // namespace lexy::_detail
326 
327 //=== parse_tree ===//
328 namespace lexy
329 {
330 template <typename Reader, typename TokenKind = void, typename MemoryResource = void>
332 {
333 public:
334  //=== construction ===//
335  class builder;
336 
337  constexpr parse_tree() : parse_tree(_detail::get_memory_resource<MemoryResource>()) {}
338  constexpr explicit parse_tree(MemoryResource* resource)
339  : _buffer(resource), _root(nullptr), _size(0), _depth(0)
340  {}
341 
342  //=== container access ===//
343  bool empty() const noexcept
344  {
345  return _root == nullptr;
346  }
347 
348  std::size_t size() const noexcept
349  {
350  return _size;
351  }
352 
353  std::size_t depth() const noexcept
354  {
356  return _depth;
357  }
358 
359  void clear() noexcept
360  {
361  _buffer.reset();
362  _root = nullptr;
363  }
364 
365  //=== node access ===//
366  class node;
367  class node_kind;
368 
369  node root() const noexcept
370  {
372  return node(_root);
373  }
374 
375  //=== traverse ===//
376  class traverse_range;
377 
378  traverse_range traverse(const node& n) const noexcept
379  {
380  return traverse_range(n);
381  }
382  traverse_range traverse() const noexcept
383  {
384  if (empty())
385  return traverse_range();
386  else
387  return traverse_range(root());
388  }
389 
390  //=== remaining input ===//
392  {
393  return _remaining_input;
394  }
395 
396 private:
399  std::size_t _size;
400  std::size_t _depth;
402 };
403 
404 template <typename Input, typename TokenKind = void, typename MemoryResource = void>
405 using parse_tree_for = lexy::parse_tree<lexy::input_reader<Input>, TokenKind, MemoryResource>;
406 
407 template <typename Reader, typename TokenKind, typename MemoryResource>
408 class parse_tree<Reader, TokenKind, MemoryResource>::builder
409 {
410 public:
411  class marker
412  {
413  public:
414  marker() : marker(nullptr, 0) {}
415 
416  private:
417  // Where to unwind when done.
418  void* unwind_pos;
419  // The current production node.
420  // nullptr if using the container API.
422  // The number of children we've already added.
423  std::size_t child_count;
424  // The first and last child of the container.
427 
428  // For a production node, depth of the production node.
429  // For a container node, depth of the children.
430  std::size_t cur_depth;
431  // The maximum local depth seen in the subtree beginning at the marker.
432  std::size_t local_max_depth;
433 
434  explicit marker(void* unwind_pos, std::size_t cur_depth,
435  _detail::pt_node_production<Reader>* prod = nullptr)
436  : unwind_pos(unwind_pos), prod(prod), child_count(0), first_child(nullptr),
437  last_child(nullptr), cur_depth(cur_depth), local_max_depth(cur_depth)
438  {}
439 
440  void clear()
441  {
442  first_child = nullptr;
443  last_child = nullptr;
444  child_count = 0;
445  }
446 
448  {
449  if (first_child == nullptr)
450  {
451  // Initialize the pointers.
452  first_child = last_child = child;
453  }
454  else
455  {
456  // last_child gets a sibling pointer.
457  last_child->set_sibling(child);
458  // child is now the last child.
459  last_child = child;
460  }
461 
462  ++child_count;
463  }
464  void insert_list(std::size_t length, _detail::pt_node<Reader>* first,
466  {
467  if (length == 0)
468  return;
469 
470  if (first_child == nullptr)
471  {
472  first_child = first;
473  last_child = last;
474  }
475  else
476  {
477  last_child->set_sibling(first);
478  last_child = last;
479  }
480 
481  child_count += length;
482  }
483 
485  {
486  LEXY_PRECONDITION(parent->child_count == 0);
487  if (child_count == 0)
488  return;
489 
490  if (first_child == parent + 1)
491  {
492  parent->first_child_adjacent = true;
493  }
494  else
495  {
496  // This case happens either if the first child is in a new block or if we're
497  // dealing with a container node. In either case, we've already reserved memory
498  // for a pointer.
499  auto memory = static_cast<void*>(parent + 1);
500  ::new (memory) _detail::pt_node<Reader>*(first_child);
501  parent->first_child_adjacent = false;
502  }
503 
504  // last_child needs a pointer to the production.
505  last_child->set_parent(parent);
506 
507  constexpr auto mask
508  = ((std::size_t(1) << _detail::pt_node_production<Reader>::child_count_bits) - 1);
509  parent->child_count = child_count & mask;
510  }
511 
512  void update_size_depth(std::size_t& size, std::size_t& max_depth)
513  {
514  size += child_count;
515 
516  if (cur_depth == local_max_depth && child_count > 0)
517  // We have children we haven't yet accounted for.
518  ++local_max_depth;
519 
520  if (max_depth < local_max_depth)
521  max_depth = local_max_depth;
522  }
523 
524  friend builder;
525  };
526 
527  //=== root node ===//
528  explicit builder(parse_tree&& tree, production_info production) : _result(LEXY_MOV(tree))
529  {
530  // Empty the initial parse tree.
531  _result._buffer.reset();
532 
533  // Allocate a new root node.
534  // No need to reserve for the initial node.
535  _result._root
536  = _result._buffer.template allocate<_detail::pt_node_production<Reader>>(production);
537  _result._size = 1;
538  _result._depth = 0;
539 
540  // Begin construction at the root.
541  _cur = marker(_result._buffer.top(), 0, _result._root);
542  }
543  explicit builder(production_info production) : builder(parse_tree(), production) {}
544 
546  {
547  LEXY_PRECONDITION(_cur.prod == _result._root);
548  _cur.insert_children_into(_cur.prod);
549  _cur.update_size_depth(_result._size, _result._depth);
550  _result._remaining_input = remaining_input;
551  return LEXY_MOV(_result);
552  }
553 
554  //=== production nodes ===//
556  {
557  if (production.is_transparent)
558  // Don't need to add a new node for a transparent production.
559  return _cur;
560 
561  // Allocate a node for the production and append it to the current child list.
562  // We reserve enough memory to allow for a trailing pointer.
563  // This is only necessary if the first child is in a new block,
564  // in which case we won't overwrite it.
565  _result._buffer.reserve(sizeof(_detail::pt_node_production<Reader>)
566  + sizeof(_detail::pt_node<Reader>*));
567  auto node
568  = _result._buffer.template allocate<_detail::pt_node_production<Reader>>(production);
569  // Note: don't append the node yet, we might still backtrack.
570 
571  // Subsequent insertions are to the new node, so update marker and return old one.
572  auto old = LEXY_MOV(_cur);
573  _cur = marker(node, old.cur_depth + 1, node);
574  return old;
575  }
576 
578  {
579  LEXY_PRECONDITION(_cur.prod || m.prod == _cur.prod);
580  if (m.prod == _cur.prod)
581  // We're finishing with a transparent production, do nothing.
582  return;
583 
584  _cur.update_size_depth(_result._size, m.local_max_depth);
585  _cur.insert_children_into(_cur.prod);
586 
587  // Insert the production node into the parent and continue with it.
588  m.insert(_cur.prod);
589  _cur = LEXY_MOV(m);
590  }
591 
593  {
594  LEXY_PRECONDITION(_cur.prod || m.prod == _cur.prod);
595  if (_cur.prod == m.prod)
596  // We're backtracking a transparent production, do nothing.
597  return;
598 
599  _result._buffer.unwind(_cur.unwind_pos);
600  // Continue with parent.
601  _cur = LEXY_MOV(m);
602  }
603 
604  //=== container nodes ===//
606  {
607  auto unwind_pos = _result._buffer.top();
608  if (_cur.prod && _cur.child_count == 0)
609  {
610  // If our parent production doesn't have any children,
611  // we might need space for a first child pointer.
612  //
613  // If our parent is another container, its start_container() function took care of it.
614  // If our parent already has a child, the first_child pointer is taken care of.
615  _result._buffer.template allocate<_detail::pt_node<Reader>*>(nullptr);
616  }
617 
618  // Create a new container marker and activate it.
619  auto old = LEXY_MOV(_cur);
620  _cur = marker(unwind_pos, old.cur_depth);
621  return old;
622  }
623 
625  {
626  LEXY_PRECONDITION(!_cur.prod);
627  if (production.is_transparent)
628  // If the production is transparent, we do nothing.
629  return;
630 
631  // Allocate a new node for the production.
632  // We definitely need space for node pointer at this point,
633  // as the first child precedes it.
634  _result._buffer.reserve(sizeof(_detail::pt_node_production<Reader>)
635  + sizeof(_detail::pt_node<Reader>*));
636  auto node
637  = _result._buffer.template allocate<_detail::pt_node_production<Reader>>(production);
638  _result._buffer.template allocate<_detail::pt_node<Reader>*>(nullptr);
639 
640  // Create a new container that will contain the production as its only child.
641  // As such, it logically starts at the same position and depth as the current container.
642  auto new_container = marker(_cur.unwind_pos, _cur.cur_depth);
643  new_container.insert(node);
644 
645  // The production contains all the children.
646  _cur.insert_children_into(node);
647 
648  // The local_max_depth of the new container is determined by the old maximum depth + 1.
649  new_container.local_max_depth = [&] {
650  if (_cur.cur_depth == _cur.local_max_depth && _cur.child_count > 0)
651  // There are children we haven't yet accounted for.
652  return _cur.local_max_depth + 1 + 1;
653  else
654  return _cur.local_max_depth + 1;
655  }();
656  _result._size += _cur.child_count;
657 
658  // And we continue with the current container.
659  _cur = new_container;
660  }
661 
663  {
664  LEXY_PRECONDITION(!_cur.prod);
665 
666  // Insert the children of our container into the parent.
667  m.insert_list(_cur.child_count, _cur.first_child, _cur.last_child);
668 
669  // We can't update size yet, it would be double counted.
670  // We do need to update the max depth if necessary, however.
671  std::size_t size = 0;
672  _cur.update_size_depth(size, m.local_max_depth);
673 
674  // Continue with the parent.
675  _cur = LEXY_MOV(m);
676  }
677 
679  {
680  LEXY_PRECONDITION(!_cur.prod);
681 
682  // Deallocate everything we've inserted.
683  _result._buffer.unwind(_cur.unwind_pos);
684  // Continue with parent.
685  _cur = LEXY_MOV(m);
686  }
687 
688  //=== token nodes ===//
689  void token(token_kind<TokenKind> _kind, typename Reader::iterator begin,
690  typename Reader::iterator end)
691  {
692  if (_kind.ignore_if_empty() && begin == end)
693  return;
694 
695  auto kind = token_kind<TokenKind>::to_raw(_kind);
696 
697  // We merge error tokens.
698  if (kind == lexy::error_token_kind && _cur.last_child && _cur.last_child->as_token()
699  && _cur.last_child->as_token()->kind == lexy::error_token_kind)
700  {
701  // No need to allocate a new node, just extend the previous node.
702  _cur.last_child->as_token()->update_end(end);
703  }
704  else
705  {
706  // Allocate and append.
707  _result._buffer.reserve(sizeof(_detail::pt_node_token<Reader>));
708  auto node
709  = _result._buffer.template allocate<_detail::pt_node_token<Reader>>(kind, begin,
710  end);
711  _cur.insert(node);
712  }
713  }
714 
715 private:
718 };
719 
720 template <typename Reader, typename TokenKind, typename MemoryResource>
721 class parse_tree<Reader, TokenKind, MemoryResource>::node_kind
722 {
723 public:
724  bool is_token() const noexcept
725  {
726  return _ptr->as_token() != nullptr;
727  }
728  bool is_production() const noexcept
729  {
730  return _ptr->as_production() != nullptr;
731  }
732 
733  bool is_root() const noexcept
734  {
735  // Root node has no next node.
736  return _ptr->next_node() == nullptr;
737  }
738  bool is_token_production() const noexcept
739  {
740  return is_production() && _ptr->as_production()->token_production;
741  }
742 
743  const char* name() const noexcept
744  {
745  if (auto prod = _ptr->as_production())
746  return *prod->id;
747  else if (auto token = _ptr->as_token())
749  else
750  {
751  LEXY_ASSERT(false, "unreachable");
752  return nullptr;
753  }
754  }
755 
756  friend bool operator==(node_kind lhs, node_kind rhs)
757  {
758  if (lhs.is_token() && rhs.is_token())
759  return lhs._ptr->as_token()->kind == rhs._ptr->as_token()->kind;
760  else
761  return lhs._ptr->as_production()->id == rhs._ptr->as_production()->id;
762  }
763  friend bool operator!=(node_kind lhs, node_kind rhs)
764  {
765  return !(lhs == rhs);
766  }
767 
769  {
770  if (auto token = nk._ptr->as_token())
772  else
773  return false;
774  }
776  {
777  return nk == tk;
778  }
780  {
781  return !(nk == tk);
782  }
784  {
785  return !(nk == tk);
786  }
787 
788  friend bool operator==(node_kind nk, production_info info)
789  {
790  return nk.is_production() && nk._ptr->as_production()->id == info.id;
791  }
792  friend bool operator==(production_info info, node_kind nk)
793  {
794  return nk == info;
795  }
796  friend bool operator!=(node_kind nk, production_info info)
797  {
798  return !(nk == info);
799  }
800  friend bool operator!=(production_info info, node_kind nk)
801  {
802  return !(nk == info);
803  }
804 
805 private:
806  explicit node_kind(_detail::pt_node<Reader>* ptr) : _ptr(ptr) {}
807 
809 
810  friend parse_tree::node;
811 };
812 
813 template <typename Reader, typename TokenKind, typename MemoryResource>
814 class parse_tree<Reader, TokenKind, MemoryResource>::node
815 {
816 public:
817  void* address() const noexcept
818  {
819  return _ptr;
820  }
821 
822  auto kind() const noexcept
823  {
824  return node_kind(_ptr);
825  }
826 
827  auto parent() const noexcept
828  {
829  if (kind().is_root())
830  // The root has itself as parent.
831  return *this;
832 
833  // If we follow the sibling pointer, we reach a parent pointer.
834  auto cur = _ptr;
835  while (cur->next_role() == _detail::pt_node<Reader>::role_sibling)
836  cur = cur->next_node();
837  return node(cur->next_node());
838  }
839 
841  {
842  public:
843  class iterator : public _detail::forward_iterator_base<iterator, node, node, void>
844  {
845  public:
846  iterator() noexcept : _cur(nullptr) {}
847 
848  node deref() const noexcept
849  {
850  return node(_cur);
851  }
852 
853  void increment() noexcept
854  {
855  _cur = _cur->next_node();
856  }
857 
858  bool equal(iterator rhs) const noexcept
859  {
860  return _cur == rhs._cur;
861  }
862 
863  private:
864  explicit iterator(_detail::pt_node<Reader>* ptr) noexcept : _cur(ptr) {}
865 
867 
869  };
870 
871  bool empty() const noexcept
872  {
873  return size() == 0;
874  }
875 
876  std::size_t size() const noexcept
877  {
878  if (auto prod = _node->as_production())
879  return prod->child_count;
880  else
881  return 0;
882  }
883 
884  iterator begin() const noexcept
885  {
886  if (auto prod = _node->as_production(); prod && prod->first_child())
887  return iterator(prod->first_child());
888  else
889  return end();
890  }
891  iterator end() const noexcept
892  {
893  // The last child has a next pointer back to the parent,
894  // so if we keep following it, we'll end up here.
895  return iterator(_node);
896  }
897 
898  private:
900  {
902  }
903 
905 
906  friend node;
907  };
908 
909  auto children() const noexcept
910  {
911  return children_range(_ptr);
912  }
913 
915  {
916  public:
917  class iterator : public _detail::forward_iterator_base<iterator, node, node, void>
918  {
919  public:
920  iterator() noexcept : _cur() {}
921 
922  node deref() const noexcept
923  {
924  return node(_cur);
925  }
926 
927  void increment() noexcept
928  {
929  if (_cur->next_role() == _detail::pt_node<Reader>::role_parent)
930  // We're pointing to the parent, go to first child instead.
931  _cur = _cur->next_node()->as_production()->first_child();
932  else
933  // We're pointing to a sibling, go there.
934  _cur = _cur->next_node();
935  }
936 
937  bool equal(iterator rhs) const noexcept
938  {
939  return _cur == rhs._cur;
940  }
941 
942  private:
943  explicit iterator(_detail::pt_node<Reader>* ptr) noexcept : _cur(ptr) {}
944 
946 
948  };
949 
950  bool empty() const noexcept
951  {
952  return begin() == end();
953  }
954 
955  iterator begin() const noexcept
956  {
957  // We begin with the next node after ours.
958  // If we don't have siblings, this is our node itself.
959  return ++iterator(_node);
960  }
961  iterator end() const noexcept
962  {
963  // We end when we're back at the node.
964  return iterator(_node);
965  }
966 
967  private:
968  explicit sibling_range(_detail::pt_node<Reader>* node) noexcept : _node(node) {}
969 
971 
972  friend node;
973  };
974 
975  auto siblings() const noexcept
976  {
977  return sibling_range(_ptr);
978  }
979 
980  bool is_last_child() const noexcept
981  {
982  // We're the last child if our pointer points to the parent.
983  return _ptr->next_role() == _detail::pt_node<Reader>::role_parent;
984  }
985 
986  auto lexeme() const noexcept
987  {
988  if (auto token = _ptr->as_token())
989  return lexy::lexeme<Reader>(token->begin, token->end());
990  else
991  return lexy::lexeme<Reader>();
992  }
993 
994  auto token() const noexcept
995  {
996  LEXY_PRECONDITION(kind().is_token());
997 
998  auto token = _ptr->as_token();
1000  return lexy::token<Reader, TokenKind>(kind, token->begin, token->end());
1001  }
1002 
1003  friend bool operator==(node lhs, node rhs) noexcept
1004  {
1005  return lhs._ptr == rhs._ptr;
1006  }
1007  friend bool operator!=(node lhs, node rhs) noexcept
1008  {
1009  return lhs._ptr != rhs._ptr;
1010  }
1011 
1012 private:
1013  explicit node(_detail::pt_node<Reader>* ptr) noexcept : _ptr(ptr) {}
1014 
1016 
1017  friend parse_tree;
1018 };
1019 
1020 enum class traverse_event
1021 {
1023  enter,
1025  exit,
1027  leaf,
1028 };
1029 
1030 template <typename Reader, typename TokenKind, typename MemoryResource>
1031 class parse_tree<Reader, TokenKind, MemoryResource>::traverse_range
1032 {
1033 public:
1034  using event = traverse_event;
1035 
1037  {
1040  };
1041 
1042  class iterator : public _detail::forward_iterator_base<iterator, _value_type, _value_type, void>
1043  {
1044  public:
1045  iterator() noexcept = default;
1046 
1047  _value_type deref() const noexcept
1048  {
1049  return {_ev, node(_cur)};
1050  }
1051 
1052  void increment() noexcept
1053  {
1054  if (_ev == traverse_event::enter)
1055  {
1056  auto child = _cur->as_production()->first_child();
1057  if (child)
1058  {
1059  // We go to the first child next.
1060  if (child->as_token())
1062  else
1064 
1065  _cur = child;
1066  }
1067  else
1068  {
1069  // Don't have children, exit.
1071  }
1072  }
1073  else
1074  {
1075  // We follow the next pointer.
1076 
1077  if (_cur->next_role() == _detail::pt_node<Reader>::role_parent)
1078  // We go back to a production for the second time.
1080  else if (_cur->next_node()->as_production())
1081  // We're having a production as sibling.
1083  else
1084  // Token as sibling.
1086 
1087  _cur = _cur->next_node();
1088  }
1089  }
1090 
1091  bool equal(iterator rhs) const noexcept
1092  {
1093  return _ev == rhs._ev && _cur == rhs._cur;
1094  }
1095 
1096  private:
1097  _detail::pt_node<Reader>* _cur = nullptr;
1099 
1101  };
1102 
1103  bool empty() const noexcept
1104  {
1105  return _begin == _end;
1106  }
1107 
1108  iterator begin() const noexcept
1109  {
1110  return _begin;
1111  }
1112 
1113  iterator end() const noexcept
1114  {
1115  return _end;
1116  }
1117 
1118 private:
1119  traverse_range() noexcept = default;
1121  {
1122  if (n.kind().is_token())
1123  {
1124  _begin._cur = n._ptr;
1125  _begin._ev = traverse_event::leaf;
1126 
1127  _end = _detail::next(_begin);
1128  }
1129  else
1130  {
1131  _begin._cur = n._ptr;
1132  _begin._ev = traverse_event::enter;
1133 
1134  _end._cur = n._ptr;
1135  _end._ev = traverse_event::exit;
1136  ++_end; // half-open range
1137  }
1138  }
1139 
1140  iterator _begin, _end;
1141 
1142  friend parse_tree;
1143 };
1144 } // namespace lexy
1145 
1146 #endif // LEXY_PARSE_TREE_HPP_INCLUDED
1147 
cx::size
constexpr auto size(const C &c) -> decltype(c.size())
Definition: wildcards.hpp:636
lexy::parse_tree::traverse
traverse_range traverse(const node &n) const noexcept
Definition: parse_tree.hpp:378
LEXY_MOV
#define LEXY_MOV(...)
Definition: config.hpp:21
lexy::parse_tree::node::siblings
auto siblings() const noexcept
Definition: parse_tree.hpp:975
lexy::_detail::pt_node
Definition: parse_tree.hpp:18
lexy::parse_tree::node_kind::is_root
bool is_root() const noexcept
Definition: parse_tree.hpp:733
lexy::parse_tree::node::_ptr
_detail::pt_node< Reader > * _ptr
Definition: parse_tree.hpp:1015
lexy::_detail::pt_node_token::_optimize_end
static constexpr auto _optimize_end
Definition: parse_tree.hpp:100
lexy::_detail::pt_node::pt_node
pt_node(unsigned type)
Definition: parse_tree.hpp:71
lexy::parse_tree::traverse_range::_value_type::event
traverse_event event
Definition: parse_tree.hpp:1038
lexy::parse_tree::node::children_range::iterator::iterator
iterator(_detail::pt_node< Reader > *ptr) noexcept
Definition: parse_tree.hpp:864
lexy::parse_tree::_depth
std::size_t _depth
Definition: parse_tree.hpp:400
lexy::parse_tree::node_kind::is_token
bool is_token() const noexcept
Definition: parse_tree.hpp:724
lexy::parse_tree::node::children_range::empty
bool empty() const noexcept
Definition: parse_tree.hpp:871
lexy::parse_tree::traverse_range
Definition: parse_tree.hpp:1031
lexy::parse_tree::builder::marker
Definition: parse_tree.hpp:411
lexy::parse_tree::builder::_result
parse_tree _result
Definition: parse_tree.hpp:716
lexy::_detail::pt_buffer::block
Definition: parse_tree.hpp:194
lexy::parse_tree::node_kind::operator==
friend bool operator==(production_info info, node_kind nk)
Definition: parse_tree.hpp:792
lexy::_detail::pt_buffer::_cur_block
block * _cur_block
Definition: parse_tree.hpp:322
lexy::parse_tree::node::children_range::iterator::deref
node deref() const noexcept
Definition: parse_tree.hpp:848
lexy::_detail::memory_resource_ptr
std::conditional_t< std::is_void_v< MemoryResource >, _memory_resource_ptr_empty< default_memory_resource >, std::conditional_t< std::is_empty_v< MemoryResource >, _memory_resource_ptr_empty< MemoryResource >, _memory_resource_ptr< MemoryResource > >> memory_resource_ptr
Definition: memory_resource.hpp:140
lexy::parse_tree::traverse_range::iterator::equal
bool equal(iterator rhs) const noexcept
Definition: parse_tree.hpp:1091
iterator.hpp
lexy::_detail::pt_buffer::~pt_buffer
~pt_buffer() noexcept
Definition: parse_tree.hpp:234
lexy::parse_tree::builder::marker::unwind_pos
void * unwind_pos
Definition: parse_tree.hpp:418
config.hpp
lexy::_detail::pt_buffer::_cur_pos
unsigned char * _cur_pos
Definition: parse_tree.hpp:323
lexy::parse_tree::_remaining_input
lexy::lexeme< Reader > _remaining_input
Definition: parse_tree.hpp:401
lexy::_detail::pt_node::next_node
pt_node< Reader > * next_node() const noexcept
Definition: parse_tree.hpp:64
lexy::parse_tree::node_kind::is_production
bool is_production() const noexcept
Definition: parse_tree.hpp:728
lexy::parse_events
Definition: trace.hpp:14
lexy::_detail::get_memory_resource
constexpr MemoryResource * get_memory_resource()
Definition: memory_resource.hpp:146
lexy::_detail::pt_node::as_token
auto as_token() noexcept
Definition: parse_tree.hpp:40
lexy::_detail::pt_node::as_production
auto as_production() noexcept
Definition: parse_tree.hpp:44
lexy::parse_tree::node::sibling_range::iterator::_cur
_detail::pt_node< Reader > * _cur
Definition: parse_tree.hpp:945
lexy::parse_tree::traverse
traverse_range traverse() const noexcept
Definition: parse_tree.hpp:382
lexy::parse_tree::node::token
auto token() const noexcept
Definition: parse_tree.hpp:994
lexy::_detail::pt_node::role_parent
static constexpr auto role_parent
Definition: parse_tree.hpp:32
lexy::token_kind::ignore_if_empty
constexpr bool ignore_if_empty() const noexcept
Definition: token.hpp:168
lexy::parse_tree::parse_tree
constexpr parse_tree(MemoryResource *resource)
Definition: parse_tree.hpp:338
lexy::parse_tree::builder::marker::first_child
_detail::pt_node< Reader > * first_child
Definition: parse_tree.hpp:425
lexy::parse_tree::builder::_cur
marker _cur
Definition: parse_tree.hpp:717
lexy::parse_tree::builder::set_container_production
void set_container_production(production_info production)
Definition: parse_tree.hpp:624
lexy::traverse_event::exit
@ exit
We're visiting a production node after all its children.
lexy::parse_tree::builder::marker::prod
_detail::pt_node_production< Reader > * prod
Definition: parse_tree.hpp:421
lexy::_detail::pt_buffer::pt_buffer
pt_buffer(pt_buffer &&other) noexcept
Definition: parse_tree.hpp:226
lexy::_detail::pt_buffer::block::allocate
static block * allocate(resource_ptr resource)
Definition: parse_tree.hpp:199
lexy::_detail::pt_buffer::block::memory
unsigned char memory[block_size]
Definition: parse_tree.hpp:197
lexy::parse_tree::node_kind::operator==
friend bool operator==(node_kind nk, token_kind< TokenKind > tk)
Definition: parse_tree.hpp:768
lexy::parse_tree::node_kind
Definition: parse_tree.hpp:721
lexy::token
A parsed token, i.e. its kind and its lexeme.
Definition: token.hpp:228
lexy::_detail::pt_buffer::block::end
unsigned char * end() noexcept
Definition: parse_tree.hpp:214
lexy::parse_tree::traverse_range::iterator::increment
void increment() noexcept
Definition: parse_tree.hpp:1052
LEXY_FWD
#define LEXY_FWD(...)
Definition: config.hpp:22
lexy::parse_tree::node::children_range::children_range
children_range(_detail::pt_node< Reader > *node)
Definition: parse_tree.hpp:899
lexy::_detail::pt_node::_value
std::uintptr_t _value
Definition: parse_tree.hpp:92
lexy::parse_tree::node::sibling_range::iterator::iterator
iterator(_detail::pt_node< Reader > *ptr) noexcept
Definition: parse_tree.hpp:943
lexy::parse_tree::node::sibling_range::node
friend node
Definition: parse_tree.hpp:972
token.hpp
lexy::parse_tree::node_kind::operator==
friend bool operator==(token_kind< TokenKind > tk, node_kind nk)
Definition: parse_tree.hpp:775
lexy::parse_tree::node::parent
auto parent() const noexcept
Definition: parse_tree.hpp:827
lexy::parse_tree::builder::builder
builder(production_info production)
Definition: parse_tree.hpp:543
lexy::_detail::pt_node::type_token
static constexpr auto type_token
Definition: parse_tree.hpp:28
lexy::_detail::next
constexpr Iterator next(Iterator iter)
Definition: iterator.hpp:38
lexy::parse_tree::node::children_range::iterator::iterator
iterator() noexcept
Definition: parse_tree.hpp:846
lexy::parse_tree::builder::marker::insert_children_into
void insert_children_into(_detail::pt_node_production< Reader > *parent)
Definition: parse_tree.hpp:484
lexy::parse_tree::node_kind::operator!=
friend bool operator!=(node_kind lhs, node_kind rhs)
Definition: parse_tree.hpp:763
lexy::parse_tree::builder::builder
builder(parse_tree &&tree, production_info production)
Definition: parse_tree.hpp:528
lexy::parse_tree::node_kind::operator!=
friend bool operator!=(token_kind< TokenKind > tk, node_kind nk)
Definition: parse_tree.hpp:783
lexy::parse_tree::builder::marker::child_count
std::size_t child_count
Definition: parse_tree.hpp:423
lexy
Definition: any_ref.hpp:12
LEXY_PRECONDITION
#define LEXY_PRECONDITION(Expr)
Definition: assert.hpp:36
lexy::is_production
constexpr bool is_production
Definition: grammar.hpp:136
lexy::_detail::pt_node_token::begin
Reader::iterator begin
Definition: parse_tree.hpp:105
lexy::_detail::pt_buffer::reserve
void reserve(std::size_t size)
Definition: parse_tree.hpp:265
cx::end
constexpr auto end(const C &c) -> decltype(c.end())
Definition: wildcards.hpp:686
lexy::parse_tree::node::children_range::iterator::children_range
friend children_range
Definition: parse_tree.hpp:868
lexy::parse_tree::builder::finish_production
void finish_production(marker &&m)
Definition: parse_tree.hpp:577
lexy::_detail::pt_buffer::_head
block * _head
Definition: parse_tree.hpp:320
grammar.hpp
lexy::parse_tree::traverse_range::begin
iterator begin() const noexcept
Definition: parse_tree.hpp:1108
lexy::parse_tree::node::node
node(_detail::pt_node< Reader > *ptr) noexcept
Definition: parse_tree.hpp:1013
lexy::_detail::pt_node_token::update_end
void update_end(typename Reader::iterator end) noexcept
Definition: parse_tree.hpp:124
lexy::parse_tree::node_kind::is_token_production
bool is_token_production() const noexcept
Definition: parse_tree.hpp:738
lexy::parse_tree::node::sibling_range
Definition: parse_tree.hpp:914
lexy::parse_tree::node::children_range::iterator
Definition: parse_tree.hpp:843
lexy::parse_tree::node::is_last_child
bool is_last_child() const noexcept
Definition: parse_tree.hpp:980
lexy::parse_tree::traverse_range::end
iterator end() const noexcept
Definition: parse_tree.hpp:1113
lexy::_detail::pt_node::set_parent
void set_parent(pt_node_production< Reader > *parent) noexcept
Definition: parse_tree.hpp:54
lexy::parse_tree::builder::marker::last_child
_detail::pt_node< Reader > * last_child
Definition: parse_tree.hpp:426
lexy::token::kind
constexpr token_kind< TokenKind > kind() const noexcept
Definition: token.hpp:244
lexy::_detail::pt_node::role_sibling
static constexpr auto role_sibling
Definition: parse_tree.hpp:31
lexy::parse_tree::traverse_range::parse_tree
friend parse_tree
Definition: parse_tree.hpp:1142
lexy::parse_tree::node_kind::node_kind
node_kind(_detail::pt_node< Reader > *ptr)
Definition: parse_tree.hpp:806
lexy::parse_tree::node_kind::operator!=
friend bool operator!=(node_kind nk, token_kind< TokenKind > tk)
Definition: parse_tree.hpp:779
lexy::parse_tree::node::children_range::begin
iterator begin() const noexcept
Definition: parse_tree.hpp:884
lexy::parse_tree::_root
_detail::pt_node_production< Reader > * _root
Definition: parse_tree.hpp:398
lexy::parse_tree::builder::finish_container
void finish_container(marker &&m)
Definition: parse_tree.hpp:662
lexy::parse_tree::node::children_range::iterator::_cur
_detail::pt_node< Reader > * _cur
Definition: parse_tree.hpp:866
lexy::_detail::pt_node_token::_end_t
std::conditional_t< _optimize_end, std::uint_least32_t, typename Reader::iterator > _end_t
Definition: parse_tree.hpp:103
lexy::parse_tree::node::sibling_range::empty
bool empty() const noexcept
Definition: parse_tree.hpp:950
lexy::parse_tree::clear
void clear() noexcept
Definition: parse_tree.hpp:359
lexy::_detail::pt_node_token::pt_node_token
pt_node_token(std::uint_least16_t kind, typename Reader::iterator begin, typename Reader::iterator end) noexcept
Definition: parse_tree.hpp:109
lexy::token_kind
What sort of token it is.
Definition: token.hpp:102
lexy::parse_tree::builder::start_production
auto start_production(production_info production)
Definition: parse_tree.hpp:555
lexy::_detail::pt_node_production::first_child_adjacent
std::size_t first_child_adjacent
Definition: parse_tree.hpp:151
lexy::_detail::swap
constexpr void swap(T &lhs, T &rhs)
Definition: config.hpp:45
lexy::parse_tree::node::operator!=
friend bool operator!=(node lhs, node rhs) noexcept
Definition: parse_tree.hpp:1007
lexy::_detail::pt_node::_make_packed_ptr
static std::uintptr_t _make_packed_ptr(pt_node< Reader > *ptr, unsigned type, unsigned role)
Definition: parse_tree.hpp:78
lexy::parse_tree::node::children_range
Definition: parse_tree.hpp:840
lexy::parse_tree::node_kind::_ptr
_detail::pt_node< Reader > * _ptr
Definition: parse_tree.hpp:808
lexy::_detail::pt_node_token::end_impl
_end_t end_impl
Definition: parse_tree.hpp:106
lexy::parse_tree::node_kind::operator!=
friend bool operator!=(node_kind nk, production_info info)
Definition: parse_tree.hpp:796
lexy::_detail::pt_node_production::id
const char *const * id
Definition: parse_tree.hpp:148
lexy_ext::child
auto child(const lexy::parse_tree< Reader, TokenKind, MemoryResource > &tree, typename lexy::parse_tree< Reader, TokenKind, MemoryResource >::node node, Predicate predicate) -> std::optional< typename lexy::parse_tree< Reader, TokenKind, MemoryResource >::node >
Returns the first child that matches predicate, if there is any.
Definition: parse_tree_algorithm.hpp:244
lexy::parse_tree::builder::marker::cur_depth
std::size_t cur_depth
Definition: parse_tree.hpp:430
lexy::_detail::pt_buffer::block::deallocate
static block * deallocate(resource_ptr resource, block *ptr)
Definition: parse_tree.hpp:207
lexy::_detail::pt_buffer::operator=
pt_buffer & operator=(pt_buffer &&other) noexcept
Definition: parse_tree.hpp:241
lexy::token_kind::from_raw
static constexpr token_kind< TokenKind > from_raw(std::uint_least16_t kind) noexcept
Definition: token.hpp:205
lexy::production_info::is_transparent
bool is_transparent
Definition: grammar.hpp:183
lexy::parse_tree::builder
Definition: parse_tree.hpp:408
lexy::parse_tree::builder::marker::builder
friend builder
Definition: parse_tree.hpp:524
lexy::parse_tree::builder::finish
parse_tree && finish(lexy::lexeme< Reader > remaining_input={}) &&
Definition: parse_tree.hpp:545
lexy::parse_tree::node::lexeme
auto lexeme() const noexcept
Definition: parse_tree.hpp:986
lexy::traverse_event::leaf
@ leaf
We're visiting a token.
lexy::_detail::pt_buffer::_resource
LEXY_EMPTY_MEMBER resource_ptr _resource
Definition: parse_tree.hpp:319
lexy::parse_tree
Definition: parse_tree.hpp:331
lexy::parse_tree::builder::cancel_production
void cancel_production(marker &&m)
Definition: parse_tree.hpp:592
lexy::parse_tree::node::sibling_range::end
iterator end() const noexcept
Definition: parse_tree.hpp:961
assert.hpp
lexy::parse_tree::_size
std::size_t _size
Definition: parse_tree.hpp:399
lexy::parse_tree::node::sibling_range::_node
_detail::pt_node< Reader > * _node
Definition: parse_tree.hpp:970
lexy::_detail::pt_node::type_production
static constexpr auto type_production
Definition: parse_tree.hpp:29
lexy::parse_tree::node
Definition: parse_tree.hpp:814
lexy::_detail::pt_node_production
Definition: parse_tree.hpp:22
lexy::_detail::pt_buffer::remaining_capacity
std::size_t remaining_capacity() const noexcept
Definition: parse_tree.hpp:314
lexy::error_token_kind
@ error_token_kind
Definition: grammar.hpp:77
lexy::parse_tree::node::children_range::iterator::equal
bool equal(iterator rhs) const noexcept
Definition: parse_tree.hpp:858
magic_enum::detail::n
constexpr auto n() noexcept
Definition: magic_enum.hpp:417
lexy::_detail::pt_buffer::top
void * top()
Definition: parse_tree.hpp:290
lexy::_detail::pt_buffer
Definition: parse_tree.hpp:188
lexy::parse_tree::node::children_range::_node
_detail::pt_node< Reader > * _node
Definition: parse_tree.hpp:904
lexy::_detail::pt_buffer::pt_buffer
constexpr pt_buffer(MemoryResource *resource) noexcept
Definition: parse_tree.hpp:222
lexy::parse_tree::node::children_range::size
std::size_t size() const noexcept
Definition: parse_tree.hpp:876
lexy::traverse_event
traverse_event
Definition: parse_tree.hpp:1020
lexy::parse_tree::builder::start_container
marker start_container()
Definition: parse_tree.hpp:605
cx::begin
constexpr auto begin(const C &c) -> decltype(c.begin())
Definition: wildcards.hpp:661
lexy::parse_tree::builder::marker::insert
void insert(_detail::pt_node< Reader > *child)
Definition: parse_tree.hpp:447
lexy::parse_tree::remaining_input
lexy::lexeme< Reader > remaining_input() const noexcept
Definition: parse_tree.hpp:391
lexy::parse_tree::node::kind
auto kind() const noexcept
Definition: parse_tree.hpp:822
lexy::parse_tree::node_kind::name
const char * name() const noexcept
Definition: parse_tree.hpp:743
lexy::_detail::pt_node_production::child_count_bits
static constexpr std::size_t child_count_bits
Definition: parse_tree.hpp:146
lexy::parse_tree::node::children_range::node
friend node
Definition: parse_tree.hpp:906
lexy::_detail::pt_buffer::resource_ptr
_detail::memory_resource_ptr< MemoryResource > resource_ptr
Definition: parse_tree.hpp:190
lexy::parse_tree::node_kind::operator!=
friend bool operator!=(production_info info, node_kind nk)
Definition: parse_tree.hpp:800
lexy::_detail::pt_node_token::kind
::uint_least16_t kind
Definition: parse_tree.hpp:107
lexy::_detail
Definition: any_ref.hpp:12
lexy::_detail::pt_buffer::block_size
static constexpr std::size_t block_size
Definition: parse_tree.hpp:192
lexy::parse_tree::builder::cancel_container
void cancel_container(marker &&m)
Definition: parse_tree.hpp:678
lexy::parse_tree::traverse_range::iterator
Definition: parse_tree.hpp:1042
lexy::parse_tree::node::address
void * address() const noexcept
Definition: parse_tree.hpp:817
lexy::parse_tree::node::children_range::end
iterator end() const noexcept
Definition: parse_tree.hpp:891
lexy::parse_tree::traverse_range::empty
bool empty() const noexcept
Definition: parse_tree.hpp:1103
lexy::parse_tree::builder::marker::local_max_depth
std::size_t local_max_depth
Definition: parse_tree.hpp:432
std
Definition: std.hpp:30
lexy::_detail::pt_node::set_sibling
void set_sibling(pt_node< Reader > *sibling) noexcept
Definition: parse_tree.hpp:50
lexy::lexeme
Definition: lexeme.hpp:16
lexy::parse_tree::traverse_range::iterator::deref
_value_type deref() const noexcept
Definition: parse_tree.hpp:1047
lexy::_detail::pt_node::type
unsigned type() const noexcept
Definition: parse_tree.hpp:35
lexy::parse_tree::_buffer
_detail::pt_buffer< MemoryResource > _buffer
Definition: parse_tree.hpp:397
lexy::_detail::pt_buffer::unwind
void unwind(void *marker) noexcept
Definition: parse_tree.hpp:295
lexy::parse_tree::builder::token
void token(token_kind< TokenKind > _kind, typename Reader::iterator begin, typename Reader::iterator end)
Definition: parse_tree.hpp:689
lexy::parse_tree::traverse_range::_value_type::node
parse_tree::node node
Definition: parse_tree.hpp:1039
lexy::parse_tree::node::sibling_range::iterator::iterator
iterator() noexcept
Definition: parse_tree.hpp:920
lexy::parse_tree::parse_tree
constexpr parse_tree()
Definition: parse_tree.hpp:337
lexy::_detail::pt_buffer::reset
void reset()
Definition: parse_tree.hpp:256
lexy::parse_tree::empty
bool empty() const noexcept
Definition: parse_tree.hpp:343
lexy::production_info
Definition: grammar.hpp:178
lexy::parse_tree::builder::marker::update_size_depth
void update_size_depth(std::size_t &size, std::size_t &max_depth)
Definition: parse_tree.hpp:512
lexy::_detail::pt_node_token::end
Reader::iterator end() const noexcept
Definition: parse_tree.hpp:116
lexy::parse_tree::builder::marker::marker
marker()
Definition: parse_tree.hpp:414
lexy::_detail::pt_node_production::child_count
std::size_t child_count
Definition: parse_tree.hpp:149
lexy::parse_tree::builder::marker::marker
marker(void *unwind_pos, std::size_t cur_depth, _detail::pt_node_production< Reader > *prod=nullptr)
Definition: parse_tree.hpp:434
lexy::_detail::pt_node_production::pt_node_production
pt_node_production(production_info info) noexcept
Definition: parse_tree.hpp:153
lexy::parse_tree::node::sibling_range::iterator::sibling_range
friend sibling_range
Definition: parse_tree.hpp:947
LEXY_EMPTY_MEMBER
#define LEXY_EMPTY_MEMBER
Definition: config.hpp:170
lexy::_detail::forward_iterator_base
Definition: iterator.hpp:157
lexy::parse_tree::traverse_range::_value_type
Definition: parse_tree.hpp:1036
lexy::parse_tree::builder::marker::insert_list
void insert_list(std::size_t length, _detail::pt_node< Reader > *first, _detail::pt_node< Reader > *last)
Definition: parse_tree.hpp:464
lexy::parse_tree::node::children_range::iterator::increment
void increment() noexcept
Definition: parse_tree.hpp:853
lexy::parse_tree::node::operator==
friend bool operator==(node lhs, node rhs) noexcept
Definition: parse_tree.hpp:1003
lexy::parse_tree::size
std::size_t size() const noexcept
Definition: parse_tree.hpp:348
lexy::parse_tree::node::sibling_range::begin
iterator begin() const noexcept
Definition: parse_tree.hpp:955
lexy::parse_tree::traverse_range::iterator::_ev
traverse_event _ev
Definition: parse_tree.hpp:1098
lexy::parse_tree::traverse_range::_end
iterator _end
Definition: parse_tree.hpp:1140
lexy::parse_tree::traverse_range::iterator::traverse_range
friend traverse_range
Definition: parse_tree.hpp:1100
lexy::_detail::pt_buffer::block::next
block * next
Definition: parse_tree.hpp:196
lexy::_detail::pt_node_production::token_production
std::size_t token_production
Definition: parse_tree.hpp:150
lexy::parse_tree::node::children
auto children() const noexcept
Definition: parse_tree.hpp:909
lexy::_detail::pt_node_production::first_child
pt_node< Reader > * first_child()
Definition: parse_tree.hpp:161
lexy::parse_tree::node::sibling_range::sibling_range
sibling_range(_detail::pt_node< Reader > *node) noexcept
Definition: parse_tree.hpp:968
lexy::traverse_event::enter
@ enter
We're visiting a production node before all its children.
lexy::parse_tree::node::sibling_range::iterator::deref
node deref() const noexcept
Definition: parse_tree.hpp:922
lexy::_detail::pt_node_token
Definition: parse_tree.hpp:20
lexy::_detail::pt_buffer::allocate
T * allocate(Args &&... args)
Definition: parse_tree.hpp:277
lexy::parse_tree::node::sibling_range::iterator::equal
bool equal(iterator rhs) const noexcept
Definition: parse_tree.hpp:937
lexy::parse_tree::node::sibling_range::iterator
Definition: parse_tree.hpp:917
LEXY_ASSERT
#define LEXY_ASSERT(Expr, Msg)
Definition: assert.hpp:37
lexy::parse_tree::node_kind::operator==
friend bool operator==(node_kind lhs, node_kind rhs)
Definition: parse_tree.hpp:756
lexy::parse_tree::node::sibling_range::iterator::increment
void increment() noexcept
Definition: parse_tree.hpp:927
lexy::parse_tree::root
node root() const noexcept
Definition: parse_tree.hpp:369
lexy::parse_tree::depth
std::size_t depth() const noexcept
Definition: parse_tree.hpp:353
lexy::_detail::pt_node::next_role
unsigned next_role() const noexcept
Definition: parse_tree.hpp:59
lexy::parse_tree::node::parse_tree
friend parse_tree
Definition: parse_tree.hpp:1017
lexy::token_kind::to_raw
static constexpr std::uint_least16_t to_raw(token_kind< TokenKind > kind) noexcept
Definition: token.hpp:201
lexy::parse_tree::node_kind::operator==
friend bool operator==(node_kind nk, production_info info)
Definition: parse_tree.hpp:788
memory_resource.hpp
lexy::parse_tree::builder::marker::clear
void clear()
Definition: parse_tree.hpp:440


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