RESTinio
easy_parser.hpp
Go to the documentation of this file.
1/*
2 * RESTinio
3 */
4
13#pragma once
14
17
20
23
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
35namespace restinio
36{
37
38namespace easy_parser
39{
40
42
43//
44// error_reason_t
45//
52{
65
71
82};
83
84//
85// parse_error_t
86//
93{
95 std::size_t m_position;
98
99public:
102 std::size_t position,
103 error_reason_t reason ) noexcept
105 , m_reason{ reason }
106 {}
107
110 std::size_t
111 position() const noexcept { return m_position; }
112
116 reason() const noexcept { return m_reason; }
117};
118
119//
120// nothing_t
121//
128struct nothing_t {};
129
130//
131// result_value_wrapper
132//
178template< typename T >
180{
181 using result_type = T;
183
184 static void
186 {
187 to = std::move(what);
188 }
189
191 static result_type &&
193 {
194 return std::move(v);
195 }
196};
197
198//
199// result_wrapper_for
200//
243template< typename T >
245{
247};
248
249template< typename T >
251
252template< typename T, typename... Args >
253struct 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;
258
259 static void
261 {
262 to = std::move(what);
263 }
264
265 static void
267 {
268 to.push_back( std::move(what) );
269 }
270
272 static result_type &&
274 {
275 return std::move(v);
276 }
277};
278
279namespace impl
280{
281
282//
283// std_array_wrapper
284//
297template< typename T, std::size_t S >
299{
300 std::array< T, S > m_array;
301 std::size_t m_index{ 0u };
302};
303
304} /* namespace impl */
305
306template< typename T, std::size_t S >
307struct 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;
312
313 static void
315 {
316 to.m_array = std::move(what);
317 to.m_index = 0u;
318 }
319
320 static void
322 {
323 if( to.m_index >= S )
324 throw exception_t(
325 "index in the result std::array is out of range, "
326 "index=" + std::to_string(to.m_index) +
327 ", size={}" + std::to_string(S) );
328
329 to.m_array[ to.m_index ] = std::move(what);
330 ++to.m_index;
331 }
332
334 static result_type &&
336 {
337 return std::move(v.m_array);
338 }
339};
340
347template< typename T, std::size_t S >
348struct result_wrapper_for< impl::std_array_wrapper<T, S> >
349{
351};
352
353template< typename Char, typename... Args >
354struct result_value_wrapper< std::basic_string< Char, Args... > >
355{
356 using result_type = std::basic_string< Char, Args... >;
357 using value_type = Char;
359
360 static void
362 {
363 to = std::move(what);
364 }
365
366 static void
368 {
369 to.push_back( what );
370 }
371
385 static void
387 {
388 to.append( what );
389 }
390
392 static result_type &&
394 {
395 return std::move(v);
396 }
397};
398
399template< typename K, typename V, typename... Args >
400struct result_value_wrapper< std::map< K, V, Args... > >
401{
402 using result_type = std::map< K, V, Args... >;
403 // NOTE: we can't use container_type::value_type here
404 // because value_type for std::map is std::pair<const K, V>,
405 // not just std::pair<K, V>,
406 using value_type = std::pair<K, V>;
408
409 static void
411 {
412 to = std::move(what);
413 }
414
415 static void
417 {
418 to.emplace( std::move(what) );
419 }
420
422 static result_type &&
424 {
425 return std::move(v);
426 }
427};
428
429template<>
431{
435
436 static void
437 as_result( wrapped_type &, result_type && ) noexcept {}
438
439 static void
441
443 static result_type &&
445 {
446 return std::move(v);
447 }
448};
449
455constexpr std::size_t N = std::numeric_limits<std::size_t>::max();
456
457//
458// digits_to_consume_t
459//
467{
468public:
469 using underlying_int_t = std::int_fast8_t;
470
472
480
481public:
486 constexpr
488 : m_min{ total }
489 , m_max{ total }
490 {}
491
496 constexpr
499 underlying_int_t max ) noexcept
500 : m_min{ min }
501 , m_max{ max }
502 {}
503
506 constexpr auto
507 min() const noexcept { return m_min; }
508
511 constexpr auto
512 max() const noexcept { return m_max; }
513
516 constexpr static auto
517 unlimited_max() noexcept
518 {
519 return std::numeric_limits<underlying_int_t>::max();
520 }
521
526 constexpr static auto
528 {
529 return digits_to_consume_t{ 1, unlimited_max() };
530 }
531};
532
548inline constexpr digits_to_consume_t
550{
551 return { total };
552}
553
569inline constexpr digits_to_consume_t
573{
574 return { min, max };
575}
576
577namespace impl
578{
579
580//
581// character_t
582//
593{
594 bool m_eof;
595 char m_ch;
596};
597
599inline bool
600operator==( 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
606inline bool
607operator!=( 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
617constexpr char SP = ' ';
623constexpr char HTAB = '\x09';
624
625//
626// is_space
627//
634inline constexpr bool
635is_space( const char ch ) noexcept
636{
637 return ch == SP || ch == HTAB;
638}
639
640//
641// is_space_predicate_t
642//
650{
652 bool
653 operator()( const char actual ) const noexcept
654 {
655 return is_space(actual);
656 }
657};
658
659//
660// is_digit
661//
668inline constexpr bool
669is_digit( const char ch ) noexcept
670{
671 return (ch >= '0' && ch <= '9');
672}
673
674//
675// is_digit_predicate_t
676//
683{
685 bool
686 operator()( const char actual ) const noexcept
687 {
688 return is_digit( actual );
689 }
690};
691
692//
693// is_hexdigit
694//
701inline constexpr bool
702is_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//
719{
721 bool
722 operator()( const char actual ) const noexcept
723 {
724 return is_hexdigit( actual );
725 }
726};
727
728//
729// source_t
730//
740{
744
749 string_view_t::size_type m_index{};
750
751public:
753 using position_t = string_view_t::size_type;
754
756 explicit source_t( string_view_t data ) noexcept : m_data{ data } {}
757
759
764 character_t
765 getch() noexcept
766 {
767 if( m_index < m_data.size() )
768 {
769 return {false, m_data[ m_index++ ]};
770 }
771 else
772 return {true, 0};
773 }
774
776 void
777 putback() noexcept
778 {
779 if( m_index )
780 --m_index;
781 }
782
787 {
788 return m_index;
789 }
790
793 void
794 backto( position_t pos ) noexcept
795 {
796 if( pos <= m_data.size() )
797 m_index = pos;
798 }
799
802 bool
803 eof() const noexcept
804 {
805 return m_index >= m_data.size();
806 }
807
809
818 string_view_t::size_type from,
822 string_view_t::size_type length = string_view_t::npos ) const noexcept
823 {
824 return m_data.substr( from, length );
825 }
826
851 {
854 bool m_consumed{ false };
855
856 public :
860
861 content_consumer_t( source_t & from ) noexcept
862 : m_from{ from }
863 , m_started_at{ from.current_position() }
864 {}
865
867 {
868 if( !m_consumed )
870 }
871
873 started_at() const noexcept
874 {
875 return m_started_at;
876 }
877
879
884 void
885 commit() noexcept
886 {
887 m_consumed = true;
888 }
889 };
890};
891
892//
893// entity_type_t
894//
901{
903 producer,
908 consumer,
910 clause,
913
917};
918
919//
920// producer_tag
921//
943template< typename Result_Type >
945{
946 using result_type = Result_Type;
948};
949
950template< typename T, typename = meta::void_t<> >
951struct is_producer : public std::false_type {};
952
953template< typename T >
954struct 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
969template< typename T >
971
972//
973// transformer_tag
974//
997template< typename Result_Type >
999{
1000 using result_type = Result_Type;
1002};
1003
1004template< typename T, typename = meta::void_t<> >
1006
1007template< typename T >
1008struct 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
1023template< typename T >
1025
1026//
1027// transformer_invoker
1028//
1046template< typename Result_Type >
1048{
1049 template< typename Transformer, typename Input_Type >
1051 static Result_Type
1053 source_t &,
1054 Transformer & transformer,
1056 {
1057 return transformer.transform( std::move(*input) );
1058 }
1059};
1060
1067template< typename Result_Type >
1069{
1070 template< typename Transformer, typename Input_Type >
1074 // source_t is necessary to get the position in the case of an error.
1075 source_t & source,
1076 Transformer & transformer,
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//
1109template< typename Result_Type >
1111{
1112 static constexpr bool value = true;
1113};
1114
1115template< typename Result_Type >
1117 expected_t< Result_Type, error_reason_t > >
1118{
1119 static constexpr bool value = true;
1120};
1121
1122template< typename 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//
1143template< typename Producer, typename Transformer >
1145{
1146 static_assert( is_producer_v<Producer>,
1147 "Producer should be a producer type" );
1148 static_assert( is_transformer_v<Transformer>,
1149 "Transformer should be a transformer type" );
1150
1151 using producer_result_t = std::decay_t< decltype(
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
1164};
1165
1166//
1167// transformed_value_producer_t
1168//
1178template< typename Producer, typename Transformer >
1180 : public producer_tag< typename Transformer::result_type >
1181{
1183 Producer, Transformer >;
1184
1185 static_assert(
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
1193public :
1194 using result_type = typename Transformer::result_type;
1195
1197 Producer && producer,
1198 Transformer && transformer )
1201 {}
1202
1206 {
1207 auto producer_result = m_producer.try_parse( source );
1208 if( producer_result )
1209 {
1210 using transformation_result_t =
1212
1214 source,
1216 std::move(producer_result) );
1217 }
1218 else
1219 return make_unexpected( producer_result.error() );
1220 }
1221};
1222
1228template< typename P, typename T >
1230std::enable_if_t<
1231 is_producer_v<P> & is_transformer_v<T>,
1232 transformed_value_producer_t< P, T > >
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//
1267{
1269};
1270
1271template< typename T, typename = meta::void_t<> >
1273
1274template< typename T >
1275struct 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
1289template< typename T >
1291
1298template<
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 > >
1305auto
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
1316
1317 return producer_type{ std::move(producer), std::move(real_transformer) };
1318}
1319
1320//
1321// consumer_tag
1322//
1343{
1345};
1346
1347template< typename T, typename = meta::void_t<> >
1348struct is_consumer : public std::false_type {};
1349
1350template< typename T >
1351struct 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
1366template< typename T >
1368
1369//
1370// clause_tag
1371//
1393{
1395};
1396
1397template< typename T, typename = meta::void_t<> >
1398struct is_clause : public std::false_type {};
1399
1400template< typename T >
1402 decltype(std::decay_t<T>::entity_type) > >
1403{
1404 using real_type = std::decay_t<T>;
1405
1406 static constexpr bool value = entity_type_t::clause == real_type::entity_type;
1407};
1408
1419template< typename T >
1421
1422//
1423// tuple_of_entities_t
1424//
1455template< typename... Entities >
1457 meta::transform_t< std::decay, meta::type_list<Entities...> >,
1458 std::tuple >;
1459
1460//
1461// consume_value_clause_t
1462//
1472template< typename P, typename C >
1474{
1475 static_assert( is_producer_v<P>, "P should be a producer type" );
1476 static_assert( is_consumer_v<C>, "C should be a consumer type" );
1477
1480
1481public :
1482 consume_value_clause_t( P && producer, C && consumer )
1485 {}
1486
1487 template< typename Target_Type >
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
1508template< typename P, typename C >
1510std::enable_if_t<
1511 is_producer_v<P> && is_consumer_v<C>,
1512 consume_value_clause_t< P, C > >
1513operator>>( P producer, C consumer )
1514{
1515 return { std::move(producer), std::move(consumer) };
1516}
1517
1518//
1519// top_level_clause_t
1520//
1531template< typename Producer >
1533{
1534 static_assert( is_producer_v<Producer>,
1535 "Producer should be a producer type" );
1536
1537 Producer m_producer;
1538
1539public :
1540 top_level_clause_t( Producer && producer )
1542 {}
1543
1545 auto
1547 {
1548 return m_producer.try_parse( from );
1549 }
1550};
1551
1552//
1553// ensure_no_remaining_content
1554//
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(),
1577 };
1578 }
1579 }
1580
1581 return nullopt;
1582}
1583
1584//
1585// remove_trailing_spaces
1586//
1593inline string_view_t
1595{
1596 auto s = from.size();
1597 for(; s && is_space( from[ (s-1u) ] ); --s) {}
1598
1599 return from.substr( 0u, s );
1600}
1601
1602//
1603// alternatives_clause_t
1604//
1633template<
1634 typename Subitems_Tuple >
1636{
1637 Subitems_Tuple m_subitems;
1638
1639public :
1641 Subitems_Tuple && subitems )
1642 : m_subitems{ std::move(subitems) }
1643 {}
1644
1645 template< typename Target_Type >
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 ) {
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.
1673 actual_parse_error->reason();
1674 }
1675 } );
1676
1677 if( !success || actual_parse_error )
1678 return parse_error_t{
1679 starting_pos,
1681 };
1682 else
1683 return nullopt;
1684 }
1685};
1686
1687//
1688// maybe_clause_t
1689//
1714template<
1715 typename Subitems_Tuple >
1717{
1718 Subitems_Tuple m_subitems;
1719
1720public :
1722 Subitems_Tuple && subitems )
1723 : m_subitems{ std::move(subitems) }
1724 {}
1725
1726 template< typename Target_Type >
1729 try_process( source_t & from, Target_Type & target )
1730 {
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//
1777template<
1778 typename Subitems_Tuple >
1780{
1781 Subitems_Tuple m_subitems;
1782
1783public :
1785 Subitems_Tuple && subitems )
1786 : m_subitems{ std::move(subitems) }
1787 {}
1788
1789 template< typename Target_Type >
1792 try_process( source_t & from, Target_Type & )
1793 {
1794 // NOTE: will always return the current position back.
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?
1813 };
1814 else
1815 return nullopt;
1816 }
1817};
1818
1819//
1820// and_clause_t
1821//
1845template<
1846 typename Subitems_Tuple >
1848{
1849 Subitems_Tuple m_subitems;
1850
1851public :
1853 Subitems_Tuple && subitems )
1854 : m_subitems{ std::move(subitems) }
1855 {}
1856
1857 template< typename Target_Type >
1860 try_process( source_t & from, Target_Type & )
1861 {
1862 // NOTE: will always return the current position back.
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(),
1877 };
1878 else
1879 return nullopt;
1880 }
1881};
1882
1883//
1884// sequence_clause_t
1885//
1906template<
1907 typename Subitems_Tuple >
1909{
1910 Subitems_Tuple m_subitems;
1911
1912public :
1914 Subitems_Tuple && subitems )
1915 : m_subitems{ std::move(subitems) }
1916 {}
1917
1918 template< typename Target_Type >
1921 try_process( source_t & from, Target_Type & target )
1922 {
1924 Target_Type tmp_value{ target };
1925
1926 // We should store actual parse error from subitems to return it.
1928
1929 const bool success = restinio::utils::tuple_algorithms::all_of(
1930 m_subitems,
1931 [&from, &tmp_value, &result]( auto && one_producer ) {
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//
1959template<
1960 typename Subitems_Tuple >
1961class forced_alternative_clause_t : public sequence_clause_t< Subitems_Tuple >
1962{
1964
1965public :
1966 using base_type_t::base_type_t;
1967
1968 template< typename Target_Type >
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,
1982 };
1983 }
1984 else
1985 return nullopt;
1986 }
1987};
1988
1989//
1990// produce_t
1991//
2006template<
2007 typename Target_Type,
2008 typename Subitems_Tuple >
2009class produce_t : public producer_tag< Target_Type >
2010{
2012
2013 Subitems_Tuple m_subitems;
2014
2015public :
2017 Subitems_Tuple && subitems )
2018 : m_subitems{ std::move(subitems) }
2019 {}
2020
2024 {
2025 typename value_wrapper_t::wrapped_type tmp_value{};
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//
2058template<
2059 typename Subitems_Tuple >
2061{
2062 std::size_t m_min_occurences;
2063 std::size_t m_max_occurences;
2064
2065 Subitems_Tuple m_subitems;
2066
2067public :
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 >
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
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(),
2113 };
2114 }
2115};
2116
2117//
2118// symbol_producer_template_t
2119//
2129template< typename Predicate >
2131 : public producer_tag< char >
2132 , protected Predicate
2133{
2134public:
2135 template< typename... Args >
2137 : Predicate{ std::forward<Args>(args)... }
2138 {}
2139
2142 try_parse( source_t & from ) const noexcept
2143 {
2144 const auto ch = from.getch();
2145 if( !ch.m_eof )
2146 {
2147 // A call to predicate.
2148 if( (*this)(ch.m_ch) )
2149 return ch.m_ch;
2150 else
2151 {
2152 from.putback();
2153 return make_unexpected( parse_error_t{
2154 from.current_position(),
2156 } );
2157 }
2158 }
2159 else
2160 return make_unexpected( parse_error_t{
2161 from.current_position(),
2163 } );
2164 }
2165};
2166
2167//
2168// any_symbol_predicate_t
2169//
2179{
2181 constexpr bool
2182 operator()( const char ) const noexcept
2183 {
2184 return true;
2185 }
2186};
2187
2188//
2189// particular_symbol_predicate_t
2190//
2198{
2200
2202 bool
2203 operator()( const char actual ) const noexcept
2204 {
2205 return m_expected == actual;
2206 }
2207};
2208
2209//
2210// not_particular_symbol_predicate_t
2211//
2219{
2221
2223 bool
2224 operator()( const char actual ) const noexcept
2225 {
2226 return m_sentinel != actual;
2227 }
2228};
2229
2230//
2231// caseless_particular_symbol_predicate_t
2232//
2240{
2242
2245 {}
2246
2248 bool
2249 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//
2267{
2270
2272 bool
2273 operator()( const char actual ) const noexcept
2274 {
2275 return ( actual >= m_left && actual <= m_right );
2276 }
2277};
2278
2279//
2280// symbol_producer_t
2281//
2291 : public symbol_producer_template_t< particular_symbol_predicate_t >
2292{
2295
2296public:
2297 symbol_producer_t( char expected )
2299 {}
2300};
2301
2302//
2303// any_symbol_if_not_producer_t
2304//
2314 : public symbol_producer_template_t< not_particular_symbol_predicate_t >
2315{
2318
2319public:
2322 {}
2323};
2324
2325//
2326// caseless_symbol_producer_t
2327//
2340 : public symbol_producer_template_t< caseless_particular_symbol_predicate_t >
2341{
2344
2345public:
2348 {}
2349};
2350
2351//
2352// symbol_from_range_producer_t
2353//
2363 : public symbol_producer_template_t< symbol_from_range_predicate_t >
2364{
2367
2368public:
2369 symbol_from_range_producer_t( char left, char right )
2371 {}
2372};
2373
2374//
2375// digit_producer_t
2376//
2386 : public symbol_producer_template_t< is_digit_predicate_t >
2387{
2388public:
2390};
2391
2392//
2393// hexdigit_producer_t
2394//
2404 : public symbol_producer_template_t< is_hexdigit_predicate_t >
2405{
2406public:
2408};
2409
2410//
2411// try_parse_digits_with_digits_limit
2412//
2434template< typename T, typename Value_Accumulator >
2438 source_t & from,
2439 digits_to_consume_t digits_limit,
2440 Value_Accumulator acc ) noexcept
2441{
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(),
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(),
2474 } );
2475 else
2476 {
2477 consumer.commit();
2478 return acc.value();
2479 }
2480}
2481
2482//
2483// try_parse_hexdigits_with_digits_limit
2484//
2498template< typename T, typename Value_Accumulator >
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
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(),
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(),
2550 } );
2551 else
2552 {
2553 consumer.commit();
2554 return acc.value();
2555 }
2556}
2557
2558//
2559// non_negative_decimal_number_producer_t
2560//
2569template< typename T >
2571{
2572public:
2575 try_parse( source_t & from ) const noexcept
2576 {
2577 return try_parse_digits_with_digits_limit< T >(
2578 from,
2581 }
2582};
2583
2584//
2585// non_negative_decimal_number_producer_with_digits_limit_t
2586//
2597template< typename T >
2600{
2602
2603public:
2605 digits_to_consume_t digits_limit )
2606 : m_digits_limit{ digits_limit }
2607 {}
2608
2611 try_parse( source_t & from ) const noexcept
2612 {
2613 return try_parse_digits_with_digits_limit< T >(
2614 from,
2617 }
2618};
2619
2620//
2621// hexadecimal_number_producer_t
2622//
2631template< typename T >
2633{
2634 static_assert( std::is_unsigned<T>::value,
2635 "T is expected to be unsigned type" );
2636
2637public:
2640 try_parse( source_t & from ) const noexcept
2641 {
2642 return try_parse_hexdigits_with_digits_limit< T >(
2643 from,
2646 }
2647};
2648
2649//
2650// hexadecimal_number_producer_with_digits_limit_t
2651//
2662template< typename T >
2664 : public hexadecimal_number_producer_t< T >
2665{
2667
2668public:
2670 digits_to_consume_t digits_limit )
2671 : m_digits_limit{ digits_limit }
2672 {}
2673
2676 try_parse( source_t & from ) const noexcept
2677 {
2678 return try_parse_hexdigits_with_digits_limit< T >(
2679 from,
2682 }
2683};
2684
2685//
2686// decimal_number_producer_t
2687//
2696template< typename T >
2698{
2699 static_assert( std::is_signed<T>::value,
2700 "decimal_number_producer_t can be used only for signed types" );
2701
2702public:
2704
2707 try_parse( source_t & from ) const noexcept
2708 {
2709 return try_parse_impl( from,
2710 []() noexcept {
2712 } );
2713 }
2714
2715protected:
2716 template< typename Digits_Limit_Maker >
2720 source_t & from,
2721 Digits_Limit_Maker && digits_limit_maker ) const noexcept
2722 {
2724
2725 auto sign_ch = from.getch();
2726 if( !sign_ch.m_eof )
2727 {
2728 const auto r = try_parse_with_this_first_symbol(
2729 from,
2730 sign_ch.m_ch,
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(),
2742 } );
2743 }
2744
2745private:
2746 template< typename Digits_Limit_Maker >
2750 source_t & from,
2751 char first_symbol,
2752 Digits_Limit_Maker && digits_limit_maker ) noexcept
2753 {
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(),
2792 } );
2793 }
2794};
2795
2796//
2797// decimal_number_producer_with_digits_limit_t
2798//
2809template< typename T >
2811 : public decimal_number_producer_t< T >
2812{
2814
2815public:
2817 digits_to_consume_t digits_limit )
2818 : m_digits_limit{ digits_limit }
2819 {}
2820
2822 auto
2823 try_parse( source_t & from ) const noexcept
2824 {
2825 return this->try_parse_impl(
2826 from,
2827 [this]() noexcept { return m_digits_limit; } );
2828 }
2829};
2830
2831//
2832// any_value_skipper_t
2833//
2843{
2844 template< typename Target_Type, typename Value >
2845 void
2846 consume( Target_Type &, Value && ) const noexcept {}
2847};
2848
2849//
2850// as_result_consumer_t
2851//
2870{
2871 template< typename Target_Type, typename Value >
2872 void
2873 consume( Target_Type & dest, Value && src ) const
2874 {
2876 dest, std::forward<Value>(src) );
2877 }
2878};
2879
2880//
2881// just_result_consumer_t
2882//
2890template< typename Result_Type >
2892{
2893 Result_Type m_result;
2894
2895 // NOTE: this helper method is necessary for MSVC++ compiler.
2896 // It's because MSVC++ can't compile expression:
2897 //
2898 // as_result(dest, Result_Type{m_result})
2899 //
2900 // in consume() method for trivial types like size_t.
2901 Result_Type
2903 noexcept(noexcept(Result_Type{m_result}))
2904 {
2905 return m_result;
2906 }
2907
2908public :
2909 template< typename Result_Arg >
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
2917 consume( Target_Type & dest, Value && ) const
2918 {
2920 dest,
2921 // NOTE: use a copy of m_result.
2923 }
2924};
2925
2926//
2927// custom_consumer_t
2928//
2938template< typename C >
2940{
2942
2943public :
2945
2946 template< typename Target_Type, typename Value >
2947 void
2948 consume( Target_Type & dest, Value && src ) const
2949 noexcept(noexcept(m_consumer(dest, std::forward<Value>(src))))
2950 {
2951 m_consumer( dest, std::forward<Value>(src) );
2952 }
2953};
2954
2955//
2956// field_setter_consumer_t
2957//
2967template< typename F, typename C >
2969{
2970 using pointer_t = F C::*;
2971
2973
2974public :
2975 field_setter_consumer_t( pointer_t ptr ) noexcept : m_ptr{ptr} {}
2976
2977 // NOTE: it seems that this method won't be compiled if
2978 // result_value_wrapper::result_type differs from
2979 // result_value_wrapper::wrapped_type.
2980 //
2981 // This is not a problem for the current version.
2982 // But this moment would require more attention in the future.
2983 void
2984 consume( C & to, F && value ) const
2985 noexcept(noexcept(to.*m_ptr = std::move(value)))
2986 {
2987 to.*m_ptr = std::move(value);
2988 }
2989};
2990
2997template< typename P, typename F, typename C >
2999std::enable_if_t<
3000 is_producer_v<P>,
3001 consume_value_clause_t< P, field_setter_consumer_t<F,C> > >
3002operator>>( P producer, F C::*member_ptr )
3003{
3004 return {
3006 field_setter_consumer_t<F,C>{ member_ptr }
3007 };
3008}
3009
3010//
3011// tuple_item_consumer_t
3012//
3019template< std::size_t Index >
3021{
3022 // NOTE: it seems that this method won't be compiled if
3023 // result_value_wrapper::result_type differs from
3024 // result_value_wrapper::wrapped_type.
3025 //
3026 // This is not a problem for the current version.
3027 // But this moment would require more attention in the future.
3028 template< typename Target_Type, typename Value >
3029 void
3030 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//
3040template< typename Input_Type >
3042
3049template<>
3051 : public transformer_tag< std::string >
3052{
3053 using input_type = std::string;
3054
3057 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
3075template<>
3077 : public transformer_tag< char >
3078{
3079 using input_type = char;
3080
3083 transform( input_type && input ) const noexcept
3084 {
3085 return restinio::impl::to_lower_case(input);
3086 }
3087};
3088
3095template< std::size_t S >
3096struct to_lower_transformer_t< std::array< char, S > >
3097 : public transformer_tag< std::array< char, S > >
3098{
3099 using input_type = std::array< char, S >;
3101
3103 typename base_type::result_type
3104 transform( input_type && input ) const noexcept
3105 {
3106 typename base_type::result_type result;
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//
3125{
3126 template< typename Input_Type >
3128 auto
3130 {
3132 }
3133};
3134
3135//
3136// just_value_transformer_t
3137//
3144template< typename T >
3146{
3148
3149public :
3150 just_value_transformer_t( T v ) noexcept(noexcept(T{std::move(v)}))
3151 : m_value{ std::move(v) }
3152 {}
3153
3154 template< typename Input >
3156 T
3157 transform( Input && ) const noexcept(noexcept(T{m_value}))
3158 {
3159 return m_value;
3160 }
3161};
3162
3163//
3164// convert_transformer_t
3165//
3172template< typename Output_Type, typename Converter >
3173class convert_transformer_t : public transformer_tag< Output_Type >
3174{
3175 Converter m_converter;
3176
3177public :
3178 template< typename Convert_Arg >
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
3192 template< typename Input >
3194 auto
3195 transform( Input && input ) const
3196 noexcept(noexcept(m_converter(std::forward<Input>(input))))
3197 {
3198 using actual_result_t = std::decay_t< decltype(
3199 m_converter(std::forward<Input>(input))
3200 ) >;
3201
3202 static_assert(
3204 "the return value of converter should be either Output_Type or "
3205 "expected_t<Output_Type, error_reason_t>" );
3206
3207 return m_converter(std::forward<Input>(input));
3208 }
3209};
3210
3211//
3212// conversion_result_type_detector
3213//
3224template< typename Result_Type >
3226{
3227 using type = Result_Type;
3228};
3229
3230template< typename Result_Type >
3232{
3233 using type = Result_Type;
3234};
3235
3241template< typename Result_Type >
3244
3245//
3246// convert_transformer_proxy_t
3247//
3261template< typename Converter >
3263{
3264 template< typename Input_Type >
3266 std::decay_t< decltype(
3267 std::declval<Converter &>()(std::declval<Input_Type&&>())
3268 ) >
3269 >;
3270
3271 Converter m_converter;
3272
3273public :
3274 template< typename Convert_Arg >
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 >
3282 auto
3284 noexcept(noexcept(Converter{m_converter}))
3285 {
3286 using output_t = output<Input_Type>;
3287
3289 }
3290
3291 template< typename Input_Type >
3293 auto
3295 noexcept(noexcept(Converter{std::move(m_converter)}))
3296 {
3297 using output_t = output<Input_Type>;
3298
3301 };
3302 }
3303};
3304
3305//
3306// try_parse_exact_fragment
3307//
3308
3309// Requires that begin is not equal to end.
3310template< typename It >
3312expected_t< bool, parse_error_t >
3313try_parse_exact_fragment( source_t & from, It begin, It end )
3314{
3315 assert( begin != end );
3316
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(),
3325 } );
3326 if( ++begin == end )
3327 break;
3328 }
3329
3330 if( begin != end )
3331 return make_unexpected( parse_error_t{
3332 consumer.started_at(),
3334 } );
3335
3336 consumer.commit();
3337
3338 return true;
3339}
3340
3341//
3342// exact_fixed_size_fragment_producer_t
3343//
3353template< std::size_t Size >
3355 : public producer_tag< bool >
3356{
3357 static_assert( 1u < Size, "Size is expected to greater that 1" );
3358
3359 // NOTE: there is no space for last zero-byte.
3360 std::array< char, Size-1u > m_fragment;
3361
3362public:
3364 {
3365 // NOTE: last zero-byte is discarded.
3366 std::copy( &f[ 0 ], &f[ m_fragment.size() ], m_fragment.data() );
3367 }
3368
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//
3388 : public producer_tag< bool >
3389{
3390 std::string m_fragment;
3391
3392public:
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
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.
3416template< typename It >
3420{
3421 assert( begin != end );
3422
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(),
3431 } );
3432 if( ++begin == end )
3433 break;
3434 }
3435
3436 if( begin != end )
3437 return make_unexpected( parse_error_t{
3438 consumer.started_at(),
3440 } );
3441
3442 consumer.commit();
3443
3444 return true;
3445}
3446
3447//
3448// caseless_exact_fixed_size_fragment_producer_t
3449//
3461template< std::size_t Size >
3463 : public producer_tag< bool >
3464{
3465 static_assert( 1u < Size, "Size is expected to greater that 1" );
3466
3467 // NOTE: there is no space for last zero-byte.
3468 std::array< char, Size-1u > m_fragment;
3469
3470public:
3472 {
3473 // Content should be converted to lower-case.
3474 // NOTE: last zero-byte is discarded.
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
3486 {
3488 m_fragment.begin(), m_fragment.end() );
3489 }
3490};
3491
3492//
3493// caseless_exact_fragment_producer_t
3494//
3504 : public producer_tag< bool >
3505{
3506 std::string m_fragment;
3507
3508public:
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 )
3519 }
3520
3524 {
3526 m_fragment.begin(), m_fragment.end() );
3527 }
3528};
3529
3530} /* namespace impl */
3531
3532//
3533// produce
3534//
3549template<
3550 typename Target_Type,
3551 typename... Clauses >
3553auto
3554produce( 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//
3592template< typename... Clauses >
3594auto
3595alternatives( 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//
3631template< typename... Clauses >
3633auto
3634maybe( 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//
3673template< typename... Clauses >
3675auto
3676not_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//
3715template< typename... Clauses >
3717auto
3718and_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//
3755template< typename... Clauses >
3757auto
3758sequence( 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//
3818template< typename... Clauses >
3820auto
3821force_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//
3872template<
3873 typename... Clauses >
3875auto
3878 std::size_t min_occurences,
3880
3885 std::size_t max_occurences,
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//
3921inline auto
3922skip() noexcept { return impl::any_value_skipper_t{}; }
3923
3924//
3925// any_symbol_p
3926//
3936inline auto
3938{
3940}
3941
3942//
3943// symbol_p
3944//
3954inline auto
3955symbol_p( char expected ) noexcept
3956{
3957 return impl::symbol_producer_t{expected};
3958}
3959
3960//
3961// any_symbol_if_not_p
3962//
3972inline auto
3973any_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//
3992inline auto
3993caseless_symbol_p( char expected ) noexcept
3994{
3995 return impl::caseless_symbol_producer_t{expected};
3996}
3997
3998//
3999// symbol_from_range_p
4000//
4010inline auto
4011symbol_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//
4031inline auto
4032symbol( char expected ) noexcept
4033{
4034 return symbol_p(expected) >> skip();
4035}
4036
4037//
4038// caseless_symbol
4039//
4054inline auto
4055caseless_symbol( char expected ) noexcept
4056{
4057 return caseless_symbol_p(expected) >> skip();
4058}
4059
4060//
4061// symbol_from_range
4062//
4075inline auto
4076symbol_from_range( char left, char right ) noexcept
4077{
4078 return symbol_from_range_p(left, right) >> skip();
4079}
4080
4081//
4082// space_p
4083//
4093inline auto
4094space_p() noexcept
4095{
4097}
4098
4099//
4100// space
4101//
4114inline auto
4115space() noexcept
4116{
4117 return space_p() >> skip();
4118}
4119
4120//
4121// digit_p
4122//
4132inline auto
4133digit_p() noexcept
4134{
4135 return impl::digit_producer_t{};
4136}
4137
4138//
4139// digit
4140//
4153inline auto
4154digit() noexcept
4155{
4156 return digit_p() >> skip();
4157}
4158
4159//
4160// hexdigit_p
4161//
4171inline auto
4172hexdigit_p() noexcept
4173{
4175}
4176
4177//
4178// hexdigit
4179//
4192inline auto
4193hexdigit() noexcept
4194{
4195 return hexdigit_p() >> skip();
4196}
4197
4198//
4199// non_negative_decimal_number_p
4200//
4215template< typename T >
4217inline auto
4219{
4221}
4222
4223//
4224// non_negative_decimal_number_p
4225//
4254template< typename T >
4256inline auto
4258{
4260 digits_limit
4261 };
4262}
4263
4264//FIXME: remove in v.0.7.0!
4265//
4266// positive_decimal_number_p
4267//
4276template< typename T >
4277[[deprecated]] RESTINIO_NODISCARD
4278inline auto
4280{
4281 return non_negative_decimal_number_p<T>();
4282}
4283
4284//
4285// hexadecimal_number_p
4286//
4304template< typename T >
4306inline auto
4308{
4310}
4311
4312//
4313// hexadecimal_number_p
4314//
4346template< typename T >
4348inline auto
4350{
4352 digits_limit
4353 };
4354}
4355
4356//
4357// decimal_number_p
4358//
4384template< typename T >
4386inline auto
4388{
4389 static_assert( std::is_signed<T>::value,
4390 "decimal_number_p() can be used only for signed numeric types" );
4391
4393}
4394
4395//
4396// decimal_number_p
4397//
4437template< typename T >
4439inline auto
4441{
4442 static_assert( std::is_signed<T>::value,
4443 "decimal_number_p() can be used only for signed numeric types" );
4444
4446 digits_limit
4447 };
4448}
4449
4450//
4451// as_result
4452//
4469inline auto
4471
4472//
4473// custom_consumer
4474//
4513template< typename F >
4515auto
4516custom_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
4523namespace impl
4524{
4525
4526//
4527// to_container_consumer_t
4528//
4541{
4542 template< typename Container, typename Item >
4543 void
4544 consume( Container & to, Item && item )
4545 {
4546 using container_adaptor_type = result_wrapper_for_t<Container>;
4548 }
4549};
4550
4551} /* namespace impl */
4552
4553//
4554// to_container
4555//
4582inline auto
4584{
4586}
4587
4588//
4589// to_lower
4590//
4609inline auto
4611
4612//
4613// just
4614//
4632template< typename T >
4634auto
4635just( 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//
4661template< typename T >
4663auto
4664just_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//
4734template< typename Converter >
4736auto
4737convert( 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//
4767inline auto
4769{
4771 std::string{ fragment.data(), fragment.size() }
4772 };
4773}
4774
4809template< std::size_t Size >
4811auto
4812exact_p( const char (&fragment)[Size] )
4813{
4815}
4816
4817//
4818// exact
4819//
4832inline auto
4834{
4836 std::string{ fragment.data(), fragment.size() }
4837 } >> skip();
4838}
4839
4868template< std::size_t Size >
4870auto
4871exact( const char (&fragment)[Size] )
4872{
4874}
4875
4876//
4877// caseless_exact_p
4878//
4896inline auto
4898{
4900 std::string{ fragment.data(), fragment.size() }
4901 };
4902}
4903
4938template< std::size_t Size >
4940auto
4941caseless_exact_p( const char (&fragment)[Size] )
4942{
4944}
4945
4946//
4947// caseless_exact
4948//
4961inline auto
4963{
4965 std::string{ fragment.data(), fragment.size() }
4966 } >> skip();
4967}
4968
4997template< std::size_t Size >
4999auto
5000caseless_exact( const char (&fragment)[Size] )
5001{
5003}
5004
5005//
5006// try_parse
5007//
5039template< typename Producer >
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 =
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//
5102inline std::string
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 {
5166 basic_reaction( "unexpected character" );
5167 break;
5168
5170 result += "unexpected EOF at ";
5171 result += std::to_string( error.position() );
5172 break;
5173
5175 basic_reaction( "appropriate alternative can't found" );
5176 break;
5177
5179 basic_reaction( "expected pattern is not found" );
5180 break;
5181
5183 basic_reaction( "unconsumed input found" );
5184 break;
5185
5187 basic_reaction( "some illegal value found" );
5188 break;
5189
5191 basic_reaction( "forced selection alternative failed" );
5192 break;
5193 }
5194
5195 return result;
5196}
5197
5198} /* namespace easy_parser */
5199
5200} /* namespace restinio */
5201
Limits for number of digits to be extracted during parsing of decimal numbers.
constexpr digits_to_consume_t(underlying_int_t total) noexcept
RESTINIO_NODISCARD static constexpr auto from_one_to_max() noexcept
constexpr digits_to_consume_t(underlying_int_t min, underlying_int_t max) noexcept
RESTINIO_NODISCARD constexpr auto max() const noexcept
Get the maximum value.
underlying_int_t m_max
Maximal number of digits to consume.
RESTINIO_NODISCARD static constexpr auto unlimited_max() noexcept
Get the value that means that maximum is not limited.
RESTINIO_NODISCARD constexpr auto min() const noexcept
Get the minimal value.
underlying_int_t m_min
Minimal number of digits to consume.
A template for implementation of clause that selects one of alternative clauses.
RESTINIO_NODISCARD optional_t< parse_error_t > try_process(source_t &from, Target_Type &target)
A template for implementation of clause that checks the presence of some entity in the input stream.
RESTINIO_NODISCARD optional_t< parse_error_t > try_process(source_t &from, Target_Type &)
and_clause_t(Subitems_Tuple &&subitems)
A producer for the case when any character except the specific sentinel character is expected in the ...
A producer that expects a fragment in the input and produces boolean value if that fragment is found.
RESTINIO_NODISCARD expected_t< bool, parse_error_t > try_parse(source_t &from)
A producer that expects a fragment in the input and produces boolean value if that fragment is found.
RESTINIO_NODISCARD expected_t< bool, parse_error_t > try_parse(source_t &from)
A producer for the case when a particual character is expected in the input stream.
A template for a clause that binds a value producer with value consumer.
RESTINIO_NODISCARD optional_t< parse_error_t > try_process(source_t &from, Target_Type &target)
A proxy for the creation of convert_transformer instances for a specific value producers.
conversion_result_type_detector_t< std::decay_t< decltype(std::declval< Converter & >()(std::declval< Input_Type && >())) > > output
RESTINIO_NODISCARD auto make_transformer() &&noexcept(noexcept(Converter{std::move(m_converter)}))
RESTINIO_NODISCARD auto make_transformer() const &noexcept(noexcept(Converter{m_converter}))
convert_transformer_proxy_t(Convert_Arg &&converter) noexcept(noexcept(Converter{std::forward< Convert_Arg >(converter)}))
A transformator that uses a user supplied function/functor for conversion a value from one type to an...
RESTINIO_NODISCARD auto transform(Input &&input) const noexcept(noexcept(m_converter(std::forward< Input >(input))))
Performs the transformation by calling the converter.
convert_transformer_t(Convert_Arg &&converter) noexcept(noexcept(Converter{std::forward< Convert_Arg >(converter)}))
A template for consumers that are released by lambda/functional objects.
void consume(Target_Type &dest, Value &&src) const noexcept(noexcept(m_consumer(dest, std::forward< Value >(src))))
A producer for the case when a signed decimal number is expected in the input stream.
RESTINIO_NODISCARD try_parse_result_type try_parse(source_t &from) const noexcept
static RESTINIO_NODISCARD try_parse_result_type try_parse_with_this_first_symbol(source_t &from, char first_symbol, Digits_Limit_Maker &&digits_limit_maker) noexcept
RESTINIO_NODISCARD try_parse_result_type try_parse_impl(source_t &from, Digits_Limit_Maker &&digits_limit_maker) const noexcept
A producer for the case when a signed decimal number is expected in the input stream.
RESTINIO_NODISCARD auto try_parse(source_t &from) const noexcept
A producer for the case when a decimal digit is expected in the input stream.
A producer that expects a fragment in the input and produces boolean value if that fragment is found.
RESTINIO_NODISCARD expected_t< bool, parse_error_t > try_parse(source_t &from)
A producer that expects a fragment in the input and produces boolean value if that fragment is found.
RESTINIO_NODISCARD expected_t< bool, parse_error_t > try_parse(source_t &from)
A template for consumers that store a value to the specified field of a target object.
void consume(C &to, F &&value) const noexcept(noexcept(to.*m_ptr=std::move(value)))
An alternative that should be parsed correctly or the parsing of the whole alternatives clause should...
RESTINIO_NODISCARD optional_t< parse_error_t > try_process(source_t &from, Target_Type &target)
A producer for the case when a number in hexadecimal form is expected in the input stream.
RESTINIO_NODISCARD expected_t< T, parse_error_t > try_parse(source_t &from) const noexcept
A producer for the case when a number in hexadecimal form is expected in the input stream.
RESTINIO_NODISCARD expected_t< T, parse_error_t > try_parse(source_t &from) const noexcept
A producer for the case when a hexadecimal digit is expected in the input stream.
A consumer for the case when a specific value should be used as the result instead of the value produ...
Result_Type make_copy_of_result() const noexcept(noexcept(Result_Type{m_result}))
just_result_consumer_t(Result_Arg &&result) noexcept(noexcept(Result_Type{std::forward< Result_Arg >(result)}))
void consume(Target_Type &dest, Value &&) const
A transformer that skips incoming value and returns a value specified by a user.
RESTINIO_NODISCARD T transform(Input &&) const noexcept(noexcept(T{m_value}))
just_value_transformer_t(T v) noexcept(noexcept(T{std::move(v)}))
A template for implementation of clause that checks and handles presence of optional entity in the in...
RESTINIO_NODISCARD optional_t< parse_error_t > try_process(source_t &from, Target_Type &target)
maybe_clause_t(Subitems_Tuple &&subitems)
A producer for the case when a non-negative decimal number is expected in the input stream.
RESTINIO_NODISCARD expected_t< T, parse_error_t > try_parse(source_t &from) const noexcept
A producer for the case when a non-negative decimal number is expected in the input stream.
RESTINIO_NODISCARD expected_t< T, parse_error_t > try_parse(source_t &from) const noexcept
A template for implementation of clause that checks absence of some entity in the input stream.
not_clause_t(Subitems_Tuple &&subitems)
RESTINIO_NODISCARD optional_t< parse_error_t > try_process(source_t &from, Target_Type &)
A template for producing a value of specific type of a sequence of entities from the input stream.
produce_t(Subitems_Tuple &&subitems)
RESTINIO_NODISCARD expected_t< Target_Type, parse_error_t > try_parse(source_t &from)
A template for handling repetition of clauses.
RESTINIO_NODISCARD optional_t< parse_error_t > try_process(source_t &from, Target_Type &dest)
repeat_clause_t(std::size_t min_occurences, std::size_t max_occurences, Subitems_Tuple &&subitems)
A template for implementation of clause that checks and handles presence of sequence of entities in t...
RESTINIO_NODISCARD optional_t< parse_error_t > try_process(source_t &from, Target_Type &target)
A helper class to automatically return acquired content back to the input stream.
content_consumer_t(const content_consumer_t &)=delete
void commit() noexcept
Consume all acquired content.
The class that implements "input stream".
source_t(string_view_t data) noexcept
Initializing constructor.
RESTINIO_NODISCARD bool eof() const noexcept
Is EOF has been reached?
string_view_t::size_type m_index
The current position in the input stream.
RESTINIO_NODISCARD character_t getch() noexcept
Get the next character from the input stream.
void putback() noexcept
Return one character back to the input stream.
RESTINIO_NODISCARD position_t current_position() const noexcept
Get the current position in the stream.
RESTINIO_NODISCARD string_view_t fragment(string_view_t::size_type from, string_view_t::size_type length=string_view_t::npos) const noexcept
Return a fragment from the input stream.
const string_view_t m_data
The content to be used as "input stream".
void backto(position_t pos) noexcept
Return the current position in the input stream at the specified position.
string_view_t::size_type position_t
Type to be used as the index inside the input stream.
A producer for the case when a symbol should belong to specified range.
A producer for the case when a particual character is expected in the input stream.
A template for producer of charachers that satisfy some predicate.
RESTINIO_NODISCARD expected_t< char, parse_error_t > try_parse(source_t &from) const noexcept
A special class to be used as the top level clause in parser.
RESTINIO_NODISCARD auto try_process(source_t &from)
A template of producer that gets a value from another producer, transforms it and produces transforme...
RESTINIO_NODISCARD expected_t< result_type, parse_error_t > try_parse(source_t &source)
transformed_value_producer_t(Producer &&producer, Transformer &&transformer)
Information about parsing error.
Definition: easy_parser.hpp:93
RESTINIO_NODISCARD std::size_t position() const noexcept
Get the position in the input stream where error was detected.
error_reason_t m_reason
The reason of the error.
Definition: easy_parser.hpp:97
RESTINIO_NODISCARD error_reason_t reason() const noexcept
Get the reason of the error.
std::size_t m_position
Position in the input stream.
Definition: easy_parser.hpp:95
parse_error_t(std::size_t position, error_reason_t reason) noexcept
Initializing constructor.
Exception class for all exceptions thrown by RESTinio.
Definition: exception.hpp:26
Helper class for accumulating integer value during parsing it from string (with check for overflow).
Detection of compiler version and absence of various features.
#define RESTINIO_NODISCARD
Various tools for C++ metaprogramming.
bool_constant< false > false_type
Definition: optional.hpp:460
const nullopt_t nullopt((nullopt_t::init()))
std::basic_string< CharT, Traits > to_string(basic_string_view< CharT, Traits > v)
RESTINIO_NODISCARD bool operator==(const character_t &a, const character_t &b) noexcept
RESTINIO_NODISCARD string_view_t remove_trailing_spaces(string_view_t from) noexcept
Helper function for removal of trailing spaces from a string-view.
typename conversion_result_type_detector< Result_Type >::type conversion_result_type_detector_t
RESTINIO_NODISCARD expected_t< T, parse_error_t > try_parse_hexdigits_with_digits_limit(source_t &from, digits_to_consume_t digits_limit, Value_Accumulator acc) noexcept
Helper function for parsing integers in hexadecimal form.
constexpr bool is_producer_v
A meta-value to check whether T is a producer type.
constexpr char HTAB
A constant for Horizontal Tab value.
RESTINIO_NODISCARD constexpr bool is_space(const char ch) noexcept
If a character a space character?
meta::rename_t< meta::transform_t< std::decay, meta::type_list< Entities... > >, std::tuple > tuple_of_entities_t
A helper meta-function to create an actual type of tuple with clauses/producers.
RESTINIO_NODISCARD expected_t< bool, parse_error_t > try_parse_caseless_exact_fragment(source_t &from, It begin, It end)
constexpr bool is_consumer_v
A meta-value to check whether T is a consumer type.
constexpr char SP
A constant for SPACE value.
RESTINIO_NODISCARD constexpr bool is_hexdigit(const char ch) noexcept
Is a character a hexadecimal digit?
RESTINIO_NODISCARD constexpr bool is_digit(const char ch) noexcept
Is a character a decimal digit?
entity_type_t
A marker for distinguish different kind of entities in parser.
@ consumer
Entity is a consumer of values. It requires a value on the input and doesn't produces anything.
@ transformer
Entity is a transformer of a value from one type to another.
@ clause
Entity is a clause. It doesn't produces anything.
@ producer
Entity is a producer of values.
@ transformer_proxy
Entity is a transformer-proxy. It can't be used directly, only for binding a producer and transformer...
constexpr bool is_transformer_proxy_v
A meta-value to check whether T is a transformer-proxy type.
constexpr bool is_clause_v
A meta-value to check whether T is a consumer type.
RESTINIO_NODISCARD expected_t< bool, parse_error_t > try_parse_exact_fragment(source_t &from, It begin, It end)
RESTINIO_NODISCARD bool operator!=(const character_t &a, const character_t &b) noexcept
constexpr bool is_transformer_v
A meta-value to check whether T is a transformer type.
RESTINIO_NODISCARD optional_t< parse_error_t > ensure_no_remaining_content(source_t &from)
A special function to check that there is no more actual data in the input stream except whitespaces.
RESTINIO_NODISCARD std::enable_if_t< is_producer_v< P > &is_transformer_v< T >, transformed_value_producer_t< P, T > > operator>>(P producer, T transformer)
A special operator to connect a value producer with value transformer.
RESTINIO_NODISCARD expected_t< T, parse_error_t > try_parse_digits_with_digits_limit(source_t &from, digits_to_consume_t digits_limit, Value_Accumulator acc) noexcept
Helper function for parsing integers with respect to the number of digits to be consumed.
RESTINIO_NODISCARD auto symbol_from_range_p(char left, char right) noexcept
A factory function to create a symbol_from_range_producer.
RESTINIO_NODISCARD auto hexadecimal_number_p() noexcept
A factory function to create a hexadecimal_number_producer.
RESTINIO_NODISCARD auto force_only_this_alternative(Clauses &&... clauses)
An alternative that should be parsed correctly or the parsing of the whole alternatives clause should...
RESTINIO_NODISCARD auto non_negative_decimal_number_p() noexcept
A factory function to create a non_negative_decimal_number_producer.
RESTINIO_NODISCARD auto maybe(Clauses &&... clauses)
A factory function to create an optional clause.
RESTINIO_NODISCARD auto symbol(char expected) noexcept
A factory function to create a clause that expects the speficied symbol, extracts it and then skips i...
RESTINIO_NODISCARD auto sequence(Clauses &&... clauses)
A factory function to create a sequence of subclauses.
RESTINIO_NODISCARD auto space_p() noexcept
A factory function to create a space_producer.
RESTINIO_NODISCARD auto produce(Clauses &&... clauses)
A factory function to create a producer that creates an instance of the target type by using specifie...
RESTINIO_NODISCARD auto any_symbol_if_not_p(char sentinel) noexcept
A factory function to create a any_symbol_if_not_producer.
RESTINIO_NODISCARD constexpr digits_to_consume_t expected_digits(digits_to_consume_t::underlying_int_t total) noexcept
Create a limit for number of digits to be extracted.
RESTINIO_NODISCARD auto and_clause(Clauses &&... clauses)
A factory function to create an and_clause.
RESTINIO_NODISCARD auto space() noexcept
A factory function to create a clause that expects a space, extracts it and then skips it.
RESTINIO_NODISCARD auto positive_decimal_number_producer() noexcept
A factory function to create a producer for non-negative decimal numbers.
error_reason_t
Reason of parsing error.
Definition: easy_parser.hpp:52
@ unexpected_eof
Unexpected end of input is encontered when some character expected.
@ force_only_this_alternative_failed
A failure of parsing an alternative marked as "force only this alternative".
@ no_appropriate_alternative
None of alternatives was found in the input.
@ unexpected_character
Unexpected character is found in the input.
@ unconsumed_input
There are some unconsumed non-whitespace characters in the input after the completion of parsing.
@ pattern_not_found
Required pattern is not found in the input.
@ illegal_value_found
Illegal value was found in the input.
RESTINIO_NODISCARD auto digit() noexcept
A factory function to create a clause that expects a decimal digit, extracts it and then skips it.
RESTINIO_NODISCARD expected_t< typename Producer::result_type, parse_error_t > try_parse(string_view_t from, Producer producer)
Perform the parsing of the specified content by using specified value producer.
RESTINIO_NODISCARD auto repeat(std::size_t min_occurences, std::size_t max_occurences, Clauses &&... clauses)
A factory function to create repetitor of subclauses.
RESTINIO_NODISCARD auto skip() noexcept
A factory function to create a skip_consumer.
RESTINIO_NODISCARD auto caseless_exact(string_view_t fragment)
A factory function that creates an instance of caseless_exact_fragment clause.
RESTINIO_NODISCARD auto just_result(T value) noexcept(noexcept(impl::just_result_consumer_t< T >{value}))
A special consumer that replaces the produced value by a value specified by a user and sets that user...
RESTINIO_NODISCARD auto custom_consumer(F consumer)
A factory function to create a custom_consumer.
RESTINIO_NODISCARD auto digit_p() noexcept
A factory function to create a digit_producer.
RESTINIO_NODISCARD std::string make_error_description(const parse_error_t &error, string_view_t from)
Make textual description of error returned by try_parse function.
RESTINIO_NODISCARD auto exact_p(string_view_t fragment)
A factory function that creates an instance of exact_fragment_producer.
RESTINIO_NODISCARD auto exact(string_view_t fragment)
A factory function that creates an instance of exact_fragment clause.
RESTINIO_NODISCARD auto symbol_from_range(char left, char right) noexcept
A factory function to create a clause that expects a symbol from specified range, extracts it and the...
RESTINIO_NODISCARD auto caseless_symbol(char expected) noexcept
A factory function to create a clause that expects the speficied symbol, extracts it and then skips i...
RESTINIO_NODISCARD auto as_result() noexcept
A factory function to create a as_result_consumer.
constexpr std::size_t N
A special marker that means infinite repetitions.
RESTINIO_NODISCARD auto caseless_symbol_p(char expected) noexcept
A factory function to create a caseless_symbol_producer.
RESTINIO_NODISCARD auto hexdigit_p() noexcept
A factory function to create a hexdigit_producer.
RESTINIO_NODISCARD auto to_container()
A factory function to create a to_container_consumer.
RESTINIO_NODISCARD auto symbol_p(char expected) noexcept
A factory function to create a symbol_producer.
RESTINIO_NODISCARD auto not_clause(Clauses &&... clauses)
A factory function to create a not_clause.
RESTINIO_NODISCARD auto hexdigit() noexcept
A factory function to create a clause that expects a hexadecimal digit, extracts it and then skips it...
typename result_wrapper_for< T >::type result_wrapper_for_t
RESTINIO_NODISCARD auto caseless_exact_p(string_view_t fragment)
A factory function that creates an instance of caseless_exact_fragment_producer.
RESTINIO_NODISCARD auto decimal_number_p() noexcept
A factory function to create a decimal_number_producer.
RESTINIO_NODISCARD auto any_symbol_p() noexcept
A factory function to create an any_symbol_producer.
RESTINIO_NODISCARD auto to_lower() noexcept
A factory function to create a to_lower_transformer.
RESTINIO_NODISCARD auto just(T value) noexcept(noexcept(impl::just_value_transformer_t< T >{value}))
A special transformer that replaces the produced value by a value specified by a user.
RESTINIO_NODISCARD auto alternatives(Clauses &&... clauses)
A factory function to create an alternatives clause.
RESTINIO_NODISCARD auto convert(Converter &&converter)
A factory function to create convert_transformer.
RESTINIO_NODISCARD char to_lower_case(char ch)
std::string transform(string_view_t input, const params_t &params)
Do a specified zlib transformation.
Definition: zlib.hpp:878
constexpr bool all_of_v
Applies the predicate to all types from the list and return true only if all types satisty that predi...
typename impl::rename< From, To >::type rename_t
Allows to pass all template arguments from one type to another.
typename make_void< Ts... >::type void_t
typename impl::transform< Transform_F, From, type_list<> >::type transform_t
Applies a specified meta-function to every item from a specified type-list and return a new type-list...
RESTINIO_NODISCARD bool all_of(Tuple &&tuple, Predicate &&predicate)
RESTINIO_NODISCARD bool any_of(Tuple &&tuple, Predicate &&predicate)
nonstd::string_view string_view_t
Definition: string_view.hpp:19
nonstd::expected< T, E > expected_t
Definition: expected.hpp:22
STL namespace.
Helper for parsing integer values.
A predicate that allows extraction of any symbol.
RESTINIO_NODISCARD constexpr bool operator()(const char) const noexcept
A special consumer that simply throws any value away.
void consume(Target_Type &, Value &&) const noexcept
A consumer for the case when the current value should be returned as the result for the producer at o...
void consume(Target_Type &dest, Value &&src) const
A predicate for cases where the case-insensitive match of expected and actual symbols is required.
RESTINIO_NODISCARD bool operator()(const char actual) const noexcept
One character extracted from the input stream.
A special base class to be used with clauses.
static constexpr entity_type_t entity_type
A special base class to be used with consumers.
static constexpr entity_type_t entity_type
A helper template for the detection of type to be produced as conversion procedure.
A metafunction that checks is Result_Type can be used as the result of transformation method.
A predicate for cases where char to be expected to be a decimal digit.
RESTINIO_NODISCARD bool operator()(const char actual) const noexcept
A predicate for cases where char to be expected to be a hexadecimal digit.
RESTINIO_NODISCARD bool operator()(const char actual) const noexcept
A preducate for symbol_producer_template that checks that a symbol is a space.
RESTINIO_NODISCARD bool operator()(const char actual) const noexcept
A predicate for cases where mismatch with a particular symbol is required.
RESTINIO_NODISCARD bool operator()(const char actual) const noexcept
A predicate for cases where exact match of expected and actual symbols is required.
RESTINIO_NODISCARD bool operator()(const char actual) const noexcept
A special base class to be used with producers.
static constexpr entity_type_t entity_type
A special wrapper for std::array type to be used inside a producer during the parsing.
A predicate for cases where a symbol should belong to specified range.
RESTINIO_NODISCARD bool operator()(const char actual) const noexcept
A template for a consumer that stories values into a container.
A proxy for the creation of an appropriate to_lower_transformer.
RESTINIO_NODISCARD auto make_transformer() const noexcept
RESTINIO_NODISCARD result_type transform(input_type &&input) const noexcept
RESTINIO_NODISCARD base_type::result_type transform(input_type &&input) const noexcept
RESTINIO_NODISCARD result_type transform(input_type &&input) const noexcept
A helper template for checking a possibility to connect a producer with a transformer.
std::decay_t< decltype(std::declval< Producer & >().try_parse(std::declval< source_t & >())) > producer_result_t
std::decay_t< decltype(std::declval< Transformer & >().transform(std::move(*(std::declval< producer_result_t >())))) > transformation_result_t
static RESTINIO_NODISCARD expected_t< Result_Type, parse_error_t > invoke(source_t &source, Transformer &transformer, expected_t< Input_Type, parse_error_t > &&input)
A helper template for calling transformation function.
static RESTINIO_NODISCARD Result_Type invoke(source_t &, Transformer &transformer, expected_t< Input_Type, parse_error_t > &&input)
A special base class to be used with transformer-proxies.
A special base class to be used with transformers.
static constexpr entity_type_t entity_type
A consumer that stores a result value at the specified index in the result tuple.
void consume(Target_Type &&to, Value &&value)
A special type to be used in the case where there is no need to store produced value.
static void as_result(wrapped_type &, result_type &&) noexcept
static RESTINIO_NODISCARD result_type && unwrap_value(wrapped_type &v)
static void to_container(wrapped_type &, value_type &&) noexcept
static RESTINIO_NODISCARD result_type && unwrap_value(wrapped_type &v)
static void as_result(wrapped_type &to, result_type &&what)
static void to_container(wrapped_type &to, value_type &&what)
static void to_container(wrapped_type &to, wrapped_type &&what)
Special overload for the case when std::string should be added to another std::string.
static RESTINIO_NODISCARD result_type && unwrap_value(wrapped_type &v)
static void to_container(wrapped_type &to, value_type &&what)
static void as_result(wrapped_type &to, result_type &&what)
static RESTINIO_NODISCARD result_type && unwrap_value(wrapped_type &v)
static RESTINIO_NODISCARD result_type && unwrap_value(wrapped_type &v)
static void as_result(wrapped_type &to, result_type &&what)
static void to_container(wrapped_type &to, value_type &&what)
A template with specializations for different kind of result values and for type nothing.
static void as_result(wrapped_type &to, result_type &&what)
static RESTINIO_NODISCARD result_type && unwrap_value(wrapped_type &v)
A metafunction for detection of actual result_value_wrapper type for T.
The basic building block: a type for representation of a type list.
Various meta-functions for operating the content of a tuple.
#define const
Definition: zconf.h:230