sassc 0.0.9 → 0.0.10

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 (111) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/ext/libsass/.gitignore +13 -6
  4. data/ext/libsass/Makefile +42 -26
  5. data/ext/libsass/Makefile.am +43 -30
  6. data/ext/libsass/Readme.md +4 -2
  7. data/ext/libsass/appveyor.yml +10 -14
  8. data/ext/libsass/ast.cpp +54 -44
  9. data/ext/libsass/ast.hpp +404 -236
  10. data/ext/libsass/ast_def_macros.hpp +5 -0
  11. data/ext/libsass/ast_factory.hpp +6 -3
  12. data/ext/libsass/ast_fwd_decl.hpp +12 -0
  13. data/ext/libsass/b64/encode.h +2 -2
  14. data/ext/libsass/backtrace.hpp +13 -17
  15. data/ext/libsass/base64vlq.hpp +4 -1
  16. data/ext/libsass/bind.cpp +12 -15
  17. data/ext/libsass/bind.hpp +6 -6
  18. data/ext/libsass/color_names.hpp +4 -1
  19. data/ext/libsass/configure.ac +7 -21
  20. data/ext/libsass/constants.cpp +6 -4
  21. data/ext/libsass/constants.hpp +10 -4
  22. data/ext/libsass/context.cpp +89 -58
  23. data/ext/libsass/context.hpp +28 -35
  24. data/ext/libsass/contextualize.cpp +20 -10
  25. data/ext/libsass/contextualize.hpp +8 -23
  26. data/ext/libsass/contrib/libsass.spec +66 -0
  27. data/ext/libsass/cssize.cpp +547 -0
  28. data/ext/libsass/cssize.hpp +82 -0
  29. data/ext/libsass/debug.hpp +3 -3
  30. data/ext/libsass/debugger.hpp +358 -0
  31. data/ext/libsass/emitter.cpp +255 -0
  32. data/ext/libsass/emitter.hpp +83 -0
  33. data/ext/libsass/environment.hpp +7 -3
  34. data/ext/libsass/error_handling.cpp +11 -14
  35. data/ext/libsass/error_handling.hpp +9 -7
  36. data/ext/libsass/eval.cpp +253 -161
  37. data/ext/libsass/eval.hpp +13 -13
  38. data/ext/libsass/expand.cpp +135 -64
  39. data/ext/libsass/expand.hpp +11 -13
  40. data/ext/libsass/extend.cpp +66 -20
  41. data/ext/libsass/extend.hpp +6 -11
  42. data/ext/libsass/file.cpp +31 -26
  43. data/ext/libsass/file.hpp +6 -1
  44. data/ext/libsass/functions.cpp +270 -287
  45. data/ext/libsass/functions.hpp +8 -11
  46. data/ext/libsass/inspect.cpp +385 -255
  47. data/ext/libsass/inspect.hpp +15 -26
  48. data/ext/libsass/kwd_arg_macros.hpp +5 -0
  49. data/ext/libsass/mapping.hpp +4 -3
  50. data/ext/libsass/memory_manager.hpp +5 -2
  51. data/ext/libsass/node.cpp +50 -50
  52. data/ext/libsass/node.hpp +26 -27
  53. data/ext/libsass/operation.hpp +15 -4
  54. data/ext/libsass/output.cpp +401 -0
  55. data/ext/libsass/output.hpp +56 -0
  56. data/ext/libsass/parser.cpp +573 -399
  57. data/ext/libsass/parser.hpp +122 -88
  58. data/ext/libsass/paths.hpp +7 -2
  59. data/ext/libsass/plugins.cpp +155 -0
  60. data/ext/libsass/plugins.hpp +56 -0
  61. data/ext/libsass/position.cpp +128 -0
  62. data/ext/libsass/position.hpp +108 -11
  63. data/ext/libsass/prelexer.cpp +184 -110
  64. data/ext/libsass/prelexer.hpp +131 -24
  65. data/ext/libsass/remove_placeholders.cpp +1 -1
  66. data/ext/libsass/remove_placeholders.hpp +6 -6
  67. data/ext/libsass/sass.cpp +3 -3
  68. data/ext/libsass/sass.h +12 -4
  69. data/ext/libsass/sass2scss.cpp +3 -2
  70. data/ext/libsass/sass2scss.h +5 -0
  71. data/ext/libsass/sass_context.cpp +136 -37
  72. data/ext/libsass/sass_context.h +19 -10
  73. data/ext/libsass/sass_functions.cpp +29 -2
  74. data/ext/libsass/sass_functions.h +8 -2
  75. data/ext/libsass/sass_interface.cpp +32 -23
  76. data/ext/libsass/sass_interface.h +9 -4
  77. data/ext/libsass/sass_util.cpp +19 -23
  78. data/ext/libsass/sass_util.hpp +28 -27
  79. data/ext/libsass/sass_values.cpp +6 -4
  80. data/ext/libsass/sass_values.h +3 -3
  81. data/ext/libsass/script/ci-build-libsass +13 -1
  82. data/ext/libsass/script/ci-report-coverage +2 -1
  83. data/ext/libsass/source_map.cpp +79 -28
  84. data/ext/libsass/source_map.hpp +35 -16
  85. data/ext/libsass/subset_map.hpp +6 -4
  86. data/ext/libsass/to_c.hpp +4 -4
  87. data/ext/libsass/to_string.cpp +13 -8
  88. data/ext/libsass/to_string.hpp +6 -4
  89. data/ext/libsass/units.cpp +2 -1
  90. data/ext/libsass/units.hpp +6 -1
  91. data/ext/libsass/utf8_string.cpp +0 -5
  92. data/ext/libsass/utf8_string.hpp +3 -2
  93. data/ext/libsass/util.cpp +461 -49
  94. data/ext/libsass/util.hpp +34 -13
  95. data/ext/libsass/version.sh +10 -0
  96. data/ext/libsass/win/libsass.filters +20 -11
  97. data/ext/libsass/win/libsass.vcxproj +11 -8
  98. data/lib/sassc/importer.rb +1 -8
  99. data/lib/sassc/native.rb +7 -0
  100. data/lib/sassc/native/native_context_api.rb +5 -5
  101. data/lib/sassc/version.rb +1 -1
  102. data/test/native_test.rb +1 -1
  103. metadata +14 -10
  104. data/ext/libsass/copy_c_str.cpp +0 -13
  105. data/ext/libsass/copy_c_str.hpp +0 -5
  106. data/ext/libsass/output_compressed.cpp +0 -401
  107. data/ext/libsass/output_compressed.hpp +0 -95
  108. data/ext/libsass/output_nested.cpp +0 -364
  109. data/ext/libsass/output_nested.hpp +0 -108
  110. data/ext/libsass/test-driver +0 -127
  111. data/ext/libsass/token.hpp +0 -32
@@ -1,8 +1,9 @@
1
- #define SASS_SUBSET_MAP
1
+ #ifndef SASS_SUBSET_MAP_H
2
+ #define SASS_SUBSET_MAP_H
2
3
 
3
- #include <vector>
4
4
  #include <map>
5
5
  #include <set>
6
+ #include <vector>
6
7
  #include <algorithm>
7
8
  #include <iterator>
8
9
  #include <iostream>
@@ -81,6 +82,7 @@ namespace Sass {
81
82
  vector<V> get_v(const vector<K>& s);
82
83
  bool empty() { return values_.empty(); }
83
84
  void clear() { values_.clear(); hash_.clear(); }
85
+ const vector<V> values(void) { return values_; }
84
86
  };
85
87
 
86
88
  template<typename K, typename V>
@@ -106,9 +108,7 @@ namespace Sass {
106
108
  sort(sorted.begin(), sorted.end());
107
109
  vector<pair<size_t, vector<K> > > indices;
108
110
  for (size_t i = 0, S = s.size(); i < S; ++i) {
109
- // cerr << "looking for " << s[i] << endl;
110
111
  if (!hash_.count(s[i])) {
111
- // cerr << "didn't find " << s[i] << endl;
112
112
  continue;
113
113
  }
114
114
  vector<triple<vector<K>, set<K>, size_t> > subsets = hash_[s[i]];
@@ -143,3 +143,5 @@ namespace Sass {
143
143
  }
144
144
 
145
145
  }
146
+
147
+ #endif
@@ -1,9 +1,7 @@
1
- #define SASS_TO_C
1
+ #ifndef SASS_TO_C_H
2
+ #define SASS_TO_C_H
2
3
 
3
- #ifndef SASS_OPERATION
4
4
  #include "operation.hpp"
5
- #endif
6
-
7
5
  #include "sass_values.h"
8
6
 
9
7
  namespace Sass {
@@ -42,3 +40,5 @@ namespace Sass {
42
40
  };
43
41
 
44
42
  }
43
+
44
+ #endif
@@ -1,29 +1,34 @@
1
1
  #include <cmath>
2
2
  #include <sstream>
3
3
  #include <iomanip>
4
+ #include <iostream>
4
5
 
5
- #ifndef SASS_TO_STRING
6
- #include "to_string.hpp"
7
- #endif
8
-
9
- #include "inspect.hpp"
10
6
  #include "ast.hpp"
7
+ #include "inspect.hpp"
11
8
  #include "context.hpp"
12
- #include <iostream>
9
+ #include "to_string.hpp"
13
10
 
14
11
  namespace Sass {
15
12
  using namespace std;
16
13
 
17
- To_String::To_String(Context* ctx) : ctx(ctx) { }
14
+ To_String::To_String(Context* ctx)
15
+ : ctx(ctx) { }
18
16
  To_String::~To_String() { }
19
17
 
20
18
  inline string To_String::fallback_impl(AST_Node* n)
21
19
  {
22
- Inspect i(ctx);
20
+ Emitter emitter(ctx);
21
+ Inspect i(emitter);
22
+ i.in_declaration_list = true;
23
23
  n->perform(&i);
24
24
  return i.get_buffer();
25
25
  }
26
26
 
27
+ inline string To_String::operator()(String_Constant* s)
28
+ {
29
+ return s->value();
30
+ }
31
+
27
32
  inline string To_String::operator()(Null* n)
28
33
  { return ""; }
29
34
  }
@@ -1,15 +1,14 @@
1
- #define SASS_TO_STRING
1
+ #ifndef SASS_TO_STRING_H
2
+ #define SASS_TO_STRING_H
2
3
 
3
4
  #include <string>
4
5
 
5
- #ifndef SASS_OPERATION
6
6
  #include "operation.hpp"
7
- #endif
8
7
 
9
8
  namespace Sass {
10
9
  using namespace std;
11
10
 
12
- struct Context;
11
+ class Context;
13
12
  class Null;
14
13
 
15
14
  class To_String : public Operation_CRTP<string, To_String> {
@@ -25,8 +24,11 @@ namespace Sass {
25
24
  virtual ~To_String();
26
25
 
27
26
  string operator()(Null* n);
27
+ string operator()(String_Constant*);
28
28
 
29
29
  template <typename U>
30
30
  string fallback(U n) { return fallback_impl(n); }
31
31
  };
32
32
  }
33
+
34
+ #endif
@@ -45,10 +45,11 @@ namespace Sass {
45
45
  return factor;
46
46
  }
47
47
 
48
+ /* not used anymore - remove?
48
49
  double convert(double n, const string& from, const string& to)
49
50
  {
50
51
  double factor = conversion_factor(from, to);
51
52
  return factor ? factor * n : n;
52
- }
53
+ } */
53
54
 
54
55
  }
@@ -1,3 +1,6 @@
1
+ #ifndef SASS_UNITS_H
2
+ #define SASS_UNITS_H
3
+
1
4
  #include <string>
2
5
 
3
6
  namespace Sass {
@@ -6,5 +9,7 @@ namespace Sass {
6
9
  extern double conversion_factors[10][10];
7
10
  Unit string_to_unit(const string&);
8
11
  double conversion_factor(const string&, const string&);
9
- double convert(double, const string&, const string&);
12
+ // double convert(double, const string&, const string&);
10
13
  }
14
+
15
+ #endif
@@ -1,6 +1,3 @@
1
- #ifndef SASS_UTF8_STRING
2
- #define SASS_UTF8_STRING
3
-
4
1
  #include <string>
5
2
  #include <vector>
6
3
  #include <cstdlib>
@@ -98,5 +95,3 @@ namespace Sass {
98
95
 
99
96
  }
100
97
  }
101
-
102
- #endif
@@ -1,7 +1,8 @@
1
- #ifndef SASS_UTF8_STRING
2
- #define SASS_UTF8_STRING
1
+ #ifndef SASS_UTF8_STRING_H
2
+ #define SASS_UTF8_STRING_H
3
3
 
4
4
  #include <string>
5
+ #include "utf8.h"
5
6
 
6
7
  namespace Sass {
7
8
  namespace UTF_8 {
@@ -1,6 +1,391 @@
1
+ #include<stdint.h>
2
+ #include "ast.hpp"
1
3
  #include "util.hpp"
4
+ #include "prelexer.hpp"
5
+ #include "utf8/checked.h"
2
6
 
3
7
  namespace Sass {
8
+
9
+ #define out_of_memory() do { \
10
+ fprintf(stderr, "Out of memory.\n"); \
11
+ exit(EXIT_FAILURE); \
12
+ } while (0)
13
+
14
+ /* Sadly, sass_strdup is not portable. */
15
+ char *sass_strdup(const char *str)
16
+ {
17
+ char *ret = (char*) malloc(strlen(str) + 1);
18
+ if (ret == NULL)
19
+ out_of_memory();
20
+ strcpy(ret, str);
21
+ return ret;
22
+ }
23
+
24
+ /* Locale unspecific atof function. */
25
+ double sass_atof(const char *str)
26
+ {
27
+ char separator = *(localeconv()->decimal_point);
28
+ if(separator != '.'){
29
+ // The current locale specifies another
30
+ // separator. convert the separator to the
31
+ // one understood by the locale if needed
32
+ const char *found = strchr(str, '.');
33
+ if(found != NULL){
34
+ // substitution is required. perform the substitution on a copy
35
+ // of the string. This is slower but it is thread safe.
36
+ char *copy = sass_strdup(str);
37
+ *(copy + (found - str)) = separator;
38
+ double res = atof(copy);
39
+ free(copy);
40
+ return res;
41
+ }
42
+ }
43
+
44
+ return atof(str);
45
+ }
46
+
47
+ // double escape every escape sequences
48
+ // escape unescaped quotes and backslashes
49
+ string string_escape(const string& str)
50
+ {
51
+ string out("");
52
+ for (auto i : str) {
53
+ // escape some characters
54
+ if (i == '"') out += '\\';
55
+ if (i == '\'') out += '\\';
56
+ if (i == '\\') out += '\\';
57
+ out += i;
58
+ }
59
+ return out;
60
+ }
61
+
62
+ // unescape every escape sequence
63
+ // only removes unescaped backslashes
64
+ string string_unescape(const string& str)
65
+ {
66
+ string out("");
67
+ bool esc = false;
68
+ for (auto i : str) {
69
+ if (esc || i != '\\') {
70
+ esc = false;
71
+ out += i;
72
+ } else {
73
+ esc = true;
74
+ }
75
+ }
76
+ // open escape sequence at end
77
+ // maybe it should thow an error
78
+ if (esc) { out += '\\'; }
79
+ return out;
80
+ }
81
+
82
+ // evacuate unescaped quoted
83
+ // leave everything else untouched
84
+ string evacuate_quotes(const string& str)
85
+ {
86
+ string out("");
87
+ bool esc = false;
88
+ for (auto i : str) {
89
+ if (!esc) {
90
+ // ignore next character
91
+ if (i == '\\') esc = true;
92
+ // evacuate unescaped quotes
93
+ else if (i == '"') out += '\\';
94
+ else if (i == '\'') out += '\\';
95
+ }
96
+ // get escaped char now
97
+ else { esc = false; }
98
+ // remove nothing
99
+ out += i;
100
+ }
101
+ return out;
102
+ }
103
+
104
+ // double escape all escape sequences
105
+ // keep unescaped quotes and backslashes
106
+ string evacuate_escapes(const string& str)
107
+ {
108
+ string out("");
109
+ bool esc = false;
110
+ for (auto i : str) {
111
+ if (i == '\\' && !esc) {
112
+ out += '\\';
113
+ out += '\\';
114
+ esc = true;
115
+ } else if (esc && i == '"') {
116
+ out += '\\';
117
+ out += i;
118
+ esc = false;
119
+ } else if (esc && i == '\'') {
120
+ out += '\\';
121
+ out += i;
122
+ esc = false;
123
+ } else if (esc && i == '\\') {
124
+ out += '\\';
125
+ out += i;
126
+ esc = false;
127
+ } else {
128
+ esc = false;
129
+ out += i;
130
+ }
131
+ }
132
+ // happens when parsing does not correctly skip
133
+ // over escaped sequences for ie. interpolations
134
+ // one example: foo\#{interpolate}
135
+ // if (esc) out += '\\';
136
+ return out;
137
+ }
138
+
139
+ // bell character is replaces with space
140
+ string string_to_output(const string& str)
141
+ {
142
+ string out("");
143
+ for (auto i : str) {
144
+ if (i == 10) {
145
+ out += ' ';
146
+ } else {
147
+ out += i;
148
+ }
149
+ }
150
+ return out;
151
+ }
152
+
153
+ string comment_to_string(const string& text)
154
+ {
155
+ string str = "";
156
+ size_t has = 0;
157
+ bool clean = false;
158
+ for (auto i : text) {
159
+ if (clean) {
160
+ if (i == '\n') { has = 0; }
161
+ else if (i == '\r') { has = 0; }
162
+ else if (i == '\t') { ++ has; }
163
+ else if (i == ' ') { ++ has; }
164
+ else if (i == '*') {}
165
+ else {
166
+ clean = false;
167
+ str += ' ';
168
+ str += i;
169
+ }
170
+ } else if (i == '\n') {
171
+ clean = true;
172
+ } else if (i == '\r') {
173
+ clean = true;
174
+ } else {
175
+ str += i;
176
+ }
177
+ }
178
+ if (has) return str;
179
+ else return text;
180
+ }
181
+
182
+ string normalize_wspace(const string& str)
183
+ {
184
+ bool ws = false;
185
+ bool esc = false;
186
+ char inside_str = 0;
187
+ string text = "";
188
+ for(auto i : str) {
189
+ if (!esc && i == '\\') {
190
+ esc = true;
191
+ text += i;
192
+ } else if (esc) {
193
+ esc = false;
194
+ text += i;
195
+ } else if (!inside_str && (i == '"' || i == '\'')) {
196
+ inside_str = i;
197
+ text += i;
198
+ } else if (inside_str) {
199
+ if (i == inside_str)
200
+ inside_str = false;
201
+ text += i;
202
+ } else if (
203
+ i == ' ' ||
204
+ i == '\r' ||
205
+ i == '\n' ||
206
+ i == ' '
207
+ ) {
208
+ // only add one space
209
+ if (!ws) text += ' ';
210
+ ws = true;
211
+ } else {
212
+ ws = false;
213
+ text += i;
214
+ }
215
+ }
216
+ if (esc) text += '\\';
217
+ return text;
218
+ }
219
+
220
+ // find best quote_mark by detecting if the string contains any single
221
+ // or double quotes. When a single quote is found, we not we want a double
222
+ // quote as quote_mark. Otherwise we check if the string cotains any double
223
+ // quotes, which will trigger the use of single quotes as best quote_mark.
224
+ char detect_best_quotemark(const char* s, char qm)
225
+ {
226
+ // ensure valid fallback quote_mark
227
+ char quote_mark = qm && qm != '*' ? qm : '"';
228
+ while (*s) {
229
+ // force double quotes as soon
230
+ // as one single quote is found
231
+ if (*s == '\'') { return '"'; }
232
+ // a single does not force quote_mark
233
+ // maybe we see a double quote later
234
+ else if (*s == '"') { quote_mark = '\''; }
235
+ ++ s;
236
+ }
237
+ return quote_mark;
238
+ }
239
+
240
+ string unquote(const string& s, char* qd)
241
+ {
242
+
243
+ // not enough room for quotes
244
+ // no possibility to unquote
245
+ if (s.length() < 2) return s;
246
+
247
+ char q;
248
+ bool skipped = false;
249
+
250
+ // this is no guarantee that the unquoting will work
251
+ // what about whitespace before/after the quote_mark?
252
+ if (*s.begin() == '"' && *s.rbegin() == '"') q = '"';
253
+ else if (*s.begin() == '\'' && *s.rbegin() == '\'') q = '\'';
254
+ else return s;
255
+
256
+ string unq;
257
+ unq.reserve(s.length()-2);
258
+
259
+ for (size_t i = 1, L = s.length() - 1; i < L; ++i) {
260
+
261
+ // implement the same strange ruby sass behavior
262
+ // an escape sequence can also mean a unicode char
263
+ if (s[i] == '\\' && !skipped) {
264
+ // remember
265
+ skipped = true;
266
+
267
+ // skip it
268
+ // ++ i;
269
+
270
+ // if (i == L) break;
271
+
272
+ // escape length
273
+ size_t len = 1;
274
+
275
+ // parse as many sequence chars as possible
276
+ // ToDo: Check if ruby aborts after possible max
277
+ while (i + len < L && s[i + len] && isxdigit(s[i + len])) ++ len;
278
+
279
+ // hex string?
280
+ if (len > 1) {
281
+
282
+ // convert the extracted hex string to code point value
283
+ // ToDo: Maybe we could do this without creating a substring
284
+ uint32_t cp = strtol(s.substr (i + 1, len - 1).c_str(), nullptr, 16);
285
+
286
+ // assert invalid code points
287
+ if (cp == 0) cp = 0xFFFD;
288
+ // replace bell character
289
+ // if (cp == 10) cp = 32;
290
+
291
+ // use a very simple approach to convert via utf8 lib
292
+ // maybe there is a more elegant way; maybe we shoud
293
+ // convert the whole output from string to a stream!?
294
+ // allocate memory for utf8 char and convert to utf8
295
+ unsigned char u[5] = {0,0,0,0,0}; utf8::append(cp, u);
296
+ for(size_t m = 0; u[m] && m < 5; m++) unq.push_back(u[m]);
297
+
298
+ // skip some more chars?
299
+ i += len - 1; skipped = false;
300
+
301
+ }
302
+
303
+
304
+ }
305
+ // check for unexpected delimiter
306
+ // be strict and throw error back
307
+ else if (!skipped && q == s[i]) {
308
+ // don't be that strict
309
+ return s;
310
+ // this basically always means an internal error and not users fault
311
+ error("Unescaped delimiter in string to unquote found. [" + s + "]", ParserState("[UNQUOTE]", -1));
312
+ }
313
+ else {
314
+ skipped = false;
315
+ unq.push_back(s[i]);
316
+ }
317
+
318
+ }
319
+ if (skipped) { return s; }
320
+ if (qd) *qd = q;
321
+ return unq;
322
+
323
+ }
324
+
325
+ string quote(const string& s, char q)
326
+ {
327
+
328
+ // return an empty quoted string
329
+ if (s.empty()) return string(2, q ? q : '"');
330
+
331
+ // autodetect with fallback to given quote
332
+ q = detect_best_quotemark(s.c_str(), q);
333
+
334
+ string quoted;
335
+ quoted.reserve(s.length()+2);
336
+ quoted.push_back(q);
337
+
338
+ const char* it = s.c_str();
339
+ const char* end = it + strlen(it) + 1;
340
+ while (*it && it < end) {
341
+ const char* now = it;
342
+
343
+ if (*it == q) {
344
+ quoted.push_back('\\');
345
+ } else if (*it == '\\') {
346
+ quoted.push_back('\\');
347
+ }
348
+
349
+ int cp = utf8::next(it, end);
350
+
351
+ if (cp == 10) {
352
+ quoted.push_back('\\');
353
+ quoted.push_back('a');
354
+ } else if (cp < 127) {
355
+ quoted.push_back((char) cp);
356
+ } else {
357
+ while (now < it) {
358
+ quoted.push_back(*now);
359
+ ++ now;
360
+ }
361
+ }
362
+ }
363
+
364
+ quoted.push_back(q);
365
+ return quoted;
366
+ }
367
+
368
+ bool is_hex_doublet(double n)
369
+ {
370
+ return n == 0x00 || n == 0x11 || n == 0x22 || n == 0x33 ||
371
+ n == 0x44 || n == 0x55 || n == 0x66 || n == 0x77 ||
372
+ n == 0x88 || n == 0x99 || n == 0xAA || n == 0xBB ||
373
+ n == 0xCC || n == 0xDD || n == 0xEE || n == 0xFF ;
374
+ }
375
+
376
+ bool is_color_doublet(double r, double g, double b)
377
+ {
378
+ return is_hex_doublet(r) && is_hex_doublet(g) && is_hex_doublet(b);
379
+ }
380
+
381
+ bool peek_linefeed(const char* start)
382
+ {
383
+ if(*start == '\n' || *start == '\r') return true;;
384
+ const char* linefeed = Prelexer::wspaces(start);
385
+ if (linefeed == 0) return false;
386
+ return *linefeed == '\n' || *linefeed == '\r';
387
+ }
388
+
4
389
  namespace Util {
5
390
  using std::string;
6
391
 
@@ -37,7 +422,7 @@ namespace Sass {
37
422
  }
38
423
  }
39
424
 
40
- bool isPrintable(Ruleset* r) {
425
+ bool isPrintable(Ruleset* r, Output_Style style) {
41
426
  if (r == NULL) {
42
427
  return false;
43
428
  }
@@ -47,7 +432,7 @@ namespace Sass {
47
432
  bool hasSelectors = static_cast<Selector_List*>(r->selector())->length() > 0;
48
433
 
49
434
  if (!hasSelectors) {
50
- return false;
435
+ return false;
51
436
  }
52
437
 
53
438
  bool hasDeclarations = false;
@@ -55,23 +440,29 @@ namespace Sass {
55
440
  for (size_t i = 0, L = b->length(); i < L; ++i) {
56
441
  Statement* stm = (*b)[i];
57
442
  if (dynamic_cast<Has_Block*>(stm)) {
58
- Block* pChildBlock = ((Has_Block*)stm)->block();
59
- if (isPrintable(pChildBlock)) {
443
+ Block* pChildBlock = ((Has_Block*)stm)->block();
444
+ if (isPrintable(pChildBlock, style)) {
60
445
  hasPrintableChildBlocks = true;
61
446
  }
447
+ } else if (Comment* c = dynamic_cast<Comment*>(stm)) {
448
+ if (style == COMPRESSED) {
449
+ hasDeclarations = c->is_important();
450
+ } else {
451
+ hasDeclarations = true;
452
+ }
62
453
  } else {
63
- hasDeclarations = true;
454
+ hasDeclarations = true;
64
455
  }
65
456
 
66
457
  if (hasDeclarations || hasPrintableChildBlocks) {
67
- return true;
458
+ return true;
68
459
  }
69
460
  }
70
461
 
71
462
  return false;
72
463
  }
73
464
 
74
- bool isPrintable(Feature_Block* f) {
465
+ bool isPrintable(Feature_Block* f, Output_Style style) {
75
466
  if (f == NULL) {
76
467
  return false;
77
468
  }
@@ -95,7 +486,7 @@ namespace Sass {
95
486
  }
96
487
  else if (dynamic_cast<Has_Block*>(stm)) {
97
488
  Block* pChildBlock = ((Has_Block*)stm)->block();
98
- if (isPrintable(pChildBlock)) {
489
+ if (isPrintable(pChildBlock, style)) {
99
490
  hasPrintableChildBlocks = true;
100
491
  }
101
492
  }
@@ -108,7 +499,7 @@ namespace Sass {
108
499
  return false;
109
500
  }
110
501
 
111
- bool isPrintable(Media_Block* m) {
502
+ bool isPrintable(Media_Block* m, Output_Style style) {
112
503
  if (m == NULL) {
113
504
  return false;
114
505
  }
@@ -122,7 +513,7 @@ namespace Sass {
122
513
  for (size_t i = 0, L = b->length(); i < L; ++i) {
123
514
  Statement* stm = (*b)[i];
124
515
  if (!stm->is_hoistable() && m->selector() != NULL && !hasSelectors) {
125
- // If a statement isn't hoistable, the selectors apply to it. If there are no selectors (a selector list of length 0),
516
+ // If a statement isn't hoistable, the selectors apply to it. If there are no selectors (a selector list of length 0),
126
517
  // then those statements aren't considered printable. That means there was a placeholder that was removed. If the selector
127
518
  // is NULL, then that means there was never a wrapping selector and it is printable (think of a top level media block with
128
519
  // a declaration in it).
@@ -131,55 +522,76 @@ namespace Sass {
131
522
  hasDeclarations = true;
132
523
  }
133
524
  else if (dynamic_cast<Has_Block*>(stm)) {
134
- Block* pChildBlock = ((Has_Block*)stm)->block();
135
- if (isPrintable(pChildBlock)) {
525
+ Block* pChildBlock = ((Has_Block*)stm)->block();
526
+ if (isPrintable(pChildBlock, style)) {
136
527
  hasPrintableChildBlocks = true;
137
528
  }
138
529
  }
139
530
 
140
- if (hasDeclarations || hasPrintableChildBlocks) {
141
- return true;
531
+ if (hasDeclarations || hasPrintableChildBlocks) {
532
+ return true;
142
533
  }
143
534
  }
144
535
 
145
536
  return false;
146
537
  }
147
538
 
148
- bool isPrintable(Block* b) {
149
- if (b == NULL) {
150
- return false;
151
- }
152
-
153
- for (size_t i = 0, L = b->length(); i < L; ++i) {
154
- Statement* stm = (*b)[i];
155
- if (typeid(*stm) == typeid(Declaration) || typeid(*stm) == typeid(At_Rule)) {
156
- return true;
157
- }
158
- else if (typeid(*stm) == typeid(Ruleset)) {
159
- Ruleset* r = (Ruleset*) stm;
160
- if (isPrintable(r)) {
161
- return true;
162
- }
163
- }
164
- else if (typeid(*stm) == typeid(Feature_Block)) {
165
- Feature_Block* f = (Feature_Block*) stm;
166
- if (isPrintable(f)) {
167
- return true;
168
- }
169
- }
170
- else if (typeid(*stm) == typeid(Media_Block)) {
171
- Media_Block* m = (Media_Block*) stm;
172
- if (isPrintable(m)) {
173
- return true;
174
- }
175
- }
176
- else if (dynamic_cast<Has_Block*>(stm) && isPrintable(((Has_Block*)stm)->block())) {
177
- return true;
178
- }
179
- }
180
-
181
- return false;
182
- }
539
+ bool isPrintable(Block* b, Output_Style style) {
540
+ if (b == NULL) {
541
+ return false;
542
+ }
543
+
544
+ for (size_t i = 0, L = b->length(); i < L; ++i) {
545
+ Statement* stm = (*b)[i];
546
+ if (typeid(*stm) == typeid(Declaration) || typeid(*stm) == typeid(At_Rule)) {
547
+ return true;
548
+ }
549
+ else if (typeid(*stm) == typeid(Comment)) {
550
+
551
+ }
552
+ else if (typeid(*stm) == typeid(Ruleset)) {
553
+ Ruleset* r = (Ruleset*) stm;
554
+ if (isPrintable(r, style)) {
555
+ return true;
556
+ }
557
+ }
558
+ else if (typeid(*stm) == typeid(Feature_Block)) {
559
+ Feature_Block* f = (Feature_Block*) stm;
560
+ if (isPrintable(f, style)) {
561
+ return true;
562
+ }
563
+ }
564
+ else if (typeid(*stm) == typeid(Media_Block)) {
565
+ Media_Block* m = (Media_Block*) stm;
566
+ if (isPrintable(m, style)) {
567
+ return true;
568
+ }
569
+ }
570
+ else if (dynamic_cast<Has_Block*>(stm) && isPrintable(((Has_Block*)stm)->block(), style)) {
571
+ return true;
572
+ }
573
+ }
574
+
575
+ return false;
576
+ }
577
+
578
+ string vecJoin(const vector<string>& vec, const string& sep)
579
+ {
580
+ switch (vec.size())
581
+ {
582
+ case 0:
583
+ return string("");
584
+ case 1:
585
+ return vec[0];
586
+ default:
587
+ std::ostringstream os;
588
+ os << vec[0];
589
+ for (size_t i = 1; i < vec.size(); i++) {
590
+ os << sep << vec[i];
591
+ }
592
+ return os.str();
593
+ }
594
+ }
183
595
 
184
596
  bool isAscii(int ch) {
185
597
  return ch >= 0 && ch < 128;