php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
state.c
Go to the documentation of this file.
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"
12
13
14static 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
56static bool
57lxb_css_selectors_state_complex_list_end(lxb_css_parser_t *parser,
58 const lxb_css_syntax_token_t *token,
59 void *ctx);
60
61static bool
62lxb_css_selectors_state_relative_list_end(lxb_css_parser_t *parser,
63 const lxb_css_syntax_token_t *token,
64 void *ctx);
65
66static bool
67lxb_css_selectors_state_relative_list_wo_root(lxb_css_parser_t *parser,
68 const lxb_css_syntax_token_t *token,
69 void *ctx);
70
71static bool
72lxb_css_selectors_state_relative_wo_root(lxb_css_parser_t *parser,
73 const lxb_css_syntax_token_t *token,
74 void *ctx);
75
76static bool
77lxb_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
81static bool
82lxb_css_selectors_state_complex_end(lxb_css_parser_t *parser,
83 const lxb_css_syntax_token_t *token,
84 void *ctx);
85
86static bool
87lxb_css_selectors_state_complex_wo_root(lxb_css_parser_t *parser,
88 const lxb_css_syntax_token_t *token,
89 void *ctx);
90
91static bool
92lxb_css_selectors_state_complex_handler(lxb_css_parser_t *parser,
93 const lxb_css_syntax_token_t *token,
94 void *ctx, bool root);
95
96static bool
97lxb_css_selectors_state_compound_list_end(lxb_css_parser_t *parser,
98 const lxb_css_syntax_token_t *token,
99 void *ctx);
100
101static bool
102lxb_css_selectors_state_compound_wo_root(lxb_css_parser_t *parser,
103 const lxb_css_syntax_token_t *token,
104 void *ctx);
105
106static bool
107lxb_css_selectors_state_compound_handler(lxb_css_parser_t *parser,
108 const lxb_css_syntax_token_t *token,
109 void *ctx);
110
111static bool
112lxb_css_selectors_state_compound_sub(lxb_css_parser_t *parser,
113 const lxb_css_syntax_token_t *token,
114 void *ctx);
115
116static bool
117lxb_css_selectors_state_compound_pseudo(lxb_css_parser_t *parser,
118 const lxb_css_syntax_token_t *token,
119 void *ctx);
120
121static bool
122lxb_css_selectors_state_simple_list_end(lxb_css_parser_t *parser,
123 const lxb_css_syntax_token_t *token,
124 void *ctx);
125
126static bool
127lxb_css_selectors_state_simple_wo_root(lxb_css_parser_t *parser,
128 const lxb_css_syntax_token_t *token,
129 void *ctx);
130
131static bool
132lxb_css_selectors_state_simple_handler(lxb_css_parser_t *parser,
133 const lxb_css_syntax_token_t *token,
134 void *ctx);
135
136static bool
137lxb_css_selectors_state_simple_back(lxb_css_parser_t *parser,
138 const lxb_css_syntax_token_t *token,
139 void *ctx);
140
141static lxb_status_t
142lxb_css_selectors_state_hash(lxb_css_parser_t *parser,
143 const lxb_css_syntax_token_t *token);
144
145static lxb_status_t
146lxb_css_selectors_state_class(lxb_css_parser_t *parser,
147 const lxb_css_syntax_token_t *token);
148
149static lxb_status_t
150lxb_css_selectors_state_element_ns(lxb_css_parser_t *parser,
151 const lxb_css_syntax_token_t *token);
152
153static lxb_status_t
154lxb_css_selectors_state_element(lxb_css_parser_t *parser,
155 const lxb_css_syntax_token_t *token);
156
157static lxb_status_t
158lxb_css_selectors_state_attribute(lxb_css_parser_t *parser);
159
160static lxb_status_t
161lxb_css_selectors_state_ns(lxb_css_parser_t *parser,
162 lxb_css_selector_t *selector);
163
164static lxb_status_t
165lxb_css_selectors_state_ns_ident(lxb_css_parser_t *parser,
166 lxb_css_selector_t *selector);
167
168static lxb_status_t
169lxb_css_selectors_state_pseudo_class(lxb_css_parser_t *parser,
170 const lxb_css_syntax_token_t *token);
171
172static lxb_status_t
173lxb_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
177static lxb_status_t
178lxb_css_selectors_state_pseudo_element(lxb_css_parser_t *parser,
179 const lxb_css_syntax_token_t *token);
180
181static lxb_status_t
182lxb_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
186static lxb_status_t
187lxb_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
192static void
193lxb_css_selectors_state_restore_parent(lxb_css_selectors_t *selectors,
195
196static bool
197lxb_css_selectors_state_list_end(lxb_css_parser_t *parser,
198 const lxb_css_syntax_token_t *token,
200
201static bool
202lxb_css_selectors_state_end(lxb_css_parser_t *parser,
203 const lxb_css_syntax_token_t *token, void *ctx);
204
205static const lxb_css_syntax_token_t *
206lxb_css_selectors_state_function_error(lxb_css_parser_t *parser,
207 const lxb_css_syntax_token_t *token);
208
209
210lxb_inline bool
217
218lxb_inline void
220{
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) {
229 lxb_css_selector_sp_set_b(last->specificity, 1);
230 }
231 }
232 else {
234 last->specificity = 0;
235 }
236
237 lxb_css_selector_sp_set_b(last->specificity, 1);
238 }
239}
240
241lxb_inline void
243{
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) {
252 lxb_css_selector_sp_set_c(last->specificity, 1);
253 }
254 }
255 else {
257 last->specificity = 0;
258 }
259
260 lxb_css_selector_sp_set_c(last->specificity, 1);
261 }
262}
263
264lxb_inline void
266{
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 */
282bool
284 const lxb_css_syntax_token_t *token,
285 void *ctx)
286{
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
300static bool
301lxb_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 */
312bool
314 const lxb_css_syntax_token_t *token,
315 void *ctx)
316{
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
330static bool
331lxb_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 */
342bool
344 const lxb_css_syntax_token_t *token,
345 void *ctx)
346{
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
360static bool
361lxb_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
369static bool
370lxb_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
378static bool
379lxb_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{
385 lxb_css_selectors_t *selectors = parser->selectors;
386
387 /* <combinator> */
388
389 switch (token->type) {
393 return true;
394
396 switch (lxb_css_syntax_token_delim_char(token)) {
397 case '>':
399 break;
400
401 case '+':
403 break;
404
405 case '~':
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 {
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
433
434done:
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 */
452bool
454 const lxb_css_syntax_token_t *token, void *ctx)
455{
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
469static bool
470lxb_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
477static bool
478lxb_css_selectors_state_complex_handler(lxb_css_parser_t *parser,
479 const lxb_css_syntax_token_t *token,
480 void *ctx, bool root)
481{
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
495static bool
496lxb_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
504again:
505
506 switch (token->type) {
509
511
512 lxb_css_parser_token_m(parser, token);
513 goto again;
514
516 return lxb_css_selectors_done(parser);
517
519 switch (lxb_css_syntax_token_delim_char(token)) {
520 case '>':
522 break;
523
524 case '+':
526 break;
527
528 case '~':
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 {
540 break;
541 }
542
543 goto done;
544
545 default:
547 goto unexpected;
548 }
549
550 goto done;
551 }
552
553 break;
554
556 return lxb_css_selectors_done(parser);
557
558 default:
560 goto unexpected;
561 }
562
563 goto done;
564 }
565
567
568done:
569
570 lxb_css_parser_state_set(parser, lxb_css_selectors_state_compound_handler);
571
572 return true;
573
574unexpected:
575
577
578 return lxb_css_parser_unexpected(parser);
579}
580
581/*
582 * <compound-selector-list>
583 */
584bool
586 const lxb_css_syntax_token_t *token,
587 void *ctx)
588{
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
602static bool
603lxb_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 */
615bool
617 const lxb_css_syntax_token_t *token,
618 void *ctx)
619{
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
633static bool
634lxb_css_selectors_state_compound_wo_root(lxb_css_parser_t *parser,
635 const lxb_css_syntax_token_t *token,
636 void *ctx)
637{
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
647static bool
648lxb_css_selectors_state_compound_handler(lxb_css_parser_t *parser,
649 const lxb_css_syntax_token_t *token,
650 void *ctx)
651{
653 lxb_css_selectors_t *selectors;
654
655again:
656
657 lxb_css_parser_state_set(parser, lxb_css_selectors_state_compound_sub);
658
659 switch (token->type) {
661 status = lxb_css_selectors_state_hash(parser, token);
662 break;
663
665 switch (lxb_css_syntax_token_delim_char(token)) {
666 case '.':
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
683 status = lxb_css_selectors_state_element(parser, token);
684 break;
685
688 status = lxb_css_selectors_state_attribute(parser);
689 break;
690
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) {
701 lxb_css_parser_token_m(parser, token);
702
703 if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) {
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
727 lxb_css_parser_token_m(parser, token);
728 goto again;
729
731 selectors = parser->selectors;
732
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
750 return lxb_css_parser_memory_fail(parser);
751 }
752
753unexpected:
754
757
758 return lxb_css_parser_unexpected(parser);
759}
760
761static bool
762lxb_css_selectors_state_compound_sub(lxb_css_parser_t *parser,
763 const lxb_css_syntax_token_t *token,
764 void *ctx)
765{
767
768 /* <subclass-selector> */
769
770 switch (token->type) {
772 status = lxb_css_selectors_state_hash(parser, token);
773 break;
774
776 switch (lxb_css_syntax_token_delim_char(token)) {
777 case '.':
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
790 status = lxb_css_selectors_state_attribute(parser);
791 break;
792
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) {
803 lxb_css_parser_token_m(parser, token);
804
805 if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) {
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
837 return lxb_css_parser_memory_fail(parser);
838 }
839
840 return lxb_css_parser_unexpected(parser);
841}
842
843static bool
844lxb_css_selectors_state_compound_pseudo(lxb_css_parser_t *parser,
845 const lxb_css_syntax_token_t *token,
846 void *ctx)
847{
849
850 if (token->type != LXB_CSS_SYNTAX_TOKEN_COLON) {
851 return lxb_css_parser_states_set_back(parser);
852 }
853
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) {
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
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 */
897bool
899 const lxb_css_syntax_token_t *token,
900 void *ctx)
901{
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
914static bool
915lxb_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 */
926bool
928 const lxb_css_syntax_token_t *token, void *ctx)
929{
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
943static bool
944lxb_css_selectors_state_simple_wo_root(lxb_css_parser_t *parser,
945 const lxb_css_syntax_token_t *token,
946 void *ctx)
947{
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
957static bool
958lxb_css_selectors_state_simple_handler(lxb_css_parser_t *parser,
959 const lxb_css_syntax_token_t *token,
960 void *ctx)
961{
963
964again:
965
966 lxb_css_parser_state_set(parser, lxb_css_selectors_state_simple_back);
967
968 switch (token->type) {
970 status = lxb_css_selectors_state_hash(parser, token);
971 break;
972
974 switch (lxb_css_syntax_token_delim_char(token)) {
975 case '.':
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
992 status = lxb_css_selectors_state_element(parser, token);
993 break;
994
997 status = lxb_css_selectors_state_attribute(parser);
998 break;
999
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
1018 lxb_css_parser_token_m(parser, token);
1019 goto again;
1020
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
1033 return lxb_css_parser_memory_fail(parser);
1034 }
1035
1036unexpected:
1037
1039
1040 return lxb_css_parser_unexpected(parser);
1041}
1042
1043static bool
1044lxb_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
1051static lxb_status_t
1052lxb_css_selectors_state_hash(lxb_css_parser_t *parser,
1053 const lxb_css_syntax_token_t *token)
1054{
1056 lxb_css_selector_t *selector;
1057 lxb_css_selectors_t *selectors;
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) {
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
1080 &selector->name, parser->memory->mraw);
1082
1083 return status;
1084}
1085
1086static lxb_status_t
1087lxb_css_selectors_state_class(lxb_css_parser_t *parser,
1088 const lxb_css_syntax_token_t *token)
1089{
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
1100 lxb_css_selectors_state_append(parser, selectors, selector);
1101
1103
1105 &selector->name, parser->memory->mraw);
1107
1108 return status;
1109 }
1110
1111 return lxb_css_parser_unexpected_status(parser);
1112}
1113
1114static lxb_status_t
1115lxb_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) {
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) == '*') {
1138 return lxb_css_selectors_state_ns(parser, selector);
1139 }
1140
1142
1143 return lxb_css_selectors_state_ns_ident(parser, selector);
1144}
1145
1146static lxb_status_t
1147lxb_css_selectors_state_element(lxb_css_parser_t *parser,
1148 const lxb_css_syntax_token_t *token)
1149{
1151 lxb_css_selector_t *selector;
1152 lxb_css_selectors_t *selectors;
1153
1154 selectors = parser->selectors;
1155
1157
1158 lxb_css_selectors_state_append(parser, selectors, selector);
1159
1161
1162 lxb_css_selectors_state_string_dup_m(selectors, &selector->name);
1163
1165
1166 return lxb_css_selectors_state_ns(parser, selector);
1167}
1168
1169
1170static lxb_status_t
1171lxb_css_selectors_state_attribute(lxb_css_parser_t *parser)
1172{
1173 lxb_char_t modifier;
1175 lxb_css_selector_t *selector;
1176 lxb_css_selectors_t *selectors;
1177 const lxb_css_syntax_token_t *token;
1179
1180 selectors = parser->selectors;
1181
1182 lxb_css_selectors_state_append(parser, selectors, selector);
1184
1185 switch (token->type) {
1187 if (lxb_css_syntax_token_delim_char(token) != '|') {
1188 goto failed;
1189 }
1190
1192 lxb_css_parser_token_status_m(parser, token);
1193
1194 if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) {
1195 goto failed;
1196 }
1197
1199
1200 selector->ns.data = lexbor_mraw_alloc(parser->memory->mraw, 2);
1201 if (selector->ns.data == NULL) {
1203 }
1204
1205 selector->ns.data[0] = '*';
1206 selector->ns.data[1] = '\0';
1207 selector->ns.length = 1;
1208
1210 &selector->name);
1211
1214 break;
1215
1218
1219 lxb_css_selectors_state_string_dup_m(selectors, &selector->name);
1220
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) {
1229 lxb_css_parser_token_status_m(parser, token);
1230 }
1231
1232 break;
1233 }
1234
1236 lxb_css_parser_token_status_m(parser, token);
1237
1238 if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) {
1239 attribute = &selector->u.attribute;
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
1252 break;
1253
1254 default:
1255 goto failed;
1256 }
1257
1258 attribute = &selector->u.attribute;
1259
1260 switch (token->type) {
1262 goto done;
1263
1265 switch (lxb_css_syntax_token_delim_char(token)) {
1266 case '~':
1268 break;
1269
1270 case '|':
1272 break;
1273
1274 case '^':
1276 break;
1277
1278 case '$':
1280 break;
1281
1282 case '*':
1284 break;
1285
1286 case '=':
1288
1291 goto string_or_ident;
1292
1293 default:
1294 goto failed;
1295 }
1296
1298 lxb_css_parser_token_status_m(parser, token);
1299
1300 break;
1301
1302 default:
1303 goto failed;
1304 }
1305
1306assignment:
1307
1308 if (token->type != LXB_CSS_SYNTAX_TOKEN_DELIM
1309 || lxb_css_syntax_token_delim_char(token) != '=')
1310 {
1311 goto failed;
1312 }
1313
1316
1317string_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
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':
1343 break;
1344
1345 case 's':
1347 break;
1348
1349 default:
1350 goto failed;
1351 }
1352
1355
1356 if (token->type != LXB_CSS_SYNTAX_TOKEN_RS_BRACKET) {
1357 goto failed;
1358 }
1359
1360done:
1361
1364
1365 return LXB_STATUS_OK;
1366
1367failed:
1368
1369 return lxb_css_parser_unexpected_status(parser);
1370}
1371
1372static lxb_status_t
1373lxb_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 {
1384 return lxb_css_selectors_state_ns_ident(parser, selector);
1385 }
1386
1387 return LXB_STATUS_OK;
1388}
1389
1390static lxb_status_t
1391lxb_css_selectors_state_ns_ident(lxb_css_parser_t *parser,
1392 lxb_css_selector_t *selector)
1393{
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
1404
1406
1407 selector->ns = selector->name;
1408 lexbor_str_clean_all(&selector->name);
1409
1411 &selector->name, parser->memory->mraw);
1412
1414
1415 return status;
1416 }
1417 else if (token->type == LXB_CSS_SYNTAX_TOKEN_DELIM
1418 && lxb_css_syntax_token_delim_char(token) == '*')
1419 {
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) {
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
1441static lxb_status_t
1442lxb_css_selectors_state_pseudo_class(lxb_css_parser_t *parser,
1443 const lxb_css_syntax_token_t *token)
1444{
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);
1455
1456 lxb_css_selectors_state_string_dup_m(selectors, &selector->name);
1457
1459 selector->name.length);
1460 if (pseudo == NULL) {
1461 return lxb_css_parser_unexpected_status(parser);
1462 }
1463
1464 switch (pseudo->id) {
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
1501
1502 return LXB_STATUS_OK;
1503}
1504
1505static lxb_status_t
1506lxb_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{
1511 lxb_css_selector_t *selector;
1512 lxb_css_selectors_t *selectors;
1516
1517 selectors = parser->selectors;
1518
1519 lxb_css_selectors_state_append(parser, selectors, selector);
1521
1522 lxb_css_selectors_state_string_dup_m(selectors, &selector->name);
1523
1525 selector->name.length);
1526 if (func == NULL) {
1527 return lxb_css_parser_unexpected_status(parser);
1528 }
1529
1530 switch (func->id) {
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
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
1567
1568 return LXB_STATUS_OK;
1569
1570failed:
1571
1573
1574 return parser->status;
1575}
1576
1577static lxb_status_t
1578lxb_css_selectors_state_pseudo_element(lxb_css_parser_t *parser,
1579 const lxb_css_syntax_token_t *token)
1580{
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);
1591
1592 lxb_css_selectors_state_string_dup_m(selectors, &selector->name);
1593
1595 selector->name.length);
1596 if (pseudo == NULL) {
1597 return lxb_css_parser_unexpected_status(parser);
1598 }
1599
1600 switch (pseudo->id) {
1614 lxb_css_selectors_module_name,
1615 (const char *) selector->name.data);
1616 if (msg == NULL) {
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
1631
1632 return LXB_STATUS_OK;
1633}
1634
1635static lxb_status_t
1636lxb_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{
1641 lxb_css_selector_t *selector;
1642 lxb_css_selectors_t *selectors;
1645
1646 selectors = parser->selectors;
1647
1648 lxb_css_selectors_state_append(parser, selectors, selector);
1650
1651 lxb_css_selectors_state_string_dup_m(selectors, &selector->name);
1652
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) {
1670 return parser->status;
1671 }
1672
1674
1675 return LXB_STATUS_OK;
1676}
1677
1678lxb_inline void
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
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
1701 selectors->comb_default = comb_default;
1702}
1703
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) {
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
1728empty:
1729
1730 selector = selectors->list_last->last;
1731
1734 cy);
1735 if (cy) {
1736 lxb_css_parser_set_ok(parser);
1737 return LXB_STATUS_OK;
1738 }
1739
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
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,
1760 failed);
1761}
1762
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,
1770 failed);
1771}
1772
1773static lxb_status_t
1774lxb_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) {
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
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
1806empty:
1807
1808 selector = selectors->list_last->last;
1809
1812 cy);
1813 if (cy) {
1814 return LXB_STATUS_OK;
1815 }
1816
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
1830static void
1831lxb_css_selectors_state_restore_parent(lxb_css_selectors_t *selectors,
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) {
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
1872}
1873
1874static bool
1875lxb_css_selectors_state_list_end(lxb_css_parser_t *parser,
1876 const lxb_css_syntax_token_t *token,
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,
1887 }
1888 }
1889 else if (token->type == LXB_CSS_SYNTAX_TOKEN_WHITESPACE) {
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 {
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,
1909 }
1910 }
1911
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
1923 lxb_css_parser_set_ok(parser);
1924
1925 return true;
1926}
1927
1928static bool
1929lxb_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) {
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,
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,
1955 }
1956 }
1957
1959 return lxb_css_parser_success(parser);
1960 }
1961
1962 return lxb_css_selectors_done(parser);
1963}
1964
1965
1966static const lxb_css_syntax_token_t *
1967lxb_css_selectors_state_function_error(lxb_css_parser_t *parser,
1968 const lxb_css_syntax_token_t *token)
1969{
1970 bool cy, comma;
1972 lxb_css_selector_t *selector;
1973 lxb_css_selectors_t *selectors = parser->selectors;
1974 const lxb_css_syntax_token_t *origin;
1976
1977 cy = false;
1978 comma = true;
1979 list = selectors->list_last;
1980 selector = selectors->parent;
1981
1982 if (selector != NULL) {
1984
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) {
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
2034 token = lxb_css_syntax_parser_token(parser);
2035 }
2036
2037 return token;
2038 }
2039
2041
2042 selectors->list = NULL;
2043 selectors->list_last = NULL;
2044
2045 while (token != NULL
2046 && token->type != LXB_CSS_SYNTAX_TOKEN__END)
2047 {
2049 token = lxb_css_syntax_parser_token(parser);
2050 }
2051
2052 return token;
2053}
prev(array|object &$array)
@ LXB_STATUS_ERROR_MEMORY_ALLOCATION
Definition base.h:51
@ LXB_STATUS_OK
Definition base.h:49
struct lxb_css_parser_state lxb_css_parser_state_t
Definition base.h:42
struct lxb_css_syntax_token lxb_css_syntax_token_t
Definition base.h:46
bool(* lxb_css_parser_state_f)(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, void *ctx)
Definition base.h:49
struct lxb_css_parser lxb_css_parser_t
Definition base.h:41
bool lxb_css_parser_unexpected(lxb_css_parser_t *parser)
Definition parser.c:272
bool lxb_css_parser_success(lxb_css_parser_t *parser)
Definition parser.c:279
lxb_status_t lxb_css_parser_unexpected_status(lxb_css_parser_t *parser)
Definition parser.c:297
bool lxb_css_parser_fail(lxb_css_parser_t *parser, lxb_status_t status)
Definition parser.c:264
bool lxb_css_parser_memory_fail(lxb_css_parser_t *parser)
Definition parser.c:335
lxb_css_parser_state_t * lxb_css_parser_states_next(lxb_css_parser_t *parser, lxb_css_parser_state_f next, lxb_css_parser_state_f back, void *ctx, bool root)
Definition parser.c:208
lxb_inline void lxb_css_parser_set_ok(lxb_css_parser_t *parser)
Definition parser.h:321
#define lxb_css_parser_token_status_m(parser, token)
Definition parser.h:56
#define lxb_css_parser_token_status_wo_ws_m(parser, token)
Definition parser.h:74
lxb_inline lxb_css_parser_state_t * lxb_css_parser_states_to_root(lxb_css_parser_t *parser)
Definition parser.h:401
lxb_inline size_t lxb_css_parser_rule_deep(lxb_css_parser_t *parser)
Definition parser.h:389
#define lxb_css_parser_token_next_m(parser, token)
Definition parser.h:30
#define lxb_css_parser_token_m(parser, token)
Definition parser.h:21
lxb_inline bool lxb_css_parser_states_set_back(lxb_css_parser_t *parser)
Definition parser.h:415
lxb_inline lxb_css_parser_state_t * lxb_css_parser_states_current(lxb_css_parser_t *parser)
Definition parser.h:440
lxb_inline void lxb_css_parser_state_set(lxb_css_parser_t *parser, lxb_css_parser_state_f state)
Definition parser.h:351
lxb_inline void lxb_css_parser_failed_set_by_id(lxb_css_parser_t *parser, int idx, bool is)
Definition parser.h:305
lxb_inline lxb_css_parser_state_t * lxb_css_parser_states_pop(lxb_css_parser_t *parser)
Definition parser.h:395
lxb_inline bool lxb_css_parser_is_failed(lxb_css_parser_t *parser)
Definition parser.h:315
struct lxb_css_selector lxb_css_selector_t
Definition base.h:39
struct lxb_css_selector_list lxb_css_selector_list_t
Definition base.h:40
struct lxb_css_selectors lxb_css_selectors_t
Definition base.h:38
#define lxb_css_selectors_state_string_dup_m(selectors, name)
Definition state.c:17
bool lxb_css_selectors_state_compound(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, void *ctx)
Definition state.c:616
bool lxb_css_selectors_state_compound_list(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, void *ctx)
Definition state.c:585
bool lxb_css_selectors_state_simple(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, void *ctx)
Definition state.c:927
lxb_inline void lxb_css_selectors_state_restore_combinator(lxb_css_selectors_t *selectors)
Definition state.c:1679
#define lxb_css_selectors_state_append(parser, selectors, selector)
Definition state.c:28
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)
Definition state.c:1764
lxb_inline bool lxb_css_selectors_done(lxb_css_parser_t *parser)
Definition state.c:211
bool lxb_css_selectors_state_relative_list(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, void *ctx)
Definition state.c:313
bool lxb_css_selectors_state_complex(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, void *ctx)
Definition state.c:453
bool lxb_css_selectors_state_relative(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, void *ctx)
Definition state.c:343
lxb_inline void lxb_css_selectors_state_func_specificity(lxb_css_selectors_t *selectors)
Definition state.c:265
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)
Definition state.c:1754
lxb_inline void lxb_css_selectors_state_specificity_set_c(lxb_css_selectors_t *selectors)
Definition state.c:242
bool lxb_css_selectors_state_complex_list(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, void *ctx)
Definition state.c:283
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)
Definition state.c:1705
#define lxb_css_selectors_state_list_append(parser, selectors, list)
Definition state.c:42
lxb_inline void lxb_css_selectors_state_specificity_set_b(lxb_css_selectors_t *selectors)
Definition state.c:219
bool lxb_css_selectors_state_simple_list(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, void *ctx)
Definition state.c:898
lxb_css_syntax_rule_t * lxb_css_syntax_parser_function_push(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, lxb_css_parser_state_f state_back, const lxb_css_syntax_cb_function_t *func, void *ctx)
Definition parser.c:427
const lxb_css_syntax_token_t * lxb_css_syntax_parser_token(lxb_css_parser_t *parser)
Definition parser.c:142
void lxb_css_syntax_parser_consume(lxb_css_parser_t *parser)
Definition parser.c:171
lxb_css_log_message_t * lxb_css_syntax_token_error(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, const char *module_name)
Definition token.c:594
lxb_css_syntax_token_t * lxb_css_syntax_token(lxb_css_syntax_tokenizer_t *tkz)
Definition token.c:45
lxb_status_t lxb_css_syntax_token_string_dup(lxb_css_syntax_token_string_t *token, lexbor_str_t *str, lexbor_mraw_t *mraw)
Definition token.c:96
void lxb_css_syntax_token_consume(lxb_css_syntax_tokenizer_t *tkz)
Definition token.c:63
#define lxb_css_syntax_token_string(token)
Definition token.h:25
@ LXB_CSS_SYNTAX_TOKEN_FUNCTION
Definition token.h:73
@ LXB_CSS_SYNTAX_TOKEN_LS_BRACKET
Definition token.h:95
@ LXB_CSS_SYNTAX_TOKEN__EOF
Definition token.h:101
@ LXB_CSS_SYNTAX_TOKEN_COMMA
Definition token.h:94
@ LXB_CSS_SYNTAX_TOKEN_DELIM
Definition token.h:87
@ LXB_CSS_SYNTAX_TOKEN_COLON
Definition token.h:92
@ LXB_CSS_SYNTAX_TOKEN_RS_BRACKET
Definition token.h:96
@ LXB_CSS_SYNTAX_TOKEN_STRING
Definition token.h:76
@ LXB_CSS_SYNTAX_TOKEN_IDENT
Definition token.h:72
@ LXB_CSS_SYNTAX_TOKEN_WHITESPACE
Definition token.h:81
@ LXB_CSS_SYNTAX_TOKEN_HASH
Definition token.h:75
@ LXB_CSS_SYNTAX_TOKEN__END
Definition token.h:103
#define lxb_css_syntax_token_delim_char(token)
Definition token.h:30
DNS_STATUS status
Definition dns_win32.c:49
#define NULL
Definition gdcache.h:45
lxb_css_log_message_t * lxb_css_log_format(lxb_css_log_t *log, lxb_css_log_type_t type, const char *format,...)
Definition log.c:140
lxb_css_log_message_t * lxb_css_log_not_supported(lxb_css_log_t *log, const char *module_name, const char *description)
Definition log.c:170
@ LXB_CSS_LOG_ERROR
Definition log.h:23
void * lexbor_mraw_alloc(lexbor_mraw_t *mraw, size_t size)
Definition mraw.c:180
char * msg
Definition phpdbg.h:289
const lxb_css_selectors_pseudo_data_func_t * lxb_css_selector_pseudo_class_function_by_id(unsigned id)
Definition pseudo.c:44
const lxb_css_selectors_pseudo_data_func_t * lxb_css_selector_pseudo_element_function_by_id(unsigned id)
Definition pseudo.c:79
bool lxb_css_selector_pseudo_function_can_empty(unsigned id, bool is_class)
Definition pseudo.c:95
const lxb_css_selectors_pseudo_data_func_t * lxb_css_selector_pseudo_class_function_by_name(const lxb_char_t *name, size_t length)
Definition pseudo.c:29
const lxb_css_selectors_pseudo_data_func_t * lxb_css_selector_pseudo_function_by_id(unsigned id, bool is_class)
Definition pseudo.c:85
const lxb_css_selectors_pseudo_data_func_t * lxb_css_selector_pseudo_element_function_by_name(const lxb_char_t *name, size_t length)
Definition pseudo.c:64
const lxb_css_selectors_pseudo_data_t * lxb_css_selector_pseudo_class_by_name(const lxb_char_t *name, size_t length)
Definition pseudo.c:15
const lxb_css_selectors_pseudo_data_t * lxb_css_selector_pseudo_element_by_name(const lxb_char_t *name, size_t length)
Definition pseudo.c:50
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_IN_RANGE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_PAST
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_WARNING
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_TARGET_WITHIN
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_LOCAL_LINK
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FULLSCREEN
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_CURRENT
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_VISITED
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FOCUS_WITHIN
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_INDETERMINATE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUTURE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FOCUS_VISIBLE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_USER_INVALID
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_VALID
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_SCOPE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_DEFAULT
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_INVALID
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_TARGET
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_OUT_OF_RANGE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_COL
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_DIR
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_COL
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_LANG
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_WHERE
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_CHILD
@ LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_CHILD
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_SELECTION
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_BACKDROP
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_AFTER
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_GRAMMAR_ERROR
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_TARGET_TEXT
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_PLACEHOLDER
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_FIRST_LINE
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_BEFORE
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_INACTIVE_SELECTION
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_SPELLING_ERROR
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_MARKER
@ LXB_CSS_SELECTOR_PSEUDO_ELEMENT_FIRST_LETTER
void lxb_css_selector_remove(lxb_css_selector_t *selector)
Definition selector.c:149
void lxb_css_selector_list_destroy(lxb_css_selector_list_t *list)
Definition selector.c:211
void lxb_css_selector_list_destroy_chain(lxb_css_selector_list_t *list)
Definition selector.c:220
void lxb_css_selector_list_selectors_remove(lxb_css_selectors_t *selectors, lxb_css_selector_list_t *list)
Definition selector.c:196
void lxb_css_selector_destroy(lxb_css_selector_t *selector)
Definition selector.c:124
#define lxb_css_selector_sp_c(sp)
Definition selector.h:126
#define lxb_css_selector_sp_add_b(sp, num)
Definition selector.h:150
#define lxb_css_selector_sp_set_b(sp, num)
Definition selector.h:138
lxb_css_selector_combinator_t
Definition selector.h:34
@ LXB_CSS_SELECTOR_COMBINATOR_CELL
Definition selector.h:40
@ LXB_CSS_SELECTOR_COMBINATOR_CLOSE
Definition selector.h:36
@ LXB_CSS_SELECTOR_COMBINATOR_DESCENDANT
Definition selector.h:35
@ LXB_CSS_SELECTOR_COMBINATOR_SIBLING
Definition selector.h:38
@ LXB_CSS_SELECTOR_COMBINATOR_CHILD
Definition selector.h:37
@ LXB_CSS_SELECTOR_COMBINATOR_FOLLOWING
Definition selector.h:39
#define lxb_css_selector_sp_set_a(sp, num)
Definition selector.h:135
#define lxb_css_selector_sp_add_c(sp, num)
Definition selector.h:153
@ LXB_CSS_SELECTOR_TYPE_ELEMENT
Definition selector.h:22
@ LXB_CSS_SELECTOR_TYPE_PSEUDO_CLASS_FUNCTION
Definition selector.h:27
@ LXB_CSS_SELECTOR_TYPE_PSEUDO_CLASS
Definition selector.h:26
@ LXB_CSS_SELECTOR_TYPE_ATTRIBUTE
Definition selector.h:25
@ LXB_CSS_SELECTOR_TYPE_PSEUDO_ELEMENT_FUNCTION
Definition selector.h:29
@ LXB_CSS_SELECTOR_TYPE_ID
Definition selector.h:23
@ LXB_CSS_SELECTOR_TYPE_CLASS
Definition selector.h:24
@ LXB_CSS_SELECTOR_TYPE_PSEUDO_ELEMENT
Definition selector.h:28
@ LXB_CSS_SELECTOR_TYPE_ANY
Definition selector.h:21
#define lxb_css_selector_sp_add_a(sp, num)
Definition selector.h:147
#define lxb_css_selector_sp_b(sp)
Definition selector.h:123
#define LXB_CSS_SELECTOR_SP_B_MAX
Definition selector.h:161
#define lxb_css_selector_sp_a(sp)
Definition selector.h:120
#define lxb_css_selector_sp_set_c(sp, num)
Definition selector.h:141
#define LXB_CSS_SELECTOR_SP_C_MAX
Definition selector.h:162
@ LXB_CSS_SELECTOR_MODIFIER_S
Definition selector.h:59
@ LXB_CSS_SELECTOR_MODIFIER_I
Definition selector.h:58
@ LXB_CSS_SELECTOR_MATCH_PREFIX
Definition selector.h:49
@ LXB_CSS_SELECTOR_MATCH_SUBSTRING
Definition selector.h:51
@ LXB_CSS_SELECTOR_MATCH_DASH
Definition selector.h:48
@ LXB_CSS_SELECTOR_MATCH_SUFFIX
Definition selector.h:50
@ LXB_CSS_SELECTOR_MATCH_INCLUDE
Definition selector.h:47
@ LXB_CSS_SELECTOR_MATCH_EQUAL
Definition selector.h:46
void lexbor_str_clean_all(lexbor_str_t *str)
Definition str.c:70
lxb_char_t * data
Definition str.h:47
size_t length
Definition str.h:48
lexbor_mraw_t * mraw
Definition base.h:32
lxb_css_log_t * log
Definition parser.h:168
lxb_status_t status
Definition parser.h:177
lxb_css_memory_t * memory
Definition parser.h:141
lxb_css_syntax_tokenizer_t * tkz
Definition parser.h:136
lxb_css_selectors_t * selectors
Definition parser.h:137
lxb_css_selector_modifier_t modifier
Definition selector.h:66
lxb_css_selector_match_t match
Definition selector.h:65
lxb_css_selector_t * last
Definition selector.h:167
lxb_css_selector_specificity_t specificity
Definition selector.h:176
lxb_css_selector_list_t * prev
Definition selector.h:172
lxb_css_selector_t * first
Definition selector.h:166
lxb_css_selector_type_t type
Definition selector.h:84
lexbor_str_t ns
Definition selector.h:88
union lxb_css_selector::lxb_css_selector_u u
lexbor_str_t name
Definition selector.h:87
lxb_css_selector_combinator_t combinator
Definition pseudo.h:24
lxb_css_selector_list_t * list_last
Definition selectors.h:25
lxb_css_selector_combinator_t combinator
Definition selectors.h:29
lxb_css_selector_list_t * list
Definition selectors.h:24
lxb_css_selector_t * parent
Definition selectors.h:27
lxb_css_selector_combinator_t comb_default
Definition selectors.h:30
lxb_css_syntax_token_type_t type
Definition token.h:192
struct lxb_css_syntax_rule lxb_css_syntax_rule_t
Definition syntax.h:17
unsigned int lxb_status_t
Definition types.h:28
#define lxb_inline
Definition types.h:21
unsigned char lxb_char_t
Definition types.h:27
lxb_css_selector_attribute_t attribute
Definition selector.h:91
lxb_css_selector_pseudo_t pseudo
Definition selector.h:92
execute_data func
ZEND_API void(ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data)
int last