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
12namespace Sass {
13 using namespace Constants;
14
15 namespace Prelexer {
16
17 //####################################
18 // BASIC CHARACTER MATCHERS
19 //####################################
20
21 // Match standard control chars
22 const char* kwd_at(const char* src) { return exactly<'@'>(src); }
23 const char* kwd_dot(const char* src) { return exactly<'.'>(src); }
24 const char* kwd_comma(const char* src) { return exactly<','>(src); };
25 const char* kwd_colon(const char* src) { return exactly<':'>(src); };
26 const char* kwd_star(const char* src) { return exactly<'*'>(src); };
27 const char* kwd_plus(const char* src) { return exactly<'+'>(src); };
28 const char* kwd_minus(const char* src) { return exactly<'-'>(src); };
29 const char* kwd_slash(const char* src) { return exactly<'/'>(src); };
30
31 bool is_number(char chr) {
32 return Util::ascii_isdigit(c: static_cast<unsigned char>(chr)) ||
33 chr == '-' || chr == '+';
34 }
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 {
40 unsigned int cmp = unsigned(chr);
41 return (cmp > 41 && cmp < 127) ||
42 cmp == ':' || cmp == '/';
43 }
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 {
49 unsigned int cmp = unsigned(chr);
50 return cmp > 31 && cmp < 127;
51 }
52
53 // Match word character (look ahead)
54 bool is_character(char chr)
55 {
56 // valid alpha, numeric or unicode char (plus hyphen)
57 return Util::ascii_isalnum(c: static_cast<unsigned char>(chr)) ||
58 !Util::ascii_isascii(c: static_cast<unsigned char>(chr)) ||
59 chr == '-';
60 }
61
62 //####################################
63 // BASIC CLASS MATCHERS
64 //####################################
65
66 // create matchers that advance the position
67 const char* space(const char* src) { return Util::ascii_isspace(c: static_cast<unsigned char>(*src)) ? src + 1 : nullptr; }
68 const char* alpha(const char* src) { return Util::ascii_isalpha(c: static_cast<unsigned char>(*src)) ? src + 1 : nullptr; }
69 const char* nonascii(const char* src) { return Util::ascii_isascii(c: static_cast<unsigned char>(*src)) ? nullptr : src + 1; }
70 const char* digit(const char* src) { return Util::ascii_isdigit(c: static_cast<unsigned char>(*src)) ? src + 1 : nullptr; }
71 const char* xdigit(const char* src) { return Util::ascii_isxdigit(c: static_cast<unsigned char>(*src)) ? src + 1 : nullptr; }
72 const char* alnum(const char* src) { return Util::ascii_isalnum(c: static_cast<unsigned char>(*src)) ? src + 1 : nullptr; }
73 const char* hyphen(const char* src) { return *src == '-' ? src + 1 : 0; }
74 const char* uri_character(const char* src) { return is_uri_character(chr: *src) ? src + 1 : 0; }
75 const char* escapable_character(const char* src) { return is_escapable_character(chr: *src) ? src + 1 : 0; }
76
77 // Match multiple ctype characters.
78 const char* spaces(const char* src) { return one_plus<space>(src); }
79 const char* digits(const char* src) { return one_plus<digit>(src); }
80 const char* hyphens(const char* src) { return one_plus<hyphen>(src); }
81
82 // Whitespace handling.
83 const char* no_spaces(const char* src) { return negate< space >(src); }
84 const char* optional_spaces(const char* src) { return zero_plus< space >(src); }
85
86 // Match any single character.
87 const char* any_char(const char* src) { return *src ? src + 1 : src; }
88
89 // Match word boundary (zero-width lookahead).
90 const char* word_boundary(const char* src) { return is_character(chr: *src) || *src == '#' ? 0 : src; }
91
92 // Match linefeed /(?:\n|\r\n?|\f)/
93 const char* re_linebreak(const char* src)
94 {
95 // end of file or unix linefeed return here
96 if (*src == 0) return src;
97 // end of file or unix linefeed return here
98 if (*src == '\n' || *src == '\f') return src + 1;
99 // a carriage return may optionally be followed by a linefeed
100 if (*src == '\r') return *(src + 1) == '\n' ? src + 2 : src + 1;
101 // no linefeed
102 return 0;
103 }
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 {
109 // end of file or unix linefeed return here
110 return *src == 0 || *src == '\n' || *src == '\r' || *src == '\f' ? src : 0;
111 }
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 {
117 // end of file or unix linefeed return here
118 return *src == 0 ? src : 0;
119 }
120
121 }
122}
123

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