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