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));
}