3
3
#include < ctype.h>
4
4
#include < stdio.h>
5
5
6
+ #define PARSE_ASSERT (x ) \
7
+ if (!(x)) { \
8
+ dbg () << " CSS PARSER ASSERTION FAILED: " << #x; \
9
+ dbg () << " At character# " << index << " in CSS: _" << css << " _" ; \
10
+ ASSERT_NOT_REACHED (); \
11
+ }
12
+
6
13
static Optional<Color> parse_css_color (const StringView& view)
7
14
{
8
15
auto color = Color::from_string (view);
@@ -53,7 +60,7 @@ class CSSParser {
53
60
54
61
char consume_specific (char ch)
55
62
{
56
- ASSERT (peek () == ch);
63
+ PARSE_ASSERT (peek () == ch);
57
64
++index;
58
65
return ch;
59
66
}
@@ -71,13 +78,23 @@ class CSSParser {
71
78
72
79
bool is_valid_selector_char (char ch) const
73
80
{
74
- return isalnum (ch) || ch == ' -' || ch == ' _' ;
81
+ return isalnum (ch) || ch == ' -' || ch == ' _' || ch == ' ( ' || ch == ' ) ' || ch == ' @ ' ;
75
82
}
76
83
77
- void parse_selector ()
84
+ Optional<Selector::Component> parse_selector_component ()
78
85
{
79
86
consume_whitespace ();
80
87
Selector::Component::Type type;
88
+ Selector::Component::Relation relation = Selector::Component::Relation::None;
89
+
90
+ if (peek () == ' {' )
91
+ return {};
92
+
93
+ if (peek () == ' >' ) {
94
+ relation = Selector::Component::Relation::ImmediateChild;
95
+ consume_one ();
96
+ consume_whitespace ();
97
+ }
81
98
82
99
if (peek () == ' .' ) {
83
100
type = Selector::Component::Type::Class;
@@ -92,13 +109,43 @@ class CSSParser {
92
109
while (is_valid_selector_char (peek ()))
93
110
buffer.append (consume_one ());
94
111
95
- ASSERT (!buffer.is_null ());
112
+ PARSE_ASSERT (!buffer.is_null ());
113
+ Selector::Component component { type, relation, String::copy (buffer) };
114
+ buffer.clear ();
115
+
116
+ if (peek () == ' [' ) {
117
+ // FIXME: Implement attribute selectors.
118
+ while (peek () != ' ]' ) {
119
+ consume_one ();
120
+ }
121
+ consume_one ();
122
+ }
96
123
97
- auto component_string = String::copy (buffer);
124
+ if (peek () == ' :' ) {
125
+ // FIXME: Implement pseudo stuff.
126
+ consume_one ();
127
+ if (peek () == ' :' )
128
+ consume_one ();
129
+ while (is_valid_selector_char (peek ()))
130
+ consume_one ();
131
+ }
98
132
133
+ return component;
134
+ }
135
+
136
+ void parse_selector ()
137
+ {
99
138
Vector<Selector::Component> components;
100
- components.append ({ type, component_string });
101
- buffer.clear ();
139
+
140
+ for (;;) {
141
+ auto component = parse_selector_component ();
142
+ if (component.has_value ())
143
+ components.append (component.value ());
144
+ consume_whitespace ();
145
+ if (peek () == ' ,' || peek () == ' {' )
146
+ break ;
147
+ }
148
+
102
149
current_rule.selectors .append (Selector (move (components)));
103
150
};
104
151
@@ -123,12 +170,16 @@ class CSSParser {
123
170
124
171
bool is_valid_property_value_char (char ch) const
125
172
{
126
- return ! isspace (ch) && ch != ' ;' ;
173
+ return ch != ' ! ' && ch != ' ;' ;
127
174
}
128
175
129
- void parse_property ()
176
+ Optional<StyleProperty> parse_property ()
130
177
{
131
178
consume_whitespace ();
179
+ if (peek () == ' ;' ) {
180
+ consume_one ();
181
+ return {};
182
+ }
132
183
buffer.clear ();
133
184
while (is_valid_property_name_char (peek ()))
134
185
buffer.append (consume_one ());
@@ -141,14 +192,32 @@ class CSSParser {
141
192
buffer.append (consume_one ());
142
193
auto property_value = String::copy (buffer);
143
194
buffer.clear ();
195
+ consume_whitespace ();
196
+ bool is_important = false ;
197
+ if (peek () == ' !' ) {
198
+ consume_specific (' !' );
199
+ consume_specific (' i' );
200
+ consume_specific (' m' );
201
+ consume_specific (' p' );
202
+ consume_specific (' o' );
203
+ consume_specific (' r' );
204
+ consume_specific (' t' );
205
+ consume_specific (' a' );
206
+ consume_specific (' n' );
207
+ consume_specific (' t' );
208
+ consume_whitespace ();
209
+ is_important = true ;
210
+ }
144
211
consume_specific (' ;' );
145
- current_rule. properties . append ( { property_name, parse_css_value (property_value) }) ;
212
+ return StyleProperty { property_name, parse_css_value (property_value), is_important } ;
146
213
}
147
214
148
215
void parse_declaration ()
149
216
{
150
217
for (;;) {
151
- parse_property ();
218
+ auto property = parse_property ();
219
+ if (property.has_value ())
220
+ current_rule.properties .append (property.value ());
152
221
consume_whitespace ();
153
222
if (peek () == ' }' )
154
223
break ;
0 commit comments