xref: /PHP-8.4/ext/dom/lexbor/lexbor/css/selectors/state.c (revision 7defc235)
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