Меня, честно говоря, за последние пару недель основательно подзадолбали наезды на C++. Мол, страх и ужас, давным-давно свернул не туда, понадобавляли в новые стандарты всякой херни, комитет работает как бешеный принтер, комитет нихера не делает и пр., и пр.
Иногда складывается впечатление, что эти стенания повсюду. Особенно на профильных ресурсах, типа Reddit, LOR, RSDN (может и на Хабре, но до Хабра сейчас просто уже руки не доходят).
Финальным гвоздем стали очередные вбросы в Telegram канале C++ Russia от известного своим праздным звездежом хаскелиста Александра Гранина, у которого, походу, второй натурой стал троллинг C++а и C++ников. С традиционным уже участием на C++ Russia с докладом про функциональщину.
В общем, послушать активно испражняющихся в Интернетах специалистов по всем вопросам на свете и может показаться, что хуже C++ только мучительная смерть от бубонной чумы. Да и то не факт.
В тоже самое время этот самый современный C++, в который, как искренне верят неасиляторы, напихали всякой ненужной чуйни, лично мне позволяет в декларативном виде записывать в коде ABNF грамматики из RFC по HTTP/1.1.
Причем это даже не самый еще современный C++, а всего лишь C++14.
И что-то мне подсказывает, что сделать подобное на каких-то "типа альтернативах" C++ будет не так уж и просто. Особенно с учетом накладных расходов в run-time. Если вообще возможно.
Ну а вот и сам упомянутый фрагмент. Который отвечает за парсинг содержимого HTTP-заголовка Transfer-Encoding согласно спецификации.
/*! * This struct represents parsed value of HTTP-field Transfer-Encoding * (see https://tools.ietf.org/html/rfc7230#section-3.3.1 and * https://tools.ietf.org/html/rfc7230#section-4): @verbatim Transfer-Encoding = 1#transfer-coding transfer-coding = "chunked" / "compress" / "deflate" / ("gzip" | "x-gzip") / transfer-extension transfer-extension = token *( OWS ";" OWS transfer-parameter ) transfer-parameter = token BWS "=" BWS ( token / quoted-string ) @endverbatim */ static auto make_parser() { return produce< transfer_encoding_value_t >( non_empty_comma_separated_list_p< value_container_t >( produce< value_t >( alternatives( expected_caseless_token_p("chunked") >> just_result(chunked), expected_caseless_token_p("compress") >> just_result(compress), expected_caseless_token_p("deflate") >> just_result(deflate), expected_caseless_token_p("gzip") >> just_result(gzip), expected_caseless_token_p("x-gzip") >> just_result(gzip), produce< transfer_extension_t >( token_p() >> to_lower() >> &transfer_extension_t::token, params_with_value_p() >> &transfer_extension_t::transfer_parameters ) >> as_result() ) ) ) >> &transfer_encoding_value_t::values ); } |
Где transfer_encoding_value_t и пр. вещи описываются следующей структурой:
struct transfer_encoding_value_t { //! Enumeration for transfer-coding values from RFC7230. enum class known_transfer_coding_t { chunked, compress, deflate, gzip, }; static constexpr known_transfer_coding_t chunked = known_transfer_coding_t::chunked; static constexpr known_transfer_coding_t compress = known_transfer_coding_t::compress; static constexpr known_transfer_coding_t deflate = known_transfer_coding_t::deflate; static constexpr known_transfer_coding_t gzip = known_transfer_coding_t::gzip; //! Description of transfer-extension. struct transfer_extension_t { std::string token; parameter_with_mandatory_value_container_t transfer_parameters; RESTINIO_NODISCARD bool operator==( const transfer_extension_t & o ) const noexcept { return std::tie(this->token, this->transfer_parameters) == std::tie(o.token, o.transfer_parameters); } }; //! Type for one value from Transfer-Encoding HTTP-field. using value_t = variant_t< known_transfer_coding_t, transfer_extension_t >; using value_container_t = std::vector< value_t >; value_container_t values; }; |
Да ну, это похоже на монадные парсер-комбинаторы, которые только ленивый не делал на всем подряд. И с таким количеством скобок и знаков препинания, что можно лишь насмехаться.
ОтветитьУдалитьТем временем на "альтернативах С++" можно взять именно вариант BNF, как у вас в комменте выше, отдать его библиотечной ф-ии, она в компайл-тайме распарсит и построит парсер, который можно использовать как в рантайме, так и в компайл-тайме тут же. https://github.com/PhilippeSigaud/Pegged
@Dmitry Popov
ОтветитьУдалитьЯ еще застал C++, в котором не то что шаблонов. Но и исключений с пространствами имен не было. И подобные вещи, которые могут казаться до смешного убогими, в том C++ даже на уровне фантастики представить себе нельзя было.
А вот сейчас можно. И это всего лишь C++14.
Так что не удивлюсь, если лет через 10-15 на C++ будут делать то, что сейчас кажется совсем невероятным.
А вот будет ли D нужен кому-то через 10 лет... Вот это вопрос.
Ну Boost Spirit еще с начала 2000-х существует... Сейчас, наверное, проще стало такие штуки делать.
ОтветитьУдалитьДля меня что Boost.Spirit, что Boost.Lambda в свое время были проектами, которые показывают, что в принципе можно сделать, но что делать в принципе не следует. Хотя, конечно, если бы не проекты подобного рода, то C++ до своего сегодняшнего уровня мог бы и не развиться.
ОтветитьУдалить