1 /*
2 Copyright (C) 2016-2017 Alexander Borisov
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Author: lex.borisov@gmail.com (Alexander Borisov)
19 */
20
21 #include "mycss/selectors/parser.h"
22 #include "mycss/selectors/value_resource.h"
23
24 /////////////////////////////////////////////////////////
25 //// Selectors Begin
26 ////
27 /////////////////////////////////////////////////////////
mycss_selectors_parser_selector_begin(mycss_entry_t * entry,mycss_token_t * token)28 void mycss_selectors_parser_selector_begin(mycss_entry_t* entry, mycss_token_t* token)
29 {
30 mycss_selectors_entry_t *selector = mycss_selectors_entry_create(entry->selectors);
31 mycss_selectors_entry_append_to_current(entry->selectors, selector);
32 }
33
34 /////////////////////////////////////////////////////////
35 //// Selector type
36 ////
37 /////////////////////////////////////////////////////////
mycss_selectors_parser_selector_ident_type(mycss_entry_t * entry,mycss_token_t * token)38 void mycss_selectors_parser_selector_ident_type(mycss_entry_t* entry, mycss_token_t* token)
39 {
40 mycss_selectors_entry_t *selector = entry->selectors->entry_last;
41
42 mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
43 mycss_token_data_to_string(entry, token, str, true, false);
44
45 /* set default namespace */
46 if(entry->stylesheet)
47 selector->ns_entry = entry->stylesheet->ns_stylesheet.entry_default;
48
49 selector->type = MyCSS_SELECTORS_TYPE_ELEMENT;
50 selector->key = str;
51
52 if(entry->selectors->specificity)
53 if(str->length != 1 || *str->data != '*')
54 entry->selectors->specificity->c++;
55 }
56
mycss_selectors_parser_selector_ident_attr(mycss_entry_t * entry,mycss_token_t * token)57 void mycss_selectors_parser_selector_ident_attr(mycss_entry_t* entry, mycss_token_t* token)
58 {
59 mycss_selectors_entry_t *selector = entry->selectors->entry_last;
60
61 mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
62 mycss_token_data_to_string(entry, token, str, true, false);
63
64 /* set default namespace */
65 if(entry->stylesheet)
66 selector->ns_entry = entry->stylesheet->ns_stylesheet.entry_default;
67
68 selector->type = MyCSS_SELECTORS_TYPE_ATTRIBUTE;
69 selector->key = str;
70
71 if(entry->selectors->specificity)
72 if(str->length != 1 || *str->data != '*')
73 entry->selectors->specificity->b++;
74 }
75
mycss_selectors_parser_selector_id(mycss_entry_t * entry,mycss_token_t * token)76 void mycss_selectors_parser_selector_id(mycss_entry_t* entry, mycss_token_t* token)
77 {
78 mycss_selectors_entry_t *selector = entry->selectors->entry_last;
79
80 mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
81 mycss_token_data_to_string(entry, token, str, true, false);
82
83 /* set default namespace */
84 if(entry->stylesheet)
85 selector->ns_entry = entry->stylesheet->ns_stylesheet.entry_default;
86
87 selector->type = MyCSS_SELECTORS_TYPE_ID;
88 selector->key = str;
89
90 if(entry->selectors->specificity)
91 entry->selectors->specificity->a++;
92
93 mycss_selectors_parser_selector_end(entry, token);
94 }
95
mycss_selectors_parser_selector_class(mycss_entry_t * entry,mycss_token_t * token)96 void mycss_selectors_parser_selector_class(mycss_entry_t* entry, mycss_token_t* token)
97 {
98 mycss_selectors_entry_t *selector = entry->selectors->entry_last;
99
100 mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
101 mycss_token_data_to_string(entry, token, str, true, false);
102
103 /* set default namespace */
104 if(entry->stylesheet)
105 selector->ns_entry = entry->stylesheet->ns_stylesheet.entry_default;
106
107 selector->type = MyCSS_SELECTORS_TYPE_CLASS;
108 selector->key = str;
109
110 if(entry->selectors->specificity)
111 entry->selectors->specificity->b++;
112
113 mycss_selectors_parser_selector_end(entry, token);
114 }
115
116 /////////////////////////////////////////////////////////
117 //// Namespace
118 ////
119 /////////////////////////////////////////////////////////
mycss_selectors_parser_selector_namespace(mycss_entry_t * entry,mycss_token_t * token)120 void mycss_selectors_parser_selector_namespace(mycss_entry_t* entry, mycss_token_t* token)
121 {
122 mycss_selectors_entry_t *selector = entry->selectors->entry_last;
123 mycore_string_t *str = selector->key;
124
125 if(str == NULL || str->length == 0) {
126 mycore_string_destroy(str, 0);
127
128 selector->key = NULL;
129
130 if(entry->stylesheet)
131 selector->ns_entry = &entry->stylesheet->ns_stylesheet.entry_undef;
132
133 return;
134 }
135
136 if(str->length == 1 && *str->data == '*') {
137 mycore_string_destroy(str, 0);
138
139 selector->key = NULL;
140
141 if(entry->stylesheet)
142 selector->ns_entry = &entry->stylesheet->ns_stylesheet.entry_any;
143
144 return;
145 }
146
147 if(entry->stylesheet)
148 selector->ns_entry = mycss_namespace_entry_by_name(entry->ns, entry->stylesheet->ns_stylesheet.name_tree, str->data, str->length, false);
149
150 if(selector->ns_entry == NULL)
151 mycss_selectors_parser_expectations_error(entry, token);
152
153 mycore_string_destroy(str, 0);
154 selector->key = NULL;
155 }
156
mycss_selectors_parser_selector_namespace_ident(mycss_entry_t * entry,mycss_token_t * token)157 void mycss_selectors_parser_selector_namespace_ident(mycss_entry_t* entry, mycss_token_t* token)
158 {
159 mycss_selectors_entry_t *selector = entry->selectors->entry_last;
160
161 mycss_selectors_parser_selector_namespace(entry, token);
162
163 if(selector->type == MyCSS_SELECTORS_TYPE_UNDEF)
164 selector->type = MyCSS_SELECTORS_TYPE_ELEMENT;
165 }
166
mycss_selectors_parser_selector_namespace_attr(mycss_entry_t * entry,mycss_token_t * token)167 void mycss_selectors_parser_selector_namespace_attr(mycss_entry_t* entry, mycss_token_t* token)
168 {
169 mycss_selectors_entry_t *selector = entry->selectors->entry_last;
170
171 mycss_selectors_parser_selector_namespace(entry, token);
172
173 if(selector->type == MyCSS_SELECTORS_TYPE_UNDEF)
174 selector->type = MyCSS_SELECTORS_TYPE_ATTRIBUTE;
175 }
176
mycss_selectors_parser_selector_after_namespace(mycss_entry_t * entry,mycss_token_t * token)177 void mycss_selectors_parser_selector_after_namespace(mycss_entry_t* entry, mycss_token_t* token)
178 {
179 mycss_selectors_entry_t *selector = entry->selectors->entry_last;
180
181 mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
182 mycss_token_data_to_string(entry, token, str, true, true);
183
184 selector->key = str;
185
186 if(entry->selectors->specificity) {
187 if(selector->ns_entry == &entry->stylesheet->ns_stylesheet.entry_any) {
188 if(selector->type == MyCSS_SELECTORS_TYPE_ATTRIBUTE)
189 entry->selectors->specificity->b--;
190 else
191 entry->selectors->specificity->c--;
192 }
193
194 if(str->length != 1 || *str->data != '*') {
195 if(selector->type == MyCSS_SELECTORS_TYPE_ATTRIBUTE)
196 entry->selectors->specificity->b++;
197 else
198 entry->selectors->specificity->c++;
199 }
200 }
201 }
202
203 /////////////////////////////////////////////////////////
204 //// Value and Modifier
205 ////
206 /////////////////////////////////////////////////////////
mycss_selectors_parser_selector_value(mycss_entry_t * entry,mycss_token_t * token)207 void mycss_selectors_parser_selector_value(mycss_entry_t* entry, mycss_token_t* token)
208 {
209 mycss_selectors_entry_t *selector = entry->selectors->entry_last;
210 mycss_selectors_object_attribute_t *attr = selector->value;
211
212 mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
213 mycss_token_data_to_string(entry, token, str, true, false);
214
215 attr->value = str;
216 }
217
mycss_selectors_parser_selector_modifier(mycss_entry_t * entry,mycss_token_t * token)218 void mycss_selectors_parser_selector_modifier(mycss_entry_t* entry, mycss_token_t* token)
219 {
220 mycss_selectors_entry_t *selector = entry->selectors->entry_last;
221 mycss_selector_value_attribute(selector->value)->mod = MyCSS_SELECTORS_MOD_I;
222 }
223
224 /////////////////////////////////////////////////////////
225 //// Pseudo Class
226 ////
227 /////////////////////////////////////////////////////////
mycss_selectors_parser_selector_pseudo_class(mycss_entry_t * entry,mycss_token_t * token)228 void mycss_selectors_parser_selector_pseudo_class(mycss_entry_t* entry, mycss_token_t* token)
229 {
230 mycss_selectors_entry_t *selector = entry->selectors->entry_last;
231
232 mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
233 mycss_token_data_to_string(entry, token, str, true, true);
234
235 selector->sub_type = mycss_pseudo_class_by_name(str->data, str->length);
236 selector->key = str;
237 selector->type = MyCSS_SELECTORS_TYPE_PSEUDO_CLASS;
238
239 /* hack for elements */
240 if(selector->sub_type == MyCSS_SELECTORS_SUB_TYPE_PSEUDO_CLASS_UNKNOWN) {
241 selector->sub_type = mycss_pseudo_element_by_name(str->data, str->length);
242
243 if(selector->sub_type == MyCSS_SELECTORS_SUB_TYPE_PSEUDO_ELEMENT_UNKNOWN) {
244 selector->flags |= MyCSS_SELECTORS_FLAGS_SELECTOR_BAD;
245 }
246 else {
247 selector->type = MyCSS_SELECTORS_TYPE_PSEUDO_ELEMENT;
248 }
249 }
250
251 if(selector->type == MyCSS_SELECTORS_TYPE_PSEUDO_ELEMENT) {
252 if(entry->selectors->specificity)
253 entry->selectors->specificity->c++;
254 } else {
255 if(entry->selectors->specificity)
256 entry->selectors->specificity->b++;
257 }
258
259 mycss_selectors_parser_check_and_set_bad_parent_selector(entry, entry->selectors->list_last);
260 mycss_selectors_parser_selector_end(entry, token);
261 }
262
mycss_selectors_parser_selector_pseudo_class_function(mycss_entry_t * entry,mycss_token_t * token)263 void mycss_selectors_parser_selector_pseudo_class_function(mycss_entry_t* entry, mycss_token_t* token)
264 {
265 mycss_selectors_entry_t *selector = entry->selectors->entry_last;
266
267 mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
268 mycss_token_data_to_string(entry, token, str, true, true);
269
270 selector->key = str;
271 selector->type = MyCSS_SELECTORS_TYPE_PSEUDO_CLASS_FUNCTION;
272
273 entry->parser_ending_token = MyCSS_TOKEN_TYPE_RIGHT_PARENTHESIS;
274 mycss_entry_parser_list_push(entry, mycss_selectors_state_simple_selector_colon_function, entry->parser_switch, entry->selectors->ending_token, false);
275
276 if(entry->selectors->specificity)
277 entry->selectors->specificity->b++;
278
279 mycss_selectors_function_begin_f to_func = mycss_function_begin_by_name(str->data, str->length);
280
281 if(to_func) {
282 to_func(entry, selector);
283 }
284 else {
285 /* skip and set bad type for current selector */
286 selector->flags |= MyCSS_SELECTORS_FLAGS_SELECTOR_BAD;
287
288 if(entry->selectors->list_last)
289 entry->selectors->list_last->flags |= MyCSS_SELECTORS_FLAGS_SELECTOR_BAD;
290
291 mycss_selectors_begin_unknown(entry, selector);
292 }
293 }
294
mycss_selectors_parser_selector_pseudo_class_function_end(mycss_entry_t * entry,mycss_token_t * token)295 void mycss_selectors_parser_selector_pseudo_class_function_end(mycss_entry_t* entry, mycss_token_t* token)
296 {
297 entry->selectors->ending_token = entry->parser_ending_token;
298
299 mycss_selectors_parser_check_and_set_bad_parent_selector(entry, entry->selectors->list_last);
300 mycss_selectors_parser_selector_end(entry, token);
301 }
302
303 /////////////////////////////////////////////////////////
304 //// Pseudo Element
305 ////
306 /////////////////////////////////////////////////////////
mycss_selectors_parser_selector_pseudo_element(mycss_entry_t * entry,mycss_token_t * token)307 void mycss_selectors_parser_selector_pseudo_element(mycss_entry_t* entry, mycss_token_t* token)
308 {
309 mycss_selectors_entry_t *selector = entry->selectors->entry_last;
310
311 mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
312 mycss_token_data_to_string(entry, token, str, true, true);
313
314 selector->key = str;
315 selector->type = MyCSS_SELECTORS_TYPE_PSEUDO_ELEMENT;
316
317 selector->sub_type = mycss_pseudo_element_by_name(str->data, str->length);
318
319 if(selector->sub_type == MyCSS_SELECTORS_SUB_TYPE_PSEUDO_ELEMENT_UNKNOWN)
320 selector->flags |= MyCSS_SELECTORS_FLAGS_SELECTOR_BAD;
321
322 if(entry->selectors->specificity)
323 entry->selectors->specificity->c++;
324
325 mycss_selectors_parser_check_and_set_bad_parent_selector(entry, entry->selectors->list_last);
326 mycss_selectors_parser_selector_end(entry, token);
327 }
328
mycss_selectors_parser_selector_pseudo_element_function(mycss_entry_t * entry,mycss_token_t * token)329 void mycss_selectors_parser_selector_pseudo_element_function(mycss_entry_t* entry, mycss_token_t* token)
330 {
331 mycss_selectors_entry_t *selector = entry->selectors->entry_last;
332
333 mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
334 mycss_token_data_to_string(entry, token, str, true, true);
335
336 selector->key = str;
337 selector->type = MyCSS_SELECTORS_TYPE_PSEUDO_ELEMENT_FUNCTION;
338
339 selector->flags |= MyCSS_SELECTORS_FLAGS_SELECTOR_BAD;
340 mycss_selectors_begin_unknown(entry, selector);
341
342 if(entry->selectors->specificity)
343 entry->selectors->specificity->c++;
344 }
345
mycss_selectors_parser_selector_pseudo_element_function_end(mycss_entry_t * entry,mycss_token_t * token)346 void mycss_selectors_parser_selector_pseudo_element_function_end(mycss_entry_t* entry, mycss_token_t* token)
347 {
348 mycss_selectors_parser_check_and_set_bad_parent_selector(entry, entry->selectors->list_last);
349 mycss_selectors_parser_selector_end(entry, token);
350 }
351
352 /////////////////////////////////////////////////////////
353 //// End and bad selectors
354 ////
355 /////////////////////////////////////////////////////////
mycss_selectors_parser_selector_end(mycss_entry_t * entry,mycss_token_t * token)356 void mycss_selectors_parser_selector_end(mycss_entry_t* entry, mycss_token_t* token)
357 {
358 mycss_selectors_entry_t *selector = entry->selectors->entry_last;
359
360 if(entry->callback_selector_done)
361 entry->callback_selector_done(entry->selectors, selector);
362 }
363
mycss_selectors_parser_expectations_error(mycss_entry_t * entry,mycss_token_t * token)364 void mycss_selectors_parser_expectations_error(mycss_entry_t* entry, mycss_token_t* token)
365 {
366 mycss_selectors_t *selectors = entry->selectors;
367
368 selectors->entry_last->flags |= MyCSS_SELECTORS_FLAGS_SELECTOR_BAD;
369
370 if(entry->selectors->list_last)
371 entry->selectors->list_last->flags |= MyCSS_SELECTORS_FLAGS_SELECTOR_BAD;
372 }
373
mycss_selectors_parser_bad_token(mycss_entry_t * entry,mycss_token_t * token)374 void mycss_selectors_parser_bad_token(mycss_entry_t* entry, mycss_token_t* token)
375 {
376 mycss_selectors_entry_t *selector = entry->selectors->entry_last;
377
378 if((selector->flags & MyCSS_SELECTORS_FLAGS_SELECTOR_BAD) == 0) {
379 selector->flags |= MyCSS_SELECTORS_FLAGS_SELECTOR_BAD;
380
381 mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
382 selector->key = str;
383
384 mycss_token_data_to_string(entry, token, selector->key, true, false);
385 return;
386 }
387
388 mycss_token_data_to_string(entry, token, selector->key, false, false);
389 }
390
391 /////////////////////////////////////////////////////////
392 //// Set bad
393 ////
394 /////////////////////////////////////////////////////////
mycss_selectors_parser_check_and_set_bad_parent_selector(mycss_entry_t * entry,mycss_selectors_list_t * selectors_list)395 void mycss_selectors_parser_check_and_set_bad_parent_selector(mycss_entry_t* entry, mycss_selectors_list_t* selectors_list)
396 {
397 mycss_selectors_list_t *list = entry->selectors->list_last;
398
399 if(list && entry->selectors->entry_last->flags & MyCSS_SELECTORS_FLAGS_SELECTOR_BAD)
400 {
401 if((list->flags & MyCSS_SELECTORS_FLAGS_SELECTOR_BAD) == 0)
402 list->flags |= MyCSS_SELECTORS_FLAGS_SELECTOR_BAD;
403 }
404 }
405
406
407