6 #include "position.hpp"
7 #include "prelexer.hpp"
8 #include "constants.hpp"
12 // using namespace Lexer;
13 using namespace Constants;
20 def string_re(open, close)
21 /#{open}((?:\\.|\#(?!\{)|[^#{close}\\#])*)(#{close}|#\{)/m
25 # A hash of regular expressions that are used for tokenizing strings.
27 # The key is a `[Symbol, Boolean]` pair.
28 # The symbol represents which style of quotation to use,
29 # while the boolean represents whether or not the string
30 # is following an interpolated segment.
31 STRING_REGULAR_EXPRESSIONS = {
33 /#{open}((?:\\.|\#(?!\{)|[^#{close}\\#])*)(#{close}|#\{)/m
34 false => string_re('"', '"'),
35 true => string_re('', '"')
38 false => string_re("'", "'"),
39 true => string_re('', "'")
42 false => /url\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
43 true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
45 # Defined in https://developer.mozilla.org/en/CSS/@-moz-document as a
46 # non-standard version of http://www.w3.org/TR/css3-conditional/
48 false => /url-prefix\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
49 true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
52 false => /domain\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
53 true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
69 false => string_re('"', '"'),
70 true => string_re('', '"')
72 extern const char string_double_negates[] = "\"\\#";
73 const char* re_string_double_close(const char* src)
84 // non interpolate hash
97 // quoted string closer
98 // or interpolate opening
101 lookahead < exactly< hash_lbrace > >
106 const char* re_string_double_open(const char* src)
109 // quoted string opener
119 // non interpolate hash
128 string_double_negates
132 // quoted string closer
133 // or interpolate opening
136 lookahead < exactly< hash_lbrace > >
141 extern const char string_single_negates[] = "'\\#";
142 const char* re_string_single_close(const char* src)
153 // non interpolate hash
162 string_single_negates
166 // quoted string closer
167 // or interpolate opening
170 lookahead < exactly< hash_lbrace > >
175 const char* re_string_single_open(const char* src)
178 // quoted string opener
188 // non interpolate hash
197 string_single_negates
201 // quoted string closer
202 // or interpolate opening
205 lookahead < exactly< hash_lbrace > >
212 false => /url\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
213 true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
216 const char* re_string_uri_close(const char* src)
221 class_char< real_uri_chars >,
227 sequence < optional < W >, exactly <')'> >,
228 lookahead < exactly< hash_lbrace > >
232 sequence < optional < W >, exactly <')'> >
237 const char* re_string_uri_open(const char* src)
249 class_char< real_uri_chars >,
255 sequence < W, exactly <')'> >,
256 exactly< hash_lbrace >
263 // Match a line comment (/.*?(?=\n|\r\n?|\Z)/.
264 const char* line_comment(const char* src)
277 // Match a block comment.
278 const char* block_comment(const char* src)
288 /* not use anymore - remove?
289 const char* block_comment_prefix(const char* src) {
290 return exactly<slash_star>(src);
292 // Match either comment.
293 const char* comment(const char* src) {
294 return line_comment(src);
298 // Match zero plus white-space or line_comments
299 const char* optional_css_whitespace(const char* src) {
300 return zero_plus< alternatives<spaces, line_comment> >(src);
302 const char* css_whitespace(const char* src) {
303 return one_plus< alternatives<spaces, line_comment> >(src);
305 // Match optional_css_whitepace plus block_comments
306 const char* optional_css_comments(const char* src) {
307 return zero_plus< alternatives<spaces, line_comment, block_comment> >(src);
309 const char* css_comments(const char* src) {
310 return one_plus< alternatives<spaces, line_comment, block_comment> >(src);
313 // Match one backslash escaped char /\\./
314 const char* escape_seq(const char* src)
330 // Match identifier start
331 const char* identifier_alpha(const char* src)
345 // Match identifier after start
346 const char* identifier_alnum(const char* src)
360 // Match CSS identifiers.
361 const char* strict_identifier(const char* src)
364 one_plus < strict_identifier_alpha >,
365 zero_plus < strict_identifier_alnum >
366 // word_boundary not needed
370 // Match CSS identifiers.
371 const char* identifier(const char* src)
374 zero_plus< exactly<'-'> >,
375 one_plus < identifier_alpha >,
376 zero_plus < identifier_alnum >
377 // word_boundary not needed
381 const char* strict_identifier_alpha(const char* src)
383 return alternatives <
391 const char* strict_identifier_alnum(const char* src)
393 return alternatives <
401 // Match a single CSS unit
402 const char* one_unit(const char* src)
405 optional < exactly <'-'> >,
406 strict_identifier_alpha,
407 zero_plus < alternatives<
408 strict_identifier_alnum,
410 one_plus < exactly<'-'> >,
411 strict_identifier_alpha
417 // Match numerator/denominator CSS units
418 const char* multiple_units(const char* src)
432 // Match complex CSS unit identifiers
433 const char* unit_identifier(const char* src)
445 const char* identifier_alnums(const char* src)
447 return one_plus< identifier_alnum >(src);
450 // Match number prefix ([\+\-]+)
451 const char* number_prefix(const char* src) {
452 return alternatives <
456 optional_css_whitespace,
462 // Match interpolant schemas
463 const char* identifier_schema(const char* src) {
501 // interpolants can be recursive/nested
502 const char* interpolant(const char* src) {
503 return recursive_scopes< exactly<hash_lbrace>, exactly<rbrace> >(src);
506 // $re_squote = /'(?:$re_itplnt|\\.|[^'])*'/
507 const char* single_quoted_string(const char* src) {
508 // match a single quoted string, while skipping interpolants
522 // skip non delimiters
523 any_char_but < '\'' >
530 // $re_dquote = /"(?:$re_itp|\\.|[^"])*"/
531 const char* double_quoted_string(const char* src) {
532 // match a single quoted string, while skipping interpolants
546 // skip non delimiters
554 // $re_quoted = /(?:$re_squote|$re_dquote)/
555 const char* quoted_string(const char* src) {
556 // match a quoted string, while skipping interpolants
558 single_quoted_string,
563 const char* sass_value(const char* src) {
564 return alternatives <
574 // this is basically `one_plus < sass_value >`
575 // takes care to not parse invalid combinations
576 const char* value_combinations(const char* src) {
577 // `2px-2px` is invalid combo
578 bool was_number = false;
579 const char* pos = src;
581 if ((pos = alternatives < quoted_string, identifier, percentage, hex >(src))) {
584 } else if (!was_number && !exactly<'+'>(src) && (pos = alternatives < dimension, number >(src))) {
594 // must be at least one interpolant
595 // can be surrounded by sass values
596 // make sure to never parse (dim)(dim)
597 // since this wrongly consumes `2px-1px`
598 // `2px1px` is valid number (unit `px1px`)
599 const char* value_schema(const char* src)
604 optional < value_combinations >,
606 optional < value_combinations >
612 // Match CSS '@' keywords.
613 const char* at_keyword(const char* src) {
614 return sequence<exactly<'@'>, identifier>(src);
629 !(?![a-z]) # TODO: never consume "!" when issue 1126 is fixed.
631 }xi) || tok(COMMENT) || tok(SINGLE_LINE_COMMENT) || interp_string || interp_uri ||
632 interpolation(:warn_for_color)
634 const char* re_almost_any_value_token(const char* src) {
636 return alternatives <
651 almost_any_value_class
689 class_char< real_uri_chars >,
695 // false => /url\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
696 // true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
703 DIRECTIVES = Set[:mixin, :include, :function, :return, :debug, :warn, :for,
704 :each, :while, :if, :else, :extend, :import, :media, :charset, :content,
705 :_moz_document, :at_root, :error]
707 const char* re_special_directive(const char* src) {
708 return alternatives <
710 word < include_kwd >,
711 word < function_kwd >,
723 word < charset_kwd >,
724 word < content_kwd >,
725 // exactly < moz_document_kwd >,
726 word < at_root_kwd >,
731 const char* re_prefixed_directive(const char* src) {
740 exactly < supports_kwd >
744 const char* re_reference_combinator(const char* src) {
762 const char* static_reference_combinator(const char* src) {
765 re_reference_combinator,
770 const char* schema_reference_combinator(const char* src) {
784 const char* kwd_import(const char* src) {
785 return word<import_kwd>(src);
788 const char* kwd_at_root(const char* src) {
789 return word<at_root_kwd>(src);
792 const char* kwd_with_directive(const char* src) {
793 return word<with_kwd>(src);
796 const char* kwd_without_directive(const char* src) {
797 return word<without_kwd>(src);
800 const char* kwd_media(const char* src) {
801 return word<media_kwd>(src);
804 const char* kwd_supports_directive(const char* src) {
805 return word<supports_kwd>(src);
808 const char* kwd_mixin(const char* src) {
809 return word<mixin_kwd>(src);
812 const char* kwd_function(const char* src) {
813 return word<function_kwd>(src);
816 const char* kwd_return_directive(const char* src) {
817 return word<return_kwd>(src);
820 const char* kwd_include_directive(const char* src) {
821 return word<include_kwd>(src);
824 const char* kwd_content_directive(const char* src) {
825 return word<content_kwd>(src);
828 const char* kwd_charset_directive(const char* src) {
829 return word<charset_kwd>(src);
832 const char* kwd_extend(const char* src) {
833 return word<extend_kwd>(src);
837 const char* kwd_if_directive(const char* src) {
838 return word<if_kwd>(src);
841 const char* kwd_else_directive(const char* src) {
842 return word<else_kwd>(src);
844 const char* elseif_directive(const char* src) {
845 return sequence< exactly< else_kwd >,
846 optional_css_comments,
847 word< if_after_else_kwd > >(src);
850 const char* kwd_for_directive(const char* src) {
851 return word<for_kwd>(src);
854 const char* kwd_from(const char* src) {
855 return word<from_kwd>(src);
858 const char* kwd_to(const char* src) {
859 return word<to_kwd>(src);
862 const char* kwd_through(const char* src) {
863 return word<through_kwd>(src);
866 const char* kwd_each_directive(const char* src) {
867 return word<each_kwd>(src);
870 const char* kwd_in(const char* src) {
871 return word<in_kwd>(src);
874 const char* kwd_while_directive(const char* src) {
875 return word<while_kwd>(src);
878 const char* name(const char* src) {
879 return one_plus< alternatives< alnum,
885 const char* kwd_warn(const char* src) {
886 return word<warn_kwd>(src);
889 const char* kwd_err(const char* src) {
890 return word<error_kwd>(src);
893 const char* kwd_dbg(const char* src) {
894 return word<debug_kwd>(src);
897 /* not used anymore - remove?
898 const char* directive(const char* src) {
899 return sequence< exactly<'@'>, identifier >(src);
902 const char* kwd_null(const char* src) {
903 return word<null_kwd>(src);
906 const char* css_identifier(const char* src) {
915 const char* css_ip_identifier(const char* src) {
927 // Match CSS type selectors
928 const char* namespace_prefix(const char* src) {
943 // Match CSS type selectors
944 const char* namespace_schema(const char* src) {
959 const char* hyphens_and_identifier(const char* src) {
960 return sequence< zero_plus< exactly< '-' > >, identifier_alnums >(src);
962 const char* hyphens_and_name(const char* src) {
963 return sequence< zero_plus< exactly< '-' > >, name >(src);
965 const char* universal(const char* src) {
966 return sequence< optional<namespace_schema>, exactly<'*'> >(src);
968 // Match CSS id names.
969 const char* id_name(const char* src) {
970 return sequence<exactly<'#'>, identifier_alnums >(src);
972 // Match CSS class names.
973 const char* class_name(const char* src) {
974 return sequence<exactly<'.'>, identifier >(src);
976 // Attribute name in an attribute selector.
977 const char* attribute_name(const char* src) {
978 return alternatives< sequence< optional<namespace_schema>, identifier>,
981 // match placeholder selectors
982 const char* placeholder(const char* src) {
983 return sequence<exactly<'%'>, identifier_alnums >(src);
985 // Match CSS numeric constants.
987 const char* op(const char* src) {
988 return class_char<op_chars>(src);
990 const char* sign(const char* src) {
991 return class_char<sign_chars>(src);
993 const char* unsigned_number(const char* src) {
994 return alternatives<sequence< zero_plus<digits>,
999 const char* number(const char* src) {
1000 return sequence< optional<sign>, unsigned_number>(src);
1002 const char* coefficient(const char* src) {
1003 return alternatives< sequence< optional<sign>, digits >,
1006 const char* binomial(const char* src) {
1009 optional < digits >,
1011 zero_plus < sequence <
1012 optional_css_whitespace, sign,
1013 optional_css_whitespace, digits
1017 const char* percentage(const char* src) {
1018 return sequence< number, exactly<'%'> >(src);
1020 const char* ampersand(const char* src) {
1021 return exactly<'&'>(src);
1024 /* not used anymore - remove?
1025 const char* em(const char* src) {
1026 return sequence< number, exactly<em_kwd> >(src);
1028 const char* dimension(const char* src) {
1029 return sequence<number, unit_identifier >(src);
1031 const char* hex(const char* src) {
1032 const char* p = sequence< exactly<'#'>, one_plus<xdigit> >(src);
1033 ptrdiff_t len = p - src;
1034 return (len != 4 && len != 7) ? 0 : p;
1036 const char* hexa(const char* src) {
1037 const char* p = sequence< exactly<'#'>, one_plus<xdigit> >(src);
1038 ptrdiff_t len = p - src;
1039 return (len != 4 && len != 7 && len != 9) ? 0 : p;
1041 const char* hex0(const char* src) {
1042 const char* p = sequence< exactly<'0'>, exactly<'x'>, one_plus<xdigit> >(src);
1043 ptrdiff_t len = p - src;
1044 return (len != 5 && len != 8) ? 0 : p;
1047 /* no longer used - remove?
1048 const char* rgb_prefix(const char* src) {
1049 return word<rgb_kwd>(src);
1051 // Match CSS uri specifiers.
1053 const char* uri_prefix(const char* src) {
1070 // TODO: rename the following two functions
1071 /* no longer used - remove?
1072 const char* uri(const char* src) {
1073 return sequence< exactly<url_kwd>,
1077 exactly<')'> >(src);
1079 /* no longer used - remove?
1080 const char* url_value(const char* src) {
1081 return sequence< optional< sequence< identifier, exactly<':'> > >, // optional protocol
1082 one_plus< sequence< zero_plus< exactly<'/'> >, filename > >, // one or more folders and/or trailing filename
1083 optional< exactly<'/'> > >(src);
1085 /* no longer used - remove?
1086 const char* url_schema(const char* src) {
1087 return sequence< optional< sequence< identifier, exactly<':'> > >, // optional protocol
1088 filename_schema >(src); // optional trailing slash
1090 // Match CSS "!important" keyword.
1091 const char* kwd_important(const char* src) {
1092 return sequence< exactly<'!'>,
1093 optional_css_whitespace,
1094 word<important_kwd> >(src);
1096 // Match CSS "!optional" keyword.
1097 const char* kwd_optional(const char* src) {
1098 return sequence< exactly<'!'>,
1099 optional_css_whitespace,
1100 word<optional_kwd> >(src);
1102 // Match Sass "!default" keyword.
1103 const char* default_flag(const char* src) {
1104 return sequence< exactly<'!'>,
1105 optional_css_whitespace,
1106 word<default_kwd> >(src);
1108 // Match Sass "!global" keyword.
1109 const char* global_flag(const char* src) {
1110 return sequence< exactly<'!'>,
1111 optional_css_whitespace,
1112 word<global_kwd> >(src);
1114 // Match CSS pseudo-class/element prefixes.
1115 const char* pseudo_prefix(const char* src) {
1116 return sequence< exactly<':'>, optional< exactly<':'> > >(src);
1118 // Match CSS function call openers.
1119 const char* functional_schema(const char* src) {
1151 const char* re_nothing(const char* src) {
1155 const char* re_functional(const char* src) {
1156 return sequence< identifier, optional < block_comment >, exactly<'('> >(src);
1158 const char* re_pseudo_selector(const char* src) {
1159 return sequence< identifier, optional < block_comment >, exactly<'('> >(src);
1161 // Match the CSS negation pseudo-class.
1162 const char* pseudo_not(const char* src) {
1163 return word< pseudo_not_kwd >(src);
1165 // Match CSS 'odd' and 'even' keywords for functional pseudo-classes.
1166 const char* even(const char* src) {
1167 return word<even_kwd>(src);
1169 const char* odd(const char* src) {
1170 return word<odd_kwd>(src);
1172 // Match CSS attribute-matching operators.
1173 const char* exact_match(const char* src) { return exactly<'='>(src); }
1174 const char* class_match(const char* src) { return exactly<tilde_equal>(src); }
1175 const char* dash_match(const char* src) { return exactly<pipe_equal>(src); }
1176 const char* prefix_match(const char* src) { return exactly<caret_equal>(src); }
1177 const char* suffix_match(const char* src) { return exactly<dollar_equal>(src); }
1178 const char* substring_match(const char* src) { return exactly<star_equal>(src); }
1179 // Match CSS combinators.
1180 /* not used anymore - remove?
1181 const char* adjacent_to(const char* src) {
1182 return sequence< optional_spaces, exactly<'+'> >(src);
1184 const char* precedes(const char* src) {
1185 return sequence< optional_spaces, exactly<'~'> >(src);
1187 const char* parent_of(const char* src) {
1188 return sequence< optional_spaces, exactly<'>'> >(src);
1190 const char* ancestor_of(const char* src) {
1191 return sequence< spaces, negate< exactly<'{'> > >(src);
1194 // Match SCSS variable names.
1195 const char* variable(const char* src) {
1196 return sequence<exactly<'$'>, identifier>(src);
1199 // parse `calc`, `-a-calc` and `--b-c-calc`
1200 // but do not parse `foocalc` or `foo-calc`
1201 const char* calc_fn_call(const char* src) {
1203 optional < sequence <
1205 one_plus < sequence <
1210 exactly < calc_fn_kwd >,
1215 // Match Sass boolean keywords.
1216 const char* kwd_true(const char* src) {
1217 return word<true_kwd>(src);
1219 const char* kwd_false(const char* src) {
1220 return word<false_kwd>(src);
1222 const char* kwd_only(const char* src) {
1223 return keyword < only_kwd >(src);
1225 const char* kwd_and(const char* src) {
1226 return keyword < and_kwd >(src);
1228 const char* kwd_or(const char* src) {
1229 return keyword < or_kwd >(src);
1231 const char* kwd_not(const char* src) {
1232 return keyword < not_kwd >(src);
1234 const char* kwd_eq(const char* src) {
1235 return exactly<eq>(src);
1237 const char* kwd_neq(const char* src) {
1238 return exactly<neq>(src);
1240 const char* kwd_gt(const char* src) {
1241 return exactly<gt>(src);
1243 const char* kwd_gte(const char* src) {
1244 return exactly<gte>(src);
1246 const char* kwd_lt(const char* src) {
1247 return exactly<lt>(src);
1249 const char* kwd_lte(const char* src) {
1250 return exactly<lte>(src);
1253 // match specific IE syntax
1254 const char* ie_progid(const char* src) {
1258 alternatives< identifier_schema, identifier >,
1259 zero_plus< sequence<
1261 alternatives< identifier_schema, identifier >
1263 zero_plus < sequence<
1265 optional_css_whitespace,
1266 optional < sequence<
1267 alternatives< variable, identifier_schema, identifier >,
1268 optional_css_whitespace,
1270 optional_css_whitespace,
1271 alternatives< variable, identifier_schema, identifier, quoted_string, number, hexa >,
1272 zero_plus< sequence<
1273 optional_css_whitespace,
1275 optional_css_whitespace,
1277 alternatives< variable, identifier_schema, identifier >,
1278 optional_css_whitespace,
1280 optional_css_whitespace,
1281 alternatives< variable, identifier_schema, identifier, quoted_string, number, hexa >
1285 optional_css_whitespace,
1290 const char* ie_expression(const char* src) {
1291 return sequence < word<expression_kwd>, exactly<'('>, skip_over_scopes< exactly<'('>, exactly<')'> > >(src);
1293 const char* ie_property(const char* src) {
1294 return alternatives < ie_expression, ie_progid >(src);
1297 // const char* ie_args(const char* src) {
1298 // return sequence< alternatives< ie_keyword_arg, value_schema, quoted_string, interpolant, number, identifier, delimited_by< '(', ')', true> >,
1299 // 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);
1302 const char* ie_keyword_arg_property(const char* src) {
1303 return alternatives <
1309 const char* ie_keyword_arg_value(const char* src) {
1310 return alternatives <
1327 const char* ie_keyword_arg(const char* src) {
1329 ie_keyword_arg_property,
1330 optional_css_whitespace,
1332 optional_css_whitespace,
1333 ie_keyword_arg_value
1337 // Path matching functions.
1338 /* not used anymore - remove?
1339 const char* folder(const char* src) {
1340 return sequence< zero_plus< any_char_except<'/'> >,
1341 exactly<'/'> >(src);
1343 const char* folders(const char* src) {
1344 return zero_plus< folder >(src);
1346 /* not used anymore - remove?
1347 const char* chunk(const char* src) {
1348 char inside_str = 0;
1349 const char* p = src;
1355 else if (!inside_str && (*p == '"' || *p == '\'')) {
1358 else if (*p == inside_str && *(p-1) != '\\') {
1361 else if (*p == '(' && !inside_str) {
1364 else if (*p == ')' && !inside_str) {
1365 if (depth == 0) return p;
1375 // follow the CSS spec more closely and see if this helps us scan URLs correctly
1376 /* not used anymore - remove?
1377 const char* NL(const char* src) {
1378 return alternatives< exactly<'\n'>,
1379 sequence< exactly<'\r'>, exactly<'\n'> >,
1381 exactly<'\f'> >(src);
1384 const char* H(const char* src) {
1385 return std::isxdigit(*src) ? src+1 : 0;
1388 const char* W(const char* src) {
1389 return zero_plus< alternatives<
1398 const char* UUNICODE(const char* src) {
1399 return sequence< exactly<'\\'>,
1405 const char* NONASCII(const char* src) {
1406 return nonascii(src);
1409 const char* ESCAPE(const char* src) {
1410 return alternatives<
1422 const char* list_terminator(const char* src) {
1423 return alternatives <
1437 const char* space_list_terminator(const char* src) {
1438 return alternatives <
1445 // const char* real_uri_prefix(const char* src) {
1446 // return alternatives<
1447 // exactly< url_kwd >,
1448 // exactly< url_prefix_kwd >
1452 const char* real_uri_suffix(const char* src) {
1453 return sequence< W, exactly< ')' > >(src);
1456 const char* real_uri_value(const char* src) {
1461 class_char< real_uri_chars >,
1468 exactly< hash_lbrace >
1475 const char* static_string(const char* src) {
1476 const char* pos = src;
1477 const char * s = quoted_string(pos);
1479 const unsigned int p = count_interval< interpolant >(t.begin, t.end);
1480 return (p == 0) ? t.end : 0;
1483 const char* unicode_seq(const char* src) {
1497 const char* static_component(const char* src) {
1498 return alternatives< identifier,
1504 sequence < number, unit_identifier >,
1506 sequence< exactly<'!'>, word<important_kwd> >
1510 const char* static_property(const char* src) {
1515 optional_css_comments,
1537 optional_css_comments,
1548 const char* static_value(const char* src) {
1549 return sequence< sequence<
1551 zero_plus< identifier >
1553 zero_plus < sequence<
1555 sequence< optional_spaces, alternatives<
1559 >, optional_spaces >,
1564 zero_plus < spaces >,
1565 alternatives< exactly<';'>, exactly<'}'> >
1569 const char* parenthese_scope(const char* src) {
1579 const char* re_selector_list(const char* src) {
1580 return alternatives <
1581 // partial bem selector
1590 // main selector matching
1593 // consume whitespace and comments
1594 spaces, block_comment, line_comment,
1595 // match `/deep/` selector (pass-trough)
1596 // there is no functionality for it yet
1597 schema_reference_combinator,
1598 // match selector ops /[*&%,\[\]]/
1599 class_char < selector_lookahead_ops >,
1600 // match selector combinators /[>+~]/
1601 class_char < selector_combinator_ops >,
1602 // match attribute compare operators
1606 optional <re_selector_list>,
1611 exact_match, class_match, dash_match,
1612 prefix_match, suffix_match, substring_match
1614 // main selector match
1616 // allow namespace prefix
1617 optional < namespace_schema >,
1618 // modifiers prefixes
1622 // not for interpolation
1623 negate < exactly <'{'> >
1627 // single or double colon
1628 optional < pseudo_prefix >
1630 // accept hypens in token
1631 one_plus < sequence <
1632 // can start with hyphens
1633 zero_plus < exactly<'-'> >,
1634 // now the main token
1648 // can also end with hyphens
1649 zero_plus < exactly<'-'> >
1656 const char* type_selector(const char* src) {
1657 return sequence< optional<namespace_schema>, identifier>(src);
1659 const char* re_type_selector(const char* src) {
1660 return alternatives< type_selector, universal, quoted_string, dimension, percentage, number, identifier_alnums >(src);
1662 const char* re_type_selector2(const char* src) {
1663 return alternatives< type_selector, universal, quoted_string, dimension, percentage, number, identifier_alnums >(src);
1665 const char* re_static_expression(const char* src) {
1666 return sequence< number, optional_spaces, exactly<'/'>, optional_spaces, number >(src);
1669 // lexer special_fn: these functions cannot be overloaded
1670 // (/((-[\w-]+-)?(calc|element)|expression|progid:[a-z\.]*)\(/i)
1671 const char* re_special_fun(const char* src) {
1673 // match this first as we test prefix hyphens
1674 if (const char* calc = calc_fn_call(src)) {
1692 word < expression_kwd >,
1695 exactly < progid_kwd >,
1700 char_range <'a', 'z'>,