diff --git a/LibHTML/CSS/Selector.cpp b/LibHTML/CSS/Selector.cpp index de7a87d1d4..bef4d1f9a5 100644 --- a/LibHTML/CSS/Selector.cpp +++ b/LibHTML/CSS/Selector.cpp @@ -1,6 +1,7 @@ #include -Selector::Selector() +Selector::Selector(Vector&& components) + : m_components(move(components)) { } diff --git a/LibHTML/CSS/Selector.h b/LibHTML/CSS/Selector.h index cc87e34653..fac4b5681a 100644 --- a/LibHTML/CSS/Selector.h +++ b/LibHTML/CSS/Selector.h @@ -5,15 +5,15 @@ class Selector { public: - Selector(); - ~Selector(); - struct Component { enum class Type { Invalid, TagName, Id, Class }; Type type { Type::Invalid }; String value; }; + explicit Selector(Vector&&); + ~Selector(); + const Vector& components() const { return m_components; } private: diff --git a/LibHTML/Parser/CSSParser.cpp b/LibHTML/Parser/CSSParser.cpp index be1c745746..4a01727f3a 100644 --- a/LibHTML/Parser/CSSParser.cpp +++ b/LibHTML/Parser/CSSParser.cpp @@ -7,5 +7,100 @@ NonnullRefPtr parse_css(const String& css) { Vector> rules; + enum class State { + Free, + InSelectorComponent, + InPropertyName, + InPropertyValue, + }; + + struct CurrentRule { + Vector selectors; + Vector declarations; + }; + + CurrentRule current_rule; + Vector buffer; + + int index = 0; + + auto peek = [&]() -> char { + if (index + 1 < css.length()) + return css[index + 1]; + return 0; + }; + + auto consume_specific = [&](char ch) { + ASSERT(peek() == ch); + ++index; + return ch; + }; + + auto consume_one = [&]() -> char { + return css[index++]; + }; + + auto consume_whitespace = [&] { + while (isspace(peek())) + ++index; + }; + + auto is_valid_selector_char = [](char ch) { + return isalnum(ch) || ch == '-' || ch == '_'; + }; + + auto parse_selector = [&] { + consume_whitespace(); + Selector::Component::Type type; + if (peek() == '.') + type = Selector::Component::Type::Class; + else if (peek() == '#') + type = Selector::Component::Type::Id; + else + type = Selector::Component::Type::TagName; + + while (is_valid_selector_char(peek())) + buffer.append(consume_one()); + + Vector components; + components.append({ type, String::copy(buffer) }); + buffer.clear(); + current_rule.selectors.append(Selector(move(components))); + }; + + auto parse_selector_list = [&] { + for (;;) { + parse_selector(); + if (peek() == ',') + continue; + if (peek() == '{') + break; + } + }; + + auto parse_declaration = [&] { + consume_whitespace(); + + }; + + auto parse_declarations = [&] { + for (;;) { + parse_declaration(); + if (peek() == '}') + break; + } + }; + + auto parse_rule = [&] { + parse_selector_list(); + consume_specific('{'); + parse_declarations(); + consume_specific('}'); + }; + + while (index < css.length()) { + parse_rule(); + } + return StyleSheet::create(move(rules)); }