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
@@ -0,0 +1,539 @@
1
+ // sass.hpp must go before all system headers to get the
2
+ // __EXTENSIONS__ fix on Solaris.
3
+ #include "sass.hpp"
4
+ #include "ast.hpp"
5
+
6
+ #include "util_string.hpp"
7
+
8
+ namespace Sass {
9
+
10
+ // ##########################################################################
11
+ // To compare/debug against libsass you can use debugger.hpp:
12
+ // c++: std::cerr << "result " << debug_vec(compound) << "\n";
13
+ // dart: stderr.writeln("result " + compound.toString());
14
+ // ##########################################################################
15
+
16
+ // ##########################################################################
17
+ // Returns whether [list1] is a superselector of [list2].
18
+ // That is, whether [list1] matches every element that
19
+ // [list2] matches, as well as possibly additional elements.
20
+ // ##########################################################################
21
+ bool listIsSuperslector(
22
+ const std::vector<ComplexSelectorObj>& list1,
23
+ const std::vector<ComplexSelectorObj>& list2);
24
+
25
+ // ##########################################################################
26
+ // Returns whether [complex1] is a superselector of [complex2].
27
+ // That is, whether [complex1] matches every element that
28
+ // [complex2] matches, as well as possibly additional elements.
29
+ // ##########################################################################
30
+ bool complexIsSuperselector(
31
+ const std::vector<SelectorComponentObj>& complex1,
32
+ const std::vector<SelectorComponentObj>& complex2);
33
+
34
+ // ##########################################################################
35
+ // Returns all pseudo selectors in [compound] that have
36
+ // a selector argument, and that have the given [name].
37
+ // ##########################################################################
38
+ std::vector<Pseudo_Selector_Obj> selectorPseudoNamed(
39
+ CompoundSelectorObj compound, std::string name)
40
+ {
41
+ std::vector<Pseudo_Selector_Obj> rv;
42
+ for (SimpleSelectorObj sel : compound->elements()) {
43
+ if (Pseudo_Selector_Obj pseudo = Cast<Pseudo_Selector>(sel)) {
44
+ if (pseudo->isClass() && pseudo->selector()) {
45
+ if (sel->name() == name) {
46
+ rv.push_back(sel);
47
+ }
48
+ }
49
+ }
50
+ }
51
+ return rv;
52
+ }
53
+ // EO selectorPseudoNamed
54
+
55
+ // ##########################################################################
56
+ // Returns whether [simple1] is a superselector of [simple2].
57
+ // That is, whether [simple1] matches every element that
58
+ // [simple2] matches, as well as possibly additional elements.
59
+ // ##########################################################################
60
+ bool simpleIsSuperselector(
61
+ const SimpleSelectorObj& simple1,
62
+ const SimpleSelectorObj& simple2)
63
+ {
64
+ // If they are equal they are superselectors
65
+ if (ObjEqualityFn(simple1, simple2)) {
66
+ return true;
67
+ }
68
+ // Some selector pseudoclasses can match normal selectors.
69
+ if (const Pseudo_Selector* pseudo = Cast<Pseudo_Selector>(simple2)) {
70
+ if (pseudo->selector() && isSubselectorPseudo(pseudo->normalized())) {
71
+ for (auto complex : pseudo->selector()->elements()) {
72
+ // Make sure we have exacly one items
73
+ if (complex->length() != 1) {
74
+ return false;
75
+ }
76
+ // That items must be a compound selector
77
+ if (auto compound = Cast<CompoundSelector>(complex->at(0))) {
78
+ // It must contain the lhs simple selector
79
+ if (!compound->contains(simple1)) {
80
+ return false;
81
+ }
82
+ }
83
+ }
84
+ return true;
85
+ }
86
+ }
87
+ return false;
88
+ }
89
+ // EO simpleIsSuperselector
90
+
91
+ // ##########################################################################
92
+ // Returns whether [simple] is a superselector of [compound].
93
+ // That is, whether [simple] matches every element that
94
+ // [compound] matches, as well as possibly additional elements.
95
+ // ##########################################################################
96
+ bool simpleIsSuperselectorOfCompound(
97
+ const SimpleSelectorObj& simple,
98
+ const CompoundSelectorObj& compound)
99
+ {
100
+ for (SimpleSelectorObj simple2 : compound->elements()) {
101
+ if (simpleIsSuperselector(simple, simple2)) {
102
+ return true;
103
+ }
104
+ }
105
+ return false;
106
+ }
107
+ // EO simpleIsSuperselectorOfCompound
108
+
109
+ // ##########################################################################
110
+ // ##########################################################################
111
+ bool typeIsSuperselectorOfCompound(
112
+ const Type_Selector_Obj& type,
113
+ const CompoundSelectorObj& compound)
114
+ {
115
+ for (const SimpleSelectorObj& simple : compound->elements()) {
116
+ if (const Type_Selector_Obj& rhs = Cast<Type_Selector>(simple)) {
117
+ if (*type != *rhs) return true;
118
+ }
119
+ }
120
+ return false;
121
+ }
122
+ // EO typeIsSuperselectorOfCompound
123
+
124
+ // ##########################################################################
125
+ // ##########################################################################
126
+ bool idIsSuperselectorOfCompound(
127
+ const Id_Selector_Obj& id,
128
+ const CompoundSelectorObj& compound)
129
+ {
130
+ for (const SimpleSelectorObj& simple : compound->elements()) {
131
+ if (const Id_Selector_Obj& rhs = Cast<Id_Selector>(simple)) {
132
+ if (*id != *rhs) return true;
133
+ }
134
+ }
135
+ return false;
136
+ }
137
+ // EO idIsSuperselectorOfCompound
138
+
139
+ // ##########################################################################
140
+ // ##########################################################################
141
+ bool pseudoIsSuperselectorOfPseudo(
142
+ const Pseudo_Selector_Obj& pseudo1,
143
+ const Pseudo_Selector_Obj& pseudo2,
144
+ const ComplexSelectorObj& parent
145
+ )
146
+ {
147
+ if (!pseudo2->selector()) return false;
148
+ if (pseudo1->name() == pseudo2->name()) {
149
+ SelectorListObj list = pseudo2->selector();
150
+ return listIsSuperslector(list->elements(), { parent });
151
+ }
152
+ return false;
153
+ }
154
+ // EO pseudoIsSuperselectorOfPseudo
155
+
156
+ // ##########################################################################
157
+ // ##########################################################################
158
+ bool pseudoNotIsSuperselectorOfCompound(
159
+ const Pseudo_Selector_Obj& pseudo1,
160
+ const CompoundSelectorObj& compound2,
161
+ const ComplexSelectorObj& parent)
162
+ {
163
+ for (const SimpleSelectorObj& simple2 : compound2->elements()) {
164
+ if (const Type_Selector_Obj& type2 = Cast<Type_Selector>(simple2)) {
165
+ if (const CompoundSelectorObj& compound1 = Cast<CompoundSelector>(parent->last())) {
166
+ if (typeIsSuperselectorOfCompound(type2, compound1)) return true;
167
+ }
168
+ }
169
+ else if (const Id_Selector_Obj& id2 = Cast<Id_Selector>(simple2)) {
170
+ if (const CompoundSelectorObj& compound1 = Cast<CompoundSelector>(parent->last())) {
171
+ if (idIsSuperselectorOfCompound(id2, compound1)) return true;
172
+ }
173
+ }
174
+ else if (const Pseudo_Selector_Obj& pseudo2 = Cast<Pseudo_Selector>(simple2)) {
175
+ if (pseudoIsSuperselectorOfPseudo(pseudo1, pseudo2, parent)) return true;
176
+ }
177
+ }
178
+ return false;
179
+ }
180
+ // pseudoNotIsSuperselectorOfCompound
181
+
182
+ // ##########################################################################
183
+ // Returns whether [pseudo1] is a superselector of [compound2].
184
+ // That is, whether [pseudo1] matches every element that [compound2]
185
+ // matches, as well as possibly additional elements. This assumes that
186
+ // [pseudo1]'s `selector` argument is not `null`. If [parents] is passed,
187
+ // it represents the parents of [compound2]. This is relevant for pseudo
188
+ // selectors with selector arguments, where we may need to know if the
189
+ // parent selectors in the selector argument match [parents].
190
+ // ##########################################################################
191
+ bool selectorPseudoIsSuperselector(
192
+ const Pseudo_Selector_Obj& pseudo1,
193
+ const CompoundSelectorObj& compound2,
194
+ // ToDo: is this really the most convenient way to do this?
195
+ std::vector<SelectorComponentObj>::const_iterator parents_from,
196
+ std::vector<SelectorComponentObj>::const_iterator parents_to)
197
+ {
198
+
199
+ // ToDo: move normalization function
200
+ std::string name(Util::unvendor(pseudo1->name()));
201
+
202
+ if (name == "matches" || name == "any") {
203
+ std::vector<Pseudo_Selector_Obj> pseudos =
204
+ selectorPseudoNamed(compound2, pseudo1->name());
205
+ SelectorListObj selector1 = pseudo1->selector();
206
+ for (Pseudo_Selector_Obj pseudo2 : pseudos) {
207
+ SelectorListObj selector = pseudo2->selector();
208
+ if (selector1->isSuperselectorOf(selector)) {
209
+ return true;
210
+ }
211
+ }
212
+
213
+ for (ComplexSelectorObj complex1 : selector1->elements()) {
214
+ std::vector<SelectorComponentObj> parents;
215
+ for (auto cur = parents_from; cur != parents_to; cur++) {
216
+ parents.push_back(*cur);
217
+ }
218
+ parents.push_back(compound2);
219
+ if (complexIsSuperselector(complex1->elements(), parents)) {
220
+ return true;
221
+ }
222
+ }
223
+
224
+ }
225
+ else if (name == "has" || name == "host" || name == "host-context" || name == "slotted") {
226
+ std::vector<Pseudo_Selector_Obj> pseudos =
227
+ selectorPseudoNamed(compound2, pseudo1->name());
228
+ SelectorListObj selector1 = pseudo1->selector();
229
+ for (Pseudo_Selector_Obj pseudo2 : pseudos) {
230
+ SelectorListObj selector = pseudo2->selector();
231
+ if (selector1->isSuperselectorOf(selector)) {
232
+ return true;
233
+ }
234
+ }
235
+
236
+ }
237
+ else if (name == "not") {
238
+ for (ComplexSelectorObj complex : pseudo1->selector()->elements()) {
239
+ if (!pseudoNotIsSuperselectorOfCompound(pseudo1, compound2, complex)) return false;
240
+ }
241
+ return true;
242
+ }
243
+ else if (name == "current") {
244
+ std::vector<Pseudo_Selector_Obj> pseudos =
245
+ selectorPseudoNamed(compound2, "current");
246
+ for (Pseudo_Selector_Obj pseudo2 : pseudos) {
247
+ if (ObjEqualityFn(pseudo1, pseudo2)) return true;
248
+ }
249
+
250
+ }
251
+ else if (name == "nth-child" || name == "nth-last-child") {
252
+ for (auto simple2 : compound2->elements()) {
253
+ if (Pseudo_Selector_Obj pseudo2 = simple2->getPseudoSelector()) {
254
+ if (pseudo1->name() != pseudo2->name()) continue;
255
+ if (!ObjEqualityFn(pseudo1->argument(), pseudo2->argument())) continue;
256
+ if (pseudo1->selector()->isSuperselectorOf(pseudo2->selector())) return true;
257
+ }
258
+ }
259
+ return false;
260
+ }
261
+
262
+ return false;
263
+
264
+ }
265
+ // EO selectorPseudoIsSuperselector
266
+
267
+ // ##########################################################################
268
+ // Returns whether [compound1] is a superselector of [compound2].
269
+ // That is, whether [compound1] matches every element that [compound2]
270
+ // matches, as well as possibly additional elements. If [parents] is
271
+ // passed, it represents the parents of [compound2]. This is relevant
272
+ // for pseudo selectors with selector arguments, where we may need to
273
+ // know if the parent selectors in the selector argument match [parents].
274
+ // ##########################################################################
275
+ bool compoundIsSuperselector(
276
+ const CompoundSelectorObj& compound1,
277
+ const CompoundSelectorObj& compound2,
278
+ // ToDo: is this really the most convenient way to do this?
279
+ const std::vector<SelectorComponentObj>::const_iterator parents_from,
280
+ const std::vector<SelectorComponentObj>::const_iterator parents_to)
281
+ {
282
+ // Every selector in [compound1.components] must have
283
+ // a matching selector in [compound2.components].
284
+ for (SimpleSelectorObj simple1 : compound1->elements()) {
285
+ Pseudo_Selector_Obj pseudo1 = Cast<Pseudo_Selector>(simple1);
286
+ if (pseudo1 && pseudo1->selector()) {
287
+ if (!selectorPseudoIsSuperselector(pseudo1, compound2, parents_from, parents_to)) {
288
+ return false;
289
+ }
290
+ }
291
+ else if (!simpleIsSuperselectorOfCompound(simple1, compound2)) {
292
+ return false;
293
+ }
294
+ }
295
+ // [compound1] can't be a superselector of a selector
296
+ // with pseudo-elements that [compound2] doesn't share.
297
+ for (SimpleSelectorObj simple2 : compound2->elements()) {
298
+ Pseudo_Selector_Obj pseudo2 = Cast<Pseudo_Selector>(simple2);
299
+ if (pseudo2 && pseudo2->isElement()) {
300
+ if (!simpleIsSuperselectorOfCompound(pseudo2, compound1)) {
301
+ return false;
302
+ }
303
+ }
304
+ }
305
+ return true;
306
+ }
307
+ // EO compoundIsSuperselector
308
+
309
+ // ##########################################################################
310
+ // Returns whether [compound1] is a superselector of [compound2].
311
+ // That is, whether [compound1] matches every element that [compound2]
312
+ // matches, as well as possibly additional elements. If [parents] is
313
+ // passed, it represents the parents of [compound2]. This is relevant
314
+ // for pseudo selectors with selector arguments, where we may need to
315
+ // know if the parent selectors in the selector argument match [parents].
316
+ // ##########################################################################
317
+ bool compoundIsSuperselector(
318
+ const CompoundSelectorObj& compound1,
319
+ const CompoundSelectorObj& compound2,
320
+ const std::vector<SelectorComponentObj>& parents)
321
+ {
322
+ return compoundIsSuperselector(
323
+ compound1, compound2,
324
+ parents.begin(), parents.end()
325
+ );
326
+ }
327
+ // EO compoundIsSuperselector
328
+
329
+ // ##########################################################################
330
+ // Returns whether [complex1] is a superselector of [complex2].
331
+ // That is, whether [complex1] matches every element that
332
+ // [complex2] matches, as well as possibly additional elements.
333
+ // ##########################################################################
334
+ bool complexIsSuperselector(
335
+ const std::vector<SelectorComponentObj>& complex1,
336
+ const std::vector<SelectorComponentObj>& complex2)
337
+ {
338
+
339
+ // Selectors with trailing operators are neither superselectors nor subselectors.
340
+ if (!complex1.empty() && Cast<SelectorCombinator>(complex1.back())) return false;
341
+ if (!complex2.empty() && Cast<SelectorCombinator>(complex2.back())) return false;
342
+
343
+ size_t i1 = 0, i2 = 0;
344
+ while (true) {
345
+
346
+ size_t remaining1 = complex1.size() - i1;
347
+ size_t remaining2 = complex2.size() - i2;
348
+
349
+ if (remaining1 == 0 || remaining2 == 0) {
350
+ return false;
351
+ }
352
+ // More complex selectors are never
353
+ // superselectors of less complex ones.
354
+ if (remaining1 > remaining2) {
355
+ return false;
356
+ }
357
+
358
+ // Selectors with leading operators are
359
+ // neither superselectors nor subselectors.
360
+ if (Cast<SelectorCombinator>(complex1[i1])) {
361
+ return false;
362
+ }
363
+ if (Cast<SelectorCombinator>(complex2[i2])) {
364
+ return false;
365
+ }
366
+
367
+ CompoundSelectorObj compound1 = Cast<CompoundSelector>(complex1[i1]);
368
+ CompoundSelectorObj compound2 = Cast<CompoundSelector>(complex2.back());
369
+
370
+ if (remaining1 == 1) {
371
+ std::vector<SelectorComponentObj>::const_iterator parents_to = complex2.end();
372
+ std::vector<SelectorComponentObj>::const_iterator parents_from = complex2.begin();
373
+ std::advance(parents_from, i2 + 1); // equivalent to dart `.skip(i2 + 1)`
374
+ bool rv = compoundIsSuperselector(compound1, compound2, parents_from, parents_to);
375
+ std::vector<SelectorComponentObj> pp;
376
+
377
+ std::vector<SelectorComponentObj>::const_iterator end = parents_to;
378
+ std::vector<SelectorComponentObj>::const_iterator beg = parents_from;
379
+ while (beg != end) {
380
+ pp.push_back(*beg);
381
+ beg++;
382
+ }
383
+
384
+ return rv;
385
+ }
386
+
387
+ // Find the first index where `complex2.sublist(i2, afterSuperselector)`
388
+ // is a subselector of [compound1]. We stop before the superselector
389
+ // would encompass all of [complex2] because we know [complex1] has
390
+ // more than one element, and consuming all of [complex2] wouldn't
391
+ // leave anything for the rest of [complex1] to match.
392
+ size_t afterSuperselector = i2 + 1;
393
+ for (; afterSuperselector < complex2.size(); afterSuperselector++) {
394
+ SelectorComponentObj component2 = complex2[afterSuperselector - 1];
395
+ if (CompoundSelectorObj compound2 = Cast<CompoundSelector>(component2)) {
396
+ std::vector<SelectorComponentObj>::const_iterator parents_to = complex2.begin();
397
+ std::vector<SelectorComponentObj>::const_iterator parents_from = complex2.begin();
398
+ // complex2.take(afterSuperselector - 1).skip(i2 + 1)
399
+ std::advance(parents_from, i2 + 1); // equivalent to dart `.skip`
400
+ std::advance(parents_to, afterSuperselector); // equivalent to dart `.take`
401
+ if (compoundIsSuperselector(compound1, compound2, parents_from, parents_to)) {
402
+ break;
403
+ }
404
+ }
405
+ }
406
+ if (afterSuperselector == complex2.size()) {
407
+ return false;
408
+ }
409
+
410
+ SelectorComponentObj component1 = complex1[i1 + 1],
411
+ component2 = complex2[afterSuperselector];
412
+
413
+ SelectorCombinatorObj combinator1 = Cast<SelectorCombinator>(component1);
414
+ SelectorCombinatorObj combinator2 = Cast<SelectorCombinator>(component2);
415
+
416
+ if (!combinator1.isNull()) {
417
+
418
+ if (combinator2.isNull()) {
419
+ return false;
420
+ }
421
+ // `.a ~ .b` is a superselector of `.a + .b`,
422
+ // but otherwise the combinators must match.
423
+ if (combinator1->isGeneralCombinator()) {
424
+ if (combinator2->isChildCombinator()) {
425
+ return false;
426
+ }
427
+ }
428
+ else if (*combinator1 != *combinator2) {
429
+ return false;
430
+ }
431
+
432
+ // `.foo > .baz` is not a superselector of `.foo > .bar > .baz` or
433
+ // `.foo > .bar .baz`, despite the fact that `.baz` is a superselector of
434
+ // `.bar > .baz` and `.bar .baz`. Same goes for `+` and `~`.
435
+ if (remaining1 == 3 && remaining2 > 3) {
436
+ return false;
437
+ }
438
+
439
+ i1 += 2; i2 = afterSuperselector + 1;
440
+
441
+ }
442
+ else if (!combinator2.isNull()) {
443
+ if (!combinator2->isChildCombinator()) {
444
+ return false;
445
+ }
446
+ i1 += 1; i2 = afterSuperselector + 1;
447
+ }
448
+ else {
449
+ i1 += 1; i2 = afterSuperselector;
450
+ }
451
+ }
452
+
453
+ return false;
454
+
455
+ }
456
+ // EO complexIsSuperselector
457
+
458
+ // ##########################################################################
459
+ // Like [complexIsSuperselector], but compares [complex1]
460
+ // and [complex2] as though they shared an implicit base
461
+ // [SimpleSelector]. For example, `B` is not normally a
462
+ // superselector of `B A`, since it doesn't match elements
463
+ // that match `A`. However, it *is* a parent superselector,
464
+ // since `B X` is a superselector of `B A X`.
465
+ // ##########################################################################
466
+ bool complexIsParentSuperselector(
467
+ const std::vector<SelectorComponentObj>& complex1,
468
+ const std::vector<SelectorComponentObj>& complex2)
469
+ {
470
+ // Try some simple heuristics to see if we can avoid allocations.
471
+ if (complex1.empty() && complex2.empty()) return false;
472
+ if (Cast<SelectorCombinator>(complex1.front())) return false;
473
+ if (Cast<SelectorCombinator>(complex2.front())) return false;
474
+ if (complex1.size() > complex2.size()) return false;
475
+ // TODO(nweiz): There's got to be a way to do this without a bunch of extra allocations...
476
+ std::vector<SelectorComponentObj> cplx1(complex1);
477
+ std::vector<SelectorComponentObj> cplx2(complex2);
478
+ CompoundSelectorObj base = SASS_MEMORY_NEW(CompoundSelector, "[tmp]");
479
+ cplx1.push_back(base); cplx2.push_back(base);
480
+ return complexIsSuperselector(cplx1, cplx2);
481
+ }
482
+ // EO complexIsParentSuperselector
483
+
484
+ // ##########################################################################
485
+ // Returns whether [list] has a superselector for [complex].
486
+ // That is, whether an item in [list] matches every element that
487
+ // [complex] matches, as well as possibly additional elements.
488
+ // ##########################################################################
489
+ bool listHasSuperslectorForComplex(
490
+ std::vector<ComplexSelectorObj> list,
491
+ ComplexSelectorObj complex)
492
+ {
493
+ // Return true if every [complex] selector on [list2]
494
+ // is a super selector of the full selector [list1].
495
+ for (ComplexSelectorObj lhs : list) {
496
+ if (complexIsSuperselector(lhs->elements(), complex->elements())) {
497
+ return true;
498
+ }
499
+ }
500
+ return false;
501
+ }
502
+ // listIsSuperslectorOfComplex
503
+
504
+ // ##########################################################################
505
+ // Returns whether [list1] is a superselector of [list2].
506
+ // That is, whether [list1] matches every element that
507
+ // [list2] matches, as well as possibly additional elements.
508
+ // ##########################################################################
509
+ bool listIsSuperslector(
510
+ const std::vector<ComplexSelectorObj>& list1,
511
+ const std::vector<ComplexSelectorObj>& list2)
512
+ {
513
+ // Return true if every [complex] selector on [list2]
514
+ // is a super selector of the full selector [list1].
515
+ for (ComplexSelectorObj complex : list2) {
516
+ if (!listHasSuperslectorForComplex(list1, complex)) {
517
+ return false;
518
+ }
519
+ }
520
+ return true;
521
+ }
522
+ // EO listIsSuperslector
523
+
524
+ // ##########################################################################
525
+ // Implement selector methods (dispatch to functions)
526
+ // ##########################################################################
527
+ bool SelectorList::isSuperselectorOf(const SelectorList* sub) const
528
+ {
529
+ return listIsSuperslector(elements(), sub->elements());
530
+ }
531
+ bool ComplexSelector::isSuperselectorOf(const ComplexSelector* sub) const
532
+ {
533
+ return complexIsSuperselector(elements(), sub->elements());
534
+ }
535
+
536
+ // ##########################################################################
537
+ // ##########################################################################
538
+
539
+ }