1 /*
2 * Copyright (C) 2020-2022 Alexander Borisov
3 *
4 * Author: Alexander Borisov <borisov@lexbor.com>
5 */
6
7 #include "lexbor/css/parser.h"
8 #include "lexbor/css/css.h"
9 #include "lexbor/css/selectors/selectors.h"
10 #include "lexbor/css/selectors/pseudo.h"
11 #include "lexbor/css/selectors/pseudo_const.h"
12
13
14 static const char lxb_css_selectors_module_name[] = "Selectors";
15
16
17 #define lxb_css_selectors_state_string_dup_m(selectors, name) \
18 do { \
19 (status) = lxb_css_syntax_token_string_dup( \
20 lxb_css_syntax_token_string(token), (name), \
21 (parser)->memory->mraw); \
22 if ((status) != LXB_STATUS_OK) { \
23 return (status); \
24 } \
25 } \
26 while (false)
27
28 #define lxb_css_selectors_state_append(parser, selectors, selector) \
29 do { \
30 (selector) = lxb_css_selector_create((selectors)->list_last); \
31 if ((selector) == NULL) { \
32 return lxb_css_parser_memory_fail(parser); \
33 } \
34 \
35 lxb_css_selectors_append_next((selectors), (selector)); \
36 \
37 (selector)->combinator = (selectors)->combinator; \
38 (selectors)->combinator = LXB_CSS_SELECTOR_COMBINATOR_CLOSE; \
39 } \
40 while (false)
41
42 #define lxb_css_selectors_state_list_append(parser, selectors, list) \
43 do { \
44 (list) = lxb_css_selector_list_create((parser)->memory); \
45 if ((list) == NULL) { \
46 return lxb_css_parser_memory_fail(parser); \
47 } \
48 \
49 lxb_css_selectors_list_append_next((selectors), (list)); \
50 \
51 (list)->parent = selectors->parent; \
52 } \
53 while (false)
54
55
56 static bool
57 lxb_css_selectors_state_complex_list_end(lxb_css_parser_t *parser,
58 const lxb_css_syntax_token_t *token,
59 void *ctx);
60
61 static bool
62 lxb_css_selectors_state_relative_list_end(lxb_css_parser_t *parser,
63 const lxb_css_syntax_token_t *token,
64 void *ctx);
65
66 static bool
67 lxb_css_selectors_state_relative_list_wo_root(lxb_css_parser_t *parser,
68 const lxb_css_syntax_token_t *token,
69 void *ctx);
70
71 static bool
72 lxb_css_selectors_state_relative_wo_root(lxb_css_parser_t *parser,
73 const lxb_css_syntax_token_t *token,
74 void *ctx);
75
76 static bool
77 lxb_css_selectors_state_relative_handler(lxb_css_parser_t *parser,
78 const lxb_css_syntax_token_t *token,
79 void *ctx, bool list, bool root);
80
81 static bool
82 lxb_css_selectors_state_complex_end(lxb_css_parser_t *parser,
83 const lxb_css_syntax_token_t *token,
84 void *ctx);
85
86 static bool
87 lxb_css_selectors_state_complex_wo_root(lxb_css_parser_t *parser,
88 const lxb_css_syntax_token_t *token,
89 void *ctx);
90
91 static bool
92 lxb_css_selectors_state_complex_handler(lxb_css_parser_t *parser,
93 const lxb_css_syntax_token_t *token,
94 void *ctx, bool root);
95
96 static bool
97 lxb_css_selectors_state_compound_list_end(lxb_css_parser_t *parser,
98 const lxb_css_syntax_token_t *token,
99 void *ctx);
100
101 static bool
102 lxb_css_selectors_state_compound_wo_root(lxb_css_parser_t *parser,
103 const lxb_css_syntax_token_t *token,
104 void *ctx);
105
106 static bool
107 lxb_css_selectors_state_compound_handler(lxb_css_parser_t *parser,
108 const lxb_css_syntax_token_t *token,
109 void *ctx);
110
111 static bool
112 lxb_css_selectors_state_compound_sub(lxb_css_parser_t *parser,
113 const lxb_css_syntax_token_t *token,
114 void *ctx);
115
116 static bool
117 lxb_css_selectors_state_compound_pseudo(lxb_css_parser_t *parser,
118 const lxb_css_syntax_token_t *token,
119 void *ctx);
120
121 static bool
122 lxb_css_selectors_state_simple_list_end(lxb_css_parser_t *parser,
123 const lxb_css_syntax_token_t *token,
124 void *ctx);
125
126 static bool
127 lxb_css_selectors_state_simple_wo_root(lxb_css_parser_t *parser,
128 const lxb_css_syntax_token_t *token,
129 void *ctx);
130
131 static bool
132 lxb_css_selectors_state_simple_handler(lxb_css_parser_t *parser,
133 const lxb_css_syntax_token_t *token,
134 void *ctx);
135
136 static bool
137 lxb_css_selectors_state_simple_back(lxb_css_parser_t *parser,
138 const lxb_css_syntax_token_t *token,
139 void *ctx);
140
141 static lxb_status_t
142 lxb_css_selectors_state_hash(lxb_css_parser_t *parser,
143 const lxb_css_syntax_token_t *token);
144
145 static lxb_status_t
146 lxb_css_selectors_state_class(lxb_css_parser_t *parser,
147 const lxb_css_syntax_token_t *token);
148
149 static lxb_status_t
150 lxb_css_selectors_state_element_ns(lxb_css_parser_t *parser,
151 const lxb_css_syntax_token_t *token);
152
153 static lxb_status_t
154 lxb_css_selectors_state_element(lxb_css_parser_t *parser,
155 const lxb_css_syntax_token_t *token);
156
157 static lxb_status_t
158 lxb_css_selectors_state_attribute(lxb_css_parser_t *parser);
159
160 static lxb_status_t
161 lxb_css_selectors_state_ns(lxb_css_parser_t *parser,
162 lxb_css_selector_t *selector);
163
164 static lxb_status_t
165 lxb_css_selectors_state_ns_ident(lxb_css_parser_t *parser,
166 lxb_css_selector_t *selector);
167
168 static lxb_status_t
169 lxb_css_selectors_state_pseudo_class(lxb_css_parser_t *parser,
170 const lxb_css_syntax_token_t *token);
171
172 static lxb_status_t
173 lxb_css_selectors_state_pseudo_class_function(lxb_css_parser_t *parser,
174 const lxb_css_syntax_token_t *token,
175 lxb_css_parser_state_f success);
176
177 static lxb_status_t
178 lxb_css_selectors_state_pseudo_element(lxb_css_parser_t *parser,
179 const lxb_css_syntax_token_t *token);
180
181 static lxb_status_t
182 lxb_css_selectors_state_pseudo_element_function(lxb_css_parser_t *parser,
183 const lxb_css_syntax_token_t *token,
184 lxb_css_parser_state_f success);
185
186 static lxb_status_t
187 lxb_css_selectors_state_forgiving_cb(lxb_css_parser_t *parser,
188 const lxb_css_syntax_token_t *token,
189 void *ctx, lxb_css_parser_state_f state,
190 bool failed);
191
192 static void
193 lxb_css_selectors_state_restore_parent(lxb_css_selectors_t *selectors,
194 lxb_css_selector_list_t *last);
195
196 static bool
197 lxb_css_selectors_state_list_end(lxb_css_parser_t *parser,
198 const lxb_css_syntax_token_t *token,
199 lxb_css_parser_state_f state);
200
201 static bool
202 lxb_css_selectors_state_end(lxb_css_parser_t *parser,
203 const lxb_css_syntax_token_t *token, void *ctx);
204
205 static const lxb_css_syntax_token_t *
206 lxb_css_selectors_state_function_error(lxb_css_parser_t *parser,
207 const lxb_css_syntax_token_t *token);
208
209
210 lxb_inline bool
lxb_css_selectors_done(lxb_css_parser_t * parser)211 lxb_css_selectors_done(lxb_css_parser_t *parser)
212 {
213 lxb_css_parser_states_pop(parser);
214
215 return lxb_css_parser_states_set_back(parser);
216 }
217
218 lxb_inline void
lxb_css_selectors_state_specificity_set_b(lxb_css_selectors_t * selectors)219 lxb_css_selectors_state_specificity_set_b(lxb_css_selectors_t *selectors)
220 {
221 lxb_css_selector_list_t *last = selectors->list_last;
222
223 if (selectors->parent == NULL) {
224 lxb_css_selector_sp_set_b(last->specificity,
225 lxb_css_selector_sp_b(last->specificity) + 1);
226 }
227 else if (last->specificity > LXB_CSS_SELECTOR_SP_B_MAX) {
228 if (selectors->combinator == LXB_CSS_SELECTOR_COMBINATOR_CLOSE) {
229 lxb_css_selector_sp_set_b(last->specificity, 1);
230 }
231 }
232 else {
233 if (selectors->combinator != LXB_CSS_SELECTOR_COMBINATOR_CLOSE) {
234 last->specificity = 0;
235 }
236
237 lxb_css_selector_sp_set_b(last->specificity, 1);
238 }
239 }
240
241 lxb_inline void
lxb_css_selectors_state_specificity_set_c(lxb_css_selectors_t * selectors)242 lxb_css_selectors_state_specificity_set_c(lxb_css_selectors_t *selectors)
243 {
244 lxb_css_selector_list_t *last = selectors->list_last;
245
246 if (selectors->parent == NULL) {
247 lxb_css_selector_sp_set_c(last->specificity,
248 lxb_css_selector_sp_c(last->specificity) + 1);
249 }
250 else if (last->specificity > LXB_CSS_SELECTOR_SP_C_MAX) {
251 if (selectors->combinator == LXB_CSS_SELECTOR_COMBINATOR_CLOSE) {
252 lxb_css_selector_sp_set_c(last->specificity, 1);
253 }
254 }
255 else {
256 if (selectors->combinator != LXB_CSS_SELECTOR_COMBINATOR_CLOSE) {
257 last->specificity = 0;
258 }
259
260 lxb_css_selector_sp_set_c(last->specificity, 1);
261 }
262 }
263
264 lxb_inline void
lxb_css_selectors_state_func_specificity(lxb_css_selectors_t * selectors)265 lxb_css_selectors_state_func_specificity(lxb_css_selectors_t *selectors)
266 {
267 lxb_css_selector_list_t *prev, *last;
268
269 last = selectors->list_last;
270 prev = last->prev;
271
272 if (prev->specificity > last->specificity) {
273 last->specificity = prev->specificity;
274 }
275
276 prev->specificity = 0;
277 }
278
279 /*
280 * <complex-selector-list>
281 */
282 bool
lxb_css_selectors_state_complex_list(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)283 lxb_css_selectors_state_complex_list(lxb_css_parser_t *parser,
284 const lxb_css_syntax_token_t *token,
285 void *ctx)
286 {
287 lxb_css_parser_state_t *states;
288
289 states = lxb_css_parser_states_next(parser,
290 lxb_css_selectors_state_complex_wo_root,
291 lxb_css_selectors_state_complex_list_end,
292 ctx, true);
293 if (states == NULL) {
294 return lxb_css_parser_memory_fail(parser);
295 }
296
297 return false;
298 }
299
300 static bool
lxb_css_selectors_state_complex_list_end(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)301 lxb_css_selectors_state_complex_list_end(lxb_css_parser_t *parser,
302 const lxb_css_syntax_token_t *token,
303 void *ctx)
304 {
305 return lxb_css_selectors_state_list_end(parser, token,
306 lxb_css_selectors_state_complex_wo_root);
307 }
308
309 /*
310 * <relative-selector-list>
311 */
312 bool
lxb_css_selectors_state_relative_list(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)313 lxb_css_selectors_state_relative_list(lxb_css_parser_t *parser,
314 const lxb_css_syntax_token_t *token,
315 void *ctx)
316 {
317 lxb_css_parser_state_t *states;
318
319 states = lxb_css_parser_states_next(parser,
320 lxb_css_selectors_state_relative_list_wo_root,
321 lxb_css_selectors_state_relative_list_end,
322 ctx, true);
323 if (states == NULL) {
324 return lxb_css_parser_memory_fail(parser);
325 }
326
327 return false;
328 }
329
330 static bool
lxb_css_selectors_state_relative_list_end(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)331 lxb_css_selectors_state_relative_list_end(lxb_css_parser_t *parser,
332 const lxb_css_syntax_token_t *token,
333 void *ctx)
334 {
335 return lxb_css_selectors_state_list_end(parser, token,
336 lxb_css_selectors_state_relative_list_wo_root);
337 }
338
339 /*
340 * <relative-selector>
341 */
342 bool
lxb_css_selectors_state_relative(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)343 lxb_css_selectors_state_relative(lxb_css_parser_t *parser,
344 const lxb_css_syntax_token_t *token,
345 void *ctx)
346 {
347 lxb_css_parser_state_t *states;
348
349 states = lxb_css_parser_states_next(parser,
350 lxb_css_selectors_state_relative_wo_root,
351 lxb_css_selectors_state_end,
352 ctx, true);
353 if (states == NULL) {
354 return lxb_css_parser_memory_fail(parser);
355 }
356
357 return false;
358 }
359
360 static bool
lxb_css_selectors_state_relative_list_wo_root(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)361 lxb_css_selectors_state_relative_list_wo_root(lxb_css_parser_t *parser,
362 const lxb_css_syntax_token_t *token,
363 void *ctx)
364 {
365 return lxb_css_selectors_state_relative_handler(parser, token, ctx, true,
366 false);
367 }
368
369 static bool
lxb_css_selectors_state_relative_wo_root(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)370 lxb_css_selectors_state_relative_wo_root(lxb_css_parser_t *parser,
371 const lxb_css_syntax_token_t *token,
372 void *ctx)
373 {
374 return lxb_css_selectors_state_relative_handler(parser, token, ctx, false,
375 false);
376 }
377
378 static bool
lxb_css_selectors_state_relative_handler(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx,bool list,bool root)379 lxb_css_selectors_state_relative_handler(lxb_css_parser_t *parser,
380 const lxb_css_syntax_token_t *token,
381 void *ctx, bool list, bool root)
382 {
383 lxb_css_parser_state_f back;
384 lxb_css_parser_state_t *states;
385 lxb_css_selectors_t *selectors = parser->selectors;
386
387 /* <combinator> */
388
389 switch (token->type) {
390 case LXB_CSS_SYNTAX_TOKEN_WHITESPACE:
391 lxb_css_syntax_parser_consume(parser);
392 selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_DESCENDANT;
393 return true;
394
395 case LXB_CSS_SYNTAX_TOKEN_DELIM:
396 switch (lxb_css_syntax_token_delim_char(token)) {
397 case '>':
398 selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_CHILD;
399 break;
400
401 case '+':
402 selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_SIBLING;
403 break;
404
405 case '~':
406 selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_FOLLOWING;
407 break;
408
409 case '|':
410 lxb_css_parser_token_next_m(parser, token);
411
412 if (token->type == LXB_CSS_SYNTAX_TOKEN_DELIM
413 && lxb_css_syntax_token_delim_char(token) == '|')
414 {
415 lxb_css_syntax_parser_consume(parser);
416 selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_CELL;
417 break;
418 }
419
420 goto done;
421
422 default:
423 goto done;
424 }
425
426 break;
427
428 default:
429 goto done;
430 }
431
432 lxb_css_syntax_parser_consume(parser);
433
434 done:
435
436 back = (list) ? lxb_css_selectors_state_complex_end
437 : lxb_css_selectors_state_end;
438
439 states = lxb_css_parser_states_next(parser,
440 lxb_css_selectors_state_compound_wo_root,
441 back, ctx, root);
442 if (states == NULL) {
443 return lxb_css_parser_memory_fail(parser);
444 }
445
446 return true;
447 }
448
449 /*
450 * <complex-selector>
451 */
452 bool
lxb_css_selectors_state_complex(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)453 lxb_css_selectors_state_complex(lxb_css_parser_t *parser,
454 const lxb_css_syntax_token_t *token, void *ctx)
455 {
456 lxb_css_parser_state_t *states;
457
458 states = lxb_css_parser_states_next(parser,
459 lxb_css_selectors_state_complex_wo_root,
460 lxb_css_selectors_state_end,
461 ctx, true);
462 if (states == NULL) {
463 return lxb_css_parser_memory_fail(parser);
464 }
465
466 return false;
467 }
468
469 static bool
lxb_css_selectors_state_complex_wo_root(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)470 lxb_css_selectors_state_complex_wo_root(lxb_css_parser_t *parser,
471 const lxb_css_syntax_token_t *token,
472 void *ctx)
473 {
474 return lxb_css_selectors_state_complex_handler(parser, token, ctx, false);
475 }
476
477 static bool
lxb_css_selectors_state_complex_handler(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx,bool root)478 lxb_css_selectors_state_complex_handler(lxb_css_parser_t *parser,
479 const lxb_css_syntax_token_t *token,
480 void *ctx, bool root)
481 {
482 lxb_css_parser_state_t *states;
483
484 states = lxb_css_parser_states_next(parser,
485 lxb_css_selectors_state_compound_wo_root,
486 lxb_css_selectors_state_complex_end,
487 ctx, root);
488 if (states == NULL) {
489 return lxb_css_parser_memory_fail(parser);
490 }
491
492 return false;
493 }
494
495 static bool
lxb_css_selectors_state_complex_end(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)496 lxb_css_selectors_state_complex_end(lxb_css_parser_t *parser,
497 const lxb_css_syntax_token_t *token,
498 void *ctx)
499 {
500 lxb_css_selectors_t *selectors = parser->selectors;
501
502 /* <combinator> */
503
504 again:
505
506 switch (token->type) {
507 case LXB_CSS_SYNTAX_TOKEN_WHITESPACE:
508 lxb_css_syntax_parser_consume(parser);
509
510 selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_DESCENDANT;
511
512 lxb_css_parser_token_m(parser, token);
513 goto again;
514
515 case LXB_CSS_SYNTAX_TOKEN__END:
516 return lxb_css_selectors_done(parser);
517
518 case LXB_CSS_SYNTAX_TOKEN_DELIM:
519 switch (lxb_css_syntax_token_delim_char(token)) {
520 case '>':
521 selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_CHILD;
522 break;
523
524 case '+':
525 selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_SIBLING;
526 break;
527
528 case '~':
529 selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_FOLLOWING;
530 break;
531
532 case '|':
533 lxb_css_parser_token_next_m(parser, token);
534
535 if (token->type == LXB_CSS_SYNTAX_TOKEN_DELIM
536 && lxb_css_syntax_token_delim_char(token) == '|')
537 {
538 lxb_css_syntax_parser_consume(parser);
539 selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_CELL;
540 break;
541 }
542
543 goto done;
544
545 default:
546 if (selectors->combinator != LXB_CSS_SELECTOR_COMBINATOR_DESCENDANT) {
547 goto unexpected;
548 }
549
550 goto done;
551 }
552
553 break;
554
555 case LXB_CSS_SYNTAX_TOKEN_COMMA:
556 return lxb_css_selectors_done(parser);
557
558 default:
559 if (selectors->combinator != LXB_CSS_SELECTOR_COMBINATOR_DESCENDANT) {
560 goto unexpected;
561 }
562
563 goto done;
564 }
565
566 lxb_css_syntax_parser_consume(parser);
567
568 done:
569
570 lxb_css_parser_state_set(parser, lxb_css_selectors_state_compound_handler);
571
572 return true;
573
574 unexpected:
575
576 (void) lxb_css_selectors_done(parser);
577
578 return lxb_css_parser_unexpected(parser);
579 }
580
581 /*
582 * <compound-selector-list>
583 */
584 bool
lxb_css_selectors_state_compound_list(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)585 lxb_css_selectors_state_compound_list(lxb_css_parser_t *parser,
586 const lxb_css_syntax_token_t *token,
587 void *ctx)
588 {
589 lxb_css_parser_state_t *states;
590
591 states = lxb_css_parser_states_next(parser,
592 lxb_css_selectors_state_compound_wo_root,
593 lxb_css_selectors_state_compound_list_end,
594 ctx, true);
595 if (states == NULL) {
596 return lxb_css_parser_memory_fail(parser);
597 }
598
599 return false;
600 }
601
602 static bool
lxb_css_selectors_state_compound_list_end(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)603 lxb_css_selectors_state_compound_list_end(lxb_css_parser_t *parser,
604 const lxb_css_syntax_token_t *token,
605 void *ctx)
606 {
607 return lxb_css_selectors_state_list_end(parser, token,
608 lxb_css_selectors_state_compound_wo_root);
609 }
610
611 /*
612 *
613 * <compound-selector>
614 */
615 bool
lxb_css_selectors_state_compound(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)616 lxb_css_selectors_state_compound(lxb_css_parser_t *parser,
617 const lxb_css_syntax_token_t *token,
618 void *ctx)
619 {
620 lxb_css_parser_state_t *states;
621
622 states = lxb_css_parser_states_next(parser,
623 lxb_css_selectors_state_compound_wo_root,
624 lxb_css_selectors_state_end,
625 ctx, true);
626 if (states == NULL) {
627 return lxb_css_parser_memory_fail(parser);
628 }
629
630 return false;
631 }
632
633 static bool
lxb_css_selectors_state_compound_wo_root(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)634 lxb_css_selectors_state_compound_wo_root(lxb_css_parser_t *parser,
635 const lxb_css_syntax_token_t *token,
636 void *ctx)
637 {
638 lxb_css_selector_list_t *list;
639
640 lxb_css_selectors_state_list_append(parser, parser->selectors, list);
641
642 lxb_css_parser_state_set(parser, lxb_css_selectors_state_compound_handler);
643
644 return false;
645 }
646
647 static bool
lxb_css_selectors_state_compound_handler(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)648 lxb_css_selectors_state_compound_handler(lxb_css_parser_t *parser,
649 const lxb_css_syntax_token_t *token,
650 void *ctx)
651 {
652 lxb_status_t status;
653 lxb_css_selectors_t *selectors;
654
655 again:
656
657 lxb_css_parser_state_set(parser, lxb_css_selectors_state_compound_sub);
658
659 switch (token->type) {
660 case LXB_CSS_SYNTAX_TOKEN_HASH:
661 status = lxb_css_selectors_state_hash(parser, token);
662 break;
663
664 case LXB_CSS_SYNTAX_TOKEN_DELIM:
665 switch (lxb_css_syntax_token_delim_char(token)) {
666 case '.':
667 lxb_css_syntax_parser_consume(parser);
668 status = lxb_css_selectors_state_class(parser, token);
669 break;
670
671 case '|':
672 case '*':
673 status = lxb_css_selectors_state_element_ns(parser, token);
674 break;
675
676 default:
677 goto unexpected;
678 }
679
680 break;
681
682 case LXB_CSS_SYNTAX_TOKEN_IDENT:
683 status = lxb_css_selectors_state_element(parser, token);
684 break;
685
686 case LXB_CSS_SYNTAX_TOKEN_LS_BRACKET:
687 lxb_css_syntax_parser_consume(parser);
688 status = lxb_css_selectors_state_attribute(parser);
689 break;
690
691 case LXB_CSS_SYNTAX_TOKEN_COLON:
692 lxb_css_syntax_parser_consume(parser);
693 lxb_css_parser_token_m(parser, token);
694
695 if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) {
696 status = lxb_css_selectors_state_pseudo_class(parser, token);
697 break;
698 }
699 else if (token->type == LXB_CSS_SYNTAX_TOKEN_COLON) {
700 lxb_css_syntax_parser_consume(parser);
701 lxb_css_parser_token_m(parser, token);
702
703 if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) {
704 lxb_css_parser_state_set(parser,
705 lxb_css_selectors_state_compound_pseudo);
706 status = lxb_css_selectors_state_pseudo_element(parser, token);
707 break;
708 }
709 else if (token->type != LXB_CSS_SYNTAX_TOKEN_FUNCTION) {
710 return lxb_css_parser_unexpected(parser);
711 }
712
713 status = lxb_css_selectors_state_pseudo_element_function(parser, token,
714 lxb_css_selectors_state_compound_pseudo);
715 break;
716 }
717 else if (token->type != LXB_CSS_SYNTAX_TOKEN_FUNCTION) {
718 goto unexpected;
719 }
720
721 status = lxb_css_selectors_state_pseudo_class_function(parser, token,
722 lxb_css_selectors_state_compound_sub);
723 break;
724
725 case LXB_CSS_SYNTAX_TOKEN_WHITESPACE:
726 lxb_css_syntax_parser_consume(parser);
727 lxb_css_parser_token_m(parser, token);
728 goto again;
729
730 case LXB_CSS_SYNTAX_TOKEN__END:
731 selectors = parser->selectors;
732
733 if (selectors->combinator > LXB_CSS_SELECTOR_COMBINATOR_CLOSE
734 || selectors->list_last->first == NULL)
735 {
736 goto unexpected;
737 }
738
739 return lxb_css_selectors_done(parser);
740
741 default:
742 goto unexpected;
743 }
744
745 if (status == LXB_STATUS_OK) {
746 return true;
747 }
748
749 if (status == LXB_STATUS_ERROR_MEMORY_ALLOCATION) {
750 return lxb_css_parser_memory_fail(parser);
751 }
752
753 unexpected:
754
755 (void) lxb_css_parser_states_to_root(parser);
756 (void) lxb_css_parser_states_set_back(parser);
757
758 return lxb_css_parser_unexpected(parser);
759 }
760
761 static bool
lxb_css_selectors_state_compound_sub(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)762 lxb_css_selectors_state_compound_sub(lxb_css_parser_t *parser,
763 const lxb_css_syntax_token_t *token,
764 void *ctx)
765 {
766 lxb_status_t status;
767
768 /* <subclass-selector> */
769
770 switch (token->type) {
771 case LXB_CSS_SYNTAX_TOKEN_HASH:
772 status = lxb_css_selectors_state_hash(parser, token);
773 break;
774
775 case LXB_CSS_SYNTAX_TOKEN_DELIM:
776 switch (lxb_css_syntax_token_delim_char(token)) {
777 case '.':
778 lxb_css_syntax_parser_consume(parser);
779 status = lxb_css_selectors_state_class(parser, token);
780 break;
781
782 default:
783 return lxb_css_parser_states_set_back(parser);
784 }
785
786 break;
787
788 case LXB_CSS_SYNTAX_TOKEN_LS_BRACKET:
789 lxb_css_syntax_parser_consume(parser);
790 status = lxb_css_selectors_state_attribute(parser);
791 break;
792
793 case LXB_CSS_SYNTAX_TOKEN_COLON:
794 lxb_css_syntax_parser_consume(parser);
795 lxb_css_parser_token_m(parser, token);
796
797 if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) {
798 status = lxb_css_selectors_state_pseudo_class(parser, token);
799 break;
800 }
801 else if (token->type == LXB_CSS_SYNTAX_TOKEN_COLON) {
802 lxb_css_syntax_parser_consume(parser);
803 lxb_css_parser_token_m(parser, token);
804
805 if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) {
806 lxb_css_parser_state_set(parser,
807 lxb_css_selectors_state_compound_pseudo);
808 status = lxb_css_selectors_state_pseudo_element(parser,
809 token);
810 break;
811 }
812 else if (token->type != LXB_CSS_SYNTAX_TOKEN_FUNCTION) {
813 return lxb_css_parser_unexpected(parser);
814 }
815
816 status = lxb_css_selectors_state_pseudo_element_function(parser,
817 token, lxb_css_selectors_state_compound_pseudo);
818 break;
819 }
820 else if (token->type != LXB_CSS_SYNTAX_TOKEN_FUNCTION) {
821 return lxb_css_parser_unexpected(parser);
822 }
823
824 status = lxb_css_selectors_state_pseudo_class_function(parser, token,
825 lxb_css_selectors_state_compound_sub);
826 break;
827
828 default:
829 return lxb_css_parser_states_set_back(parser);
830 }
831
832 if (status == LXB_STATUS_OK) {
833 return true;
834 }
835
836 if (status == LXB_STATUS_ERROR_MEMORY_ALLOCATION) {
837 return lxb_css_parser_memory_fail(parser);
838 }
839
840 return lxb_css_parser_unexpected(parser);
841 }
842
843 static bool
lxb_css_selectors_state_compound_pseudo(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)844 lxb_css_selectors_state_compound_pseudo(lxb_css_parser_t *parser,
845 const lxb_css_syntax_token_t *token,
846 void *ctx)
847 {
848 lxb_status_t status;
849
850 if (token->type != LXB_CSS_SYNTAX_TOKEN_COLON) {
851 return lxb_css_parser_states_set_back(parser);
852 }
853
854 lxb_css_syntax_parser_consume(parser);
855 lxb_css_parser_token_m(parser, token);
856
857 if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) {
858 status = lxb_css_selectors_state_pseudo_class(parser, token);
859 }
860 else if (token->type == LXB_CSS_SYNTAX_TOKEN_COLON) {
861 lxb_css_syntax_parser_consume(parser);
862 lxb_css_parser_token_m(parser, token);
863
864 if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) {
865 status = lxb_css_selectors_state_pseudo_element(parser, token);
866 }
867 else if (token->type == LXB_CSS_SYNTAX_TOKEN_FUNCTION) {
868 status = lxb_css_selectors_state_pseudo_element_function(parser, token,
869 lxb_css_selectors_state_compound_pseudo);
870 }
871 else {
872 return lxb_css_parser_unexpected(parser);
873 }
874 }
875 else if (token->type != LXB_CSS_SYNTAX_TOKEN_FUNCTION) {
876 return lxb_css_parser_unexpected(parser);
877 }
878 else {
879 status = lxb_css_selectors_state_pseudo_class_function(parser, token,
880 lxb_css_selectors_state_compound_pseudo);
881 }
882
883 if (status == LXB_STATUS_OK) {
884 return true;
885 }
886
887 if (status == LXB_STATUS_ERROR_MEMORY_ALLOCATION) {
888 return lxb_css_parser_memory_fail(parser);
889 }
890
891 return lxb_css_parser_unexpected(parser);
892 }
893
894 /*
895 * <simple-selector-list>
896 */
897 bool
lxb_css_selectors_state_simple_list(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)898 lxb_css_selectors_state_simple_list(lxb_css_parser_t *parser,
899 const lxb_css_syntax_token_t *token,
900 void *ctx)
901 {
902 lxb_css_parser_state_t *states;
903
904 states = lxb_css_parser_states_next(parser, lxb_css_selectors_state_simple_wo_root,
905 lxb_css_selectors_state_simple_list_end,
906 ctx, true);
907 if (states == NULL) {
908 return lxb_css_parser_memory_fail(parser);
909 }
910
911 return false;
912 }
913
914 static bool
lxb_css_selectors_state_simple_list_end(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)915 lxb_css_selectors_state_simple_list_end(lxb_css_parser_t *parser,
916 const lxb_css_syntax_token_t *token,
917 void *ctx)
918 {
919 return lxb_css_selectors_state_list_end(parser, token,
920 lxb_css_selectors_state_simple_wo_root);
921 }
922
923 /*
924 * <simple-selector>
925 */
926 bool
lxb_css_selectors_state_simple(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)927 lxb_css_selectors_state_simple(lxb_css_parser_t *parser,
928 const lxb_css_syntax_token_t *token, void *ctx)
929 {
930 lxb_css_parser_state_t *states;
931
932 states = lxb_css_parser_states_next(parser,
933 lxb_css_selectors_state_simple_wo_root,
934 lxb_css_selectors_state_end,
935 ctx, true);
936 if (states == NULL) {
937 return lxb_css_parser_memory_fail(parser);
938 }
939
940 return false;
941 }
942
943 static bool
lxb_css_selectors_state_simple_wo_root(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)944 lxb_css_selectors_state_simple_wo_root(lxb_css_parser_t *parser,
945 const lxb_css_syntax_token_t *token,
946 void *ctx)
947 {
948 lxb_css_selector_list_t *list;
949
950 lxb_css_selectors_state_list_append(parser, parser->selectors, list);
951
952 lxb_css_parser_state_set(parser, lxb_css_selectors_state_simple_handler);
953
954 return false;
955 }
956
957 static bool
lxb_css_selectors_state_simple_handler(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)958 lxb_css_selectors_state_simple_handler(lxb_css_parser_t *parser,
959 const lxb_css_syntax_token_t *token,
960 void *ctx)
961 {
962 lxb_status_t status;
963
964 again:
965
966 lxb_css_parser_state_set(parser, lxb_css_selectors_state_simple_back);
967
968 switch (token->type) {
969 case LXB_CSS_SYNTAX_TOKEN_HASH:
970 status = lxb_css_selectors_state_hash(parser, token);
971 break;
972
973 case LXB_CSS_SYNTAX_TOKEN_DELIM:
974 switch (lxb_css_syntax_token_delim_char(token)) {
975 case '.':
976 lxb_css_syntax_parser_consume(parser);
977 status = lxb_css_selectors_state_class(parser, token);
978 break;
979
980 case '|':
981 case '*':
982 status = lxb_css_selectors_state_element_ns(parser, token);
983 break;
984
985 default:
986 goto unexpected;
987 }
988
989 break;
990
991 case LXB_CSS_SYNTAX_TOKEN_IDENT:
992 status = lxb_css_selectors_state_element(parser, token);
993 break;
994
995 case LXB_CSS_SYNTAX_TOKEN_LS_BRACKET:
996 lxb_css_syntax_parser_consume(parser);
997 status = lxb_css_selectors_state_attribute(parser);
998 break;
999
1000 case LXB_CSS_SYNTAX_TOKEN_COLON:
1001 lxb_css_syntax_parser_consume(parser);
1002 lxb_css_parser_token_m(parser, token);
1003
1004 if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) {
1005 status = lxb_css_selectors_state_pseudo_class(parser, token);
1006 break;
1007 }
1008 else if (token->type != LXB_CSS_SYNTAX_TOKEN_FUNCTION) {
1009 goto unexpected;
1010 }
1011
1012 status = lxb_css_selectors_state_pseudo_class_function(parser, token,
1013 lxb_css_selectors_state_simple_back);
1014 break;
1015
1016 case LXB_CSS_SYNTAX_TOKEN_WHITESPACE:
1017 lxb_css_syntax_parser_consume(parser);
1018 lxb_css_parser_token_m(parser, token);
1019 goto again;
1020
1021 case LXB_CSS_SYNTAX_TOKEN__END:
1022 return lxb_css_parser_states_set_back(parser);
1023
1024 default:
1025 goto unexpected;
1026 }
1027
1028 if (status == LXB_STATUS_OK) {
1029 return true;
1030 }
1031
1032 if (status == LXB_STATUS_ERROR_MEMORY_ALLOCATION) {
1033 return lxb_css_parser_memory_fail(parser);
1034 }
1035
1036 unexpected:
1037
1038 (void) lxb_css_parser_states_set_back(parser);
1039
1040 return lxb_css_parser_unexpected(parser);
1041 }
1042
1043 static bool
lxb_css_selectors_state_simple_back(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)1044 lxb_css_selectors_state_simple_back(lxb_css_parser_t *parser,
1045 const lxb_css_syntax_token_t *token,
1046 void *ctx)
1047 {
1048 return lxb_css_parser_states_set_back(parser);
1049 }
1050
1051 static lxb_status_t
lxb_css_selectors_state_hash(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token)1052 lxb_css_selectors_state_hash(lxb_css_parser_t *parser,
1053 const lxb_css_syntax_token_t *token)
1054 {
1055 lxb_status_t status;
1056 lxb_css_selector_t *selector;
1057 lxb_css_selectors_t *selectors;
1058 lxb_css_selector_list_t *last;
1059
1060 selectors = parser->selectors;
1061 last = selectors->list_last;
1062
1063 if (selectors->parent == NULL) {
1064 lxb_css_selector_sp_set_a(last->specificity,
1065 lxb_css_selector_sp_a(last->specificity) + 1);
1066 }
1067 else if (lxb_css_selector_sp_a(last->specificity) == 0) {
1068 if (selectors->combinator != LXB_CSS_SELECTOR_COMBINATOR_CLOSE) {
1069 last->specificity = 0;
1070 }
1071
1072 lxb_css_selector_sp_set_a(last->specificity, 1);
1073 }
1074
1075 lxb_css_selectors_state_append(parser, selectors, selector);
1076
1077 selector->type = LXB_CSS_SELECTOR_TYPE_ID;
1078
1079 status = lxb_css_syntax_token_string_dup(lxb_css_syntax_token_string(token),
1080 &selector->name, parser->memory->mraw);
1081 lxb_css_syntax_parser_consume(parser);
1082
1083 return status;
1084 }
1085
1086 static lxb_status_t
lxb_css_selectors_state_class(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token)1087 lxb_css_selectors_state_class(lxb_css_parser_t *parser,
1088 const lxb_css_syntax_token_t *token)
1089 {
1090 lxb_status_t status;
1091 lxb_css_selector_t *selector;
1092 lxb_css_selectors_t *selectors;
1093
1094 lxb_css_parser_token_status_m(parser, token);
1095
1096 if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) {
1097 selectors = parser->selectors;
1098
1099 lxb_css_selectors_state_specificity_set_b(selectors);
1100 lxb_css_selectors_state_append(parser, selectors, selector);
1101
1102 selector->type = LXB_CSS_SELECTOR_TYPE_CLASS;
1103
1104 status = lxb_css_syntax_token_string_dup(lxb_css_syntax_token_string(token),
1105 &selector->name, parser->memory->mraw);
1106 lxb_css_syntax_parser_consume(parser);
1107
1108 return status;
1109 }
1110
1111 return lxb_css_parser_unexpected_status(parser);
1112 }
1113
1114 static lxb_status_t
lxb_css_selectors_state_element_ns(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token)1115 lxb_css_selectors_state_element_ns(lxb_css_parser_t *parser,
1116 const lxb_css_syntax_token_t *token)
1117 {
1118 lxb_css_selector_t *selector;
1119 lxb_css_selectors_t *selectors;
1120
1121 selectors = parser->selectors;
1122
1123 lxb_css_selectors_state_append(parser, selectors, selector);
1124
1125 selector->type = LXB_CSS_SELECTOR_TYPE_ANY;
1126
1127 selector->name.data = lexbor_mraw_alloc(parser->memory->mraw, 2);
1128 if (selector->name.data == NULL) {
1129 return LXB_STATUS_ERROR_MEMORY_ALLOCATION;
1130 }
1131
1132 selector->name.data[0] = '*';
1133 selector->name.data[1] = '\0';
1134 selector->name.length = 1;
1135
1136 if (lxb_css_syntax_token_delim_char(token) == '*') {
1137 lxb_css_syntax_parser_consume(parser);
1138 return lxb_css_selectors_state_ns(parser, selector);
1139 }
1140
1141 lxb_css_syntax_parser_consume(parser);
1142
1143 return lxb_css_selectors_state_ns_ident(parser, selector);
1144 }
1145
1146 static lxb_status_t
lxb_css_selectors_state_element(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token)1147 lxb_css_selectors_state_element(lxb_css_parser_t *parser,
1148 const lxb_css_syntax_token_t *token)
1149 {
1150 lxb_status_t status;
1151 lxb_css_selector_t *selector;
1152 lxb_css_selectors_t *selectors;
1153
1154 selectors = parser->selectors;
1155
1156 lxb_css_selectors_state_specificity_set_c(selectors);
1157
1158 lxb_css_selectors_state_append(parser, selectors, selector);
1159
1160 selector->type = LXB_CSS_SELECTOR_TYPE_ELEMENT;
1161
1162 lxb_css_selectors_state_string_dup_m(selectors, &selector->name);
1163
1164 lxb_css_syntax_parser_consume(parser);
1165
1166 return lxb_css_selectors_state_ns(parser, selector);
1167 }
1168
1169
1170 static lxb_status_t
lxb_css_selectors_state_attribute(lxb_css_parser_t * parser)1171 lxb_css_selectors_state_attribute(lxb_css_parser_t *parser)
1172 {
1173 lxb_char_t modifier;
1174 lxb_status_t status;
1175 lxb_css_selector_t *selector;
1176 lxb_css_selectors_t *selectors;
1177 const lxb_css_syntax_token_t *token;
1178 lxb_css_selector_attribute_t *attribute;
1179
1180 selectors = parser->selectors;
1181
1182 lxb_css_selectors_state_append(parser, selectors, selector);
1183 lxb_css_parser_token_status_wo_ws_m(parser, token);
1184
1185 switch (token->type) {
1186 case LXB_CSS_SYNTAX_TOKEN_DELIM:
1187 if (lxb_css_syntax_token_delim_char(token) != '|') {
1188 goto failed;
1189 }
1190
1191 lxb_css_syntax_parser_consume(parser);
1192 lxb_css_parser_token_status_m(parser, token);
1193
1194 if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) {
1195 goto failed;
1196 }
1197
1198 selector->type = LXB_CSS_SELECTOR_TYPE_ATTRIBUTE;
1199
1200 selector->ns.data = lexbor_mraw_alloc(parser->memory->mraw, 2);
1201 if (selector->ns.data == NULL) {
1202 return LXB_STATUS_ERROR_MEMORY_ALLOCATION;
1203 }
1204
1205 selector->ns.data[0] = '*';
1206 selector->ns.data[1] = '\0';
1207 selector->ns.length = 1;
1208
1209 lxb_css_selectors_state_string_dup_m(parser->selectors,
1210 &selector->name);
1211
1212 lxb_css_syntax_parser_consume(parser);
1213 lxb_css_parser_token_status_wo_ws_m(parser, token);
1214 break;
1215
1216 case LXB_CSS_SYNTAX_TOKEN_IDENT:
1217 selector->type = LXB_CSS_SELECTOR_TYPE_ATTRIBUTE;
1218
1219 lxb_css_selectors_state_string_dup_m(selectors, &selector->name);
1220
1221 lxb_css_syntax_parser_consume(parser);
1222 lxb_css_parser_token_status_m(parser, token);
1223
1224 if (token->type != LXB_CSS_SYNTAX_TOKEN_DELIM
1225 || lxb_css_syntax_token_delim_char(token) != '|')
1226 {
1227 if (token->type == LXB_CSS_SYNTAX_TOKEN_WHITESPACE) {
1228 lxb_css_syntax_parser_consume(parser);
1229 lxb_css_parser_token_status_m(parser, token);
1230 }
1231
1232 break;
1233 }
1234
1235 lxb_css_syntax_parser_consume(parser);
1236 lxb_css_parser_token_status_m(parser, token);
1237
1238 if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) {
1239 attribute = &selector->u.attribute;
1240 attribute->match = LXB_CSS_SELECTOR_MATCH_DASH;
1241
1242 goto assignment;
1243 }
1244
1245 selector->ns = selector->name;
1246 lexbor_str_clean_all(&selector->name);
1247
1248 lxb_css_selectors_state_string_dup_m(selectors, &selector->name);
1249
1250 lxb_css_syntax_parser_consume(parser);
1251 lxb_css_parser_token_status_wo_ws_m(parser, token);
1252 break;
1253
1254 default:
1255 goto failed;
1256 }
1257
1258 attribute = &selector->u.attribute;
1259
1260 switch (token->type) {
1261 case LXB_CSS_SYNTAX_TOKEN_RS_BRACKET:
1262 goto done;
1263
1264 case LXB_CSS_SYNTAX_TOKEN_DELIM:
1265 switch (lxb_css_syntax_token_delim_char(token)) {
1266 case '~':
1267 attribute->match = LXB_CSS_SELECTOR_MATCH_INCLUDE;
1268 break;
1269
1270 case '|':
1271 attribute->match = LXB_CSS_SELECTOR_MATCH_DASH;
1272 break;
1273
1274 case '^':
1275 attribute->match = LXB_CSS_SELECTOR_MATCH_PREFIX;
1276 break;
1277
1278 case '$':
1279 attribute->match = LXB_CSS_SELECTOR_MATCH_SUFFIX;
1280 break;
1281
1282 case '*':
1283 attribute->match = LXB_CSS_SELECTOR_MATCH_SUBSTRING;
1284 break;
1285
1286 case '=':
1287 attribute->match = LXB_CSS_SELECTOR_MATCH_EQUAL;
1288
1289 lxb_css_syntax_parser_consume(parser);
1290 lxb_css_parser_token_status_wo_ws_m(parser, token);
1291 goto string_or_ident;
1292
1293 default:
1294 goto failed;
1295 }
1296
1297 lxb_css_syntax_parser_consume(parser);
1298 lxb_css_parser_token_status_m(parser, token);
1299
1300 break;
1301
1302 default:
1303 goto failed;
1304 }
1305
1306 assignment:
1307
1308 if (token->type != LXB_CSS_SYNTAX_TOKEN_DELIM
1309 || lxb_css_syntax_token_delim_char(token) != '=')
1310 {
1311 goto failed;
1312 }
1313
1314 lxb_css_syntax_parser_consume(parser);
1315 lxb_css_parser_token_status_wo_ws_m(parser, token);
1316
1317 string_or_ident:
1318
1319 if (token->type != LXB_CSS_SYNTAX_TOKEN_STRING
1320 && token->type != LXB_CSS_SYNTAX_TOKEN_IDENT)
1321 {
1322 goto failed;
1323 }
1324
1325 lxb_css_selectors_state_string_dup_m(selectors, &attribute->value);
1326
1327 lxb_css_syntax_parser_consume(parser);
1328 lxb_css_parser_token_status_wo_ws_m(parser, token);
1329
1330 if (token->type == LXB_CSS_SYNTAX_TOKEN_RS_BRACKET) {
1331 goto done;
1332 }
1333
1334 if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) {
1335 goto failed;
1336 }
1337
1338 modifier = *lxb_css_syntax_token_string(token)->data;
1339
1340 switch (modifier) {
1341 case 'i':
1342 attribute->modifier = LXB_CSS_SELECTOR_MODIFIER_I;
1343 break;
1344
1345 case 's':
1346 attribute->modifier = LXB_CSS_SELECTOR_MODIFIER_S;
1347 break;
1348
1349 default:
1350 goto failed;
1351 }
1352
1353 lxb_css_syntax_parser_consume(parser);
1354 lxb_css_parser_token_status_wo_ws_m(parser, token);
1355
1356 if (token->type != LXB_CSS_SYNTAX_TOKEN_RS_BRACKET) {
1357 goto failed;
1358 }
1359
1360 done:
1361
1362 lxb_css_selectors_state_specificity_set_b(selectors);
1363 lxb_css_syntax_parser_consume(parser);
1364
1365 return LXB_STATUS_OK;
1366
1367 failed:
1368
1369 return lxb_css_parser_unexpected_status(parser);
1370 }
1371
1372 static lxb_status_t
lxb_css_selectors_state_ns(lxb_css_parser_t * parser,lxb_css_selector_t * selector)1373 lxb_css_selectors_state_ns(lxb_css_parser_t *parser,
1374 lxb_css_selector_t *selector)
1375 {
1376 const lxb_css_syntax_token_t *token;
1377
1378 lxb_css_parser_token_status_m(parser, token);
1379
1380 if (token->type == LXB_CSS_SYNTAX_TOKEN_DELIM
1381 && lxb_css_syntax_token_delim_char(token) == '|')
1382 {
1383 lxb_css_syntax_parser_consume(parser);
1384 return lxb_css_selectors_state_ns_ident(parser, selector);
1385 }
1386
1387 return LXB_STATUS_OK;
1388 }
1389
1390 static lxb_status_t
lxb_css_selectors_state_ns_ident(lxb_css_parser_t * parser,lxb_css_selector_t * selector)1391 lxb_css_selectors_state_ns_ident(lxb_css_parser_t *parser,
1392 lxb_css_selector_t *selector)
1393 {
1394 lxb_status_t status;
1395 const lxb_css_syntax_token_t *token;
1396 lxb_css_selectors_t *selectors;
1397
1398 lxb_css_parser_token_status_m(parser, token);
1399
1400 if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) {
1401 selectors = parser->selectors;
1402
1403 lxb_css_selectors_state_specificity_set_c(selectors);
1404
1405 selector->type = LXB_CSS_SELECTOR_TYPE_ELEMENT;
1406
1407 selector->ns = selector->name;
1408 lexbor_str_clean_all(&selector->name);
1409
1410 status = lxb_css_syntax_token_string_dup(lxb_css_syntax_token_string(token),
1411 &selector->name, parser->memory->mraw);
1412
1413 lxb_css_syntax_parser_consume(parser);
1414
1415 return status;
1416 }
1417 else if (token->type == LXB_CSS_SYNTAX_TOKEN_DELIM
1418 && lxb_css_syntax_token_delim_char(token) == '*')
1419 {
1420 lxb_css_syntax_parser_consume(parser);
1421
1422 selector->type = LXB_CSS_SELECTOR_TYPE_ANY;
1423
1424 selector->ns = selector->name;
1425
1426 selector->name.data = lexbor_mraw_alloc(parser->memory->mraw, 2);
1427 if (selector->name.data == NULL) {
1428 return LXB_STATUS_ERROR_MEMORY_ALLOCATION;
1429 }
1430
1431 selector->name.data[0] = '*';
1432 selector->name.data[1] = '\0';
1433 selector->name.length = 1;
1434
1435 return LXB_STATUS_OK;
1436 }
1437
1438 return lxb_css_parser_unexpected_status(parser);
1439 }
1440
1441 static lxb_status_t
lxb_css_selectors_state_pseudo_class(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token)1442 lxb_css_selectors_state_pseudo_class(lxb_css_parser_t *parser,
1443 const lxb_css_syntax_token_t *token)
1444 {
1445 lxb_status_t status;
1446 lxb_css_log_message_t *msg;
1447 lxb_css_selector_t *selector;
1448 lxb_css_selectors_t *selectors;
1449 const lxb_css_selectors_pseudo_data_t *pseudo;
1450
1451 selectors = parser->selectors;
1452
1453 lxb_css_selectors_state_append(parser, selectors, selector);
1454 selector->type = LXB_CSS_SELECTOR_TYPE_PSEUDO_CLASS;
1455
1456 lxb_css_selectors_state_string_dup_m(selectors, &selector->name);
1457
1458 pseudo = lxb_css_selector_pseudo_class_by_name(selector->name.data,
1459 selector->name.length);
1460 if (pseudo == NULL) {
1461 return lxb_css_parser_unexpected_status(parser);
1462 }
1463
1464 switch (pseudo->id) {
1465 case LXB_CSS_SELECTOR_PSEUDO_CLASS_CURRENT:
1466 case LXB_CSS_SELECTOR_PSEUDO_CLASS_DEFAULT:
1467 case LXB_CSS_SELECTOR_PSEUDO_CLASS_FOCUS_VISIBLE:
1468 case LXB_CSS_SELECTOR_PSEUDO_CLASS_FOCUS_WITHIN:
1469 case LXB_CSS_SELECTOR_PSEUDO_CLASS_FULLSCREEN:
1470 case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUTURE:
1471 case LXB_CSS_SELECTOR_PSEUDO_CLASS_IN_RANGE:
1472 case LXB_CSS_SELECTOR_PSEUDO_CLASS_INDETERMINATE:
1473 case LXB_CSS_SELECTOR_PSEUDO_CLASS_INVALID:
1474 case LXB_CSS_SELECTOR_PSEUDO_CLASS_LOCAL_LINK:
1475 case LXB_CSS_SELECTOR_PSEUDO_CLASS_OUT_OF_RANGE:
1476 case LXB_CSS_SELECTOR_PSEUDO_CLASS_PAST:
1477 case LXB_CSS_SELECTOR_PSEUDO_CLASS_SCOPE:
1478 case LXB_CSS_SELECTOR_PSEUDO_CLASS_TARGET:
1479 case LXB_CSS_SELECTOR_PSEUDO_CLASS_TARGET_WITHIN:
1480 case LXB_CSS_SELECTOR_PSEUDO_CLASS_USER_INVALID:
1481 case LXB_CSS_SELECTOR_PSEUDO_CLASS_VALID:
1482 case LXB_CSS_SELECTOR_PSEUDO_CLASS_VISITED:
1483 case LXB_CSS_SELECTOR_PSEUDO_CLASS_WARNING:
1484 msg = lxb_css_log_not_supported(parser->log,
1485 lxb_css_selectors_module_name,
1486 (const char *) selector->name.data);
1487 if (msg == NULL) {
1488 return lxb_css_parser_memory_fail(parser);
1489 }
1490
1491 return lxb_css_parser_unexpected_status(parser);
1492
1493 default:
1494 break;
1495 }
1496
1497 selector->u.pseudo.type = pseudo->id;
1498 selector->u.pseudo.data = NULL;
1499
1500 lxb_css_syntax_parser_consume(parser);
1501
1502 return LXB_STATUS_OK;
1503 }
1504
1505 static lxb_status_t
lxb_css_selectors_state_pseudo_class_function(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,lxb_css_parser_state_f success)1506 lxb_css_selectors_state_pseudo_class_function(lxb_css_parser_t *parser,
1507 const lxb_css_syntax_token_t *token,
1508 lxb_css_parser_state_f success)
1509 {
1510 lxb_status_t status;
1511 lxb_css_selector_t *selector;
1512 lxb_css_selectors_t *selectors;
1513 lxb_css_log_message_t *msg;
1514 lxb_css_syntax_rule_t *rule;
1515 const lxb_css_selectors_pseudo_data_func_t *func;
1516
1517 selectors = parser->selectors;
1518
1519 lxb_css_selectors_state_append(parser, selectors, selector);
1520 selector->type = LXB_CSS_SELECTOR_TYPE_PSEUDO_CLASS_FUNCTION;
1521
1522 lxb_css_selectors_state_string_dup_m(selectors, &selector->name);
1523
1524 func = lxb_css_selector_pseudo_class_function_by_name(selector->name.data,
1525 selector->name.length);
1526 if (func == NULL) {
1527 return lxb_css_parser_unexpected_status(parser);
1528 }
1529
1530 switch (func->id) {
1531 case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_DIR:
1532 case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_LANG:
1533 case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_COL:
1534 case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_COL:
1535 msg = lxb_css_log_not_supported(parser->log,
1536 lxb_css_selectors_module_name,
1537 (const char *) selector->name.data);
1538 if (msg == NULL) {
1539 goto failed;
1540 }
1541
1542 return lxb_css_parser_unexpected_status(parser);
1543
1544 case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_CHILD:
1545 case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_CHILD:
1546 lxb_css_selectors_state_specificity_set_b(selectors);
1547 break;
1548
1549 default:
1550 break;
1551 }
1552
1553 selector->u.pseudo.type = func->id;
1554 selector->u.pseudo.data = NULL;
1555
1556 selectors->combinator = func->combinator;
1557 selectors->comb_default = func->combinator;
1558 selectors->parent = selector;
1559
1560 rule = lxb_css_syntax_parser_function_push(parser, token, success,
1561 &func->cb, selectors->list_last);
1562 if (rule == NULL) {
1563 goto failed;
1564 }
1565
1566 lxb_css_syntax_parser_consume(parser);
1567
1568 return LXB_STATUS_OK;
1569
1570 failed:
1571
1572 (void) lxb_css_parser_memory_fail(parser);
1573
1574 return parser->status;
1575 }
1576
1577 static lxb_status_t
lxb_css_selectors_state_pseudo_element(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token)1578 lxb_css_selectors_state_pseudo_element(lxb_css_parser_t *parser,
1579 const lxb_css_syntax_token_t *token)
1580 {
1581 lxb_status_t status;
1582 lxb_css_log_message_t *msg;
1583 lxb_css_selector_t *selector;
1584 lxb_css_selectors_t *selectors;
1585 const lxb_css_selectors_pseudo_data_t *pseudo;
1586
1587 selectors = parser->selectors;
1588
1589 lxb_css_selectors_state_append(parser, selectors, selector);
1590 selector->type = LXB_CSS_SELECTOR_TYPE_PSEUDO_ELEMENT;
1591
1592 lxb_css_selectors_state_string_dup_m(selectors, &selector->name);
1593
1594 pseudo = lxb_css_selector_pseudo_element_by_name(selector->name.data,
1595 selector->name.length);
1596 if (pseudo == NULL) {
1597 return lxb_css_parser_unexpected_status(parser);
1598 }
1599
1600 switch (pseudo->id) {
1601 case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_AFTER:
1602 case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_BACKDROP:
1603 case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_BEFORE:
1604 case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_FIRST_LETTER:
1605 case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_FIRST_LINE:
1606 case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_GRAMMAR_ERROR:
1607 case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_INACTIVE_SELECTION:
1608 case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_MARKER:
1609 case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_PLACEHOLDER:
1610 case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_SELECTION:
1611 case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_SPELLING_ERROR:
1612 case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_TARGET_TEXT:
1613 msg = lxb_css_log_not_supported(parser->log,
1614 lxb_css_selectors_module_name,
1615 (const char *) selector->name.data);
1616 if (msg == NULL) {
1617 (void) lxb_css_parser_memory_fail(parser);
1618 return parser->status;
1619 }
1620
1621 return lxb_css_parser_unexpected_status(parser);
1622
1623 default:
1624 break;
1625 }
1626
1627 selector->u.pseudo.type = pseudo->id;
1628 selector->u.pseudo.data = NULL;
1629
1630 lxb_css_syntax_parser_consume(parser);
1631
1632 return LXB_STATUS_OK;
1633 }
1634
1635 static lxb_status_t
lxb_css_selectors_state_pseudo_element_function(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,lxb_css_parser_state_f success)1636 lxb_css_selectors_state_pseudo_element_function(lxb_css_parser_t *parser,
1637 const lxb_css_syntax_token_t *token,
1638 lxb_css_parser_state_f success)
1639 {
1640 lxb_status_t status;
1641 lxb_css_selector_t *selector;
1642 lxb_css_selectors_t *selectors;
1643 lxb_css_syntax_rule_t *rule;
1644 const lxb_css_selectors_pseudo_data_func_t *func;
1645
1646 selectors = parser->selectors;
1647
1648 lxb_css_selectors_state_append(parser, selectors, selector);
1649 selector->type = LXB_CSS_SELECTOR_TYPE_PSEUDO_ELEMENT_FUNCTION;
1650
1651 lxb_css_selectors_state_string_dup_m(selectors, &selector->name);
1652
1653 func = lxb_css_selector_pseudo_element_function_by_name(selector->name.data,
1654 selector->name.length);
1655 if (func == NULL) {
1656 return lxb_css_parser_unexpected_status(parser);
1657 }
1658
1659 selector->u.pseudo.type = func->id;
1660 selector->u.pseudo.data = NULL;
1661
1662 selectors->combinator = func->combinator;
1663 selectors->comb_default = func->combinator;
1664 selectors->parent = selector;
1665
1666 rule = lxb_css_syntax_parser_function_push(parser, token, success,
1667 &func->cb, selectors->list_last);
1668 if (rule == NULL) {
1669 (void) lxb_css_parser_memory_fail(parser);
1670 return parser->status;
1671 }
1672
1673 lxb_css_syntax_parser_consume(parser);
1674
1675 return LXB_STATUS_OK;
1676 }
1677
1678 lxb_inline void
lxb_css_selectors_state_restore_combinator(lxb_css_selectors_t * selectors)1679 lxb_css_selectors_state_restore_combinator(lxb_css_selectors_t *selectors)
1680 {
1681 lxb_css_selector_t *parent;
1682 lxb_css_selector_combinator_t comb_default;
1683 const lxb_css_selectors_pseudo_data_func_t *data_func;
1684
1685 comb_default = LXB_CSS_SELECTOR_COMBINATOR_DESCENDANT;
1686
1687 if (selectors->parent != NULL) {
1688 parent = selectors->parent;
1689
1690 if (parent->type == LXB_CSS_SELECTOR_TYPE_PSEUDO_CLASS_FUNCTION) {
1691 data_func = lxb_css_selector_pseudo_class_function_by_id(parent->u.pseudo.type);
1692 }
1693 else {
1694 data_func = lxb_css_selector_pseudo_element_function_by_id(parent->u.pseudo.type);
1695 }
1696
1697 comb_default = data_func->combinator;
1698 }
1699
1700 selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_CLOSE;
1701 selectors->comb_default = comb_default;
1702 }
1703
1704 lxb_status_t
lxb_css_selectors_state_function_end(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx,bool failed)1705 lxb_css_selectors_state_function_end(lxb_css_parser_t *parser,
1706 const lxb_css_syntax_token_t *token,
1707 void *ctx, bool failed)
1708 {
1709 bool cy;
1710 lxb_css_selector_t *selector;
1711 lxb_css_selectors_t *selectors = parser->selectors;
1712
1713 if (token->type == LXB_CSS_SYNTAX_TOKEN__EOF) {
1714 (void) lxb_css_log_format(parser->log, LXB_CSS_LOG_ERROR,
1715 "%s. End Of File in pseudo function",
1716 lxb_css_selectors_module_name);
1717 }
1718
1719 if (selectors->list_last == NULL) {
1720 lxb_css_selectors_state_restore_parent(selectors, ctx);
1721 goto empty;
1722 }
1723
1724 lxb_css_selectors_state_restore_parent(selectors, ctx);
1725
1726 return LXB_STATUS_OK;
1727
1728 empty:
1729
1730 selector = selectors->list_last->last;
1731
1732 cy = selector->type == LXB_CSS_SELECTOR_TYPE_PSEUDO_CLASS_FUNCTION;
1733 cy = lxb_css_selector_pseudo_function_can_empty(selector->u.pseudo.type,
1734 cy);
1735 if (cy) {
1736 lxb_css_parser_set_ok(parser);
1737 return LXB_STATUS_OK;
1738 }
1739
1740 (void) lxb_css_log_format(parser->log, LXB_CSS_LOG_ERROR,
1741 "%s. Pseudo function can't be empty: %S()",
1742 lxb_css_selectors_module_name, &selector->name);
1743
1744 lxb_css_selector_remove(selector);
1745 lxb_css_selector_destroy(selector);
1746
1747 lxb_css_parser_failed_set_by_id(parser, -1, true);
1748 selectors->err_in_function = true;
1749
1750 return LXB_STATUS_OK;
1751 }
1752
1753 lxb_status_t
lxb_css_selectors_state_function_forgiving(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx,bool failed)1754 lxb_css_selectors_state_function_forgiving(lxb_css_parser_t *parser,
1755 const lxb_css_syntax_token_t *token,
1756 void *ctx, bool failed)
1757 {
1758 return lxb_css_selectors_state_forgiving_cb(parser, token, ctx,
1759 lxb_css_selectors_state_complex_list,
1760 failed);
1761 }
1762
1763 lxb_status_t
lxb_css_selectors_state_function_forgiving_relative(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx,bool failed)1764 lxb_css_selectors_state_function_forgiving_relative(lxb_css_parser_t *parser,
1765 const lxb_css_syntax_token_t *token,
1766 void *ctx, bool failed)
1767 {
1768 return lxb_css_selectors_state_forgiving_cb(parser, token, ctx,
1769 lxb_css_selectors_state_relative_list,
1770 failed);
1771 }
1772
1773 static lxb_status_t
lxb_css_selectors_state_forgiving_cb(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx,lxb_css_parser_state_f state,bool failed)1774 lxb_css_selectors_state_forgiving_cb(lxb_css_parser_t *parser,
1775 const lxb_css_syntax_token_t *token,
1776 void *ctx, lxb_css_parser_state_f state,
1777 bool failed)
1778 {
1779 bool cy;
1780 lxb_css_selector_t *selector;
1781 lxb_css_selectors_t *selectors = parser->selectors;
1782
1783 lxb_css_parser_set_ok(parser);
1784
1785 if (token->type == LXB_CSS_SYNTAX_TOKEN__EOF) {
1786 (void) lxb_css_log_format(parser->log, LXB_CSS_LOG_ERROR,
1787 "%s. End Of File in pseudo function",
1788 lxb_css_selectors_module_name);
1789 }
1790
1791 if (selectors->list_last == NULL) {
1792 lxb_css_selectors_state_restore_parent(selectors, ctx);
1793 goto empty;
1794 }
1795
1796 if (selectors->parent->u.pseudo.type
1797 == LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_WHERE)
1798 {
1799 selectors->list_last->specificity = 0;
1800 }
1801
1802 lxb_css_selectors_state_restore_parent(selectors, ctx);
1803
1804 return LXB_STATUS_OK;
1805
1806 empty:
1807
1808 selector = selectors->list_last->last;
1809
1810 cy = selector->type == LXB_CSS_SELECTOR_TYPE_PSEUDO_CLASS_FUNCTION;
1811 cy = lxb_css_selector_pseudo_function_can_empty(selector->u.pseudo.type,
1812 cy);
1813 if (cy) {
1814 return LXB_STATUS_OK;
1815 }
1816
1817 (void) lxb_css_log_format(parser->log, LXB_CSS_LOG_ERROR,
1818 "%s. Pseudo function can't be empty: %S()",
1819 lxb_css_selectors_module_name, &selector->name);
1820
1821 lxb_css_selector_remove(selector);
1822 lxb_css_selector_destroy(selector);
1823
1824 lxb_css_parser_failed_set_by_id(parser, -1, true);
1825 selectors->err_in_function = true;
1826
1827 return LXB_STATUS_OK;
1828 }
1829
1830 static void
lxb_css_selectors_state_restore_parent(lxb_css_selectors_t * selectors,lxb_css_selector_list_t * last)1831 lxb_css_selectors_state_restore_parent(lxb_css_selectors_t *selectors,
1832 lxb_css_selector_list_t *last)
1833 {
1834 uint32_t src, dst;
1835
1836 if (selectors->list_last != NULL && selectors->list_last != last) {
1837 dst = last->specificity;
1838 src = selectors->list_last->specificity;
1839
1840 selectors->list_last = 0;
1841
1842 if (last->parent == NULL) {
1843 lxb_css_selector_sp_add_a(dst, lxb_css_selector_sp_a(src));
1844 lxb_css_selector_sp_add_b(dst, lxb_css_selector_sp_b(src));
1845 lxb_css_selector_sp_add_c(dst, lxb_css_selector_sp_c(src));
1846 }
1847 else if (selectors->combinator == LXB_CSS_SELECTOR_COMBINATOR_CLOSE) {
1848 dst |= src;
1849 }
1850 else if (src > dst) {
1851 dst = src;
1852 }
1853
1854 last->specificity = dst;
1855 }
1856
1857 if (selectors->list != NULL) {
1858 last->last->u.pseudo.data = selectors->list;
1859 }
1860
1861 selectors->list_last = last;
1862
1863 /* Get first Selector in chain. */
1864 while (last->prev != NULL) {
1865 last = last->prev;
1866 }
1867
1868 selectors->list = last;
1869 selectors->parent = last->parent;
1870
1871 lxb_css_selectors_state_restore_combinator(selectors);
1872 }
1873
1874 static bool
lxb_css_selectors_state_list_end(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,lxb_css_parser_state_f state)1875 lxb_css_selectors_state_list_end(lxb_css_parser_t *parser,
1876 const lxb_css_syntax_token_t *token,
1877 lxb_css_parser_state_f state)
1878 {
1879 lxb_css_parser_state_t *states;
1880 lxb_css_selectors_t *selectors = parser->selectors;
1881
1882 if (lxb_css_parser_is_failed(parser)) {
1883 token = lxb_css_selectors_state_function_error(parser, token);
1884 if (token == NULL) {
1885 return lxb_css_parser_fail(parser,
1886 LXB_STATUS_ERROR_MEMORY_ALLOCATION);
1887 }
1888 }
1889 else if (token->type == LXB_CSS_SYNTAX_TOKEN_WHITESPACE) {
1890 lxb_css_syntax_parser_consume(parser);
1891 lxb_css_parser_token_status_m(parser, token);
1892 }
1893
1894 if (selectors->parent != NULL && selectors->list_last &&
1895 selectors->list_last->prev != NULL)
1896 {
1897 lxb_css_selectors_state_func_specificity(selectors);
1898 }
1899
1900 if (token->type != LXB_CSS_SYNTAX_TOKEN_COMMA) {
1901 states = lxb_css_parser_states_current(parser);
1902
1903 if (states->root) {
1904 if (token->type != LXB_CSS_SYNTAX_TOKEN__END) {
1905 token = lxb_css_selectors_state_function_error(parser, token);
1906 if (token == NULL) {
1907 return lxb_css_parser_fail(parser,
1908 LXB_STATUS_ERROR_MEMORY_ALLOCATION);
1909 }
1910 }
1911
1912 (void) lxb_css_parser_states_pop(parser);
1913 return lxb_css_parser_success(parser);
1914 }
1915
1916 return lxb_css_selectors_done(parser);
1917 }
1918
1919 selectors->combinator = selectors->comb_default;
1920
1921 lxb_css_syntax_token_consume(parser->tkz);
1922 lxb_css_parser_state_set(parser, state);
1923 lxb_css_parser_set_ok(parser);
1924
1925 return true;
1926 }
1927
1928 static bool
lxb_css_selectors_state_end(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token,void * ctx)1929 lxb_css_selectors_state_end(lxb_css_parser_t *parser,
1930 const lxb_css_syntax_token_t *token, void *ctx)
1931 {
1932 lxb_css_parser_state_t *states;
1933
1934 if (token->type == LXB_CSS_SYNTAX_TOKEN_WHITESPACE) {
1935 lxb_css_syntax_parser_consume(parser);
1936 lxb_css_parser_token_status_m(parser, token);
1937 }
1938
1939 if (lxb_css_parser_is_failed(parser)) {
1940 token = lxb_css_selectors_state_function_error(parser, token);
1941 if (token == NULL) {
1942 return lxb_css_parser_fail(parser,
1943 LXB_STATUS_ERROR_MEMORY_ALLOCATION);
1944 }
1945 }
1946
1947 states = lxb_css_parser_states_current(parser);
1948
1949 if (states->root) {
1950 if (token->type != LXB_CSS_SYNTAX_TOKEN__END) {
1951 token = lxb_css_selectors_state_function_error(parser, token);
1952 if (token == NULL) {
1953 return lxb_css_parser_fail(parser,
1954 LXB_STATUS_ERROR_MEMORY_ALLOCATION);
1955 }
1956 }
1957
1958 (void) lxb_css_parser_states_pop(parser);
1959 return lxb_css_parser_success(parser);
1960 }
1961
1962 return lxb_css_selectors_done(parser);
1963 }
1964
1965
1966 static const lxb_css_syntax_token_t *
lxb_css_selectors_state_function_error(lxb_css_parser_t * parser,const lxb_css_syntax_token_t * token)1967 lxb_css_selectors_state_function_error(lxb_css_parser_t *parser,
1968 const lxb_css_syntax_token_t *token)
1969 {
1970 bool cy, comma;
1971 lxb_css_selector_list_t *list;
1972 lxb_css_selector_t *selector;
1973 lxb_css_selectors_t *selectors = parser->selectors;
1974 const lxb_css_syntax_token_t *origin;
1975 const lxb_css_selectors_pseudo_data_func_t *func;
1976
1977 cy = false;
1978 comma = true;
1979 list = selectors->list_last;
1980 selector = selectors->parent;
1981
1982 if (selector != NULL) {
1983 cy = selector->type == LXB_CSS_SELECTOR_TYPE_PSEUDO_CLASS_FUNCTION;
1984
1985 func = lxb_css_selector_pseudo_function_by_id(selector->u.pseudo.type,
1986 cy);
1987 if (func == NULL) {
1988 return NULL;
1989 }
1990
1991 cy = func->forgiving;
1992 comma = func->comma;
1993 }
1994
1995 if (!selectors->err_in_function) {
1996 origin = lxb_css_syntax_token(parser->tkz);
1997 if (origin == NULL) {
1998 return NULL;
1999 }
2000
2001 if (token->type != LXB_CSS_SYNTAX_TOKEN__END) {
2002 origin = token;
2003 }
2004 else if (origin->type != LXB_CSS_SYNTAX_TOKEN__EOF) {
2005 origin = NULL;
2006 }
2007
2008 if (origin != NULL) {
2009 if (lxb_css_syntax_token_error(parser, origin,
2010 "Selectors") == NULL)
2011 {
2012 return NULL;
2013 }
2014 }
2015 }
2016
2017 selectors->err_in_function = false;
2018
2019 if (cy) {
2020 lxb_css_selector_list_selectors_remove(selectors, list);
2021 lxb_css_selector_list_destroy(list);
2022
2023 while (token != NULL
2024 && token->type != LXB_CSS_SYNTAX_TOKEN__END)
2025 {
2026 if (comma == true
2027 && token->type == LXB_CSS_SYNTAX_TOKEN_COMMA
2028 && lxb_css_parser_rule_deep(parser) == 0)
2029 {
2030 break;
2031 }
2032
2033 lxb_css_syntax_parser_consume(parser);
2034 token = lxb_css_syntax_parser_token(parser);
2035 }
2036
2037 return token;
2038 }
2039
2040 lxb_css_selector_list_destroy_chain(selectors->list);
2041
2042 selectors->list = NULL;
2043 selectors->list_last = NULL;
2044
2045 while (token != NULL
2046 && token->type != LXB_CSS_SYNTAX_TOKEN__END)
2047 {
2048 lxb_css_syntax_parser_consume(parser);
2049 token = lxb_css_syntax_parser_token(parser);
2050 }
2051
2052 return token;
2053 }
2054