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