sassc 2.2.1 → 2.3.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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/CHANGELOG.md +13 -0
  4. data/Rakefile +1 -3
  5. data/ext/extconf.rb +13 -5
  6. data/ext/libsass/VERSION +1 -1
  7. data/ext/libsass/include/sass/base.h +2 -1
  8. data/ext/libsass/include/sass/context.h +1 -0
  9. data/ext/libsass/src/ast.cpp +49 -59
  10. data/ext/libsass/src/ast.hpp +263 -102
  11. data/ext/libsass/src/ast_def_macros.hpp +8 -0
  12. data/ext/libsass/src/ast_fwd_decl.cpp +2 -1
  13. data/ext/libsass/src/ast_fwd_decl.hpp +40 -116
  14. data/ext/libsass/src/ast_helpers.hpp +292 -0
  15. data/ext/libsass/src/ast_sel_cmp.cpp +209 -722
  16. data/ext/libsass/src/ast_sel_super.cpp +539 -0
  17. data/ext/libsass/src/ast_sel_unify.cpp +207 -212
  18. data/ext/libsass/src/ast_sel_weave.cpp +616 -0
  19. data/ext/libsass/src/ast_selectors.cpp +559 -1001
  20. data/ext/libsass/src/ast_selectors.hpp +311 -367
  21. data/ext/libsass/src/ast_supports.cpp +1 -17
  22. data/ext/libsass/src/ast_values.cpp +216 -29
  23. data/ext/libsass/src/ast_values.hpp +42 -33
  24. data/ext/libsass/src/bind.cpp +1 -1
  25. data/ext/libsass/src/cencode.c +4 -6
  26. data/ext/libsass/src/check_nesting.cpp +5 -6
  27. data/ext/libsass/src/check_nesting.hpp +4 -0
  28. data/ext/libsass/src/color_maps.cpp +11 -10
  29. data/ext/libsass/src/color_maps.hpp +0 -8
  30. data/ext/libsass/src/constants.cpp +5 -0
  31. data/ext/libsass/src/constants.hpp +6 -0
  32. data/ext/libsass/src/context.cpp +30 -60
  33. data/ext/libsass/src/context.hpp +8 -20
  34. data/ext/libsass/src/cssize.cpp +36 -120
  35. data/ext/libsass/src/cssize.hpp +4 -10
  36. data/ext/libsass/src/dart_helpers.hpp +199 -0
  37. data/ext/libsass/src/debugger.hpp +364 -207
  38. data/ext/libsass/src/emitter.cpp +3 -4
  39. data/ext/libsass/src/emitter.hpp +0 -2
  40. data/ext/libsass/src/environment.hpp +5 -0
  41. data/ext/libsass/src/error_handling.cpp +21 -0
  42. data/ext/libsass/src/error_handling.hpp +25 -3
  43. data/ext/libsass/src/eval.cpp +33 -153
  44. data/ext/libsass/src/eval.hpp +11 -13
  45. data/ext/libsass/src/eval_selectors.cpp +75 -0
  46. data/ext/libsass/src/expand.cpp +214 -167
  47. data/ext/libsass/src/expand.hpp +26 -6
  48. data/ext/libsass/src/extender.cpp +1186 -0
  49. data/ext/libsass/src/extender.hpp +399 -0
  50. data/ext/libsass/src/extension.cpp +43 -0
  51. data/ext/libsass/src/extension.hpp +89 -0
  52. data/ext/libsass/src/file.cpp +15 -14
  53. data/ext/libsass/src/file.hpp +5 -12
  54. data/ext/libsass/src/fn_colors.cpp +12 -10
  55. data/ext/libsass/src/fn_lists.cpp +12 -11
  56. data/ext/libsass/src/fn_miscs.cpp +22 -34
  57. data/ext/libsass/src/fn_numbers.cpp +13 -6
  58. data/ext/libsass/src/fn_selectors.cpp +94 -124
  59. data/ext/libsass/src/fn_strings.cpp +16 -14
  60. data/ext/libsass/src/fn_utils.cpp +5 -6
  61. data/ext/libsass/src/fn_utils.hpp +9 -3
  62. data/ext/libsass/src/inspect.cpp +154 -117
  63. data/ext/libsass/src/inspect.hpp +10 -8
  64. data/ext/libsass/src/lexer.cpp +17 -81
  65. data/ext/libsass/src/lexer.hpp +5 -16
  66. data/ext/libsass/src/listize.cpp +22 -36
  67. data/ext/libsass/src/listize.hpp +8 -9
  68. data/ext/libsass/src/memory/SharedPtr.hpp +39 -5
  69. data/ext/libsass/src/operation.hpp +27 -17
  70. data/ext/libsass/src/operators.cpp +1 -0
  71. data/ext/libsass/src/ordered_map.hpp +112 -0
  72. data/ext/libsass/src/output.cpp +30 -49
  73. data/ext/libsass/src/output.hpp +1 -1
  74. data/ext/libsass/src/parser.cpp +211 -381
  75. data/ext/libsass/src/parser.hpp +17 -15
  76. data/ext/libsass/src/parser_selectors.cpp +189 -0
  77. data/ext/libsass/src/permutate.hpp +140 -0
  78. data/ext/libsass/src/position.hpp +1 -1
  79. data/ext/libsass/src/prelexer.cpp +6 -6
  80. data/ext/libsass/src/remove_placeholders.cpp +55 -56
  81. data/ext/libsass/src/remove_placeholders.hpp +21 -18
  82. data/ext/libsass/src/sass.hpp +1 -0
  83. data/ext/libsass/src/sass2scss.cpp +4 -4
  84. data/ext/libsass/src/sass_context.cpp +42 -91
  85. data/ext/libsass/src/sass_context.hpp +2 -2
  86. data/ext/libsass/src/sass_functions.cpp +1 -1
  87. data/ext/libsass/src/sass_values.cpp +0 -1
  88. data/ext/libsass/src/stylesheet.cpp +22 -0
  89. data/ext/libsass/src/stylesheet.hpp +57 -0
  90. data/ext/libsass/src/to_value.cpp +2 -2
  91. data/ext/libsass/src/to_value.hpp +1 -1
  92. data/ext/libsass/src/units.cpp +5 -3
  93. data/ext/libsass/src/util.cpp +10 -12
  94. data/ext/libsass/src/util.hpp +2 -3
  95. data/ext/libsass/src/util_string.cpp +111 -61
  96. data/ext/libsass/src/util_string.hpp +61 -8
  97. data/lib/sassc/engine.rb +5 -3
  98. data/lib/sassc/functions_handler.rb +8 -8
  99. data/lib/sassc/native.rb +1 -1
  100. data/lib/sassc/script.rb +4 -4
  101. data/lib/sassc/version.rb +1 -1
  102. data/test/functions_test.rb +18 -1
  103. data/test/native_test.rb +1 -1
  104. metadata +17 -12
  105. data/ext/libsass/src/extend.cpp +0 -2132
  106. data/ext/libsass/src/extend.hpp +0 -86
  107. data/ext/libsass/src/node.cpp +0 -322
  108. data/ext/libsass/src/node.hpp +0 -118
  109. data/ext/libsass/src/paths.hpp +0 -71
  110. data/ext/libsass/src/sass_util.cpp +0 -152
  111. data/ext/libsass/src/sass_util.hpp +0 -256
  112. data/ext/libsass/src/subset_map.cpp +0 -58
  113. data/ext/libsass/src/subset_map.hpp +0 -76
@@ -1,9 +1,14 @@
1
1
  #ifndef SASS_OPERATION_H
2
2
  #define SASS_OPERATION_H
3
3
 
4
+ // sass.hpp must go before all system headers to get the
5
+ // __EXTENSIONS__ fix on Solaris.
6
+ #include "sass.hpp"
7
+
4
8
  // base classes to implement curiously recurring template pattern (CRTP)
5
9
  // https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
6
10
 
11
+ #include <typeinfo>
7
12
  #include <stdexcept>
8
13
 
9
14
  #include "ast_fwd_decl.hpp"
@@ -47,7 +52,9 @@ namespace Sass {
47
52
  virtual T operator()(Bubble* x) = 0;
48
53
  virtual T operator()(Trace* x) = 0;
49
54
  virtual T operator()(Supports_Block* x) = 0;
50
- virtual T operator()(Media_Block* x) = 0;
55
+ virtual T operator()(MediaRule* x) = 0;
56
+ virtual T operator()(CssMediaRule* x) = 0;
57
+ virtual T operator()(CssMediaQuery* x) = 0;
51
58
  virtual T operator()(At_Root_Block* x) = 0;
52
59
  virtual T operator()(Directive* x) = 0;
53
60
  virtual T operator()(Keyframe_Rule* x) = 0;
@@ -65,7 +72,7 @@ namespace Sass {
65
72
  virtual T operator()(While* x) = 0;
66
73
  virtual T operator()(Return* x) = 0;
67
74
  virtual T operator()(Content* x) = 0;
68
- virtual T operator()(Extension* x) = 0;
75
+ virtual T operator()(ExtendRule* x) = 0;
69
76
  virtual T operator()(Definition* x) = 0;
70
77
  virtual T operator()(Mixin_Call* x) = 0;
71
78
  // expressions
@@ -92,10 +99,9 @@ namespace Sass {
92
99
  virtual T operator()(Supports_Negation* x) = 0;
93
100
  virtual T operator()(Supports_Declaration* x) = 0;
94
101
  virtual T operator()(Supports_Interpolation* x) = 0;
95
- virtual T operator()(Media_Query* x) = 0;
102
+ virtual T operator()(Media_Query* x) = 0;
96
103
  virtual T operator()(Media_Query_Expression* x) = 0;
97
104
  virtual T operator()(At_Root_Query* x) = 0;
98
- virtual T operator()(Parent_Selector* x) = 0;
99
105
  virtual T operator()(Parent_Reference* x) = 0;
100
106
  // parameters and arguments
101
107
  virtual T operator()(Parameter* x) = 0;
@@ -110,16 +116,18 @@ namespace Sass {
110
116
  virtual T operator()(Id_Selector* x) = 0;
111
117
  virtual T operator()(Attribute_Selector* x) = 0;
112
118
  virtual T operator()(Pseudo_Selector* x) = 0;
113
- virtual T operator()(Wrapped_Selector* x) = 0;
114
- virtual T operator()(Compound_Selector* x)= 0;
115
- virtual T operator()(Complex_Selector* x) = 0;
116
- virtual T operator()(Selector_List* x) = 0;
119
+ virtual T operator()(SelectorComponent* x) = 0;
120
+ virtual T operator()(SelectorCombinator* x) = 0;
121
+ virtual T operator()(CompoundSelector* x) = 0;
122
+ virtual T operator()(ComplexSelector* x) = 0;
123
+ virtual T operator()(SelectorList* x) = 0;
124
+
117
125
  };
118
126
 
119
127
  // example: Operation_CRTP<Expression*, Eval>
120
128
  // T is the base return type of all visitors
121
129
  // D is the class derived visitor class
122
- // normaly you want to implement all operators
130
+ // normally you want to implement all operators
123
131
  template <typename T, typename D>
124
132
  class Operation_CRTP : public Operation<T> {
125
133
  public:
@@ -130,7 +138,9 @@ namespace Sass {
130
138
  T operator()(Bubble* x) { return static_cast<D*>(this)->fallback(x); }
131
139
  T operator()(Trace* x) { return static_cast<D*>(this)->fallback(x); }
132
140
  T operator()(Supports_Block* x) { return static_cast<D*>(this)->fallback(x); }
133
- T operator()(Media_Block* x) { return static_cast<D*>(this)->fallback(x); }
141
+ T operator()(MediaRule* x) { return static_cast<D*>(this)->fallback(x); }
142
+ T operator()(CssMediaRule* x) { return static_cast<D*>(this)->fallback(x); }
143
+ T operator()(CssMediaQuery* x) { return static_cast<D*>(this)->fallback(x); }
134
144
  T operator()(At_Root_Block* x) { return static_cast<D*>(this)->fallback(x); }
135
145
  T operator()(Directive* x) { return static_cast<D*>(this)->fallback(x); }
136
146
  T operator()(Keyframe_Rule* x) { return static_cast<D*>(this)->fallback(x); }
@@ -148,7 +158,7 @@ namespace Sass {
148
158
  T operator()(While* x) { return static_cast<D*>(this)->fallback(x); }
149
159
  T operator()(Return* x) { return static_cast<D*>(this)->fallback(x); }
150
160
  T operator()(Content* x) { return static_cast<D*>(this)->fallback(x); }
151
- T operator()(Extension* x) { return static_cast<D*>(this)->fallback(x); }
161
+ T operator()(ExtendRule* x) { return static_cast<D*>(this)->fallback(x); }
152
162
  T operator()(Definition* x) { return static_cast<D*>(this)->fallback(x); }
153
163
  T operator()(Mixin_Call* x) { return static_cast<D*>(this)->fallback(x); }
154
164
  // expressions
@@ -178,7 +188,6 @@ namespace Sass {
178
188
  T operator()(Media_Query* x) { return static_cast<D*>(this)->fallback(x); }
179
189
  T operator()(Media_Query_Expression* x) { return static_cast<D*>(this)->fallback(x); }
180
190
  T operator()(At_Root_Query* x) { return static_cast<D*>(this)->fallback(x); }
181
- T operator()(Parent_Selector* x) { return static_cast<D*>(this)->fallback(x); }
182
191
  T operator()(Parent_Reference* x) { return static_cast<D*>(this)->fallback(x); }
183
192
  // parameters and arguments
184
193
  T operator()(Parameter* x) { return static_cast<D*>(this)->fallback(x); }
@@ -193,14 +202,15 @@ namespace Sass {
193
202
  T operator()(Id_Selector* x) { return static_cast<D*>(this)->fallback(x); }
194
203
  T operator()(Attribute_Selector* x) { return static_cast<D*>(this)->fallback(x); }
195
204
  T operator()(Pseudo_Selector* x) { return static_cast<D*>(this)->fallback(x); }
196
- T operator()(Wrapped_Selector* x) { return static_cast<D*>(this)->fallback(x); }
197
- T operator()(Compound_Selector* x){ return static_cast<D*>(this)->fallback(x); }
198
- T operator()(Complex_Selector* x) { return static_cast<D*>(this)->fallback(x); }
199
- T operator()(Selector_List* x) { return static_cast<D*>(this)->fallback(x); }
205
+ T operator()(SelectorComponent* x) { return static_cast<D*>(this)->fallback(x); }
206
+ T operator()(SelectorCombinator* x) { return static_cast<D*>(this)->fallback(x); }
207
+ T operator()(CompoundSelector* x) { return static_cast<D*>(this)->fallback(x); }
208
+ T operator()(ComplexSelector* x) { return static_cast<D*>(this)->fallback(x); }
209
+ T operator()(SelectorList* x) { return static_cast<D*>(this)->fallback(x); }
200
210
 
201
211
  // fallback with specific type U
202
212
  // will be called if not overloaded
203
- template <typename U> T fallback(U x)
213
+ template <typename U> inline T fallback(U x)
204
214
  {
205
215
  throw std::runtime_error(
206
216
  std::string(typeid(*this).name()) + ": CRTP not implemented for " + typeid(x).name());
@@ -2,6 +2,7 @@
2
2
  // __EXTENSIONS__ fix on Solaris.
3
3
  #include "sass.hpp"
4
4
 
5
+ #include <cmath>
5
6
  #include "operators.hpp"
6
7
 
7
8
  namespace Sass {
@@ -0,0 +1,112 @@
1
+ #ifndef SASS_ORDERED_MAP_H
2
+ #define SASS_ORDERED_MAP_H
3
+
4
+ namespace Sass {
5
+
6
+ // ##########################################################################
7
+ // Very simple and limited container for insert ordered hash map.
8
+ // Piggy-back implementation on std::unordered_map and std::vector
9
+ // ##########################################################################
10
+ template<
11
+ class Key,
12
+ class T,
13
+ class Hash = std::hash<Key>,
14
+ class KeyEqual = std::equal_to<Key>,
15
+ class Allocator = std::allocator<std::pair<const Key, T>>
16
+ >
17
+ class ordered_map {
18
+
19
+ private:
20
+
21
+ using map_type = typename std::unordered_map< Key, T, Hash, KeyEqual, Allocator>;
22
+ using map_iterator = typename std::unordered_map< Key, T, Hash, KeyEqual, Allocator>::iterator;
23
+ using map_const_iterator = typename std::unordered_map< Key, T, Hash, KeyEqual, Allocator>::const_iterator;
24
+
25
+ // The main unordered map
26
+ map_type _map;
27
+
28
+ // Keep insertion order
29
+ std::vector<Key> _keys;
30
+ std::vector<T> _values;
31
+
32
+ const KeyEqual _keyEqual;
33
+
34
+ public:
35
+
36
+ ordered_map() :
37
+ _keyEqual(KeyEqual())
38
+ {
39
+ }
40
+
41
+ ordered_map& operator= (const ordered_map& other) {
42
+ _map = other._map;
43
+ _keys = other._keys;
44
+ _values = other._values;
45
+ return *this;
46
+ }
47
+
48
+ std::pair<Key, T> front() {
49
+ return std::make_pair(
50
+ _keys.front(),
51
+ _values.front()
52
+ );
53
+ }
54
+
55
+ bool empty() const {
56
+ return _keys.empty();
57
+ }
58
+
59
+ void insert(const Key& key, const T& val) {
60
+ if (!hasKey(key)) {
61
+ _values.push_back(val);
62
+ _keys.push_back(key);
63
+ }
64
+ _map[key] = val;
65
+ }
66
+
67
+ bool hasKey(const Key& key) const {
68
+ return _map.find(key) != _map.end();
69
+ }
70
+
71
+ bool erase(const Key& key) {
72
+ _map.erase(key);
73
+ // find the position in the array
74
+ for (size_t i = 0; i < _keys.size(); i += 1) {
75
+ if (_keyEqual(key, _keys[i])) {
76
+ _keys.erase(_keys.begin() + i);
77
+ _values.erase(_values.begin() + i);
78
+ return true;
79
+ }
80
+ }
81
+ return false;
82
+ }
83
+
84
+ const std::vector<Key>& keys() const { return _keys; }
85
+ const std::vector<T>& values() const { return _values; }
86
+
87
+ const T& get(const Key& key) {
88
+ if (hasKey(key)) {
89
+ return _map[key];
90
+ }
91
+ throw std::runtime_error("Key does not exist");
92
+ }
93
+
94
+ using iterator = typename std::vector<Key>::iterator;
95
+ using const_iterator = typename std::vector<Key>::const_iterator;
96
+ using reverse_iterator = typename std::vector<Key>::reverse_iterator;
97
+ using const_reverse_iterator = typename std::vector<Key>::const_reverse_iterator;
98
+
99
+ typename std::vector<Key>::iterator end() { return _keys.end(); }
100
+ typename std::vector<Key>::iterator begin() { return _keys.begin(); }
101
+ typename std::vector<Key>::reverse_iterator rend() { return _keys.rend(); }
102
+ typename std::vector<Key>::reverse_iterator rbegin() { return _keys.rbegin(); }
103
+ typename std::vector<Key>::const_iterator end() const { return _keys.end(); }
104
+ typename std::vector<Key>::const_iterator begin() const { return _keys.begin(); }
105
+ typename std::vector<Key>::const_reverse_iterator rend() const { return _keys.rend(); }
106
+ typename std::vector<Key>::const_reverse_iterator rbegin() const { return _keys.rbegin(); }
107
+
108
+ };
109
+
110
+ }
111
+
112
+ #endif
@@ -113,13 +113,15 @@ namespace Sass {
113
113
 
114
114
  void Output::operator()(Ruleset* r)
115
115
  {
116
- Selector_Obj s = r->selector();
117
- Block_Obj b = r->block();
116
+ Block_Obj b = r->block();
117
+ SelectorListObj s = r->selector();
118
+
119
+ if (!s || s->empty()) return;
118
120
 
119
121
  // Filter out rulesets that aren't printable (process its children though)
120
122
  if (!Util::isPrintable(r, output_style())) {
121
123
  for (size_t i = 0, L = b->length(); i < L; ++i) {
122
- const Statement_Obj& stm = b->at(i);
124
+ const Statement_Obj& stm = b->get(i);
123
125
  if (Cast<Has_Block>(stm)) {
124
126
  if (!Cast<Declaration>(stm)) {
125
127
  stm->perform(this);
@@ -129,7 +131,9 @@ namespace Sass {
129
131
  return;
130
132
  }
131
133
 
132
- if (output_style() == NESTED) indentation += r->tabs();
134
+ if (output_style() == NESTED) {
135
+ indentation += r->tabs();
136
+ }
133
137
  if (opt.source_comments) {
134
138
  std::stringstream ss;
135
139
  append_indentation();
@@ -142,13 +146,13 @@ namespace Sass {
142
146
  if (s) s->perform(this);
143
147
  append_scope_opener(b);
144
148
  for (size_t i = 0, L = b->length(); i < L; ++i) {
145
- Statement_Obj stm = b->at(i);
149
+ Statement_Obj stm = b->get(i);
146
150
  bool bPrintExpression = true;
147
151
  // Check print conditions
148
152
  if (Declaration* dec = Cast<Declaration>(stm)) {
149
- if (String_Constant* valConst = Cast<String_Constant>(dec->value())) {
150
- std::string val(valConst->value());
151
- if (String_Quoted* qstr = Cast<String_Quoted>(valConst)) {
153
+ if (const String_Constant* valConst = Cast<String_Constant>(dec->value())) {
154
+ const std::string& val = valConst->value();
155
+ if (const String_Quoted* qstr = Cast<const String_Quoted>(valConst)) {
152
156
  if (!qstr->quote_mark() && val.empty()) {
153
157
  bPrintExpression = false;
154
158
  }
@@ -157,7 +161,7 @@ namespace Sass {
157
161
  else if (List* list = Cast<List>(dec->value())) {
158
162
  bool all_invisible = true;
159
163
  for (size_t list_i = 0, list_L = list->length(); list_i < list_L; ++list_i) {
160
- Expression* item = list->at(list_i);
164
+ Expression* item = list->get(list_i);
161
165
  if (!item->is_invisible()) all_invisible = false;
162
166
  }
163
167
  if (all_invisible && !list->is_bracketed()) bPrintExpression = false;
@@ -188,7 +192,7 @@ namespace Sass {
188
192
 
189
193
  append_scope_opener();
190
194
  for (size_t i = 0, L = b->length(); i < L; ++i) {
191
- Statement_Obj stm = b->at(i);
195
+ Statement_Obj stm = b->get(i);
192
196
  stm->perform(this);
193
197
  if (i < L - 1) append_special_linefeed();
194
198
  }
@@ -205,7 +209,7 @@ namespace Sass {
205
209
  // Filter out feature blocks that aren't printable (process its children though)
206
210
  if (!Util::isPrintable(f, output_style())) {
207
211
  for (size_t i = 0, L = b->length(); i < L; ++i) {
208
- Statement_Obj stm = b->at(i);
212
+ Statement_Obj stm = b->get(i);
209
213
  if (Cast<Has_Block>(stm)) {
210
214
  stm->perform(this);
211
215
  }
@@ -221,7 +225,7 @@ namespace Sass {
221
225
  append_scope_opener();
222
226
 
223
227
  for (size_t i = 0, L = b->length(); i < L; ++i) {
224
- Statement_Obj stm = b->at(i);
228
+ Statement_Obj stm = b->get(i);
225
229
  stm->perform(this);
226
230
  if (i < L - 1) append_special_linefeed();
227
231
  }
@@ -232,41 +236,21 @@ namespace Sass {
232
236
 
233
237
  }
234
238
 
235
- void Output::operator()(Media_Block* m)
239
+ void Output::operator()(CssMediaRule* rule)
236
240
  {
237
- if (m->is_invisible()) return;
238
-
239
- Block_Obj b = m->block();
240
-
241
- // Filter out media blocks that aren't printable (process its children though)
242
- if (!Util::isPrintable(m, output_style())) {
243
- for (size_t i = 0, L = b->length(); i < L; ++i) {
244
- Statement_Obj stm = b->at(i);
245
- if (Cast<Has_Block>(stm)) {
246
- stm->perform(this);
247
- }
248
- }
249
- return;
241
+ // Avoid null pointer exception
242
+ if (rule == nullptr) return;
243
+ // Skip empty/invisible rule
244
+ if (rule->isInvisible()) return;
245
+ // Avoid null pointer exception
246
+ if (rule->block() == nullptr) return;
247
+ // Skip empty/invisible rule
248
+ if (rule->block()->isInvisible()) return;
249
+ // Skip if block is empty/invisible
250
+ if (Util::isPrintable(rule, output_style())) {
251
+ // Let inspect do its magic
252
+ Inspect::operator()(rule);
250
253
  }
251
- if (output_style() == NESTED) indentation += m->tabs();
252
- append_indentation();
253
- append_token("@media", m);
254
- append_mandatory_space();
255
- in_media_block = true;
256
- m->media_queries()->perform(this);
257
- in_media_block = false;
258
- append_scope_opener();
259
-
260
- for (size_t i = 0, L = b->length(); i < L; ++i) {
261
- if (b->at(i)) {
262
- Statement_Obj stm = b->at(i);
263
- stm->perform(this);
264
- }
265
- if (i < L - 1) append_special_linefeed();
266
- }
267
-
268
- if (output_style() == NESTED) indentation -= m->tabs();
269
- append_scope_closer();
270
254
  }
271
255
 
272
256
  void Output::operator()(Directive* a)
@@ -304,7 +288,7 @@ namespace Sass {
304
288
  bool format = kwd != "@font-face";;
305
289
 
306
290
  for (size_t i = 0, L = b->length(); i < L; ++i) {
307
- Statement_Obj stm = b->at(i);
291
+ Statement_Obj stm = b->get(i);
308
292
  stm->perform(this);
309
293
  if (i < L - 1 && format) append_special_linefeed();
310
294
  }
@@ -326,9 +310,6 @@ namespace Sass {
326
310
  void Output::operator()(String_Constant* s)
327
311
  {
328
312
  std::string value(s->value());
329
- if (s->can_compress_whitespace() && output_style() == COMPRESSED) {
330
- value.erase(std::remove_if(value.begin(), value.end(), ::isspace), value.end());
331
- }
332
313
  if (!in_comment && !in_custom_property) {
333
314
  append_token(string_to_output(value), s);
334
315
  } else {
@@ -29,7 +29,7 @@ namespace Sass {
29
29
  virtual void operator()(Map*);
30
30
  virtual void operator()(Ruleset*);
31
31
  virtual void operator()(Supports_Block*);
32
- virtual void operator()(Media_Block*);
32
+ virtual void operator()(CssMediaRule*);
33
33
  virtual void operator()(Directive*);
34
34
  virtual void operator()(Keyframe_Rule*);
35
35
  virtual void operator()(Import*);
@@ -3,14 +3,7 @@
3
3
  #include "sass.hpp"
4
4
 
5
5
  #include "parser.hpp"
6
- #include "file.hpp"
7
- #include "inspect.hpp"
8
- #include "constants.hpp"
9
- #include "util.hpp"
10
- #include "prelexer.hpp"
11
6
  #include "color_maps.hpp"
12
- #include "sass/functions.h"
13
- #include "error_handling.hpp"
14
7
  #include "util_string.hpp"
15
8
 
16
9
  // Notes about delayed: some ast nodes can have delayed evaluation so
@@ -25,10 +18,6 @@
25
18
  // Another case with delayed values are colors. In compressed mode
26
19
  // only processed values get compressed (other are left as written).
27
20
 
28
- #include <cstdlib>
29
- #include <iostream>
30
- #include <vector>
31
- #include <typeinfo>
32
21
 
33
22
  namespace Sass {
34
23
  using namespace Constants;
@@ -70,11 +59,11 @@ namespace Sass {
70
59
  pstate.offset.line = 0;
71
60
  }
72
61
 
73
- Selector_List_Obj Parser::parse_selector(const char* beg, Context& ctx, Backtraces traces, ParserState pstate, const char* source, bool allow_parent)
62
+ SelectorListObj Parser::parse_selector(const char* beg, Context& ctx, Backtraces traces, ParserState pstate, const char* source, bool allow_parent)
74
63
  {
75
64
  Parser p = Parser::from_c_str(beg, ctx, traces, pstate, source, allow_parent);
76
65
  // ToDo: remap the source-map entries somehow
77
- return p.parse_selector_list(false);
66
+ return p.parseSelectorList(false);
78
67
  }
79
68
 
80
69
  bool Parser::peek_newline(const char* start)
@@ -261,16 +250,23 @@ namespace Sass {
261
250
  else if (lex < kwd_extend >(true)) {
262
251
  Lookahead lookahead = lookahead_for_include(position);
263
252
  if (!lookahead.found) css_error("Invalid CSS", " after ", ": expected selector, was ");
264
- Selector_List_Obj target;
253
+ SelectorListObj target;
265
254
  if (!lookahead.has_interpolants) {
266
- target = parse_selector_list(true);
255
+ LOCAL_FLAG(allow_parent, false);
256
+ auto selector = parseSelectorList(true);
257
+ auto extender = SASS_MEMORY_NEW(ExtendRule, pstate, selector);
258
+ extender->isOptional(selector && selector->is_optional());
259
+ block->append(extender);
267
260
  }
268
261
  else {
269
- target = SASS_MEMORY_NEW(Selector_List, pstate);
270
- target->schema(parse_selector_schema(lookahead.found, true));
262
+ LOCAL_FLAG(allow_parent, false);
263
+ auto selector = parse_selector_schema(lookahead.found, true);
264
+ auto extender = SASS_MEMORY_NEW(ExtendRule, pstate, selector);
265
+ // A schema is not optional yet, check once it is evaluated
266
+ // extender->isOptional(selector && selector->is_optional());
267
+ block->append(extender);
271
268
  }
272
269
 
273
- block->append(SASS_MEMORY_NEW(Extension, pstate, target));
274
270
  }
275
271
 
276
272
  // selector may contain interpolations which need delayed evaluation
@@ -283,7 +279,7 @@ namespace Sass {
283
279
  }
284
280
 
285
281
  // parse multiple specific keyword directives
286
- else if (lex < kwd_media >(true)) { block->append(parse_media_block()); }
282
+ else if (lex < kwd_media >(true)) { block->append(parseMediaRule()); }
287
283
  else if (lex < kwd_at_root >(true)) { block->append(parse_at_root_block()); }
288
284
  else if (lex < kwd_include_directive >(true)) { block->append(parse_include_directive()); }
289
285
  else if (lex < kwd_content_directive >(true)) { block->append(parse_content_directive()); }
@@ -294,9 +290,9 @@ namespace Sass {
294
290
  // ignore the @charset directive for now
295
291
  else if (lex< kwd_charset_directive >(true)) { parse_charset_directive(); }
296
292
 
293
+ else if (lex < exactly < else_kwd >>(true)) { error("Invalid CSS: @else must come after @if"); }
294
+
297
295
  // generic at keyword (keep last)
298
- else if (lex< re_special_directive >(true)) { block->append(parse_special_directive()); }
299
- else if (lex< re_prefixed_directive >(true)) { block->append(parse_prefixed_directive()); }
300
296
  else if (lex< at_keyword >(true)) { block->append(parse_directive()); }
301
297
 
302
298
  else if (is_root && stack.back() != Scope::AtRoot /* && block->is_root() */) {
@@ -530,10 +526,13 @@ namespace Sass {
530
526
  // create the connector object (add parts later)
531
527
  Ruleset_Obj ruleset = SASS_MEMORY_NEW(Ruleset, pstate);
532
528
  // parse selector static or as schema to be evaluated later
533
- if (lookahead.parsable) ruleset->selector(parse_selector_list(false));
529
+ if (lookahead.parsable) {
530
+ ruleset->selector(parseSelectorList(false));
531
+ }
534
532
  else {
535
- Selector_List_Obj list = SASS_MEMORY_NEW(Selector_List, pstate);
536
- list->schema(parse_selector_schema(lookahead.position, false));
533
+ SelectorListObj list = SASS_MEMORY_NEW(SelectorList, pstate);
534
+ auto sc = parse_selector_schema(lookahead.position, false);
535
+ ruleset->schema(sc);
537
536
  ruleset->selector(list);
538
537
  }
539
538
  // then parse the inner block
@@ -563,11 +562,10 @@ namespace Sass {
563
562
  // the selector schema is pretty much just a wrapper for the string schema
564
563
  Selector_Schema_Obj selector_schema = SASS_MEMORY_NEW(Selector_Schema, pstate, schema);
565
564
  selector_schema->connect_parent(chroot == false);
566
- selector_schema->media_block(last_media_block);
567
565
 
568
566
  // process until end
569
567
  while (i < end_of_selector) {
570
- // try to parse mutliple interpolants
568
+ // try to parse multiple interpolants
571
569
  if (const char* p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, end_of_selector)) {
572
570
  // accumulate the preceding segment if the position has advanced
573
571
  if (i < p) {
@@ -674,213 +672,8 @@ namespace Sass {
674
672
  }
675
673
  // EO parse_include_directive
676
674
 
677
- // parse a list of complex selectors
678
- // this is the main entry point for most
679
- Selector_List_Obj Parser::parse_selector_list(bool chroot)
680
- {
681
- bool reloop;
682
- bool had_linefeed = false;
683
- NESTING_GUARD(nestings);
684
- Complex_Selector_Obj sel;
685
- Selector_List_Obj group = SASS_MEMORY_NEW(Selector_List, pstate);
686
- group->media_block(last_media_block);
687
-
688
- if (peek_css< alternatives < end_of_file, exactly <'{'>, exactly <','> > >()) {
689
- css_error("Invalid CSS", " after ", ": expected selector, was ");
690
- }
691
-
692
- do {
693
- reloop = false;
694
-
695
- had_linefeed = had_linefeed || peek_newline();
696
-
697
- if (peek_css< alternatives < class_char < selector_list_delims > > >())
698
- break; // in case there are superfluous commas at the end
699
-
700
- // now parse the complex selector
701
- sel = parse_complex_selector(chroot);
702
-
703
- if (!sel) return group.detach();
704
-
705
- sel->has_line_feed(had_linefeed);
706
-
707
- had_linefeed = false;
708
-
709
- while (peek_css< exactly<','> >())
710
- {
711
- lex< css_comments >(false);
712
- // consume everything up and including the comma separator
713
- reloop = lex< exactly<','> >() != 0;
714
- // remember line break (also between some commas)
715
- had_linefeed = had_linefeed || peek_newline();
716
- // remember line break (also between some commas)
717
- }
718
- group->append(sel);
719
- }
720
- while (reloop);
721
- while (lex_css< kwd_optional >()) {
722
- group->is_optional(true);
723
- }
724
- // update for end position
725
- group->update_pstate(pstate);
726
- if (sel) sel->mutable_last()->has_line_break(false);
727
- return group.detach();
728
- }
729
- // EO parse_selector_list
730
675
 
731
- // a complex selector combines a compound selector with another
732
- // complex selector, with one of four combinator operations.
733
- // the compound selector (head) is optional, since the combinator
734
- // can come first in the whole selector sequence (like `> DIV').
735
- Complex_Selector_Obj Parser::parse_complex_selector(bool chroot)
736
- {
737
-
738
- NESTING_GUARD(nestings);
739
- String_Obj reference;
740
- lex < block_comment >();
741
- advanceToNextToken();
742
- Complex_Selector_Obj sel = SASS_MEMORY_NEW(Complex_Selector, pstate);
743
-
744
- if (peek < end_of_file >()) return {};
745
-
746
- // parse the left hand side
747
- Compound_Selector_Obj lhs;
748
- // special case if it starts with combinator ([+~>])
749
- if (!peek_css< class_char < selector_combinator_ops > >()) {
750
- // parse the left hand side
751
- lhs = parse_compound_selector();
752
- }
753
-
754
-
755
- // parse combinator between lhs and rhs
756
- Complex_Selector::Combinator combinator = Complex_Selector::ANCESTOR_OF;
757
- if (lex< exactly<'+'> >()) combinator = Complex_Selector::ADJACENT_TO;
758
- else if (lex< exactly<'~'> >()) combinator = Complex_Selector::PRECEDES;
759
- else if (lex< exactly<'>'> >()) combinator = Complex_Selector::PARENT_OF;
760
- else if (lex< sequence < exactly<'/'>, negate < exactly < '*' > > > >()) {
761
- // comments are allowed, but not spaces?
762
- combinator = Complex_Selector::REFERENCE;
763
- if (!lex < re_reference_combinator >()) return {};
764
- reference = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
765
- if (!lex < exactly < '/' > >()) return {}; // ToDo: error msg?
766
- }
767
-
768
- if (!lhs && combinator == Complex_Selector::ANCESTOR_OF) return {};
769
-
770
- // lex < block_comment >();
771
- sel->head(lhs);
772
- sel->combinator(combinator);
773
- sel->media_block(last_media_block);
774
-
775
- if (combinator == Complex_Selector::REFERENCE) sel->reference(reference);
776
- // has linfeed after combinator?
777
- sel->has_line_break(peek_newline());
778
- // sel->has_line_feed(has_line_feed);
779
-
780
- // check if we got the abort condition (ToDo: optimize)
781
- if (!peek_css< class_char < complex_selector_delims > >()) {
782
- // parse next selector in sequence
783
- sel->tail(parse_complex_selector(true));
784
- }
785
-
786
- // add a parent selector if we are not in a root
787
- // also skip adding parent ref if we only have refs
788
- if (!sel->has_parent_ref() && !chroot) {
789
- // create the objects to wrap parent selector reference
790
- Compound_Selector_Obj head = SASS_MEMORY_NEW(Compound_Selector, pstate);
791
- Parent_Selector* parent = SASS_MEMORY_NEW(Parent_Selector, pstate, false);
792
- parent->media_block(last_media_block);
793
- head->media_block(last_media_block);
794
- // add simple selector
795
- head->append(parent);
796
- // selector may not have any head yet
797
- if (!sel->head()) { sel->head(head); }
798
- // otherwise we need to create a new complex selector and set the old one as its tail
799
- else {
800
- sel = SASS_MEMORY_NEW(Complex_Selector, pstate, Complex_Selector::ANCESTOR_OF, head, sel);
801
- sel->media_block(last_media_block);
802
- }
803
- // peek for linefeed and remember result on head
804
- // if (peek_newline()) head->has_line_break(true);
805
- }
806
-
807
- sel->update_pstate(pstate);
808
- // complex selector
809
- return sel;
810
- }
811
- // EO parse_complex_selector
812
-
813
- // parse one compound selector, which is basically
814
- // a list of simple selectors (directly adjacent)
815
- // lex them exactly (without skipping white-space)
816
- Compound_Selector_Obj Parser::parse_compound_selector()
817
- {
818
- // init an empty compound selector wrapper
819
- Compound_Selector_Obj seq = SASS_MEMORY_NEW(Compound_Selector, pstate);
820
- seq->media_block(last_media_block);
821
-
822
- // skip initial white-space
823
- lex< css_whitespace >();
824
-
825
- // parse list
826
- while (true)
827
- {
828
- // remove all block comments (don't skip white-space)
829
- lex< delimited_by< slash_star, star_slash, false > >(false);
830
- // parse functional
831
- if (match < re_pseudo_selector >())
832
- {
833
- seq->append(parse_simple_selector());
834
- }
835
- // parse parent selector
836
- else if (lex< exactly<'&'> >(false))
837
- {
838
- if (!allow_parent) error("Parent selectors aren't allowed here.");
839
- // this produces a linefeed!?
840
- seq->has_parent_reference(true);
841
- seq->append(SASS_MEMORY_NEW(Parent_Selector, pstate));
842
- // parent selector only allowed at start
843
- // upcoming Sass may allow also trailing
844
- if (seq->length() > 1) {
845
- ParserState state(pstate);
846
- Simple_Selector_Obj cur = (*seq)[seq->length()-1];
847
- Simple_Selector_Obj prev = (*seq)[seq->length()-2];
848
- std::string sel(prev->to_string({ NESTED, 5 }));
849
- std::string found(cur->to_string({ NESTED, 5 }));
850
- if (lex < identifier >()) { found += std::string(lexed); }
851
- error("Invalid CSS after \"" + sel + "\": expected \"{\", was \"" + found + "\"\n\n"
852
- "\"" + found + "\" may only be used at the beginning of a compound selector.", state);
853
- }
854
- }
855
- // parse type selector
856
- else if (lex< re_type_selector >(false))
857
- {
858
- seq->append(SASS_MEMORY_NEW(Type_Selector, pstate, lexed));
859
- }
860
- // peek for abort conditions
861
- else if (peek< spaces >()) break;
862
- else if (peek< end_of_file >()) { break; }
863
- else if (peek_css < class_char < selector_combinator_ops > >()) break;
864
- else if (peek_css < class_char < complex_selector_delims > >()) break;
865
- // otherwise parse another simple selector
866
- else {
867
- Simple_Selector_Obj sel = parse_simple_selector();
868
- if (!sel) return {};
869
- seq->append(sel);
870
- }
871
- }
872
-
873
- if (seq && !peek_css<alternatives<end_of_file,exactly<'{'>>>()) {
874
- seq->has_line_break(peek_newline());
875
- }
876
-
877
- // EO while true
878
- return seq;
879
-
880
- }
881
- // EO parse_compound_selector
882
-
883
- Simple_Selector_Obj Parser::parse_simple_selector()
676
+ SimpleSelectorObj Parser::parse_simple_selector()
884
677
  {
885
678
  lex < css_comments >(false);
886
679
  if (lex< class_name >()) {
@@ -893,7 +686,7 @@ namespace Sass {
893
686
  return SASS_MEMORY_NEW(Type_Selector, pstate, lexed);
894
687
  }
895
688
  else if (peek< pseudo_not >()) {
896
- return parse_negated_selector();
689
+ return parse_negated_selector2();
897
690
  }
898
691
  else if (peek< re_pseudo_selector >()) {
899
692
  return parse_pseudo_selector();
@@ -905,9 +698,7 @@ namespace Sass {
905
698
  return parse_attribute_selector();
906
699
  }
907
700
  else if (lex< placeholder >()) {
908
- Placeholder_Selector* sel = SASS_MEMORY_NEW(Placeholder_Selector, pstate, lexed);
909
- sel->media_block(last_media_block);
910
- return sel;
701
+ return SASS_MEMORY_NEW(Placeholder_Selector, pstate, lexed);
911
702
  }
912
703
  else {
913
704
  css_error("Invalid CSS", " after ", ": expected selector, was ");
@@ -916,71 +707,104 @@ namespace Sass {
916
707
  return {};
917
708
  }
918
709
 
919
- Wrapped_Selector_Obj Parser::parse_negated_selector()
710
+ Pseudo_Selector_Obj Parser::parse_negated_selector2()
920
711
  {
921
712
  lex< pseudo_not >();
922
713
  std::string name(lexed);
923
714
  ParserState nsource_position = pstate;
924
- Selector_List_Obj negated = parse_selector_list(true);
715
+ SelectorListObj negated = parseSelectorList(true);
925
716
  if (!lex< exactly<')'> >()) {
926
717
  error("negated selector is missing ')'");
927
718
  }
928
719
  name.erase(name.size() - 1);
929
- return SASS_MEMORY_NEW(Wrapped_Selector, nsource_position, name, negated);
720
+
721
+ Pseudo_Selector* sel = SASS_MEMORY_NEW(Pseudo_Selector, nsource_position, name.substr(1));
722
+ sel->selector(negated);
723
+ return sel;
930
724
  }
931
725
 
726
+ // Helper to clean binominal string
727
+ bool BothAreSpaces(char lhs, char rhs) { return isspace(lhs) && isspace(rhs); }
728
+
932
729
  // a pseudo selector often starts with one or two colons
933
730
  // it can contain more selectors inside parentheses
934
- Simple_Selector_Obj Parser::parse_pseudo_selector() {
935
- if (lex< sequence<
936
- pseudo_prefix,
937
- // we keep the space within the name, strange enough
938
- // ToDo: refactor output to schedule the space for it
939
- // or do we really want to keep the real white-space?
940
- sequence< identifier, optional < block_comment >, exactly<'('> >
941
- > >())
942
- {
943
-
944
- std::string name(lexed);
945
- name.erase(name.size() - 1);
946
- ParserState p = pstate;
731
+ SimpleSelectorObj Parser::parse_pseudo_selector() {
732
+
733
+ // Lex one or two colon characters
734
+ if (lex<pseudo_prefix>()) {
735
+ std::string colons(lexed);
736
+ // Check if it is a pseudo element
737
+ bool element = colons.size() == 2;
738
+
739
+ if (lex< sequence<
740
+ // we keep the space within the name, strange enough
741
+ // ToDo: refactor output to schedule the space for it
742
+ // or do we really want to keep the real white-space?
743
+ sequence< identifier, optional < block_comment >, exactly<'('> >
744
+ > >())
745
+ {
947
746
 
948
- // specially parse static stuff
949
- // ToDo: really everything static?
950
- if (peek_css <
951
- sequence <
952
- alternatives <
953
- static_value,
954
- binomial
955
- >,
956
- optional_css_whitespace,
957
- exactly<')'>
958
- >
959
- >()
960
- ) {
961
- lex_css< alternatives < static_value, binomial > >();
962
- String_Constant_Obj expr = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
963
- if (lex_css< exactly<')'> >()) {
964
- expr->can_compress_whitespace(true);
965
- return SASS_MEMORY_NEW(Pseudo_Selector, p, name, expr);
747
+ std::string name(lexed);
748
+ name.erase(name.size() - 1);
749
+ ParserState p = pstate;
750
+
751
+ // specially parse nth-child pseudo selectors
752
+ if (lex_css < sequence < binomial, word_boundary >>()) {
753
+ std::string parsed(lexed); // always compacting binominals (as dart-sass)
754
+ parsed.erase(std::unique(parsed.begin(), parsed.end(), BothAreSpaces), parsed.end());
755
+ String_Constant_Obj arg = SASS_MEMORY_NEW(String_Constant, pstate, parsed);
756
+ Pseudo_Selector* pseudo = SASS_MEMORY_NEW(Pseudo_Selector, p, name, element);
757
+ if (lex < sequence < css_whitespace, insensitive < of_kwd >>>(false)) {
758
+ pseudo->selector(parseSelectorList(true));
759
+ }
760
+ pseudo->argument(arg);
761
+ if (lex_css< exactly<')'> >()) {
762
+ return pseudo;
763
+ }
966
764
  }
967
- }
968
- else if (Selector_List_Obj wrapped = parse_selector_list(true)) {
969
- if (wrapped && lex_css< exactly<')'> >()) {
970
- return SASS_MEMORY_NEW(Wrapped_Selector, p, name, wrapped);
765
+ else {
766
+ if (peek_css< exactly<')'>>() && Util::equalsLiteral("nth-", name.substr(0, 4))) {
767
+ css_error("Invalid CSS", " after ", ": expected An+B expression, was ");
768
+ }
769
+
770
+ std::string unvendored = Util::unvendor(name);
771
+
772
+ if (unvendored == "not" || unvendored == "matches" || unvendored == "current" || unvendored == "any" || unvendored == "has" || unvendored == "host" || unvendored == "host-context" || unvendored == "slotted") {
773
+ if (SelectorListObj wrapped = parseSelectorList(true)) {
774
+ if (wrapped && lex_css< exactly<')'> >()) {
775
+ Pseudo_Selector* pseudo = SASS_MEMORY_NEW(Pseudo_Selector, p, name, element);
776
+ pseudo->selector(wrapped);
777
+ return pseudo;
778
+ }
779
+ }
780
+ } else {
781
+ String_Schema_Obj arg = parse_css_variable_value();
782
+ Pseudo_Selector* pseudo = SASS_MEMORY_NEW(Pseudo_Selector, p, name, element);
783
+ pseudo->argument(arg);
784
+
785
+ if (lex_css< exactly<')'> >()) {
786
+ return pseudo;
787
+ }
788
+ }
971
789
  }
790
+
972
791
  }
792
+ // EO if pseudo selector
973
793
 
974
- }
975
- // EO if pseudo selector
794
+ else if (lex < sequence< optional < pseudo_prefix >, identifier > >()) {
795
+ return SASS_MEMORY_NEW(Pseudo_Selector, pstate, lexed, element);
796
+ }
797
+ else if (lex < pseudo_prefix >()) {
798
+ css_error("Invalid CSS", " after ", ": expected pseudoclass or pseudoelement, was ");
799
+ }
976
800
 
977
- else if (lex < sequence< optional < pseudo_prefix >, identifier > >()) {
978
- return SASS_MEMORY_NEW(Pseudo_Selector, pstate, lexed);
979
801
  }
980
- else if(lex < pseudo_prefix >()) {
981
- css_error("Invalid CSS", " after ", ": expected pseudoclass or pseudoelement, was ");
802
+ else {
803
+ lex < identifier >(); // needed for error message?
804
+ css_error("Invalid CSS", " after ", ": expected selector, was ");
982
805
  }
983
806
 
807
+
984
808
  css_error("Invalid CSS", " after ", ": expected \")\", was ");
985
809
 
986
810
  // unreachable statement
@@ -1038,7 +862,7 @@ namespace Sass {
1038
862
  }
1039
863
 
1040
864
  /* parse block comment and add to block */
1041
- void Parser::parse_block_comments()
865
+ void Parser::parse_block_comments(bool store)
1042
866
  {
1043
867
  Block_Obj block = block_stack.back();
1044
868
 
@@ -1046,7 +870,7 @@ namespace Sass {
1046
870
  bool is_important = lexed.begin[2] == '!';
1047
871
  // flag on second param is to skip loosely over comments
1048
872
  String_Obj contents = parse_interpolated_chunk(lexed, true, false);
1049
- block->append(SASS_MEMORY_NEW(Comment, pstate, contents, is_important));
873
+ if (store) block->append(SASS_MEMORY_NEW(Comment, pstate, contents, is_important));
1050
874
  }
1051
875
  }
1052
876
 
@@ -1104,23 +928,6 @@ namespace Sass {
1104
928
  }
1105
929
  }
1106
930
 
1107
- // parse +/- and return false if negative
1108
- // this is never hit via spec tests
1109
- bool Parser::parse_number_prefix()
1110
- {
1111
- bool positive = true;
1112
- while(true) {
1113
- if (lex < block_comment >()) continue;
1114
- if (lex < number_prefix >()) continue;
1115
- if (lex < exactly < '-' > >()) {
1116
- positive = !positive;
1117
- continue;
1118
- }
1119
- break;
1120
- }
1121
- return positive;
1122
- }
1123
-
1124
931
  Expression_Obj Parser::parse_map()
1125
932
  {
1126
933
  NESTING_GUARD(nestings);
@@ -1393,7 +1200,7 @@ namespace Sass {
1393
1200
  Expression_Obj lhs = parse_operators();
1394
1201
  // if it's a singleton, return it (don't wrap it)
1395
1202
  if (!(peek_css< exactly<'+'> >(position) ||
1396
- // condition is a bit misterious, but some combinations should not be counted as operations
1203
+ // condition is a bit mysterious, but some combinations should not be counted as operations
1397
1204
  (peek< no_spaces >(position) && peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< space > > >(position)) ||
1398
1205
  (peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< unsigned_number > > >(position))) ||
1399
1206
  peek< sequence < zero_plus < exactly <'-' > >, identifier > >(position))
@@ -1530,13 +1337,6 @@ namespace Sass {
1530
1337
  if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
1531
1338
  return ex;
1532
1339
  }
1533
- // this whole branch is never hit via spec tests
1534
- else if (peek < sequence < one_plus < alternatives < css_whitespace, exactly<'-'>, exactly<'+'> > >, number > >()) {
1535
- if (parse_number_prefix()) return parse_value(); // prefix is positive
1536
- Unary_Expression* ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::MINUS, parse_value());
1537
- if (ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
1538
- return ex;
1539
- }
1540
1340
  else {
1541
1341
  return parse_value();
1542
1342
  }
@@ -2326,20 +2126,107 @@ namespace Sass {
2326
2126
  return call.detach();
2327
2127
  }
2328
2128
 
2329
- // EO parse_while_directive
2330
- Media_Block_Obj Parser::parse_media_block()
2129
+
2130
+ std::vector<CssMediaQuery_Obj> Parser::parseCssMediaQueries()
2331
2131
  {
2332
- stack.push_back(Scope::Media);
2333
- Media_Block_Obj media_block = SASS_MEMORY_NEW(Media_Block, pstate, {}, {});
2132
+ std::vector<CssMediaQuery_Obj> result;
2133
+ do {
2134
+ if (auto query = parseCssMediaQuery()) {
2135
+ result.push_back(query);
2136
+ }
2137
+ } while (lex<exactly<','>>());
2138
+ return result;
2139
+ }
2140
+
2141
+ std::string Parser::parseIdentifier()
2142
+ {
2143
+ if (lex < identifier >(false)) {
2144
+ return std::string(lexed);
2145
+ }
2146
+ return std::string();
2147
+ }
2334
2148
 
2335
- media_block->media_queries(parse_media_queries());
2149
+ CssMediaQuery_Obj Parser::parseCssMediaQuery()
2150
+ {
2151
+ CssMediaQuery_Obj result = SASS_MEMORY_NEW(CssMediaQuery, pstate);
2152
+ lex<css_comments>(false);
2153
+
2154
+ // Check if any tokens are to parse
2155
+ if (!peek_css<exactly<'('>>()) {
2156
+
2157
+ std::string token1(parseIdentifier());
2158
+ lex<css_comments>(false);
2159
+
2160
+ if (token1.empty()) {
2161
+ return {};
2162
+ }
2336
2163
 
2337
- Media_Block_Obj prev_media_block = last_media_block;
2338
- last_media_block = media_block;
2339
- media_block->block(parse_css_block());
2340
- last_media_block = prev_media_block;
2164
+ std::string token2(parseIdentifier());
2165
+ lex<css_comments>(false);
2166
+
2167
+ if (Util::equalsLiteral("and", token2)) {
2168
+ result->type(token1);
2169
+ }
2170
+ else {
2171
+ if (token2.empty()) {
2172
+ result->type(token1);
2173
+ }
2174
+ else {
2175
+ result->modifier(token1);
2176
+ result->type(token2);
2177
+ }
2178
+
2179
+ if (lex < kwd_and >()) {
2180
+ lex<css_comments>(false);
2181
+ }
2182
+ else {
2183
+ return result;
2184
+ }
2185
+
2186
+ }
2187
+
2188
+ }
2189
+
2190
+ std::vector<std::string> queries;
2191
+
2192
+ do {
2193
+ lex<css_comments>(false);
2194
+
2195
+ if (lex<exactly<'('>>()) {
2196
+ // In dart sass parser returns a pure string
2197
+ if (lex < skip_over_scopes < exactly < '(' >, exactly < ')' > > >()) {
2198
+ std::string decl("(" + std::string(lexed));
2199
+ queries.push_back(decl);
2200
+ }
2201
+ // Should be: parseDeclarationValue;
2202
+ if (!lex<exactly<')'>>()) {
2203
+ // Should we throw an error here?
2204
+ }
2205
+ }
2206
+ } while (lex < kwd_and >());
2207
+
2208
+ result->features(queries);
2209
+
2210
+ if (result->features().empty()) {
2211
+ if (result->type().empty()) {
2212
+ return {};
2213
+ }
2214
+ }
2215
+
2216
+ return result;
2217
+ }
2218
+
2219
+
2220
+ // EO parse_while_directive
2221
+ MediaRule_Obj Parser::parseMediaRule()
2222
+ {
2223
+ MediaRule_Obj rule = SASS_MEMORY_NEW(MediaRule, pstate);
2224
+ stack.push_back(Scope::Media);
2225
+ rule->schema(parse_media_queries());
2226
+ parse_block_comments(false);
2227
+ rule->block(parse_css_block());
2341
2228
  stack.pop_back();
2342
- return media_block.detach();
2229
+ return rule;
2343
2230
  }
2344
2231
 
2345
2232
  List_Obj Parser::parse_media_queries()
@@ -2558,68 +2445,6 @@ namespace Sass {
2558
2445
  return cond;
2559
2446
  }
2560
2447
 
2561
- Directive_Obj Parser::parse_special_directive()
2562
- {
2563
- std::string kwd(lexed);
2564
-
2565
- if (lexed == "@else") error("Invalid CSS: @else must come after @if");
2566
-
2567
- // this whole branch is never hit via spec tests
2568
-
2569
- Directive* at_rule = SASS_MEMORY_NEW(Directive, pstate, kwd);
2570
- Lookahead lookahead = lookahead_for_include(position);
2571
- if (lookahead.found && !lookahead.has_interpolants) {
2572
- at_rule->selector(parse_selector_list(false));
2573
- }
2574
-
2575
- lex < css_comments >(false);
2576
-
2577
- if (lex < static_property >()) {
2578
- at_rule->value(parse_interpolated_chunk(Token(lexed)));
2579
- } else if (!(peek < alternatives < exactly<'{'>, exactly<'}'>, exactly<';'> > >())) {
2580
- at_rule->value(parse_list());
2581
- }
2582
-
2583
- lex < css_comments >(false);
2584
-
2585
- if (peek< exactly<'{'> >()) {
2586
- at_rule->block(parse_block());
2587
- }
2588
-
2589
- return at_rule;
2590
- }
2591
-
2592
- // this whole branch is never hit via spec tests
2593
- Directive_Obj Parser::parse_prefixed_directive()
2594
- {
2595
- std::string kwd(lexed);
2596
-
2597
- if (lexed == "@else") error("Invalid CSS: @else must come after @if");
2598
-
2599
- Directive_Obj at_rule = SASS_MEMORY_NEW(Directive, pstate, kwd);
2600
- Lookahead lookahead = lookahead_for_include(position);
2601
- if (lookahead.found && !lookahead.has_interpolants) {
2602
- at_rule->selector(parse_selector_list(false));
2603
- }
2604
-
2605
- lex < css_comments >(false);
2606
-
2607
- if (lex < static_property >()) {
2608
- at_rule->value(parse_interpolated_chunk(Token(lexed)));
2609
- } else if (!(peek < alternatives < exactly<'{'>, exactly<'}'>, exactly<';'> > >())) {
2610
- at_rule->value(parse_list());
2611
- }
2612
-
2613
- lex < css_comments >(false);
2614
-
2615
- if (peek< exactly<'{'> >()) {
2616
- at_rule->block(parse_block());
2617
- }
2618
-
2619
- return at_rule;
2620
- }
2621
-
2622
-
2623
2448
  Directive_Obj Parser::parse_directive()
2624
2449
  {
2625
2450
  Directive_Obj directive = SASS_MEMORY_NEW(Directive, pstate, lexed);
@@ -2660,6 +2485,7 @@ namespace Sass {
2660
2485
  lex <
2661
2486
  one_plus <
2662
2487
  alternatives <
2488
+ exactly <'>'>,
2663
2489
  sequence <
2664
2490
  exactly <'\\'>,
2665
2491
  any_char
@@ -2826,7 +2652,7 @@ namespace Sass {
2826
2652
  rv.error = q;
2827
2653
  rv.position = q;
2828
2654
  // check expected opening bracket
2829
- // only after successfull matching
2655
+ // only after successful matching
2830
2656
  if (peek < exactly<'{'> >(q)) rv.found = q;
2831
2657
  // else if (peek < end_of_file >(q)) rv.found = q;
2832
2658
  else if (peek < exactly<'('> >(q)) rv.found = q;
@@ -3068,6 +2894,10 @@ namespace Sass {
3068
2894
  Position p(pos.line ? pos : before_token);
3069
2895
  ParserState pstate(path, source, p, Offset(0, 0));
3070
2896
  // `pstate.src` may not outlive stack unwind so we must copy it.
2897
+ // This is needed since we often parse dynamically generated code,
2898
+ // e.g. for interpolations, and we normally don't want to keep this
2899
+ // memory around after we parsed the AST tree successfully. Only on
2900
+ // errors we want to preserve them for better error reporting.
3071
2901
  char *src_copy = sass_copy_c_string(pstate.src);
3072
2902
  pstate.src = src_copy;
3073
2903
  traces.push_back(Backtrace(pstate));
@@ -3094,7 +2924,7 @@ namespace Sass {
3094
2924
  }
3095
2925
  // backup position to last significant char
3096
2926
  while (trim && last_pos > source && last_pos < end) {
3097
- if (!Prelexer::is_space(*last_pos)) break;
2927
+ if (!Util::ascii_isspace(static_cast<unsigned char>(*last_pos))) break;
3098
2928
  utf8::prior(last_pos, source);
3099
2929
  }
3100
2930