input_location.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_INPUT_LOCATION_HPP_INCLUDED
5 #define LEXY_INPUT_LOCATION_HPP_INCLUDED
6 
8 #include <lexy/dsl/newline.hpp>
9 #include <lexy/input/base.hpp>
10 #include <lexy/lexeme.hpp>
11 
12 //=== input_location_anchor ===//
13 namespace lexy
14 {
16 template <typename Input>
18 {
20 
21  constexpr explicit input_location_anchor(const Input& input)
22  : _line_begin(input.reader().position()), _line_nr(1)
23  {}
24 
25  // implementation detail
26  constexpr explicit input_location_anchor(iterator line_begin, unsigned line_nr)
27  : _line_begin(line_begin), _line_nr(line_nr)
28  {}
29 
31  unsigned _line_nr;
32 };
33 } // namespace lexy
34 
35 //=== counting strategies ===//
36 namespace lexy
37 {
40 {
41 public:
42  template <typename Reader>
43  constexpr bool try_match_newline(Reader& reader)
44  {
46  }
47 
48  template <typename Reader>
49  constexpr void match_column(Reader& reader)
50  {
51  reader.bump();
52  }
53 };
54 
57 {
58 public:
59  template <typename Reader>
60  constexpr bool try_match_newline(Reader& reader)
61  {
63  }
64 
65  template <typename Reader>
66  constexpr void match_column(Reader& reader)
67  {
69  reader.bump();
70  }
71 };
72 
74 template <std::size_t LineWidth = 16>
76 {
77 public:
78  template <typename Reader>
79  constexpr bool try_match_newline(Reader& reader)
80  {
81  LEXY_PRECONDITION(_cur_index <= LineWidth - 1);
82  if (_cur_index == LineWidth - 1)
83  {
84  // Consider the last byte to be the "newline".
85  // We need to consume something if possible;
86  // the logic in the function breaks otherwise.
87  if (reader.peek() != Reader::encoding::eof())
88  reader.bump();
89  _cur_index = 0;
90  return true;
91  }
92  else
93  {
94  return false;
95  }
96  }
97 
98  template <typename Reader>
99  constexpr void match_column(Reader& reader)
100  {
101  static_assert(std::is_same_v<typename Reader::encoding, lexy::byte_encoding>);
102 
103  reader.bump();
104  ++_cur_index;
105  }
106 
107 private:
108  std::size_t _cur_index = 0;
109 };
110 
111 template <typename Input>
112 using _default_location_counting = std::conditional_t<
113  std::is_same_v<typename lexy::input_reader<Input>::encoding, lexy::byte_encoding>,
115 } // namespace lexy
116 
117 //=== input_location ===//
118 namespace lexy
119 {
121 template <typename Input, typename Counting = _default_location_counting<Input>>
123 {
125 
126 public:
127  constexpr explicit input_location(const Input& input)
128  : _line_begin(input.reader().position()), _column_begin(_line_begin), _line_nr(1), _column_nr(1)
129  {}
130 
133  {
135  }
136 
137  constexpr unsigned line_nr() const
138  {
139  return _line_nr;
140  }
141  constexpr unsigned column_nr() const
142  {
143  return _column_nr;
144  }
145 
147  constexpr iterator position() const
148  {
149  return _column_begin;
150  }
151 
152  friend constexpr bool operator==(const input_location& lhs, const input_location& rhs)
153  {
154  return lhs._line_nr == rhs._line_nr && lhs._column_nr == rhs._column_nr;
155  }
156  friend constexpr bool operator!=(const input_location& lhs, const input_location& rhs)
157  {
158  return !(lhs == rhs);
159  }
160 
161  friend constexpr bool operator<(const input_location& lhs, const input_location& rhs)
162  {
163  if (lhs._line_nr != rhs._line_nr)
164  return lhs._line_nr < rhs._line_nr;
165  return lhs._column_nr < rhs._colum_nr;
166  }
167  friend constexpr bool operator<=(const input_location& lhs, const input_location& rhs)
168  {
169  return !(rhs < lhs);
170  }
171  friend constexpr bool operator>(const input_location& lhs, const input_location& rhs)
172  {
173  return rhs < lhs;
174  }
175  friend constexpr bool operator>=(const input_location& lhs, const input_location& rhs)
176  {
177  return !(rhs > lhs);
178  }
179 
180 private:
181  constexpr input_location(iterator line_begin, unsigned line_nr, iterator column_begin,
182  unsigned column_nr)
183  : _line_begin(line_begin), _column_begin(column_begin), _line_nr(line_nr), _column_nr(column_nr)
184  {}
185 
187  unsigned _line_nr, _column_nr;
188 
189  template <typename C, typename I>
190  friend constexpr auto get_input_location(const I& input,
194 };
195 
197 template <typename Counting, typename Input>
198 constexpr auto get_input_location(const Input& input,
202 {
203  auto reader = input.reader();
204  reader.set_position(anchor._line_begin);
205 
206  auto line_begin = anchor._line_begin;
207  auto line_nr = anchor._line_nr;
208  auto column_begin = line_begin;
209  auto column_nr = 1u;
210 
211  Counting counting;
212  while (true)
213  {
214  if (reader.position() == position)
215  {
216  // We've already found the position; it's at the beginning of a colum nor newline.
217  // No need to do the expensive checks.
218  //
219  // This also allows `lexy_ext::shell` to work properly, if position is at EOF,
220  // the reader.peek() call will ask for more input.
221  break;
222  }
223  else if (reader.peek() == lexy::input_reader<Input>::encoding::eof())
224  {
225  LEXY_ASSERT(false, "invalid position + anchor combination");
226  }
227  else if (counting.try_match_newline(reader))
228  {
229  // [column_begin, newline_end) covers the newline.
230  auto newline_end = reader.position();
231  if (lexy::_detail::min_range_end(column_begin, newline_end, position) != newline_end)
232  break;
233 
234  // Advance to the next line.
235  ++line_nr;
236  line_begin = newline_end;
237  column_nr = 1;
238  column_begin = line_begin;
239  }
240  else
241  {
242  counting.match_column(reader);
243 
244  // [column_begin, column_end) covers the column.
245  auto column_end = reader.position();
246  if (lexy::_detail::min_range_end(column_begin, column_end, position) != column_end)
247  break;
248 
249  // Advance to the next column.
250  ++column_nr;
251  column_begin = column_end;
252  }
253  }
254 
255  return {line_begin, line_nr, column_begin, column_nr};
256 }
257 
258 template <typename Counting, typename Input>
259 constexpr auto get_input_location(const Input& input,
261 {
262  return get_input_location<Counting>(input, position, input_location_anchor(input));
263 }
264 template <typename Input>
265 constexpr auto get_input_location(const Input& input,
268 {
269  return get_input_location<_default_location_counting<Input>>(input, position, anchor);
270 }
271 template <typename Input>
272 constexpr auto get_input_location(const Input& input,
274 {
275  return get_input_location<_default_location_counting<Input>>(input, position,
276  input_location_anchor(input));
277 }
278 } // namespace lexy
279 
280 //=== input_line_annotation ===//
281 namespace lexy::_detail
282 {
283 template <typename Counting, typename Input>
284 constexpr auto get_input_line(const Input& input,
285  typename lexy::input_reader<Input>::iterator line_begin)
286 {
287  auto reader = input.reader();
288  reader.set_position(line_begin);
289 
290  auto line_end = reader.position();
291  for (Counting counting;
292  reader.peek() != decltype(reader)::encoding::eof() && !counting.try_match_newline(reader);
293  line_end = reader.position())
294  {
295  counting.match_column(reader);
296  }
297  auto newline_end = reader.position();
298 
299  struct result_t
300  {
303  };
304  return result_t{{line_begin, line_end}, {line_end, newline_end}};
305 }
306 
307 // Advances the iterator to the beginning of the next code point.
308 template <typename Encoding, typename Iterator>
309 constexpr Iterator find_cp_boundary(Iterator cur, Iterator end)
310 {
311  auto is_cp_continuation = [](auto c) {
312  if constexpr (std::is_same_v<Encoding,
314  || std::is_same_v<Encoding, lexy::utf8_char_encoding>)
315  return (c & 0b1100'0000) == (0b10 << 6);
316  else if constexpr (std::is_same_v<Encoding, lexy::utf16_encoding>)
317  return 0xDC00 <= c && c <= 0xDFFF;
318  else
319  {
320  // This encoding doesn't have continuation code units.
321  (void)c;
322  return std::false_type{};
323  }
324  };
325 
326  while (cur != end && is_cp_continuation(*cur))
327  ++cur;
328  return cur;
329 }
330 } // namespace lexy::_detail
331 
332 namespace lexy
333 {
334 template <typename Input>
336 {
343 
350 };
351 
352 template <typename Input>
358 {
359  // At this point there are two cases:
360  // Either line.begin() <= begin < end <= newline.end()),
361  // or line.begin() <= begin == end == newline.end().
362 
363  // We then round end to the code point boundary.
364  // Note that we don't round begin.
365  {
366  auto old_end = end;
367 
368  using encoding = typename lexy::input_reader<Input>::encoding;
369  end = _detail::find_cp_boundary<encoding>(end, newline.end());
370 
371  result.rounded_end = end != old_end;
372  }
373 
374  // Now we can compute the annotation.
375  if (lexy::_detail::min_range_end(line.begin(), line.end(), end) == end)
376  {
377  // We have end <= line.end(),
378  // so line.end() is the end of after.
379  result.before = {line.begin(), begin};
380  result.annotated = {begin, end};
381  result.after = {end, line.end()};
382  }
383  else
384  {
385  // We have end > line.end(),
386  // so newline.end() is the end of annotated.
387  result.before = {line.begin(), begin};
388  result.annotated = {begin, newline.end()};
389  result.after = {newline.end(), newline.end()};
390  result.annotated_newline = true;
391  }
392 }
393 
394 template <typename Input, typename Counting>
395 constexpr auto get_input_line_annotation(const Input& input,
396  const input_location<Input, Counting>& begin_location,
399 {
401 
402  auto [line, newline]
403  = _detail::get_input_line<Counting>(input, begin_location.anchor()._line_begin);
404 
405  // We first normalize the range.
406  auto begin = begin_location.position();
407  if (begin == end)
408  {
409  if (end == newline.begin())
410  {
411  // Empty range at the newline; make it cover the entire newline.
412  end = newline.end();
413  }
414  else if (end != newline.end())
415  {
416  // Empty range before end of newline; extend by one code unit.
417  ++end;
418  }
419  else
420  {
421  // begin == end == newline.end()
422  }
423  }
424  else if (lexy::_detail::min_range_end(begin, end, newline.end()) != end)
425  {
426  // Truncate a multiline range to a single line.
427  // Note that we can't have both an empty range and a multiline range.
428  end = newline.end();
429  result.truncated_multiline = true;
430  }
431 
432  _get_input_line_annotation(result, line, newline, begin, end);
433  return result;
434 }
435 
437 template <typename Input, typename Counting>
438 constexpr auto get_input_line_annotation(const Input& input,
439  const input_location<Input, Counting>& location,
440  std::size_t size)
441 {
443  auto [line, newline] = _detail::get_input_line<Counting>(input, location.anchor()._line_begin);
444 
445  // We don't want an empty annotation.
446  auto range_size = size == 0 ? 1 : size;
447 
448  auto begin = location.position();
449  auto end = _detail::next_clamped(location.position(), range_size, newline.end());
450  if (_detail::range_size(location.position(), end) < size)
451  {
452  // We didn't have enough of the current line to match the size request.
453  // As such, we needed to truncate it.
454  result.truncated_multiline = true;
455  }
456 
457  _get_input_line_annotation(result, line, newline, begin, end);
458  return result;
459 }
460 } // namespace lexy
461 
462 #endif // LEXY_INPUT_LOCATION_HPP_INCLUDED
463 
cx::size
constexpr auto size(const C &c) -> decltype(c.size())
Definition: wildcards.hpp:636
lexyd::position
constexpr auto position
Produces an iterator to the current reader position without parsing anything.
Definition: position.hpp:79
lexy::input_location::operator<=
constexpr friend bool operator<=(const input_location &lhs, const input_location &rhs)
Definition: input_location.hpp:167
lexy::code_unit_location_counting::try_match_newline
constexpr bool try_match_newline(Reader &reader)
Definition: input_location.hpp:43
lexy::code_unit_location_counting::match_column
constexpr void match_column(Reader &reader)
Definition: input_location.hpp:49
lexy::input_location_anchor::iterator
typename lexy::input_reader< Input >::iterator iterator
Definition: input_location.hpp:19
lexy::input_location::_line_begin
iterator _line_begin
Definition: input_location.hpp:186
lexy::input_location
A location in the input.
Definition: input_location.hpp:122
lexy::input_location_anchor::input_location_anchor
constexpr input_location_anchor(iterator line_begin, unsigned line_nr)
Definition: input_location.hpp:26
lexy::code_point_location_counting::match_column
constexpr void match_column(Reader &reader)
Definition: input_location.hpp:66
lexy::byte_location_counting::try_match_newline
constexpr bool try_match_newline(Reader &reader)
Definition: input_location.hpp:79
lexy::input_location::iterator
typename lexy::input_reader< Input >::iterator iterator
Definition: input_location.hpp:124
lexy::_get_input_line_annotation
constexpr void _get_input_line_annotation(input_line_annotation< Input > &result, lexy::lexeme_for< Input > line, lexy::lexeme_for< Input > newline, typename lexy::input_reader< Input >::iterator begin, typename lexy::input_reader< Input >::iterator end)
Definition: input_location.hpp:353
lexy::code_point_location_counting::try_match_newline
constexpr bool try_match_newline(Reader &reader)
Definition: input_location.hpp:60
newline.hpp
lexy::input_location_anchor::_line_nr
unsigned _line_nr
Definition: input_location.hpp:31
lexyd::ascii::newline
constexpr auto newline
Definition: ascii.hpp:77
lexy::input_location::_column_begin
iterator _column_begin
Definition: input_location.hpp:186
lexy::_detail::get_input_line
constexpr auto get_input_line(const Input &input, typename lexy::input_reader< Input >::iterator line_begin)
Definition: input_location.hpp:284
lexy::lexeme::begin
constexpr iterator begin() const noexcept
Definition: lexeme.hpp:38
lexyd::code_point
constexpr auto code_point
Matches a single unicode code point in the current unicode encoding.
Definition: dsl/code_point.hpp:200
lexy::get_input_location
constexpr auto get_input_location(const Input &input, typename lexy::input_reader< Input >::iterator position, input_location_anchor< Input > anchor) -> input_location< Input, Counting >
The location for a position in the input; search starts at the anchor.
Definition: input_location.hpp:198
lexy
Definition: any_ref.hpp:12
LEXY_PRECONDITION
#define LEXY_PRECONDITION(Expr)
Definition: assert.hpp:36
lexy::input_location::input_location
constexpr input_location(iterator line_begin, unsigned line_nr, iterator column_begin, unsigned column_nr)
Definition: input_location.hpp:181
cx::end
constexpr auto end(const C &c) -> decltype(c.end())
Definition: wildcards.hpp:686
lexy::input_location::column_nr
constexpr unsigned column_nr() const
Definition: input_location.hpp:141
lexy::_detail::next_clamped
constexpr Iterator next_clamped(Iterator iter, std::size_t n, Sentinel end)
Definition: iterator.hpp:58
lexy::input_line_annotation::rounded_end
bool rounded_end
true if end needed to be moved to a code point boundary.
Definition: input_location.hpp:349
lexy::input_location::get_input_location
constexpr friend auto get_input_location(const I &input, typename lexy::input_reader< I >::iterator position, input_location_anchor< I > anchor) -> input_location< I, C >
lexy::input_location::operator!=
constexpr friend bool operator!=(const input_location &lhs, const input_location &rhs)
Definition: input_location.hpp:156
lexy::input_location::line_nr
constexpr unsigned line_nr() const
Definition: input_location.hpp:137
lexy::get_input_line_annotation
constexpr auto get_input_line_annotation(const Input &input, const input_location< Input, Counting > &begin_location, typename lexy::input_reader< Input >::iterator end) -> input_line_annotation< Input >
Definition: input_location.hpp:395
lexy::input_location::position
constexpr iterator position() const
The corresponding position, rounded down to the previous column start.
Definition: input_location.hpp:147
lexy::try_match_token
constexpr LEXY_FORCE_INLINE auto try_match_token(TokenRule, Reader &reader)
Definition: dsl/base.hpp:232
lexeme.hpp
lexy::input_line_annotation
Definition: input_location.hpp:335
lexy::byte_encoding
An encoding where the input is just raw bytes, not characters.
Definition: encoding.hpp:180
lexy::byte_location_counting::match_column
constexpr void match_column(Reader &reader)
Definition: input_location.hpp:99
lexy::byte_location_counting
Counts bytes for columns, lines end after LineWidth bytes.
Definition: input_location.hpp:75
lexy::input_line_annotation::annotated
lexy::lexeme_for< Input > annotated
The annotated part.
Definition: input_location.hpp:340
lexy::utf8_encoding
An encoding where the input is assumed to be valid UTF-8.
Definition: encoding.hpp:84
lexy::input_location::operator>=
constexpr friend bool operator>=(const input_location &lhs, const input_location &rhs)
Definition: input_location.hpp:175
code_point.hpp
lexy::_detail::range_size
constexpr std::size_t range_size(Iterator begin, Sentinel end)
Definition: iterator.hpp:22
lexy::lexeme::end
constexpr iterator end() const noexcept
Definition: lexeme.hpp:42
cx::begin
constexpr auto begin(const C &c) -> decltype(c.begin())
Definition: wildcards.hpp:661
lexy::code_point_location_counting
Counts code points for columns, newlines for lines.
Definition: input_location.hpp:56
lexy::input_line_annotation::truncated_multiline
bool truncated_multiline
true if the the range was spanning multiple line and needed to be truncated.
Definition: input_location.hpp:345
lexy::_detail
Definition: any_ref.hpp:12
lexy::byte_location_counting::_cur_index
std::size_t _cur_index
Definition: input_location.hpp:108
lexy::input_location::input_location
constexpr input_location(const Input &input)
Definition: input_location.hpp:127
lexy::input_location::_column_nr
unsigned _column_nr
Definition: input_location.hpp:187
lexy::input_location::anchor
constexpr input_location_anchor< Input > anchor() const
The closest previous anchor.
Definition: input_location.hpp:132
lexy::input_line_annotation::annotated_newline
bool annotated_newline
true if annotated includes the newline (this implies after.empty())
Definition: input_location.hpp:347
lexy::lexeme
Definition: lexeme.hpp:16
lexy::input_location::operator==
constexpr friend bool operator==(const input_location &lhs, const input_location &rhs)
Definition: input_location.hpp:152
lexy::_default_location_counting
std::conditional_t< std::is_same_v< typename lexy::input_reader< Input >::encoding, lexy::byte_encoding >, byte_location_counting<>, code_unit_location_counting > _default_location_counting
Definition: input_location.hpp:114
lexy::input_location::_line_nr
unsigned _line_nr
Definition: input_location.hpp:187
base.hpp
lexy::input_location_anchor::input_location_anchor
constexpr input_location_anchor(const Input &input)
Definition: input_location.hpp:21
lexy::input_location::operator<
constexpr friend bool operator<(const input_location &lhs, const input_location &rhs)
Definition: input_location.hpp:161
lexy::_detail::min_range_end
constexpr Iterator min_range_end(Iterator begin, Iterator end_a, Iterator end_b)
Definition: iterator.hpp:93
lexy::_detail::find_cp_boundary
constexpr Iterator find_cp_boundary(Iterator cur, Iterator end)
Definition: input_location.hpp:309
lexy::input_line_annotation::before
lexy::lexeme_for< Input > before
Everything of the line before the range.
Definition: input_location.hpp:338
lexy::input_location_anchor
Anchor for the location search.
Definition: input_location.hpp:17
lexy::input_line_annotation::after
lexy::lexeme_for< Input > after
Everything of the line after the annotated range.
Definition: input_location.hpp:342
lexyd::eof
constexpr auto eof
Matches EOF.
Definition: eof.hpp:72
lexy::input_location_anchor::_line_begin
iterator _line_begin
Definition: input_location.hpp:30
LEXY_ASSERT
#define LEXY_ASSERT(Expr, Msg)
Definition: assert.hpp:37
lexy::input_reader
decltype(LEXY_DECLVAL(Input).reader()) input_reader
Definition: input/base.hpp:92
lexy::code_unit_location_counting
Counts code units for columns, newlines for lines.
Definition: input_location.hpp:39
lexy::input_location::operator>
constexpr friend bool operator>(const input_location &lhs, const input_location &rhs)
Definition: input_location.hpp:171


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