Coverage Report

Created: 2026-04-12 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libsass/src/lexer.cpp
Line
Count
Source
1
// sass.hpp must go before all system headers to get the
2
// __EXTENSIONS__ fix on Solaris.
3
#include "sass.hpp"
4
5
#include <iostream>
6
#include <iomanip>
7
#include "lexer.hpp"
8
#include "constants.hpp"
9
#include "util_string.hpp"
10
11
12
namespace Sass {
13
  using namespace Constants;
14
15
  namespace Prelexer {
16
17
    //####################################
18
    // BASIC CHARACTER MATCHERS
19
    //####################################
20
21
    // Match standard control chars
22
0
    const char* kwd_at(const char* src) { return exactly<'@'>(src); }
23
0
    const char* kwd_dot(const char* src) { return exactly<'.'>(src); }
24
0
    const char* kwd_comma(const char* src) { return exactly<','>(src); };
25
0
    const char* kwd_colon(const char* src) { return exactly<':'>(src); };
26
0
    const char* kwd_star(const char* src) { return exactly<'*'>(src); };
27
0
    const char* kwd_plus(const char* src) { return exactly<'+'>(src); };
28
0
    const char* kwd_minus(const char* src) { return exactly<'-'>(src); };
29
0
    const char* kwd_slash(const char* src) { return exactly<'/'>(src); };
30
31
4
    bool is_number(char chr) {
32
4
      return Util::ascii_isdigit(static_cast<unsigned char>(chr)) ||
33
4
        chr == '-' || chr == '+';
34
4
    }
35
36
    // check if char is within a reduced ascii range
37
    // valid in a uri (copied from Ruby Sass)
38
    bool is_uri_character(char chr)
39
0
    {
40
0
      unsigned int cmp = unsigned(chr);
41
0
      return (cmp > 41 && cmp < 127) ||
42
0
             cmp == ':' || cmp == '/' || cmp == '|';
43
0
    }
44
45
    // check if char is within a reduced ascii range
46
    // valid for escaping (copied from Ruby Sass)
47
    bool is_escapable_character(char chr)
48
33.1k
    {
49
33.1k
      unsigned int cmp = unsigned(chr);
50
33.1k
      return cmp > 31 && cmp < 127;
51
33.1k
    }
52
53
    // Match word character (look ahead)
54
    bool is_character(char chr)
55
23.9k
    {
56
      // valid alpha, numeric or unicode char (plus hyphen)
57
23.9k
      return Util::ascii_isalnum(static_cast<unsigned char>(chr)) ||
58
23.9k
        !Util::ascii_isascii(static_cast<unsigned char>(chr)) ||
59
23.9k
        chr == '-';
60
23.9k
    }
61
62
    //####################################
63
    // BASIC CLASS MATCHERS
64
    //####################################
65
66
    // create matchers that advance the position
67
8.26M
    const char* space(const char* src) { return Util::ascii_isspace(static_cast<unsigned char>(*src)) ? src + 1 : nullptr; }
68
10.0M
    const char* alpha(const char* src) { return Util::ascii_isalpha(static_cast<unsigned char>(*src)) ? src + 1 : nullptr; }
69
6.24M
    const char* nonascii(const char* src) { return Util::ascii_isascii(static_cast<unsigned char>(*src)) ? nullptr : src + 1; }
70
3.04M
    const char* digit(const char* src) { return Util::ascii_isdigit(static_cast<unsigned char>(*src)) ? src + 1 : nullptr; }
71
26.6k
    const char* xdigit(const char* src) { return Util::ascii_isxdigit(static_cast<unsigned char>(*src)) ? src + 1 : nullptr; }
72
6.72M
    const char* alnum(const char* src) { return Util::ascii_isalnum(static_cast<unsigned char>(*src)) ? src + 1 : nullptr; }
73
195k
    const char* hyphen(const char* src) { return *src == '-' ? src + 1 : 0; }
74
0
    const char* uri_character(const char* src) { return is_uri_character(*src) ? src + 1 : 0; }
75
33.1k
    const char* escapable_character(const char* src) { return is_escapable_character(*src) ? src + 1 : 0; }
76
77
    // Match multiple ctype characters.
78
8.23M
    const char* spaces(const char* src) { return one_plus<space>(src); }
79
2.06M
    const char* digits(const char* src) { return one_plus<digit>(src); }
80
168k
    const char* hyphens(const char* src) { return one_plus<hyphen>(src); }
81
82
    // Whitespace handling.
83
31.6k
    const char* no_spaces(const char* src) { return negate< space >(src); }
84
5.29k
    const char* optional_spaces(const char* src) { return zero_plus< space >(src); }
85
86
    // Match any single character.
87
14.5k
    const char* any_char(const char* src) { return *src ? src + 1 : src; }
88
89
    // Match word boundary (zero-width lookahead).
90
23.9k
    const char* word_boundary(const char* src) { return is_character(*src) || *src == '#' ? 0 : src; }
91
92
    // Match linefeed /(?:\n|\r\n?|\f)/
93
    const char* re_linebreak(const char* src)
94
17.8k
    {
95
      // end of file or unix linefeed return here
96
17.8k
      if (*src == 0) return src;
97
      // end of file or unix linefeed return here
98
17.8k
      if (*src == '\n' || *src == '\f') return src + 1;
99
      // a carriage return may optionally be followed by a linefeed
100
17.8k
      if (*src == '\r') return *(src + 1) == '\n' ? src + 2 : src + 1;
101
      // no linefeed
102
17.8k
      return 0;
103
17.8k
    }
104
105
    // Assert string boundaries (/\Z|\z|\A/)
106
    // This is a zero-width positive lookahead
107
    const char* end_of_line(const char* src)
108
0
    {
109
      // end of file or unix linefeed return here
110
0
      return *src == 0 || *src == '\n' || *src == '\r' || *src == '\f' ? src : 0;
111
0
    }
112
113
    // Assert end_of_file boundary (/\z/)
114
    // This is a zero-width positive lookahead
115
    const char* end_of_file(const char* src)
116
184k
    {
117
      // end of file or unix linefeed return here
118
184k
      return *src == 0 ? src : 0;
119
184k
    }
120
121
  }
122
}