sassc4 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.gitmodules +3 -0
- data/.travis.yml +16 -0
- data/CHANGELOG.md +97 -0
- data/CODE_OF_CONDUCT.md +10 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +22 -0
- data/README.md +80 -0
- data/Rakefile +51 -0
- data/ext/depend +4 -0
- data/ext/extconf.rb +92 -0
- data/ext/libsass/VERSION +1 -0
- data/ext/libsass/contrib/plugin.cpp +60 -0
- data/ext/libsass/include/sass/base.h +97 -0
- data/ext/libsass/include/sass/context.h +174 -0
- data/ext/libsass/include/sass/functions.h +139 -0
- data/ext/libsass/include/sass/values.h +145 -0
- data/ext/libsass/include/sass/version.h +12 -0
- data/ext/libsass/include/sass.h +15 -0
- data/ext/libsass/include/sass2scss.h +120 -0
- data/ext/libsass/src/MurmurHash2.hpp +91 -0
- data/ext/libsass/src/ast.cpp +953 -0
- data/ext/libsass/src/ast.hpp +1064 -0
- data/ext/libsass/src/ast2c.cpp +80 -0
- data/ext/libsass/src/ast2c.hpp +39 -0
- data/ext/libsass/src/ast_def_macros.hpp +140 -0
- data/ext/libsass/src/ast_fwd_decl.cpp +31 -0
- data/ext/libsass/src/ast_fwd_decl.hpp +274 -0
- data/ext/libsass/src/ast_helpers.hpp +316 -0
- data/ext/libsass/src/ast_sel_cmp.cpp +396 -0
- data/ext/libsass/src/ast_sel_super.cpp +539 -0
- data/ext/libsass/src/ast_sel_unify.cpp +275 -0
- data/ext/libsass/src/ast_sel_weave.cpp +616 -0
- data/ext/libsass/src/ast_selectors.cpp +1070 -0
- data/ext/libsass/src/ast_selectors.hpp +523 -0
- data/ext/libsass/src/ast_supports.cpp +114 -0
- data/ext/libsass/src/ast_supports.hpp +121 -0
- data/ext/libsass/src/ast_values.cpp +1154 -0
- data/ext/libsass/src/ast_values.hpp +498 -0
- data/ext/libsass/src/b64/cencode.h +32 -0
- data/ext/libsass/src/b64/encode.h +79 -0
- data/ext/libsass/src/backtrace.cpp +50 -0
- data/ext/libsass/src/backtrace.hpp +29 -0
- data/ext/libsass/src/base64vlq.cpp +47 -0
- data/ext/libsass/src/base64vlq.hpp +30 -0
- data/ext/libsass/src/bind.cpp +312 -0
- data/ext/libsass/src/bind.hpp +15 -0
- data/ext/libsass/src/c2ast.cpp +64 -0
- data/ext/libsass/src/c2ast.hpp +14 -0
- data/ext/libsass/src/c99func.c +54 -0
- data/ext/libsass/src/cencode.c +106 -0
- data/ext/libsass/src/check_nesting.cpp +393 -0
- data/ext/libsass/src/check_nesting.hpp +70 -0
- data/ext/libsass/src/color_maps.cpp +652 -0
- data/ext/libsass/src/color_maps.hpp +323 -0
- data/ext/libsass/src/color_spaces.cpp +241 -0
- data/ext/libsass/src/color_spaces.hpp +227 -0
- data/ext/libsass/src/constants.cpp +199 -0
- data/ext/libsass/src/constants.hpp +200 -0
- data/ext/libsass/src/context.cpp +870 -0
- data/ext/libsass/src/context.hpp +140 -0
- data/ext/libsass/src/cssize.cpp +521 -0
- data/ext/libsass/src/cssize.hpp +71 -0
- data/ext/libsass/src/dart_helpers.hpp +199 -0
- data/ext/libsass/src/debug.hpp +43 -0
- data/ext/libsass/src/debugger.hpp +964 -0
- data/ext/libsass/src/emitter.cpp +297 -0
- data/ext/libsass/src/emitter.hpp +101 -0
- data/ext/libsass/src/environment.cpp +260 -0
- data/ext/libsass/src/environment.hpp +124 -0
- data/ext/libsass/src/error_handling.cpp +239 -0
- data/ext/libsass/src/error_handling.hpp +248 -0
- data/ext/libsass/src/eval.cpp +1543 -0
- data/ext/libsass/src/eval.hpp +110 -0
- data/ext/libsass/src/eval_selectors.cpp +75 -0
- data/ext/libsass/src/expand.cpp +875 -0
- data/ext/libsass/src/expand.hpp +98 -0
- data/ext/libsass/src/extender.cpp +1226 -0
- data/ext/libsass/src/extender.hpp +399 -0
- data/ext/libsass/src/extension.cpp +43 -0
- data/ext/libsass/src/extension.hpp +89 -0
- data/ext/libsass/src/file.cpp +531 -0
- data/ext/libsass/src/file.hpp +124 -0
- data/ext/libsass/src/fn_colors.cpp +836 -0
- data/ext/libsass/src/fn_colors.hpp +99 -0
- data/ext/libsass/src/fn_lists.cpp +285 -0
- data/ext/libsass/src/fn_lists.hpp +34 -0
- data/ext/libsass/src/fn_maps.cpp +94 -0
- data/ext/libsass/src/fn_maps.hpp +30 -0
- data/ext/libsass/src/fn_miscs.cpp +248 -0
- data/ext/libsass/src/fn_miscs.hpp +40 -0
- data/ext/libsass/src/fn_numbers.cpp +246 -0
- data/ext/libsass/src/fn_numbers.hpp +45 -0
- data/ext/libsass/src/fn_selectors.cpp +205 -0
- data/ext/libsass/src/fn_selectors.hpp +35 -0
- data/ext/libsass/src/fn_strings.cpp +268 -0
- data/ext/libsass/src/fn_strings.hpp +34 -0
- data/ext/libsass/src/fn_utils.cpp +159 -0
- data/ext/libsass/src/fn_utils.hpp +62 -0
- data/ext/libsass/src/inspect.cpp +1126 -0
- data/ext/libsass/src/inspect.hpp +101 -0
- data/ext/libsass/src/json.cpp +1436 -0
- data/ext/libsass/src/json.hpp +117 -0
- data/ext/libsass/src/kwd_arg_macros.hpp +28 -0
- data/ext/libsass/src/lexer.cpp +122 -0
- data/ext/libsass/src/lexer.hpp +304 -0
- data/ext/libsass/src/listize.cpp +70 -0
- data/ext/libsass/src/listize.hpp +37 -0
- data/ext/libsass/src/mapping.hpp +19 -0
- data/ext/libsass/src/memory/allocator.cpp +48 -0
- data/ext/libsass/src/memory/allocator.hpp +138 -0
- data/ext/libsass/src/memory/config.hpp +20 -0
- data/ext/libsass/src/memory/memory_pool.hpp +186 -0
- data/ext/libsass/src/memory/shared_ptr.cpp +33 -0
- data/ext/libsass/src/memory/shared_ptr.hpp +332 -0
- data/ext/libsass/src/memory.hpp +12 -0
- data/ext/libsass/src/operation.hpp +223 -0
- data/ext/libsass/src/operators.cpp +267 -0
- data/ext/libsass/src/operators.hpp +30 -0
- data/ext/libsass/src/ordered_map.hpp +112 -0
- data/ext/libsass/src/output.cpp +320 -0
- data/ext/libsass/src/output.hpp +47 -0
- data/ext/libsass/src/parser.cpp +3059 -0
- data/ext/libsass/src/parser.hpp +395 -0
- data/ext/libsass/src/parser_selectors.cpp +189 -0
- data/ext/libsass/src/permutate.hpp +164 -0
- data/ext/libsass/src/plugins.cpp +188 -0
- data/ext/libsass/src/plugins.hpp +57 -0
- data/ext/libsass/src/position.cpp +163 -0
- data/ext/libsass/src/position.hpp +147 -0
- data/ext/libsass/src/prelexer.cpp +1780 -0
- data/ext/libsass/src/prelexer.hpp +484 -0
- data/ext/libsass/src/remove_placeholders.cpp +86 -0
- data/ext/libsass/src/remove_placeholders.hpp +37 -0
- data/ext/libsass/src/sass.cpp +156 -0
- data/ext/libsass/src/sass.hpp +147 -0
- data/ext/libsass/src/sass2scss.cpp +895 -0
- data/ext/libsass/src/sass_context.cpp +742 -0
- data/ext/libsass/src/sass_context.hpp +129 -0
- data/ext/libsass/src/sass_functions.cpp +210 -0
- data/ext/libsass/src/sass_functions.hpp +50 -0
- data/ext/libsass/src/sass_values.cpp +362 -0
- data/ext/libsass/src/sass_values.hpp +82 -0
- data/ext/libsass/src/settings.hpp +19 -0
- data/ext/libsass/src/source.cpp +69 -0
- data/ext/libsass/src/source.hpp +95 -0
- data/ext/libsass/src/source_data.hpp +32 -0
- data/ext/libsass/src/source_map.cpp +202 -0
- data/ext/libsass/src/source_map.hpp +65 -0
- data/ext/libsass/src/stylesheet.cpp +22 -0
- data/ext/libsass/src/stylesheet.hpp +57 -0
- data/ext/libsass/src/to_value.cpp +114 -0
- data/ext/libsass/src/to_value.hpp +46 -0
- data/ext/libsass/src/units.cpp +507 -0
- data/ext/libsass/src/units.hpp +110 -0
- data/ext/libsass/src/utf8/checked.h +336 -0
- data/ext/libsass/src/utf8/core.h +332 -0
- data/ext/libsass/src/utf8/unchecked.h +235 -0
- data/ext/libsass/src/utf8.h +34 -0
- data/ext/libsass/src/utf8_string.cpp +104 -0
- data/ext/libsass/src/utf8_string.hpp +38 -0
- data/ext/libsass/src/util.cpp +723 -0
- data/ext/libsass/src/util.hpp +105 -0
- data/ext/libsass/src/util_string.cpp +125 -0
- data/ext/libsass/src/util_string.hpp +73 -0
- data/ext/libsass/src/values.cpp +140 -0
- data/ext/libsass/src/values.hpp +12 -0
- data/lib/sassc/dependency.rb +17 -0
- data/lib/sassc/engine.rb +141 -0
- data/lib/sassc/error.rb +37 -0
- data/lib/sassc/functions_handler.rb +73 -0
- data/lib/sassc/import_handler.rb +50 -0
- data/lib/sassc/importer.rb +31 -0
- data/lib/sassc/native/native_context_api.rb +147 -0
- data/lib/sassc/native/native_functions_api.rb +159 -0
- data/lib/sassc/native/sass2scss_api.rb +10 -0
- data/lib/sassc/native/sass_input_style.rb +13 -0
- data/lib/sassc/native/sass_output_style.rb +12 -0
- data/lib/sassc/native/sass_value.rb +97 -0
- data/lib/sassc/native/string_list.rb +10 -0
- data/lib/sassc/native.rb +64 -0
- data/lib/sassc/sass_2_scss.rb +9 -0
- data/lib/sassc/script/functions.rb +8 -0
- data/lib/sassc/script/value/bool.rb +32 -0
- data/lib/sassc/script/value/color.rb +95 -0
- data/lib/sassc/script/value/list.rb +136 -0
- data/lib/sassc/script/value/map.rb +69 -0
- data/lib/sassc/script/value/number.rb +389 -0
- data/lib/sassc/script/value/string.rb +96 -0
- data/lib/sassc/script/value.rb +137 -0
- data/lib/sassc/script/value_conversion/base.rb +13 -0
- data/lib/sassc/script/value_conversion/bool.rb +13 -0
- data/lib/sassc/script/value_conversion/color.rb +18 -0
- data/lib/sassc/script/value_conversion/list.rb +25 -0
- data/lib/sassc/script/value_conversion/map.rb +21 -0
- data/lib/sassc/script/value_conversion/number.rb +13 -0
- data/lib/sassc/script/value_conversion/string.rb +17 -0
- data/lib/sassc/script/value_conversion.rb +69 -0
- data/lib/sassc/script.rb +17 -0
- data/lib/sassc/util/normalized_map.rb +117 -0
- data/lib/sassc/util.rb +231 -0
- data/lib/sassc/version.rb +5 -0
- data/lib/sassc.rb +57 -0
- data/sassc.gemspec +69 -0
- data/test/css_color_level4_test.rb +168 -0
- data/test/custom_importer_test.rb +127 -0
- data/test/engine_test.rb +314 -0
- data/test/error_test.rb +29 -0
- data/test/fixtures/paths.scss +10 -0
- data/test/functions_test.rb +340 -0
- data/test/native_test.rb +213 -0
- data/test/output_style_test.rb +107 -0
- data/test/sass_2_scss_test.rb +14 -0
- data/test/test_helper.rb +45 -0
- metadata +396 -0
|
@@ -0,0 +1,723 @@
|
|
|
1
|
+
#include "sass.hpp"
|
|
2
|
+
#include "sass.h"
|
|
3
|
+
#include "ast.hpp"
|
|
4
|
+
#include "util.hpp"
|
|
5
|
+
#include "util_string.hpp"
|
|
6
|
+
#include "lexer.hpp"
|
|
7
|
+
#include "prelexer.hpp"
|
|
8
|
+
#include "constants.hpp"
|
|
9
|
+
#include "utf8/checked.h"
|
|
10
|
+
|
|
11
|
+
#include <cmath>
|
|
12
|
+
#include <stdint.h>
|
|
13
|
+
#if defined(_MSC_VER) && _MSC_VER >= 1800 && _MSC_VER < 1900 && defined(_M_X64)
|
|
14
|
+
#include <mutex>
|
|
15
|
+
#endif
|
|
16
|
+
|
|
17
|
+
namespace Sass {
|
|
18
|
+
|
|
19
|
+
double round(double val, size_t precision)
|
|
20
|
+
{
|
|
21
|
+
// Disable FMA3-optimized implementation when compiling with VS2013 for x64 targets
|
|
22
|
+
// See https://github.com/sass/node-sass/issues/1854 for details
|
|
23
|
+
// FIXME: Remove this workaround when we switch to VS2015+
|
|
24
|
+
#if defined(_MSC_VER) && _MSC_VER >= 1800 && _MSC_VER < 1900 && defined(_M_X64)
|
|
25
|
+
static std::once_flag flag;
|
|
26
|
+
std::call_once(flag, []() { _set_FMA3_enable(0); });
|
|
27
|
+
#endif
|
|
28
|
+
|
|
29
|
+
// https://github.com/sass/sass/commit/4e3e1d5684cc29073a507578fc977434ff488c93
|
|
30
|
+
if (std::fmod(val, 1) - 0.5 > - std::pow(0.1, precision + 1)) return std::ceil(val);
|
|
31
|
+
else if (std::fmod(val, 1) - 0.5 > std::pow(0.1, precision)) return std::floor(val);
|
|
32
|
+
// work around some compiler issue
|
|
33
|
+
// cygwin has it not defined in std
|
|
34
|
+
using namespace std;
|
|
35
|
+
return ::round(val);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* Locale unspecific atof function. */
|
|
39
|
+
double sass_strtod(const char *str)
|
|
40
|
+
{
|
|
41
|
+
char separator = *(localeconv()->decimal_point);
|
|
42
|
+
if(separator != '.'){
|
|
43
|
+
// The current locale specifies another
|
|
44
|
+
// separator. convert the separator to the
|
|
45
|
+
// one understood by the locale if needed
|
|
46
|
+
const char *found = strchr(str, '.');
|
|
47
|
+
if(found != NULL){
|
|
48
|
+
// substitution is required. perform the substitution on a copy
|
|
49
|
+
// of the string. This is slower but it is thread safe.
|
|
50
|
+
char *copy = sass_copy_c_string(str);
|
|
51
|
+
*(copy + (found - str)) = separator;
|
|
52
|
+
double res = strtod(copy, NULL);
|
|
53
|
+
free(copy);
|
|
54
|
+
return res;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return strtod(str, NULL);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// helper for safe access to c_ctx
|
|
62
|
+
const char* safe_str (const char* str, const char* alt) {
|
|
63
|
+
return str == NULL ? alt : str;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
void free_string_array(char ** arr) {
|
|
67
|
+
if(!arr)
|
|
68
|
+
return;
|
|
69
|
+
|
|
70
|
+
char **it = arr;
|
|
71
|
+
while (it && (*it)) {
|
|
72
|
+
free(*it);
|
|
73
|
+
++it;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
free(arr);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
char **copy_strings(const sass::vector<sass::string>& strings, char*** array, int skip) {
|
|
80
|
+
int num = static_cast<int>(strings.size()) - skip;
|
|
81
|
+
char** arr = (char**) calloc(num + 1, sizeof(char*));
|
|
82
|
+
if (arr == 0)
|
|
83
|
+
return *array = (char **)NULL;
|
|
84
|
+
|
|
85
|
+
for(int i = 0; i < num; i++) {
|
|
86
|
+
arr[i] = (char*) malloc(sizeof(char) * (strings[i + skip].size() + 1));
|
|
87
|
+
if (arr[i] == 0) {
|
|
88
|
+
free_string_array(arr);
|
|
89
|
+
return *array = (char **)NULL;
|
|
90
|
+
}
|
|
91
|
+
std::copy(strings[i + skip].begin(), strings[i + skip].end(), arr[i]);
|
|
92
|
+
arr[i][strings[i + skip].size()] = '\0';
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
arr[num] = 0;
|
|
96
|
+
return *array = arr;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// read css string (handle multiline DELIM)
|
|
100
|
+
sass::string read_css_string(const sass::string& str, bool css)
|
|
101
|
+
{
|
|
102
|
+
if (!css) return str;
|
|
103
|
+
sass::string out("");
|
|
104
|
+
bool esc = false;
|
|
105
|
+
for (auto i : str) {
|
|
106
|
+
if (i == '\\') {
|
|
107
|
+
esc = ! esc;
|
|
108
|
+
} else if (esc && i == '\r') {
|
|
109
|
+
continue;
|
|
110
|
+
} else if (esc && i == '\n') {
|
|
111
|
+
out.resize (out.size () - 1);
|
|
112
|
+
esc = false;
|
|
113
|
+
continue;
|
|
114
|
+
} else {
|
|
115
|
+
esc = false;
|
|
116
|
+
}
|
|
117
|
+
out.push_back(i);
|
|
118
|
+
}
|
|
119
|
+
// happens when parsing does not correctly skip
|
|
120
|
+
// over escaped sequences for ie. interpolations
|
|
121
|
+
// one example: foo\#{interpolate}
|
|
122
|
+
// if (esc) out += '\\';
|
|
123
|
+
return out;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// double escape all escape sequences
|
|
127
|
+
// keep unescaped quotes and backslashes
|
|
128
|
+
sass::string evacuate_escapes(const sass::string& str)
|
|
129
|
+
{
|
|
130
|
+
sass::string out("");
|
|
131
|
+
bool esc = false;
|
|
132
|
+
for (auto i : str) {
|
|
133
|
+
if (i == '\\' && !esc) {
|
|
134
|
+
out += '\\';
|
|
135
|
+
out += '\\';
|
|
136
|
+
esc = true;
|
|
137
|
+
} else if (esc && i == '"') {
|
|
138
|
+
out += '\\';
|
|
139
|
+
out += i;
|
|
140
|
+
esc = false;
|
|
141
|
+
} else if (esc && i == '\'') {
|
|
142
|
+
out += '\\';
|
|
143
|
+
out += i;
|
|
144
|
+
esc = false;
|
|
145
|
+
} else if (esc && i == '\\') {
|
|
146
|
+
out += '\\';
|
|
147
|
+
out += i;
|
|
148
|
+
esc = false;
|
|
149
|
+
} else {
|
|
150
|
+
esc = false;
|
|
151
|
+
out += i;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// happens when parsing does not correctly skip
|
|
155
|
+
// over escaped sequences for ie. interpolations
|
|
156
|
+
// one example: foo\#{interpolate}
|
|
157
|
+
// if (esc) out += '\\';
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// bell characters are replaced with spaces
|
|
162
|
+
void newline_to_space(sass::string& str)
|
|
163
|
+
{
|
|
164
|
+
std::replace(str.begin(), str.end(), '\n', ' ');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// 1. Removes whitespace after newlines.
|
|
168
|
+
// 2. Replaces newlines with spaces.
|
|
169
|
+
//
|
|
170
|
+
// This method only considers LF and CRLF as newlines.
|
|
171
|
+
sass::string string_to_output(const sass::string& str)
|
|
172
|
+
{
|
|
173
|
+
sass::string result;
|
|
174
|
+
result.reserve(str.size());
|
|
175
|
+
std::size_t pos = 0;
|
|
176
|
+
while (true) {
|
|
177
|
+
const std::size_t newline = str.find_first_of("\n\r", pos);
|
|
178
|
+
if (newline == sass::string::npos) break;
|
|
179
|
+
result.append(str, pos, newline - pos);
|
|
180
|
+
if (str[newline] == '\r') {
|
|
181
|
+
if (str[newline + 1] == '\n') {
|
|
182
|
+
pos = newline + 2;
|
|
183
|
+
} else {
|
|
184
|
+
// CR without LF: append as-is and continue.
|
|
185
|
+
result += '\r';
|
|
186
|
+
pos = newline + 1;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
} else {
|
|
190
|
+
pos = newline + 1;
|
|
191
|
+
}
|
|
192
|
+
result += ' ';
|
|
193
|
+
const std::size_t non_space = str.find_first_not_of(" \f\n\r\t\v", pos);
|
|
194
|
+
if (non_space != sass::string::npos) {
|
|
195
|
+
pos = non_space;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
result.append(str, pos, sass::string::npos);
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
sass::string escape_string(const sass::string& str)
|
|
203
|
+
{
|
|
204
|
+
sass::string out;
|
|
205
|
+
out.reserve(str.size());
|
|
206
|
+
for (char c : str) {
|
|
207
|
+
switch (c) {
|
|
208
|
+
case '\n':
|
|
209
|
+
out.append("\\n");
|
|
210
|
+
break;
|
|
211
|
+
case '\r':
|
|
212
|
+
out.append("\\r");
|
|
213
|
+
break;
|
|
214
|
+
case '\f':
|
|
215
|
+
out.append("\\f");
|
|
216
|
+
break;
|
|
217
|
+
default:
|
|
218
|
+
out += c;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return out;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
sass::string comment_to_compact_string(const sass::string& text)
|
|
225
|
+
{
|
|
226
|
+
sass::string str = "";
|
|
227
|
+
size_t has = 0;
|
|
228
|
+
char prev = 0;
|
|
229
|
+
bool clean = false;
|
|
230
|
+
for (auto i : text) {
|
|
231
|
+
if (clean) {
|
|
232
|
+
if (i == '\n') { has = 0; }
|
|
233
|
+
else if (i == '\t') { ++ has; }
|
|
234
|
+
else if (i == ' ') { ++ has; }
|
|
235
|
+
else if (i == '*') {}
|
|
236
|
+
else {
|
|
237
|
+
clean = false;
|
|
238
|
+
str += ' ';
|
|
239
|
+
if (prev == '*' && i == '/') str += "*/";
|
|
240
|
+
else str += i;
|
|
241
|
+
}
|
|
242
|
+
} else if (i == '\n') {
|
|
243
|
+
clean = true;
|
|
244
|
+
} else {
|
|
245
|
+
str += i;
|
|
246
|
+
}
|
|
247
|
+
prev = i;
|
|
248
|
+
}
|
|
249
|
+
if (has) return str;
|
|
250
|
+
else return text;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// find best quote_mark by detecting if the string contains any single
|
|
254
|
+
// or double quotes. When a single quote is found, we not we want a double
|
|
255
|
+
// quote as quote_mark. Otherwise we check if the string cotains any double
|
|
256
|
+
// quotes, which will trigger the use of single quotes as best quote_mark.
|
|
257
|
+
char detect_best_quotemark(const char* s, char qm)
|
|
258
|
+
{
|
|
259
|
+
// ensure valid fallback quote_mark
|
|
260
|
+
char quote_mark = qm && qm != '*' ? qm : '"';
|
|
261
|
+
while (*s) {
|
|
262
|
+
// force double quotes as soon
|
|
263
|
+
// as one single quote is found
|
|
264
|
+
if (*s == '\'') { return '"'; }
|
|
265
|
+
// a single does not force quote_mark
|
|
266
|
+
// maybe we see a double quote later
|
|
267
|
+
else if (*s == '"') { quote_mark = '\''; }
|
|
268
|
+
++ s;
|
|
269
|
+
}
|
|
270
|
+
return quote_mark;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
sass::string read_hex_escapes(const sass::string& s)
|
|
274
|
+
{
|
|
275
|
+
|
|
276
|
+
sass::string result;
|
|
277
|
+
bool skipped = false;
|
|
278
|
+
|
|
279
|
+
for (size_t i = 0, L = s.length(); i < L; ++i) {
|
|
280
|
+
|
|
281
|
+
// implement the same strange ruby sass behavior
|
|
282
|
+
// an escape sequence can also mean a unicode char
|
|
283
|
+
if (s[i] == '\\' && !skipped) {
|
|
284
|
+
|
|
285
|
+
// remember
|
|
286
|
+
skipped = true;
|
|
287
|
+
|
|
288
|
+
// escape length
|
|
289
|
+
size_t len = 1;
|
|
290
|
+
|
|
291
|
+
// parse as many sequence chars as possible
|
|
292
|
+
// ToDo: Check if ruby aborts after possible max
|
|
293
|
+
while (i + len < L && s[i + len] && Util::ascii_isxdigit(static_cast<unsigned char>(s[i + len]))) ++ len;
|
|
294
|
+
|
|
295
|
+
if (len > 1) {
|
|
296
|
+
|
|
297
|
+
// convert the extracted hex string to code point value
|
|
298
|
+
// ToDo: Maybe we could do this without creating a substring
|
|
299
|
+
uint32_t cp = strtol(s.substr (i + 1, len - 1).c_str(), NULL, 16);
|
|
300
|
+
|
|
301
|
+
if (s[i + len] == ' ') ++ len;
|
|
302
|
+
|
|
303
|
+
// assert invalid code points
|
|
304
|
+
if (cp == 0) cp = 0xFFFD;
|
|
305
|
+
// replace bell character
|
|
306
|
+
// if (cp == '\n') cp = 32;
|
|
307
|
+
|
|
308
|
+
// use a very simple approach to convert via utf8 lib
|
|
309
|
+
// maybe there is a more elegant way; maybe we should
|
|
310
|
+
// convert the whole output from string to a stream!?
|
|
311
|
+
// allocate memory for utf8 char and convert to utf8
|
|
312
|
+
unsigned char u[5] = {0,0,0,0,0}; utf8::append(cp, u);
|
|
313
|
+
for(size_t m = 0; m < 5 && u[m]; m++) result.push_back(u[m]);
|
|
314
|
+
|
|
315
|
+
// skip some more chars?
|
|
316
|
+
i += len - 1; skipped = false;
|
|
317
|
+
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
else {
|
|
321
|
+
|
|
322
|
+
skipped = false;
|
|
323
|
+
|
|
324
|
+
result.push_back(s[i]);
|
|
325
|
+
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
else {
|
|
331
|
+
|
|
332
|
+
result.push_back(s[i]);
|
|
333
|
+
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return result;
|
|
339
|
+
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
sass::string unquote(const sass::string& s, char* qd, bool keep_utf8_sequences, bool strict)
|
|
343
|
+
{
|
|
344
|
+
|
|
345
|
+
// not enough room for quotes
|
|
346
|
+
// no possibility to unquote
|
|
347
|
+
if (s.length() < 2) return s;
|
|
348
|
+
|
|
349
|
+
char q;
|
|
350
|
+
bool skipped = false;
|
|
351
|
+
|
|
352
|
+
// this is no guarantee that the unquoting will work
|
|
353
|
+
// what about whitespace before/after the quote_mark?
|
|
354
|
+
if (*s.begin() == '"' && *s.rbegin() == '"') q = '"';
|
|
355
|
+
else if (*s.begin() == '\'' && *s.rbegin() == '\'') q = '\'';
|
|
356
|
+
else return s;
|
|
357
|
+
|
|
358
|
+
sass::string unq;
|
|
359
|
+
unq.reserve(s.length()-2);
|
|
360
|
+
|
|
361
|
+
for (size_t i = 1, L = s.length() - 1; i < L; ++i) {
|
|
362
|
+
|
|
363
|
+
// implement the same strange ruby sass behavior
|
|
364
|
+
// an escape sequence can also mean a unicode char
|
|
365
|
+
if (s[i] == '\\' && !skipped) {
|
|
366
|
+
// remember
|
|
367
|
+
skipped = true;
|
|
368
|
+
|
|
369
|
+
// skip it
|
|
370
|
+
// ++ i;
|
|
371
|
+
|
|
372
|
+
// if (i == L) break;
|
|
373
|
+
|
|
374
|
+
// escape length
|
|
375
|
+
size_t len = 1;
|
|
376
|
+
|
|
377
|
+
// parse as many sequence chars as possible
|
|
378
|
+
// ToDo: Check if ruby aborts after possible max
|
|
379
|
+
while (i + len < L && s[i + len] && Util::ascii_isxdigit(static_cast<unsigned char>(s[i + len]))) ++ len;
|
|
380
|
+
|
|
381
|
+
// hex string?
|
|
382
|
+
if (keep_utf8_sequences) {
|
|
383
|
+
unq.push_back(s[i]);
|
|
384
|
+
} else if (len > 1) {
|
|
385
|
+
|
|
386
|
+
// convert the extracted hex string to code point value
|
|
387
|
+
// ToDo: Maybe we could do this without creating a substring
|
|
388
|
+
uint32_t cp = strtol(s.substr (i + 1, len - 1).c_str(), NULL, 16);
|
|
389
|
+
|
|
390
|
+
if (s[i + len] == ' ') ++ len;
|
|
391
|
+
|
|
392
|
+
// assert invalid code points
|
|
393
|
+
if (cp == 0) cp = 0xFFFD;
|
|
394
|
+
// replace bell character
|
|
395
|
+
// if (cp == '\n') cp = 32;
|
|
396
|
+
|
|
397
|
+
// use a very simple approach to convert via utf8 lib
|
|
398
|
+
// maybe there is a more elegant way; maybe we should
|
|
399
|
+
// convert the whole output from string to a stream!?
|
|
400
|
+
// allocate memory for utf8 char and convert to utf8
|
|
401
|
+
unsigned char u[5] = {0,0,0,0,0}; utf8::append(cp, u);
|
|
402
|
+
for(size_t m = 0; m < 5 && u[m]; m++) unq.push_back(u[m]);
|
|
403
|
+
|
|
404
|
+
// skip some more chars?
|
|
405
|
+
i += len - 1; skipped = false;
|
|
406
|
+
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
}
|
|
411
|
+
// check for unexpected delimiter
|
|
412
|
+
// be strict and throw error back
|
|
413
|
+
// else if (!skipped && q == s[i]) {
|
|
414
|
+
// // don't be that strict
|
|
415
|
+
// return s;
|
|
416
|
+
// // this basically always means an internal error and not users fault
|
|
417
|
+
// error("Unescaped delimiter in string to unquote found. [" + s + "]", SourceSpan("[UNQUOTE]"));
|
|
418
|
+
// }
|
|
419
|
+
else {
|
|
420
|
+
if (strict && !skipped) {
|
|
421
|
+
if (s[i] == q) return s;
|
|
422
|
+
}
|
|
423
|
+
skipped = false;
|
|
424
|
+
unq.push_back(s[i]);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
}
|
|
428
|
+
if (skipped) { return s; }
|
|
429
|
+
if (qd) *qd = q;
|
|
430
|
+
return unq;
|
|
431
|
+
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
sass::string quote(const sass::string& s, char q)
|
|
435
|
+
{
|
|
436
|
+
|
|
437
|
+
// autodetect with fallback to given quote
|
|
438
|
+
q = detect_best_quotemark(s.c_str(), q);
|
|
439
|
+
|
|
440
|
+
// return an empty quoted string
|
|
441
|
+
if (s.empty()) return sass::string(2, q ? q : '"');
|
|
442
|
+
|
|
443
|
+
sass::string quoted;
|
|
444
|
+
quoted.reserve(s.length()+2);
|
|
445
|
+
quoted.push_back(q);
|
|
446
|
+
|
|
447
|
+
const char* it = s.c_str();
|
|
448
|
+
const char* end = it + strlen(it) + 1;
|
|
449
|
+
while (*it && it < end) {
|
|
450
|
+
const char* now = it;
|
|
451
|
+
|
|
452
|
+
if (*it == q) {
|
|
453
|
+
quoted.push_back('\\');
|
|
454
|
+
} else if (*it == '\\') {
|
|
455
|
+
quoted.push_back('\\');
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
int cp = utf8::next(it, end);
|
|
459
|
+
|
|
460
|
+
// in case of \r, check if the next in sequence
|
|
461
|
+
// is \n and then advance the iterator and skip \r
|
|
462
|
+
if (cp == '\r' && it < end && utf8::peek_next(it, end) == '\n') {
|
|
463
|
+
cp = utf8::next(it, end);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
if (cp == '\n') {
|
|
467
|
+
quoted.push_back('\\');
|
|
468
|
+
quoted.push_back('a');
|
|
469
|
+
// we hope we can remove this flag once we figure out
|
|
470
|
+
// why ruby sass has these different output behaviors
|
|
471
|
+
// gsub(/\n(?![a-fA-F0-9\s])/, "\\a").gsub("\n", "\\a ")
|
|
472
|
+
using namespace Prelexer;
|
|
473
|
+
if (alternatives <
|
|
474
|
+
Prelexer::char_range<'a', 'f'>,
|
|
475
|
+
Prelexer::char_range<'A', 'F'>,
|
|
476
|
+
Prelexer::char_range<'0', '9'>,
|
|
477
|
+
space
|
|
478
|
+
>(it) != NULL) {
|
|
479
|
+
quoted.push_back(' ');
|
|
480
|
+
}
|
|
481
|
+
} else if (cp < 127) {
|
|
482
|
+
quoted.push_back((char) cp);
|
|
483
|
+
} else {
|
|
484
|
+
while (now < it) {
|
|
485
|
+
quoted.push_back(*now);
|
|
486
|
+
++ now;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
quoted.push_back(q);
|
|
492
|
+
return quoted;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
bool is_hex_doublet(double n)
|
|
496
|
+
{
|
|
497
|
+
return n == 0x00 || n == 0x11 || n == 0x22 || n == 0x33 ||
|
|
498
|
+
n == 0x44 || n == 0x55 || n == 0x66 || n == 0x77 ||
|
|
499
|
+
n == 0x88 || n == 0x99 || n == 0xAA || n == 0xBB ||
|
|
500
|
+
n == 0xCC || n == 0xDD || n == 0xEE || n == 0xFF ;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
bool is_color_doublet(double r, double g, double b)
|
|
504
|
+
{
|
|
505
|
+
return is_hex_doublet(r) && is_hex_doublet(g) && is_hex_doublet(b);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
bool peek_linefeed(const char* start)
|
|
509
|
+
{
|
|
510
|
+
using namespace Prelexer;
|
|
511
|
+
using namespace Constants;
|
|
512
|
+
return sequence <
|
|
513
|
+
zero_plus <
|
|
514
|
+
alternatives <
|
|
515
|
+
exactly <' '>,
|
|
516
|
+
exactly <'\t'>,
|
|
517
|
+
line_comment,
|
|
518
|
+
block_comment,
|
|
519
|
+
delimited_by <
|
|
520
|
+
slash_star,
|
|
521
|
+
star_slash,
|
|
522
|
+
false
|
|
523
|
+
>
|
|
524
|
+
>
|
|
525
|
+
>,
|
|
526
|
+
re_linebreak
|
|
527
|
+
>(start) != 0;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
namespace Util {
|
|
531
|
+
|
|
532
|
+
bool isPrintable(StyleRule* r, Sass_Output_Style style) {
|
|
533
|
+
if (r == NULL) {
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
Block_Obj b = r->block();
|
|
538
|
+
|
|
539
|
+
SelectorList* sl = r->selector();
|
|
540
|
+
bool hasSelectors = sl ? sl->length() > 0 : false;
|
|
541
|
+
|
|
542
|
+
if (!hasSelectors) {
|
|
543
|
+
return false;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
bool hasDeclarations = false;
|
|
547
|
+
bool hasPrintableChildBlocks = false;
|
|
548
|
+
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
549
|
+
Statement_Obj stm = b->at(i);
|
|
550
|
+
if (Cast<AtRule>(stm)) {
|
|
551
|
+
return true;
|
|
552
|
+
} else if (Declaration* d = Cast<Declaration>(stm)) {
|
|
553
|
+
return isPrintable(d, style);
|
|
554
|
+
} else if (ParentStatement* p = Cast<ParentStatement>(stm)) {
|
|
555
|
+
Block_Obj pChildBlock = p->block();
|
|
556
|
+
if (isPrintable(pChildBlock, style)) {
|
|
557
|
+
hasPrintableChildBlocks = true;
|
|
558
|
+
}
|
|
559
|
+
} else if (Comment* c = Cast<Comment>(stm)) {
|
|
560
|
+
// keep for uncompressed
|
|
561
|
+
if (style != COMPRESSED) {
|
|
562
|
+
hasDeclarations = true;
|
|
563
|
+
}
|
|
564
|
+
// output style compressed
|
|
565
|
+
if (c->is_important()) {
|
|
566
|
+
hasDeclarations = c->is_important();
|
|
567
|
+
}
|
|
568
|
+
} else {
|
|
569
|
+
hasDeclarations = true;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
if (hasDeclarations || hasPrintableChildBlocks) {
|
|
573
|
+
return true;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
return false;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
bool isPrintable(String_Constant* s, Sass_Output_Style style)
|
|
581
|
+
{
|
|
582
|
+
return ! s->value().empty();
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
bool isPrintable(String_Quoted* s, Sass_Output_Style style)
|
|
586
|
+
{
|
|
587
|
+
return true;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
bool isPrintable(Declaration* d, Sass_Output_Style style)
|
|
591
|
+
{
|
|
592
|
+
ExpressionObj val = d->value();
|
|
593
|
+
if (String_Quoted_Obj sq = Cast<String_Quoted>(val)) return isPrintable(sq.ptr(), style);
|
|
594
|
+
if (String_Constant_Obj sc = Cast<String_Constant>(val)) return isPrintable(sc.ptr(), style);
|
|
595
|
+
return true;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
bool isPrintable(SupportsRule* f, Sass_Output_Style style) {
|
|
599
|
+
if (f == NULL) {
|
|
600
|
+
return false;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
Block_Obj b = f->block();
|
|
604
|
+
|
|
605
|
+
bool hasDeclarations = false;
|
|
606
|
+
bool hasPrintableChildBlocks = false;
|
|
607
|
+
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
608
|
+
Statement_Obj stm = b->at(i);
|
|
609
|
+
if (Cast<Declaration>(stm) || Cast<AtRule>(stm)) {
|
|
610
|
+
hasDeclarations = true;
|
|
611
|
+
}
|
|
612
|
+
else if (ParentStatement* b = Cast<ParentStatement>(stm)) {
|
|
613
|
+
Block_Obj pChildBlock = b->block();
|
|
614
|
+
if (!b->is_invisible()) {
|
|
615
|
+
if (isPrintable(pChildBlock, style)) {
|
|
616
|
+
hasPrintableChildBlocks = true;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
if (hasDeclarations || hasPrintableChildBlocks) {
|
|
622
|
+
return true;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
return false;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
bool isPrintable(CssMediaRule* m, Sass_Output_Style style)
|
|
630
|
+
{
|
|
631
|
+
if (m == nullptr) return false;
|
|
632
|
+
Block_Obj b = m->block();
|
|
633
|
+
if (b == nullptr) return false;
|
|
634
|
+
if (m->empty()) return false;
|
|
635
|
+
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
636
|
+
Statement_Obj stm = b->at(i);
|
|
637
|
+
if (Cast<AtRule>(stm)) return true;
|
|
638
|
+
else if (Cast<Declaration>(stm)) return true;
|
|
639
|
+
else if (Comment* c = Cast<Comment>(stm)) {
|
|
640
|
+
if (isPrintable(c, style)) {
|
|
641
|
+
return true;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
else if (StyleRule* r = Cast<StyleRule>(stm)) {
|
|
645
|
+
if (isPrintable(r, style)) {
|
|
646
|
+
return true;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
else if (SupportsRule* f = Cast<SupportsRule>(stm)) {
|
|
650
|
+
if (isPrintable(f, style)) {
|
|
651
|
+
return true;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
else if (CssMediaRule* mb = Cast<CssMediaRule>(stm)) {
|
|
655
|
+
if (isPrintable(mb, style)) {
|
|
656
|
+
return true;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
else if (ParentStatement* b = Cast<ParentStatement>(stm)) {
|
|
660
|
+
if (isPrintable(b->block(), style)) {
|
|
661
|
+
return true;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
return false;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
bool isPrintable(Comment* c, Sass_Output_Style style)
|
|
669
|
+
{
|
|
670
|
+
// keep for uncompressed
|
|
671
|
+
if (style != COMPRESSED) {
|
|
672
|
+
return true;
|
|
673
|
+
}
|
|
674
|
+
// output style compressed
|
|
675
|
+
if (c->is_important()) {
|
|
676
|
+
return true;
|
|
677
|
+
}
|
|
678
|
+
// not printable
|
|
679
|
+
return false;
|
|
680
|
+
};
|
|
681
|
+
|
|
682
|
+
bool isPrintable(Block_Obj b, Sass_Output_Style style) {
|
|
683
|
+
if (!b) {
|
|
684
|
+
return false;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
688
|
+
Statement_Obj stm = b->at(i);
|
|
689
|
+
if (Cast<Declaration>(stm) || Cast<AtRule>(stm)) {
|
|
690
|
+
return true;
|
|
691
|
+
}
|
|
692
|
+
else if (Comment* c = Cast<Comment>(stm)) {
|
|
693
|
+
if (isPrintable(c, style)) {
|
|
694
|
+
return true;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
else if (StyleRule* r = Cast<StyleRule>(stm)) {
|
|
698
|
+
if (isPrintable(r, style)) {
|
|
699
|
+
return true;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
else if (SupportsRule* f = Cast<SupportsRule>(stm)) {
|
|
703
|
+
if (isPrintable(f, style)) {
|
|
704
|
+
return true;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
else if (CssMediaRule * m = Cast<CssMediaRule>(stm)) {
|
|
708
|
+
if (isPrintable(m, style)) {
|
|
709
|
+
return true;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
else if (ParentStatement* b = Cast<ParentStatement>(stm)) {
|
|
713
|
+
if (isPrintable(b->block(), style)) {
|
|
714
|
+
return true;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
return false;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
}
|
|
723
|
+
}
|