RESTinio
easy_parser.hpp
Go to the documentation of this file.
1 /*
2  * RESTinio
3  */
4 
5 /*!
6  * @file
7  * @brief An very small, simple and somewhat limited implementation of
8  * recursive-descent parser.
9  *
10  * @since v.0.6.1
11  */
12 
13 #pragma once
14 
15 #include <restinio/impl/to_lower_lut.hpp>
16 #include <restinio/impl/overflow_controlled_integer_accumulator.hpp>
17 
18 #include <restinio/utils/tuple_algorithms.hpp>
19 #include <restinio/utils/metaprogramming.hpp>
20 
21 #include <restinio/string_view.hpp>
22 #include <restinio/compiler_features.hpp>
23 
24 #include <restinio/exception.hpp>
25 #include <restinio/expected.hpp>
26 
27 #include <algorithm>
28 #include <array>
29 #include <cstring>
30 #include <iostream>
31 #include <limits>
32 #include <map>
33 #include <optional>
34 #include <vector>
35 
36 namespace restinio
37 {
38 
39 namespace easy_parser
40 {
41 
42 namespace meta = restinio::utils::metaprogramming;
43 
44 //
45 // error_reason_t
46 //
47 /*!
48  * @brief Reason of parsing error.
49  *
50  * @since v.0.6.1
51  */
52 enum class error_reason_t
53 {
54  //! Unexpected character is found in the input.
56  //! Unexpected end of input is encontered when some character expected.
58  //! None of alternatives was found in the input.
60  //! Required pattern is not found in the input.
62  //! There are some unconsumed non-whitespace characters in the input
63  //! after the completion of parsing.
65  //! Illegal value was found in the input.
66  /*!
67  * @since v.0.6.2
68  */
70  //! A failure of parsing an alternative marked as "force only this
71  //! alternative".
72  /*!
73  * This error code is intended for internal use for the implementation
74  * of alternatives() and force_only_this_alternative() stuff.
75  *
76  * This error tells the parser that other alternatives should not be
77  * checked and the parsing of the whole alternatives clause should
78  * failed too.
79  *
80  * @since v.0.6.7
81  */
83 };
84 
85 //
86 // parse_error_t
87 //
88 /*!
89  * @brief Information about parsing error.
90  *
91  * @since v.0.6.1
92  */
94 {
95  //! Position in the input stream.
97  //! The reason of the error.
99 
100 public:
101  //! Initializing constructor.
103  std::size_t position,
104  error_reason_t reason ) noexcept
105  : m_position{ position }
106  , m_reason{ reason }
107  {}
108 
109  //! Get the position in the input stream where error was detected.
110  [[nodiscard]]
111  std::size_t
112  position() const noexcept { return m_position; }
113 
114  //! Get the reason of the error.
115  [[nodiscard]]
117  reason() const noexcept { return m_reason; }
118 };
119 
120 //
121 // nothing_t
122 //
123 /*!
124  * @brief A special type to be used in the case where there is no
125  * need to store produced value.
126  *
127  * @since v.0.6.1
128  */
129 struct nothing_t {};
130 
131 //
132 // result_value_wrapper
133 //
134 /*!
135  * @brief A template with specializations for different kind
136  * of result values and for type `nothing`.
137  *
138  * Every specialization for a case when T is not a container should have the
139  * following content:
140  * @code
141  * struct result_value_wrapper<...>
142  * {
143  * using result_type = ... // type of the result value.
144  * using wrapped_type = ... // type to be created inside a producer
145  * // to hold a temporary value during the parsing.
146  *
147  * static void
148  * as_result( wrapped_type & to, result_type && what );
149  *
150  * [[nodiscard]] static result_type &&
151  * unwrap_value( wrapped_type & from );
152  * };
153  * @endcode
154  *
155  * Every specialization for a case when T is a container should have
156  * the following content:
157  * @code
158  * struct result_value_wrapper<...>
159  * {
160  * using result_type = ... // type of the result value.
161  * using value_type = ... // type of object to be placed into a container
162  * // if result_type is a container.
163  * using wrapped_type = ... // type to be created inside a producer
164  * // to hold a temporary value during the parsing.
165  *
166  * static void
167  * as_result( wrapped_type & to, result_type && what );
168  *
169  * static void
170  * to_container( wrapped_type & to, value_type && item );
171  *
172  * [[nodiscard]] static result_type &&
173  * unwrap_value( wrapped_type & from );
174  * };
175  * @endcode
176  *
177  * @since v.0.6.6
178  */
179 template< typename T >
181 {
182  using result_type = T;
183  using wrapped_type = result_type;
184 
185  static void
186  as_result( wrapped_type & to, result_type && what )
187  {
188  to = std::move(what);
189  }
190 
191  [[nodiscard]]
192  static result_type &&
193  unwrap_value( wrapped_type & v )
194  {
195  return std::move(v);
196  }
197 };
198 
199 //
200 // result_wrapper_for
201 //
202 /*!
203  * @brief A metafunction for detection of actual result_value_wrapper
204  * type for T
205  *
206  * If a specialization of result_value_wrapper defines wrapped_type
207  * as a different type from result_type then transform() and consume()
208  * methods will receive a reference to wrapped_type. And there will be
209  * a task to detect actual result_type from a wrapped_type.
210  *
211  * To solve this task it is necessary to have a way to get
212  * result_value_wrapper<result_type> from wrapped_type.
213  *
214  * This metafunction is that way.
215  *
216  * @note
217  * For each specialization of result_value_wrapper<T> that introduces
218  * wrapped_type different from result_type a specialization of
219  * result_wrapper_for should also be provided. For example:
220  * @code
221  * class my_type {...};
222  * class my_type_wrapper { ... };
223  *
224  * namespace restinio {
225  * namespace easy_parser {
226  *
227  * template<>
228  * struct result_value_wrapper<my_type> {
229  * using result_type = my_type;
230  * using wrapped_type = my_type_wrapper;
231  * ...
232  * };
233  * template<>
234  * struct result_wrapper_for<my_type_wrapper> {
235  * using type = result_value_wrapper<my_type>;
236  * };
237  *
238  * } // namespace easy_parser
239  * } // namespace restinio
240  * @endcode
241  *
242  * @since v.0.6.6
243  */
244 template< typename T >
246 {
247  using type = result_value_wrapper< T >;
248 };
249 
250 template< typename T >
251 using result_wrapper_for_t = typename result_wrapper_for<T>::type;
252 
253 template< typename T, typename... Args >
255 {
256  using result_type = std::vector< T, Args... >;
257  using value_type = typename result_type::value_type;
259 
260  static void
262  {
263  to = std::move(what);
264  }
265 
266  static void
268  {
269  to.push_back( std::move(what) );
270  }
271 
272  [[nodiscard]]
273  static result_type &&
275  {
276  return std::move(v);
277  }
278 };
279 
280 namespace impl
281 {
282 
283 //
284 // std_array_wrapper
285 //
286 /*!
287  * @brief A special wrapper for std::array type to be used inside
288  * a producer during the parsing.
289  *
290  * This type is intended to be used inside a specialization of
291  * result_value_wrapper for std::array.
292  *
293  * This type holds the current index that can be used by
294  * to_container method for addition of a new item to the result array.
295  *
296  * @since v.0.6.6
297  */
298 template< typename T, std::size_t S >
300 {
303 };
304 
305 } /* namespace impl */
306 
307 template< typename T, std::size_t S >
309 {
310  using result_type = std::array< T, S >;
311  using value_type = typename result_type::value_type;
313 
314  static void
316  {
317  to.m_array = std::move(what);
318  to.m_index = 0u;
319  }
320 
321  static void
323  {
324  if( to.m_index >= S )
325  throw exception_t(
326  "index in the result std::array is out of range, "
327  "index=" + std::to_string(to.m_index) +
328  ", size={}" + std::to_string(S) );
329 
330  to.m_array[ to.m_index ] = std::move(what);
331  ++to.m_index;
332  }
333 
334  [[nodiscard]]
335  static result_type &&
337  {
338  return std::move(v.m_array);
339  }
340 };
341 
342 /*!
343  * @brief A specialization of result_wrapper_for metafunction for
344  * the case of std::array wrapper.
345  *
346  * @since v.0.6.6
347  */
348 template< typename T, std::size_t S >
350 {
352 };
353 
354 template< typename Char, typename... Args >
356 {
358  using value_type = Char;
360 
361  static void
363  {
364  to = std::move(what);
365  }
366 
367  static void
369  {
370  to.push_back( what );
371  }
372 
373  /*!
374  * @brief Special overload for the case when std::string should
375  * be added to another std::string.
376  *
377  * For example, in cases like:
378  * @code
379  * produce< std::string >(
380  * produce< std::string >(...) >> to_container(),
381  * produce< std::string >(...) >> to_container(),
382  * ...
383  * )
384  * @endcode
385  */
386  static void
388  {
389  to.append( what );
390  }
391 
392  [[nodiscard]]
393  static result_type &&
395  {
396  return std::move(v);
397  }
398 };
399 
400 template< typename K, typename V, typename... Args >
401 struct result_value_wrapper< std::map< K, V, Args... > >
402 {
403  using result_type = std::map< K, V, Args... >;
404  // NOTE: we can't use container_type::value_type here
405  // because value_type for std::map is std::pair<const K, V>,
406  // not just std::pair<K, V>,
407  using value_type = std::pair<K, V>;
409 
410  static void
412  {
413  to = std::move(what);
414  }
415 
416  static void
418  {
419  to.emplace( std::move(what) );
420  }
421 
422  [[nodiscard]]
423  static result_type &&
425  {
426  return std::move(v);
427  }
428 };
429 
430 template<>
432 {
433  using result_type = nothing_t;
434  using value_type = nothing_t;
435  using wrapped_type = result_type;
436 
437  static void
438  as_result( wrapped_type &, result_type && ) noexcept {}
439 
440  static void
441  to_container( wrapped_type &, value_type && ) noexcept {}
442 
443  [[nodiscard]]
444  static result_type &&
445  unwrap_value( wrapped_type & v )
446  {
447  return std::move(v);
448  }
449 };
450 
451 /*!
452  * @brief A special marker that means infinite repetitions.
453  *
454  * @since v.0.6.1
455  */
456 constexpr std::size_t N = std::numeric_limits<std::size_t>::max();
457 
458 //
459 // digits_to_consume_t
460 //
461 /*!
462  * @brief Limits for number of digits to be extracted during
463  * parsing of decimal numbers.
464  *
465  * @since v.0.6.6
466  */
468 {
469 public:
471 
472  //! Minimal number of digits to consume.
473  /*!
474  * @note
475  * Can't be 0, but this value is not checked for
476  * performance reasons.
477  */
479  //! Maximal number of digits to consume.
481 
482 public:
483  /*!
484  * A constructor for the case when min = max and both are
485  * equal to @a total.
486  */
487  constexpr
488  digits_to_consume_t( underlying_int_t total ) noexcept
489  : m_min{ total }
490  , m_max{ total }
491  {}
492 
493  /*!
494  * A constructor for the case when min and max are specified
495  * separately.
496  */
497  constexpr
499  underlying_int_t min,
500  underlying_int_t max ) noexcept
501  : m_min{ min }
502  , m_max{ max }
503  {}
504 
505  //! Get the minimal value.
506  [[nodiscard]]
507  constexpr auto
508  min() const noexcept { return m_min; }
509 
510  //! Get the maximum value.
511  [[nodiscard]]
512  constexpr auto
513  max() const noexcept { return m_max; }
514 
515  //! Get the value that means that maximum is not limited.
516  [[nodiscard]]
517  constexpr static auto
518  unlimited_max() noexcept
519  {
520  return std::numeric_limits<underlying_int_t>::max();
521  }
522 
523  /*!
524  * Returns `digits_to_consume_t{1, unlimited_max()}`.
525  */
526  [[nodiscard]]
527  constexpr static auto
528  from_one_to_max() noexcept
529  {
530  return digits_to_consume_t{ 1, unlimited_max() };
531  }
532 };
533 
534 /*!
535  * @brief Create a limit for number of digits to be extracted.
536  *
537  * Makes a limit where min==max and both are equal to @a total.
538  *
539  * Usage example:
540  * @code
541  * using namespace restinio::easy_parser;
542  *
543  * auto x_uint32_p = hexadecimal_number_p<std::uint32_t>(expected_digits(8));
544  * @endcode
545  *
546  * @since v.0.6.6
547  */
548 [[nodiscard]]
549 inline constexpr digits_to_consume_t
550 expected_digits( digits_to_consume_t::underlying_int_t total ) noexcept
551 {
552  return { total };
553 }
554 
555 /*!
556  * @brief Create a limit for number of digits to be extracted.
557  *
558  * Makes a limit where min and max are specified separately.
559  *
560  * Usage example:
561  * @code
562  * using namespace restinio::easy_parser;
563  *
564  * auto ten_digits_int32_p = decimal_number_p<std::int32_t>(expected_digits(1, 10));
565  * @endcode
566  *
567  * @since v.0.6.6
568  */
569 [[nodiscard]]
570 inline constexpr digits_to_consume_t
572  digits_to_consume_t::underlying_int_t min,
573  digits_to_consume_t::underlying_int_t max ) noexcept
574 {
575  return { min, max };
576 }
577 
578 namespace impl
579 {
580 
581 //
582 // character_t
583 //
584 /*!
585  * @brief One character extracted from the input stream.
586  *
587  * If the characted extracted successfuly then m_eof will be `false`.
588  * If the end of input reached then m_eof is `true` and the value
589  * of m_ch is undefined.
590  *
591  * @since v.0.6.1
592  */
594 {
595  bool m_eof;
596  char m_ch;
597 };
598 
599 [[nodiscard]]
600 inline bool
601 operator==( const character_t & a, const character_t & b ) noexcept
602 {
603  return (a.m_eof == b.m_eof && a.m_ch == b.m_ch);
604 }
605 
606 [[nodiscard]]
607 inline bool
608 operator!=( const character_t & a, const character_t & b ) noexcept
609 {
610  return (a.m_eof != b.m_eof || a.m_ch != b.m_ch);
611 }
612 
613 /*!
614  * @brief A constant for SPACE value.
615  *
616  * @since v.0.6.1
617  */
618 constexpr char SP = ' ';
619 /*!
620  * @brief A constant for Horizontal Tab value.
621  *
622  * @since v.0.6.1
623  */
624 constexpr char HTAB = '\x09';
625 
626 //
627 // is_space
628 //
629 /*!
630  * @brief If a character a space character?
631  *
632  * @since v.0.6.1
633  */
634 [[nodiscard]]
635 inline constexpr bool
636 is_space( const char ch ) noexcept
637 {
638  return ch == SP || ch == HTAB;
639 }
640 
641 //
642 // is_space_predicate_t
643 //
644 /*!
645  * @brief A preducate for symbol_producer_template that checks that
646  * a symbol is a space.
647  *
648  * @since v.0.6.4
649  */
651 {
652  [[nodiscard]]
653  bool
654  operator()( const char actual ) const noexcept
655  {
656  return is_space(actual);
657  }
658 };
659 
660 //
661 // is_digit
662 //
663 /*!
664  * @brief Is a character a decimal digit?
665  *
666  * @since v.0.6.1
667  */
668 [[nodiscard]]
669 inline constexpr bool
670 is_digit( const char ch ) noexcept
671 {
672  return (ch >= '0' && ch <= '9');
673 }
674 
675 //
676 // is_digit_predicate_t
677 //
678 /*!
679  * @brief A predicate for cases where char to be expected to be a decimal digit.
680  *
681  * @since v.0.6.6
682  */
684 {
685  [[nodiscard]]
686  bool
687  operator()( const char actual ) const noexcept
688  {
689  return is_digit( actual );
690  }
691 };
692 
693 //
694 // is_hexdigit
695 //
696 /*!
697  * @brief Is a character a hexadecimal digit?
698  *
699  * @since v.0.6.6
700  */
701 [[nodiscard]]
702 inline constexpr bool
703 is_hexdigit( const char ch ) noexcept
704 {
705  return (ch >= '0' && ch <= '9') ||
706  (ch >= 'A' && ch <= 'F') ||
707  (ch >= 'a' && ch <= 'f');
708 }
709 
710 //
711 // is_hexdigit_predicate_t
712 //
713 /*!
714  * @brief A predicate for cases where char to be expected
715  * to be a hexadecimal digit.
716  *
717  * @since v.0.6.6
718  */
720 {
721  [[nodiscard]]
722  bool
723  operator()( const char actual ) const noexcept
724  {
725  return is_hexdigit( actual );
726  }
727 };
728 
729 //
730 // source_t
731 //
732 /*!
733  * @brief The class that implements "input stream".
734  *
735  * It is expected that string_view passed to the constructor of
736  * source_t will outlive the instance of source_t.
737  *
738  * @since v.0.6.1
739  */
740 class source_t
741 {
742  //! The content to be used as "input stream".
744  //! The current position in the input stream.
745  /*!
746  * \note
747  * m_index can have value of m_data.size(). In that case
748  * EOF will be returned.
749  */
751 
752 public:
753  //! Type to be used as the index inside the input stream.
755 
756  //! Initializing constructor.
757  explicit source_t( string_view_t data ) noexcept : m_data{ data } {}
758 
759  //! Get the next character from the input stream.
760  /*!
761  * EOF can be returned in the case if there is no more data in
762  * the input stream.
763  */
764  [[nodiscard]]
766  getch() noexcept
767  {
768  if( m_index < m_data.size() )
769  {
770  return {false, m_data[ m_index++ ]};
771  }
772  else
773  return {true, 0};
774  }
775 
776  //! Return one character back to the input stream.
777  void
778  putback() noexcept
779  {
780  if( m_index )
781  --m_index;
782  }
783 
784  //! Get the current position in the stream.
785  [[nodiscard]]
786  position_t
787  current_position() const noexcept
788  {
789  return m_index;
790  }
791 
792  //! Return the current position in the input stream
793  //! at the specified position.
794  void
795  backto( position_t pos ) noexcept
796  {
797  if( pos <= m_data.size() )
798  m_index = pos;
799  }
800 
801  //! Is EOF has been reached?
802  [[nodiscard]]
803  bool
804  eof() const noexcept
805  {
806  return m_index >= m_data.size();
807  }
808 
809  //! Return a fragment from the input stream.
810  /*!
811  * \attention
812  * The value of \a from should be lesser than the size of the
813  * input stream.
814  */
815  [[nodiscard]]
818  //! Starting position for the fragment required.
820  //! Length of the fragment required.
821  //! Value string_view_t::npos means the whole remaining content
822  //! of the input stream starting from position \a from.
823  string_view_t::size_type length = string_view_t::npos ) const noexcept
824  {
825  return m_data.substr( from, length );
826  }
827 
828  /*!
829  * @brief A helper class to automatically return acquired
830  * content back to the input stream.
831  *
832  * Usage example:
833  * @code
834  * expected_t<result_type, parse_error_t> try_parse(source_t & from) {
835  * source_t::content_consumer_t consumer{from};
836  * for(auto ch = from.getch(); some_condition(ch); ch = from.getch())
837  * {
838  * ... // do something with ch.
839  * }
840  * if(no_errors_detected())
841  * // All acquired content should be consumed.
842  * consumer.commit();
843  *
844  * // Otherwise all acquired content will be returned back to the input stream.
845  * ...
846  * }
847  * @endcode
848  *
849  * @since v.0.6.1
850  */
852  {
855  bool m_consumed{ false };
856 
857  public :
858  content_consumer_t() = delete;
859  content_consumer_t( const content_consumer_t & ) = delete;
860  content_consumer_t( content_consumer_t && ) = delete;
861 
862  content_consumer_t( source_t & from ) noexcept
863  : m_from{ from }
865  {}
866 
867  ~content_consumer_t() noexcept
868  {
869  if( !m_consumed )
870  m_from.backto( m_started_at );
871  }
872 
873  position_t
874  started_at() const noexcept
875  {
876  return m_started_at;
877  }
878 
879  //! Consume all acquired content.
880  /*!
881  * @note
882  * If that method is not called then all acquired content
883  * will be returned back.
884  */
885  void
886  commit() noexcept
887  {
888  m_consumed = true;
889  }
890  };
891 };
892 
893 //
894 // entity_type_t
895 //
896 /*!
897  * @brief A marker for distinguish different kind of entities in parser.
898  *
899  * @since v.0.6.1
900  */
901 enum class entity_type_t
902 {
903  //! Entity is a producer of values.
904  producer,
905  //! Entity is a transformer of a value from one type to another.
906  transformer,
907  //! Entity is a consumer of values. It requires a value on the input
908  //! and doesn't produces anything.
909  consumer,
910  //! Entity is a clause. It doesn't produces anything.
911  clause,
912  //! Entity is a transformer-proxy. It can't be used directly, only
913  //! for binding a producer and transformer together.
914  /*!
915  * @since v.0.6.6.
916  */
918 };
919 
920 //
921 // producer_tag
922 //
923 /*!
924  * @brief A special base class to be used with producers.
925  *
926  * Every producer class should have the following content:
927  *
928  * @code
929  * class some_producer_type
930  * {
931  * public:
932  * using result_type = ... // some producer-specific type.
933  * static constexpr entity_type_t entity_type = entity_type_t::producer;
934  *
935  * expected_t<result_type, parse_error_t>
936  * try_parse(source_t & from);
937  *
938  * ...
939  * };
940  * @endcode
941  *
942  * @since v.0.6.1
943  */
944 template< typename Result_Type >
946 {
947  using result_type = Result_Type;
949 };
950 
951 template< typename T, typename = meta::void_t<> >
952 struct is_producer : public std::false_type {};
953 
954 template< typename T >
955 struct is_producer< T, meta::void_t< decltype(T::entity_type) > >
956 {
957  static constexpr bool value = entity_type_t::producer == T::entity_type;
958 };
959 
960 /*!
961  * @brief A meta-value to check whether T is a producer type.
962  *
963  * @note
964  * The current implementation checks only the presence of T::entity_type of
965  * type entity_type_t and the value of T::entity_type. Presence of
966  * T::result_type and T::try_parse is not checked.
967  *
968  * @since v.0.6.1
969  */
970 template< typename T >
971 constexpr bool is_producer_v = is_producer<T>::value;
972 
973 //
974 // transformer_tag
975 //
976 /*!
977  * @brief A special base class to be used with transformers.
978  *
979  * Every transformer class should have the following content:
980  *
981  * @code
982  * class some_transformer_type
983  * {
984  * public:
985  * using result_type = ... // some transformer-specific type.
986  * static constexpr entity_type_t entity_type = entity_type_t::transformer;
987  *
988  * result_type
989  * transform(Input_Type && from);
990  *
991  * ...
992  * };
993  * @endcode
994  * where `Input_Type` is transformer's specific types.
995  *
996  * @since v.0.6.1
997  */
998 template< typename Result_Type >
1000 {
1001  using result_type = Result_Type;
1003 };
1004 
1005 template< typename T, typename = meta::void_t<> >
1006 struct is_transformer : public std::false_type {};
1007 
1008 template< typename T >
1009 struct is_transformer< T, meta::void_t< decltype(T::entity_type) > >
1010 {
1011  static constexpr bool value = entity_type_t::transformer == T::entity_type;
1012 };
1013 
1014 /*!
1015  * @brief A meta-value to check whether T is a transformer type.
1016  *
1017  * @note
1018  * The current implementation checks only the presence of T::entity_type of
1019  * type entity_type_t and the value of T::entity_type. Presence of
1020  * T::result_type and T::transform is not checked.
1021  *
1022  * @since v.0.6.1
1023  */
1024 template< typename T >
1026 
1027 //
1028 // transformer_invoker
1029 //
1030 /*!
1031  * @brief A helper template for calling transformation function.
1032  *
1033  * The transformer_invoker class is intended to wrap a call to
1034  * @a Transformer::transform method. That method can return
1035  * a value of type T or a value of type expected_t<T, error_reason_t>.
1036  *
1037  * In the case of return value of type T the returned value of T
1038  * should be used directly.
1039  *
1040  * In the case of return value of type expected_t<T, error_reason_t>
1041  * the return value should be checked for the presence of an error.
1042  * In the case of an error expected_t<T, error_reason_t> should be
1043  * converted into expected_t<T, parser_error_t>.
1044  *
1045  * @since v.0.6.11
1046  */
1047 template< typename Result_Type >
1049 {
1050  template< typename Transformer, typename Input_Type >
1051  [[nodiscard]]
1052  static Result_Type
1054  source_t &,
1055  Transformer & transformer,
1056  expected_t< Input_Type, parse_error_t > && input )
1057  {
1058  return transformer.transform( std::move(*input) );
1059  }
1060 };
1061 
1062 /*!
1063  * This specialization of transformer_invoker handles a case when
1064  * transformation method returns expected_t<T, error_reason_t>.
1065  *
1066  * @since v.0.6.11
1067  */
1068 template< typename Result_Type >
1070 {
1071  template< typename Transformer, typename Input_Type >
1072  [[nodiscard]]
1075  // source_t is necessary to get the position in the case of an error.
1076  source_t & source,
1079  {
1080  auto result = transformer.transform( std::move(*input) );
1081  if( result )
1082  return *result;
1083  else
1086  result.error()
1087  } );
1088  }
1089 };
1090 
1091 //
1092 // is_appropriate_transformer_result_type
1093 //
1094 /*!
1095  * @brief A metafunction that checks is Result_Type can be used as
1096  * the result of transformation method.
1097  *
1098  * A transformation method can return a value of type T or a value
1099  * of type expected_t<T, error_reason_t>. But a user can define
1100  * transformation method that returns an expected_t<T, parse_error_t>
1101  * just by a mistake. That mistake should be detected.
1102  *
1103  * Metafunction is_appropriate_transformer_result_type serves that
1104  * purpose: it defines @a value to `true` if transformation method
1105  * returns T or expected_t<T, error_reason_t>. In the case of
1106  * expected_t<T, parse_error_t> @a value will be set to `false.
1107  *
1108  * @since v.0.6.11
1109  */
1110 template< typename Result_Type >
1112 {
1113  static constexpr bool value = true;
1114 };
1115 
1116 template< typename Result_Type >
1119 {
1120  static constexpr bool value = true;
1121 };
1122 
1123 template< typename Result_Type >
1126 {
1127  static constexpr bool value = false;
1128 };
1129 
1130 //
1131 // transformed_value_producer_traits_checker
1132 //
1133 /*!
1134  * @brief A helper template for checking a possibility to connect
1135  * a producer with a transformer.
1136  *
1137  * This helper can be seen as a metafunction that defines a boolean
1138  * value is_valid_transformation_result_type. If that value is `true`
1139  * then @a Transformer::transform method returns allowed type
1140  * (T or expected_t<T, error_reson_t>).
1141  *
1142  * @since v.0.6.11
1143  */
1144 template< typename Producer, typename Transformer >
1146 {
1147  static_assert( is_producer_v<Producer>,
1148  "Producer should be a producer type" );
1149  static_assert( is_transformer_v<Transformer>,
1150  "Transformer should be a transformer type" );
1151 
1152  using producer_result_t = std::decay_t< decltype(
1154  ) >;
1155 
1156  using transformation_result_t = std::decay_t< decltype(
1158  std::move(*(std::declval<producer_result_t>())) )
1159  ) >;
1160 
1161  using expected_result_t = typename Transformer::result_type;
1162 
1163  static constexpr bool is_valid_transformation_result_type =
1164  is_appropriate_transformer_result_type< expected_result_t >::value;
1165 };
1166 
1167 //
1168 // transformed_value_producer_t
1169 //
1170 /*!
1171  * @brief A template of producer that gets a value from another
1172  * producer, transforms it and produces transformed value.
1173  *
1174  * @tparam Producer the type of producer of source value.
1175  * @tparam Transformer the type of transformer from source to the target value.
1176  *
1177  * @since v.0.6.1
1178  */
1179 template< typename Producer, typename Transformer >
1181  : public producer_tag< typename Transformer::result_type >
1182 {
1183  using traits_checker = transformed_value_producer_traits_checker<
1184  Producer, Transformer >;
1185 
1186  static_assert(
1187  traits_checker::is_valid_transformation_result_type,
1188  "transformation result should be either T or "
1189  "expected_t<T, error_reson_t>, not expected_t<T, parse_error_t>" );
1190 
1191  Producer m_producer;
1192  Transformer m_transformer;
1193 
1194 public :
1195  using result_type = typename Transformer::result_type;
1196 
1198  Producer && producer,
1199  Transformer && transformer )
1200  : m_producer{ std::move(producer) }
1202  {}
1203 
1204  [[nodiscard]]
1207  {
1209  if( producer_result )
1210  {
1211  using transformation_result_t =
1213 
1215  source,
1216  m_transformer,
1217  std::move(producer_result) );
1218  }
1219  else
1221  }
1222 };
1223 
1224 /*!
1225  * @brief A special operator to connect a value producer with value transformer.
1226  *
1227  * @since v.0.6.1
1228  */
1229 template< typename P, typename T >
1230 [[nodiscard]]
1231 std::enable_if_t<
1235  P producer,
1236  T transformer )
1237 {
1239 
1241 }
1242 
1243 //
1244 // transformer_proxy_tag
1245 //
1246 /*!
1247  * @brief A special base class to be used with transformer-proxies.
1248  *
1249  * Every transformer-proxy class should have the following content:
1250  *
1251  * @code
1252  * class some_transformer_proxy_type
1253  * {
1254  * public:
1255  * static constexpr entity_type_t entity_type = entity_type_t::transformer;
1256  *
1257  * template< typename Input_Type >
1258  * auto
1259  * make_transformer();
1260  * ...
1261  * };
1262  * @endcode
1263  * where `Input_Type` is will be specified by a producer.
1264  *
1265  * @since v.0.6.6
1266  */
1268 {
1270 };
1271 
1272 template< typename T, typename = meta::void_t<> >
1274 
1275 template< typename T >
1276 struct is_transformer_proxy< T, meta::void_t< decltype(T::entity_type) > >
1277 {
1278  static constexpr bool value = entity_type_t::transformer_proxy == T::entity_type;
1279 };
1280 
1281 /*!
1282  * @brief A meta-value to check whether T is a transformer-proxy type.
1283  *
1284  * @note
1285  * The current implementation checks only the presence of T::entity_type of
1286  * type entity_type_t and the value of T::entity_type.
1287  *
1288  * @since v.0.6.6
1289  */
1290 template< typename T >
1292 
1293 /*!
1294  * @brief A special operator to connect a value producer with value transformer
1295  * via transformer-proxy.
1296  *
1297  * @since v.0.6.6
1298  */
1299 template<
1300  typename P,
1301  typename T,
1302  typename S = std::enable_if_t<
1304  void > >
1305 [[nodiscard]]
1306 auto
1308  P producer,
1309  T transformer_proxy )
1310 {
1311  auto real_transformer = transformer_proxy.template make_transformer<
1312  typename P::result_type >();
1313 
1314  using transformator_type = std::decay_t< decltype(real_transformer) >;
1315 
1316  using producer_type = transformed_value_producer_t< P, transformator_type >;
1317 
1318  return producer_type{ std::move(producer), std::move(real_transformer) };
1319 }
1320 
1321 //
1322 // consumer_tag
1323 //
1324 /*!
1325  * @brief A special base class to be used with consumers.
1326  *
1327  * Every consumer class should have the following content:
1328  *
1329  * @code
1330  * class some_consumer_type
1331  * {
1332  * public :
1333  * static constexpr entity_type_t entity_type = entity_type_t::consumer;
1334  *
1335  * void consume( Target_Type & dest, Value && current_value );
1336  * ...
1337  * };
1338  * @endcode
1339  * where `Target_Type` and `Value` are consumer's specific types.
1340  *
1341  * @since v.0.6.1
1342  */
1344 {
1346 };
1347 
1348 template< typename T, typename = meta::void_t<> >
1349 struct is_consumer : public std::false_type {};
1350 
1351 template< typename T >
1352 struct is_consumer< T, meta::void_t< decltype(T::entity_type) > >
1353 {
1354  static constexpr bool value = entity_type_t::consumer == T::entity_type;
1355 };
1356 
1357 /*!
1358  * @brief A meta-value to check whether T is a consumer type.
1359  *
1360  * @note
1361  * The current implementation checks only the presence of T::entity_type of
1362  * type entity_type_t and the value of T::entity_type. Presence of
1363  * T::consume is not checked.
1364  *
1365  * @since v.0.6.1
1366  */
1367 template< typename T >
1368 constexpr bool is_consumer_v = is_consumer<T>::value;
1369 
1370 //
1371 // clause_tag
1372 //
1373 /*!
1374  * @brief A special base class to be used with clauses.
1375  *
1376  * Every clause class should have the following content:
1377  *
1378  * @code
1379  * class some_consumer_type
1380  * {
1381  * public :
1382  * static constexpr entity_type_t entity_type = entity_type_t::clause;
1383  *
1384  * std::optional<parse_error_t>
1385  * try_process(source_t & from, Target_Type & dest);
1386  * ...
1387  * };
1388  * @endcode
1389  * where `Target_Type` is clause's specific types.
1390  *
1391  * @since v.0.6.1
1392  */
1394 {
1396 };
1397 
1398 template< typename T, typename = meta::void_t<> >
1399 struct is_clause : public std::false_type {};
1400 
1401 template< typename T >
1403  decltype(std::decay_t<T>::entity_type) > >
1404 {
1405  using real_type = std::decay_t<T>;
1406 
1407  static constexpr bool value = entity_type_t::clause == real_type::entity_type;
1408 };
1409 
1410 /*!
1411  * @brief A meta-value to check whether T is a consumer type.
1412  *
1413  * @note
1414  * The current implementation checks only the presence of T::entity_type of
1415  * type entity_type_t and the value of T::entity_type. Presence of
1416  * T::try_process is not checked.
1417  *
1418  * @since v.0.6.1
1419  */
1420 template< typename T >
1421 constexpr bool is_clause_v = is_clause<T>::value;
1422 
1423 //
1424 // tuple_of_entities_t
1425 //
1426 /*!
1427  * @brief A helper meta-function to create an actual type of tuple
1428  * with clauses/producers.
1429  *
1430  * Usage example:
1431  * @code
1432  * template< typename... Clauses >
1433  * auto
1434  * some_clause( Clauses && ...clauses ) {
1435  * using clause_type = impl::some_clause_t<
1436  * impl::tuple_of_entities_t<Clauses...> >;
1437  * return clause_type{ std::forward<Clauses>(clauses)... };
1438  * }
1439  * @endcode
1440  *
1441  * The tuple_of_entities_t takes care about such cases as references and
1442  * constness of parameters. For example:
1443  * @code
1444  * auto c = symbol('c');
1445  * const auto b = symbol('b');
1446  * auto clause = some_clause(c, b);
1447  * @endcode
1448  * In that case `Clauses...` will be `symbol_clause_t&, const
1449  * symbol_clause_t&`. And an attempt to make type `std::tuple<Clauses...>` will
1450  * produce type `std::tuple<symbol_clause_t&, const symbol_clause_t&>`. But we
1451  * need `std::tuple<symbol_clause_t, symbol_clause_t>`. This result will be
1452  * obtained if `tuple_of_entities_t` is used instead of `std::tuple`.
1453  *
1454  * @since v.0.6.6
1455  */
1456 template< typename... Entities >
1460 
1461 //
1462 // consume_value_clause_t
1463 //
1464 /*!
1465  * @brief A template for a clause that binds a value producer with value
1466  * consumer.
1467  *
1468  * @tparam P the type of value producer.
1469  * @tparam C the type of value consumer.
1470  *
1471  * @since v.0.6.1
1472  */
1473 template< typename P, typename C >
1475 {
1476  static_assert( is_producer_v<P>, "P should be a producer type" );
1477  static_assert( is_consumer_v<C>, "C should be a consumer type" );
1478 
1479  P m_producer;
1481 
1482 public :
1483  consume_value_clause_t( P && producer, C && consumer )
1484  : m_producer{ std::move(producer) }
1485  , m_consumer{ std::move(consumer) }
1486  {}
1487 
1488  template< typename Target_Type >
1489  [[nodiscard]]
1492  {
1494  if( parse_result )
1495  {
1497  return std::nullopt;
1498  }
1499  else
1500  return parse_result.error();
1501  }
1502 };
1503 
1504 /*!
1505  * @brief A special operator to connect a value producer with a value consumer.
1506  *
1507  * @since v.0.6.1
1508  */
1509 template< typename P, typename C >
1510 [[nodiscard]]
1511 std::enable_if_t<
1513  consume_value_clause_t< P, C > >
1515 {
1516  return { std::move(producer), std::move(consumer) };
1517 }
1518 
1519 //
1520 // top_level_clause_t
1521 //
1522 /*!
1523  * @brief A special class to be used as the top level clause in parser.
1524  *
1525  * @note
1526  * That class doesn't look like an ordinal clause and can't be connected
1527  * with other clauses. Method try_process has the different format and
1528  * returns the value of Producer::try_parse.
1529  *
1530  * @since v.0.6.1
1531  */
1532 template< typename Producer >
1534 {
1535  static_assert( is_producer_v<Producer>,
1536  "Producer should be a producer type" );
1537 
1538  Producer m_producer;
1539 
1540 public :
1541  top_level_clause_t( Producer && producer )
1542  : m_producer{ std::move(producer) }
1543  {}
1544 
1545  [[nodiscard]]
1546  auto
1548  {
1549  return m_producer.try_parse( from );
1550  }
1551 };
1552 
1553 //
1554 // ensure_no_remaining_content
1555 //
1556 /*!
1557  * @brief A special function to check that there is no more actual
1558  * data in the input stream except whitespaces.
1559  *
1560  * @return parse_error_t if some non-whitespace character is found
1561  * in the input stream.
1562  *
1563  * @since v.0.6.1
1564  */
1565 [[nodiscard]]
1566 inline std::optional< parse_error_t >
1568  source_t & from )
1569 {
1570  while( !from.eof() )
1571  {
1572  if( !is_space( from.getch().m_ch ) )
1573  {
1574  from.putback(); // Otherwise current_position() will be wrong.
1575  return parse_error_t{
1576  from.current_position(),
1577  error_reason_t::unconsumed_input
1578  };
1579  }
1580  }
1581 
1582  return std::nullopt;
1583 }
1584 
1585 //
1586 // remove_trailing_spaces
1587 //
1588 /*!
1589  * @brief Helper function for removal of trailing spaces from a string-view.
1590  *
1591  * @since v.0.6.7
1592  */
1593 [[nodiscard]]
1594 inline string_view_t
1596 {
1597  auto s = from.size();
1598  for(; s && is_space( from[ (s-1u) ] ); --s) {}
1599 
1600  return from.substr( 0u, s );
1601 }
1602 
1603 //
1604 // alternatives_clause_t
1605 //
1606 /*!
1607  * @brief A template for implementation of clause that selects one of
1608  * alternative clauses.
1609  *
1610  * This template implements rules like:
1611  @verbatim
1612  T := A | B | C
1613  @endverbatim
1614  *
1615  * It works very simple way:
1616  *
1617  * - `try_process` for the first alternative is called. If it fails then...
1618  * - `try_process` for the second alternative is called. If it fails then...
1619  * - `try_process` for the third alternative is called...
1620  * - and so on.
1621  *
1622  * If no one of alternatives is selected then the current position in
1623  * the input stream is restored.
1624  *
1625  * @note
1626  * The copy of Target_Type object passed to `try_process` method is
1627  * created before checking each alternative.
1628  *
1629  * @tparam Subitems_Tuple the type of std::tuple with items for every
1630  * alternative clauses.
1631  *
1632  * @since v.0.6.1
1633  */
1634 template<
1635  typename Subitems_Tuple >
1637 {
1638  Subitems_Tuple m_subitems;
1639 
1640 public :
1642  Subitems_Tuple && subitems )
1643  : m_subitems{ std::move(subitems) }
1644  {}
1645 
1646  template< typename Target_Type >
1647  [[nodiscard]]
1650  {
1651  const auto starting_pos = from.current_position();
1652 
1654  const bool success = restinio::utils::tuple_algorithms::any_of(
1655  m_subitems,
1656  [&from, &target, &actual_parse_error]( auto && one_producer ) {
1659 
1661  if( !actual_parse_error )
1662  {
1663  target = std::move(tmp_value);
1664  consumer.commit();
1665 
1666  return true;
1667  }
1668  else {
1669  // Since v.0.6.7 we should check for
1670  // force_only_this_alternative_failed error.
1671  // In the case of that error enumeration of alternatives
1672  // should be stopped.
1675  }
1676  } );
1677 
1678  if( !success || actual_parse_error )
1679  return parse_error_t{
1680  starting_pos,
1682  };
1683  else
1684  return std::nullopt;
1685  }
1686 };
1687 
1688 //
1689 // maybe_clause_t
1690 //
1691 /*!
1692  * @brief A template for implementation of clause that checks and
1693  * handles presence of optional entity in the input stream.
1694  *
1695  * This template implements rules like:
1696  @verbatim
1697  T := [ A B C ]
1698  @endverbatim
1699  *
1700  * @note
1701  * The copy of Target_Type object passed to `try_process` method is
1702  * created before checking the presence of subitems. If all subitems
1703  * are found then the value of that temporary object moved back to
1704  * \a target parameter of `try_process` method.
1705  *
1706  * @note
1707  * This clause always returns success even if nothing has been
1708  * consumed from the input stream.
1709  *
1710  * @tparam Subitems_Tuple the type of std::tuple with items for every
1711  * clause to be checked.
1712  *
1713  * @since v.0.6.1
1714  */
1715 template<
1716  typename Subitems_Tuple >
1718 {
1719  Subitems_Tuple m_subitems;
1720 
1721 public :
1723  Subitems_Tuple && subitems )
1724  : m_subitems{ std::move(subitems) }
1725  {}
1726 
1727  template< typename Target_Type >
1728  [[nodiscard]]
1731  {
1734 
1735  const bool success = restinio::utils::tuple_algorithms::all_of(
1736  m_subitems,
1737  [&from, &tmp_value]( auto && one_producer ) {
1738  return !one_producer.try_process( from, tmp_value );
1739  } );
1740 
1741  if( success )
1742  {
1743  target = std::move(tmp_value);
1744  consumer.commit();
1745  }
1746 
1747  // maybe_clause always returns success even if nothing consumed.
1748  return std::nullopt;
1749  }
1750 };
1751 
1752 //
1753 // not_clause_t
1754 //
1755 /*!
1756  * @brief A template for implementation of clause that checks absence of
1757  * some entity in the input stream.
1758  *
1759  * This template implements rules like:
1760  @verbatim
1761  T := !A B
1762  @endverbatim
1763  * where not_clause_t is related to the part `!A` only.
1764  *
1765  * @note
1766  * The empty temporary object of Target_Type passed to call of `try_process` of
1767  * subitems.
1768  *
1769  * @note
1770  * This clause always returns the current position in the input stream
1771  * back at the position where this clause was called.
1772  *
1773  * @tparam Subitems_Tuple the type of std::tuple with items for every
1774  * clause to be checked.
1775  *
1776  * @since v.0.6.1
1777  */
1778 template<
1779  typename Subitems_Tuple >
1780 class not_clause_t : public clause_tag
1781 {
1782  Subitems_Tuple m_subitems;
1783 
1784 public :
1786  Subitems_Tuple && subitems )
1787  : m_subitems{ std::move(subitems) }
1788  {}
1789 
1790  template< typename Target_Type >
1791  [[nodiscard]]
1794  {
1795  // NOTE: will always return the current position back.
1797 
1799 
1800  const auto success = !restinio::utils::tuple_algorithms::all_of(
1801  m_subitems,
1802  [&from, &dummy_value]( auto && one_producer ) {
1804  } );
1805 
1806  // This is contra-intuitive but: we return pattern_not_found in
1807  // the case when pattern is actually found in the input.
1808  if( !success )
1809  return parse_error_t{
1810  consumer.started_at(),
1811  //FIXME: maybe a more appropriate error_reason can
1812  //be used here?
1814  };
1815  else
1816  return std::nullopt;
1817  }
1818 };
1819 
1820 //
1821 // and_clause_t
1822 //
1823 /*!
1824  * @brief A template for implementation of clause that checks the presence of
1825  * some entity in the input stream.
1826  *
1827  * This template implements rules like:
1828  @verbatim
1829  T := A &B
1830  @endverbatim
1831  * where and_clause_t is related to the part `&B` only.
1832  *
1833  * @note
1834  * The empty temporary object of Target_Type passed to call of `try_process` of
1835  * subitems.
1836  *
1837  * @note
1838  * This clause always returns the current position in the input stream
1839  * back at the position where this clause was called.
1840  *
1841  * @tparam Subitems_Tuple the type of std::tuple with items for every
1842  * clause to be checked.
1843  *
1844  * @since v.0.6.1
1845  */
1846 template<
1847  typename Subitems_Tuple >
1848 class and_clause_t : public clause_tag
1849 {
1850  Subitems_Tuple m_subitems;
1851 
1852 public :
1854  Subitems_Tuple && subitems )
1855  : m_subitems{ std::move(subitems) }
1856  {}
1857 
1858  template< typename Target_Type >
1859  [[nodiscard]]
1862  {
1863  // NOTE: will always return the current position back.
1865 
1867 
1868  const bool success = restinio::utils::tuple_algorithms::all_of(
1869  m_subitems,
1870  [&from, &dummy_value]( auto && one_producer ) {
1872  } );
1873 
1874  if( !success )
1875  return parse_error_t{
1876  consumer.started_at(),
1878  };
1879  else
1880  return std::nullopt;
1881  }
1882 };
1883 
1884 //
1885 // sequence_clause_t
1886 //
1887 /*!
1888  * @brief A template for implementation of clause that checks and
1889  * handles presence of sequence of entities in the input stream.
1890  *
1891  * This template implements rules like:
1892  @verbatim
1893  T := A B C
1894  @endverbatim
1895  *
1896  * @note
1897  * The copy of Target_Type object passed to `try_process` method is
1898  * created before checking the presence of subitems. If all subitems
1899  * are found then the value of that temporary object moved back to
1900  * @a target parameter of `try_process` method.
1901  *
1902  * @tparam Subitems_Tuple the type of std::tuple with items for every
1903  * clause to be checked.
1904  *
1905  * @since v.0.6.1
1906  */
1907 template<
1908  typename Subitems_Tuple >
1910 {
1911  Subitems_Tuple m_subitems;
1912 
1913 public :
1915  Subitems_Tuple && subitems )
1916  : m_subitems{ std::move(subitems) }
1917  {}
1918 
1919  template< typename Target_Type >
1920  [[nodiscard]]
1923  {
1926 
1927  // We should store actual parse error from subitems to return it.
1929 
1930  const bool success = restinio::utils::tuple_algorithms::all_of(
1931  m_subitems,
1932  [&from, &tmp_value, &result]( auto && one_producer ) {
1934  return !result;
1935  } );
1936 
1937  if( success )
1938  {
1939  target = std::move(tmp_value);
1940  consumer.commit();
1941  }
1942 
1943  return result;
1944  }
1945 };
1946 
1947 //
1948 // forced_alternative_clause_t
1949 //
1950 /*!
1951  * @brief An alternative that should be parsed correctly or the parsing
1952  * of the whole alternatives clause should fail.
1953  *
1954  * This special clause is intended to be used in the implementation
1955  * of restinio::easy_parser::force_only_this_alternative(). See the
1956  * description of that function for more details.
1957  *
1958  * @since v.0.6.7
1959  */
1960 template<
1961  typename Subitems_Tuple >
1962 class forced_alternative_clause_t : public sequence_clause_t< Subitems_Tuple >
1963 {
1964  using base_type_t = sequence_clause_t< Subitems_Tuple >;
1965 
1966 public :
1967  using base_type_t::base_type_t;
1968 
1969  template< typename Target_Type >
1970  [[nodiscard]]
1973  {
1974  const auto starting_pos = from.current_position();
1975 
1976  if( base_type_t::try_process( from, target ) )
1977  {
1978  // The forced clause is not parsed correctly.
1979  // So the special error code should be returned in that case.
1980  return parse_error_t{
1981  starting_pos,
1983  };
1984  }
1985  else
1986  return std::nullopt;
1987  }
1988 };
1989 
1990 //
1991 // produce_t
1992 //
1993 /*!
1994  * @brief A template for producing a value of specific type of
1995  * a sequence of entities from the input stream.
1996  *
1997  * Creates a new empty object of type Target_Type in `try_parse` and
1998  * then call `try_process` methods for every subitems. A reference to
1999  * that new object is passed to every `try_process` call.
2000  *
2001  * @tparam Target_Type the type of value to be produced.
2002  * @tparam Subitems_Tuple the type of std::tuple with items for every
2003  * clause to be checked.
2004  *
2005  * @since v.0.6.1
2006  */
2007 template<
2008  typename Target_Type,
2009  typename Subitems_Tuple >
2010 class produce_t : public producer_tag< Target_Type >
2011 {
2012  using value_wrapper_t = result_value_wrapper< Target_Type >;
2013 
2014  Subitems_Tuple m_subitems;
2015 
2016 public :
2018  Subitems_Tuple && subitems )
2019  : m_subitems{ std::move(subitems) }
2020  {}
2021 
2022  [[nodiscard]]
2025  {
2028 
2029  const bool success = restinio::utils::tuple_algorithms::all_of(
2030  m_subitems,
2031  [&from, &tmp_value, &error]( auto && one_clause ) {
2033  return !error;
2034  } );
2035 
2036  if( success )
2038  else
2039  return make_unexpected( *error );
2040  }
2041 };
2042 
2043 //
2044 // repeat_clause_t
2045 //
2046 /*!
2047  * @brief A template for handling repetition of clauses.
2048  *
2049  * Calls `try_process` for all subitems until some of them returns
2050  * error or max_occurences will be passed.
2051  *
2052  * Returns failure if min_occurences wasn't passed.
2053  *
2054  * @tparam Subitems_Tuple the type of std::tuple with items for every
2055  * clause to be checked.
2056  *
2057  * @since v.0.6.1
2058  */
2059 template<
2060  typename Subitems_Tuple >
2062 {
2065 
2066  Subitems_Tuple m_subitems;
2067 
2068 public :
2070  std::size_t min_occurences,
2071  std::size_t max_occurences,
2072  Subitems_Tuple && subitems )
2075  , m_subitems{ std::move(subitems) }
2076  {}
2077 
2078  template< typename Target_Type >
2079  [[nodiscard]]
2082  {
2084 
2085  std::size_t count{};
2086  bool failure_detected{ false };
2087  for(; !failure_detected && count != m_max_occurences; )
2088  {
2090 
2092  m_subitems,
2093  [&from, &dest]( auto && one_clause ) {
2094  return !one_clause.try_process( from, dest );
2095  } );
2096 
2097  if( !failure_detected )
2098  {
2099  // Another item successfully parsed and should be stored.
2101  ++count;
2102  }
2103  }
2104 
2105  if( count >= m_min_occurences )
2106  {
2108  return std::nullopt;
2109  }
2110 
2111  return parse_error_t{
2114  };
2115  }
2116 };
2117 
2118 //
2119 // symbol_producer_template_t
2120 //
2121 /*!
2122  * @brief A template for producer of charachers that satisfy some predicate.
2123  *
2124  * In the case of success returns the expected character.
2125  *
2126  * @tparam Predicate the type of predicate to check extracted symbol.
2127  *
2128  * @since v.0.6.1
2129  */
2130 template< typename Predicate >
2132  : public producer_tag< char >
2133  , protected Predicate
2134 {
2135 public:
2136  template< typename... Args >
2137  symbol_producer_template_t( Args &&... args )
2138  : Predicate{ std::forward<Args>(args)... }
2139  {}
2140 
2141  [[nodiscard]]
2142  expected_t< char, parse_error_t >
2143  try_parse( source_t & from ) const noexcept
2144  {
2145  const auto ch = from.getch();
2146  if( !ch.m_eof )
2147  {
2148  // A call to predicate.
2149  if( (*this)(ch.m_ch) )
2150  return ch.m_ch;
2151  else
2152  {
2153  from.putback();
2157  } );
2158  }
2159  }
2160  else
2164  } );
2165  }
2166 };
2167 
2168 //
2169 // any_symbol_predicate_t
2170 //
2171 /*!
2172  * @brief A predicate that allows extraction of any symbol.
2173  *
2174  * This predicate is necessary for implementation of any_symbol_p()
2175  * producer.
2176  *
2177  * @since v.0.6.6
2178  */
2180 {
2181  [[nodiscard]]
2182  constexpr bool
2183  operator()( const char ) const noexcept
2184  {
2185  return true;
2186  }
2187 };
2188 
2189 //
2190 // particular_symbol_predicate_t
2191 //
2192 /*!
2193  * @brief A predicate for cases where exact match of expected and
2194  * actual symbols is required.
2195  *
2196  * @since v.0.6.1
2197  */
2199 {
2201 
2202  [[nodiscard]]
2203  bool
2204  operator()( const char actual ) const noexcept
2205  {
2206  return m_expected == actual;
2207  }
2208 };
2209 
2210 //
2211 // not_particular_symbol_predicate_t
2212 //
2213 /*!
2214  * @brief A predicate for cases where mismatch with a particular
2215  * symbol is required.
2216  *
2217  * @since v.0.6.6
2218  */
2220 {
2222 
2223  [[nodiscard]]
2224  bool
2225  operator()( const char actual ) const noexcept
2226  {
2227  return m_sentinel != actual;
2228  }
2229 };
2230 
2231 //
2232 // caseless_particular_symbol_predicate_t
2233 //
2234 /*!
2235  * @brief A predicate for cases where the case-insensitive match of expected
2236  * and actual symbols is required.
2237  *
2238  * @since v.0.6.6
2239  */
2241 {
2243 
2246  {}
2247 
2248  [[nodiscard]]
2249  bool
2250  operator()( const char actual ) const noexcept
2251  {
2252  return m_expected == restinio::impl::to_lower_case(actual);
2253  }
2254 };
2255 
2256 //
2257 // symbol_from_range_predicate_t
2258 //
2259 /*!
2260  * @brief A predicate for cases where a symbol should belong
2261  * to specified range.
2262  *
2263  * Range is inclusive. It means that `(ch >= left && ch <= right)`.
2264  *
2265  * @since v.0.6.9
2266  */
2268 {
2269  char m_left;
2270  char m_right;
2271 
2272  [[nodiscard]]
2273  bool
2274  operator()( const char actual ) const noexcept
2275  {
2276  return ( actual >= m_left && actual <= m_right );
2277  }
2278 };
2279 
2280 //
2281 // symbol_producer_t
2282 //
2283 /*!
2284  * @brief A producer for the case when a particual character is expected
2285  * in the input stream.
2286  *
2287  * In the case of success returns the expected character.
2288  *
2289  * @since v.0.6.1
2290  */
2293 {
2294  using base_type_t =
2296 
2297 public:
2298  symbol_producer_t( char expected )
2300  {}
2301 };
2302 
2303 //
2304 // any_symbol_if_not_producer_t
2305 //
2306 /*!
2307  * @brief A producer for the case when any character except the specific
2308  * sentinel character is expected in the input stream.
2309  *
2310  * In the case of success returns a character from the input stream.
2311  *
2312  * @since v.0.6.6
2313  */
2316 {
2317  using base_type_t =
2319 
2320 public:
2323  {}
2324 };
2325 
2326 //
2327 // caseless_symbol_producer_t
2328 //
2329 /*!
2330  * @brief A producer for the case when a particual character is expected
2331  * in the input stream.
2332  *
2333  * Performs caseless comparison of symbols.
2334  *
2335  * In the case of success returns the character from the input stream
2336  * (e.g. without transformation to lower or upper case).
2337  *
2338  * @since v.0.6.6
2339  */
2342 {
2343  using base_type_t =
2345 
2346 public:
2349  {}
2350 };
2351 
2352 //
2353 // symbol_from_range_producer_t
2354 //
2355 /*!
2356  * @brief A producer for the case when a symbol should belong
2357  * to specified range.
2358  *
2359  * Range is inclusive. It means that `(ch >= left && ch <= right)`.
2360  *
2361  * @since v.0.6.9
2362  */
2365 {
2366  using base_type_t =
2368 
2369 public:
2370  symbol_from_range_producer_t( char left, char right )
2372  {}
2373 };
2374 
2375 //
2376 // digit_producer_t
2377 //
2378 /*!
2379  * @brief A producer for the case when a decimal digit is expected
2380  * in the input stream.
2381  *
2382  * In the case of success returns the extracted character.
2383  *
2384  * @since v.0.6.1
2385  */
2388 {
2389 public:
2391 };
2392 
2393 //
2394 // hexdigit_producer_t
2395 //
2396 /*!
2397  * @brief A producer for the case when a hexadecimal digit is expected
2398  * in the input stream.
2399  *
2400  * In the case of success returns the extracted character.
2401  *
2402  * @since v.0.6.6
2403  */
2406 {
2407 public:
2409 };
2410 
2411 //
2412 // try_parse_digits_with_digits_limit
2413 //
2414 /*!
2415  * @brief Helper function for parsing integers with respect to
2416  * the number of digits to be consumed.
2417  *
2418  * Usage example:
2419  * @code
2420  * // For the case of unsigned or positive signed integer:
2421  * auto r = try_parse_digits_with_digits_limit<unsigned int>(from,
2422  * expected_digits(4),
2423  * restinio::impl::overflow_controlled_integer_accumulator_t<unsigned int, 10>{});
2424  * // For the case of negative signed integer.
2425  * auto r = try_parse_digits_with_digits_limit<short>(from,
2426  * expected_digits(4),
2427  * restinio::impl::overflow_controlled_integer_accumulator_t<
2428  * short,
2429  * 10,
2430  * restinio::impl::check_negative_extremum>{});
2431  * @endcode
2432  *
2433  * @since v.0.6.6
2434  */
2435 template< typename T, typename Value_Accumulator >
2436 [[nodiscard]]
2439  source_t & from,
2441  Value_Accumulator acc ) noexcept
2442 {
2444 
2446 
2447  for( auto ch = from.getch(); !ch.m_eof; ch = from.getch() )
2448  {
2449  if( is_digit(ch.m_ch) )
2450  {
2451  acc.next_digit( static_cast<T>(ch.m_ch - '0') );
2452 
2453  if( acc.overflow_detected() )
2455  consumer.started_at(),
2457  } );
2458 
2461  break;
2462  }
2463  else
2464  {
2465  from.putback();
2466  break;
2467  }
2468  }
2469 
2471  // Not all required digits are extracted.
2475  } );
2476  else
2477  {
2478  consumer.commit();
2479  return acc.value();
2480  }
2481 }
2482 
2483 //
2484 // try_parse_hexdigits_with_digits_limit
2485 //
2486 /*!
2487  * @brief Helper function for parsing integers in hexadecimal form.
2488  *
2489  * Usage example:
2490  * @code
2491  * // For the case of unsigned or positive signed integer:
2492  * auto r = try_parse_hexdigits_with_digits_limit<unsigned int>(from,
2493  * expected_digits(4, 8),
2494  * restinio::impl::overflow_controlled_integer_accumulator_t<unsigned int, 16>{});
2495  * @endcode
2496  *
2497  * @since v.0.6.6
2498  */
2499 template< typename T, typename Value_Accumulator >
2500 [[nodiscard]]
2503  source_t & from,
2505  Value_Accumulator acc ) noexcept
2506 {
2507  const auto ch_to_digit = []( char ch ) -> std::pair<bool, T> {
2508  if( ch >= '0' && ch <= '9' )
2509  return std::make_pair( true, static_cast<T>(ch - '0') );
2510  else if( ch >= 'A' && ch <= 'F' )
2511  return std::make_pair( true, static_cast<T>(10 + (ch - 'A')) );
2512  else if( ch >= 'a' && ch <= 'f' )
2513  return std::make_pair( true, static_cast<T>(10 + (ch - 'a')) );
2514  else
2515  return std::make_pair( false, static_cast<T>(0) );
2516  };
2517 
2519 
2521 
2522  for( auto ch = from.getch(); !ch.m_eof; ch = from.getch() )
2523  {
2524  const auto d = ch_to_digit( ch.m_ch );
2525  if( d.first )
2526  {
2527  acc.next_digit( d.second );
2528 
2529  if( acc.overflow_detected() )
2531  consumer.started_at(),
2533  } );
2534 
2537  break;
2538  }
2539  else
2540  {
2541  from.putback();
2542  break;
2543  }
2544  }
2545 
2547  // Not all required digits are extracted.
2551  } );
2552  else
2553  {
2554  consumer.commit();
2555  return acc.value();
2556  }
2557 }
2558 
2559 //
2560 // non_negative_decimal_number_producer_t
2561 //
2562 /*!
2563  * @brief A producer for the case when a non-negative decimal number is
2564  * expected in the input stream.
2565  *
2566  * In the case of success returns the extracted number.
2567  *
2568  * @since v.0.6.2
2569  */
2570 template< typename T >
2572 {
2573 public:
2574  [[nodiscard]]
2576  try_parse( source_t & from ) const noexcept
2577  {
2579  from,
2582  }
2583 };
2584 
2585 //
2586 // non_negative_decimal_number_producer_with_digits_limit_t
2587 //
2588 /*!
2589  * @brief A producer for the case when a non-negative decimal number is
2590  * expected in the input stream.
2591  *
2592  * This class takes into account a number of digits to be consumed.
2593  *
2594  * In the case of success returns the extracted number.
2595  *
2596  * @since v.0.6.6
2597  */
2598 template< typename T >
2601 {
2603 
2604 public:
2606  digits_to_consume_t digits_limit )
2608  {}
2609 
2610  [[nodiscard]]
2612  try_parse( source_t & from ) const noexcept
2613  {
2615  from,
2618  }
2619 };
2620 
2621 //
2622 // hexadecimal_number_producer_t
2623 //
2624 /*!
2625  * @brief A producer for the case when a number in hexadecimal form is expected
2626  * in the input stream.
2627  *
2628  * In the case of success returns the extracted number.
2629  *
2630  * @since v.0.6.6
2631  */
2632 template< typename T >
2634 {
2635  static_assert( std::is_unsigned<T>::value,
2636  "T is expected to be unsigned type" );
2637 
2638 public:
2639  [[nodiscard]]
2641  try_parse( source_t & from ) const noexcept
2642  {
2644  from,
2647  }
2648 };
2649 
2650 //
2651 // hexadecimal_number_producer_with_digits_limit_t
2652 //
2653 /*!
2654  * @brief A producer for the case when a number in hexadecimal form is expected
2655  * in the input stream.
2656  *
2657  * This class takes into account a number of digits to be consumed.
2658  *
2659  * In the case of success returns the extracted number.
2660  *
2661  * @since v.0.6.6
2662  */
2663 template< typename T >
2665  : public hexadecimal_number_producer_t< T >
2666 {
2668 
2669 public:
2671  digits_to_consume_t digits_limit )
2673  {}
2674 
2675  [[nodiscard]]
2677  try_parse( source_t & from ) const noexcept
2678  {
2680  from,
2683  }
2684 };
2685 
2686 //
2687 // decimal_number_producer_t
2688 //
2689 /*!
2690  * @brief A producer for the case when a signed decimal number is
2691  * expected in the input stream.
2692  *
2693  * In the case of success returns the extracted number.
2694  *
2695  * @since v.0.6.6
2696  */
2697 template< typename T >
2699 {
2700  static_assert( std::is_signed<T>::value,
2701  "decimal_number_producer_t can be used only for signed types" );
2702 
2703 public:
2705 
2706  [[nodiscard]]
2708  try_parse( source_t & from ) const noexcept
2709  {
2710  return try_parse_impl( from,
2711  []() noexcept {
2713  } );
2714  }
2715 
2716 protected:
2717  template< typename Digits_Limit_Maker >
2718  [[nodiscard]]
2721  source_t & from,
2722  Digits_Limit_Maker && digits_limit_maker ) const noexcept
2723  {
2725 
2726  auto sign_ch = from.getch();
2727  if( !sign_ch.m_eof )
2728  {
2729  const auto r = try_parse_with_this_first_symbol(
2730  from,
2731  sign_ch.m_ch,
2733 
2734  if( r )
2735  consumer.commit();
2736 
2737  return r;
2738  }
2739  else
2743  } );
2744  }
2745 
2746 private:
2747  template< typename Digits_Limit_Maker >
2748  [[nodiscard]]
2749  static try_parse_result_type
2751  source_t & from,
2752  char first_symbol,
2754  {
2757 
2758  if( '-' == first_symbol )
2759  {
2760  const auto r = try_parse_digits_with_digits_limit< T >(
2761  from,
2764  T,
2765  10,
2767  if( r )
2768  return static_cast< T >( -(*r) ); // This static_cast is required
2769  // for clang compiler that warns that if type of *r is `short`,
2770  // then -(*r) will have type `int`.
2771  else
2772  return r;
2773  }
2774  else if( '+' == first_symbol )
2775  {
2777  from,
2780  }
2781  else if( is_digit(first_symbol) )
2782  {
2783  from.putback();
2785  from,
2788  }
2789 
2793  } );
2794  }
2795 };
2796 
2797 //
2798 // decimal_number_producer_with_digits_limit_t
2799 //
2800 /*!
2801  * @brief A producer for the case when a signed decimal number is
2802  * expected in the input stream.
2803  *
2804  * This class takes into account a number of digits to be consumed.
2805  *
2806  * In the case of success returns the extracted number.
2807  *
2808  * @since v.0.6.6
2809  */
2810 template< typename T >
2812  : public decimal_number_producer_t< T >
2813 {
2815 
2816 public:
2818  digits_to_consume_t digits_limit )
2820  {}
2821 
2822  [[nodiscard]]
2823  auto
2824  try_parse( source_t & from ) const noexcept
2825  {
2826  return this->try_parse_impl(
2827  from,
2828  [this]() noexcept { return m_digits_limit; } );
2829  }
2830 };
2831 
2832 //
2833 // any_value_skipper_t
2834 //
2835 /*!
2836  * @brief A special consumer that simply throws any value away.
2837  *
2838  * This consumer is intended to be used in the case when the presence
2839  * of some value should be checked but the value itself isn't needed.
2840  *
2841  * @since v.0.6.1
2842  */
2844 {
2845  template< typename Target_Type, typename Value >
2846  void
2847  consume( Target_Type &, Value && ) const noexcept {}
2848 };
2849 
2850 //
2851 // as_result_consumer_t
2852 //
2853 /*!
2854  * @brief A consumer for the case when the current value should
2855  * be returned as the result for the producer at one level up.
2856  *
2857  * For example that consumer can be necessary for rules like that:
2858  @verbatim
2859  T := 'v' '=' token
2860  @endverbatim
2861  * such rule will be implemented by a such sequence of clauses:
2862  * @code
2863  * produce<std::string>(symbol('v'), symbol('='), token_p() >> as_result());
2864  * @endcode
2865  * The result of `token_p()` producer in a subclause should be returned
2866  * as the result of top-level producer.
2867  *
2868  * @since v.0.6.1
2869  */
2871 {
2872  template< typename Target_Type, typename Value >
2873  void
2874  consume( Target_Type & dest, Value && src ) const
2875  {
2877  dest, std::forward<Value>(src) );
2878  }
2879 };
2880 
2881 //
2882 // just_result_consumer_t
2883 //
2884 /*!
2885  * @brief A consumer for the case when a specific value should
2886  * be used as the result instead of the value produced on
2887  * the previous step.
2888  *
2889  * @since v.0.6.6
2890  */
2891 template< typename Result_Type >
2893 {
2894  Result_Type m_result;
2895 
2896  // NOTE: this helper method is necessary for MSVC++ compiler.
2897  // It's because MSVC++ can't compile expression:
2898  //
2899  // as_result(dest, Result_Type{m_result})
2900  //
2901  // in consume() method for trivial types like size_t.
2902  Result_Type
2904  noexcept(noexcept(Result_Type{m_result}))
2905  {
2906  return m_result;
2907  }
2908 
2909 public :
2910  template< typename Result_Arg >
2911  just_result_consumer_t( Result_Arg && result )
2912  noexcept(noexcept(Result_Type{std::forward<Result_Arg>(result)}))
2914  {}
2915 
2916  template< typename Target_Type, typename Value >
2917  void
2918  consume( Target_Type & dest, Value && ) const
2919  {
2921  dest,
2922  // NOTE: use a copy of m_result.
2923  make_copy_of_result() );
2924  }
2925 };
2926 
2927 //
2928 // custom_consumer_t
2929 //
2930 /*!
2931  * @brief A template for consumers that are released by lambda/functional
2932  * objects.
2933  *
2934  * @tparam C the type of lambda/functional object/function pointer to
2935  * be used as the actual consumer.
2936  *
2937  * @since v.0.6.1
2938  */
2939 template< typename C >
2941 {
2943 
2944 public :
2945  custom_consumer_t( C && consumer ) : m_consumer{std::move(consumer)} {}
2946 
2947  template< typename Target_Type, typename Value >
2948  void
2949  consume( Target_Type & dest, Value && src ) const
2950  noexcept(noexcept(m_consumer(dest, std::forward<Value>(src))))
2951  {
2953  }
2954 };
2955 
2956 //
2957 // field_setter_consumer_t
2958 //
2959 /*!
2960  * @brief A template for consumers that store a value to the specified
2961  * field of a target object.
2962  *
2963  * @tparam F type of the target field
2964  * @tparam C type of the target object.
2965  *
2966  * @since v.0.6.1
2967  */
2968 template< typename F, typename C >
2970 {
2971  using pointer_t = F C::*;
2972 
2973  pointer_t m_ptr;
2974 
2975 public :
2976  field_setter_consumer_t( pointer_t ptr ) noexcept : m_ptr{ptr} {}
2977 
2978  // NOTE: it seems that this method won't be compiled if
2979  // result_value_wrapper::result_type differs from
2980  // result_value_wrapper::wrapped_type.
2981  //
2982  // This is not a problem for the current version.
2983  // But this moment would require more attention in the future.
2984  void
2985  consume( C & to, F && value ) const
2986  noexcept(noexcept(to.*m_ptr = std::move(value)))
2987  {
2988  to.*m_ptr = std::move(value);
2989  }
2990 };
2991 
2992 /*!
2993  * @brief A special operator to connect a value producer with
2994  * field_setter_consumer.
2995  *
2996  * @since v.0.6.1
2997  */
2998 template< typename P, typename F, typename C >
2999 [[nodiscard]]
3000 std::enable_if_t<
3001  is_producer_v<P>,
3004 {
3005  return {
3006  std::move(producer),
3008  };
3009 }
3010 
3011 //
3012 // tuple_item_consumer_t
3013 //
3014 /*!
3015  * @brief A consumer that stores a result value at the specified
3016  * index in the result tuple.
3017  *
3018  * @since v.0.6.6
3019  */
3020 template< std::size_t Index >
3022 {
3023  // NOTE: it seems that this method won't be compiled if
3024  // result_value_wrapper::result_type differs from
3025  // result_value_wrapper::wrapped_type.
3026  //
3027  // This is not a problem for the current version.
3028  // But this moment would require more attention in the future.
3029  template< typename Target_Type, typename Value >
3030  void
3031  consume( Target_Type && to, Value && value )
3032  {
3034  std::forward<Value>(value);
3035  }
3036 };
3037 
3038 //
3039 // to_lower_transformer_t
3040 //
3041 template< typename Input_Type >
3042 struct to_lower_transformer_t;
3043 
3044 /*!
3045  * @brief An implementation of transformer that converts the content
3046  * of the input std::string to lower case.
3047  *
3048  * @since v.0.6.1
3049  */
3050 template<>
3052  : public transformer_tag< std::string >
3053 {
3055 
3056  [[nodiscard]]
3057  result_type
3058  transform( input_type && input ) const noexcept
3059  {
3062  []( unsigned char ch ) -> char {
3063  return restinio::impl::to_lower_case(ch);
3064  } );
3065 
3066  return result;
3067  }
3068 };
3069 
3070 /*!
3071  * @brief An implementation of transformer that converts the content
3072  * of the input character to lower case.
3073  *
3074  * @since v.0.6.6
3075  */
3076 template<>
3077 struct to_lower_transformer_t< char >
3078  : public transformer_tag< char >
3079 {
3080  using input_type = char;
3081 
3082  [[nodiscard]]
3083  result_type
3084  transform( input_type && input ) const noexcept
3085  {
3086  return restinio::impl::to_lower_case(input);
3087  }
3088 };
3089 
3090 /*!
3091  * @brief An implementation of transformer that converts the content
3092  * of the input std::array to lower case.
3093  *
3094  * @since v.0.6.6
3095  */
3096 template< std::size_t S >
3097 struct to_lower_transformer_t< std::array< char, S > >
3098  : public transformer_tag< std::array< char, S > >
3099 {
3100  using input_type = std::array< char, S >;
3102 
3103  [[nodiscard]]
3104  typename base_type::result_type
3105  transform( input_type && input ) const noexcept
3106  {
3107  typename base_type::result_type result;
3109  []( unsigned char ch ) -> char {
3110  return restinio::impl::to_lower_case(ch);
3111  } );
3112 
3113  return result;
3114  }
3115 };
3116 
3117 //
3118 // to_lower_transformer_proxy_t
3119 //
3120 /*!
3121  * @brief A proxy for the creation of an appropriate to_lower_transformer.
3122  *
3123  * @since v.0.6.6
3124  */
3126 {
3127  template< typename Input_Type >
3128  [[nodiscard]]
3129  auto
3130  make_transformer() const noexcept
3131  {
3132  return to_lower_transformer_t< Input_Type >{};
3133  }
3134 };
3135 
3136 //
3137 // just_value_transformer_t
3138 //
3139 /*!
3140  * @brief A transformer that skips incoming value and returns
3141  * a value specified by a user.
3142  *
3143  * @since v.0.6.6
3144  */
3145 template< typename T >
3147 {
3149 
3150 public :
3151  just_value_transformer_t( T v ) noexcept(noexcept(T{std::move(v)}))
3152  : m_value{ std::move(v) }
3153  {}
3154 
3155  template< typename Input >
3156  [[nodiscard]]
3157  T
3158  transform( Input && ) const noexcept(noexcept(T{m_value}))
3159  {
3160  return m_value;
3161  }
3162 };
3163 
3164 //
3165 // convert_transformer_t
3166 //
3167 /*!
3168  * @brief A transformator that uses a user supplied function/functor
3169  * for conversion a value from one type to another.
3170  *
3171  * @since v.0.6.6
3172  */
3173 template< typename Output_Type, typename Converter >
3174 class convert_transformer_t : public transformer_tag< Output_Type >
3175 {
3176  Converter m_converter;
3177 
3178 public :
3179  template< typename Convert_Arg >
3180  convert_transformer_t( Convert_Arg && converter )
3181  noexcept(noexcept(Converter{std::forward<Convert_Arg>(converter)}))
3183  {}
3184 
3185  /*!
3186  * @brief Performs the transformation by calling the converter.
3187  *
3188  * @note
3189  * Since v.0.6.11 the result type changed from Output_Type to `auto`.
3190  * That allows to use converters that returns
3191  * expected_t<Output_Type, error_reason_t>.
3192  */
3193  template< typename Input >
3194  [[nodiscard]]
3195  auto
3196  transform( Input && input ) const
3197  noexcept(noexcept(m_converter(std::forward<Input>(input))))
3198  {
3199  using actual_result_t = std::decay_t< decltype(
3200  m_converter(std::forward<Input>(input))
3201  ) >;
3202 
3203  static_assert(
3204  is_appropriate_transformer_result_type<actual_result_t>::value,
3205  "the return value of converter should be either Output_Type or "
3206  "expected_t<Output_Type, error_reason_t>" );
3207 
3208  return m_converter(std::forward<Input>(input));
3209  }
3210 };
3211 
3212 //
3213 // conversion_result_type_detector
3214 //
3215 /*!
3216  * @brief A helper template for the detection of type to be produced
3217  * as conversion procedure.
3218  *
3219  * A conversion procedure can produce either T or expected_t<T, error_reason_t>.
3220  * In the case of expected_t<T, error_reason_t> it is necessary to know T.
3221  * This helper template allows to detect T in both cases.
3222  *
3223  * @since v.0.6.11
3224  */
3225 template< typename Result_Type >
3227 {
3228  using type = Result_Type;
3229 };
3230 
3231 template< typename Result_Type >
3233 {
3235 };
3236 
3237 /*!
3238  * A helper for simplification of usage of conversion_result_type_detector<R>.
3239  *
3240  * @since v.0.6.11
3241  */
3242 template< typename Result_Type >
3243 using conversion_result_type_detector_t =
3244  typename conversion_result_type_detector<Result_Type>::type;
3245 
3246 //
3247 // convert_transformer_proxy_t
3248 //
3249 /*!
3250  * @brief A proxy for the creation of convert_transformer instances
3251  * for a specific value producers.
3252  *
3253  * @note
3254  * This class is intended to be used in implementation of operator>>
3255  * for cases like that:
3256  * @code
3257  * symbol_p('k') >> convert([](auto ch) { return 1024u; })
3258  * @endcode
3259  *
3260  * @since v.0.6.6
3261  */
3262 template< typename Converter >
3264 {
3265  template< typename Input_Type >
3267  std::decay_t< decltype(
3268  std::declval<Converter &>()(std::declval<Input_Type&&>())
3269  ) >
3270  >;
3271 
3272  Converter m_converter;
3273 
3274 public :
3275  template< typename Convert_Arg >
3276  convert_transformer_proxy_t( Convert_Arg && converter )
3277  noexcept(noexcept(Converter{std::forward<Convert_Arg>(converter)}))
3279  {}
3280 
3281  template< typename Input_Type >
3282  [[nodiscard]]
3283  auto
3285  noexcept(noexcept(Converter{m_converter}))
3286  {
3287  using output_t = output<Input_Type>;
3288 
3289  return convert_transformer_t< output_t, Converter >{ m_converter };
3290  }
3291 
3292  template< typename Input_Type >
3293  [[nodiscard]]
3294  auto
3296  noexcept(noexcept(Converter{std::move(m_converter)}))
3297  {
3298  using output_t = output<Input_Type>;
3299 
3300  return convert_transformer_t< output_t, Converter >{
3301  std::move(m_converter)
3302  };
3303  }
3304 };
3305 
3306 //
3307 // try_parse_exact_fragment
3308 //
3309 
3310 // Requires that begin is not equal to end.
3311 template< typename It >
3312 [[nodiscard]]
3313 expected_t< bool, parse_error_t >
3315 {
3316  assert( begin != end );
3317 
3319 
3320  for( auto ch = from.getch(); !ch.m_eof; ch = from.getch() )
3321  {
3322  if( ch.m_ch != *begin )
3324  consumer.started_at(),
3326  } );
3327  if( ++begin == end )
3328  break;
3329  }
3330 
3331  if( begin != end )
3333  consumer.started_at(),
3335  } );
3336 
3337  consumer.commit();
3338 
3339  return true;
3340 }
3341 
3342 //
3343 // exact_fixed_size_fragment_producer_t
3344 //
3345 /*!
3346  * @brief A producer that expects a fragment in the input and
3347  * produces boolean value if that fragment is found.
3348  *
3349  * This class is indended for working with fixed-size string literals
3350  * with terminating null-symbol.
3351  *
3352  * @since v.0.6.6
3353  */
3354 template< std::size_t Size >
3356  : public producer_tag< bool >
3357 {
3358  static_assert( 1u < Size, "Size is expected to greater that 1" );
3359 
3360  // NOTE: there is no space for last zero-byte.
3361  std::array< char, Size-1u > m_fragment;
3362 
3363 public:
3364  exact_fixed_size_fragment_producer_t( const char (&f)[Size] )
3365  {
3366  // NOTE: last zero-byte is discarded.
3367  std::copy( &f[ 0 ], &f[ m_fragment.size() ], m_fragment.data() );
3368  }
3369 
3370  [[nodiscard]]
3371  expected_t< bool, parse_error_t >
3373  {
3375  m_fragment.begin(), m_fragment.end() );
3376  }
3377 };
3378 
3379 //
3380 // exact_fragment_producer_t
3381 //
3382 /*!
3383  * @brief A producer that expects a fragment in the input and
3384  * produces boolean value if that fragment is found.
3385  *
3386  * @since v.0.6.6
3387  */
3389  : public producer_tag< bool >
3390 {
3392 
3393 public:
3394  exact_fragment_producer_t( std::string fragment )
3395  : m_fragment{ std::move(fragment) }
3396  {
3397  if( m_fragment.empty() )
3398  throw exception_t( "'fragment' value for exact_fragment_producer_t "
3399  "can't be empty!" );
3400  }
3401 
3402  [[nodiscard]]
3403  expected_t< bool, parse_error_t >
3405  {
3406  return try_parse_exact_fragment( from,
3407  m_fragment.begin(), m_fragment.end() );
3408  }
3409 };
3410 
3411 //
3412 // try_parse_caseless_exact_fragment
3413 //
3414 
3415 // Requires that begin is not equal to end.
3416 // It assumes that content in [begin, end) is already in lower case.
3417 template< typename It >
3418 [[nodiscard]]
3419 expected_t< bool, parse_error_t >
3421 {
3422  assert( begin != end );
3423 
3425 
3426  for( auto ch = from.getch(); !ch.m_eof; ch = from.getch() )
3427  {
3428  if( restinio::impl::to_lower_case(ch.m_ch) != *begin )
3430  consumer.started_at(),
3432  } );
3433  if( ++begin == end )
3434  break;
3435  }
3436 
3437  if( begin != end )
3439  consumer.started_at(),
3441  } );
3442 
3443  consumer.commit();
3444 
3445  return true;
3446 }
3447 
3448 //
3449 // caseless_exact_fixed_size_fragment_producer_t
3450 //
3451 /*!
3452  * @brief A producer that expects a fragment in the input and
3453  * produces boolean value if that fragment is found.
3454  *
3455  * The comparison is performed in case-insensitive manner.
3456  *
3457  * This class is indended for working with fixed-size string literals
3458  * with terminating null-symbol.
3459  *
3460  * @since v.0.6.9
3461  */
3462 template< std::size_t Size >
3464  : public producer_tag< bool >
3465 {
3466  static_assert( 1u < Size, "Size is expected to greater that 1" );
3467 
3468  // NOTE: there is no space for last zero-byte.
3469  std::array< char, Size-1u > m_fragment;
3470 
3471 public:
3473  {
3474  // Content should be converted to lower-case.
3475  // NOTE: last zero-byte is discarded.
3476  std::transform(
3477  &f[ 0 ], &f[ m_fragment.size() ],
3478  m_fragment.data(),
3479  []( const char src ) {
3480  return restinio::impl::to_lower_case( src );
3481  } );
3482  }
3483 
3484  [[nodiscard]]
3485  expected_t< bool, parse_error_t >
3487  {
3489  m_fragment.begin(), m_fragment.end() );
3490  }
3491 };
3492 
3493 //
3494 // caseless_exact_fragment_producer_t
3495 //
3496 /*!
3497  * @brief A producer that expects a fragment in the input and
3498  * produces boolean value if that fragment is found.
3499  *
3500  * The comparison is performed in case-insensitive manner.
3501  *
3502  * @since v.0.6.9
3503  */
3505  : public producer_tag< bool >
3506 {
3508 
3509 public:
3510  caseless_exact_fragment_producer_t( std::string fragment )
3511  : m_fragment{ std::move(fragment) }
3512  {
3513  if( m_fragment.empty() )
3514  throw exception_t( "'fragment' value for exact_fragment_producer_t "
3515  "can't be empty!" );
3516 
3517  // Content should be converted to lower-case.
3518  for( auto & ch : m_fragment )
3519  ch = restinio::impl::to_lower_case( ch );
3520  }
3521 
3522  [[nodiscard]]
3523  expected_t< bool, parse_error_t >
3525  {
3526  return try_parse_caseless_exact_fragment( from,
3527  m_fragment.begin(), m_fragment.end() );
3528  }
3529 };
3530 
3531 } /* namespace impl */
3532 
3533 //
3534 // produce
3535 //
3536 /*!
3537  * @brief A factory function to create a producer that creates an
3538  * instance of the target type by using specified clauses.
3539  *
3540  * Usage example:
3541  * @code
3542  * produce<std::string>(symbol('v'), symbol('='), token_p() >> as_result());
3543  * @endcode
3544  *
3545  * @tparam Target_Type the type of value to be produced.
3546  * @tparam Clauses the list of clauses to be used for a new value.
3547  *
3548  * @since v.0.6.1
3549  */
3550 template<
3551  typename Target_Type,
3552  typename... Clauses >
3553 [[nodiscard]]
3554 auto
3555 produce( Clauses &&... clauses )
3556 {
3557  static_assert( 0 != sizeof...(clauses),
3558  "list of clauses can't be empty" );
3559  static_assert( meta::all_of_v< impl::is_clause, Clauses... >,
3560  "all arguments for produce() should be clauses" );
3561 
3562  using producer_type_t = impl::produce_t<
3563  Target_Type,
3564  impl::tuple_of_entities_t<Clauses...> >;
3565 
3566  return producer_type_t{
3567  std::make_tuple(std::forward<Clauses>(clauses)...)
3568  };
3569 }
3570 
3571 //
3572 // alternatives
3573 //
3574 /*!
3575  * @brief A factory function to create an alternatives clause.
3576  *
3577  * Usage example:
3578  * @code
3579  * produce<std::string>(
3580  * alternatives(
3581  * sequence(symbol('v'), symbol('='), token_p() >> as_result()),
3582  * sequence(symbol('T'), symbol('/'), token_p() >> as_result())
3583  * )
3584  * );
3585  * @endcode
3586  * Please note the usage of sequence() inside the call to
3587  * alternatives().
3588  *
3589  * @tparam Clauses the list of clauses to be used as alternatives.
3590  *
3591  * @since v.0.6.1
3592  */
3593 template< typename... Clauses >
3594 [[nodiscard]]
3595 auto
3596 alternatives( Clauses &&... clauses )
3597 {
3598  static_assert( 0 != sizeof...(clauses),
3599  "list of clauses can't be empty" );
3600  static_assert( meta::all_of_v< impl::is_clause, Clauses... >,
3601  "all arguments for alternatives() should be clauses" );
3602 
3603  using clause_type_t = impl::alternatives_clause_t<
3604  impl::tuple_of_entities_t< Clauses... > >;
3605 
3606  return clause_type_t{
3607  std::make_tuple(std::forward<Clauses>(clauses)...)
3608  };
3609 }
3610 
3611 //
3612 // maybe
3613 //
3614 /*!
3615  * @brief A factory function to create an optional clause.
3616  *
3617  * Usage example:
3618  * @code
3619  * produce<std::pair<std::string, std::string>>(
3620  * token_p() >> &std::pair<std::string, std::string>::first,
3621  * maybe(
3622  * symbol('='),
3623  * token_p() >> &std::pair<std::string, std::string>::second
3624  * )
3625  * );
3626  * @endcode
3627  *
3628  * @tparam Clauses the list of clauses to be used as optional sequence.
3629  *
3630  * @since v.0.6.1
3631  */
3632 template< typename... Clauses >
3633 [[nodiscard]]
3634 auto
3635 maybe( Clauses &&... clauses )
3636 {
3637  static_assert( 0 != sizeof...(clauses),
3638  "list of clauses can't be empty" );
3639  static_assert( meta::all_of_v< impl::is_clause, Clauses... >,
3640  "all arguments for maybe() should be clauses" );
3641 
3642  using clause_type_t = impl::maybe_clause_t<
3643  impl::tuple_of_entities_t<Clauses...> >;
3644 
3645  return clause_type_t{
3646  std::make_tuple(std::forward<Clauses>(clauses)...)
3647  };
3648 }
3649 
3650 //
3651 // not_clause
3652 //
3653 /*!
3654  * @brief A factory function to create a not_clause.
3655  *
3656  * Usage example:
3657  * @code
3658  * produce<std::pair<std::string, std::string>>(
3659  * token_p() >> &std::pair<std::string, std::string>::first,
3660  * symbol(' '),
3661  * token_p() >> &std::pair<std::string, std::string>::second
3662  * not_clause(symbol('.'))
3663  * );
3664  * @endcode
3665  * this expression corresponds the following rule:
3666  @verbatim
3667  T := token SP token !'.'
3668  @endverbatim
3669  *
3670  * @tparam Clauses the list of clauses to be used as sequence to be checked.
3671  *
3672  * @since v.0.6.1
3673  */
3674 template< typename... Clauses >
3675 [[nodiscard]]
3676 auto
3677 not_clause( Clauses &&... clauses )
3678 {
3679  static_assert( 0 != sizeof...(clauses),
3680  "list of clauses can't be empty" );
3681  static_assert( meta::all_of_v< impl::is_clause, Clauses... >,
3682  "all arguments for not_clause() should be clauses" );
3683 
3684  using clause_type_t = impl::not_clause_t<
3685  impl::tuple_of_entities_t<Clauses...> >;
3686 
3687  return clause_type_t{
3688  std::make_tuple(std::forward<Clauses>(clauses)...)
3689  };
3690 }
3691 
3692 //
3693 // and_clause
3694 //
3695 /*!
3696  * @brief A factory function to create an and_clause.
3697  *
3698  * Usage example:
3699  * @code
3700  * produce<std::pair<std::string, std::string>>(
3701  * token_p() >> &std::pair<std::string, std::string>::first,
3702  * symbol(' '),
3703  * token_p() >> &std::pair<std::string, std::string>::second
3704  * and_clause(symbol(','), maybe(symbol(' ')), token_p() >> skip())
3705  * );
3706  * @endcode
3707  * this expression corresponds the following rule:
3708  @verbatim
3709  T := token SP token &(',' [' '] token)
3710  @endverbatim
3711  *
3712  * @tparam Clauses the list of clauses to be used as sequence to be checked.
3713  *
3714  * @since v.0.6.1
3715  */
3716 template< typename... Clauses >
3717 [[nodiscard]]
3718 auto
3719 and_clause( Clauses &&... clauses )
3720 {
3721  static_assert( 0 != sizeof...(clauses),
3722  "list of clauses can't be empty" );
3723  static_assert( meta::all_of_v< impl::is_clause, Clauses... >,
3724  "all arguments for sequence() should be clauses" );
3725 
3726  using clause_type_t = impl::and_clause_t<
3727  impl::tuple_of_entities_t<Clauses...> >;
3728 
3729  return clause_type_t{
3730  std::make_tuple(std::forward<Clauses>(clauses)...)
3731  };
3732 }
3733 
3734 //
3735 // sequence
3736 //
3737 /*!
3738  * @brief A factory function to create a sequence of subclauses
3739  *
3740  * Usage example:
3741  * @code
3742  * produce<std::string>(
3743  * alternatives(
3744  * sequence(symbol('v'), symbol('='), token_p() >> as_result()),
3745  * sequence(symbol('T'), symbol('/'), token_p() >> as_result())
3746  * )
3747  * );
3748  * @endcode
3749  * Please note the usage of sequence() inside the call to
3750  * alternatives().
3751  *
3752  * @tparam Clauses the list of clauses to be used as the sequence.
3753  *
3754  * @since v.0.6.1
3755  */
3756 template< typename... Clauses >
3757 [[nodiscard]]
3758 auto
3759 sequence( Clauses &&... clauses )
3760 {
3761  static_assert( 0 != sizeof...(clauses),
3762  "list of clauses can't be empty" );
3763  static_assert( meta::all_of_v< impl::is_clause, Clauses... >,
3764  "all arguments for sequence() should be clauses" );
3765 
3766  using clause_type_t = impl::sequence_clause_t<
3767  impl::tuple_of_entities_t< Clauses... > >;
3768 
3769  return clause_type_t{
3770  std::make_tuple(std::forward<Clauses>(clauses)...)
3771  };
3772 }
3773 
3774 //
3775 // force_only_this_alternative
3776 //
3777 /*!
3778  * @brief An alternative that should be parsed correctly or the parsing
3779  * of the whole alternatives clause should fail.
3780  *
3781  * This special clause is intended to be used to avoid mistakes in
3782  * grammars like that:
3783 @verbatim
3784 v = "key" '=' token
3785  | token '=' 1*VCHAR
3786 @endverbatim
3787  * If that grammar will be used for parsing a sentence like "key=123" then
3788  * the second alternative will be selected. It's because the parsing
3789  * of rule <tt>"key" '=' token</tt> fails at `123` and the second alternative
3790  * will be tried. And "key" will be recognized as a token.
3791  *
3792  * Before v.0.6.7 this mistake can be avoided by using rules like those:
3793 @verbatim
3794 v = "key" '=' token
3795  | !"key" token '=' 1*VCHAR
3796 @endverbatim
3797  *
3798  * Since v.0.6.7 this mistake can be avoided by using
3799  * force_only_this_alternative() function:
3800  * @code
3801  * alternatives(
3802  * sequence(
3803  * exact("key"),
3804  * force_only_this_alternative(
3805  * symbol('='),
3806  * token() >> skip()
3807  * )
3808  * ),
3809  * sequence(
3810  * token() >> skip(),
3811  * symbol('='),
3812  * repeat(1, N, vchar_symbol_p() >> skip())
3813  * )
3814  * );
3815  * @endcode
3816  *
3817  * @since v.0.6.7
3818  */
3819 template< typename... Clauses >
3820 [[nodiscard]]
3821 auto
3822 force_only_this_alternative( Clauses &&... clauses )
3823 {
3824  static_assert( 0 != sizeof...(clauses),
3825  "list of clauses can't be empty" );
3826  static_assert( meta::all_of_v< impl::is_clause, Clauses... >,
3827  "all arguments for force_only_this_alternative() should "
3828  "be clauses" );
3829 
3830  using clause_type_t = impl::forced_alternative_clause_t<
3831  impl::tuple_of_entities_t< Clauses... > >;
3832 
3833  return clause_type_t{
3834  std::make_tuple(std::forward<Clauses>(clauses)...)
3835  };
3836 }
3837 
3838 //
3839 // repeat
3840 //
3841 /*!
3842  * @brief A factory function to create repetitor of subclauses.
3843  *
3844  * Usage example:
3845  * @code
3846  * using str_pair = std::pair<std::string, std::string>;
3847  * produce<std::vector<str_pair>>(
3848  * produce<str_pair>(
3849  * token_p() >> &str_pair::first,
3850  * symbol('='),
3851  * token_p() >> &str_pair::second
3852  * ) >> to_container(),
3853  * repeat(0, N,
3854  * symbol(','),
3855  * produce<str_pair>(
3856  * token_p() >> &str_pair::first,
3857  * symbol('='),
3858  * token_p() >> &str_pair::second
3859  * ) >> to_container()
3860  * )
3861  * );
3862  * @endcode
3863  * this expression corresponds to the following rule:
3864  @verbatim
3865  T := token '=' token *(',' token '=' token)
3866  @endverbatim
3867  *
3868  * @tparam Clauses the list of clauses to be used as the sequence
3869  * to be repeated.
3870  *
3871  * @since v.0.6.1
3872  */
3873 template<
3874  typename... Clauses >
3875 [[nodiscard]]
3876 auto
3878  //! Minimal occurences of the sequences in the repetition.
3879  std::size_t min_occurences,
3880  //! Maximal occurences of the sequences in the repetition.
3881  /*!
3882  * @note
3883  * The repetition will be stopped when that numer of repetitions
3884  * will be reached.
3885  */
3886  std::size_t max_occurences,
3887  //! The sequence of clauses to be repeated.
3888  Clauses &&... clauses )
3889 {
3890  static_assert( 0 != sizeof...(clauses),
3891  "list of clauses can't be empty" );
3892  static_assert( meta::all_of_v< impl::is_clause, Clauses... >,
3893  "all arguments for repeat() should be clauses" );
3894 
3895  using producer_type_t = impl::repeat_clause_t<
3896  impl::tuple_of_entities_t<Clauses...> >;
3897 
3898  return producer_type_t{
3899  min_occurences,
3900  max_occurences,
3901  std::make_tuple(std::forward<Clauses>(clauses)...)
3902  };
3903 }
3904 
3905 //
3906 // skip
3907 //
3908 /*!
3909  * @brief A factory function to create a skip_consumer.
3910  *
3911  * Usage example:
3912  * @code
3913  * produce<std::string>(
3914  * token_p() >> as_result(),
3915  * not_clause(symbol('='), token_p() >> skip())
3916  * );
3917  * @endcode
3918  *
3919  * @since v.0.6.1
3920  */
3921 [[nodiscard]]
3922 inline auto
3923 skip() noexcept { return impl::any_value_skipper_t{}; }
3924 
3925 //
3926 // any_symbol_p
3927 //
3928 /*!
3929  * @brief A factory function to create an any_symbol_producer.
3930  *
3931  * @return a producer that expects any symbol in the input stream
3932  * and returns it.
3933  *
3934  * @since v.0.6.6
3935  */
3936 [[nodiscard]]
3937 inline auto
3938 any_symbol_p() noexcept
3939 {
3940  return impl::symbol_producer_template_t<impl::any_symbol_predicate_t>{};
3941 }
3942 
3943 //
3944 // symbol_p
3945 //
3946 /*!
3947  * @brief A factory function to create a symbol_producer.
3948  *
3949  * @return a producer that expects @a expected in the input stream
3950  * and returns it if that character is found.
3951  *
3952  * @since v.0.6.1
3953  */
3954 [[nodiscard]]
3955 inline auto
3956 symbol_p( char expected ) noexcept
3957 {
3958  return impl::symbol_producer_t{expected};
3959 }
3960 
3961 //
3962 // any_symbol_if_not_p
3963 //
3964 /*!
3965  * @brief A factory function to create a any_symbol_if_not_producer.
3966  *
3967  * @return a producer that expects any character except @a sentinel in the
3968  * input stream and returns it if that character is found.
3969  *
3970  * @since v.0.6.6
3971  */
3972 [[nodiscard]]
3973 inline auto
3974 any_symbol_if_not_p( char sentinel ) noexcept
3975 {
3976  return impl::any_symbol_if_not_producer_t{sentinel};
3977 }
3978 
3979 //
3980 // caseless_symbol_p
3981 //
3982 /*!
3983  * @brief A factory function to create a caseless_symbol_producer.
3984  *
3985  * This producer performs caseless comparison of characters.
3986  *
3987  * @return a producer that expects @a expected in the input stream
3988  * and returns it if that character is found.
3989  *
3990  * @since v.0.6.6
3991  */
3992 [[nodiscard]]
3993 inline auto
3994 caseless_symbol_p( char expected ) noexcept
3995 {
3996  return impl::caseless_symbol_producer_t{expected};
3997 }
3998 
3999 //
4000 // symbol_from_range_p
4001 //
4002 /*!
4003  * @brief A factory function to create a symbol_from_range_producer.
4004  *
4005  * @return a producer that expects a symbol from `[left, right]` range in the
4006  * input stream and returns it if that character is found.
4007  *
4008  * @since v.0.6.9
4009  */
4010 [[nodiscard]]
4011 inline auto
4012 symbol_from_range_p( char left, char right ) noexcept
4013 {
4014  return impl::symbol_from_range_producer_t{left, right};
4015 }
4016 
4017 //
4018 // symbol
4019 //
4020 /*!
4021  * @brief A factory function to create a clause that expects the
4022  * speficied symbol, extracts it and then skips it.
4023  *
4024  * The call to `symbol('a')` function is an equivalent of:
4025  * @code
4026  * symbol_p('a') >> skip()
4027  * @endcode
4028  *
4029  * @since v.0.6.1
4030  */
4031 [[nodiscard]]
4032 inline auto
4033 symbol( char expected ) noexcept
4034 {
4035  return symbol_p(expected) >> skip();
4036 }
4037 
4038 //
4039 // caseless_symbol
4040 //
4041 /*!
4042  * @brief A factory function to create a clause that expects the
4043  * speficied symbol, extracts it and then skips it.
4044  *
4045  * This clause performs caseless comparison of characters.
4046  *
4047  * The call to `caseless_symbol('a')` function is an equivalent of:
4048  * @code
4049  * caseless_symbol_p('a') >> skip()
4050  * @endcode
4051  *
4052  * @since v.0.6.6
4053  */
4054 [[nodiscard]]
4055 inline auto
4056 caseless_symbol( char expected ) noexcept
4057 {
4058  return caseless_symbol_p(expected) >> skip();
4059 }
4060 
4061 //
4062 // symbol_from_range
4063 //
4064 /*!
4065  * @brief A factory function to create a clause that expects a symbol
4066  * from specified range, extracts it and then skips it.
4067  *
4068  * The call to `symbol_from_range('a', 'z')` function is an equivalent of:
4069  * @code
4070  * symbol_from_range_p('a', 'z') >> skip()
4071  * @endcode
4072  *
4073  * @since v.0.6.9
4074  */
4075 [[nodiscard]]
4076 inline auto
4077 symbol_from_range( char left, char right ) noexcept
4078 {
4079  return symbol_from_range_p(left, right) >> skip();
4080 }
4081 
4082 //
4083 // space_p
4084 //
4085 /*!
4086  * @brief A factory function to create a space_producer.
4087  *
4088  * @return a producer that expects space character in the input stream
4089  * and returns it if that character is found.
4090  *
4091  * @since v.0.6.4
4092  */
4093 [[nodiscard]]
4094 inline auto
4095 space_p() noexcept
4096 {
4097  return impl::symbol_producer_template_t< impl::is_space_predicate_t >{};
4098 }
4099 
4100 //
4101 // space
4102 //
4103 /*!
4104  * @brief A factory function to create a clause that expects a space,
4105  * extracts it and then skips it.
4106  *
4107  * The call to `space()` function is an equivalent of:
4108  * @code
4109  * space_p() >> skip()
4110  * @endcode
4111  *
4112  * @since v.0.6.4
4113  */
4114 [[nodiscard]]
4115 inline auto
4116 space() noexcept
4117 {
4118  return space_p() >> skip();
4119 }
4120 
4121 //
4122 // digit_p
4123 //
4124 /*!
4125  * @brief A factory function to create a digit_producer.
4126  *
4127  * @return a producer that expects a decimal digit in the input stream
4128  * and returns it if a decimal digit is found.
4129  *
4130  * @since v.0.6.1
4131  */
4132 [[nodiscard]]
4133 inline auto
4134 digit_p() noexcept
4135 {
4136  return impl::digit_producer_t{};
4137 }
4138 
4139 //
4140 // digit
4141 //
4142 /*!
4143  * @brief A factory function to create a clause that expects a decimal digit,
4144  * extracts it and then skips it.
4145  *
4146  * The call to `digit()` function is an equivalent of:
4147  * @code
4148  * digit_p() >> skip()
4149  * @endcode
4150  *
4151  * @since v.0.6.6
4152  */
4153 [[nodiscard]]
4154 inline auto
4155 digit() noexcept
4156 {
4157  return digit_p() >> skip();
4158 }
4159 
4160 //
4161 // hexdigit_p
4162 //
4163 /*!
4164  * @brief A factory function to create a hexdigit_producer.
4165  *
4166  * @return a producer that expects a hexadecimal digit in the input stream
4167  * and returns it if a hexadecimal digit is found.
4168  *
4169  * @since v.0.6.6
4170  */
4171 [[nodiscard]]
4172 inline auto
4173 hexdigit_p() noexcept
4174 {
4176 }
4177 
4178 //
4179 // hexdigit
4180 //
4181 /*!
4182  * @brief A factory function to create a clause that expects a hexadecimal
4183  * digit, extracts it and then skips it.
4184  *
4185  * The call to `hexdigit()` function is an equivalent of:
4186  * @code
4187  * hexdigit_p() >> skip()
4188  * @endcode
4189  *
4190  * @since v.0.6.6
4191  */
4192 [[nodiscard]]
4193 inline auto
4194 hexdigit() noexcept
4195 {
4196  return hexdigit_p() >> skip();
4197 }
4198 
4199 //
4200 // non_negative_decimal_number_p
4201 //
4202 /*!
4203  * @brief A factory function to create a non_negative_decimal_number_producer.
4204  *
4205  * @note
4206  * This parser consumes all digits until the first non-digit symbol will
4207  * be found in the input. It means that in the case of `1111someword` the
4208  * first four digits (e.g. `1111`) will be extracted from the input and
4209  * the remaining part (e.g. `someword`) won't be consumed by this parser.
4210  *
4211  * @return a producer that expects a positive decimal number in the input stream
4212  * and returns it if a number is found.
4213  *
4214  * @since v.0.6.2
4215  */
4216 template< typename T >
4217 [[nodiscard]]
4218 inline auto
4220 {
4222 }
4223 
4224 //
4225 // non_negative_decimal_number_p
4226 //
4227 /*!
4228  * @brief A factory function to create a non_negative_decimal_number_producer.
4229  *
4230  * @note
4231  * This parser consumes a number of digits with respect to @a digits_limit.
4232  *
4233  * Usage example:
4234  * @code
4235  * using namespace restinio::easy_parser;
4236  *
4237  * struct compound_number {
4238  * short prefix_;
4239  * int suffix_;
4240  * };
4241  *
4242  * auto parse = produce<compound_number>(
4243  * non_negative_decimal_number_p<short>(expected_digits(2, 5))
4244  * >> &compound_number::prefix_,
4245  * non_negative_decimal_number_p<int>(expected_digits(7, 12))
4246  * >> &compound_number::suffix_
4247  * );
4248  * @endcode
4249  *
4250  * @return a producer that expects a positive decimal number in the input stream
4251  * and returns it if a number is found.
4252  *
4253  * @since v.0.6.2
4254  */
4255 template< typename T >
4256 [[nodiscard]]
4257 inline auto
4259 {
4261  digits_limit
4262  };
4263 }
4264 
4265 //
4266 // hexadecimal_number_p
4267 //
4268 /*!
4269  * @brief A factory function to create a hexadecimal_number_producer.
4270  *
4271  * @note
4272  * This parser consumes all digits until the first non-digit symbol will
4273  * be found in the input. It means that in the case of `1111someword` the
4274  * first four digits (e.g. `1111`) will be extracted from the input and
4275  * the remaining part (e.g. `someword`) won't be consumed by this parser.
4276  *
4277  * @attention
4278  * T should be an unsigned type.
4279  *
4280  * @return a producer that expects a positive hexadecimal number in the input
4281  * stream and returns it if a number is found.
4282  *
4283  * @since v.0.6.6
4284  */
4285 template< typename T >
4286 [[nodiscard]]
4287 inline auto
4289 {
4290  return impl::hexadecimal_number_producer_t<T>{};
4291 }
4292 
4293 //
4294 // hexadecimal_number_p
4295 //
4296 /*!
4297  * @brief A factory function to create a hexadecimal_number_producer.
4298  *
4299  * @note
4300  * This parser consumes a number of digits with respect to @a digits_limit.
4301  *
4302  * Usage example:
4303  * @code
4304  * using namespace restinio::easy_parser;
4305  *
4306  * struct compound_number {
4307  * short prefix_;
4308  * int suffix_;
4309  * };
4310  *
4311  * auto parse = produce<compound_number>(
4312  * hexadecimal_number_p<short>(expected_digits(4))
4313  * >> &compound_number::prefix_,
4314  * hexadecimal_number_p<int>(expected_digits(7, 12))
4315  * >> &compound_number::suffix_
4316  * );
4317  * @endcode
4318  *
4319  * @attention
4320  * T should be an unsigned type.
4321  *
4322  * @return a producer that expects a positive hexadecimal number in the input
4323  * stream and returns it if a number is found.
4324  *
4325  * @since v.0.6.6
4326  */
4327 template< typename T >
4328 [[nodiscard]]
4329 inline auto
4331 {
4333  digits_limit
4334  };
4335 }
4336 
4337 //
4338 // decimal_number_p
4339 //
4340 /*!
4341  * @brief A factory function to create a decimal_number_producer.
4342  *
4343  * Parses numbers in the form:
4344 @verbatim
4345 number := [sign] DIGIT+
4346 sign := '-' | '+'
4347 @endverbatim
4348  *
4349  * @note
4350  * This parser consumes all digits until the first non-digit symbol will be
4351  * found in the input. It means that in the case of `-1111someword` the leading
4352  * minus sign and thefirst four digits (e.g. `-1111`) will be extracted from
4353  * the input and the remaining part (e.g. `someword`) won't be consumed by this
4354  * parser.
4355  *
4356  * @attention
4357  * Can be used only for singed number types (e.g. short, int, long,
4358  * std::int32_t and so on).
4359  *
4360  * @return a producer that expects a decimal number in the input stream
4361  * and returns it if a number is found.
4362  *
4363  * @since v.0.6.6
4364  */
4365 template< typename T >
4366 [[nodiscard]]
4367 inline auto
4369 {
4370  static_assert( std::is_signed<T>::value,
4371  "decimal_number_p() can be used only for signed numeric types" );
4372 
4373  return impl::decimal_number_producer_t<T>{};
4374 }
4375 
4376 //
4377 // decimal_number_p
4378 //
4379 /*!
4380  * @brief A factory function to create a decimal_number_producer.
4381  *
4382  * Parses numbers in the form:
4383 @verbatim
4384 number := [sign] DIGIT+
4385 sign := '-' | '+'
4386 @endverbatim
4387  *
4388  * @note
4389  * This parser consumes a number of digits with respect to @a digits_limit.
4390  * The leading sign (if present) is not added to a number of extracted digits.
4391  *
4392  * Usage example:
4393  * @code
4394  * using namespace restinio::easy_parser;
4395  *
4396  * struct compound_number {
4397  * short prefix_;
4398  * int suffix_;
4399  * };
4400  *
4401  * auto parse = produce<compound_number>(
4402  * decimal_number_p<short>(expected_digits(4))
4403  * >> &compound_number::prefix_,
4404  * decimal_number_p<int>(expected_digits(7, 12))
4405  * >> &compound_number::suffix_
4406  * );
4407  * @endcode
4408  *
4409  * @attention
4410  * Can be used only for singed number types (e.g. short, int, long,
4411  * std::int32_t and so on).
4412  *
4413  * @return a producer that expects a decimal number in the input stream
4414  * and returns it if a number is found.
4415  *
4416  * @since v.0.6.6
4417  */
4418 template< typename T >
4419 [[nodiscard]]
4420 inline auto
4421 decimal_number_p( digits_to_consume_t digits_limit ) noexcept
4422 {
4423  static_assert( std::is_signed<T>::value,
4424  "decimal_number_p() can be used only for signed numeric types" );
4425 
4427  digits_limit
4428  };
4429 }
4430 
4431 //
4432 // as_result
4433 //
4434 /*!
4435  * @brief A factory function to create a as_result_consumer.
4436  *
4437  * Usage example:
4438  * @code
4439  * produce<std::string>(
4440  * symbol('v'),
4441  * symbol('='),
4442  * token_p() >> as_result(),
4443  * symbol('.')
4444  * );
4445  * @endcode
4446  *
4447  * @since v.0.6.1
4448  */
4449 [[nodiscard]]
4450 inline auto
4451 as_result() noexcept { return impl::as_result_consumer_t{}; }
4452 
4453 //
4454 // custom_consumer
4455 //
4456 /*!
4457  * @brief A factory function to create a custom_consumer.
4458  *
4459  * Usage example:
4460  * @code
4461  * class composed_value {
4462  * std::string name_;
4463  * std::string value_;
4464  * public:
4465  * composed_value() = default;
4466  *
4467  * void set_name(std::string name) { name_ = std::move(name); }
4468  * void set_value(std::string value) { value_ = std::move(value); }
4469  * ...
4470  * };
4471  * produce<composed_value>(
4472  * token_p() >> custom_consumer(
4473  * [](composed_value & to, std::string && what) {
4474  * to.set_name(std::move(what));
4475  * } ),
4476  * symbol('='),
4477  * token_p() >> custom_consumer(
4478  * [](composed_value & to, std::string && what) {
4479  * to.set_value(std::move(what));
4480  * } ),
4481  * symbol('.')
4482  * );
4483  * @endcode
4484  *
4485  * @note
4486  * A custom consumer should be a function/lambda/function objects with
4487  * the following prototype:
4488  * @code
4489  * void(Target_Type & destination, Value && value);
4490  * @endcode
4491  *
4492  * @since v.0.6.1
4493  */
4494 template< typename F >
4495 [[nodiscard]]
4496 auto
4497 custom_consumer( F consumer )
4498 {
4499  using actual_consumer_t = impl::custom_consumer_t< F >;
4500 
4501  return actual_consumer_t{ std::move(consumer) };
4502 }
4503 
4504 namespace impl
4505 {
4506 
4507 //
4508 // to_container_consumer_t
4509 //
4510 /*!
4511  * @brief A template for a consumer that stories values into a container.
4512  *
4513  * Instances of such consumer will be used inside repeat_clause_t.
4514  *
4515  * @tparam Container_Adaptor a class that knows how to store a value
4516  * into the target container. See result_value_wrapper for the
4517  * requirement for such type.
4518  *
4519  * @since v.0.6.1
4520  */
4522 {
4523  template< typename Container, typename Item >
4524  void
4525  consume( Container & to, Item && item )
4526  {
4529  }
4530 };
4531 
4532 } /* namespace impl */
4533 
4534 //
4535 // to_container
4536 //
4537 /*!
4538  * @brief A factory function to create a to_container_consumer.
4539  *
4540  * Usage example:
4541  * @code
4542  * using str_pair = std::pair<std::string, std::string>;
4543  * produce<std::vector<str_pair>>(
4544  * produce<str_pair>(
4545  * token_p() >> &str_pair::first,
4546  * symbol('='),
4547  * token_p() >> &str_pair::second
4548  * ) >> to_container(),
4549  * repeat(0, N,
4550  * symbol(','),
4551  * produce<str_pair>(
4552  * token_p() >> &str_pair::first,
4553  * symbol('='),
4554  * token_p() >> &str_pair::second
4555  * ) >> to_container()
4556  * )
4557  * );
4558  * @endcode
4559  *
4560  * @since v.0.6.1
4561  */
4562 [[nodiscard]]
4563 inline auto
4565 {
4566  return impl::to_container_consumer_t();
4567 }
4568 
4569 //
4570 // to_lower
4571 //
4572 /*!
4573  * @brief A factory function to create a to_lower_transformer.
4574  *
4575  * Usage example:
4576  * @code
4577  * produce<std::string>(
4578  * symbol('T'), symbol(':'),
4579  * token_p() >> to_lower() >> as_result()
4580  * );
4581  * ...
4582  * // Since v.0.6.6 to_lower can also be used for a single character.
4583  * produce<char>(
4584  * exact("I="), any_symbol_p() >> to_lower() >> as_result() );
4585  * @endcode
4586  *
4587  * @since v.0.6.1
4588  */
4589 [[nodiscard]]
4590 inline auto
4591 to_lower() noexcept { return impl::to_lower_transformer_proxy_t{}; }
4592 
4593 //
4594 // just
4595 //
4596 /*!
4597  * @brief A special transformer that replaces the produced value by
4598  * a value specified by a user.
4599  *
4600  * Usage example:
4601  * @code
4602  * produce<unsigned int>(
4603  * alternatives(
4604  * symbol('b') >> just(1u) >> as_result(),
4605  * symbol('k') >> just(1024u) >> as_result(),
4606  * symbol('m') >> just(1024u*1024u) >> as_result()
4607  * )
4608  * );
4609  * @endcode
4610  *
4611  * @since v.0.6.6
4612  */
4613 template< typename T >
4614 [[nodiscard]]
4615 auto
4616 just( T value ) noexcept(noexcept(impl::just_value_transformer_t<T>{value}))
4617 {
4618  return impl::just_value_transformer_t<T>{value};
4619 }
4620 
4621 //
4622 // just_result
4623 //
4624 /*!
4625  * @brief A special consumer that replaces the produced value by
4626  * a value specified by a user and sets that user-specified value
4627  * as the result.
4628  *
4629  * Usage example:
4630  * @code
4631  * produce<unsigned int>(
4632  * alternatives(
4633  * symbol('b') >> just_result(1u),
4634  * symbol('k') >> just_result(1024u),
4635  * symbol('m') >> just_result(1024u*1024u)
4636  * )
4637  * );
4638  * @endcode
4639  *
4640  * @since v.0.6.6
4641  */
4642 template< typename T >
4643 [[nodiscard]]
4644 auto
4645 just_result( T value )
4646  noexcept(noexcept(impl::just_result_consumer_t<T>{value}))
4647 {
4648  return impl::just_result_consumer_t<T>{value};
4649 }
4650 
4651 //
4652 // convert
4653 //
4654 /*!
4655  * @brief A factory function to create convert_transformer.
4656  *
4657  * Usage example:
4658  * @code
4659  * // Parser for:
4660  * // size := DIGIT+ [multiplier]
4661  * // multiplier := ('b'|'B') | ('k'|'K') | ('m'|'M')
4662  * struct tmp_size { std::uint32_t c_{1u}; std::uint32_t m_{1u}; };
4663  * auto size_producer = produce<std::uint64_t>(
4664  * produce<tmp_size>(
4665  * non_negative_decimal_number_p<std::uint32_t>() >> &tmp_size::c_,
4666  * maybe(
4667  * produce<std::uint32_t>(
4668  * alternatives(
4669  * caseless_symbol_p('b') >> just_result(1u),
4670  * caseless_symbol_p('k') >> just_result(1024u),
4671  * caseless_symbol_p('m') >> just_result(1024u*1024u)
4672  * )
4673  * ) >> &tmp_size::m_
4674  * )
4675  * )
4676  * >> convert( [](const tmp_size & ts) { return std::uint64_t{ts.c_} * ts.m_; } )
4677  * >> as_result()
4678  * );
4679  * @endcode
4680  *
4681  * @note
4682  * Since v.0.6.11 a conversion function can have two formats. The first one is:
4683  * @code
4684  * result_type fn(input_type source_val);
4685  * @endcode
4686  * for example:
4687  * @code
4688  * convert([](const std::string & from) -> int {...})
4689  * @endcode
4690  * in that case a conversion error can only be reported via an exception.
4691  * The second one is:
4692  * @code
4693  * expected_t<result_type, error_reason_t> fn(input_type source_val);
4694  * @endcode
4695  * for example:
4696  * @code
4697  * convert([](const std::string & from) -> expected_t<int, error_reason_t> {...})
4698  * @endcode
4699  * in that case a converion error can be reported also via returning value.
4700  * For example, let's assume that in the code snippet shown above the result
4701  * value should be greater than 0. It can be checked in the conversion
4702  * function that way:
4703  * @code
4704  * convert([](const tmp_size & ts) -> expected_t<std::uint64_t, error_reason_t> {
4705  * const auto r = std::uint64_t{ts.c_} * ts.m_;
4706  * if( r )
4707  * return r;
4708  * else
4709  * return make_unexpected(error_reason_t::illegal_value_found);
4710  * }
4711  * @endcode
4712  *
4713  * @since v.0.6.6
4714  */
4715 template< typename Converter >
4716 [[nodiscard]]
4717 auto
4718 convert( Converter && converter )
4719 {
4720  using converter_type = std::decay_t<Converter>;
4721 
4722  using transformer_proxy_type = impl::convert_transformer_proxy_t<
4723  converter_type >;
4724 
4725  return transformer_proxy_type{ std::forward<Converter>(converter) };
4726 }
4727 
4728 //
4729 // exact_p
4730 //
4731 /*!
4732  * @brief A factory function that creates an instance of
4733  * exact_fragment_producer.
4734  *
4735  * Usage example:
4736  * @code
4737  * produce<std::string>(
4738  * alternatives(
4739  * exact_p("pro") >> just_result("Professional"),
4740  * exact_p("con") >> just_result("Consumer")
4741  * )
4742  * );
4743  * @endcode
4744  *
4745  * @since v.0.6.6
4746  */
4747 [[nodiscard]]
4748 inline auto
4749 exact_p( string_view_t fragment )
4750 {
4751  return impl::exact_fragment_producer_t{
4752  std::string{ fragment.data(), fragment.size() }
4753  };
4754 }
4755 
4756 /*!
4757  * @brief A factory function that creates an instance of
4758  * exact_fragment_producer.
4759  *
4760  * Usage example:
4761  * @code
4762  * produce<std::string>(
4763  * alternatives(
4764  * exact_p("pro") >> just_result("Professional"),
4765  * exact_p("con") >> just_result("Consumer")
4766  * )
4767  * );
4768  * @endcode
4769  *
4770  * @attention
4771  * This version is dedicated to be used with string literals.
4772  * Because of that the last byte from a literal will be ignored (it's
4773  * assumed that this byte contains zero).
4774  * But this behavior would lead to unexpected results in such cases:
4775  * @code
4776  * const char prefix[]{ 'h', 'e', 'l', 'l', 'o' };
4777  *
4778  * produce<std::string>(exact_p(prefix) >> just_result("Hi!"));
4779  * @endcode
4780  * because the last byte with value 'o' will be ignored by
4781  * exact_producer. To avoid such behavior string_view_t should be
4782  * used explicitely:
4783  * @code
4784  * produce<std::string>(exact_p(string_view_t{prefix})
4785  * >> just_result("Hi!"));
4786  * @endcode
4787  *
4788  * @since v.0.6.6
4789  */
4790 template< std::size_t Size >
4791 [[nodiscard]]
4792 auto
4793 exact_p( const char (&fragment)[Size] )
4794 {
4795  return impl::exact_fixed_size_fragment_producer_t<Size>{ fragment };
4796 }
4797 
4798 //
4799 // exact
4800 //
4801 /*!
4802  * @brief A factory function that creates an instance of
4803  * exact_fragment clause.
4804  *
4805  * Usage example:
4806  * @code
4807  * produce<std::string>(exact("version="), token() >> as_result());
4808  * @endcode
4809  *
4810  * @since v.0.6.6
4811  */
4812 [[nodiscard]]
4813 inline auto
4814 exact( string_view_t fragment )
4815 {
4816  return impl::exact_fragment_producer_t{
4817  std::string{ fragment.data(), fragment.size() }
4818  } >> skip();
4819 }
4820 
4821 /*!
4822  * @brief A factory function that creates an instance of
4823  * exact_fragment clause.
4824  *
4825  * Usage example:
4826  * @code
4827  * produce<std::string>(exact("version="), token() >> as_result());
4828  * @endcode
4829  *
4830  * @attention
4831  * This version is dedicated to be used with string literals.
4832  * Because of that the last byte from a literal will be ignored (it's
4833  * assumed that this byte contains zero).
4834  * But this behavior would lead to unexpected results in such cases:
4835  * @code
4836  * const char prefix[]{ 'v', 'e', 'r', 's', 'i', 'o', 'n', '=' };
4837  *
4838  * produce<std::string>(exact(prefix), token() >> as_result());
4839  * @endcode
4840  * because the last byte with value '=' will be ignored by
4841  * exact_producer. To avoid such behavior string_view_t should be
4842  * used explicitely:
4843  * @code
4844  * produce<std::string>(exact(string_view_t{prefix}), token() >> as_result());
4845  * @endcode
4846  *
4847  * @since v.0.6.6
4848  */
4849 template< std::size_t Size >
4850 [[nodiscard]]
4851 auto
4852 exact( const char (&fragment)[Size] )
4853 {
4854  return impl::exact_fixed_size_fragment_producer_t<Size>{ fragment } >> skip();
4855 }
4856 
4857 //
4858 // caseless_exact_p
4859 //
4860 /*!
4861  * @brief A factory function that creates an instance of
4862  * caseless_exact_fragment_producer.
4863  *
4864  * Usage example:
4865  * @code
4866  * produce<std::string>(
4867  * alternatives(
4868  * caseless_exact_p("pro") >> just_result("Professional"),
4869  * caseless_exact_p("con") >> just_result("Consumer")
4870  * )
4871  * );
4872  * @endcode
4873  *
4874  * @since v.0.6.9
4875  */
4876 [[nodiscard]]
4877 inline auto
4878 caseless_exact_p( string_view_t fragment )
4879 {
4880  return impl::caseless_exact_fragment_producer_t{
4881  std::string{ fragment.data(), fragment.size() }
4882  };
4883 }
4884 
4885 /*!
4886  * @brief A factory function that creates an instance of
4887  * caseless_exact_fragment_producer.
4888  *
4889  * Usage example:
4890  * @code
4891  * produce<std::string>(
4892  * alternatives(
4893  * caseless_exact_p("pro") >> just_result("Professional"),
4894  * caseless_exact_p("con") >> just_result("Consumer")
4895  * )
4896  * );
4897  * @endcode
4898  *
4899  * @attention
4900  * This version is dedicated to be used with string literals.
4901  * Because of that the last byte from a literal will be ignored (it's
4902  * assumed that this byte contains zero).
4903  * But this behavior would lead to unexpected results in such cases:
4904  * @code
4905  * const char prefix[]{ 'h', 'e', 'l', 'l', 'o' };
4906  *
4907  * produce<std::string>(caseless_exact_p(prefix) >> just_result("Hi!"));
4908  * @endcode
4909  * because the last byte with value 'o' will be ignored by
4910  * exact_producer. To avoid such behavior string_view_t should be
4911  * used explicitely:
4912  * @code
4913  * produce<std::string>(caseless_exact_p(string_view_t{prefix})
4914  * >> just_result("Hi!"));
4915  * @endcode
4916  *
4917  * @since v.0.6.9
4918  */
4919 template< std::size_t Size >
4920 [[nodiscard]]
4921 auto
4922 caseless_exact_p( const char (&fragment)[Size] )
4923 {
4924  return impl::caseless_exact_fixed_size_fragment_producer_t<Size>{ fragment };
4925 }
4926 
4927 //
4928 // caseless_exact
4929 //
4930 /*!
4931  * @brief A factory function that creates an instance of
4932  * caseless_exact_fragment clause.
4933  *
4934  * Usage example:
4935  * @code
4936  * produce<std::string>(caseless_exact("version="), token() >> as_result());
4937  * @endcode
4938  *
4939  * @since v.0.6.9
4940  */
4941 [[nodiscard]]
4942 inline auto
4943 caseless_exact( string_view_t fragment )
4944 {
4945  return impl::caseless_exact_fragment_producer_t{
4946  std::string{ fragment.data(), fragment.size() }
4947  } >> skip();
4948 }
4949 
4950 /*!
4951  * @brief A factory function that creates an instance of
4952  * caseless_exact_fragment clause.
4953  *
4954  * Usage example:
4955  * @code
4956  * produce<std::string>(caseless_exact("version="), token() >> as_result());
4957  * @endcode
4958  *
4959  * @attention
4960  * This version is dedicated to be used with string literals.
4961  * Because of that the last byte from a literal will be ignored (it's
4962  * assumed that this byte contains zero).
4963  * But this behavior would lead to unexpected results in such cases:
4964  * @code
4965  * const char prefix[]{ 'v', 'e', 'r', 's', 'i', 'o', 'n', '=' };
4966  *
4967  * produce<std::string>(caseless_exact(prefix), token() >> as_result());
4968  * @endcode
4969  * because the last byte with value '=' will be ignored by
4970  * exact_producer. To avoid such behavior string_view_t should be
4971  * used explicitely:
4972  * @code
4973  * produce<std::string>(caseless_exact(string_view_t{prefix}), token() >> as_result());
4974  * @endcode
4975  *
4976  * @since v.0.6.9
4977  */
4978 template< std::size_t Size >
4979 [[nodiscard]]
4980 auto
4981 caseless_exact( const char (&fragment)[Size] )
4982 {
4983  return impl::caseless_exact_fixed_size_fragment_producer_t<Size>{ fragment } >> skip();
4984 }
4985 
4986 //
4987 // try_parse
4988 //
4989 /*!
4990  * @brief Perform the parsing of the specified content by using
4991  * specified value producer.
4992  *
4993  * @note
4994  * The whole content of @a from should be consumed. There can be
4995  * whitespace remaining in @from after the return from
4996  * Producer::try_parser. But if there will be some non-whitespace
4997  * symbol the failure will be reported.
4998  * (As a side note: since v.0.6.7 all trailing spaces are removed
4999  * from @from before the parsing starts.)
5000  *
5001  * Usage example
5002  * @code
5003  * const auto tokens = try_parse(
5004  * "first,Second;Third;Four",
5005  * produce<std::vector<std::string>>(
5006  * token_p() >> to_lower() >> to_container(),
5007  * repeat( 0, N,
5008  * alternatives(symbol(','), symbol(';')),
5009  * token_p() >> to_lower() >> to_container()
5010  * )
5011  * )
5012  * );
5013  * if(tokens)
5014  * for(const auto & v: *tokens)
5015  * std::cout << v << std::endl;
5016  * @endcode
5017  *
5018  * @since v.0.6.1
5019  */
5020 template< typename Producer >
5021 [[nodiscard]]
5025  Producer producer )
5026 {
5027  static_assert( impl::is_producer_v<Producer>,
5028  "Producer should be a value producer type" );
5029 
5031  impl::source_t source{ from };
5032 
5034  .try_process( source );
5035 
5036  if( result )
5037  {
5038  // We should ensure that all content has been consumed.
5039  const auto all_content_check =
5041  if( all_content_check )
5043  }
5044 
5045  return result;
5046 }
5047 
5048 //
5049 // make_error_description
5050 //
5051 /*!
5052  * @brief Make textual description of error returned by try_parse function.
5053  *
5054  * @note
5055  * The format of textual description is not specified and can be changed
5056  * in some future versions without notice.
5057  *
5058  * Usage example:
5059  * @code
5060  * const char * content = "first,Second;Third;Four";
5061  * const auto tokens = try_parse(
5062  * content,
5063  * produce<std::vector<std::string>>(
5064  * token_p() >> to_lower() >> to_container(),
5065  * repeat( 0, N,
5066  * alternatives(symbol(','), symbol(';')),
5067  * token_p() >> to_lower() >> to_container()
5068  * )
5069  * )
5070  * );
5071  * if(tokens)
5072  * {
5073  * for(const auto & v: *tokens)
5074  * std::cout << v << std::endl;
5075  * }
5076  * else
5077  * std::cerr << make_error_description(tokens.error(), content) << std::endl;
5078  * @endcode
5079  *
5080  * @since v.0.6.1
5081  */
5082 [[nodiscard]]
5083 inline std::string
5085  const parse_error_t & error,
5087 {
5088  const auto append_quote = [&]( std::string & dest ) {
5089  constexpr std::size_t max_quote_size = 16u;
5090  if( error.position() > 0u )
5091  {
5092  // How many chars we can get from right of error position?
5093  const auto prefix_size = error.position() > max_quote_size ?
5094  max_quote_size : error.position();
5095 
5096  dest.append( 1u, '"' );
5097  dest.append(
5098  &from[ error.position() ] - prefix_size,
5099  prefix_size );
5100  dest.append( "\" >>> " );
5101  }
5102 
5103  const char problematic_symbol = error.position() < from.size() ?
5104  from[ error.position() ] : '?';
5105  dest.append( 1u, '\'' );
5106  if( problematic_symbol >= '\x00' && problematic_symbol < ' ' )
5107  {
5108  constexpr char hex_digits[] = "0123456789abcdef";
5109 
5110  dest.append( "\\x" );
5111  dest.append( 1u, hex_digits[
5112  static_cast<unsigned char>(problematic_symbol) >> 4 ] );
5113  dest.append( 1u, hex_digits[
5114  static_cast<unsigned char>(problematic_symbol) & 0xfu ] );
5115  }
5116  else
5117  dest.append( 1u, problematic_symbol );
5118 
5119  dest.append( 1u, '\'' );
5120 
5121  if( error.position() + 1u < from.size() )
5122  {
5123  // How many chars we can get from the right of error position?
5124  const auto suffix_size =
5125  error.position() + 1u + max_quote_size < from.size() ?
5126  max_quote_size : from.size() - error.position() - 1u;
5127 
5128  dest.append( " <<< \"" );
5129  dest.append( &from[ error.position() + 1u ], suffix_size );
5130  dest.append( 1u, '"' );
5131  }
5132  };
5133 
5134  std::string result;
5135 
5136  const auto basic_reaction = [&](const char * msg) {
5137  result += msg;
5138  result += " at ";
5139  result += std::to_string( error.position() );
5140  result += ": ";
5141  append_quote( result );
5142  };
5143 
5144  switch( error.reason() )
5145  {
5147  basic_reaction( "unexpected character" );
5148  break;
5149 
5150  case error_reason_t::unexpected_eof:
5151  result += "unexpected EOF at ";
5152  result += std::to_string( error.position() );
5153  break;
5154 
5156  basic_reaction( "appropriate alternative can't found" );
5157  break;
5158 
5160  basic_reaction( "expected pattern is not found" );
5161  break;
5162 
5164  basic_reaction( "unconsumed input found" );
5165  break;
5166 
5168  basic_reaction( "some illegal value found" );
5169  break;
5170 
5172  basic_reaction( "forced selection alternative failed" );
5173  break;
5174  }
5175 
5176  return result;
5177 }
5178 
5179 } /* namespace easy_parser */
5180 
5181 } /* namespace restinio */
expected_t< bool, parse_error_t > try_parse(source_t &from)
expected_t< T, parse_error_t > try_parse(source_t &from) const noexcept
auto exact_p(const char(&fragment)[Size])
A factory function that creates an instance of exact_fragment_producer.
Unexpected end of input is encontered when some character expected.
expected_t< bool, parse_error_t > try_parse(source_t &from)
A producer for the case when a decimal digit is expected in the input stream.
A special base class to be used with consumers.
A helper template for calling transformation function.
expected_t< T, parse_error_t > try_parse_digits_with_digits_limit(source_t &from, digits_to_consume_t digits_limit, Value_Accumulator acc) noexcept
Helper function for parsing integers with respect to the number of digits to be consumed.
auto operator>>(P producer, T transformer_proxy)
A special operator to connect a value producer with value transformer via transformer-proxy.
std::optional< parse_error_t > try_process(source_t &from, Target_Type &)
expected_t< bool, parse_error_t > try_parse(source_t &from)
A producer for the case when a number in hexadecimal form is expected in the input stream...
void consume(Target_Type &dest, Value &&src) const noexcept(noexcept(m_consumer(dest, std::forward< Value >(src))))
A helper template for the detection of type to be produced as conversion procedure.
error_reason_t
Reason of parsing error.
Definition: easy_parser.hpp:52
A predicate for cases where char to be expected to be a decimal digit.
constexpr bool operator()(const char) const noexcept
A producer that expects a fragment in the input and produces boolean value if that fragment is found...
bool operator()(const char actual) const noexcept
std::string make_error_description(const parse_error_t &error, string_view_t from)
Make textual description of error returned by try_parse function.
repeat_clause_t(std::size_t min_occurences, std::size_t max_occurences, Subitems_Tuple &&subitems)
A producer for the case when a particual character is expected in the input stream.
A producer for the case when any character except the specific sentinel character is expected in the ...
A producer for the case when a symbol should belong to specified range.
A special base class to be used with transformers.
auto just(T value) noexcept(noexcept(impl::just_value_transformer_t< T >{value}))
A special transformer that replaces the produced value by a value specified by a user.
auto maybe(Clauses &&... clauses)
A factory function to create an optional clause.
constexpr digits_to_consume_t(underlying_int_t total) noexcept
A template for producer of charachers that satisfy some predicate.
auto as_result() noexcept
A factory function to create a as_result_consumer.
std::size_t m_position
Position in the input stream.
Definition: easy_parser.hpp:96
A template with specializations for different kind of result values and for type nothing.
std::optional< parse_error_t > try_process(source_t &from, Target_Type &target)
underlying_int_t m_max
Maximal number of digits to consume.
Required pattern is not found in the input.
auto convert(Converter &&converter)
A factory function to create convert_transformer.
A special wrapper for std::array type to be used inside a producer during the parsing.
expected_t< bool, parse_error_t > try_parse_exact_fragment(source_t &from, It begin, It end)
One character extracted from the input stream.
static constexpr entity_type_t entity_type
static constexpr entity_type_t entity_type
A metafunction that checks is Result_Type can be used as the result of transformation method...
auto decimal_number_p(digits_to_consume_t digits_limit) noexcept
A factory function to create a decimal_number_producer.
auto decimal_number_p() noexcept
A factory function to create a decimal_number_producer.
auto and_clause(Clauses &&... clauses)
A factory function to create an and_clause.
A predicate for cases where char to be expected to be a hexadecimal digit.
content_consumer_t(const content_consumer_t &)=delete
auto hexdigit() noexcept
A factory function to create a clause that expects a hexadecimal digit, extracts it and then skips it...
try_parse_result_type try_parse_impl(source_t &from, Digits_Limit_Maker &&digits_limit_maker) const noexcept
bool operator!=(const character_t &a, const character_t &b) noexcept
constexpr digits_to_consume_t(underlying_int_t min, underlying_int_t max) noexcept
auto any_symbol_p() noexcept
A factory function to create an any_symbol_producer.
string_view_t remove_trailing_spaces(string_view_t from) noexcept
Helper function for removal of trailing spaces from a string-view.
std::optional< parse_error_t > try_process(source_t &from, Target_Type &target)
constexpr bool is_clause_v
A meta-value to check whether T is a consumer type.
Entity is a transformer of a value from one type to another.
static result_type && unwrap_value(wrapped_type &v)
void consume(Target_Type &dest, Value &&) const
None of alternatives was found in the input.
A predicate for cases where a symbol should belong to specified range.
A producer for the case when a signed decimal number is expected in the input stream.
A preducate for symbol_producer_template that checks that a symbol is a space.
A template for implementation of clause that checks and handles presence of sequence of entities in t...
auto space() noexcept
A factory function to create a clause that expects a space, extracts it and then skips it...
A transformator that uses a user supplied function/functor for conversion a value from one type to an...
Entity is a transformer-proxy. It can&#39;t be used directly, only for binding a producer and transformer...
A template for implementation of clause that checks and handles presence of optional entity in the in...
A producer for the case when a number in hexadecimal form is expected in the input stream...
static constexpr entity_type_t entity_type
auto not_clause(Clauses &&... clauses)
A factory function to create a not_clause.
static constexpr auto from_one_to_max() noexcept
Unexpected character is found in the input.
auto non_negative_decimal_number_p() noexcept
A factory function to create a non_negative_decimal_number_producer.
auto alternatives(Clauses &&... clauses)
A factory function to create an alternatives clause.
string_view_t fragment(string_view_t::size_type from, string_view_t::size_type length=string_view_t::npos) const noexcept
Return a fragment from the input stream.
bool operator()(const char actual) const noexcept
auto symbol_from_range_p(char left, char right) noexcept
A factory function to create a symbol_from_range_producer.
A helper template for checking a possibility to connect a producer with a transformer.
A predicate that allows extraction of any symbol.
auto make_transformer() const &noexcept(noexcept(Converter{m_converter}))
A producer for the case when a hexadecimal digit is expected in the input stream. ...
static constexpr auto unlimited_max() noexcept
Get the value that means that maximum is not limited.
A consumer for the case when a specific value should be used as the result instead of the value produ...
A template for a consumer that stories values into a container.
std::enable_if< std::is_same< Parameter_Container, query_string_params_t >::value||std::is_same< Parameter_Container, router::route_params_t >::value, std::optional< Value_Type > >::type opt_value(const Parameter_Container &params, string_view_t key)
Gets the value of a parameter specified by key wrapped in std::optional<Value_Type> if parameter exis...
Definition: value_or.hpp:64
just_result_consumer_t(Result_Arg &&result) noexcept(noexcept(Result_Type{std::forward< Result_Arg >(result)}))
not_clause_t(Subitems_Tuple &&subitems)
expected_t< Target_Type, parse_error_t > try_parse(source_t &from)
static void as_result(wrapped_type &to, result_type &&what)
auto to_lower() noexcept
A factory function to create a to_lower_transformer.
auto non_negative_decimal_number_p(digits_to_consume_t digits_limit) noexcept
A factory function to create a non_negative_decimal_number_producer.
A consumer that stores a result value at the specified index in the result tuple. ...
expected_t< char, parse_error_t > try_parse(source_t &from) const noexcept
constexpr std::size_t N
A special marker that means infinite repetitions.
A template of producer that gets a value from another producer, transforms it and produces transforme...
A transformer that skips incoming value and returns a value specified by a user.
maybe_clause_t(Subitems_Tuple &&subitems)
constexpr bool is_hexdigit(const char ch) noexcept
Is a character a hexadecimal digit?
expected_t< T, parse_error_t > try_parse(source_t &from) const noexcept
auto caseless_exact(string_view_t fragment)
A factory function that creates an instance of caseless_exact_fragment clause.
std::optional< parse_error_t > try_process(source_t &from, Target_Type &target)
A proxy for the creation of convert_transformer instances for a specific value producers.
auto caseless_symbol(char expected) noexcept
A factory function to create a clause that expects the speficied symbol, extracts it and then skips i...
auto exact(string_view_t fragment)
A factory function that creates an instance of exact_fragment clause.
constexpr digits_to_consume_t expected_digits(digits_to_consume_t::underlying_int_t total) noexcept
Create a limit for number of digits to be extracted.
bool operator()(const char actual) const noexcept
and_clause_t(Subitems_Tuple &&subitems)
static try_parse_result_type try_parse_with_this_first_symbol(source_t &from, char first_symbol, Digits_Limit_Maker &&digits_limit_maker) noexcept
void putback() noexcept
Return one character back to the input stream.
void consume(Target_Type &dest, Value &&src) const
auto caseless_exact_p(const char(&fragment)[Size])
A factory function that creates an instance of caseless_exact_fragment_producer.
A producer that expects a fragment in the input and produces boolean value if that fragment is found...
A template for producing a value of specific type of a sequence of entities from the input stream...
A helper class to automatically return acquired content back to the input stream. ...
std::size_t position() const noexcept
Get the position in the input stream where error was detected.
constexpr auto max() const noexcept
Get the maximum value.
expected_t< bool, parse_error_t > try_parse_caseless_exact_fragment(source_t &from, It begin, It end)
An alternative that should be parsed correctly or the parsing of the whole alternatives clause should...
character_t getch() noexcept
Get the next character from the input stream.
Entity is a consumer of values. It requires a value on the input and doesn&#39;t produces anything...
expected_t< typename Producer::result_type, parse_error_t > try_parse(string_view_t from, Producer producer)
Perform the parsing of the specified content by using specified value producer.
std::enable_if_t< is_producer_v< P >, consume_value_clause_t< P, field_setter_consumer_t< F, C > > > operator>>(P producer, F C::*member_ptr)
A special operator to connect a value producer with field_setter_consumer.
constexpr bool is_transformer_proxy_v
A meta-value to check whether T is a transformer-proxy type.
constexpr bool is_digit(const char ch) noexcept
Is a character a decimal digit?
auto caseless_exact_p(string_view_t fragment)
A factory function that creates an instance of caseless_exact_fragment_producer.
error_reason_t reason() const noexcept
Get the reason of the error.
A producer that expects a fragment in the input and produces boolean value if that fragment is found...
A predicate for cases where the case-insensitive match of expected and actual symbols is required...
just_value_transformer_t(T v) noexcept(noexcept(T{std::move(v)}))
auto produce(Clauses &&... clauses)
A factory function to create a producer that creates an instance of the target type by using specifie...
auto sequence(Clauses &&... clauses)
A factory function to create a sequence of subclauses.
auto exact(const char(&fragment)[Size])
A factory function that creates an instance of exact_fragment clause.
auto make_transformer() &&noexcept(noexcept(Converter{std::move(m_converter)}))
auto symbol_from_range(char left, char right) noexcept
A factory function to create a clause that expects a symbol from specified range, extracts it and the...
A template for implementation of clause that selects one of alternative clauses.
A template for implementation of clause that checks the presence of some entity in the input stream...
A producer that expects a fragment in the input and produces boolean value if that fragment is found...
expected_t< T, parse_error_t > try_parse(source_t &from) const noexcept
base_type::result_type transform(input_type &&input) const noexcept
constexpr auto min() const noexcept
Get the minimal value.
A special consumer that simply throws any value away.
constexpr bool is_transformer_v
A meta-value to check whether T is a transformer type.
const string_view_t m_data
The content to be used as "input stream".
static result_type && unwrap_value(wrapped_type &v)
bool eof() const noexcept
Is EOF has been reached?
expected_t< result_type, parse_error_t > try_parse(source_t &source)
Entity is a clause. It doesn&#39;t produces anything.
There are some unconsumed non-whitespace characters in the input after the completion of parsing...
auto transform(Input &&input) const noexcept(noexcept(m_converter(std::forward< Input >(input))))
Performs the transformation by calling the converter.
constexpr bool is_space(const char ch) noexcept
If a character a space character?
transformed_value_producer_t(Producer &&producer, Transformer &&transformer)
result_type transform(input_type &&input) const noexcept
auto repeat(std::size_t min_occurences, std::size_t max_occurences, Clauses &&... clauses)
A factory function to create repetitor of subclauses.
produce_t(Subitems_Tuple &&subitems)
constexpr char HTAB
A constant for Horizontal Tab value.
A failure of parsing an alternative marked as "force only this alternative".
std::enable_if_t< is_producer_v< P > &&is_consumer_v< C >, consume_value_clause_t< P, C > > operator>>(P producer, C consumer)
A special operator to connect a value producer with a value consumer.
void consume(Target_Type &, Value &&) const noexcept
A template for consumers that store a value to the specified field of a target object.
A special class to be used as the top level clause in parser.
auto digit() noexcept
A factory function to create a clause that expects a decimal digit, extracts it and then skips it...
A consumer for the case when the current value should be returned as the result for the producer at o...
A special base class to be used with clauses.
auto symbol_p(char expected) noexcept
A factory function to create a symbol_producer.
auto caseless_exact(const char(&fragment)[Size])
A factory function that creates an instance of caseless_exact_fragment clause.
bool operator()(const char actual) const noexcept
std::optional< parse_error_t > try_process(source_t &from, Target_Type &target)
auto symbol(char expected) noexcept
A factory function to create a clause that expects the speficied symbol, extracts it and then skips i...
The class that implements "input stream".
void commit() noexcept
Consume all acquired content.
std::optional< parse_error_t > try_process(source_t &from, Target_Type &target)
auto just_result(T value) noexcept(noexcept(impl::just_result_consumer_t< T >{value}))
A special consumer that replaces the produced value by a value specified by a user and sets that user...
static void to_container(wrapped_type &, value_type &&) noexcept
Limits for number of digits to be extracted during parsing of decimal numbers.
auto custom_consumer(F consumer)
A factory function to create a custom_consumer.
auto hexadecimal_number_p() noexcept
A factory function to create a hexadecimal_number_producer.
Information about parsing error.
Definition: easy_parser.hpp:93
void consume(Target_Type &&to, Value &&value)
A special base class to be used with producers.
static Result_Type invoke(source_t &, Transformer &transformer, expected_t< Input_Type, parse_error_t > &&input)
source_t(string_view_t data) noexcept
Initializing constructor.
expected_t< bool, parse_error_t > try_parse(source_t &from)
underlying_int_t m_min
Minimal number of digits to consume.
auto exact_p(string_view_t fragment)
A factory function that creates an instance of exact_fragment_producer.
try_parse_result_type try_parse(source_t &from) const noexcept
convert_transformer_t(Convert_Arg &&converter) noexcept(noexcept(Converter{std::forward< Convert_Arg >(converter)}))
void consume(C &to, F &&value) const noexcept(noexcept(to.*m_ptr=std::move(value)))
A template for handling repetition of clauses.
string_view_t::size_type m_index
The current position in the input stream.
static constexpr entity_type_t entity_type
constexpr digits_to_consume_t expected_digits(digits_to_consume_t::underlying_int_t min, digits_to_consume_t::underlying_int_t max) noexcept
Create a limit for number of digits to be extracted.
constexpr bool is_consumer_v
A meta-value to check whether T is a consumer type.
A special base class to be used with transformer-proxies.
parse_error_t(std::size_t position, error_reason_t reason) noexcept
Initializing constructor.
bool operator()(const char actual) const noexcept
std::optional< parse_error_t > try_process(source_t &from, Target_Type &)
auto skip() noexcept
A factory function to create a skip_consumer.
Result_Type make_copy_of_result() const noexcept(noexcept(Result_Type{m_result}))
static void as_result(wrapped_type &, result_type &&) noexcept
std::optional< parse_error_t > try_process(source_t &from, Target_Type &dest)
auto caseless_symbol_p(char expected) noexcept
A factory function to create a caseless_symbol_producer.
A producer for the case when a non-negative decimal number is expected in the input stream...
A predicate for cases where exact match of expected and actual symbols is required.
T transform(Input &&) const noexcept(noexcept(T{m_value}))
auto hexdigit_p() noexcept
A factory function to create a hexdigit_producer.
auto space_p() noexcept
A factory function to create a space_producer.
expected_t< T, parse_error_t > try_parse_hexdigits_with_digits_limit(source_t &from, digits_to_consume_t digits_limit, Value_Accumulator acc) noexcept
Helper function for parsing integers in hexadecimal form.
A producer for the case when a particual character is expected in the input stream.
A template for implementation of clause that checks absence of some entity in the input stream...
A template for a clause that binds a value producer with value consumer.
position_t current_position() const noexcept
Get the current position in the stream.
constexpr char SP
A constant for SPACE value.
A producer for the case when a non-negative decimal number is expected in the input stream...
auto force_only_this_alternative(Clauses &&... clauses)
An alternative that should be parsed correctly or the parsing of the whole alternatives clause should...
A template for consumers that are released by lambda/functional objects.
A special type to be used in the case where there is no need to store produced value.
entity_type_t
A marker for distinguish different kind of entities in parser.
error_reason_t m_reason
The reason of the error.
Definition: easy_parser.hpp:98
A proxy for the creation of an appropriate to_lower_transformer.
A predicate for cases where mismatch with a particular symbol is required.
auto hexadecimal_number_p(digits_to_consume_t digits_limit) noexcept
A factory function to create a hexadecimal_number_producer.
bool operator==(const character_t &a, const character_t &b) noexcept
A metafunction for detection of actual result_value_wrapper type for T.
auto to_container()
A factory function to create a to_container_consumer.
auto digit_p() noexcept
A factory function to create a digit_producer.
void backto(position_t pos) noexcept
Return the current position in the input stream at the specified position.
auto any_symbol_if_not_p(char sentinel) noexcept
A factory function to create a any_symbol_if_not_producer.
std::optional< parse_error_t > ensure_no_remaining_content(source_t &from)
A special function to check that there is no more actual data in the input stream except whitespaces...
constexpr bool is_producer_v
A meta-value to check whether T is a producer type.
convert_transformer_proxy_t(Convert_Arg &&converter) noexcept(noexcept(Converter{std::forward< Convert_Arg >(converter)}))
expected_t< T, parse_error_t > try_parse(source_t &from) const noexcept