sassc 2.2.1 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
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