parse_tree_algorithm.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_EXT_PARSE_TREE_ALGORITHM_HPP_INCLUDED
5 #define LEXY_EXT_PARSE_TREE_ALGORITHM_HPP_INCLUDED
6 
7 #include <lexy/parse_tree.hpp>
8 #include <optional>
9 
10 namespace lexy_ext
11 {
14 template <typename Reader, typename TokenKind, typename MemoryResource>
17 {
19  using node_t = typename tree_t::node;
20  using traverse_range = typename tree_t::traverse_range;
21  using traverse_iterator = typename traverse_range::iterator;
22 
23  class token_range
24  {
25  public:
26  class iterator;
27  struct sentinel : lexy::_detail::sentinel_base<sentinel, iterator>
28  {};
29 
30  class iterator : public lexy::_detail::forward_iterator_base<iterator, node_t, node_t, void>
31  {
32  public:
33  iterator() noexcept = default;
34 
35  auto deref() const noexcept
36  {
37  LEXY_PRECONDITION(_cur != _end);
38  LEXY_ASSERT(_cur->event == lexy::traverse_event::leaf, "invalid increment");
39  return _cur->node;
40  }
41 
42  void increment() noexcept
43  {
44  LEXY_PRECONDITION(_cur != _end);
45 
46  // Advance at least once.
47  ++_cur;
48  // Continue advancing until the next token is found.
49  while (_cur != _end && _cur->event != lexy::traverse_event::leaf)
50  ++_cur;
51  }
52 
53  bool equal(iterator rhs) const noexcept
54  {
55  return _cur == rhs._cur;
56  }
57  bool is_end() const noexcept
58  {
59  return _cur == _end;
60  }
61 
62  private:
63  explicit iterator(const traverse_range& range) noexcept
64  : _cur(range.begin()), _end(range.end())
65  {
66  // Advancing until initial token is found.
67  while (_cur != _end && _cur->event != lexy::traverse_event::leaf)
68  ++_cur;
69  }
70 
71  traverse_iterator _cur;
72  traverse_iterator _end;
73 
74  friend token_range;
75  };
76 
77  explicit token_range(const traverse_range& range) noexcept : _begin(range) {}
78 
79  bool empty() const noexcept
80  {
81  return begin() == end();
82  }
83 
84  iterator begin() const noexcept
85  {
86  return _begin;
87  }
88 
89  sentinel end() const noexcept
90  {
91  return {};
92  }
93 
94  private:
95  iterator _begin;
96  };
97 
98  return token_range(tree.traverse(node));
99 }
100 
101 template <typename Reader, typename TokenKind, typename MemoryResource>
103 {
104  LEXY_PRECONDITION(!tree.empty());
105  return tokens(tree, tree.root());
106 }
107 } // namespace lexy_ext
108 
109 namespace lexy_ext
110 {
113 template <typename Reader, typename TokenKind, typename MemoryResource>
115  typename Reader::iterator position) ->
117 {
118  LEXY_PRECONDITION(!tree.empty());
119 
120  // Just do a linear search over all the tokens.
121  // This can be done more efficiently by pruning subtrees, but this should be fast enough.
122  for (auto token : tokens(tree))
123  {
124  if (position < token.lexeme().end())
125  // We've reached the first token that reaches past the position.
126  // This is the covering one.
127  return token;
128  }
129 
130  LEXY_PRECONDITION(false); // Position out of bounds.
131  return tree.root();
132 }
133 } // namespace lexy_ext
134 
135 namespace lexy_ext
136 {
137 template <typename Predicate, typename Iterator, typename Sentinel>
139 {
140  using node_t = decltype(*Iterator());
141 
142 public:
143  class iterator;
144  struct sentinel : lexy::_detail::sentinel_base<sentinel, iterator>
145  {};
146 
147  class iterator : public lexy::_detail::forward_iterator_base<iterator, node_t, node_t, void>
148  {
149  public:
150  iterator() noexcept = default;
151 
152  auto deref() const noexcept
153  {
155  return *_cur;
156  }
157 
158  void increment() noexcept
159  {
161 
162  // Advance at least once.
163  ++_cur;
164  // Continue advancing until the next matching is found.
165  while (_cur != _end && !_predicate(*_cur))
166  ++_cur;
167  }
168 
169  bool equal(iterator rhs) const noexcept
170  {
171  return _cur == rhs._cur;
172  }
173  bool is_end() const noexcept
174  {
175  return _cur == _end;
176  }
177 
178  private:
179  explicit iterator(Predicate&& pred, Iterator cur, Sentinel end) noexcept
180  : _cur(cur), _end(end), _predicate(LEXY_MOV(pred))
181  {
182  // Advancing until initial token is found.
183  while (_cur != _end && !_predicate(*_cur))
184  ++_cur;
185  }
186 
187  Iterator _cur;
190 
192  };
193 
194  explicit _filtered_node_range(Predicate&& pred, Iterator begin, Sentinel end) noexcept
195  : _begin(LEXY_MOV(pred), begin, end)
196  {}
197 
198  bool empty() const noexcept
199  {
200  return begin() == end();
201  }
202 
203  iterator begin() const noexcept
204  {
205  return _begin;
206  }
207 
208  sentinel end() const noexcept
209  {
210  return {};
211  }
212 
213 private:
215 };
216 
217 template <typename Predicate, typename Iterator, typename Sentinel>
218 _filtered_node_range(Predicate&& pred, Iterator begin, Sentinel end) noexcept
219  ->_filtered_node_range<std::decay_t<Predicate>, Iterator, Sentinel>;
220 
226 template <typename Reader, typename TokenKind, typename MemoryResource, typename Predicate>
229  Predicate predicate)
230 {
231  if constexpr (std::is_constructible_v<lexy::token_kind<TokenKind>, Predicate>)
232  return _filtered_node_range([kind = predicate](auto n) { return n.kind() == kind; },
233  node.children().begin(), node.children().end());
234  else if constexpr (lexy::is_production<Predicate>)
235  return _filtered_node_range([](auto n) { return n.kind() == Predicate{}; },
236  node.children().begin(), node.children().end());
237  else
238  return _filtered_node_range(LEXY_MOV(predicate), node.children().begin(),
239  node.children().end());
240 }
241 
243 template <typename Reader, typename TokenKind, typename MemoryResource, typename Predicate>
246  Predicate predicate)
247  -> std::optional<typename lexy::parse_tree<Reader, TokenKind, MemoryResource>::node>
248 {
249  auto range = children(tree, node, predicate);
250  if (range.empty())
251  return std::nullopt;
252  else
253  return *range.begin();
254 }
255 } // namespace lexy_ext
256 
257 namespace lexy_ext
258 {
265 template <typename Reader, typename TokenKind, typename MemoryResource>
268  typename Reader::iterator
269 {
270  if (auto pos_node = child(tree, node, lexy::position_token_kind))
271  return pos_node->lexeme().begin();
272  else if (auto tokens = lexy_ext::tokens(tree, node); tokens.empty())
273  // The node does not have a token as descendant.
274  return {};
275  else
276  return tokens.begin()->lexeme().begin();
277 }
278 } // namespace lexy_ext
279 
280 #endif // LEXY_EXT_PARSE_TREE_ALGORITHM_HPP_INCLUDED
281 
lexyd::position
constexpr auto position
Produces an iterator to the current reader position without parsing anything.
Definition: position.hpp:79
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_ext::_filtered_node_range::_filtered_node_range
_filtered_node_range(Predicate &&pred, Iterator begin, Sentinel end) noexcept
Definition: parse_tree_algorithm.hpp:194
lexyd::token
constexpr auto token(Rule)
Turns the arbitrary rule into a token by matching it without producing any values.
Definition: dsl/token.hpp:214
lexy_ext::_filtered_node_range::node_t
decltype(*Iterator()) node_t
Definition: parse_tree_algorithm.hpp:140
lexy_ext::_filtered_node_range
Definition: parse_tree_algorithm.hpp:138
lexy_ext::_filtered_node_range::iterator::increment
void increment() noexcept
Definition: parse_tree_algorithm.hpp:158
lexy::position_token_kind
@ position_token_kind
Definition: grammar.hpp:82
lexy_ext::_filtered_node_range::iterator::deref
auto deref() const noexcept
Definition: parse_tree_algorithm.hpp:152
lexy_ext
Definition: compiler_explorer.hpp:12
lexy_ext::_filtered_node_range::_begin
iterator _begin
Definition: parse_tree_algorithm.hpp:214
cx::empty
constexpr auto empty(const C &c) -> decltype(c.empty())
Definition: wildcards.hpp:646
lexy_ext::_filtered_node_range::iterator::equal
bool equal(iterator rhs) const noexcept
Definition: parse_tree_algorithm.hpp:169
LEXY_PRECONDITION
#define LEXY_PRECONDITION(Expr)
Definition: assert.hpp:36
lexy_ext::_filtered_node_range::iterator::iterator
iterator() noexcept=default
lexy_ext::_filtered_node_range::iterator::_end
LEXY_EMPTY_MEMBER Sentinel _end
Definition: parse_tree_algorithm.hpp:188
cx::end
constexpr auto end(const C &c) -> decltype(c.end())
Definition: wildcards.hpp:686
lexy_ext::_filtered_node_range::empty
bool empty() const noexcept
Definition: parse_tree_algorithm.hpp:198
lexy_ext::_filtered_node_range::iterator::_filtered_node_range
friend _filtered_node_range
Definition: parse_tree_algorithm.hpp:191
lexy_ext::_filtered_node_range
_filtered_node_range(Predicate &&pred, Iterator begin, Sentinel end) noexcept -> _filtered_node_range< std::decay_t< Predicate >, Iterator, Sentinel >
lexyd::nullopt
constexpr auto nullopt
Definition: option.hpp:50
lexy_ext::_filtered_node_range::end
sentinel end() const noexcept
Definition: parse_tree_algorithm.hpp:208
lexy_ext::_filtered_node_range::iterator::_cur
Iterator _cur
Definition: parse_tree_algorithm.hpp:187
lexy::token_kind
What sort of token it is.
Definition: token.hpp:102
lexy_ext::_filtered_node_range::iterator::iterator
iterator(Predicate &&pred, Iterator cur, Sentinel end) noexcept
Definition: parse_tree_algorithm.hpp:179
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::traverse_event::leaf
@ leaf
We're visiting a token.
lexy::parse_tree
Definition: parse_tree.hpp:331
lexy_ext::_filtered_node_range::iterator
Definition: parse_tree_algorithm.hpp:147
lexy_ext::_filtered_node_range::iterator::is_end
bool is_end() const noexcept
Definition: parse_tree_algorithm.hpp:173
lexy::parse_tree::node
Definition: parse_tree.hpp:814
magic_enum::detail::n
constexpr auto n() noexcept
Definition: magic_enum.hpp:417
lexy_ext::_filtered_node_range::iterator::_predicate
LEXY_EMPTY_MEMBER Predicate _predicate
Definition: parse_tree_algorithm.hpp:189
lexy_ext::_filtered_node_range::begin
iterator begin() const noexcept
Definition: parse_tree_algorithm.hpp:203
cx::equal
constexpr bool equal(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
Definition: wildcards.hpp:1640
cx::begin
constexpr auto begin(const C &c) -> decltype(c.begin())
Definition: wildcards.hpp:661
lexy_ext::_filtered_node_range::sentinel
Definition: parse_tree_algorithm.hpp:144
lexy_ext::tokens
auto tokens(const lexy::parse_tree< Reader, TokenKind, MemoryResource > &tree, typename lexy::parse_tree< Reader, TokenKind, MemoryResource >::node node)
Definition: parse_tree_algorithm.hpp:15
lexy::parse_tree::empty
bool empty() const noexcept
Definition: parse_tree.hpp:343
LEXY_EMPTY_MEMBER
#define LEXY_EMPTY_MEMBER
Definition: config.hpp:170
lexy::_detail::forward_iterator_base
Definition: iterator.hpp:157
parse_tree.hpp
lexy::_detail::sentinel_base
Definition: iterator.hpp:222
lexy_ext::children
auto children(const lexy::parse_tree< Reader, TokenKind, MemoryResource > &, typename lexy::parse_tree< Reader, TokenKind, MemoryResource >::node node, Predicate predicate)
Definition: parse_tree_algorithm.hpp:227
lexy_ext::find_covering_node
auto find_covering_node(const lexy::parse_tree< Reader, TokenKind, MemoryResource > &tree, typename Reader::iterator position) -> typename lexy::parse_tree< Reader, TokenKind, MemoryResource >::node
Definition: parse_tree_algorithm.hpp:114
lexy_ext::node_position
auto node_position(const lexy::parse_tree< Reader, TokenKind, MemoryResource > &tree, typename lexy::parse_tree< Reader, TokenKind, MemoryResource >::node node) -> typename Reader::iterator
Definition: parse_tree_algorithm.hpp:266
lexy::parse_tree::node::children
auto children() const noexcept
Definition: parse_tree.hpp:909
LEXY_ASSERT
#define LEXY_ASSERT(Expr, Msg)
Definition: assert.hpp:37
lexy::parse_tree::root
node root() const noexcept
Definition: parse_tree.hpp:369


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