1// sass.hpp must go before all system headers to get the
2// __EXTENSIONS__ fix on Solaris.
3#include "sass.hpp"
4
5#include <iostream>
6#include <iomanip>
7#include "util.hpp"
8#include "util_string.hpp"
9#include "position.hpp"
10#include "prelexer.hpp"
11#include "constants.hpp"
12
13
14namespace Sass {
15 // using namespace Lexer;
16 using namespace Constants;
17
18 namespace Prelexer {
19
20
21 /*
22
23 def string_re(open, close)
24 /#{open}((?:\\.|\#(?!\{)|[^#{close}\\#])*)(#{close}|#\{)/m
25 end
26 end
27
28 # A hash of regular expressions that are used for tokenizing strings.
29 #
30 # The key is a `[Symbol, Boolean]` pair.
31 # The symbol represents which style of quotation to use,
32 # while the boolean represents whether or not the string
33 # is following an interpolated segment.
34 STRING_REGULAR_EXPRESSIONS = {
35 :double => {
36 /#{open}((?:\\.|\#(?!\{)|[^#{close}\\#])*)(#{close}|#\{)/m
37 false => string_re('"', '"'),
38 true => string_re('', '"')
39 },
40 :single => {
41 false => string_re("'", "'"),
42 true => string_re('', "'")
43 },
44 :uri => {
45 false => /url\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
46 true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
47 },
48 # Defined in https://developer.mozilla.org/en/CSS/@-moz-document as a
49 # non-standard version of http://www.w3.org/TR/css3-conditional/
50 :url_prefix => {
51 false => /url-prefix\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
52 true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
53 },
54 :domain => {
55 false => /domain\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
56 true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
57 }
58 }
59 */
60
61 /*
62 /#{open}
63 (
64 \\.
65 |
66 \# (?!\{)
67 |
68 [^#{close}\\#]
69 )*
70 (#{close}|#\{)
71 /m
72 false => string_re('"', '"'),
73 true => string_re('', '"')
74 */
75 extern const char string_double_negates[] = "\"\\#";
76 const char* re_string_double_close(const char* src)
77 {
78 return sequence <
79 // valid chars
80 zero_plus <
81 alternatives <
82 // escaped char
83 sequence <
84 exactly <'\\'>,
85 any_char
86 >,
87 // non interpolate hash
88 sequence <
89 exactly <'#'>,
90 negate <
91 exactly <'{'>
92 >
93 >,
94 // other valid chars
95 neg_class_char <
96 string_double_negates
97 >
98 >
99 >,
100 // quoted string closer
101 // or interpolate opening
102 alternatives <
103 exactly <'"'>,
104 lookahead < exactly< hash_lbrace > >
105 >
106 >(src);
107 }
108
109 const char* re_string_double_open(const char* src)
110 {
111 return sequence <
112 // quoted string opener
113 exactly <'"'>,
114 // valid chars
115 zero_plus <
116 alternatives <
117 // escaped char
118 sequence <
119 exactly <'\\'>,
120 any_char
121 >,
122 // non interpolate hash
123 sequence <
124 exactly <'#'>,
125 negate <
126 exactly <'{'>
127 >
128 >,
129 // other valid chars
130 neg_class_char <
131 string_double_negates
132 >
133 >
134 >,
135 // quoted string closer
136 // or interpolate opening
137 alternatives <
138 exactly <'"'>,
139 lookahead < exactly< hash_lbrace > >
140 >
141 >(src);
142 }
143
144 extern const char string_single_negates[] = "'\\#";
145 const char* re_string_single_close(const char* src)
146 {
147 return sequence <
148 // valid chars
149 zero_plus <
150 alternatives <
151 // escaped char
152 sequence <
153 exactly <'\\'>,
154 any_char
155 >,
156 // non interpolate hash
157 sequence <
158 exactly <'#'>,
159 negate <
160 exactly <'{'>
161 >
162 >,
163 // other valid chars
164 neg_class_char <
165 string_single_negates
166 >
167 >
168 >,
169 // quoted string closer
170 // or interpolate opening
171 alternatives <
172 exactly <'\''>,
173 lookahead < exactly< hash_lbrace > >
174 >
175 >(src);
176 }
177
178 const char* re_string_single_open(const char* src)
179 {
180 return sequence <
181 // quoted string opener
182 exactly <'\''>,
183 // valid chars
184 zero_plus <
185 alternatives <
186 // escaped char
187 sequence <
188 exactly <'\\'>,
189 any_char
190 >,
191 // non interpolate hash
192 sequence <
193 exactly <'#'>,
194 negate <
195 exactly <'{'>
196 >
197 >,
198 // other valid chars
199 neg_class_char <
200 string_single_negates
201 >
202 >
203 >,
204 // quoted string closer
205 // or interpolate opening
206 alternatives <
207 exactly <'\''>,
208 lookahead < exactly< hash_lbrace > >
209 >
210 >(src);
211 }
212
213 /*
214 :uri => {
215 false => /url\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
216 true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
217 },
218 */
219 const char* re_string_uri_close(const char* src)
220 {
221 return sequence <
222 non_greedy<
223 alternatives<
224 class_char< real_uri_chars >,
225 uri_character,
226 NONASCII,
227 ESCAPE
228 >,
229 alternatives<
230 sequence < optional < W >, exactly <')'> >,
231 lookahead < exactly< hash_lbrace > >
232 >
233 >,
234 optional <
235 sequence < optional < W >, exactly <')'> >
236 >
237 >(src);
238 }
239
240 const char* re_string_uri_open(const char* src)
241 {
242 return sequence <
243 exactly <'u'>,
244 exactly <'r'>,
245 exactly <'l'>,
246 exactly <'('>,
247 W,
248 alternatives<
249 quoted_string,
250 non_greedy<
251 alternatives<
252 class_char< real_uri_chars >,
253 uri_character,
254 NONASCII,
255 ESCAPE
256 >,
257 alternatives<
258 sequence < W, exactly <')'> >,
259 exactly< hash_lbrace >
260 >
261 >
262 >
263 >(src);
264 }
265
266 // Match a line comment (/.*?(?=\n|\r\n?|\f|\Z)/.
267 const char* line_comment(const char* src)
268 {
269 return sequence<
270 exactly <
271 slash_slash
272 >,
273 non_greedy<
274 any_char,
275 end_of_line
276 >
277 >(src);
278 }
279
280 // Match a block comment.
281 const char* block_comment(const char* src)
282 {
283 return sequence<
284 delimited_by<
285 slash_star,
286 star_slash,
287 false
288 >
289 >(src);
290 }
291 /* not use anymore - remove?
292 const char* block_comment_prefix(const char* src) {
293 return exactly<slash_star>(src);
294 }
295 // Match either comment.
296 const char* comment(const char* src) {
297 return line_comment(src);
298 }
299 */
300
301 // Match zero plus white-space or line_comments
302 const char* optional_css_whitespace(const char* src) {
303 return zero_plus< alternatives<spaces, line_comment> >(src);
304 }
305 const char* css_whitespace(const char* src) {
306 return one_plus< alternatives<spaces, line_comment> >(src);
307 }
308 // Match optional_css_whitepace plus block_comments
309 const char* optional_css_comments(const char* src) {
310 return zero_plus< alternatives<spaces, line_comment, block_comment> >(src);
311 }
312 const char* css_comments(const char* src) {
313 return one_plus< alternatives<spaces, line_comment, block_comment> >(src);
314 }
315
316 // Match one backslash escaped char /\\./
317 const char* escape_seq(const char* src)
318 {
319 return sequence<
320 exactly<'\\'>,
321 alternatives <
322 minmax_range<
323 1, 3, xdigit
324 >,
325 any_char
326 >,
327 optional <
328 exactly <' '>
329 >
330 >(src);
331 }
332
333 // Match identifier start
334 const char* identifier_alpha(const char* src)
335 {
336 return alternatives<
337 unicode_seq,
338 alpha,
339 nonascii,
340 exactly<'-'>,
341 exactly<'_'>,
342 NONASCII,
343 ESCAPE,
344 escape_seq
345 >(src);
346 }
347
348 // Match identifier after start
349 const char* identifier_alnum(const char* src)
350 {
351 return alternatives<
352 unicode_seq,
353 alnum,
354 nonascii,
355 exactly<'-'>,
356 exactly<'_'>,
357 NONASCII,
358 ESCAPE,
359 escape_seq
360 >(src);
361 }
362
363 // Match CSS identifiers.
364 const char* strict_identifier(const char* src)
365 {
366 return sequence<
367 one_plus < strict_identifier_alpha >,
368 zero_plus < strict_identifier_alnum >
369 // word_boundary not needed
370 >(src);
371 }
372
373 // Match CSS identifiers.
374 const char* identifier(const char* src)
375 {
376 return sequence<
377 zero_plus< exactly<'-'> >,
378 one_plus < identifier_alpha >,
379 zero_plus < identifier_alnum >
380 // word_boundary not needed
381 >(src);
382 }
383
384 const char* strict_identifier_alpha(const char* src)
385 {
386 return alternatives <
387 alpha,
388 nonascii,
389 escape_seq,
390 exactly<'_'>
391 >(src);
392 }
393
394 const char* strict_identifier_alnum(const char* src)
395 {
396 return alternatives <
397 alnum,
398 nonascii,
399 escape_seq,
400 exactly<'_'>
401 >(src);
402 }
403
404 // Match a single CSS unit
405 const char* one_unit(const char* src)
406 {
407 return sequence <
408 optional < exactly <'-'> >,
409 strict_identifier_alpha,
410 zero_plus < alternatives<
411 strict_identifier_alnum,
412 sequence <
413 one_plus < exactly<'-'> >,
414 strict_identifier_alpha
415 >
416 > >
417 >(src);
418 }
419
420 // Match numerator/denominator CSS units
421 const char* multiple_units(const char* src)
422 {
423 return
424 sequence <
425 one_unit,
426 zero_plus <
427 sequence <
428 exactly <'*'>,
429 one_unit
430 >
431 >
432 >(src);
433 }
434
435 // Match complex CSS unit identifiers
436 const char* unit_identifier(const char* src)
437 {
438 return sequence <
439 multiple_units,
440 optional <
441 sequence <
442 exactly <'/'>,
443 negate < sequence <
444 exactly < calc_fn_kwd >,
445 exactly < '(' >
446 > >,
447 multiple_units
448 > >
449 >(src);
450 }
451
452 const char* identifier_alnums(const char* src)
453 {
454 return one_plus< identifier_alnum >(src);
455 }
456
457 // Match number prefix ([\+\-]+)
458 const char* number_prefix(const char* src) {
459 return alternatives <
460 exactly < '+' >,
461 sequence <
462 exactly < '-' >,
463 optional_css_whitespace,
464 exactly< '-' >
465 >
466 >(src);
467 }
468
469 // Match interpolant schemas
470 const char* identifier_schema(const char* src) {
471
472 return sequence <
473 one_plus <
474 sequence <
475 zero_plus <
476 alternatives <
477 sequence <
478 optional <
479 exactly <'$'>
480 >,
481 identifier
482 >,
483 exactly <'-'>
484 >
485 >,
486 interpolant,
487 zero_plus <
488 alternatives <
489 digits,
490 sequence <
491 optional <
492 exactly <'$'>
493 >,
494 identifier
495 >,
496 quoted_string,
497 exactly<'-'>
498 >
499 >
500 >
501 >,
502 negate <
503 exactly<'%'>
504 >
505 > (src);
506 }
507
508 // interpolants can be recursive/nested
509 const char* interpolant(const char* src) {
510 return recursive_scopes< exactly<hash_lbrace>, exactly<rbrace> >(src);
511 }
512
513 // $re_squote = /'(?:$re_itplnt|\\.|[^'])*'/
514 const char* single_quoted_string(const char* src) {
515 // match a single quoted string, while skipping interpolants
516 return sequence <
517 exactly <'\''>,
518 zero_plus <
519 alternatives <
520 // skip escapes
521 sequence <
522 exactly < '\\' >,
523 re_linebreak
524 >,
525 escape_seq,
526 unicode_seq,
527 // skip interpolants
528 interpolant,
529 // skip non delimiters
530 any_char_but < '\'' >
531 >
532 >,
533 exactly <'\''>
534 >(src);
535 }
536
537 // $re_dquote = /"(?:$re_itp|\\.|[^"])*"/
538 const char* double_quoted_string(const char* src) {
539 // match a single quoted string, while skipping interpolants
540 return sequence <
541 exactly <'"'>,
542 zero_plus <
543 alternatives <
544 // skip escapes
545 sequence <
546 exactly < '\\' >,
547 re_linebreak
548 >,
549 escape_seq,
550 unicode_seq,
551 // skip interpolants
552 interpolant,
553 // skip non delimiters
554 any_char_but < '"' >
555 >
556 >,
557 exactly <'"'>
558 >(src);
559 }
560
561 // $re_quoted = /(?:$re_squote|$re_dquote)/
562 const char* quoted_string(const char* src) {
563 // match a quoted string, while skipping interpolants
564 return alternatives<
565 single_quoted_string,
566 double_quoted_string
567 >(src);
568 }
569
570 const char* sass_value(const char* src) {
571 return alternatives <
572 quoted_string,
573 identifier,
574 percentage,
575 hex,
576 dimension,
577 number
578 >(src);
579 }
580
581 // this is basically `one_plus < sass_value >`
582 // takes care to not parse invalid combinations
583 const char* value_combinations(const char* src) {
584 // `2px-2px` is invalid combo
585 bool was_number = false;
586 const char* pos;
587 while (src) {
588 if ((pos = alternatives < quoted_string, identifier, percentage, hex >(src))) {
589 was_number = false;
590 src = pos;
591 } else if (!was_number && !exactly<'+'>(src) && (pos = alternatives < dimension, number >(src))) {
592 was_number = true;
593 src = pos;
594 } else {
595 break;
596 }
597 }
598 return src;
599 }
600
601 // must be at least one interpolant
602 // can be surrounded by sass values
603 // make sure to never parse (dim)(dim)
604 // since this wrongly consumes `2px-1px`
605 // `2px1px` is valid number (unit `px1px`)
606 const char* value_schema(const char* src)
607 {
608 return sequence <
609 one_plus <
610 sequence <
611 optional < value_combinations >,
612 interpolant,
613 optional < value_combinations >
614 >
615 >
616 >(src);
617 }
618
619 // Match CSS '@' keywords.
620 const char* at_keyword(const char* src) {
621 return sequence<exactly<'@'>, identifier>(src);
622 }
623
624 /*
625 tok(%r{
626 (
627 \\.
628 |
629 (?!url\()
630 [^"'/\#!;\{\}] # "
631 |
632 /(?![\*\/])
633 |
634 \#(?!\{)
635 |
636 !(?![a-z]) # TODO: never consume "!" when issue 1126 is fixed.
637 )+
638 }xi) || tok(COMMENT) || tok(SINGLE_LINE_COMMENT) || interp_string || interp_uri ||
639 interpolation(:warn_for_color)
640 */
641 const char* re_almost_any_value_token(const char* src) {
642
643 return alternatives <
644 one_plus <
645 alternatives <
646 sequence <
647 exactly <'\\'>,
648 any_char
649 >,
650 sequence <
651 negate <
652 uri_prefix
653 >,
654 neg_class_char <
655 almost_any_value_class
656 >
657 >,
658 sequence <
659 exactly <'/'>,
660 negate <
661 alternatives <
662 exactly <'/'>,
663 exactly <'*'>
664 >
665 >
666 >,
667 sequence <
668 exactly <'\\'>,
669 exactly <'#'>,
670 negate <
671 exactly <'{'>
672 >
673 >,
674 sequence <
675 exactly <'!'>,
676 negate <
677 alpha
678 >
679 >
680 >
681 >,
682 block_comment,
683 line_comment,
684 interpolant,
685 space,
686 sequence <
687 exactly<'u'>,
688 exactly<'r'>,
689 exactly<'l'>,
690 exactly<'('>,
691 zero_plus <
692 alternatives <
693 class_char< real_uri_chars >,
694 uri_character,
695 NONASCII,
696 ESCAPE
697 >
698 >,
699 // false => /url\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
700 // true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
701 exactly<')'>
702 >
703 >(src);
704 }
705
706 /*
707 DIRECTIVES = Set[:mixin, :include, :function, :return, :debug, :warn, :for,
708 :each, :while, :if, :else, :extend, :import, :media, :charset, :content,
709 :_moz_document, :at_root, :error]
710 */
711 const char* re_special_directive(const char* src) {
712 return alternatives <
713 word < mixin_kwd >,
714 word < include_kwd >,
715 word < function_kwd >,
716 word < return_kwd >,
717 word < debug_kwd >,
718 word < warn_kwd >,
719 word < for_kwd >,
720 word < each_kwd >,
721 word < while_kwd >,
722 word < if_kwd >,
723 word < else_kwd >,
724 word < extend_kwd >,
725 word < import_kwd >,
726 word < media_kwd >,
727 word < charset_kwd >,
728 word < content_kwd >,
729 // exactly < moz_document_kwd >,
730 word < at_root_kwd >,
731 word < error_kwd >
732 >(src);
733 }
734
735 const char* re_prefixed_directive(const char* src) {
736 return sequence <
737 optional <
738 sequence <
739 exactly <'-'>,
740 one_plus < alnum >,
741 exactly <'-'>
742 >
743 >,
744 exactly < supports_kwd >
745 >(src);
746 }
747
748 const char* re_reference_combinator(const char* src) {
749 return sequence <
750 optional <
751 sequence <
752 zero_plus <
753 exactly <'-'>
754 >,
755 identifier,
756 exactly <'|'>
757 >
758 >,
759 zero_plus <
760 exactly <'-'>
761 >,
762 identifier
763 >(src);
764 }
765
766 const char* static_reference_combinator(const char* src) {
767 return sequence <
768 exactly <'/'>,
769 re_reference_combinator,
770 exactly <'/'>
771 >(src);
772 }
773
774 const char* schema_reference_combinator(const char* src) {
775 return sequence <
776 exactly <'/'>,
777 optional <
778 sequence <
779 css_ip_identifier,
780 exactly <'|'>
781 >
782 >,
783 css_ip_identifier,
784 exactly <'/'>
785 > (src);
786 }
787
788 const char* kwd_import(const char* src) {
789 return word<import_kwd>(src);
790 }
791
792 const char* kwd_at_root(const char* src) {
793 return word<at_root_kwd>(src);
794 }
795
796 const char* kwd_with_directive(const char* src) {
797 return word<with_kwd>(src);
798 }
799
800 const char* kwd_without_directive(const char* src) {
801 return word<without_kwd>(src);
802 }
803
804 const char* kwd_media(const char* src) {
805 return word<media_kwd>(src);
806 }
807
808 const char* kwd_supports_directive(const char* src) {
809 return word<supports_kwd>(src);
810 }
811
812 const char* kwd_mixin(const char* src) {
813 return word<mixin_kwd>(src);
814 }
815
816 const char* kwd_function(const char* src) {
817 return word<function_kwd>(src);
818 }
819
820 const char* kwd_return_directive(const char* src) {
821 return word<return_kwd>(src);
822 }
823
824 const char* kwd_include_directive(const char* src) {
825 return word<include_kwd>(src);
826 }
827
828 const char* kwd_content_directive(const char* src) {
829 return word<content_kwd>(src);
830 }
831
832 const char* kwd_charset_directive(const char* src) {
833 return word<charset_kwd>(src);
834 }
835
836 const char* kwd_extend(const char* src) {
837 return word<extend_kwd>(src);
838 }
839
840
841 const char* kwd_if_directive(const char* src) {
842 return word<if_kwd>(src);
843 }
844
845 const char* kwd_else_directive(const char* src) {
846 return word<else_kwd>(src);
847 }
848 const char* elseif_directive(const char* src) {
849 return sequence< exactly< else_kwd >,
850 optional_css_comments,
851 word< if_after_else_kwd > >(src);
852 }
853
854 const char* kwd_for_directive(const char* src) {
855 return word<for_kwd>(src);
856 }
857
858 const char* kwd_from(const char* src) {
859 return word<from_kwd>(src);
860 }
861
862 const char* kwd_to(const char* src) {
863 return word<to_kwd>(src);
864 }
865
866 const char* kwd_through(const char* src) {
867 return word<through_kwd>(src);
868 }
869
870 const char* kwd_each_directive(const char* src) {
871 return word<each_kwd>(src);
872 }
873
874 const char* kwd_in(const char* src) {
875 return word<in_kwd>(src);
876 }
877
878 const char* kwd_while_directive(const char* src) {
879 return word<while_kwd>(src);
880 }
881
882 const char* name(const char* src) {
883 return one_plus< alternatives< alnum,
884 exactly<'-'>,
885 exactly<'_'>,
886 escape_seq > >(src);
887 }
888
889 const char* kwd_warn(const char* src) {
890 return word<warn_kwd>(src);
891 }
892
893 const char* kwd_err(const char* src) {
894 return word<error_kwd>(src);
895 }
896
897 const char* kwd_dbg(const char* src) {
898 return word<debug_kwd>(src);
899 }
900
901 /* not used anymore - remove?
902 const char* directive(const char* src) {
903 return sequence< exactly<'@'>, identifier >(src);
904 } */
905
906 const char* kwd_null(const char* src) {
907 return word<null_kwd>(src);
908 }
909
910 const char* css_identifier(const char* src) {
911 return sequence <
912 zero_plus <
913 exactly <'-'>
914 >,
915 identifier
916 >(src);
917 }
918
919 const char* css_ip_identifier(const char* src) {
920 return sequence <
921 zero_plus <
922 exactly <'-'>
923 >,
924 alternatives <
925 identifier,
926 interpolant
927 >
928 >(src);
929 }
930
931 // Match CSS type selectors
932 const char* namespace_prefix(const char* src) {
933 return sequence <
934 optional <
935 alternatives <
936 exactly <'*'>,
937 css_identifier
938 >
939 >,
940 exactly <'|'>,
941 negate <
942 exactly <'='>
943 >
944 >(src);
945 }
946
947 // Match CSS type selectors
948 const char* namespace_schema(const char* src) {
949 return sequence <
950 optional <
951 alternatives <
952 exactly <'*'>,
953 css_ip_identifier
954 >
955 >,
956 exactly<'|'>,
957 negate <
958 exactly <'='>
959 >
960 >(src);
961 }
962
963 const char* hyphens_and_identifier(const char* src) {
964 return sequence< zero_plus< exactly< '-' > >, identifier_alnums >(src);
965 }
966 const char* hyphens_and_name(const char* src) {
967 return sequence< zero_plus< exactly< '-' > >, name >(src);
968 }
969 const char* universal(const char* src) {
970 return sequence< optional<namespace_schema>, exactly<'*'> >(src);
971 }
972 // Match CSS id names.
973 const char* id_name(const char* src) {
974 return sequence<exactly<'#'>, identifier_alnums >(src);
975 }
976 // Match CSS class names.
977 const char* class_name(const char* src) {
978 return sequence<exactly<'.'>, identifier >(src);
979 }
980 // Attribute name in an attribute selector.
981 const char* attribute_name(const char* src) {
982 return alternatives< sequence< optional<namespace_schema>, identifier>,
983 identifier >(src);
984 }
985 // match placeholder selectors
986 const char* placeholder(const char* src) {
987 return sequence<exactly<'%'>, identifier_alnums >(src);
988 }
989 // Match CSS numeric constants.
990
991 const char* op(const char* src) {
992 return class_char<op_chars>(src);
993 }
994 const char* sign(const char* src) {
995 return class_char<sign_chars>(src);
996 }
997 const char* unsigned_number(const char* src) {
998 return alternatives<sequence< zero_plus<digits>,
999 exactly<'.'>,
1000 one_plus<digits> >,
1001 digits>(src);
1002 }
1003 const char* number(const char* src) {
1004 return sequence<
1005 optional<sign>,
1006 unsigned_number,
1007 optional<
1008 sequence<
1009 exactly<'e'>,
1010 optional<sign>,
1011 unsigned_number
1012 >
1013 >
1014 >(src);
1015 }
1016 const char* coefficient(const char* src) {
1017 return alternatives< sequence< optional<sign>, digits >,
1018 sign >(src);
1019 }
1020 const char* binomial(const char* src) {
1021 return sequence <
1022 optional < sign >,
1023 optional < digits >,
1024 exactly <'n'>,
1025 zero_plus < sequence <
1026 optional_css_whitespace, sign,
1027 optional_css_whitespace, digits
1028 > >
1029 >(src);
1030 }
1031 const char* percentage(const char* src) {
1032 return sequence< number, exactly<'%'> >(src);
1033 }
1034 const char* ampersand(const char* src) {
1035 return exactly<'&'>(src);
1036 }
1037
1038 /* not used anymore - remove?
1039 const char* em(const char* src) {
1040 return sequence< number, exactly<em_kwd> >(src);
1041 } */
1042 const char* dimension(const char* src) {
1043 return sequence<number, unit_identifier >(src);
1044 }
1045 const char* hex(const char* src) {
1046 const char* p = sequence< exactly<'#'>, one_plus<xdigit> >(src);
1047 ptrdiff_t len = p - src;
1048 return (len != 4 && len != 7) ? 0 : p;
1049 }
1050 const char* hexa(const char* src) {
1051 const char* p = sequence< exactly<'#'>, one_plus<xdigit> >(src);
1052 ptrdiff_t len = p - src;
1053 return (len != 5 && len != 9) ? 0 : p;
1054 }
1055 const char* hex0(const char* src) {
1056 const char* p = sequence< exactly<'0'>, exactly<'x'>, one_plus<xdigit> >(src);
1057 ptrdiff_t len = p - src;
1058 return (len != 5 && len != 8) ? 0 : p;
1059 }
1060
1061 /* no longer used - remove?
1062 const char* rgb_prefix(const char* src) {
1063 return word<rgb_fn_kwd>(src);
1064 }*/
1065 // Match CSS uri specifiers.
1066
1067 const char* uri_prefix(const char* src) {
1068 return sequence <
1069 exactly <
1070 url_kwd
1071 >,
1072 zero_plus <
1073 sequence <
1074 exactly <'-'>,
1075 one_plus <
1076 alpha
1077 >
1078 >
1079 >,
1080 exactly <'('>
1081 >(src);
1082 }
1083
1084 // TODO: rename the following two functions
1085 /* no longer used - remove?
1086 const char* uri(const char* src) {
1087 return sequence< exactly<url_kwd>,
1088 optional<spaces>,
1089 quoted_string,
1090 optional<spaces>,
1091 exactly<')'> >(src);
1092 }*/
1093 /* no longer used - remove?
1094 const char* url_value(const char* src) {
1095 return sequence< optional< sequence< identifier, exactly<':'> > >, // optional protocol
1096 one_plus< sequence< zero_plus< exactly<'/'> >, filename > >, // one or more folders and/or trailing filename
1097 optional< exactly<'/'> > >(src);
1098 }*/
1099 /* no longer used - remove?
1100 const char* url_schema(const char* src) {
1101 return sequence< optional< sequence< identifier, exactly<':'> > >, // optional protocol
1102 filename_schema >(src); // optional trailing slash
1103 }*/
1104 // Match CSS "!important" keyword.
1105 const char* kwd_important(const char* src) {
1106 return sequence< exactly<'!'>,
1107 optional_css_whitespace,
1108 word<important_kwd> >(src);
1109 }
1110 // Match CSS "!optional" keyword.
1111 const char* kwd_optional(const char* src) {
1112 return sequence< exactly<'!'>,
1113 optional_css_whitespace,
1114 word<optional_kwd> >(src);
1115 }
1116 // Match Sass "!default" keyword.
1117 const char* default_flag(const char* src) {
1118 return sequence< exactly<'!'>,
1119 optional_css_whitespace,
1120 word<default_kwd> >(src);
1121 }
1122 // Match Sass "!global" keyword.
1123 const char* global_flag(const char* src) {
1124 return sequence< exactly<'!'>,
1125 optional_css_whitespace,
1126 word<global_kwd> >(src);
1127 }
1128 // Match CSS pseudo-class/element prefixes.
1129 const char* pseudo_prefix(const char* src) {
1130 return sequence< exactly<':'>, optional< exactly<':'> > >(src);
1131 }
1132 // Match CSS function call openers.
1133 const char* functional_schema(const char* src) {
1134 return sequence <
1135 one_plus <
1136 sequence <
1137 zero_plus <
1138 alternatives <
1139 identifier,
1140 exactly <'-'>
1141 >
1142 >,
1143 one_plus <
1144 sequence <
1145 interpolant,
1146 alternatives <
1147 digits,
1148 identifier,
1149 exactly<'+'>,
1150 exactly<'-'>
1151 >
1152 >
1153 >
1154 >
1155 >,
1156 negate <
1157 exactly <'%'>
1158 >,
1159 lookahead <
1160 exactly <'('>
1161 >
1162 > (src);
1163 }
1164
1165 const char* re_nothing(const char* src) {
1166 return src;
1167 }
1168
1169 const char* re_functional(const char* src) {
1170 return sequence< identifier, optional < block_comment >, exactly<'('> >(src);
1171 }
1172 const char* re_pseudo_selector(const char* src) {
1173 return sequence< identifier, optional < block_comment >, exactly<'('> >(src);
1174 }
1175 // Match the CSS negation pseudo-class.
1176 const char* pseudo_not(const char* src) {
1177 return word< pseudo_not_fn_kwd >(src);
1178 }
1179 // Match CSS 'odd' and 'even' keywords for functional pseudo-classes.
1180 const char* even(const char* src) {
1181 return word<even_kwd>(src);
1182 }
1183 const char* odd(const char* src) {
1184 return word<odd_kwd>(src);
1185 }
1186 // Match CSS attribute-matching operators.
1187 const char* exact_match(const char* src) { return exactly<'='>(src); }
1188 const char* class_match(const char* src) { return exactly<tilde_equal>(src); }
1189 const char* dash_match(const char* src) { return exactly<pipe_equal>(src); }
1190 const char* prefix_match(const char* src) { return exactly<caret_equal>(src); }
1191 const char* suffix_match(const char* src) { return exactly<dollar_equal>(src); }
1192 const char* substring_match(const char* src) { return exactly<star_equal>(src); }
1193 // Match CSS combinators.
1194 /* not used anymore - remove?
1195 const char* adjacent_to(const char* src) {
1196 return sequence< optional_spaces, exactly<'+'> >(src);
1197 }
1198 const char* precedes(const char* src) {
1199 return sequence< optional_spaces, exactly<'~'> >(src);
1200 }
1201 const char* parent_of(const char* src) {
1202 return sequence< optional_spaces, exactly<'>'> >(src);
1203 }
1204 const char* ancestor_of(const char* src) {
1205 return sequence< spaces, negate< exactly<'{'> > >(src);
1206 }*/
1207
1208 // Match SCSS variable names.
1209 const char* variable(const char* src) {
1210 return sequence<exactly<'$'>, identifier>(src);
1211 }
1212
1213 // parse `calc`, `-a-calc` and `--b-c-calc`
1214 // but do not parse `foocalc` or `foo-calc`
1215 const char* calc_fn_call(const char* src) {
1216 return sequence <
1217 optional < sequence <
1218 hyphens,
1219 one_plus < sequence <
1220 strict_identifier,
1221 hyphens
1222 > >
1223 > >,
1224 exactly < calc_fn_kwd >,
1225 word_boundary
1226 >(src);
1227 }
1228
1229 // Match Sass boolean keywords.
1230 const char* kwd_true(const char* src) {
1231 return word<true_kwd>(src);
1232 }
1233 const char* kwd_false(const char* src) {
1234 return word<false_kwd>(src);
1235 }
1236 const char* kwd_only(const char* src) {
1237 return keyword < only_kwd >(src);
1238 }
1239 const char* kwd_and(const char* src) {
1240 return keyword < and_kwd >(src);
1241 }
1242 const char* kwd_or(const char* src) {
1243 return keyword < or_kwd >(src);
1244 }
1245 const char* kwd_not(const char* src) {
1246 return keyword < not_kwd >(src);
1247 }
1248 const char* kwd_eq(const char* src) {
1249 return exactly<eq>(src);
1250 }
1251 const char* kwd_neq(const char* src) {
1252 return exactly<neq>(src);
1253 }
1254 const char* kwd_gt(const char* src) {
1255 return exactly<gt>(src);
1256 }
1257 const char* kwd_gte(const char* src) {
1258 return exactly<gte>(src);
1259 }
1260 const char* kwd_lt(const char* src) {
1261 return exactly<lt>(src);
1262 }
1263 const char* kwd_lte(const char* src) {
1264 return exactly<lte>(src);
1265 }
1266 const char* kwd_using(const char* src) {
1267 return keyword<using_kwd>(src);
1268 }
1269
1270 // match specific IE syntax
1271 const char* ie_progid(const char* src) {
1272 return sequence <
1273 word<progid_kwd>,
1274 exactly<':'>,
1275 alternatives< identifier_schema, identifier >,
1276 zero_plus< sequence<
1277 exactly<'.'>,
1278 alternatives< identifier_schema, identifier >
1279 > >,
1280 zero_plus < sequence<
1281 exactly<'('>,
1282 optional_css_whitespace,
1283 optional < sequence<
1284 alternatives< variable, identifier_schema, identifier >,
1285 optional_css_whitespace,
1286 exactly<'='>,
1287 optional_css_whitespace,
1288 alternatives< variable, identifier_schema, identifier, quoted_string, number, hex, hexa >,
1289 zero_plus< sequence<
1290 optional_css_whitespace,
1291 exactly<','>,
1292 optional_css_whitespace,
1293 sequence<
1294 alternatives< variable, identifier_schema, identifier >,
1295 optional_css_whitespace,
1296 exactly<'='>,
1297 optional_css_whitespace,
1298 alternatives< variable, identifier_schema, identifier, quoted_string, number, hex, hexa >
1299 >
1300 > >
1301 > >,
1302 optional_css_whitespace,
1303 exactly<')'>
1304 > >
1305 >(src);
1306 }
1307 const char* ie_expression(const char* src) {
1308 return sequence < word<expression_kwd>, exactly<'('>, skip_over_scopes< exactly<'('>, exactly<')'> > >(src);
1309 }
1310 const char* ie_property(const char* src) {
1311 return alternatives < ie_expression, ie_progid >(src);
1312 }
1313
1314 // const char* ie_args(const char* src) {
1315 // return sequence< alternatives< ie_keyword_arg, value_schema, quoted_string, interpolant, number, identifier, delimited_by< '(', ')', true> >,
1316 // zero_plus< sequence< optional_css_whitespace, exactly<','>, optional_css_whitespace, alternatives< ie_keyword_arg, value_schema, quoted_string, interpolant, number, identifier, delimited_by<'(', ')', true> > > > >(src);
1317 // }
1318
1319 const char* ie_keyword_arg_property(const char* src) {
1320 return alternatives <
1321 variable,
1322 identifier_schema,
1323 identifier
1324 >(src);
1325 }
1326 const char* ie_keyword_arg_value(const char* src) {
1327 return alternatives <
1328 variable,
1329 identifier_schema,
1330 identifier,
1331 quoted_string,
1332 number,
1333 hex,
1334 hexa,
1335 sequence <
1336 exactly < '(' >,
1337 skip_over_scopes <
1338 exactly < '(' >,
1339 exactly < ')' >
1340 >
1341 >
1342 >(src);
1343 }
1344
1345 const char* ie_keyword_arg(const char* src) {
1346 return sequence <
1347 ie_keyword_arg_property,
1348 optional_css_whitespace,
1349 exactly<'='>,
1350 optional_css_whitespace,
1351 ie_keyword_arg_value
1352 >(src);
1353 }
1354
1355 // Path matching functions.
1356 /* not used anymore - remove?
1357 const char* folder(const char* src) {
1358 return sequence< zero_plus< any_char_except<'/'> >,
1359 exactly<'/'> >(src);
1360 }
1361 const char* folders(const char* src) {
1362 return zero_plus< folder >(src);
1363 }*/
1364 /* not used anymore - remove?
1365 const char* chunk(const char* src) {
1366 char inside_str = 0;
1367 const char* p = src;
1368 size_t depth = 0;
1369 while (true) {
1370 if (!*p) {
1371 return 0;
1372 }
1373 else if (!inside_str && (*p == '"' || *p == '\'')) {
1374 inside_str = *p;
1375 }
1376 else if (*p == inside_str && *(p-1) != '\\') {
1377 inside_str = 0;
1378 }
1379 else if (*p == '(' && !inside_str) {
1380 ++depth;
1381 }
1382 else if (*p == ')' && !inside_str) {
1383 if (depth == 0) return p;
1384 else --depth;
1385 }
1386 ++p;
1387 }
1388 // unreachable
1389 return 0;
1390 }
1391 */
1392
1393 // follow the CSS spec more closely and see if this helps us scan URLs correctly
1394 /* not used anymore - remove?
1395 const char* NL(const char* src) {
1396 return alternatives< exactly<'\n'>,
1397 sequence< exactly<'\r'>, exactly<'\n'> >,
1398 exactly<'\r'>,
1399 exactly<'\f'> >(src);
1400 }*/
1401
1402 const char* H(const char* src) {
1403 return Util::ascii_isxdigit(c: static_cast<unsigned char>(*src)) ? src+1 : 0;
1404 }
1405
1406 const char* W(const char* src) {
1407 return zero_plus< alternatives<
1408 space,
1409 exactly< '\t' >,
1410 exactly< '\r' >,
1411 exactly< '\n' >,
1412 exactly< '\f' >
1413 > >(src);
1414 }
1415
1416 const char* UUNICODE(const char* src) {
1417 return sequence< exactly<'\\'>,
1418 between<H, 1, 6>,
1419 optional< W >
1420 >(src);
1421 }
1422
1423 const char* NONASCII(const char* src) {
1424 return nonascii(src);
1425 }
1426
1427 const char* ESCAPE(const char* src) {
1428 return alternatives<
1429 UUNICODE,
1430 sequence<
1431 exactly<'\\'>,
1432 alternatives<
1433 NONASCII,
1434 escapable_character
1435 >
1436 >
1437 >(src);
1438 }
1439
1440 const char* list_terminator(const char* src) {
1441 return alternatives <
1442 exactly<';'>,
1443 exactly<'}'>,
1444 exactly<'{'>,
1445 exactly<')'>,
1446 exactly<']'>,
1447 exactly<':'>,
1448 end_of_file,
1449 exactly<ellipsis>,
1450 default_flag,
1451 global_flag
1452 >(src);
1453 };
1454
1455 const char* space_list_terminator(const char* src) {
1456 return alternatives <
1457 exactly<','>,
1458 list_terminator
1459 >(src);
1460 };
1461
1462
1463 // const char* real_uri_prefix(const char* src) {
1464 // return alternatives<
1465 // exactly< url_kwd >,
1466 // exactly< url_prefix_kwd >
1467 // >(src);
1468 // }
1469
1470 const char* real_uri(const char* src) {
1471 return sequence<
1472 exactly< url_kwd >,
1473 exactly< '(' >,
1474 W,
1475 real_uri_value,
1476 exactly< ')' >
1477 >(src);
1478 }
1479
1480 const char* real_uri_suffix(const char* src) {
1481 return sequence< W, exactly< ')' > >(src);
1482 }
1483
1484 const char* real_uri_value(const char* src) {
1485 return
1486 sequence<
1487 non_greedy<
1488 alternatives<
1489 class_char< real_uri_chars >,
1490 uri_character,
1491 NONASCII,
1492 ESCAPE
1493 >,
1494 alternatives<
1495 real_uri_suffix,
1496 exactly< hash_lbrace >
1497 >
1498 >
1499 >
1500 (src);
1501 }
1502
1503 const char* static_string(const char* src) {
1504 const char* pos = src;
1505 const char * s = quoted_string(src: pos);
1506 Token t(pos, s);
1507 const unsigned int p = count_interval< interpolant >(beg: t.begin, end: t.end);
1508 return (p == 0) ? t.end : 0;
1509 }
1510
1511 const char* unicode_seq(const char* src) {
1512 return sequence <
1513 alternatives <
1514 exactly< 'U' >,
1515 exactly< 'u' >
1516 >,
1517 exactly< '+' >,
1518 padded_token <
1519 6, xdigit,
1520 exactly < '?' >
1521 >
1522 >(src);
1523 }
1524
1525 const char* static_component(const char* src) {
1526 return alternatives< identifier,
1527 static_string,
1528 percentage,
1529 hex,
1530 hexa,
1531 exactly<'|'>,
1532 // exactly<'+'>,
1533 sequence < number, unit_identifier >,
1534 number,
1535 sequence< exactly<'!'>, word<important_kwd> >
1536 >(src);
1537 }
1538
1539 const char* static_property(const char* src) {
1540 return
1541 sequence <
1542 zero_plus<
1543 sequence <
1544 optional_css_comments,
1545 alternatives <
1546 exactly<','>,
1547 exactly<'('>,
1548 exactly<')'>,
1549 kwd_optional,
1550 quoted_string,
1551 interpolant,
1552 identifier,
1553 percentage,
1554 dimension,
1555 variable,
1556 alnum,
1557 sequence <
1558 exactly <'\\'>,
1559 any_char
1560 >
1561 >
1562 >
1563 >,
1564 lookahead <
1565 sequence <
1566 optional_css_comments,
1567 alternatives <
1568 exactly <';'>,
1569 exactly <'}'>,
1570 end_of_file
1571 >
1572 >
1573 >
1574 >(src);
1575 }
1576
1577 const char* static_value(const char* src) {
1578 return sequence< sequence<
1579 static_component,
1580 zero_plus< identifier >
1581 >,
1582 zero_plus < sequence<
1583 alternatives<
1584 sequence< optional_spaces, alternatives<
1585 exactly < '/' >,
1586 exactly < ',' >,
1587 exactly < ' ' >
1588 >, optional_spaces >,
1589 spaces
1590 >,
1591 static_component
1592 > >,
1593 zero_plus < spaces >,
1594 alternatives< exactly<';'>, exactly<'}'> >
1595 >(src);
1596 }
1597
1598 extern const char css_variable_url_negates[] = "()[]{}\"'#/";
1599 const char* css_variable_value(const char* src) {
1600 return sequence<
1601 alternatives<
1602 sequence<
1603 negate< exactly< url_fn_kwd > >,
1604 one_plus< neg_class_char< css_variable_url_negates > >
1605 >,
1606 sequence< exactly<'#'>, negate< exactly<'{'> > >,
1607 sequence< exactly<'/'>, negate< exactly<'*'> > >,
1608 static_string,
1609 real_uri,
1610 block_comment
1611 >
1612 >(src);
1613 }
1614
1615 extern const char css_variable_url_top_level_negates[] = "()[]{}\"'#/;";
1616 const char* css_variable_top_level_value(const char* src) {
1617 return sequence<
1618 alternatives<
1619 sequence<
1620 negate< exactly< url_fn_kwd > >,
1621 one_plus< neg_class_char< css_variable_url_top_level_negates > >
1622 >,
1623 sequence< exactly<'#'>, negate< exactly<'{'> > >,
1624 sequence< exactly<'/'>, negate< exactly<'*'> > >,
1625 static_string,
1626 real_uri,
1627 block_comment
1628 >
1629 >(src);
1630 }
1631
1632 const char* parenthese_scope(const char* src) {
1633 return sequence <
1634 exactly < '(' >,
1635 skip_over_scopes <
1636 exactly < '(' >,
1637 exactly < ')' >
1638 >
1639 >(src);
1640 }
1641
1642 const char* re_selector_list(const char* src) {
1643 return alternatives <
1644 // partial bem selector
1645 sequence <
1646 ampersand,
1647 one_plus <
1648 exactly < '-' >
1649 >,
1650 word_boundary,
1651 optional_spaces
1652 >,
1653 // main selector matching
1654 one_plus <
1655 alternatives <
1656 // consume whitespace and comments
1657 spaces, block_comment, line_comment,
1658 // match `/deep/` selector (pass-trough)
1659 // there is no functionality for it yet
1660 schema_reference_combinator,
1661 // match selector ops /[*&%,\[\]]/
1662 class_char < selector_lookahead_ops >,
1663 // match selector combinators /[>+~]/
1664 class_char < selector_combinator_ops >,
1665 // match pseudo selectors
1666 sequence <
1667 exactly <'('>,
1668 optional_spaces,
1669 optional <re_selector_list>,
1670 optional_spaces,
1671 exactly <')'>
1672 >,
1673 // match attribute compare operators
1674 alternatives <
1675 exact_match, class_match, dash_match,
1676 prefix_match, suffix_match, substring_match
1677 >,
1678 // main selector match
1679 sequence <
1680 // allow namespace prefix
1681 optional < namespace_schema >,
1682 // modifiers prefixes
1683 alternatives <
1684 sequence <
1685 exactly <'#'>,
1686 // not for interpolation
1687 negate < exactly <'{'> >
1688 >,
1689 // class match
1690 exactly <'.'>,
1691 // single or double colon
1692 sequence <
1693 optional < pseudo_prefix >,
1694 // fix libsass issue 2376
1695 negate < uri_prefix >
1696 >
1697 >,
1698 // accept hypens in token
1699 one_plus < sequence <
1700 // can start with hyphens
1701 zero_plus <
1702 sequence <
1703 exactly <'-'>,
1704 optional_spaces
1705 >
1706 >,
1707 // now the main token
1708 alternatives <
1709 kwd_optional,
1710 exactly <'*'>,
1711 quoted_string,
1712 interpolant,
1713 identifier,
1714 variable,
1715 percentage,
1716 binomial,
1717 dimension,
1718 alnum
1719 >
1720 > >,
1721 // can also end with hyphens
1722 zero_plus < exactly<'-'> >
1723 >
1724 >
1725 >
1726 >(src);
1727 }
1728
1729 const char* type_selector(const char* src) {
1730 return sequence< optional<namespace_schema>, identifier>(src);
1731 }
1732 const char* re_type_selector(const char* src) {
1733 return alternatives< type_selector, universal, dimension, percentage, number, identifier_alnums >(src);
1734 }
1735 const char* re_static_expression(const char* src) {
1736 return sequence< number, optional_spaces, exactly<'/'>, optional_spaces, number >(src);
1737 }
1738
1739 // lexer special_fn: these functions cannot be overloaded
1740 // (/((-[\w-]+-)?(calc|element)|expression|progid:[a-z\.]*)\(/i)
1741 const char* re_special_fun(const char* src) {
1742
1743 // match this first as we test prefix hyphens
1744 if (const char* calc = calc_fn_call(src)) {
1745 return calc;
1746 }
1747
1748 return sequence <
1749 optional <
1750 sequence <
1751 exactly <'-'>,
1752 one_plus <
1753 alternatives <
1754 alpha,
1755 exactly <'+'>,
1756 exactly <'-'>
1757 >
1758 >
1759 >
1760 >,
1761 alternatives <
1762 word < expression_kwd >,
1763 sequence <
1764 sequence <
1765 exactly < progid_kwd >,
1766 exactly <':'>
1767 >,
1768 zero_plus <
1769 alternatives <
1770 char_range <'a', 'z'>,
1771 exactly <'.'>
1772 >
1773 >
1774 >
1775 >
1776 >(src);
1777 }
1778
1779 }
1780}
1781

source code of gtk/subprojects/libsass/src/prelexer.cpp