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