123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- /*-
- * Copyright 2021 Vsevolod Stakhov
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- #pragma once
-
- #ifndef RSPAMD_CSS_PARSER_HXX
- #define RSPAMD_CSS_PARSER_HXX
-
- #include <variant>
- #include <vector>
- #include <memory>
- #include <string>
-
- #include "function2/function2.hpp"
- #include "css_tokeniser.hxx"
- #include "parse_error.hxx"
- #include "contrib/expected/expected.hpp"
- #include "logger.h"
-
-
- namespace rspamd::css {
-
- /*
- * Represents a consumed token by a parser
- */
- class css_consumed_block {
- public:
- enum class parser_tag_type : std::uint8_t {
- css_top_block = 0,
- css_qualified_rule,
- css_at_rule,
- css_simple_block,
- css_function,
- css_function_arg,
- css_component,
- css_eof_block,
- };
- using consumed_block_ptr = std::unique_ptr<css_consumed_block>;
-
- struct css_function_block {
- css_parser_token function;
- std::vector<consumed_block_ptr> args;
-
- css_function_block(css_parser_token &&tok) :
- function(std::forward<css_parser_token>(tok)) {}
-
- auto as_string() const -> std::string_view {
- return function.get_string_or_default("");
- }
-
- static auto empty_function() -> const css_function_block & {
- static const css_function_block invalid(
- css_parser_token(css_parser_token::token_type::eof_token,
- css_parser_token_placeholder()));
- return invalid;
- }
- };
-
- css_consumed_block() : tag(parser_tag_type::css_eof_block) {}
- css_consumed_block(parser_tag_type tag) : tag(tag) {
- if (tag == parser_tag_type::css_top_block ||
- tag == parser_tag_type::css_qualified_rule ||
- tag == parser_tag_type::css_simple_block) {
- /* Pre-allocate content for known vector blocks */
- std::vector<consumed_block_ptr> vec;
- vec.reserve(4);
- content = std::move(vec);
- }
- }
- /* Construct a block from a single lexer token (for trivial blocks) */
- explicit css_consumed_block(parser_tag_type tag, css_parser_token &&tok) :
- tag(tag) {
- if (tag == parser_tag_type::css_function) {
- content = css_function_block{std::move(tok)};
- }
- else {
- content = std::move(tok);
- }
- }
-
- /* Attach a new block to the compound block, consuming block inside */
- auto attach_block(consumed_block_ptr &&block) -> bool;
- /* Attach a new argument to the compound function block, consuming block inside */
- auto add_function_argument(consumed_block_ptr &&block) -> bool;
-
- auto assign_token(css_parser_token &&tok) -> void {
- content = std::move(tok);
- }
-
- /* Empty blocks used to avoid type checks in loops */
- const inline static std::vector<consumed_block_ptr> empty_block_vec{};
-
- auto is_blocks_vec() const -> bool {
- return (std::holds_alternative<std::vector<consumed_block_ptr>>(content));
- }
-
- auto get_blocks_or_empty() const -> const std::vector<consumed_block_ptr>& {
- if (is_blocks_vec()) {
- return std::get<std::vector<consumed_block_ptr>>(content);
- }
-
- return empty_block_vec;
- }
-
- auto is_token() const -> bool {
- return (std::holds_alternative<css_parser_token>(content));
- }
-
- auto get_token_or_empty() const -> const css_parser_token& {
- if (is_token()) {
- return std::get<css_parser_token>(content);
- }
-
- return css_parser_eof_token();
- }
-
- auto is_function() const -> bool {
- return (std::holds_alternative<css_function_block>(content));
- }
-
- auto get_function_or_invalid() const -> const css_function_block& {
- if (is_function()) {
- return std::get<css_function_block>(content);
- }
-
- return css_function_block::empty_function();
- }
-
- auto size() const -> std::size_t {
- auto ret = 0;
-
- std::visit([&](auto& arg) {
- using T = std::decay_t<decltype(arg)>;
-
- if constexpr (std::is_same_v<T, std::vector<consumed_block_ptr>>) {
- /* Array of blocks */
- ret = arg.size();
- }
- else if constexpr (std::is_same_v<T, std::monostate>) {
- /* Empty block */
- ret = 0;
- }
- else {
- /* Single element block */
- ret = 1;
- }
- },
- content);
-
- return ret;
- }
-
- auto is_eof() -> bool {
- return tag == parser_tag_type::css_eof_block;
- }
-
- /* Debug methods */
- auto token_type_str(void) const -> const char *;
- auto debug_str(void) -> std::string;
-
- public:
- parser_tag_type tag;
- private:
- std::variant<std::monostate,
- std::vector<consumed_block_ptr>,
- css_parser_token,
- css_function_block> content;
- };
-
- extern const css_consumed_block css_parser_eof_block;
-
- using blocks_gen_functor = fu2::unique_function<const css_consumed_block &(void)>;
-
- class css_style_sheet;
- auto parse_css(rspamd_mempool_t *pool, const std::string_view &st) ->
- tl::expected<std::unique_ptr<css_style_sheet>, css_parse_error>;
-
- auto get_selectors_parser_functor(rspamd_mempool_t *pool,
- const std::string_view &st) -> blocks_gen_functor;
-
- }
-
- #endif //RSPAMD_CSS_PARSER_HXX
|