// // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Official repository: https://github.com/boostorg/url // #include #include "test_suite.hpp" #include #include namespace boost { namespace urls { namespace grammar { namespace impl { //[code_grammar_1_1 template< class Rule > auto parse( core::string_view s, Rule const& r) -> system::result< typename Rule::value_type >; template< class Rule > auto parse( char const *& it, char const* end, Rule const& r) -> system::result< typename Rule::value_type >; //] } // impl //------------------------------------------------ namespace { //[code_grammar_2_2 struct ws_chars_t { constexpr bool operator()( char c ) const noexcept { return c == '\t' || c == ' ' || c == '\r' || c == '\n'; } }; //] //[code_grammar_2_3 static_assert( is_charset< ws_chars_t >::value, "CharSet requirements not met" ); //] //[code_grammar_2_4 constexpr ws_chars_t ws_chars{}; //] //[code_grammar_2_5 core::string_view get_token( core::string_view s ) noexcept { auto it0 = s.data(); auto const end = it0 + s.size(); // find the first non-whitespace character it0 = find_if_not( it0, end, ws_chars ); if( it0 == end ) { // all whitespace or empty string return {}; } // find the next whitespace character auto it1 = find_if( it0, end, ws_chars ); // [it0, it1) is the part we want return core::string_view( it0, it1 - it0 ); } //] //[code_grammar_2_9 struct is_visible { constexpr bool operator()( char ch ) const noexcept { return ch >= 33 && ch <= 126; } }; constexpr lut_chars visible_chars( is_visible{} ); // (since C++11) //] #if __cplusplus >= 201703L namespace cpp17 { //[code_grammar_2_10 constexpr lut_chars visible_chars( [](char ch) { return ch >= 33 && ch <= 126; } ); // (since C++17) //] } // cpp17 #endif } // (anon) struct doc_grammar_test { void snippets1() { //[code_grammar_1_2 struct comma_rule_t { // The type of value returned upon success using value_type = core::string_view; // The algorithm which checks for a match system::result< value_type > parse( char const*& it, char const* end ) const { if( it != end && *it == ',') return core::string_view( it++, 1 ); return error::mismatch; } }; //] //[code_grammar_1_3 constexpr comma_rule_t comma_rule{}; //] { //[code_grammar_1_4 system::result< core::string_view > rv = parse( ",", comma_rule ); assert( rv.has_value() && rv.value() == "," ); //] } { //[code_grammar_1_5 system::result< unsigned short > rv = parse( "16384", unsigned_rule< unsigned short >{} ); //] ignore_unused(rv); } { //[code_grammar_1_6 system::result< core::string_view > rv = parse( ",", delim_rule(',') ); //] ignore_unused(rv); } } //-------------------------------------------- void snippets2() { { //[code_grammar_2_6 assert( get_token( " \t john-doe\r\n \t jane-doe\r\n") == "john-doe" ); //] } static //[code_grammar_2_7 constexpr lut_chars vowels = "AEIOU" "aeiou"; //] { //[code_grammar_2_8 constexpr auto vowels_and_y = vowels + 'y' + 'Y'; //] ignore_unused(vowels_and_y); } { //[code_grammar_2_11 constexpr auto visible_non_vowels = visible_chars - vowels; //] ignore_unused(visible_non_vowels); } { //[code_grammar_2_12 constexpr auto visible_non_vowels_or_y = visible_chars - vowels - 'y'; //] ignore_unused(visible_non_vowels_or_y); } } //-------------------------------------------- void snippets3() { { //[code_grammar_3_1 constexpr auto version_rule = tuple_rule( delim_rule( 'v' ), dec_octet_rule, delim_rule( '.' ), dec_octet_rule ); //] //[code_grammar_3_2 system::result< std::tuple< core::string_view, unsigned char, core::string_view, unsigned char > > rv = parse( "v42.44800", version_rule ); //] ignore_unused(rv); } { //[code_grammar_3_3 constexpr auto version_rule = tuple_rule( squelch( delim_rule( 'v' ) ), dec_octet_rule, squelch( delim_rule( '.' ) ), dec_octet_rule ); system::result< std::tuple< unsigned char, unsigned char > > rv = parse( "v42.44800", version_rule ); //] ignore_unused(rv); } { //[code_grammar_3_4 // port = ":" unsigned-short constexpr auto port_rule = tuple_rule( squelch( delim_rule( ':' ) ), unsigned_rule< unsigned short >{} ); system::result< unsigned short > rv = parse( ":443", port_rule ); //] ignore_unused(rv); } { //[code_grammar_3_5 // port = [ ":" unsigned-short ] constexpr auto port_rule = optional_rule( tuple_rule( squelch( delim_rule( ':' ) ), unsigned_rule< unsigned short >{} ) ); system::result< boost::optional< unsigned short > > rv = parse( ":8080", port_rule ); assert( rv->has_value() && rv->value() == 8080 ); //] } { //[code_grammar_3_6 // ipv4_address = dec-octet "." dec-octet "." dec-octet "." dec-octet // // port = ":" unsigned-short // // endpoint = ipv4_address [ port ] constexpr auto endpoint_rule = tuple_rule( tuple_rule( dec_octet_rule, squelch( delim_rule( '.' ) ), dec_octet_rule, squelch( delim_rule( '.' ) ), dec_octet_rule, squelch( delim_rule( '.' ) ), dec_octet_rule ), optional_rule( tuple_rule( squelch( delim_rule( ':' ) ), unsigned_rule< unsigned short >{} ) ) ); //] ignore_unused(endpoint_rule); } { //[code_grammar_3_7 constexpr auto endpoint_rule = tuple_rule( ipv4_address_rule, optional_rule( tuple_rule( squelch( delim_rule( ':' ) ), unsigned_rule< unsigned short >{} ) ) ); system::result< std::tuple< ipv4_address, boost::optional< unsigned short > > > rv = parse( "192.168.0.1:443", endpoint_rule ); //] ignore_unused(rv); } { //[code_grammar_3_8 constexpr auto request_target_rule = variant_rule( origin_form_rule, absolute_uri_rule, authority_rule, delim_rule('*') ); system::result< variant2::variant< url_view, url_view, authority_view, core::string_view > > rv = parse( "/results.htm?page=4", request_target_rule ); //] } } void snippets4() { { //[code_grammar_4_1 constexpr auto chunk_ext_rule = range_rule( tuple_rule( squelch( delim_rule( ';' ) ), token_rule( alnum_chars ) ) ); //] //[code_grammar_4_2 system::result< range< core::string_view > > rv = parse( ";johndoe;janedoe;end", chunk_ext_rule ); for( auto s : rv.value() ) std::cout << s << "\n"; //] } { //[code_grammar_4_3 constexpr auto token_list_rule = range_rule( token_rule( alnum_chars ), tuple_rule( squelch( delim_rule( ',' ) ), token_rule( alnum_chars ) ), 1 ); //] //[code_grammar_4_4 system::result< range< core::string_view > > rv = parse( "johndoe,janedoe,end", token_list_rule ); for( auto s : rv.value() ) std::cout << s << "\n"; //] } } void snippets5() { { core::string_view s; //[code_grammar_5_1 system::result< pct_string_view > rv = parse( s, pct_encoded_rule( pchars ) ); //] ignore_unused(rv); } { //[code_grammar_5_2 // request-line = method SP request-target SP HTTP-version CRLF constexpr auto request_line_rule = tuple_rule( not_empty_rule( token_rule( alpha_chars ) ), // method squelch( delim_rule( ' ' ) ), // SP variant_rule( absolute_uri_rule, // absolute-uri or relative_ref_rule), // relative-ref squelch( delim_rule( ' ' ) ), squelch( literal_rule( "HTTP/" ) ), // "HTTP/" delim_rule( digit_chars ), // DIGIT squelch( delim_rule( '.' ) ), // "." delim_rule( digit_chars ), // DIGIT squelch( literal_rule( "\r\n" ) ) ); // CRLF //] ignore_unused(request_line_rule); } } void run() { snippets1(); snippets2(); snippets3(); snippets4(); } }; TEST_SUITE( doc_grammar_test, "boost.url.doc.grammar"); } // grammar } // urls } // boost