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