Coverage Report

Created: 2025-04-11 06:43

/src/libsass/src/prelexer.hpp
Line
Count
Source (jump to first uncovered line)
1
#ifndef SASS_PRELEXER_H
2
#define SASS_PRELEXER_H
3
4
#include <cstring>
5
#include "lexer.hpp"
6
7
namespace Sass {
8
  // using namespace Lexer;
9
  namespace Prelexer {
10
11
    //####################################
12
    // KEYWORD "REGEX" MATCHERS
13
    //####################################
14
15
    // Match Sass boolean keywords.
16
    const char* kwd_true(const char* src);
17
    const char* kwd_false(const char* src);
18
    const char* kwd_only(const char* src);
19
    const char* kwd_and(const char* src);
20
    const char* kwd_or(const char* src);
21
    const char* kwd_not(const char* src);
22
    const char* kwd_eq(const char* src);
23
    const char* kwd_neq(const char* src);
24
    const char* kwd_gt(const char* src);
25
    const char* kwd_gte(const char* src);
26
    const char* kwd_lt(const char* src);
27
    const char* kwd_lte(const char* src);
28
    const char* kwd_using(const char* src);
29
30
    // Match standard control chars
31
    const char* kwd_at(const char* src);
32
    const char* kwd_dot(const char* src);
33
    const char* kwd_comma(const char* src);
34
    const char* kwd_colon(const char* src);
35
    const char* kwd_slash(const char* src);
36
    const char* kwd_star(const char* src);
37
    const char* kwd_plus(const char* src);
38
    const char* kwd_minus(const char* src);
39
40
    //####################################
41
    // SPECIAL "REGEX" CONSTRUCTS
42
    //####################################
43
44
    // Match a sequence of characters delimited by the supplied chars.
45
    template <char beg, char end, bool esc>
46
    const char* delimited_by(const char* src) {
47
      src = exactly<beg>(src);
48
      if (!src) return 0;
49
      const char* stop;
50
      while (true) {
51
        if (!*src) return 0;
52
        stop = exactly<end>(src);
53
        if (stop && (!esc || *(src - 1) != '\\')) return stop;
54
        src = stop ? stop : src + 1;
55
      }
56
    }
57
58
    // skip to delimiter (mx) inside given range
59
    // this will savely skip over all quoted strings
60
    // recursive skip stuff delimited by start/stop
61
    // first start/opener must be consumed already!
62
    template<prelexer start, prelexer stop>
63
44.2k
    const char* skip_over_scopes(const char* src, const char* end) {
64
65
44.2k
      size_t level = 0;
66
44.2k
      bool in_squote = false;
67
44.2k
      bool in_dquote = false;
68
44.2k
      bool in_backslash_escape = false;
69
70
225M
      while ((end == nullptr || src < end) && *src != '\0') {
71
        // has escaped sequence?
72
225M
        if (in_backslash_escape) {
73
836k
          in_backslash_escape = false;
74
836k
        }
75
224M
        else if (*src == '\\') {
76
836k
          in_backslash_escape = true;
77
836k
        }
78
224M
        else if (*src == '"') {
79
0
          in_dquote = ! in_dquote;
80
0
        }
81
224M
        else if (*src == '\'') {
82
390
          in_squote = ! in_squote;
83
390
        }
84
224M
        else if (in_dquote || in_squote) {
85
          // take everything literally
86
79.9k
        }
87
88
        // find another opener inside?
89
224M
        else if (const char* pos = start(src)) {
90
359k
          ++ level; // increase counter
91
359k
          src = pos - 1; // advance position
92
359k
        }
93
94
        // look for the closer (maybe final, maybe not)
95
223M
        else if (const char* final = stop(src)) {
96
          // only close one level?
97
247k
          if (level > 0) -- level;
98
          // return position at end of stop
99
          // delimiter may be multiple chars
100
43.8k
          else return final;
101
          // advance position
102
203k
          src = final - 1;
103
203k
        }
104
105
        // next
106
225M
        ++ src;
107
225M
      }
108
109
390
      return 0;
110
44.2k
    }
char const* Sass::Prelexer::skip_over_scopes<&(char const* Sass::Prelexer::exactly<(char)40>(char const*)), &(char const* Sass::Prelexer::exactly<(char)41>(char const*))>(char const*, char const*)
Line
Count
Source
63
390
    const char* skip_over_scopes(const char* src, const char* end) {
64
65
390
      size_t level = 0;
66
390
      bool in_squote = false;
67
390
      bool in_dquote = false;
68
390
      bool in_backslash_escape = false;
69
70
219M
      while ((end == nullptr || src < end) && *src != '\0') {
71
        // has escaped sequence?
72
219M
        if (in_backslash_escape) {
73
823k
          in_backslash_escape = false;
74
823k
        }
75
218M
        else if (*src == '\\') {
76
823k
          in_backslash_escape = true;
77
823k
        }
78
218M
        else if (*src == '"') {
79
0
          in_dquote = ! in_dquote;
80
0
        }
81
218M
        else if (*src == '\'') {
82
390
          in_squote = ! in_squote;
83
390
        }
84
218M
        else if (in_dquote || in_squote) {
85
          // take everything literally
86
79.9k
        }
87
88
        // find another opener inside?
89
217M
        else if (const char* pos = start(src)) {
90
336k
          ++ level; // increase counter
91
336k
          src = pos - 1; // advance position
92
336k
        }
93
94
        // look for the closer (maybe final, maybe not)
95
217M
        else if (const char* final = stop(src)) {
96
          // only close one level?
97
180k
          if (level > 0) -- level;
98
          // return position at end of stop
99
          // delimiter may be multiple chars
100
0
          else return final;
101
          // advance position
102
180k
          src = final - 1;
103
180k
        }
104
105
        // next
106
219M
        ++ src;
107
219M
      }
108
109
390
      return 0;
110
390
    }
_ZN4Sass8Prelexer16skip_over_scopesIXadL_ZNS0_7exactlyIXadsoKcL_ZNS_9Constants11hash_lbraceEEEEEEPS3_S5_EEXadL_ZNS2_IXadsoS3_L_ZNS4_6rbraceEEEEEES5_S5_EEEES5_S5_S5_
Line
Count
Source
63
43.8k
    const char* skip_over_scopes(const char* src, const char* end) {
64
65
43.8k
      size_t level = 0;
66
43.8k
      bool in_squote = false;
67
43.8k
      bool in_dquote = false;
68
43.8k
      bool in_backslash_escape = false;
69
70
6.06M
      while ((end == nullptr || src < end) && *src != '\0') {
71
        // has escaped sequence?
72
6.06M
        if (in_backslash_escape) {
73
12.7k
          in_backslash_escape = false;
74
12.7k
        }
75
6.05M
        else if (*src == '\\') {
76
12.7k
          in_backslash_escape = true;
77
12.7k
        }
78
6.04M
        else if (*src == '"') {
79
0
          in_dquote = ! in_dquote;
80
0
        }
81
6.04M
        else if (*src == '\'') {
82
0
          in_squote = ! in_squote;
83
0
        }
84
6.04M
        else if (in_dquote || in_squote) {
85
          // take everything literally
86
0
        }
87
88
        // find another opener inside?
89
6.04M
        else if (const char* pos = start(src)) {
90
23.0k
          ++ level; // increase counter
91
23.0k
          src = pos - 1; // advance position
92
23.0k
        }
93
94
        // look for the closer (maybe final, maybe not)
95
6.01M
        else if (const char* final = stop(src)) {
96
          // only close one level?
97
66.9k
          if (level > 0) -- level;
98
          // return position at end of stop
99
          // delimiter may be multiple chars
100
43.8k
          else return final;
101
          // advance position
102
23.0k
          src = final - 1;
103
23.0k
        }
104
105
        // next
106
6.02M
        ++ src;
107
6.02M
      }
108
109
0
      return 0;
110
43.8k
    }
111
112
    // skip to a skip delimited by parentheses
113
    // uses smart `skip_over_scopes` internally
114
    const char* parenthese_scope(const char* src);
115
116
    // skip to delimiter (mx) inside given range
117
    // this will savely skip over all quoted strings
118
    // recursive skip stuff delimited by start/stop
119
    // first start/opener must be consumed already!
120
    template<prelexer start, prelexer stop>
121
31.6k
    const char* skip_over_scopes(const char* src) {
122
31.6k
      return skip_over_scopes<start, stop>(src, nullptr);
123
31.6k
    }
char const* Sass::Prelexer::skip_over_scopes<&(char const* Sass::Prelexer::exactly<(char)40>(char const*)), &(char const* Sass::Prelexer::exactly<(char)41>(char const*))>(char const*)
Line
Count
Source
121
390
    const char* skip_over_scopes(const char* src) {
122
390
      return skip_over_scopes<start, stop>(src, nullptr);
123
390
    }
_ZN4Sass8Prelexer16skip_over_scopesIXadL_ZNS0_7exactlyIXadsoKcL_ZNS_9Constants11hash_lbraceEEEEEEPS3_S5_EEXadL_ZNS2_IXadsoS3_L_ZNS4_6rbraceEEEEEES5_S5_EEEES5_S5_
Line
Count
Source
121
31.2k
    const char* skip_over_scopes(const char* src) {
122
31.2k
      return skip_over_scopes<start, stop>(src, nullptr);
123
31.2k
    }
124
125
    // Match a sequence of characters delimited by the supplied chars.
126
    template <prelexer start, prelexer stop>
127
8.43M
    const char* recursive_scopes(const char* src) {
128
      // parse opener
129
8.43M
      src = start(src);
130
      // abort if not found
131
8.43M
      if (!src) return 0;
132
      // parse the rest until final closer
133
31.2k
      return skip_over_scopes<start, stop>(src);
134
8.43M
    }
135
136
    // Match a sequence of characters delimited by the supplied strings.
137
    template <const char* beg, const char* end, bool esc>
138
7.26M
    const char* delimited_by(const char* src) {
139
7.26M
      src = exactly<beg>(src);
140
7.26M
      if (!src) return 0;
141
0
      const char* stop;
142
0
      while (true) {
143
0
        if (!*src) return 0;
144
0
        stop = exactly<end>(src);
145
0
        if (stop && (!esc || *(src - 1) != '\\')) return stop;
146
0
        src = stop ? stop : src + 1;
147
0
      }
148
0
    }
149
150
    // Tries to match a certain number of times (between the supplied interval).
151
    template<prelexer mx, size_t lo, size_t hi>
152
910
    const char* between(const char* src) {
153
920
      for (size_t i = 0; i < lo; ++i) {
154
910
        src = mx(src);
155
910
        if (!src) return 0;
156
910
      }
157
10
      for (size_t i = lo; i <= hi; ++i) {
158
10
        const char* new_src = mx(src);
159
10
        if (!new_src) return src;
160
0
        src = new_src;
161
0
      }
162
0
      return src;
163
10
    }
164
165
    // equivalent of STRING_REGULAR_EXPRESSIONS
166
    const char* re_string_double_open(const char* src);
167
    const char* re_string_double_close(const char* src);
168
    const char* re_string_single_open(const char* src);
169
    const char* re_string_single_close(const char* src);
170
    const char* re_string_uri_open(const char* src);
171
    const char* re_string_uri_close(const char* src);
172
173
    // Match a line comment.
174
    const char* line_comment(const char* src);
175
176
    // Match a block comment.
177
    const char* block_comment(const char* src);
178
    // Match either.
179
    const char* comment(const char* src);
180
    // Match double- and single-quoted strings.
181
    const char* double_quoted_string(const char* src);
182
    const char* single_quoted_string(const char* src);
183
    const char* quoted_string(const char* src);
184
    // Match interpolants.
185
    const char* interpolant(const char* src);
186
    // Match number prefix ([\+\-]+)
187
    const char* number_prefix(const char* src);
188
189
    // Match zero plus white-space or line_comments
190
    const char* optional_css_whitespace(const char* src);
191
    const char* css_whitespace(const char* src);
192
    // Match optional_css_whitespace plus block_comments
193
    const char* optional_css_comments(const char* src);
194
    const char* css_comments(const char* src);
195
196
    // Match one backslash escaped char
197
    const char* escape_seq(const char* src);
198
199
    // Match CSS css variables.
200
    const char* custom_property_name(const char* src);
201
    // Match a CSS identifier.
202
    const char* identifier(const char* src);
203
    const char* identifier_alpha(const char* src);
204
    const char* identifier_alnum(const char* src);
205
    const char* strict_identifier(const char* src);
206
    const char* strict_identifier_alpha(const char* src);
207
    const char* strict_identifier_alnum(const char* src);
208
    // Match a CSS unit identifier.
209
    const char* one_unit(const char* src);
210
    const char* multiple_units(const char* src);
211
    const char* unit_identifier(const char* src);
212
    // const char* strict_identifier_alnums(const char* src);
213
    // Match reference selector.
214
    const char* re_reference_combinator(const char* src);
215
    const char* static_reference_combinator(const char* src);
216
    const char* schema_reference_combinator(const char* src);
217
218
    // Match interpolant schemas
219
    const char* identifier_schema(const char* src);
220
    const char* value_schema(const char* src);
221
    const char* sass_value(const char* src);
222
    // const char* filename(const char* src);
223
    // const char* filename_schema(const char* src);
224
    // const char* url_schema(const char* src);
225
    // const char* url_value(const char* src);
226
    const char* vendor_prefix(const char* src);
227
228
    const char* re_special_directive(const char* src);
229
    const char* re_prefixed_directive(const char* src);
230
    const char* re_almost_any_value_token(const char* src);
231
232
    // Match CSS '@' keywords.
233
    const char* at_keyword(const char* src);
234
    const char* kwd_import(const char* src);
235
    const char* kwd_at_root(const char* src);
236
    const char* kwd_with_directive(const char* src);
237
    const char* kwd_without_directive(const char* src);
238
    const char* kwd_media(const char* src);
239
    const char* kwd_supports_directive(const char* src);
240
    // const char* keyframes(const char* src);
241
    // const char* keyf(const char* src);
242
    const char* kwd_mixin(const char* src);
243
    const char* kwd_function(const char* src);
244
    const char* kwd_return_directive(const char* src);
245
    const char* kwd_include_directive(const char* src);
246
    const char* kwd_content_directive(const char* src);
247
    const char* kwd_charset_directive(const char* src);
248
    const char* kwd_extend(const char* src);
249
250
    const char* unicode_seq(const char* src);
251
252
    const char* kwd_if_directive(const char* src);
253
    const char* kwd_else_directive(const char* src);
254
    const char* elseif_directive(const char* src);
255
256
    const char* kwd_for_directive(const char* src);
257
    const char* kwd_from(const char* src);
258
    const char* kwd_to(const char* src);
259
    const char* kwd_through(const char* src);
260
261
    const char* kwd_each_directive(const char* src);
262
    const char* kwd_in(const char* src);
263
264
    const char* kwd_while_directive(const char* src);
265
266
    const char* re_nothing(const char* src);
267
268
    const char* re_special_fun(const char* src);
269
270
    const char* kwd_warn(const char* src);
271
    const char* kwd_err(const char* src);
272
    const char* kwd_dbg(const char* src);
273
274
    const char* kwd_null(const char* src);
275
276
    const char* re_selector_list(const char* src);
277
    const char* re_type_selector(const char* src);
278
    const char* re_static_expression(const char* src);
279
280
    // identifier that can start with hyphens
281
    const char* css_identifier(const char* src);
282
    const char* css_ip_identifier(const char* src);
283
284
    // Match CSS type selectors
285
    const char* namespace_schema(const char* src);
286
    const char* namespace_prefix(const char* src);
287
    const char* type_selector(const char* src);
288
    const char* hyphens_and_identifier(const char* src);
289
    const char* hyphens_and_name(const char* src);
290
    const char* universal(const char* src);
291
    // Match CSS id names.
292
    const char* id_name(const char* src);
293
    // Match CSS class names.
294
    const char* class_name(const char* src);
295
    // Attribute name in an attribute selector
296
    const char* attribute_name(const char* src);
297
    // Match placeholder selectors.
298
    const char* placeholder(const char* src);
299
    // Match CSS numeric constants.
300
    const char* op(const char* src);
301
    const char* sign(const char* src);
302
    const char* unsigned_number(const char* src);
303
    const char* number(const char* src);
304
    const char* coefficient(const char* src);
305
    const char* binomial(const char* src);
306
    const char* percentage(const char* src);
307
    const char* ampersand(const char* src);
308
    const char* dimension(const char* src);
309
    const char* hex(const char* src);
310
    const char* hexa(const char* src);
311
    const char* hex0(const char* src);
312
    // const char* rgb_prefix(const char* src);
313
    // Match CSS uri specifiers.
314
    const char* uri_prefix(const char* src);
315
    // Match CSS "!important" keyword.
316
    const char* kwd_important(const char* src);
317
    // Match CSS "!optional" keyword.
318
    const char* kwd_optional(const char* src);
319
    // Match Sass "!default" keyword.
320
    const char* default_flag(const char* src);
321
    const char* global_flag(const char* src);
322
    // Match CSS pseudo-class/element prefixes
323
    const char* pseudo_prefix(const char* src);
324
    // Match CSS function call openers.
325
    const char* re_functional(const char* src);
326
    const char* re_pseudo_selector(const char* src);
327
    const char* functional_schema(const char* src);
328
    const char* pseudo_not(const char* src);
329
    // Match CSS 'odd' and 'even' keywords for functional pseudo-classes.
330
    const char* even(const char* src);
331
    const char* odd(const char* src);
332
    // Match CSS attribute-matching operators.
333
    const char* exact_match(const char* src);
334
    const char* class_match(const char* src);
335
    const char* dash_match(const char* src);
336
    const char* prefix_match(const char* src);
337
    const char* suffix_match(const char* src);
338
    const char* substring_match(const char* src);
339
    // Match CSS combinators.
340
    // const char* adjacent_to(const char* src);
341
    // const char* precedes(const char* src);
342
    // const char* parent_of(const char* src);
343
    // const char* ancestor_of(const char* src);
344
345
    // Match SCSS variable names.
346
    const char* variable(const char* src);
347
    const char* calc_fn_call(const char* src);
348
349
    // IE stuff
350
    const char* ie_progid(const char* src);
351
    const char* ie_expression(const char* src);
352
    const char* ie_property(const char* src);
353
    const char* ie_keyword_arg(const char* src);
354
    const char* ie_keyword_arg_value(const char* src);
355
    const char* ie_keyword_arg_property(const char* src);
356
357
    // characters that terminate parsing of a list
358
    const char* list_terminator(const char* src);
359
    const char* space_list_terminator(const char* src);
360
361
    // match url()
362
    const char* H(const char* src);
363
    const char* W(const char* src);
364
    // `UNICODE` makes VS sad
365
    const char* UUNICODE(const char* src);
366
    const char* NONASCII(const char* src);
367
    const char* ESCAPE(const char* src);
368
    const char* real_uri(const char* src);
369
    const char* real_uri_suffix(const char* src);
370
    // const char* real_uri_prefix(const char* src);
371
    const char* real_uri_value(const char* src);
372
373
    // Path matching functions.
374
    // const char* folder(const char* src);
375
    // const char* folders(const char* src);
376
377
378
    const char* static_string(const char* src);
379
    const char* static_component(const char* src);
380
    const char* static_property(const char* src);
381
    const char* static_value(const char* src);
382
383
    const char* css_variable_value(const char* src);
384
    const char* css_variable_top_level_value(const char* src);
385
386
    // Utility functions for finding and counting characters in a string.
387
    template<char c>
388
0
    const char* find_first(const char* src) {
389
0
      while (*src && *src != c) ++src;
390
0
      return *src ? src : 0;
391
0
    }
392
    template<prelexer mx>
393
    const char* find_first(const char* src) {
394
      while (*src && !mx(src)) ++src;
395
      return *src ? src : 0;
396
    }
397
    template<prelexer mx>
398
8.78k
    const char* find_first_in_interval(const char* beg, const char* end) {
399
8.78k
      bool esc = false;
400
8.78k
      while ((beg < end) && *beg) {
401
8.78k
        if (esc) esc = false;
402
8.78k
        else if (*beg == '\\') esc = true;
403
8.78k
        else if (mx(beg)) return beg;
404
0
        ++beg;
405
0
      }
406
0
      return 0;
407
8.78k
    }
408
    template<prelexer mx, prelexer skip>
409
11.7k
    const char* find_first_in_interval(const char* beg, const char* end) {
410
11.7k
      bool esc = false;
411
4.07M
      while ((beg < end) && *beg) {
412
4.07M
        if (esc) esc = false;
413
4.07M
        else if (*beg == '\\') esc = true;
414
4.06M
        else if (const char* pos = skip(beg)) beg = pos;
415
4.06M
        else if (mx(beg)) return beg;
416
4.06M
        ++beg;
417
4.06M
      }
418
945
      return 0;
419
11.7k
    }
420
    template <prelexer mx>
421
3.57k
    unsigned int count_interval(const char* beg, const char* end) {
422
3.57k
      unsigned int counter = 0;
423
3.57k
      bool esc = false;
424
122k
      while (beg < end && *beg) {
425
119k
        const char* p;
426
119k
        if (esc) {
427
4.69k
          esc = false;
428
4.69k
          ++beg;
429
114k
        } else if (*beg == '\\') {
430
4.69k
          esc = true;
431
4.69k
          ++beg;
432
109k
        } else if ((p = mx(beg))) {
433
1.68k
          ++counter;
434
1.68k
          beg = p;
435
1.68k
        }
436
108k
        else {
437
108k
          ++beg;
438
108k
        }
439
119k
      }
440
3.57k
      return counter;
441
3.57k
    }
442
443
    template <size_t size, prelexer mx, prelexer pad>
444
    const char* padded_token(const char* src)
445
0
    {
446
0
      size_t got = 0;
447
0
      const char* pos = src;
448
0
      while (got < size) {
449
0
        if (!mx(pos)) break;
450
0
        ++ pos; ++ got;
451
0
      }
452
0
      while (got < size) {
453
0
        if (!pad(pos)) break;
454
0
        ++ pos; ++ got;
455
0
      }
456
0
      return got ? pos : 0;
457
0
    }
458
459
    template <size_t min, size_t max, prelexer mx>
460
    const char* minmax_range(const char* src)
461
13.6k
    {
462
13.6k
      size_t got = 0;
463
13.6k
      const char* pos = src;
464
25.2k
      while (got < max) {
465
23.4k
        if (!mx(pos)) break;
466
11.6k
        ++ pos; ++ got;
467
11.6k
      }
468
13.6k
      if (got < min) return 0;
469
6.49k
      if (got > max) return 0;
470
6.49k
      return pos;
471
6.49k
    }
472
473
    template <char min, char max>
474
    const char* char_range(const char* src)
475
0
    {
476
0
      if (*src < min) return 0;
477
0
      if (*src > max) return 0;
478
0
      return src + 1;
479
0
    }
Unexecuted instantiation: char const* Sass::Prelexer::char_range<(char)97, (char)102>(char const*)
Unexecuted instantiation: char const* Sass::Prelexer::char_range<(char)65, (char)70>(char const*)
Unexecuted instantiation: char const* Sass::Prelexer::char_range<(char)48, (char)57>(char const*)
Unexecuted instantiation: char const* Sass::Prelexer::char_range<(char)97, (char)122>(char const*)
480
481
  }
482
}
483
484
#endif