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