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.
Files changed (216) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +16 -0
  5. data/CHANGELOG.md +97 -0
  6. data/CODE_OF_CONDUCT.md +10 -0
  7. data/Gemfile +2 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +80 -0
  10. data/Rakefile +51 -0
  11. data/ext/depend +4 -0
  12. data/ext/extconf.rb +92 -0
  13. data/ext/libsass/VERSION +1 -0
  14. data/ext/libsass/contrib/plugin.cpp +60 -0
  15. data/ext/libsass/include/sass/base.h +97 -0
  16. data/ext/libsass/include/sass/context.h +174 -0
  17. data/ext/libsass/include/sass/functions.h +139 -0
  18. data/ext/libsass/include/sass/values.h +145 -0
  19. data/ext/libsass/include/sass/version.h +12 -0
  20. data/ext/libsass/include/sass.h +15 -0
  21. data/ext/libsass/include/sass2scss.h +120 -0
  22. data/ext/libsass/src/MurmurHash2.hpp +91 -0
  23. data/ext/libsass/src/ast.cpp +953 -0
  24. data/ext/libsass/src/ast.hpp +1064 -0
  25. data/ext/libsass/src/ast2c.cpp +80 -0
  26. data/ext/libsass/src/ast2c.hpp +39 -0
  27. data/ext/libsass/src/ast_def_macros.hpp +140 -0
  28. data/ext/libsass/src/ast_fwd_decl.cpp +31 -0
  29. data/ext/libsass/src/ast_fwd_decl.hpp +274 -0
  30. data/ext/libsass/src/ast_helpers.hpp +316 -0
  31. data/ext/libsass/src/ast_sel_cmp.cpp +396 -0
  32. data/ext/libsass/src/ast_sel_super.cpp +539 -0
  33. data/ext/libsass/src/ast_sel_unify.cpp +275 -0
  34. data/ext/libsass/src/ast_sel_weave.cpp +616 -0
  35. data/ext/libsass/src/ast_selectors.cpp +1070 -0
  36. data/ext/libsass/src/ast_selectors.hpp +523 -0
  37. data/ext/libsass/src/ast_supports.cpp +114 -0
  38. data/ext/libsass/src/ast_supports.hpp +121 -0
  39. data/ext/libsass/src/ast_values.cpp +1154 -0
  40. data/ext/libsass/src/ast_values.hpp +498 -0
  41. data/ext/libsass/src/b64/cencode.h +32 -0
  42. data/ext/libsass/src/b64/encode.h +79 -0
  43. data/ext/libsass/src/backtrace.cpp +50 -0
  44. data/ext/libsass/src/backtrace.hpp +29 -0
  45. data/ext/libsass/src/base64vlq.cpp +47 -0
  46. data/ext/libsass/src/base64vlq.hpp +30 -0
  47. data/ext/libsass/src/bind.cpp +312 -0
  48. data/ext/libsass/src/bind.hpp +15 -0
  49. data/ext/libsass/src/c2ast.cpp +64 -0
  50. data/ext/libsass/src/c2ast.hpp +14 -0
  51. data/ext/libsass/src/c99func.c +54 -0
  52. data/ext/libsass/src/cencode.c +106 -0
  53. data/ext/libsass/src/check_nesting.cpp +393 -0
  54. data/ext/libsass/src/check_nesting.hpp +70 -0
  55. data/ext/libsass/src/color_maps.cpp +652 -0
  56. data/ext/libsass/src/color_maps.hpp +323 -0
  57. data/ext/libsass/src/color_spaces.cpp +241 -0
  58. data/ext/libsass/src/color_spaces.hpp +227 -0
  59. data/ext/libsass/src/constants.cpp +199 -0
  60. data/ext/libsass/src/constants.hpp +200 -0
  61. data/ext/libsass/src/context.cpp +870 -0
  62. data/ext/libsass/src/context.hpp +140 -0
  63. data/ext/libsass/src/cssize.cpp +521 -0
  64. data/ext/libsass/src/cssize.hpp +71 -0
  65. data/ext/libsass/src/dart_helpers.hpp +199 -0
  66. data/ext/libsass/src/debug.hpp +43 -0
  67. data/ext/libsass/src/debugger.hpp +964 -0
  68. data/ext/libsass/src/emitter.cpp +297 -0
  69. data/ext/libsass/src/emitter.hpp +101 -0
  70. data/ext/libsass/src/environment.cpp +260 -0
  71. data/ext/libsass/src/environment.hpp +124 -0
  72. data/ext/libsass/src/error_handling.cpp +239 -0
  73. data/ext/libsass/src/error_handling.hpp +248 -0
  74. data/ext/libsass/src/eval.cpp +1543 -0
  75. data/ext/libsass/src/eval.hpp +110 -0
  76. data/ext/libsass/src/eval_selectors.cpp +75 -0
  77. data/ext/libsass/src/expand.cpp +875 -0
  78. data/ext/libsass/src/expand.hpp +98 -0
  79. data/ext/libsass/src/extender.cpp +1226 -0
  80. data/ext/libsass/src/extender.hpp +399 -0
  81. data/ext/libsass/src/extension.cpp +43 -0
  82. data/ext/libsass/src/extension.hpp +89 -0
  83. data/ext/libsass/src/file.cpp +531 -0
  84. data/ext/libsass/src/file.hpp +124 -0
  85. data/ext/libsass/src/fn_colors.cpp +836 -0
  86. data/ext/libsass/src/fn_colors.hpp +99 -0
  87. data/ext/libsass/src/fn_lists.cpp +285 -0
  88. data/ext/libsass/src/fn_lists.hpp +34 -0
  89. data/ext/libsass/src/fn_maps.cpp +94 -0
  90. data/ext/libsass/src/fn_maps.hpp +30 -0
  91. data/ext/libsass/src/fn_miscs.cpp +248 -0
  92. data/ext/libsass/src/fn_miscs.hpp +40 -0
  93. data/ext/libsass/src/fn_numbers.cpp +246 -0
  94. data/ext/libsass/src/fn_numbers.hpp +45 -0
  95. data/ext/libsass/src/fn_selectors.cpp +205 -0
  96. data/ext/libsass/src/fn_selectors.hpp +35 -0
  97. data/ext/libsass/src/fn_strings.cpp +268 -0
  98. data/ext/libsass/src/fn_strings.hpp +34 -0
  99. data/ext/libsass/src/fn_utils.cpp +159 -0
  100. data/ext/libsass/src/fn_utils.hpp +62 -0
  101. data/ext/libsass/src/inspect.cpp +1126 -0
  102. data/ext/libsass/src/inspect.hpp +101 -0
  103. data/ext/libsass/src/json.cpp +1436 -0
  104. data/ext/libsass/src/json.hpp +117 -0
  105. data/ext/libsass/src/kwd_arg_macros.hpp +28 -0
  106. data/ext/libsass/src/lexer.cpp +122 -0
  107. data/ext/libsass/src/lexer.hpp +304 -0
  108. data/ext/libsass/src/listize.cpp +70 -0
  109. data/ext/libsass/src/listize.hpp +37 -0
  110. data/ext/libsass/src/mapping.hpp +19 -0
  111. data/ext/libsass/src/memory/allocator.cpp +48 -0
  112. data/ext/libsass/src/memory/allocator.hpp +138 -0
  113. data/ext/libsass/src/memory/config.hpp +20 -0
  114. data/ext/libsass/src/memory/memory_pool.hpp +186 -0
  115. data/ext/libsass/src/memory/shared_ptr.cpp +33 -0
  116. data/ext/libsass/src/memory/shared_ptr.hpp +332 -0
  117. data/ext/libsass/src/memory.hpp +12 -0
  118. data/ext/libsass/src/operation.hpp +223 -0
  119. data/ext/libsass/src/operators.cpp +267 -0
  120. data/ext/libsass/src/operators.hpp +30 -0
  121. data/ext/libsass/src/ordered_map.hpp +112 -0
  122. data/ext/libsass/src/output.cpp +320 -0
  123. data/ext/libsass/src/output.hpp +47 -0
  124. data/ext/libsass/src/parser.cpp +3059 -0
  125. data/ext/libsass/src/parser.hpp +395 -0
  126. data/ext/libsass/src/parser_selectors.cpp +189 -0
  127. data/ext/libsass/src/permutate.hpp +164 -0
  128. data/ext/libsass/src/plugins.cpp +188 -0
  129. data/ext/libsass/src/plugins.hpp +57 -0
  130. data/ext/libsass/src/position.cpp +163 -0
  131. data/ext/libsass/src/position.hpp +147 -0
  132. data/ext/libsass/src/prelexer.cpp +1780 -0
  133. data/ext/libsass/src/prelexer.hpp +484 -0
  134. data/ext/libsass/src/remove_placeholders.cpp +86 -0
  135. data/ext/libsass/src/remove_placeholders.hpp +37 -0
  136. data/ext/libsass/src/sass.cpp +156 -0
  137. data/ext/libsass/src/sass.hpp +147 -0
  138. data/ext/libsass/src/sass2scss.cpp +895 -0
  139. data/ext/libsass/src/sass_context.cpp +742 -0
  140. data/ext/libsass/src/sass_context.hpp +129 -0
  141. data/ext/libsass/src/sass_functions.cpp +210 -0
  142. data/ext/libsass/src/sass_functions.hpp +50 -0
  143. data/ext/libsass/src/sass_values.cpp +362 -0
  144. data/ext/libsass/src/sass_values.hpp +82 -0
  145. data/ext/libsass/src/settings.hpp +19 -0
  146. data/ext/libsass/src/source.cpp +69 -0
  147. data/ext/libsass/src/source.hpp +95 -0
  148. data/ext/libsass/src/source_data.hpp +32 -0
  149. data/ext/libsass/src/source_map.cpp +202 -0
  150. data/ext/libsass/src/source_map.hpp +65 -0
  151. data/ext/libsass/src/stylesheet.cpp +22 -0
  152. data/ext/libsass/src/stylesheet.hpp +57 -0
  153. data/ext/libsass/src/to_value.cpp +114 -0
  154. data/ext/libsass/src/to_value.hpp +46 -0
  155. data/ext/libsass/src/units.cpp +507 -0
  156. data/ext/libsass/src/units.hpp +110 -0
  157. data/ext/libsass/src/utf8/checked.h +336 -0
  158. data/ext/libsass/src/utf8/core.h +332 -0
  159. data/ext/libsass/src/utf8/unchecked.h +235 -0
  160. data/ext/libsass/src/utf8.h +34 -0
  161. data/ext/libsass/src/utf8_string.cpp +104 -0
  162. data/ext/libsass/src/utf8_string.hpp +38 -0
  163. data/ext/libsass/src/util.cpp +723 -0
  164. data/ext/libsass/src/util.hpp +105 -0
  165. data/ext/libsass/src/util_string.cpp +125 -0
  166. data/ext/libsass/src/util_string.hpp +73 -0
  167. data/ext/libsass/src/values.cpp +140 -0
  168. data/ext/libsass/src/values.hpp +12 -0
  169. data/lib/sassc/dependency.rb +17 -0
  170. data/lib/sassc/engine.rb +141 -0
  171. data/lib/sassc/error.rb +37 -0
  172. data/lib/sassc/functions_handler.rb +73 -0
  173. data/lib/sassc/import_handler.rb +50 -0
  174. data/lib/sassc/importer.rb +31 -0
  175. data/lib/sassc/native/native_context_api.rb +147 -0
  176. data/lib/sassc/native/native_functions_api.rb +159 -0
  177. data/lib/sassc/native/sass2scss_api.rb +10 -0
  178. data/lib/sassc/native/sass_input_style.rb +13 -0
  179. data/lib/sassc/native/sass_output_style.rb +12 -0
  180. data/lib/sassc/native/sass_value.rb +97 -0
  181. data/lib/sassc/native/string_list.rb +10 -0
  182. data/lib/sassc/native.rb +64 -0
  183. data/lib/sassc/sass_2_scss.rb +9 -0
  184. data/lib/sassc/script/functions.rb +8 -0
  185. data/lib/sassc/script/value/bool.rb +32 -0
  186. data/lib/sassc/script/value/color.rb +95 -0
  187. data/lib/sassc/script/value/list.rb +136 -0
  188. data/lib/sassc/script/value/map.rb +69 -0
  189. data/lib/sassc/script/value/number.rb +389 -0
  190. data/lib/sassc/script/value/string.rb +96 -0
  191. data/lib/sassc/script/value.rb +137 -0
  192. data/lib/sassc/script/value_conversion/base.rb +13 -0
  193. data/lib/sassc/script/value_conversion/bool.rb +13 -0
  194. data/lib/sassc/script/value_conversion/color.rb +18 -0
  195. data/lib/sassc/script/value_conversion/list.rb +25 -0
  196. data/lib/sassc/script/value_conversion/map.rb +21 -0
  197. data/lib/sassc/script/value_conversion/number.rb +13 -0
  198. data/lib/sassc/script/value_conversion/string.rb +17 -0
  199. data/lib/sassc/script/value_conversion.rb +69 -0
  200. data/lib/sassc/script.rb +17 -0
  201. data/lib/sassc/util/normalized_map.rb +117 -0
  202. data/lib/sassc/util.rb +231 -0
  203. data/lib/sassc/version.rb +5 -0
  204. data/lib/sassc.rb +57 -0
  205. data/sassc.gemspec +69 -0
  206. data/test/css_color_level4_test.rb +168 -0
  207. data/test/custom_importer_test.rb +127 -0
  208. data/test/engine_test.rb +314 -0
  209. data/test/error_test.rb +29 -0
  210. data/test/fixtures/paths.scss +10 -0
  211. data/test/functions_test.rb +340 -0
  212. data/test/native_test.rb +213 -0
  213. data/test/output_style_test.rb +107 -0
  214. data/test/sass_2_scss_test.rb +14 -0
  215. data/test/test_helper.rb +45 -0
  216. 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
+ }