sassc 2.2.1 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -0
  3. data/CHANGELOG.md +18 -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 +4 -0
  9. data/ext/libsass/src/MurmurHash2.hpp +91 -0
  10. data/ext/libsass/src/ast.cpp +158 -168
  11. data/ext/libsass/src/ast.hpp +389 -230
  12. data/ext/libsass/src/ast_def_macros.hpp +18 -10
  13. data/ext/libsass/src/ast_fwd_decl.cpp +4 -3
  14. data/ext/libsass/src/ast_fwd_decl.hpp +98 -165
  15. data/ext/libsass/src/ast_helpers.hpp +292 -0
  16. data/ext/libsass/src/ast_sel_cmp.cpp +219 -732
  17. data/ext/libsass/src/ast_sel_super.cpp +539 -0
  18. data/ext/libsass/src/ast_sel_unify.cpp +207 -212
  19. data/ext/libsass/src/ast_sel_weave.cpp +616 -0
  20. data/ext/libsass/src/ast_selectors.cpp +594 -1026
  21. data/ext/libsass/src/ast_selectors.hpp +339 -385
  22. data/ext/libsass/src/ast_supports.cpp +36 -52
  23. data/ext/libsass/src/ast_supports.hpp +29 -29
  24. data/ext/libsass/src/ast_values.cpp +271 -84
  25. data/ext/libsass/src/ast_values.hpp +116 -107
  26. data/ext/libsass/src/backtrace.cpp +9 -9
  27. data/ext/libsass/src/backtrace.hpp +5 -5
  28. data/ext/libsass/src/base64vlq.cpp +2 -2
  29. data/ext/libsass/src/base64vlq.hpp +1 -1
  30. data/ext/libsass/src/bind.cpp +18 -18
  31. data/ext/libsass/src/bind.hpp +1 -1
  32. data/ext/libsass/src/c2ast.cpp +3 -3
  33. data/ext/libsass/src/c2ast.hpp +1 -1
  34. data/ext/libsass/src/cencode.c +4 -6
  35. data/ext/libsass/src/check_nesting.cpp +40 -41
  36. data/ext/libsass/src/check_nesting.hpp +6 -2
  37. data/ext/libsass/src/color_maps.cpp +14 -13
  38. data/ext/libsass/src/color_maps.hpp +1 -9
  39. data/ext/libsass/src/constants.cpp +5 -0
  40. data/ext/libsass/src/constants.hpp +6 -0
  41. data/ext/libsass/src/context.cpp +92 -119
  42. data/ext/libsass/src/context.hpp +41 -53
  43. data/ext/libsass/src/cssize.cpp +66 -149
  44. data/ext/libsass/src/cssize.hpp +17 -23
  45. data/ext/libsass/src/dart_helpers.hpp +199 -0
  46. data/ext/libsass/src/debugger.hpp +451 -295
  47. data/ext/libsass/src/emitter.cpp +15 -16
  48. data/ext/libsass/src/emitter.hpp +10 -12
  49. data/ext/libsass/src/environment.cpp +27 -27
  50. data/ext/libsass/src/environment.hpp +29 -24
  51. data/ext/libsass/src/error_handling.cpp +62 -41
  52. data/ext/libsass/src/error_handling.hpp +61 -51
  53. data/ext/libsass/src/eval.cpp +167 -281
  54. data/ext/libsass/src/eval.hpp +27 -29
  55. data/ext/libsass/src/eval_selectors.cpp +75 -0
  56. data/ext/libsass/src/expand.cpp +275 -222
  57. data/ext/libsass/src/expand.hpp +36 -16
  58. data/ext/libsass/src/extender.cpp +1188 -0
  59. data/ext/libsass/src/extender.hpp +399 -0
  60. data/ext/libsass/src/extension.cpp +43 -0
  61. data/ext/libsass/src/extension.hpp +89 -0
  62. data/ext/libsass/src/file.cpp +81 -72
  63. data/ext/libsass/src/file.hpp +28 -37
  64. data/ext/libsass/src/fn_colors.cpp +20 -18
  65. data/ext/libsass/src/fn_lists.cpp +30 -29
  66. data/ext/libsass/src/fn_maps.cpp +3 -3
  67. data/ext/libsass/src/fn_miscs.cpp +34 -46
  68. data/ext/libsass/src/fn_numbers.cpp +20 -13
  69. data/ext/libsass/src/fn_selectors.cpp +98 -128
  70. data/ext/libsass/src/fn_strings.cpp +47 -33
  71. data/ext/libsass/src/fn_utils.cpp +31 -29
  72. data/ext/libsass/src/fn_utils.hpp +17 -11
  73. data/ext/libsass/src/inspect.cpp +186 -148
  74. data/ext/libsass/src/inspect.hpp +31 -29
  75. data/ext/libsass/src/lexer.cpp +20 -82
  76. data/ext/libsass/src/lexer.hpp +5 -16
  77. data/ext/libsass/src/listize.cpp +23 -37
  78. data/ext/libsass/src/listize.hpp +8 -9
  79. data/ext/libsass/src/mapping.hpp +1 -0
  80. data/ext/libsass/src/memory/allocator.cpp +48 -0
  81. data/ext/libsass/src/memory/allocator.hpp +138 -0
  82. data/ext/libsass/src/memory/config.hpp +20 -0
  83. data/ext/libsass/src/memory/memory_pool.hpp +186 -0
  84. data/ext/libsass/src/memory/{SharedPtr.cpp → shared_ptr.cpp} +2 -2
  85. data/ext/libsass/src/memory/{SharedPtr.hpp → shared_ptr.hpp} +55 -9
  86. data/ext/libsass/src/memory.hpp +12 -0
  87. data/ext/libsass/src/operation.hpp +71 -61
  88. data/ext/libsass/src/operators.cpp +19 -18
  89. data/ext/libsass/src/operators.hpp +11 -11
  90. data/ext/libsass/src/ordered_map.hpp +112 -0
  91. data/ext/libsass/src/output.cpp +45 -64
  92. data/ext/libsass/src/output.hpp +6 -6
  93. data/ext/libsass/src/parser.cpp +512 -700
  94. data/ext/libsass/src/parser.hpp +89 -97
  95. data/ext/libsass/src/parser_selectors.cpp +189 -0
  96. data/ext/libsass/src/permutate.hpp +164 -0
  97. data/ext/libsass/src/plugins.cpp +7 -7
  98. data/ext/libsass/src/plugins.hpp +8 -8
  99. data/ext/libsass/src/position.cpp +7 -26
  100. data/ext/libsass/src/position.hpp +44 -21
  101. data/ext/libsass/src/prelexer.cpp +6 -6
  102. data/ext/libsass/src/remove_placeholders.cpp +55 -56
  103. data/ext/libsass/src/remove_placeholders.hpp +21 -18
  104. data/ext/libsass/src/sass.cpp +16 -15
  105. data/ext/libsass/src/sass.hpp +10 -5
  106. data/ext/libsass/src/sass2scss.cpp +4 -4
  107. data/ext/libsass/src/sass_context.cpp +91 -122
  108. data/ext/libsass/src/sass_context.hpp +2 -2
  109. data/ext/libsass/src/sass_functions.cpp +1 -1
  110. data/ext/libsass/src/sass_values.cpp +8 -11
  111. data/ext/libsass/src/settings.hpp +19 -0
  112. data/ext/libsass/src/source.cpp +69 -0
  113. data/ext/libsass/src/source.hpp +95 -0
  114. data/ext/libsass/src/source_data.hpp +32 -0
  115. data/ext/libsass/src/source_map.cpp +22 -18
  116. data/ext/libsass/src/source_map.hpp +12 -9
  117. data/ext/libsass/src/stylesheet.cpp +22 -0
  118. data/ext/libsass/src/stylesheet.hpp +57 -0
  119. data/ext/libsass/src/to_value.cpp +2 -2
  120. data/ext/libsass/src/to_value.hpp +1 -1
  121. data/ext/libsass/src/units.cpp +24 -22
  122. data/ext/libsass/src/units.hpp +8 -8
  123. data/ext/libsass/src/utf8_string.cpp +9 -10
  124. data/ext/libsass/src/utf8_string.hpp +7 -6
  125. data/ext/libsass/src/util.cpp +48 -50
  126. data/ext/libsass/src/util.hpp +20 -21
  127. data/ext/libsass/src/util_string.cpp +111 -61
  128. data/ext/libsass/src/util_string.hpp +62 -8
  129. data/ext/libsass/src/values.cpp +12 -12
  130. data/lib/sassc/engine.rb +5 -3
  131. data/lib/sassc/functions_handler.rb +8 -8
  132. data/lib/sassc/native.rb +4 -6
  133. data/lib/sassc/script.rb +4 -4
  134. data/lib/sassc/version.rb +1 -1
  135. data/test/functions_test.rb +18 -1
  136. data/test/native_test.rb +4 -4
  137. metadata +29 -15
  138. data/ext/libsass/src/extend.cpp +0 -2132
  139. data/ext/libsass/src/extend.hpp +0 -86
  140. data/ext/libsass/src/node.cpp +0 -322
  141. data/ext/libsass/src/node.hpp +0 -118
  142. data/ext/libsass/src/paths.hpp +0 -71
  143. data/ext/libsass/src/sass_util.cpp +0 -152
  144. data/ext/libsass/src/sass_util.hpp +0 -256
  145. data/ext/libsass/src/subset_map.cpp +0 -58
  146. data/ext/libsass/src/subset_map.hpp +0 -76
  147. data/lib/sassc/native/lib_c.rb +0 -21
@@ -0,0 +1,616 @@
1
+ // sass.hpp must go before all system headers to get the
2
+ // __EXTENSIONS__ fix on Solaris.
3
+ #include "sass.hpp"
4
+
5
+ #include "ast.hpp"
6
+ #include "permutate.hpp"
7
+ #include "dart_helpers.hpp"
8
+
9
+ namespace Sass {
10
+
11
+ // ##########################################################################
12
+ // Returns whether or not [compound] contains a `::root` selector.
13
+ // ##########################################################################
14
+ bool hasRoot(const CompoundSelector* compound)
15
+ {
16
+ // Libsass does not yet know the root selector
17
+ return false;
18
+ }
19
+ // EO hasRoot
20
+
21
+ // ##########################################################################
22
+ // Returns whether a [CompoundSelector] may contain only
23
+ // one simple selector of the same type as [simple].
24
+ // ##########################################################################
25
+ bool isUnique(const SimpleSelector* simple)
26
+ {
27
+ if (Cast<IDSelector>(simple)) return true;
28
+ if (const PseudoSelector * pseudo = Cast<PseudoSelector>(simple)) {
29
+ if (pseudo->is_pseudo_element()) return true;
30
+ }
31
+ return false;
32
+ }
33
+ // EO isUnique
34
+
35
+ // ##########################################################################
36
+ // Returns whether [complex1] and [complex2] need to be unified to
37
+ // produce a valid combined selector. This is necessary when both
38
+ // selectors contain the same unique simple selector, such as an ID.
39
+ // ##########################################################################
40
+ bool mustUnify(
41
+ const sass::vector<SelectorComponentObj>& complex1,
42
+ const sass::vector<SelectorComponentObj>& complex2)
43
+ {
44
+
45
+ sass::vector<const SimpleSelector*> uniqueSelectors1;
46
+ for (const SelectorComponent* component : complex1) {
47
+ if (const CompoundSelector * compound = component->getCompound()) {
48
+ for (const SimpleSelector* sel : compound->elements()) {
49
+ if (isUnique(sel)) {
50
+ uniqueSelectors1.push_back(sel);
51
+ }
52
+ }
53
+ }
54
+ }
55
+ if (uniqueSelectors1.empty()) return false;
56
+
57
+ // ToDo: unsure if this is correct
58
+ for (const SelectorComponent* component : complex2) {
59
+ if (const CompoundSelector * compound = component->getCompound()) {
60
+ for (const SimpleSelector* sel : compound->elements()) {
61
+ if (isUnique(sel)) {
62
+ for (auto check : uniqueSelectors1) {
63
+ if (*check == *sel) return true;
64
+ }
65
+ }
66
+ }
67
+ }
68
+ }
69
+
70
+ return false;
71
+
72
+ }
73
+ // EO isUnique
74
+
75
+ // ##########################################################################
76
+ // Helper function used by `weaveParents`
77
+ // ##########################################################################
78
+ bool cmpGroups(
79
+ const sass::vector<SelectorComponentObj>& group1,
80
+ const sass::vector<SelectorComponentObj>& group2,
81
+ sass::vector<SelectorComponentObj>& select)
82
+ {
83
+
84
+ if (group1.size() == group2.size() && std::equal(group1.begin(), group1.end(), group2.begin(), PtrObjEqualityFn<SelectorComponent>)) {
85
+ select = group1;
86
+ return true;
87
+ }
88
+
89
+ if (!Cast<CompoundSelector>(group1.front())) {
90
+ select = {};
91
+ return false;
92
+ }
93
+ if (!Cast<CompoundSelector>(group2.front())) {
94
+ select = {};
95
+ return false;
96
+ }
97
+
98
+ if (complexIsParentSuperselector(group1, group2)) {
99
+ select = group2;
100
+ return true;
101
+ }
102
+ if (complexIsParentSuperselector(group2, group1)) {
103
+ select = group1;
104
+ return true;
105
+ }
106
+
107
+ if (!mustUnify(group1, group2)) {
108
+ select = {};
109
+ return false;
110
+ }
111
+
112
+ sass::vector<sass::vector<SelectorComponentObj>> unified
113
+ = unifyComplex({ group1, group2 });
114
+ if (unified.empty()) return false;
115
+ if (unified.size() > 1) return false;
116
+ select = unified.front();
117
+ return true;
118
+ }
119
+ // EO cmpGroups
120
+
121
+ // ##########################################################################
122
+ // Helper function used by `weaveParents`
123
+ // ##########################################################################
124
+ template <class T>
125
+ bool checkForEmptyChild(const T& item) {
126
+ return item.empty();
127
+ }
128
+ // EO checkForEmptyChild
129
+
130
+ // ##########################################################################
131
+ // Helper function used by `weaveParents`
132
+ // ##########################################################################
133
+ bool cmpChunkForEmptySequence(
134
+ const sass::vector<sass::vector<SelectorComponentObj>>& seq,
135
+ const sass::vector<SelectorComponentObj>& group)
136
+ {
137
+ return seq.empty();
138
+ }
139
+ // EO cmpChunkForEmptySequence
140
+
141
+ // ##########################################################################
142
+ // Helper function used by `weaveParents`
143
+ // ##########################################################################
144
+ bool cmpChunkForParentSuperselector(
145
+ const sass::vector<sass::vector<SelectorComponentObj>>& seq,
146
+ const sass::vector<SelectorComponentObj>& group)
147
+ {
148
+ return seq.empty() || complexIsParentSuperselector(seq.front(), group);
149
+ }
150
+ // EO cmpChunkForParentSuperselector
151
+
152
+ // ##########################################################################
153
+ // Returns all orderings of initial subseqeuences of [queue1] and [queue2].
154
+ // The [done] callback is used to determine the extent of the initial
155
+ // subsequences. It's called with each queue until it returns `true`.
156
+ // Destructively removes the initial subsequences of [queue1] and [queue2].
157
+ // For example, given `(A B C | D E)` and `(1 2 | 3 4 5)` (with `|` denoting
158
+ // the boundary of the initial subsequence), this would return `[(A B C 1 2),
159
+ // (1 2 A B C)]`. The queues would then contain `(D E)` and `(3 4 5)`.
160
+ // ##########################################################################
161
+ template <class T>
162
+ sass::vector<sass::vector<T>> getChunks(
163
+ sass::vector<T>& queue1, sass::vector<T>& queue2,
164
+ const T& group, bool(*done)(const sass::vector<T>&, const T&)
165
+ ) {
166
+
167
+ sass::vector<T> chunk1;
168
+ while (!done(queue1, group)) {
169
+ chunk1.push_back(queue1.front());
170
+ queue1.erase(queue1.begin());
171
+ }
172
+
173
+ sass::vector<T> chunk2;
174
+ while (!done(queue2, group)) {
175
+ chunk2.push_back(queue2.front());
176
+ queue2.erase(queue2.begin());
177
+ }
178
+
179
+ if (chunk1.empty() && chunk2.empty()) return {};
180
+ else if (chunk1.empty()) return { chunk2 };
181
+ else if (chunk2.empty()) return { chunk1 };
182
+
183
+ sass::vector<T> choice1(chunk1), choice2(chunk2);
184
+ std::move(std::begin(chunk2), std::end(chunk2),
185
+ std::inserter(choice1, std::end(choice1)));
186
+ std::move(std::begin(chunk1), std::end(chunk1),
187
+ std::inserter(choice2, std::end(choice2)));
188
+ return { choice1, choice2 };
189
+ }
190
+ // EO getChunks
191
+
192
+ // ##########################################################################
193
+ // If the first element of [queue] has a `::root`
194
+ // selector, removes and returns that element.
195
+ // ##########################################################################
196
+ CompoundSelectorObj getFirstIfRoot(sass::vector<SelectorComponentObj>& queue) {
197
+ if (queue.empty()) return {};
198
+ SelectorComponent* first = queue.front();
199
+ if (CompoundSelector* sel = Cast<CompoundSelector>(first)) {
200
+ if (!hasRoot(sel)) return {};
201
+ queue.erase(queue.begin());
202
+ return sel;
203
+ }
204
+ return {};
205
+ }
206
+ // EO getFirstIfRoot
207
+
208
+ // ##########################################################################
209
+ // Returns [complex], grouped into sub-lists such that no sub-list
210
+ // contains two adjacent [ComplexSelector]s. For example,
211
+ // `(A B > C D + E ~ > G)` is grouped into `[(A) (B > C) (D + E ~ > G)]`.
212
+ // ##########################################################################
213
+ sass::vector<sass::vector<SelectorComponentObj>> groupSelectors(
214
+ const sass::vector<SelectorComponentObj>& components)
215
+ {
216
+ bool lastWasCompound = false;
217
+ sass::vector<SelectorComponentObj> group;
218
+ sass::vector<sass::vector<SelectorComponentObj>> groups;
219
+ for (size_t i = 0; i < components.size(); i += 1) {
220
+ if (CompoundSelector* compound = components[i]->getCompound()) {
221
+ if (lastWasCompound) {
222
+ groups.push_back(group);
223
+ group.clear();
224
+ }
225
+ group.push_back(compound);
226
+ lastWasCompound = true;
227
+ }
228
+ else if (SelectorCombinator* combinator = components[i]->getCombinator()) {
229
+ group.push_back(combinator);
230
+ lastWasCompound = false;
231
+ }
232
+ }
233
+ if (!group.empty()) {
234
+ groups.push_back(group);
235
+ }
236
+ return groups;
237
+ }
238
+ // EO groupSelectors
239
+
240
+ // ##########################################################################
241
+ // Extracts leading [Combinator]s from [components1] and [components2]
242
+ // and merges them together into a single list of combinators.
243
+ // If there are no combinators to be merged, returns an empty list.
244
+ // If the combinators can't be merged, returns `null`.
245
+ // ##########################################################################
246
+ bool mergeInitialCombinators(
247
+ sass::vector<SelectorComponentObj>& components1,
248
+ sass::vector<SelectorComponentObj>& components2,
249
+ sass::vector<SelectorComponentObj>& result)
250
+ {
251
+
252
+ sass::vector<SelectorComponentObj> combinators1;
253
+ while (!components1.empty() && Cast<SelectorCombinator>(components1.front())) {
254
+ SelectorCombinatorObj front = Cast<SelectorCombinator>(components1.front());
255
+ components1.erase(components1.begin());
256
+ combinators1.push_back(front);
257
+ }
258
+
259
+ sass::vector<SelectorComponentObj> combinators2;
260
+ while (!components2.empty() && Cast<SelectorCombinator>(components2.front())) {
261
+ SelectorCombinatorObj front = Cast<SelectorCombinator>(components2.front());
262
+ components2.erase(components2.begin());
263
+ combinators2.push_back(front);
264
+ }
265
+
266
+ // If neither sequence of combinators is a subsequence
267
+ // of the other, they cannot be merged successfully.
268
+ sass::vector<SelectorComponentObj> LCS = lcs<SelectorComponentObj>(combinators1, combinators2);
269
+
270
+ if (ListEquality(LCS, combinators1, PtrObjEqualityFn<SelectorComponent>)) {
271
+ result = combinators2;
272
+ return true;
273
+ }
274
+ if (ListEquality(LCS, combinators2, PtrObjEqualityFn<SelectorComponent>)) {
275
+ result = combinators1;
276
+ return true;
277
+ }
278
+
279
+ return false;
280
+
281
+ }
282
+ // EO mergeInitialCombinators
283
+
284
+ // ##########################################################################
285
+ // Extracts trailing [Combinator]s, and the selectors to which they apply,
286
+ // from [components1] and [components2] and merges them together into a
287
+ // single list. If there are no combinators to be merged, returns an
288
+ // empty list. If the sequences can't be merged, returns `null`.
289
+ // ##########################################################################
290
+ bool mergeFinalCombinators(
291
+ sass::vector<SelectorComponentObj>& components1,
292
+ sass::vector<SelectorComponentObj>& components2,
293
+ sass::vector<sass::vector<sass::vector<SelectorComponentObj>>>& result)
294
+ {
295
+
296
+ if (components1.empty() || !Cast<SelectorCombinator>(components1.back())) {
297
+ if (components2.empty() || !Cast<SelectorCombinator>(components2.back())) {
298
+ return true;
299
+ }
300
+ }
301
+
302
+ sass::vector<SelectorComponentObj> combinators1;
303
+ while (!components1.empty() && Cast<SelectorCombinator>(components1.back())) {
304
+ SelectorCombinatorObj back = Cast<SelectorCombinator>(components1.back());
305
+ components1.erase(components1.end() - 1);
306
+ combinators1.push_back(back);
307
+ }
308
+
309
+ sass::vector<SelectorComponentObj> combinators2;
310
+ while (!components2.empty() && Cast<SelectorCombinator>(components2.back())) {
311
+ SelectorCombinatorObj back = Cast<SelectorCombinator>(components2.back());
312
+ components2.erase(components2.end() - 1);
313
+ combinators2.push_back(back);
314
+ }
315
+
316
+ // reverse now as we used push_back (faster than new alloc)
317
+ std::reverse(combinators1.begin(), combinators1.end());
318
+ std::reverse(combinators2.begin(), combinators2.end());
319
+
320
+ if (combinators1.size() > 1 || combinators2.size() > 1) {
321
+ // If there are multiple combinators, something hacky's going on. If one
322
+ // is a supersequence of the other, use that, otherwise give up.
323
+ auto LCS = lcs<SelectorComponentObj>(combinators1, combinators2);
324
+ if (ListEquality(LCS, combinators1, PtrObjEqualityFn<SelectorComponent>)) {
325
+ result.push_back({ combinators2 });
326
+ }
327
+ else if (ListEquality(LCS, combinators2, PtrObjEqualityFn<SelectorComponent>)) {
328
+ result.push_back({ combinators1 });
329
+ }
330
+ else {
331
+ return false;
332
+ }
333
+ return true;
334
+ }
335
+
336
+ // This code looks complicated, but it's actually just a bunch of special
337
+ // cases for interactions between different combinators.
338
+ SelectorCombinatorObj combinator1, combinator2;
339
+ if (!combinators1.empty()) combinator1 = combinators1.back();
340
+ if (!combinators2.empty()) combinator2 = combinators2.back();
341
+
342
+ if (!combinator1.isNull() && !combinator2.isNull()) {
343
+
344
+ CompoundSelector* compound1 = Cast<CompoundSelector>(components1.back());
345
+ CompoundSelector* compound2 = Cast<CompoundSelector>(components2.back());
346
+
347
+ components1.pop_back();
348
+ components2.pop_back();
349
+
350
+ if (combinator1->isGeneralCombinator() && combinator2->isGeneralCombinator()) {
351
+
352
+ if (compound1->isSuperselectorOf(compound2)) {
353
+ result.push_back({ { compound2, combinator2 } });
354
+ }
355
+ else if (compound2->isSuperselectorOf(compound1)) {
356
+ result.push_back({ { compound1, combinator1 } });
357
+ }
358
+ else {
359
+ sass::vector<sass::vector<SelectorComponentObj>> choices;
360
+ choices.push_back({ compound1, combinator1, compound2, combinator2 });
361
+ choices.push_back({ compound2, combinator2, compound1, combinator1 });
362
+ if (CompoundSelector* unified = compound1->unifyWith(compound2)) {
363
+ choices.push_back({ unified, combinator1 });
364
+ }
365
+ result.push_back(choices);
366
+ }
367
+ }
368
+ else if ((combinator1->isGeneralCombinator() && combinator2->isAdjacentCombinator()) ||
369
+ (combinator1->isAdjacentCombinator() && combinator2->isGeneralCombinator())) {
370
+
371
+ CompoundSelector* followingSiblingSelector = combinator1->isGeneralCombinator() ? compound1 : compound2;
372
+ CompoundSelector* nextSiblingSelector = combinator1->isGeneralCombinator() ? compound2 : compound1;
373
+ SelectorCombinator* followingSiblingCombinator = combinator1->isGeneralCombinator() ? combinator1 : combinator2;
374
+ SelectorCombinator* nextSiblingCombinator = combinator1->isGeneralCombinator() ? combinator2 : combinator1;
375
+
376
+ if (followingSiblingSelector->isSuperselectorOf(nextSiblingSelector)) {
377
+ result.push_back({ { nextSiblingSelector, nextSiblingCombinator } });
378
+ }
379
+ else {
380
+ CompoundSelectorObj unified = compound1->unifyWith(compound2);
381
+ sass::vector<sass::vector<SelectorComponentObj>> items;
382
+
383
+ if (!unified.isNull()) {
384
+ items.push_back({
385
+ unified, nextSiblingCombinator
386
+ });
387
+ }
388
+
389
+ items.insert(items.begin(), {
390
+ followingSiblingSelector,
391
+ followingSiblingCombinator,
392
+ nextSiblingSelector,
393
+ nextSiblingCombinator,
394
+ });
395
+
396
+ result.push_back(items);
397
+ }
398
+
399
+ }
400
+ else if (combinator1->isChildCombinator() && (combinator2->isAdjacentCombinator() || combinator2->isGeneralCombinator())) {
401
+ result.push_back({ { compound2, combinator2 } });
402
+ components1.push_back(compound1);
403
+ components1.push_back(combinator1);
404
+ }
405
+ else if (combinator2->isChildCombinator() && (combinator1->isAdjacentCombinator() || combinator1->isGeneralCombinator())) {
406
+ result.push_back({ { compound1, combinator1 } });
407
+ components2.push_back(compound2);
408
+ components2.push_back(combinator2);
409
+ }
410
+ else if (*combinator1 == *combinator2) {
411
+ CompoundSelectorObj unified = compound1->unifyWith(compound2);
412
+ if (unified.isNull()) return false;
413
+ result.push_back({ { unified, combinator1 } });
414
+ }
415
+ else {
416
+ return false;
417
+ }
418
+
419
+ return mergeFinalCombinators(components1, components2, result);
420
+
421
+ }
422
+ else if (!combinator1.isNull()) {
423
+
424
+ if (combinator1->isChildCombinator() && !components2.empty()) {
425
+ const CompoundSelector* back1 = Cast<CompoundSelector>(components1.back());
426
+ const CompoundSelector* back2 = Cast<CompoundSelector>(components2.back());
427
+ if (back1 && back2 && back2->isSuperselectorOf(back1)) {
428
+ components2.pop_back();
429
+ }
430
+ }
431
+
432
+ result.push_back({ { components1.back(), combinator1 } });
433
+
434
+ components1.pop_back();
435
+
436
+ return mergeFinalCombinators(components1, components2, result);
437
+
438
+ }
439
+
440
+ if (combinator2->isChildCombinator() && !components1.empty()) {
441
+ const CompoundSelector* back1 = Cast<CompoundSelector>(components1.back());
442
+ const CompoundSelector* back2 = Cast<CompoundSelector>(components2.back());
443
+ if (back1 && back2 && back1->isSuperselectorOf(back2)) {
444
+ components1.pop_back();
445
+ }
446
+ }
447
+
448
+ result.push_back({ { components2.back(), combinator2 } });
449
+
450
+ components2.pop_back();
451
+
452
+ return mergeFinalCombinators(components1, components2, result);
453
+
454
+ }
455
+ // EO mergeFinalCombinators
456
+
457
+ // ##########################################################################
458
+ // Expands "parenthesized selectors" in [complexes]. That is, if
459
+ // we have `.A .B {@extend .C}` and `.D .C {...}`, this conceptually
460
+ // expands into `.D .C, .D (.A .B)`, and this function translates
461
+ // `.D (.A .B)` into `.D .A .B, .A .D .B`. For thoroughness, `.A.D .B`
462
+ // would also be required, but including merged selectors results in
463
+ // exponential output for very little gain. The selector `.D (.A .B)`
464
+ // is represented as the list `[[.D], [.A, .B]]`.
465
+ // ##########################################################################
466
+ sass::vector<sass::vector<SelectorComponentObj>> weave(
467
+ const sass::vector<sass::vector<SelectorComponentObj>>& complexes) {
468
+
469
+ sass::vector<sass::vector<SelectorComponentObj>> prefixes;
470
+
471
+ prefixes.push_back(complexes.at(0));
472
+
473
+ for (size_t i = 1; i < complexes.size(); i += 1) {
474
+
475
+ if (complexes[i].empty()) {
476
+ continue;
477
+ }
478
+ const sass::vector<SelectorComponentObj>& complex = complexes[i];
479
+ SelectorComponent* target = complex.back();
480
+ if (complex.size() == 1) {
481
+ for (auto& prefix : prefixes) {
482
+ prefix.push_back(target);
483
+ }
484
+ continue;
485
+ }
486
+
487
+ sass::vector<SelectorComponentObj> parents(complex);
488
+
489
+ parents.pop_back();
490
+
491
+ sass::vector<sass::vector<SelectorComponentObj>> newPrefixes;
492
+ for (sass::vector<SelectorComponentObj> prefix : prefixes) {
493
+ sass::vector<sass::vector<SelectorComponentObj>>
494
+ parentPrefixes = weaveParents(prefix, parents);
495
+ if (parentPrefixes.empty()) continue;
496
+ for (auto& parentPrefix : parentPrefixes) {
497
+ parentPrefix.push_back(target);
498
+ newPrefixes.push_back(parentPrefix);
499
+ }
500
+ }
501
+ prefixes = newPrefixes;
502
+
503
+ }
504
+ return prefixes;
505
+
506
+ }
507
+ // EO weave
508
+
509
+ // ##########################################################################
510
+ // Interweaves [parents1] and [parents2] as parents of the same target
511
+ // selector. Returns all possible orderings of the selectors in the
512
+ // inputs (including using unification) that maintain the relative
513
+ // ordering of the input. For example, given `.foo .bar` and `.baz .bang`,
514
+ // this would return `.foo .bar .baz .bang`, `.foo .bar.baz .bang`,
515
+ // `.foo .baz .bar .bang`, `.foo .baz .bar.bang`, `.foo .baz .bang .bar`,
516
+ // and so on until `.baz .bang .foo .bar`. Semantically, for selectors A
517
+ // and B, this returns all selectors `AB_i` such that the union over all i
518
+ // of elements matched by `AB_i X` is identical to the intersection of all
519
+ // elements matched by `A X` and all elements matched by `B X`. Some `AB_i`
520
+ // are elided to reduce the size of the output.
521
+ // ##########################################################################
522
+ sass::vector<sass::vector<SelectorComponentObj>> weaveParents(
523
+ sass::vector<SelectorComponentObj> queue1,
524
+ sass::vector<SelectorComponentObj> queue2)
525
+ {
526
+
527
+ sass::vector<SelectorComponentObj> leads;
528
+ sass::vector<sass::vector<sass::vector<SelectorComponentObj>>> trails;
529
+ if (!mergeInitialCombinators(queue1, queue2, leads)) return {};
530
+ if (!mergeFinalCombinators(queue1, queue2, trails)) return {};
531
+ // list comes out in reverse order for performance
532
+ std::reverse(trails.begin(), trails.end());
533
+
534
+ // Make sure there's at most one `:root` in the output.
535
+ // Note: does not yet do anything in libsass (no root selector)
536
+ CompoundSelectorObj root1 = getFirstIfRoot(queue1);
537
+ CompoundSelectorObj root2 = getFirstIfRoot(queue2);
538
+
539
+ if (!root1.isNull() && !root2.isNull()) {
540
+ CompoundSelectorObj root = root1->unifyWith(root2);
541
+ if (root.isNull()) return {}; // null
542
+ queue1.insert(queue1.begin(), root);
543
+ queue2.insert(queue2.begin(), root);
544
+ }
545
+ else if (!root1.isNull()) {
546
+ queue2.insert(queue2.begin(), root1);
547
+ }
548
+ else if (!root2.isNull()) {
549
+ queue1.insert(queue1.begin(), root2);
550
+ }
551
+
552
+ // group into sub-lists so no sub-list contains two adjacent ComplexSelectors.
553
+ sass::vector<sass::vector<SelectorComponentObj>> groups1 = groupSelectors(queue1);
554
+ sass::vector<sass::vector<SelectorComponentObj>> groups2 = groupSelectors(queue2);
555
+
556
+ // The main array to store our choices that will be permutated
557
+ sass::vector<sass::vector<sass::vector<SelectorComponentObj>>> choices;
558
+
559
+ // append initial combinators
560
+ choices.push_back({ leads });
561
+
562
+ sass::vector<sass::vector<SelectorComponentObj>> LCS =
563
+ lcs<sass::vector<SelectorComponentObj>>(groups1, groups2, cmpGroups);
564
+
565
+ for (auto group : LCS) {
566
+
567
+ // Create junks from groups1 and groups2
568
+ sass::vector<sass::vector<sass::vector<SelectorComponentObj>>>
569
+ chunks = getChunks<sass::vector<SelectorComponentObj>>(
570
+ groups1, groups2, group, cmpChunkForParentSuperselector);
571
+
572
+ // Create expanded array by flattening chunks2 inner
573
+ sass::vector<sass::vector<SelectorComponentObj>>
574
+ expanded = flattenInner(chunks);
575
+
576
+ // Prepare data structures
577
+ choices.push_back(expanded);
578
+ choices.push_back({ group });
579
+ if (!groups1.empty()) {
580
+ groups1.erase(groups1.begin());
581
+ }
582
+ if (!groups2.empty()) {
583
+ groups2.erase(groups2.begin());
584
+ }
585
+
586
+ }
587
+
588
+ // Create junks from groups1 and groups2
589
+ sass::vector<sass::vector<sass::vector<SelectorComponentObj>>>
590
+ chunks = getChunks<sass::vector<SelectorComponentObj>>(
591
+ groups1, groups2, {}, cmpChunkForEmptySequence);
592
+
593
+ // Append chunks with inner arrays flattened
594
+ choices.emplace_back(flattenInner(chunks));
595
+
596
+ // append all trailing selectors to choices
597
+ std::move(std::begin(trails), std::end(trails),
598
+ std::inserter(choices, std::end(choices)));
599
+
600
+ // move all non empty items to the front, then erase the trailing ones
601
+ choices.erase(std::remove_if(choices.begin(), choices.end(), checkForEmptyChild
602
+ <sass::vector<sass::vector<SelectorComponentObj>>>), choices.end());
603
+
604
+ // permutate all possible paths through selectors
605
+ sass::vector<sass::vector<SelectorComponentObj>>
606
+ results = flattenInner(permutate(choices));
607
+
608
+ return results;
609
+
610
+ }
611
+ // EO weaveParents
612
+
613
+ // ##########################################################################
614
+ // ##########################################################################
615
+
616
+ }